1 /* pdp1_dcs.c: PDP-1D terminal multiplexor simulator
2
3 Copyright (c) 2006-2008, 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 dcs Type 630 data communications subsystem
27
28 19-Nov-2008 RMS Revised for common TMXR show routines
29
30 This module implements up to 32 individual serial interfaces.
31 */
32
33 #include "pdp1_defs.h"
34 #include "sim_sock.h"
35 #include "sim_tmxr.h"
36
37 #define DCS_LINES 32 /* lines */
38 #define DCS_LINE_MASK (DCS_LINES - 1)
39 #define DCSL_WAIT 1000 /* output wait */
40 #define DCS_NUMLIN dcs_desc.lines
41
42 int32 dcs_sbs = 0; /* SBS level */
43 uint32 dcs_send = 0; /* line for send */
44 uint32 dcs_scan = 0; /* line for scanner */
45 uint8 dcs_flg[DCS_LINES]; /* line flags */
46 uint8 dcs_buf[DCS_LINES]; /* line bufffers */
47
48 extern int32 iosta, stop_inst;
49 extern int32 tmxr_poll;
50
51 TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* line descriptors */
52 TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */
53
54 t_stat dcsi_svc (UNIT *uptr);
55 t_stat dcso_svc (UNIT *uptr);
56 t_stat dcs_reset (DEVICE *dptr);
57 t_stat dcs_attach (UNIT *uptr, char *cptr);
58 t_stat dcs_detach (UNIT *uptr);
59 t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
60 void dcs_reset_ln (int32 ln);
61 void dcs_scan_next (t_bool unlk);
62
63 /* DCS data structures
64
65 dcs_dev DCS device descriptor
66 dcs_unit DCS unit descriptor
67 dcs_reg DCS register list
68 dcs_mod DCS modifiers list
69 */
70
71 UNIT dcs_unit = { UDATA (&dcsi_svc, UNIT_ATTABLE, 0) };
72
73 REG dcs_reg[] = {
74 { BRDATA (BUF, dcs_buf, 8, 8, DCS_LINES) },
75 { BRDATA (FLAGS, dcs_flg, 8, 1, DCS_LINES) },
76 { FLDATA (SCNF, iosta, IOS_V_DCS) },
77 { ORDATA (SCAN, dcs_scan, 5) },
78 { ORDATA (SEND, dcs_send, 5) },
79 { DRDATA (SBSLVL, dcs_sbs, 4), REG_HRO },
80 { NULL }
81 };
82
83 MTAB dcs_mod[] = {
84 { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
85 &dev_set_sbs, &dev_show_sbs, (void *) &dcs_sbs },
86 { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
87 &dcs_vlines, &tmxr_show_lines, (void *) &dcs_desc },
88 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
89 &tmxr_dscln, NULL, (void *) &dcs_desc },
90 { UNIT_ATT, UNIT_ATT, "summary", NULL,
91 NULL, &tmxr_show_summ, (void *) &dcs_desc },
92 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
93 NULL, &tmxr_show_cstat, (void *) &dcs_desc },
94 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
95 NULL, &tmxr_show_cstat, (void *) &dcs_desc },
96 { 0 }
97 };
98
99 DEVICE dcs_dev = {
100 "DCS", &dcs_unit, dcs_reg, dcs_mod,
101 1, 10, 31, 1, 8, 8,
102 &tmxr_ex, &tmxr_dep, &dcs_reset,
103 NULL, &dcs_attach, &dcs_detach,
104 NULL, DEV_NET | DEV_DISABLE | DEV_DIS
105 };
106
107 /* DCSL data structures
108
109 dcsl_dev DCSL device descriptor
110 dcsl_unit DCSL unit descriptor
111 dcsl_reg DCSL register list
112 dcsl_mod DCSL modifiers list
113 */
114
115 UNIT dcsl_unit[] = {
116 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
117 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
118 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
119 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
120 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
121 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
122 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
123 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
124 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
125 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
126 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
127 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
128 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
129 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
130 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
131 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
132 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
133 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
134 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
135 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
136 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
137 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
138 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
139 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
140 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
141 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
142 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
143 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
144 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
145 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
146 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
147 { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }
148 };
149
150 MTAB dcsl_mod[] = {
151 { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
152 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
153 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
154 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
155 { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
156 &tmxr_dscln, NULL, &dcs_desc },
157 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
158 &tmxr_set_log, &tmxr_show_log, &dcs_desc },
159 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
160 &tmxr_set_nolog, NULL, &dcs_desc },
161 { 0 }
162 };
163
164 REG dcsl_reg[] = {
165 { URDATA (TIME, dcsl_unit[0].wait, 10, 24, 0,
166 DCS_LINES, REG_NZ + PV_LEFT) },
167 { NULL }
168 };
169
170 DEVICE dcsl_dev = {
171 "DCSL", dcsl_unit, dcsl_reg, dcsl_mod,
172 DCS_LINES, 10, 31, 1, 8, 8,
173 NULL, NULL, &dcs_reset,
174 NULL, NULL, NULL,
175 NULL, DEV_DIS
176 };
177
178 /* DCS IOT routine */
179
dcs(int32 inst,int32 dev,int32 dat)180 int32 dcs (int32 inst, int32 dev, int32 dat)
181 {
182 int32 pls = (inst >> 6) & 077;
183
184 if (dcs_dev.flags & DEV_DIS) /* disabled? */
185 return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
186 if (pls & 020) /* pulse 20? clr IO */
187 dat = 0;
188
189 switch (pls & 057) { /* case IR<6,8:11> */
190
191 case 000: /* RCH */
192 dat |= dcs_buf[dcs_scan]; /* return line buf */
193 dcs_flg[dcs_scan] = 0; /* clr line flag */
194 break;
195
196 case 001: /* RRC */
197 dat |= dcs_scan; /* return line num */
198 break;
199
200 case 010: /* RCC */
201 dat |= dcs_buf[dcs_scan]; /* return line buf */
202 dcs_flg[dcs_scan] = 0; /* clr line flag */
203 /* fall through */
204 case 011: /* RSC */
205 dcs_scan_next (TRUE); /* unlock scanner */
206 break;
207
208 case 040: /* TCB */
209 dcs_buf[dcs_send] = dat & 0377; /* load buffer */
210 dcs_flg[dcs_send] = 0; /* clr line flag */
211 sim_activate (&dcsl_unit[dcs_send], dcsl_unit[dcs_send].wait);
212 break;
213
214 case 041: /* SSB */
215 dcs_send = dat & DCS_LINE_MASK; /* load line num */
216 break;
217
218 case 050: /* TCC */
219 dcs_buf[dcs_scan] = dat & 0377; /* load buffer */
220 dcs_flg[dcs_scan] = 0; /* clr line flag */
221 sim_activate (&dcsl_unit[dcs_scan], dcsl_unit[dcs_scan].wait);
222 dcs_scan_next (TRUE); /* unlock scanner */
223 break;
224
225 default:
226 return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
227 } /* end case */
228
229 return dat;
230 }
231
232 /* Unit service - receive side
233
234 Poll all active lines for input
235 Poll for new connections
236 */
237
dcsi_svc(UNIT * uptr)238 t_stat dcsi_svc (UNIT *uptr)
239 {
240 int32 ln, c, out;
241
242 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
243 return SCPE_OK;
244 if (dcs_dev.flags & DEV_DIS)
245 return SCPE_OK;
246 sim_activate (uptr, tmxr_poll); /* continue poll */
247 ln = tmxr_poll_conn (&dcs_desc); /* look for connect */
248 if (ln >= 0) { /* got one? */
249 dcs_ldsc[ln].rcve = 1; /* set rcv enable */
250 }
251 tmxr_poll_rx (&dcs_desc); /* poll for input */
252 for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */
253 if (dcs_ldsc[ln].conn) { /* connected? */
254 if ((c = tmxr_getc_ln (&dcs_ldsc[ln]))) { /* get char */
255 if (c & SCPE_BREAK) /* break? */
256 c = 0;
257 else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR);
258 dcs_buf[ln] = c; /* save char */
259 dcs_flg[ln] = 1; /* set line flag */
260 dcs_scan_next (FALSE); /* kick scanner */
261 out = sim_tt_outcvt (c & 0177, TT_GET_MODE (dcsl_unit[ln].flags));
262 if (out >= 0) {
263 tmxr_putc_ln (&dcs_ldsc[ln], out); /* echo char */
264 tmxr_poll_tx (&dcs_desc); /* poll xmt */
265 }
266 }
267 }
268 else dcs_ldsc[ln].rcve = 0; /* disconnected */
269 } /* end for */
270 return SCPE_OK;
271 }
272
273 /* Unit service - transmit side */
274
dcso_svc(UNIT * uptr)275 t_stat dcso_svc (UNIT *uptr)
276 {
277 int32 c;
278 uint32 ln = uptr - dcsl_unit; /* line # */
279
280 if (dcs_dev.flags & DEV_DIS)
281 return SCPE_OK;
282 if (dcs_ldsc[ln].conn) { /* connected? */
283 if (dcs_ldsc[ln].xmte) { /* xmt enabled? */
284 c = sim_tt_outcvt (dcs_buf[ln] & 0177, TT_GET_MODE (uptr->flags));
285 if (c >= 0) /* output char */
286 tmxr_putc_ln (&dcs_ldsc[ln], c);
287 tmxr_poll_tx (&dcs_desc); /* poll xmt */
288 }
289 else { /* buf full */
290 tmxr_poll_tx (&dcs_desc); /* poll xmt */
291 sim_activate (uptr, uptr->wait); /* reschedule */
292 return SCPE_OK;
293 }
294 }
295 dcs_flg[ln] = 1; /* set line flag */
296 dcs_scan_next (FALSE); /* kick scanner */
297 return SCPE_OK;
298 }
299
300 /* Kick scanner */
301
dcs_scan_next(t_bool unlk)302 void dcs_scan_next (t_bool unlk)
303 {
304 int32 i;
305
306 if (unlk) /* unlock? */
307 iosta &= ~IOS_DCS;
308 else if (iosta & IOS_DCS) /* no, locked? */
309 return;
310 for (i = 0; i < DCS_LINES; i++) { /* scan flags */
311 dcs_scan = (dcs_scan + 1) & DCS_LINE_MASK; /* next flag */
312 if (dcs_flg[dcs_scan] != 0) { /* flag set? */
313 iosta |= IOS_DCS; /* lock scanner */
314 dev_req_int (dcs_sbs); /* request intr */
315 return;
316 }
317 }
318 return;
319 }
320
321 /* Reset routine */
322
dcs_reset(DEVICE * dptr)323 t_stat dcs_reset (DEVICE *dptr)
324 {
325 int32 i;
326
327 if (dcs_dev.flags & DEV_DIS) /* master disabled? */
328 dcsl_dev.flags = dcsl_dev.flags | DEV_DIS; /* disable lines */
329 else dcsl_dev.flags = dcsl_dev.flags & ~DEV_DIS;
330 if (dcs_unit.flags & UNIT_ATT) /* master att? */
331 sim_activate_abs (&dcs_unit, tmxr_poll); /* activate */
332 else sim_cancel (&dcs_unit); /* else stop */
333 for (i = 0; i < DCS_LINES; i++) /* reset lines */
334 dcs_reset_ln (i);
335 dcs_send = 0;
336 dcs_scan = 0;
337 iosta &= ~IOS_DCS; /* clr intr req */
338 return SCPE_OK;
339 }
340
341 /* Attach master unit */
342
dcs_attach(UNIT * uptr,char * cptr)343 t_stat dcs_attach (UNIT *uptr, char *cptr)
344 {
345 t_stat r;
346
347 r = tmxr_attach (&dcs_desc, uptr, cptr); /* attach */
348 if (r != SCPE_OK) /* error */
349 return r;
350 sim_activate_abs (uptr, tmxr_poll); /* start poll */
351 return SCPE_OK;
352 }
353
354 /* Detach master unit */
355
dcs_detach(UNIT * uptr)356 t_stat dcs_detach (UNIT *uptr)
357 {
358 int32 i;
359 t_stat r;
360
361 r = tmxr_detach (&dcs_desc, uptr); /* detach */
362 for (i = 0; i < DCS_LINES; i++) /* disable rcv */
363 dcs_ldsc[i].rcve = 0;
364 sim_cancel (uptr); /* stop poll */
365 return r;
366 }
367
368 /* Change number of lines */
369
dcs_vlines(UNIT * uptr,int32 val,char * cptr,void * desc)370 t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
371 {
372 int32 newln, i, t;
373 t_stat r;
374
375 if (cptr == NULL)
376 return SCPE_ARG;
377 newln = get_uint (cptr, 10, DCS_LINES, &r);
378 if ((r != SCPE_OK) || (newln == DCS_NUMLIN))
379 return r;
380 if (newln == 0)
381 return SCPE_ARG;
382 if (newln < DCS_LINES) {
383 for (i = newln, t = 0; i < DCS_NUMLIN; i++)
384 t = t | dcs_ldsc[i].conn;
385 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
386 return SCPE_OK;
387 for (i = newln; i < DCS_NUMLIN; i++) {
388 if (dcs_ldsc[i].conn) {
389 tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n");
390 tmxr_reset_ln (&dcs_ldsc[i]); /* reset line */
391 }
392 dcsl_unit[i].flags = dcsl_unit[i].flags | UNIT_DIS;
393 dcs_reset_ln (i);
394 }
395 }
396 else {
397 for (i = DCS_NUMLIN; i < newln; i++) {
398 dcsl_unit[i].flags = dcsl_unit[i].flags & ~UNIT_DIS;
399 dcs_reset_ln (i);
400 }
401 }
402 DCS_NUMLIN = newln;
403 return SCPE_OK;
404 }
405
406 /* Reset an individual line */
407
dcs_reset_ln(int32 ln)408 void dcs_reset_ln (int32 ln)
409 {
410 sim_cancel (&dcsl_unit[ln]);
411 dcs_buf[ln] = 0;
412 dcs_flg[ln] = 0;
413 return;
414 }
415