1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-22 18:41:11 +00:00

KA10: More WAITS fixes.

This commit is contained in:
Richard Cornwell 2019-06-18 18:50:16 -04:00
parent 9681d2ab1a
commit 930fc24f01
5 changed files with 577 additions and 56 deletions

View File

@ -2179,7 +2179,7 @@ int page_lookup_waits(int addr, int flag, int *loc, int wr, int cur_context, int
/* Figure out if this is a user space access */
if (flag)
uf = 0;
else if (xct_flag != 0 && !fetch) {
else if (xct_flag != 0 && !fetch && !uf) {
if (xct_flag & 010 && cur_context) /* Indirect */
uf = 1;
if (xct_flag & 004 && wr == 0) /* XR */
@ -2211,7 +2211,21 @@ int Mem_read_waits(int flag, int cur_context, int fetch) {
int addr;
if (AB < 020) {
MB = get_reg(AB);
int uf = (FLAGS & USER) != 0;
if (uf || flag || xct_flag == 0 || fetch) {
MB = get_reg(AB);
return 0;
}
if (xct_flag & 010 && cur_context) /* Indirect */
uf = 1;
if (xct_flag & 004) /* XR */
uf = 1;
if (xct_flag & 001 && BYF5) /* XW or XLB or XDB */
uf = 1;
if (uf)
MB = M[AB + Rl];
else
MB = get_reg(AB);
} else {
sim_interval--;
if (!page_lookup_waits(AB, flag, &addr, 0, cur_context, fetch))
@ -2237,7 +2251,19 @@ int Mem_write_waits(int flag, int cur_context) {
int addr;
if (AB < 020) {
set_reg(AB, MB);
int uf = (FLAGS & USER) != 0;
if (uf || xct_flag == 0) {
set_reg(AB, MB);
return 0;
}
if (xct_flag & 010 && cur_context) /* Indirect */
uf = 1;
if (xct_flag & 001 && BYF5) /* XW or XLB or XDB */
uf = 1;
if (uf)
M[AB + Rl] = MB;
else
set_reg(AB, MB);
} else {
sim_interval--;
if (!page_lookup_waits(AB, flag, &addr, 1, cur_context, 0))

View File

@ -62,10 +62,6 @@
#error "Please define only one type of CPU"
#endif
#ifndef PDP6_DEV /* Include PDP6 devices */
#define PDP6_DEV PDP6
#endif
#ifndef KI_22BIT
#define KI_22BIT KI|KL
#endif
@ -85,6 +81,11 @@
#define WAITS KA
#endif
#ifndef PDP6_DEV /* Include PDP6 devices */
#define PDP6_DEV PDP6|WAITS
#endif
/* MPX interrupt multiplexer for ITS systems */
#define MPX_DEV ITS
@ -374,6 +375,7 @@ extern DEVICE dct_dev; /* PDP6 devices. */
extern DEVICE dtc_dev;
extern DEVICE mtc_dev;
extern DEVICE dsk_dev;
extern DEVICE t630_dev;
extern t_stat (*dev_tab[128])(uint32 dev, t_uint64 *data);
@ -449,6 +451,7 @@ int auxcpu_write (int addr, t_uint64);
#define NUM_DEVS_DCT 2
#define NUM_DEVS_MTC 1
#define NUM_DEVS_DSK 1
#define NUM_DEVS_T630 1
#endif
#if !PDP6
#define NUM_DEVS_MT 1

View File

@ -505,8 +505,11 @@ pmp_devio(uint32 dev, uint64 *data) {
break;
}
}
if (pmp_cur_unit == NULL)
if (pmp_cur_unit == NULL) {
pmp_statusb &= ~REQ_CH;
if (pmp_statusb & CMD_LD)
pmp_startcmd();
}
}
}
if (*data & CLR_DATCH) /* Data chaining */
@ -531,10 +534,7 @@ pmp_devio(uint32 dev, uint64 *data) {
dev, *data, PC);
pmp_cmd_hold = (*data) & HOLD_MASK;
pmp_statusb |= CMD_LD;
if ((pmp_statusb & CMD_LD) != 0) {
if ((pmp_statusb & (IDLE_CH)) != 0)
pmp_startcmd();
}
pmp_startcmd();
(void)pmp_checkirq();
break;
}
@ -616,8 +616,8 @@ load:
if ((pmp_cnt & 03) == 0)
pmp_cnt |= BUFF_EMPTY;
} else {
if (pmp_cnt & 0x4) {
if ((pmp_cnt & 07) == 0x4) { /* Split byte */
if ((pmp_cnt & 0xf) > 0x3) {
if ((pmp_cnt & 0xf) == 0x4) { /* Split byte */
byte = (pmp_data << 4) & 0xf0;
if (pmp_cnt & BUFF_CHNEND) {
*data = byte;
@ -631,13 +631,13 @@ load:
xfer = 1; /* Read in a word */
byte |= pmp_data & 0xf;
} else {
byte = (pmp_data >> 4 + (8 * (8 - (pmp_cnt & 0x3)))) & 0xff;
byte = (pmp_data >> 4 + (8 * (8 - (pmp_cnt & 0xf)))) & 0xff;
}
} else {
byte = (pmp_data >> 4 + (8 * (3 - (pmp_cnt & 0x3)))) & 0xff;
byte = (pmp_data >> 4 + (8 * (3 - (pmp_cnt & 0xf)))) & 0xff;
}
pmp_cnt =(pmp_cnt + 1);
if ((pmp_cnt & 017) == 9) {
if ((pmp_cnt & 0xf) == 9) {
pmp_cnt = BUFF_EMPTY;
if (pmp_cnt & BUFF_CHNEND)
goto next;
@ -709,40 +709,40 @@ chan_write_byte(uint8 *data) {
if (pmp_addr >= (int)MEMSIZE)
return pmp_posterror(NXM_ERR);
M[pmp_addr] = pmp_data;
sim_debug(DEBUG_DATA, &pmp_dev, "chan_write %06o %012llo\n", pmp_addr, pmp_data);
sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo\n", pmp_addr, pmp_data);
pmp_addr++;
xfer = 1;
}
} else {
if (pmp_cnt & 0x4) {
if ((pmp_cnt & 07) == 0x4) { /* Split byte */
if ((pmp_cnt & 0xf) > 0x3) {
if ((pmp_cnt & 0xf) == 0x4) { /* Split byte */
pmp_data &= ~0xf;
pmp_data |= (uint64)((*data >> 4) & 0xf);
if (pmp_addr >= (int)MEMSIZE)
return pmp_posterror(NXM_ERR);
M[pmp_addr] = pmp_data;
sim_debug(DEBUG_DATA, &pmp_dev, "chan_write %06o %012llo %2x\n", pmp_addr, pmp_data, pmp_cnt);
sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo %2x\n", pmp_addr, pmp_data, pmp_cnt);
pmp_addr++;
xfer = 1; /* Read in a word */
pmp_data = *data & 0xf;
pmp_cnt |= BUFF_DIRTY;
} else {
pmp_data &= ~(0xff <<(4 + (8 * (8 - (pmp_cnt & 0x3)))));
pmp_data |= (uint64)(*data & 0xff) << (4 + (8 * (8 - (pmp_cnt & 0x3))));
pmp_data &= ~(0xff <<(4 + (8 * (8 - (pmp_cnt & 0xf)))));
pmp_data |= (uint64)(*data & 0xff) << (4 + (8 * (8 - (pmp_cnt & 0xf))));
pmp_cnt |= BUFF_DIRTY;
}
} else {
pmp_data &= ~(0xff <<(4 + (8 * (3 - (pmp_cnt & 0x3)))));
pmp_data |= (uint64)(*data & 0xff) << (4 + (8 * (3 - (pmp_cnt & 0x3))));
pmp_data &= ~(0xff <<(4 + (8 * (3 - (pmp_cnt & 0xf)))));
pmp_data |= (uint64)(*data & 0xff) << (4 + (8 * (3 - (pmp_cnt & 0xf))));
pmp_cnt |= BUFF_DIRTY;
}
pmp_cnt++;
if ((pmp_cnt & 017) == 9) {
if ((pmp_cnt & 0xf) == 9) {
pmp_cnt = BUFF_EMPTY;
if (pmp_addr >= (int)MEMSIZE)
return pmp_posterror(NXM_ERR);
M[pmp_addr] = pmp_data;
sim_debug(DEBUG_DATA, &pmp_dev, "chan_write %06o %012llo %2x\n", pmp_addr, pmp_data, pmp_cnt);
sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo %2x\n", pmp_addr, pmp_data, pmp_cnt);
pmp_addr++;
xfer = 1; /* Read in a word */
}
@ -813,19 +813,7 @@ chan_end(uint8 flags) {
return;
}
/* Otherwise if there is command chaining, try new command */
if (pmp_cmd & CMDCH_ON) {
/* Channel in operation, must be command chaining */
if (((pmp_cmd & SKP_MOD_OFF) != 0) && ((pmp_status & ST_MOD) == 0)) {
pmp_statusb &= ~(CMD_LD);
(void)pmp_checkirq();
return;
}
if (((pmp_cmd & SKP_MOD_ON) != 0) && ((pmp_status & ST_MOD) != 0)) {
pmp_statusb &= ~(CMD_LD);
(void)pmp_checkirq();
return;
}
pmp_startcmd();
(void)pmp_checkirq();
return;
@ -845,6 +833,7 @@ pmp_startcmd() {
int i;
int unit;
int cmd;
int old_cmd = pmp_cmd;
uint8 ch;
sim_debug(DEBUG_CMD, &pmp_dev, "start command %o\n", pmp_statusb);
@ -892,7 +881,7 @@ pmp_startcmd() {
/* Check if device busy */
if ((pmp_cur_unit->CMD & 0xff) != 0) {
sim_debug(DEBUG_CMD, &pmp_dev, "busy %o\n", pmp_statusb);
sim_debug(DEBUG_CMD, &pmp_dev, "busy %o\n", pmp_statusb);
if (pmp_statusb & IS_CH)
(void)pmp_posterror(SEL_ERR);
pmp_status |= UNU_END|BSY;
@ -903,7 +892,7 @@ pmp_startcmd() {
/* Copy over command */
if ((pmp_statusb & CMD_LD) != 0) {
pmp_cmd = pmp_cmd_hold;
sim_debug(DEBUG_CMD, &pmp_dev, "load %o\n", pmp_cmd);
sim_debug(DEBUG_CMD, &pmp_dev, "load %o\n", pmp_cmd);
pmp_statusb &= ~(CMD_LD);
if (pmp_statusb & WCMA_LD) {
pmp_statusb &= ~(WCMA_LD);
@ -912,6 +901,21 @@ pmp_startcmd() {
pmp_cnt = BUFF_EMPTY;
}
}
/* Otherwise if there is command chaining, try new command */
if (old_cmd & CMDCH_ON) {
/* Channel in operation, must be command chaining */
if (((old_cmd & SKP_MOD_OFF) != 0) && ((pmp_status & ST_MOD) == 0)) {
pmp_statusb &= ~(CMD_LD);
(void)pmp_checkirq();
return;
}
if (((old_cmd & SKP_MOD_ON) != 0) && ((pmp_status & ST_MOD) != 0)) {
pmp_statusb &= ~(CMD_LD);
(void)pmp_checkirq();
return;
}
}
sim_debug(DEBUG_CMD, &pmp_dev, "CMD unit=%d %02x %06o\n", unit, pmp_cmd, pmp_addr);
(void)pmp_checkirq();
@ -949,19 +953,21 @@ pmp_startcmd() {
return;
}
pmp_statusb &= ~IDLE_CH;
/* Issue the actual command */
switch (cmd & 0x3) {
case 0x3: /* Control */
if (cmd == DK_RELEASE) {
if (cmd == 0x3 || cmd == DK_RELEASE) {
pmp_status &= ~(STS_MASK);
pmp_status |= NEW_STS|CHN_END|DEV_END;
(void)pmp_checkirq();
return;
}
/* Fall Through */
case 0x1: /* Write command */
case 0x2: /* Read command */
pmp_statusb &= ~IDLE_CH;
pmp_cur_unit->CMD &= ~(DK_PARAM);
pmp_cur_unit->CMD |= cmd;
sim_debug(DEBUG_CMD, &pmp_dev, "CMD unit=%d CMD=%02x\n", unit, pmp_cur_unit->CMD);
@ -969,17 +975,19 @@ pmp_startcmd() {
case 0x0: /* Status */
if (cmd == 0x4) { /* Sense */
pmp_statusb &= ~IDLE_CH;
pmp_cur_unit->CMD |= cmd;
return;
}
break;
}
pmp_status &= ~(STS_MASK);
if (pmp_cur_unit->SENSE & 0xff)
pmp_status |= UNU_END|UNIT_CHK;
pmp_status |= NEW_STS|CHN_END|DEV_END;
pmp_statusb |= IDLE_CH;
pmp_statusb &= ~OP1;
sim_debug(DEBUG_CMD, &pmp_dev, "CMD unit=%d finish\n", unit);
sim_debug(DEBUG_CMD, &pmp_dev, "CMD unit=%d finish\n", unit);
(void)pmp_checkirq();
}
@ -1159,9 +1167,9 @@ index:
/* Check for end of track */
if ((rec[0] & rec[1] & rec[2] & rec[3]) == 0xff)
data->state = DK_POS_END;
sim_activate(uptr, 10);
sim_activate(uptr, 40);
} else
sim_activate(uptr, 1);
sim_activate(uptr, 10);
break;
case DK_POS_CNT: /* In count (c) */
data->tpos++;
@ -1180,9 +1188,9 @@ index:
data->state = DK_POS_KEY;
if (data->klen == 0)
data->state = DK_POS_DATA;
sim_activate(uptr, 20);
sim_activate(uptr, 50);
} else {
sim_activate(uptr, 1);
sim_activate(uptr, 10);
}
break;
case DK_POS_KEY: /* In Key area */
@ -1194,9 +1202,9 @@ index:
data->count = 0;
count = 0;
state = DK_POS_DATA;
sim_activate(uptr, 10);
sim_activate(uptr, 50);
} else {
sim_activate(uptr, 1);
sim_activate(uptr, 10);
}
break;
case DK_POS_DATA: /* In Data area */
@ -1205,9 +1213,9 @@ index:
sim_debug(DEBUG_EXP, dptr, "state data unit=%d %d %d\n", unit, data->rec,
data->count);
data->state = DK_POS_AM;
sim_activate(uptr, 10);
sim_activate(uptr, 50);
} else {
sim_activate(uptr, 1);
sim_activate(uptr, 10);
}
break;
case DK_POS_AM: /* Beginning of record */
@ -1222,7 +1230,7 @@ index:
/* Check for end of track */
if ((rec[0] & rec[1] & rec[2] & rec[3]) == 0xff)
data->state = DK_POS_END;
sim_activate(uptr, 20);
sim_activate(uptr, 60);
break;
case DK_POS_END: /* Past end of data */
data->tpos+=10;
@ -1378,8 +1386,9 @@ sense_end:
if ((uptr->POS >> 8) == data->cyl) {
uptr->LASTCMD = cmd;
uptr->CMD &= ~(0xff);
uptr->CMD |= DK_ATTN;
pmp_statusb |= REQ_CH;
// uptr->CMD |= DK_ATTN;
// pmp_statusb |= REQ_CH;
chan_end(SNS_DEVEND|SNS_CHNEND);
sim_debug(DEBUG_DETAIL, dptr, "seek end unit=%d %d %d %x\n", unit,
uptr->POS >> 8, data->cyl, data->state);
}
@ -1450,7 +1459,7 @@ sense_end:
uptr->CMD |= DK_PARAM;
data->state = DK_POS_SEEK;
sim_debug(DEBUG_DETAIL, dptr, "seek unit=%d doing\n", unit);
chan_end(SNS_CHNEND);
// chan_end(SNS_CHNEND);
} else {
pmp_adjpos(uptr);
uptr->LASTCMD = cmd;

View File

@ -141,6 +141,9 @@ DEVICE *sim_devices[] = {
#if (NUM_DEVS_DC > 0)
&dc_dev,
#endif
#if (NUM_DEVS_T630 > 0)
&t630_dev,
#endif
#if (NUM_DEVS_DK > 0)
&dk_dev,
#endif

480
PDP10/pdp6_dcs.c Normal file
View File

@ -0,0 +1,480 @@
/* pdp6_dcs.c: PDP-6 DC630 communication server simulator
Copyright (c) 2011-2017, 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 "ka10_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_T630
#define NUM_DEVS_T630 0
#endif
#if (NUM_DEVS_T630 > 0)
#define T630_DEVNUM 0300
#define T630_LINES 16
#define STATUS u3
#define RPI_CHN 000007 /* IN STATUS. */
#define TPI_CHN 000700 /* In STATUS */
#define RLS_SCN 000010 /* CONO DCSA release scanner */
#define RST_SCN 000020 /* CONO DCSA reset to 0 */
#define RSCN_ACT 000040 /* Scanner line is active */
#define XMT_RLS 004000 /* Clear transmitter flag */
#define XSCN_ACT 004000 /* Transmit scanner active */
#define DATA 0000377
#define LINE 0000077 /* Line number in Left */
int t630_rx_scan = 0; /* Scan counter */
int t630_tx_scan = 0; /* Scan counter */
int t630_send_line = 0; /* Send line number */
TMLN t630_ldsc[T630_LINES] = { 0 }; /* Line descriptors */
TMXR t630_desc = { T630_LINES, 0, 0, t630_ldsc };
uint32 t630_tx_enable, t630_rx_rdy; /* Flags */
uint32 t630_enable; /* Enable line */
uint32 t630_rx_conn; /* Connection flags */
extern int32 tmxr_poll;
t_stat t630_devio(uint32 dev, uint64 *data);
t_stat t630_svc (UNIT *uptr);
t_stat t630_doscan (UNIT *uptr);
t_stat t630_reset (DEVICE *dptr);
t_stat t630_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat t630_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat t630_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat t630_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat t630_attach (UNIT *uptr, CONST char *cptr);
t_stat t630_detach (UNIT *uptr);
t_stat t630_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *t630_description (DEVICE *dptr);
/* Type 630 data structures
t630_dev Type 630 device descriptor
t630_unit Type 630 unit descriptor
t630_reg Type 630 register list
*/
DIB t630_dib = { T630_DEVNUM, 2, &t630_devio, NULL };
UNIT t630_unit = {
UDATA (&t630_svc, TT_MODE_7B+UNIT_IDLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT
};
REG t630_reg[] = {
{ DRDATA (TIME, t630_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (STATUS, t630_unit.STATUS, 18), PV_LEFT },
{ NULL }
};
MTAB t630_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, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &t630_desc, "Disconnect a specific line" },
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
NULL, &tmxr_show_summ, (void *) &t630_desc, "Display a summary of line states" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &tmxr_show_cstat, (void *) &t630_desc, "Display current connections" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &t630_desc, "Display multiplexer statistics" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n",
&t630_setnl, &tmxr_show_lines, (void *) &t630_desc, "Set number of lines" },
{ MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file",
&t630_set_log, NULL, (void *)&t630_desc },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG",
&t630_set_nolog, NULL, (void *)&t630_desc, "Disable logging on designated line" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL,
NULL, &t630_show_log, (void *)&t630_desc, "Display logging for all lines" },
{ 0 }
};
DEVICE t630_dev = {
"DCS", &t630_unit, t630_reg, t630_mod,
1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &t630_reset,
NULL, &t630_attach, &t630_detach,
&t630_dib, DEV_NET | DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &t630_help, NULL, NULL, &t630_description
};
/* IOT routine */
t_stat t630_devio(uint32 dev, uint64 *data) {
UNIT *uptr = &t630_unit;
TMLN *lp;
int ln;
switch(dev & 7) {
case CONI:
/* Check if we might have any interrupts pending */
if ((uptr->STATUS & (RSCN_ACT|XSCN_ACT)) != 0)
t630_doscan(uptr);
*data = uptr->STATUS & (RPI_CHN|TPI_CHN);
if ((uptr->STATUS & (RSCN_ACT)) == 0)
*data |= 010LL;
if ((uptr->STATUS & (XSCN_ACT)) == 0)
*data |= 01000LL;
sim_debug(DEBUG_CONI, &t630_dev, "T630 %03o CONI %06o PC=%o\n",
dev, (uint32)*data, PC);
break;
case CONO:
/* Set PI */
uptr->STATUS &= ~(RPI_CHN|TPI_CHN);
uptr->STATUS |= (RPI_CHN|TPI_CHN) & *data;
if (*data & RST_SCN)
t630_rx_scan = 0;
if ((*data & (RLS_SCN|RST_SCN)) != 0)
uptr->STATUS |= RSCN_ACT;
if ((*data & (XSCN_ACT)) != 0)
uptr->STATUS |= XSCN_ACT;
sim_debug(DEBUG_CONO, &t630_dev, "T630 %03o CONO %06o PC=%06o\n",
dev, (uint32)*data, PC);
t630_doscan(uptr);
break;
case DATAO:
case DATAO|4:
ln = (dev & 4) ? t630_send_line : t630_tx_scan;
if (ln < t630_desc.lines) {
lp = &t630_ldsc[ln];
if (lp->conn) {
int32 ch = *data & DATA;
ch = sim_tt_outcvt(ch, TT_GET_MODE (t630_unit.flags) | TTUF_KSR);
tmxr_putc_ln (lp, ch);
t630_tx_enable |= (1 << ln);
}
}
if (dev & 4) {
uptr->STATUS |= XSCN_ACT;
t630_doscan(uptr);
}
sim_debug(DEBUG_DATAIO, &t630_dev, "DC %03o DATO %012llo PC=%06o\n",
dev, *data, PC);
break;
case DATAI:
case DATAI|4:
ln = t630_rx_scan;
if (ln < t630_desc.lines) {
/* Nothing happens if no recieve data, which is transmit ready */
lp = &t630_ldsc[ln];
if (tmxr_rqln (lp) > 0) {
int32 ch = tmxr_getc_ln (lp);
if (ch & SCPE_BREAK) /* break? */
ch = 0;
else
ch = sim_tt_inpcvt (ch, TT_GET_MODE(t630_unit.flags) | TTUF_KSR);
*data = (uint64)(ch & DATA);
t630_tx_enable &= ~(1 << ln);
}
t630_rx_rdy &= ~(1 << ln);
}
if (dev & 4) {
uptr->STATUS |= RSCN_ACT;
t630_doscan(uptr);
}
sim_debug(DEBUG_DATAIO, &t630_dev, "T630 %03o DATI %012llo PC=%06o\n",
dev, *data, PC);
break;
case CONI|4:
/* Read in scanner */
if ((uptr->STATUS & (RSCN_ACT)) != 0)
*data = (uint64)(t630_tx_scan);
else
*data = (uint64)(t630_rx_scan);
sim_debug(DEBUG_CONI, &t630_dev, "T630 %03o CONI %06o PC=%o recieve line\n",
dev, (uint32)*data, PC);
break;
case CONO|4:
/* Output buffer pointer */
t630_send_line = (int)(*data & 077);
sim_debug(DEBUG_CONO, &t630_dev, "T630 %03o CONO %06o PC=%06o send line\n",
dev, (uint32)*data, PC);
break;
}
return SCPE_OK;
}
/* Unit service */
t_stat t630_svc (UNIT *uptr)
{
int32 ln;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
ln = tmxr_poll_conn (&t630_desc); /* look for connect */
if (ln >= 0) { /* got one? rcv enb*/
t630_ldsc[ln].rcve = 1;
t630_tx_enable |= 1 << ln;
sim_debug(DEBUG_DETAIL, &t630_dev, "DC line connect %d\n", ln);
}
tmxr_poll_tx(&t630_desc);
tmxr_poll_rx(&t630_desc);
for (ln = 0; ln < t630_desc.lines; ln++) {
/* Check to see if any pending data for this line */
if (tmxr_rqln(&t630_ldsc[ln]) > 0) {
t630_rx_rdy |= (1 << ln);
sim_debug(DEBUG_DETAIL, &t630_dev, "DC recieve %d\n", ln);
}
/* Check if disconnect */
if ((t630_rx_conn & (1 << ln)) != 0 && t630_ldsc[ln].conn == 0) {
t630_tx_enable &= ~(1 << ln);
t630_rx_conn &= ~(1 << ln);
sim_debug(DEBUG_DETAIL, &t630_dev, "DC line disconnect %d\n", ln);
}
}
/* If any pending status request, raise the PI signal */
t630_doscan(uptr);
sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */
return SCPE_OK;
}
/* Scan to see if something to do */
t_stat t630_doscan (UNIT *uptr) {
uint32 lmask;
if ((uptr->STATUS & (RSCN_ACT|XSCN_ACT)) == 0)
return SCPE_OK;
clr_interrupt(T630_DEVNUM);
if ((uptr->STATUS & (RSCN_ACT)) != 0) {
for (;t630_rx_rdy != 0; t630_rx_scan++) {
t630_rx_scan &= 037;
/* Check if we found it */
if (t630_rx_rdy & (1 << t630_rx_scan)) {
uptr->STATUS &= ~RSCN_ACT;
/* Stop scanner */
set_interrupt(T630_DEVNUM, uptr->STATUS);
return SCPE_OK;
}
}
}
if ((uptr->STATUS & (XSCN_ACT)) != 0) {
for (;t630_tx_enable != 0; t630_tx_scan++) {
t630_tx_scan &= 037;
/* Check if we found it */
if (t630_tx_enable & (1 << t630_tx_scan)) {
uptr->STATUS &= ~XSCN_ACT;
/* Stop scanner */
set_interrupt(T630_DEVNUM, (uptr->STATUS >> 6));
return SCPE_OK;
}
}
}
return SCPE_OK;
}
/* Reset routine */
t_stat t630_reset (DEVICE *dptr)
{
if (t630_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&t630_unit, tmxr_poll); /* activate */
else
sim_cancel (&t630_unit); /* else stop */
t630_tx_enable = 0;
t630_rx_rdy = 0; /* Flags */
t630_rx_conn = 0;
t630_send_line = 0;
t630_tx_scan = 0;
t630_rx_scan = 0;
t630_unit.STATUS = 0;
clr_interrupt(T630_DEVNUM);
return SCPE_OK;
}
/* SET LINES processor */
t_stat t630_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, T630_LINES, &r);
if ((r != SCPE_OK) || (newln == t630_desc.lines))
return r;
if ((newln == 0) || (newln >= T630_LINES) || (newln % 8) != 0)
return SCPE_ARG;
if (newln < t630_desc.lines) {
for (i = newln, t = 0; i < t630_desc.lines; i++)
t = t | t630_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < t630_desc.lines; i++) {
if (t630_ldsc[i].conn) {
tmxr_linemsg (&t630_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_send_buffered_data (&t630_ldsc[i]);
}
tmxr_detach_ln (&t630_ldsc[i]); /* completely reset line */
}
}
if (t630_desc.lines < newln)
memset (t630_ldsc + t630_desc.lines, 0, sizeof(*t630_ldsc)*(newln-t630_desc.lines));
t630_desc.lines = newln;
return t630_reset (&t630_dev); /* setup lines and auto config */
}
/* SET LOG processor */
t_stat t630_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, t630_desc.lines, &r);
if ((r != SCPE_OK) || (ln >= t630_desc.lines))
return SCPE_ARG;
return tmxr_set_log (NULL, ln, cptr, desc);
}
/* SET NOLOG processor */
t_stat t630_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, t630_desc.lines, &r);
if ((r != SCPE_OK) || (ln >= t630_desc.lines))
return SCPE_ARG;
return tmxr_set_nolog (NULL, ln, NULL, desc);
}
/* SHOW LOG processor */
t_stat t630_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 i;
for (i = 0; i < t630_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 t630_attach (UNIT *uptr, CONST char *cptr)
{
t_stat reason;
reason = tmxr_attach (&t630_desc, uptr, cptr);
if (reason != SCPE_OK)
return reason;
sim_activate (uptr, tmxr_poll);
return SCPE_OK;
}
/* Detach routine */
t_stat t630_detach (UNIT *uptr)
{
int32 i;
t_stat reason;
reason = tmxr_detach (&t630_desc, uptr);
for (i = 0; i < t630_desc.lines; i++)
t630_ldsc[i].rcve = 0;
sim_cancel (uptr);
return reason;
}
t_stat t630_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "Type 630 Terminal Interfaces\n\n");
fprintf (st, "The Type 630 supported up to 8 blocks of 8 lines. Modem control was on a seperate\n");
fprintf (st, "line. The simulator supports this by setting modem control to a fixed offset\n");
fprintf (st, "from the given line. The number of lines is specified with a SET command:\n\n");
fprintf (st, " sim> SET DC 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 default offset for modem lines is 32. This can be changed with\n\n");
fprintf (st, " sim> SET DC MODEM=n set offset for modem control to n [8-32]\n\n");
fprintf (st, "Modem control must be set larger then the number of lines\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 DCn LOG command enables\n");
fprintf (st, "logging on a line:\n\n");
fprintf (st, " sim> SET DCn LOG=filename log output of line n to filename\n\n");
fprintf (st, "The SET DCn NOLOG command disables logging and closes the open log file,\n");
fprintf (st, "if any.\n\n");
fprintf (st, "Once DC 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 DC DISCONNECT command, or a DETACH DC command.\n\n");
fprintf (st, "Other special commands:\n\n");
fprintf (st, " sim> SHOW DC CONNECTIONS show current connections\n");
fprintf (st, " sim> SHOW DC STATISTICS show statistics for active connections\n");
fprintf (st, " sim> SET DCn DISCONNECT disconnects the specified line.\n");
fprint_reg_help (st, &t630_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 DC is detached.\n");
return SCPE_OK;
}
const char *t630_description (DEVICE *dptr)
{
return "Type 630 asynchronous line interface";
}
#endif