1
/* pdp1_dcs.c: PDP-1D terminal multiplexor simulator
3
Copyright (c) 2006, 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
dcs Type 630 data communications subsystem
28
This module implements up to 32 individual serial interfaces.
31
#include "pdp1_defs.h"
35
#define DCS_LINES 32 /* lines */
36
#define DCS_LINE_MASK (DCS_LINES - 1)
37
#define DCSL_WAIT 1000 /* output wait */
38
#define DCS_NUMLIN dcs_desc.lines
40
int32 dcs_sbs = 0; /* SBS level */
41
uint32 dcs_send = 0; /* line for send */
42
uint32 dcs_scan = 0; /* line for scanner */
43
uint8 dcs_flg[DCS_LINES]; /* line flags */
44
uint8 dcs_buf[DCS_LINES]; /* line bufffers */
46
extern int32 iosta, stop_inst;
47
extern int32 tmxr_poll;
49
TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* line descriptors */
50
TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */
52
t_stat dcsi_svc (UNIT *uptr);
53
t_stat dcso_svc (UNIT *uptr);
54
t_stat dcs_reset (DEVICE *dptr);
55
t_stat dcs_attach (UNIT *uptr, char *cptr);
56
t_stat dcs_detach (UNIT *uptr);
57
t_stat dcs_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
58
t_stat dcs_show (FILE *st, UNIT *uptr, int32 val, void *desc);
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);
63
/* DCS data structures
65
dcs_dev DCS device descriptor
66
dcs_unit DCS unit descriptor
67
dcs_reg DCS register list
68
dcs_mod DCS modifiers list
71
REG dcs_nlreg = { DRDATA (NLINES, DCS_NUMLIN, 6), PV_LEFT };
73
UNIT dcs_unit = { UDATA (&dcsi_svc, UNIT_ATTABLE, 0) };
76
{ BRDATA (BUF, dcs_buf, 8, 8, DCS_LINES) },
77
{ BRDATA (FLAGS, dcs_flg, 8, 1, DCS_LINES) },
78
{ FLDATA (SCNF, iosta, IOS_V_DCS) },
79
{ ORDATA (SCAN, dcs_scan, 5) },
80
{ ORDATA (SEND, dcs_send, 5) },
81
{ DRDATA (SBSLVL, dcs_sbs, 4), REG_HRO },
86
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
87
&dev_set_sbs, &dev_show_sbs, (void *) &dcs_sbs },
88
{ MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",
89
&dcs_vlines, NULL, &dcs_nlreg },
90
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
91
&tmxr_dscln, NULL, &dcs_desc },
92
{ UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dcs_summ },
93
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
94
NULL, &dcs_show, NULL },
95
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
96
NULL, &dcs_show, NULL },
101
"DCS", &dcs_unit, dcs_reg, dcs_mod,
103
&tmxr_ex, &tmxr_dep, &dcs_reset,
104
NULL, &dcs_attach, &dcs_detach,
105
NULL, DEV_NET | DEV_DISABLE | DEV_DIS
108
/* DCSL data structures
110
dcsl_dev DCSL device descriptor
111
dcsl_unit DCSL unit descriptor
112
dcsl_reg DCSL register list
113
dcsl_mod DCSL modifiers list
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
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }
152
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
153
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
154
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
155
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
156
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
157
&tmxr_dscln, NULL, &dcs_desc },
158
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
159
&tmxr_set_log, &tmxr_show_log, &dcs_desc },
160
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
161
&tmxr_set_nolog, NULL, &dcs_desc },
166
{ URDATA (TIME, dcsl_unit[0].wait, 10, 24, 0,
167
DCS_LINES, REG_NZ + PV_LEFT) },
172
"DCSL", dcsl_unit, dcsl_reg, dcsl_mod,
173
DCS_LINES, 10, 31, 1, 8, 8,
174
NULL, NULL, &dcs_reset,
179
/* DCS IOT routine */
181
int32 dcs (int32 inst, int32 dev, int32 dat)
183
int32 pls = (inst >> 6) & 077;
185
if (dcs_dev.flags & DEV_DIS) /* disabled? */
186
return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
187
if (pls & 020) dat = 0; /* pulse 20? clr IO */
189
switch (pls & 057) { /* case IR<6,8:11> */
192
dat |= dcs_buf[dcs_scan]; /* return line buf */
193
dcs_flg[dcs_scan] = 0; /* clr line flag */
197
dat |= dcs_scan; /* return line num */
201
dat |= dcs_buf[dcs_scan]; /* return line buf */
202
dcs_flg[dcs_scan] = 0; /* clr line flag */
205
dcs_scan_next (TRUE); /* unlock scanner */
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);
215
dcs_send = dat & DCS_LINE_MASK; /* load line num */
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 */
226
return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
232
/* Unit service - receive side
234
Poll all active lines for input
235
Poll for new connections
238
t_stat dcsi_svc (UNIT *uptr)
242
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
243
if (dcs_dev.flags & DEV_DIS) return SCPE_OK;
244
sim_activate (uptr, tmxr_poll); /* continue poll */
245
ln = tmxr_poll_conn (&dcs_desc); /* look for connect */
246
if (ln >= 0) { /* got one? */
247
dcs_ldsc[ln].rcve = 1; /* set rcv enable */
249
tmxr_poll_rx (&dcs_desc); /* poll for input */
250
for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */
251
if (dcs_ldsc[ln].conn) { /* connected? */
252
if (c = tmxr_getc_ln (&dcs_ldsc[ln])) { /* get char */
253
if (c & SCPE_BREAK) c = 0; /* break? */
254
else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR);
255
dcs_buf[ln] = c; /* save char */
256
dcs_flg[ln] = 1; /* set line flag */
257
dcs_scan_next (FALSE); /* kick scanner */
258
out = sim_tt_outcvt (c & 0177, TT_GET_MODE (dcsl_unit[ln].flags));
260
tmxr_putc_ln (&dcs_ldsc[ln], out); /* echo char */
261
tmxr_poll_tx (&dcs_desc); /* poll xmt */
265
else dcs_ldsc[ln].rcve = 0; /* disconnected */
270
/* Unit service - transmit side */
272
t_stat dcso_svc (UNIT *uptr)
275
uint32 ln = uptr - dcsl_unit; /* line # */
277
if (dcs_dev.flags & DEV_DIS) return SCPE_OK;
278
if (dcs_ldsc[ln].conn) { /* connected? */
279
if (dcs_ldsc[ln].xmte) { /* xmt enabled? */
280
c = sim_tt_outcvt (dcs_buf[ln] & 0177, TT_GET_MODE (uptr->flags));
281
if (c >= 0) tmxr_putc_ln (&dcs_ldsc[ln], c); /* output char */
282
tmxr_poll_tx (&dcs_desc); /* poll xmt */
284
else { /* buf full */
285
tmxr_poll_tx (&dcs_desc); /* poll xmt */
286
sim_activate (uptr, uptr->wait); /* reschedule */
290
dcs_flg[ln] = 1; /* set line flag */
291
dcs_scan_next (FALSE); /* kick scanner */
297
void dcs_scan_next (t_bool unlk)
301
if (unlk) iosta &= ~IOS_DCS; /* unlock? */
302
else if (iosta & IOS_DCS) return; /* no, locked? */
303
for (i = 0; i < DCS_LINES; i++) { /* scan flags */
304
dcs_scan = (dcs_scan + 1) & DCS_LINE_MASK; /* next flag */
305
if (dcs_flg[dcs_scan] != 0) { /* flag set? */
306
iosta |= IOS_DCS; /* lock scanner */
307
dev_req_int (dcs_sbs); /* request intr */
316
t_stat dcs_reset (DEVICE *dptr)
320
if (dcs_dev.flags & DEV_DIS) /* master disabled? */
321
dcsl_dev.flags = dcsl_dev.flags | DEV_DIS; /* disable lines */
322
else dcsl_dev.flags = dcsl_dev.flags & ~DEV_DIS;
323
if (dcs_unit.flags & UNIT_ATT) /* master att? */
324
sim_activate_abs (&dcs_unit, tmxr_poll); /* activate */
325
else sim_cancel (&dcs_unit); /* else stop */
326
for (i = 0; i < DCS_LINES; i++) dcs_reset_ln (i); /* reset lines */
329
iosta &= ~IOS_DCS; /* clr intr req */
333
/* Attach master unit */
335
t_stat dcs_attach (UNIT *uptr, char *cptr)
339
r = tmxr_attach (&dcs_desc, uptr, cptr); /* attach */
340
if (r != SCPE_OK) return r; /* error */
341
sim_activate_abs (uptr, tmxr_poll); /* start poll */
345
/* Detach master unit */
347
t_stat dcs_detach (UNIT *uptr)
352
r = tmxr_detach (&dcs_desc, uptr); /* detach */
353
for (i = 0; i < DCS_LINES; i++) dcs_ldsc[i].rcve = 0; /* disable rcv */
354
sim_cancel (uptr); /* stop poll */
358
/* Show summary processor */
360
t_stat dcs_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
364
for (i = t = 0; i < DCS_LINES; i++) t = t + (dcs_ldsc[i].conn != 0);
365
if (t == 1) fprintf (st, "1 connection");
366
else fprintf (st, "%d connections", t);
370
/* SHOW CONN/STAT processor */
372
t_stat dcs_show (FILE *st, UNIT *uptr, int32 val, void *desc)
376
for (i = t = 0; i < DCS_LINES; i++) t = t + (dcs_ldsc[i].conn != 0);
378
for (i = 0; i < DCS_LINES; i++) {
379
if (dcs_ldsc[i].conn) {
380
if (val) tmxr_fconns (st, &dcs_ldsc[i], i);
381
else tmxr_fstats (st, &dcs_ldsc[i], i);
385
else fprintf (st, "all disconnected\n");
389
/* Change number of lines */
391
t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
396
if (cptr == NULL) return SCPE_ARG;
397
newln = get_uint (cptr, 10, DCS_LINES, &r);
398
if ((r != SCPE_OK) || (newln == DCS_NUMLIN)) return r;
399
if (newln == 0) return SCPE_ARG;
400
if (newln < DCS_LINES) {
401
for (i = newln, t = 0; i < DCS_NUMLIN; i++) t = t | dcs_ldsc[i].conn;
402
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
404
for (i = newln; i < DCS_NUMLIN; i++) {
405
if (dcs_ldsc[i].conn) {
406
tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n");
407
tmxr_reset_ln (&dcs_ldsc[i]); /* reset line */
409
dcsl_unit[i].flags = dcsl_unit[i].flags | UNIT_DIS;
414
for (i = DCS_NUMLIN; i < newln; i++) {
415
dcsl_unit[i].flags = dcsl_unit[i].flags & ~UNIT_DIS;
423
/* Reset an individual line */
425
void dcs_reset_ln (int32 ln)
427
sim_cancel (&dcsl_unit[ln]);