Fix divide of 0 on KS10 processor. Fix write access for auxiliary processor memory. Updated support new PIDP10 panel. Allow eight Unibux ports on the TEN device. Added GE DATANET-760 device to PDP6 Removed USER mode restriction for idle detection. Added Data Disc 6600 Television Display System.
666 lines
23 KiB
C
666 lines
23 KiB
C
/* ks10_dz.c: PDP-10 DZ11 communication server simulator
|
|
|
|
Copyright (c) 2021, Richard Cornwell
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Richard Cornwell shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Richard Cornwell.
|
|
|
|
*/
|
|
|
|
#include "kx10_defs.h"
|
|
#include "sim_sock.h"
|
|
#include "sim_tmxr.h"
|
|
|
|
#ifndef NUM_DEVS_DZ
|
|
#define NUM_DEVS_DZ 0
|
|
#endif
|
|
|
|
#if (NUM_DEVS_DZ > 0)
|
|
|
|
|
|
#define DZ11_LINES (8 * NUM_DEVS_DZ)
|
|
|
|
/* 0 CSR */
|
|
|
|
#define MAINT 0000010 /* Maintance mode */
|
|
#define CLR 0000020
|
|
#define MSE 0000040
|
|
#define RIE 0000100
|
|
#define RDONE 0000200
|
|
#define TLINE 0003400
|
|
#define TLINE_V 8
|
|
#define SAE 0010000
|
|
#define SA 0020000
|
|
#define TIE 0040000
|
|
#define TRDY 0100000
|
|
|
|
/* 2 RBUF */
|
|
#define RBUF 0000377
|
|
#define RXLINE 0003400
|
|
#define RXLINE_V 8
|
|
#define PAR_ERR 0010000
|
|
#define FRM_ERR 0020000
|
|
#define OVRN 0040000
|
|
#define VALID 0100000
|
|
|
|
/* 2 LPR */
|
|
#define LINE 0000007
|
|
#define CHAR_LEN 0000030
|
|
#define STOP 0000040
|
|
#define PAR_ENB 0000100
|
|
#define ODD_PAR 0000200
|
|
#define FREQ 0007400
|
|
#define RXON 0010000
|
|
|
|
/* 4 TCR */
|
|
#define LINE_ENB 0000001
|
|
#define DTR 0000400
|
|
|
|
/* 6 MSR */
|
|
#define RO 0000001
|
|
#define CO 0000400
|
|
|
|
/* 6 TDR */
|
|
#define TBUF 0000377
|
|
#define BRK 0000400
|
|
|
|
struct _buffer {
|
|
int in_ptr; /* Insert pointer */
|
|
int out_ptr; /* Remove pointer */
|
|
uint16 buff[64]; /* Buffer */
|
|
int len; /* Length */
|
|
};
|
|
|
|
#define full(q) ((((q)->in_ptr + 1) & 0x3f) == (q)->out_ptr)
|
|
#define empty(q) ((q)->in_ptr == (q)->out_ptr)
|
|
#define not_empty(q) ((q)->in_ptr != (q)->out_ptr)
|
|
#define inco(q) (q)->out_ptr = ((q)->out_ptr + 1) & 0x3f
|
|
#define inci(q) (q)->in_ptr = ((q)->in_ptr + 1) & 0x3f
|
|
|
|
#define LINE_EN 01
|
|
#define DTR_FLAG 02
|
|
|
|
uint16 dz_csr[NUM_DEVS_DZ];
|
|
uint16 dz_xmit[DZ11_LINES];
|
|
uint8 dz_flags[DZ11_LINES];
|
|
uint8 dz_ring[NUM_DEVS_DZ];
|
|
struct _buffer dz_recv[NUM_DEVS_DZ];
|
|
TMLN dz_ldsc[DZ11_LINES] = { 0 }; /* Line descriptors */
|
|
TMXR dz_desc = { DZ11_LINES, 0, 0, dz_ldsc };
|
|
extern int32 tmxr_poll;
|
|
|
|
int dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
|
|
int dz_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
|
|
t_stat dz_svc (UNIT *uptr);
|
|
t_stat dz_reset (DEVICE *dptr);
|
|
void dz_checkirq(struct pdp_dib *dibp);
|
|
uint16 dz_vect(struct pdp_dib *dibp);
|
|
t_stat dz_set_modem (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat dz_show_modem (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
t_stat dz_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat dz_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat dz_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
t_stat dz_attach (UNIT *uptr, CONST char *cptr);
|
|
t_stat dz_detach (UNIT *uptr);
|
|
t_stat dz_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
|
const char *cptr);
|
|
const char *dz_description (DEVICE *dptr);
|
|
DIB dz_dib = { 0760000, 077, 0340, 5, 3, &dz_read, &dz_write, 0, 0, 0 };
|
|
|
|
UNIT dz_unit = {
|
|
UDATA (&dz_svc, TT_MODE_7B+UNIT_IDLE+UNIT_DISABLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT
|
|
};
|
|
|
|
REG dz_reg[] = {
|
|
{ DRDATA (TIME, dz_unit.wait, 24), REG_NZ + PV_LEFT },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB dz_mod[] = {
|
|
{ TT_MODE, TT_MODE_KSR, "KSR", "KSR", NULL },
|
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
|
|
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
|
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
|
|
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
|
|
NULL, "Sets address of DZ11" },
|
|
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect,
|
|
NULL, "Sets vect of DZ11" },
|
|
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br,
|
|
NULL, "Sets br of DZ11" },
|
|
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
|
|
NULL, "Sets uba of DZ11" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
|
&tmxr_dscln, NULL, &dz_desc, "Disconnect a specific line" },
|
|
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
|
NULL, &tmxr_show_summ, (void *) &dz_desc, "Display a summary of line states" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
|
NULL, &tmxr_show_cstat, (void *) &dz_desc, "Display current connections" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
|
NULL, &tmxr_show_cstat, (void *) &dz_desc, "Display multiplexer statistics" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n",
|
|
&dz_setnl, &tmxr_show_lines, (void *) &dz_desc, "Set number of lines" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file",
|
|
&dz_set_log, NULL, (void *)&dz_desc },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG",
|
|
&dz_set_nolog, NULL, (void *)&dz_desc, "Disable logging on designated line" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL,
|
|
NULL, &dz_show_log, (void *)&dz_desc, "Display logging for all lines" },
|
|
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE dz_dev = {
|
|
"DZ", &dz_unit, dz_reg, dz_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
&tmxr_ex, &tmxr_dep, &dz_reset,
|
|
NULL, &dz_attach, &dz_detach,
|
|
&dz_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, &dz_help, NULL, NULL, &dz_description
|
|
};
|
|
|
|
|
|
int
|
|
dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
|
|
{
|
|
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
|
|
int base;
|
|
uint16 temp;
|
|
int ln;
|
|
TMLN *lp;
|
|
int i;
|
|
|
|
if ((dptr->flags & DEV_DIS) != 0)
|
|
return 1;
|
|
if ((dptr->units[0].flags & UNIT_DIS) != 0)
|
|
return 1;
|
|
addr &= dibp->uba_mask;
|
|
if (addr < 010 || addr > 047)
|
|
return 1;
|
|
base = ((addr & 070) - 010) >> 3;
|
|
if (((base + 1) * 8) > dz_desc.lines)
|
|
return 1;
|
|
sim_debug(DEBUG_DETAIL, dptr, "DZ%o write %06o %06o %o\n", base,
|
|
addr, data, access);
|
|
|
|
switch (addr & 06) {
|
|
case 0:
|
|
if (access == BYTE) {
|
|
temp = dz_csr[base];
|
|
if (addr & 1)
|
|
data = data | (temp & 0377);
|
|
else
|
|
data = (temp & 0177400) | data;
|
|
}
|
|
if (data & CLR) {
|
|
dz_csr[base] = 0;
|
|
dz_recv[base].in_ptr = dz_recv[base].out_ptr = 0;
|
|
dz_recv[base].len = 0;
|
|
/* Set up the current status */
|
|
ln = base << 3;
|
|
for (i = 0; i < 8; i++) {
|
|
dz_flags[ln + i] &= ~LINE_EN;
|
|
}
|
|
return 0;
|
|
}
|
|
dz_csr[base] &= ~(TIE|SAE|RIE|MSE|CLR|MAINT);
|
|
dz_csr[base] |= data & (TIE|SAE|RIE|MSE|MAINT);
|
|
if (((dz_csr[base] & (RDONE|RIE)) == (RDONE|RIE)) ||
|
|
(dz_csr[base] & (SA|SAE)) == (SA|SAE))
|
|
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
|
|
else
|
|
uba_clr_irq(dibp, dibp->uba_vect + (010 * base));
|
|
if ((dz_csr[base] & (TRDY|TIE)) == (TRDY|TIE))
|
|
uba_set_irq(dibp, dibp->uba_vect + 4 + (010 * base));
|
|
else
|
|
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
|
|
break;
|
|
|
|
case 2:
|
|
ln = (data & 07) + (base << 3);
|
|
dz_ldsc[ln].rcve = (data & RXON) != 0;
|
|
break;
|
|
|
|
case 4:
|
|
temp = 0;
|
|
ln = base << 3;
|
|
/* Set up the current status */
|
|
for (i = 0; i < 8; i++) {
|
|
if (dz_flags[ln + i] & LINE_EN)
|
|
temp |= LINE_ENB << i;
|
|
if (dz_flags[ln + i] & DTR_FLAG)
|
|
temp |= DTR << i;
|
|
dz_flags[ln + i] = 0;
|
|
}
|
|
if (access == BYTE) {
|
|
if (addr & 1)
|
|
data = data | (temp & 0377);
|
|
else
|
|
data = (temp & 0177400) | data;
|
|
}
|
|
dz_csr[base] &= ~(TRDY);
|
|
for (i = 0; i < 8; i++) {
|
|
lp = &dz_ldsc[ln + i];
|
|
if ((data & (LINE_ENB << i)) != 0)
|
|
dz_flags[ln + i] |= LINE_EN;
|
|
if ((data & (DTR << i)) != 0)
|
|
dz_flags[ln + i] |= DTR_FLAG;
|
|
if (dz_flags[ln + i] & DTR_FLAG)
|
|
tmxr_set_get_modem_bits(lp, TMXR_MDM_OUTGOING, 0, NULL);
|
|
else
|
|
tmxr_set_get_modem_bits(lp, 0, TMXR_MDM_OUTGOING, NULL);
|
|
sim_debug(DEBUG_EXP, dptr, "DZ%o sstatus %07o %o %o\n", base, data, i, dz_flags[ln+i]);
|
|
}
|
|
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
|
|
break;
|
|
|
|
case 6:
|
|
if (access == BYTE && (addr & 1) != 0) {
|
|
break;
|
|
}
|
|
|
|
if ((dz_csr[base] & TRDY) == 0)
|
|
break;
|
|
|
|
ln = ((dz_csr[base] & TLINE) >> TLINE_V) + (base << 3);
|
|
lp = &dz_ldsc[ln];
|
|
|
|
if ((dz_flags[ln] & LINE_EN) != 0 && lp->conn) {
|
|
int32 ch = data & 0377;
|
|
t_stat r;
|
|
ch = sim_tt_outcvt(ch, TT_GET_MODE (dz_unit.flags) | TTUF_KSR);
|
|
/* Try and send character */
|
|
r = tmxr_putc_ln(lp, ch);
|
|
/* If character did not send, queue it */
|
|
if (r == SCPE_STALL)
|
|
dz_xmit[ln] = TRDY | ch;
|
|
}
|
|
dz_csr[base] &= ~TRDY;
|
|
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
|
|
break;
|
|
}
|
|
|
|
dz_checkirq(dibp);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dz_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
|
|
{
|
|
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
|
|
int base;
|
|
uint16 temp;
|
|
int ln;
|
|
TMLN *lp;
|
|
int i;
|
|
|
|
if ((dptr->flags & DEV_DIS) != 0)
|
|
return 1;
|
|
if ((dptr->units[0].flags & UNIT_DIS) != 0)
|
|
return 1;
|
|
addr &= dibp->uba_mask;
|
|
if (addr < 010 || addr > 047)
|
|
return 1;
|
|
base = ((addr & 070) - 010) >> 3;
|
|
if (((base + 1) * 8) > dz_desc.lines)
|
|
return 1;
|
|
switch (addr & 06) {
|
|
case 0:
|
|
*data = dz_csr[base];
|
|
break;
|
|
|
|
case 2:
|
|
*data = 0;
|
|
if ((dz_csr[base] & MSE) == 0)
|
|
return 0;
|
|
dz_csr[base] &= ~(SA|RDONE);
|
|
uba_clr_irq(dibp, dibp->uba_vect + (010 * base));
|
|
if (!empty(&dz_recv[base])) {
|
|
*data = dz_recv[base].buff[dz_recv[base].out_ptr];
|
|
inco(&dz_recv[base]);
|
|
dz_recv[base].len = 0;
|
|
}
|
|
if (!empty(&dz_recv[base])) {
|
|
dz_csr[base] |= RDONE;
|
|
if (dz_csr[base] & RIE) {
|
|
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
temp = 0;
|
|
base <<= 3;
|
|
/* Set up the current status */
|
|
for (ln = 0; ln < 8; ln++) {
|
|
if (dz_flags[base + ln] & LINE_EN)
|
|
temp |= LINE_ENB << ln;
|
|
if (dz_flags[base + ln] & DTR_FLAG)
|
|
temp |= DTR << ln;
|
|
}
|
|
*data = temp;
|
|
break;
|
|
|
|
case 6:
|
|
temp = (uint16)dz_ring[base];
|
|
ln = base << 3;
|
|
for (i = 0; i < 8; i++) {
|
|
lp = &dz_ldsc[ln + i];
|
|
if (lp->conn)
|
|
temp |= CO << i;
|
|
}
|
|
dz_ring[base] = 0;
|
|
*data = temp;
|
|
break;
|
|
}
|
|
sim_debug(DEBUG_DETAIL, dptr, "DZ%o read %06o %06o %o\n", base,
|
|
addr, *data, access);
|
|
return 0;
|
|
}
|
|
|
|
/* Unit service */
|
|
t_stat dz_svc (UNIT *uptr)
|
|
{
|
|
int32 ln;
|
|
int base;
|
|
uint16 temp;
|
|
DEVICE *dptr = find_dev_from_unit (uptr);
|
|
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
|
|
TMLN *lp;
|
|
|
|
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
|
return SCPE_OK;
|
|
ln = tmxr_poll_conn (&dz_desc); /* look for connect */
|
|
if (ln >= 0) { /* got one? rcv enb*/
|
|
dz_ring[(ln & 030) >> 3] |= (1 << (ln & 7));
|
|
sim_debug(DEBUG_DETAIL, &dz_dev, "DZ line connect %d\n", ln);
|
|
dz_xmit[ln] = 0;
|
|
}
|
|
tmxr_poll_tx(&dz_desc);
|
|
tmxr_poll_rx(&dz_desc);
|
|
for (ln = 0; ln < dz_desc.lines; ln++) {
|
|
lp = &dz_ldsc[ln];
|
|
base = (ln >> 3) & 03;
|
|
if (dz_xmit[ln] != 0) {
|
|
/* Try and send character */
|
|
t_stat r = tmxr_putc_ln(lp, dz_xmit[ln] & 0377);
|
|
/* If character did not send, queue it */
|
|
if (r == SCPE_OK)
|
|
dz_xmit[ln] = 0;
|
|
}
|
|
/* If silo full, skip to next */
|
|
while (!full(&dz_recv[base])) {
|
|
int32 ch = tmxr_getc_ln(lp);
|
|
if ((ch & TMXR_VALID) != 0) {
|
|
if (ch & SCPE_BREAK) { /* break? */
|
|
temp = FRM_ERR;
|
|
} else {
|
|
ch = sim_tt_inpcvt (ch, TT_GET_MODE(dz_unit.flags) | TTUF_KSR);
|
|
temp = VALID | ((ln & 07) << RXLINE_V) | (uint16)(ch & RBUF);
|
|
}
|
|
dz_recv[base].buff[dz_recv[base].in_ptr] = temp;
|
|
inci(&dz_recv[base]);
|
|
dz_recv[base].len++;
|
|
dz_csr[base] |= RDONE;
|
|
if (dz_csr[base] & RIE)
|
|
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
|
|
if (dz_recv[base].len > 16) {
|
|
dz_csr[base] |= SA;
|
|
if (dz_csr[base] & SAE) {
|
|
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
|
|
}
|
|
}
|
|
sim_debug(DEBUG_DETAIL, dptr, "TTY recieve %d: %o\n", ln, ch);
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
dz_checkirq(dibp);
|
|
sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Check if a device has an IRQ event ready */
|
|
void
|
|
dz_checkirq(struct pdp_dib *dibp)
|
|
{
|
|
int i;
|
|
int ln;
|
|
int stop;
|
|
TMLN *lp;
|
|
|
|
for (i = 0; i < NUM_DEVS_DZ; i++) {
|
|
if ((dz_csr[i] & MSE) == 0)
|
|
continue;
|
|
ln = ((dz_csr[i] & TLINE) >> TLINE_V) + (i << 3);
|
|
stop = ln;
|
|
if ((dz_csr[i] & TRDY) == 0) {
|
|
/* See if there is another line ready */
|
|
do {
|
|
ln = (ln & 070) | ((ln + 1) & 07);
|
|
lp = &dz_ldsc[ln];
|
|
/* Connected and empty xmit_buffer */
|
|
if ((dz_flags[ln] & LINE_EN) != 0 && dz_xmit[ln] == 0) {
|
|
sim_debug(DEBUG_DETAIL, &dz_dev, "DZ line ready %o\n", ln);
|
|
|
|
dz_csr[i] &= ~(TRDY|TLINE);
|
|
dz_csr[i] |= TRDY | ((ln & 07) << TLINE_V);
|
|
if (dz_csr[i] & TIE) {
|
|
uba_set_irq(dibp, dibp->uba_vect + 4 + (010 * i));
|
|
}
|
|
break;
|
|
}
|
|
} while (ln != stop);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat
|
|
dz_reset (DEVICE *dptr)
|
|
{
|
|
int i;
|
|
|
|
if (dz_unit.flags & UNIT_ATT) /* if attached, */
|
|
sim_activate (&dz_unit, tmxr_poll); /* activate */
|
|
else
|
|
sim_cancel (&dz_unit); /* else stop */
|
|
for (i = 0; i < NUM_DEVS_DZ; i++) {
|
|
dz_csr[i] = 0;
|
|
dz_recv[i].in_ptr = dz_recv[i].out_ptr = 0;
|
|
dz_recv[i].len = 0;
|
|
dz_ring[i] = 0;
|
|
dz_xmit[i] = 0;
|
|
}
|
|
for (i = 0; i < DZ11_LINES; i++) {
|
|
dz_flags[i] = 0;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* SET LINES processor */
|
|
|
|
t_stat
|
|
dz_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
int32 newln, i, t;
|
|
t_stat r;
|
|
|
|
if (cptr == NULL)
|
|
return SCPE_ARG;
|
|
newln = (int32) get_uint (cptr, 10, DZ11_LINES, &r);
|
|
if ((r != SCPE_OK) || (newln == dz_desc.lines))
|
|
return r;
|
|
if ((newln == 0) || (newln > DZ11_LINES) || (newln % 8) != 0)
|
|
return SCPE_ARG;
|
|
if (newln < dz_desc.lines) {
|
|
for (i = newln - 1, t = 0; i < dz_desc.lines; i++)
|
|
t = t | dz_ldsc[i].conn;
|
|
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
|
|
return SCPE_OK;
|
|
for (i = newln - 1; i < dz_desc.lines; i++) {
|
|
if (dz_ldsc[i].conn) {
|
|
tmxr_linemsg (&dz_ldsc[i], "\r\nOperator disconnected line\r\n");
|
|
tmxr_send_buffered_data (&dz_ldsc[i]);
|
|
}
|
|
tmxr_detach_ln (&dz_ldsc[i]); /* completely reset line */
|
|
}
|
|
}
|
|
if (dz_desc.lines < newln)
|
|
memset (dz_ldsc + dz_desc.lines, 0, sizeof(*dz_ldsc)*(newln-dz_desc.lines));
|
|
dz_desc.lines = newln;
|
|
return dz_reset (&dz_dev); /* setup lines and auto config */
|
|
}
|
|
|
|
/* SET LOG processor */
|
|
|
|
t_stat
|
|
dz_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
t_stat r;
|
|
char gbuf[CBUFSIZE];
|
|
int32 ln;
|
|
|
|
if (cptr == NULL)
|
|
return SCPE_ARG;
|
|
cptr = get_glyph (cptr, gbuf, '=');
|
|
if ((cptr == NULL) || (*cptr == 0) || (gbuf[0] == 0))
|
|
return SCPE_ARG;
|
|
ln = (int32) get_uint (gbuf, 10, dz_desc.lines, &r);
|
|
if ((r != SCPE_OK) || (ln > dz_desc.lines))
|
|
return SCPE_ARG;
|
|
return tmxr_set_log (NULL, ln, cptr, desc);
|
|
}
|
|
|
|
/* SET NOLOG processor */
|
|
|
|
t_stat
|
|
dz_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
t_stat r;
|
|
int32 ln;
|
|
|
|
if (cptr == NULL)
|
|
return SCPE_ARG;
|
|
ln = (int32) get_uint (cptr, 10, dz_desc.lines, &r);
|
|
if ((r != SCPE_OK) || (ln > dz_desc.lines))
|
|
return SCPE_ARG;
|
|
return tmxr_set_nolog (NULL, ln, NULL, desc);
|
|
}
|
|
|
|
/* SHOW LOG processor */
|
|
|
|
t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
int32 i;
|
|
|
|
for (i = 0; i < dz_desc.lines; i++) {
|
|
fprintf (st, "line %d: ", i);
|
|
tmxr_show_log (st, NULL, i, desc);
|
|
fprintf (st, "\n");
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Attach routine */
|
|
|
|
t_stat
|
|
dz_attach (UNIT *uptr, CONST char *cptr)
|
|
{
|
|
t_stat reason;
|
|
|
|
reason = tmxr_attach (&dz_desc, uptr, cptr);
|
|
if (reason != SCPE_OK)
|
|
return reason;
|
|
sim_activate (uptr, tmxr_poll);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Detach routine */
|
|
|
|
t_stat
|
|
dz_detach (UNIT *uptr)
|
|
{
|
|
int32 i;
|
|
t_stat reason;
|
|
reason = tmxr_detach (&dz_desc, uptr);
|
|
for (i = 0; i < dz_desc.lines; i++)
|
|
dz_ldsc[i].rcve = 0;
|
|
sim_cancel (uptr);
|
|
return reason;
|
|
}
|
|
|
|
t_stat dz_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
|
{
|
|
fprintf (st, "DZ11 Terminal Interfaces\n\n");
|
|
fprintf (st, "Each DZ11 supports 8 serial lines. Up to 32 can be configured\n");
|
|
fprintf (st, " sim> SET DZ LINES=n set number of additional lines to n [8-32]\n\n");
|
|
fprintf (st, "Lines must be set in multiples of 8.\n");
|
|
fprintf (st, "The ATTACH command specifies the port to be used:\n\n");
|
|
tmxr_attach_help (st, dptr, uptr, flag, cptr);
|
|
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
|
|
fprintf (st, " mode input characters output characters\n\n");
|
|
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
|
|
fprintf (st, " to upper case, high-order bit cleared,\n");
|
|
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
|
|
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
|
|
fprintf (st, " non-printing characters suppressed\n");
|
|
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
|
|
fprintf (st, " 8B no changes no changes\n\n");
|
|
fprintf (st, "The default mode is 7P.\n");
|
|
fprintf (st, "Finally, each line supports output logging. The SET DZn LOG command enables\n");
|
|
fprintf (st, "logging on a line:\n\n");
|
|
fprintf (st, " sim> SET DZn LOG=filename log output of line n to filename\n\n");
|
|
fprintf (st, "The SET DZn NOLOG command disables logging and closes the open log file,\n");
|
|
fprintf (st, "if any.\n\n");
|
|
fprintf (st, "Once DZ is attached and the simulator is running, the terminals listen for\n");
|
|
fprintf (st, "connections on the specified port. They assume that the incoming connections\n");
|
|
fprintf (st, "are Telnet connections. The connections remain open until disconnected either\n");
|
|
fprintf (st, "by the Telnet client, a SET DZ DISCONNECT command, or a DETACH DC command.\n\n");
|
|
fprintf (st, "Other special commands:\n\n");
|
|
fprintf (st, " sim> SHOW DZ CONNECTIONS show current connections\n");
|
|
fprintf (st, " sim> SHOW DZ STATISTICS show statistics for active connections\n");
|
|
fprintf (st, " sim> SET DZn DISCONNECT disconnects the specified line.\n\n");
|
|
fprintf (st, "The DZ11 is a unibus device, various parameters can be changed on these devices\n");
|
|
fprintf (st, "\n The address of the device can be set with: \n");
|
|
fprintf (st, " sim> SET DZ ADDR=octal default address= 760000\n");
|
|
fprintf (st, "\n The interrupt vector can be set with: \n");
|
|
fprintf (st, " sim> SET DZ VECT=octal default 340\n");
|
|
fprintf (st, "\n The interrupt level can be set with: \n");
|
|
fprintf (st, " sim> SET DZ BR=# # should be between 4 and 7.\n");
|
|
fprintf (st, "\n The unibus addaptor that the DZ is on can be set with:\n");
|
|
fprintf (st, " sim> SET DZ CTL=# # can be either 1 or 3\n");
|
|
fprint_reg_help (st, &dz_dev);
|
|
fprintf (st, "\nThe additional terminals do not support save and restore. All open connections\n");
|
|
fprintf (st, "are lost when the simulator shuts down or DZ is detached.\n");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *dz_description (DEVICE *dptr)
|
|
{
|
|
return "DZ11 asynchronous line interface";
|
|
}
|
|
|
|
#endif
|