diff --git a/PDP10/ka10_cpu.c b/PDP10/ka10_cpu.c index 8e2ae7d..509e116 100644 --- a/PDP10/ka10_cpu.c +++ b/PDP10/ka10_cpu.c @@ -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)) diff --git a/PDP10/ka10_defs.h b/PDP10/ka10_defs.h index 4996143..6f6d786 100644 --- a/PDP10/ka10_defs.h +++ b/PDP10/ka10_defs.h @@ -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 diff --git a/PDP10/ka10_pmp.c b/PDP10/ka10_pmp.c index 5c27f35..66c234e 100644 --- a/PDP10/ka10_pmp.c +++ b/PDP10/ka10_pmp.c @@ -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; diff --git a/PDP10/ka10_sys.c b/PDP10/ka10_sys.c index 24f175d..47be316 100644 --- a/PDP10/ka10_sys.c +++ b/PDP10/ka10_sys.c @@ -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 diff --git a/PDP10/pdp6_dcs.c b/PDP10/pdp6_dcs.c new file mode 100644 index 0000000..f419873 --- /dev/null +++ b/PDP10/pdp6_dcs.c @@ -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