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