PDP8: Add support for 16 terminals in the TTIX device

This commit is contained in:
Mark Pizzolato 2016-10-10 16:59:03 -07:00
parent cf1e7b9cca
commit 9c0b0ffb46
5 changed files with 303 additions and 133 deletions

View file

@ -1,6 +1,6 @@
/* pdp8_cpu.c: PDP-8 CPU simulator /* pdp8_cpu.c: PDP-8 CPU simulator
Copyright (c) 1993-2013, Robert M Supnik Copyright (c) 1993-2016, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
cpu central processor cpu central processor
18-Sep-16 RMS Added alternate dispatch table for non-contiguous devices
17-Sep-13 RMS Fixed boot in wrong field problem (Dave Gesswein) 17-Sep-13 RMS Fixed boot in wrong field problem (Dave Gesswein)
28-Apr-07 RMS Removed clock initialization 28-Apr-07 RMS Removed clock initialization
30-Oct-06 RMS Added idle and infinite loop detection 30-Oct-06 RMS Added idle and infinite loop detection
@ -229,6 +230,7 @@ int32 tsc_ir = 0; /* TSC8-75 IR */
int32 tsc_pc = 0; /* TSC8-75 PC */ int32 tsc_pc = 0; /* TSC8-75 PC */
int32 tsc_cdf = 0; /* TSC8-75 CDF flag */ int32 tsc_cdf = 0; /* TSC8-75 CDF flag */
int32 tsc_enb = 0; /* TSC8-75 enabled */ int32 tsc_enb = 0; /* TSC8-75 enabled */
int32 cpu_astop = 0; /* address stop */
int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */ int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */
@ -338,6 +340,12 @@ reason = 0;
while (reason == 0) { /* loop until halted */ while (reason == 0) { /* loop until halted */
if (cpu_astop != 0) {
cpu_astop = 0;
reason = SCPE_STOP;
break;
}
if (sim_interval <= 0) { /* check clock queue */ if (sim_interval <= 0) { /* check clock queue */
if ((reason = sim_process_event ())) if ((reason = sim_process_event ()))
break; break;
@ -1496,16 +1504,31 @@ for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */
dibp = (DIB *) dptr->ctxt; /* get DIB */ dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */
for (j = 0; j < dibp->num; j++) { /* loop thru disp */ if (dibp->dsp_tbl) { /* dispatch table? */
if (dibp->dsp[j]) { /* any dispatch? */ DIB_DSP *dspp = dibp->dsp_tbl; /* set ptr */
if (dev_tab[dibp->dev + j]) { /* already filled? */ for (j = 0; j < dibp->num; j++, dspp++) { /* loop thru tbl */
sim_printf ("%s device number conflict at %02o\n", if (dspp->dsp) { /* any dispatch? */
sim_dname (dptr), dibp->dev + j); if (dev_tab[dspp->dev]) { /* already filled? */
return TRUE; sim_printf ("%s device number conflict at %02o\n",
} sim_dname (dptr), dibp->dev + j);
dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ return TRUE;
} /* end if dsp */ }
} /* end for j */ dev_tab[dspp->dev] = dspp->dsp; /* fill */
} /* end if dsp */
} /* end for j */
} /* end if dsp_tbl */
else { /* inline dispatches */
for (j = 0; j < dibp->num; j++) { /* loop thru disp */
if (dibp->dsp[j]) { /* any dispatch? */
if (dev_tab[dibp->dev + j]) { /* already filled? */
sim_printf ("%s device number conflict at %02o\n",
sim_dname (dptr), dibp->dev + j);
return TRUE;
}
dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */
} /* end if dsp */
} /* end for j */
} /* end else */
} /* end if enb */ } /* end if enb */
} /* end for i */ } /* end for i */
return FALSE; return FALSE;

View file

@ -1,6 +1,6 @@
/* pdp8_defs.h: PDP-8 simulator definitions /* pdp8_defs.h: PDP-8 simulator definitions
Copyright (c) 1993-2013, Robert M Supnik Copyright (c) 1993-2016, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
18-Sep-16 RMS Added support for 16 additional terminals
18-Sep-13 RMS Added set_bootpc prototype 18-Sep-13 RMS Added set_bootpc prototype
18-Apr-12 RMS Removed separate timer for additional terminals; 18-Apr-12 RMS Removed separate timer for additional terminals;
Added clock_cosched prototype Added clock_cosched prototype
@ -88,10 +89,16 @@
#define DEV_MAXBLK 8 /* max dev block */ #define DEV_MAXBLK 8 /* max dev block */
#define DEV_MAX 64 /* total devices */ #define DEV_MAX 64 /* total devices */
typedef struct {
uint32 dev; /* device number */
int32 (*dsp)(int32 IR, int32 dat); /* dispatch */
} DIB_DSP;
typedef struct { typedef struct {
uint32 dev; /* base dev number */ uint32 dev; /* base dev number */
uint32 num; /* number of slots */ uint32 num; /* number of slots */
int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat); int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat);
DIB_DSP *dsp_tbl; /* optional table */
} DIB; } DIB;
/* Standard device numbers */ /* Standard device numbers */
@ -115,6 +122,41 @@ typedef struct {
#define DEV_DTA 076 /* TC08 */ #define DEV_DTA 076 /* TC08 */
#define DEV_TD8E 077 /* TD8E */ #define DEV_TD8E 077 /* TD8E */
/* Extra PTO8/KL8JA devices */
#define DEV_TTI1 040
#define DEV_TTO1 041
#define DEV_TTI2 042
#define DEV_TTO2 043
#define DEV_TTI3 044
#define DEV_TTO3 045
#define DEV_TTI4 046
#define DEV_TTO4 047
#define DEV_TTI5 034
#define DEV_TTO5 035
#define DEV_TTI6 011
#define DEV_TTO6 012
#define DEV_TTI7 030
#define DEV_TTO7 031
#define DEV_TTI8 032
#define DEV_TTO8 033
#define DEV_TTI9 050
#define DEV_TTO9 051
#define DEV_TTI10 052
#define DEV_TTO10 053
#define DEV_TTI11 054
#define DEV_TTO11 055 /* conflict: FPP */
#define DEV_TTI12 056 /* conflict: FPP */
#define DEV_TTO12 057
#define DEV_TTI13 070 /* conflict: CT, MT */
#define DEV_TTO13 071
#define DEV_TTI14 036 /* conflict: TSC */
#define DEV_TTO14 037
#define DEV_TTI15 072
#define DEV_TTO15 073
#define DEV_TTI16 006
#define DEV_TTO16 007
/* Interrupt flags /* Interrupt flags
The interrupt flags consist of three groups: The interrupt flags consist of three groups:
@ -145,13 +187,13 @@ typedef struct {
#define INT_V_TTI (INT_V_START+4) /* keyboard */ #define INT_V_TTI (INT_V_START+4) /* keyboard */
#define INT_V_CLK (INT_V_START+5) /* clock */ #define INT_V_CLK (INT_V_START+5) /* clock */
#define INT_V_TTO1 (INT_V_START+6) /* tto1 */ #define INT_V_TTO1 (INT_V_START+6) /* tto1 */
#define INT_V_TTO2 (INT_V_START+7) /* tto2 */ //#define INT_V_TTO2 (INT_V_START+7) /* tto2 */
#define INT_V_TTO3 (INT_V_START+8) /* tto3 */ //#define INT_V_TTO3 (INT_V_START+8) /* tto3 */
#define INT_V_TTO4 (INT_V_START+9) /* tto4 */ //#define INT_V_TTO4 (INT_V_START+9) /* tto4 */
#define INT_V_TTI1 (INT_V_START+10) /* tti1 */ #define INT_V_TTI1 (INT_V_START+10) /* tti1 */
#define INT_V_TTI2 (INT_V_START+11) /* tti2 */ //#define INT_V_TTI2 (INT_V_START+11) /* tti2 */
#define INT_V_TTI3 (INT_V_START+12) /* tti3 */ //#define INT_V_TTI3 (INT_V_START+12) /* tti3 */
#define INT_V_TTI4 (INT_V_START+13) /* tti4 */ //#define INT_V_TTI4 (INT_V_START+13) /* tti4 */
#define INT_V_DIRECT (INT_V_START+14) /* direct start */ #define INT_V_DIRECT (INT_V_START+14) /* direct start */
#define INT_V_RX (INT_V_DIRECT+0) /* RX8E */ #define INT_V_RX (INT_V_DIRECT+0) /* RX8E */
#define INT_V_RK (INT_V_DIRECT+1) /* RK8E */ #define INT_V_RK (INT_V_DIRECT+1) /* RK8E */
@ -177,13 +219,13 @@ typedef struct {
#define INT_TTI (1 << INT_V_TTI) #define INT_TTI (1 << INT_V_TTI)
#define INT_CLK (1 << INT_V_CLK) #define INT_CLK (1 << INT_V_CLK)
#define INT_TTO1 (1 << INT_V_TTO1) #define INT_TTO1 (1 << INT_V_TTO1)
#define INT_TTO2 (1 << INT_V_TTO2) //#define INT_TTO2 (1 << INT_V_TTO2)
#define INT_TTO3 (1 << INT_V_TTO3) //#define INT_TTO3 (1 << INT_V_TTO3)
#define INT_TTO4 (1 << INT_V_TTO4) //#define INT_TTO4 (1 << INT_V_TTO4)
#define INT_TTI1 (1 << INT_V_TTI1) #define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTI2 (1 << INT_V_TTI2) //#define INT_TTI2 (1 << INT_V_TTI2)
#define INT_TTI3 (1 << INT_V_TTI3) //#define INT_TTI3 (1 << INT_V_TTI3)
#define INT_TTI4 (1 << INT_V_TTI4) //#define INT_TTI4 (1 << INT_V_TTI4)
#define INT_RX (1 << INT_V_RX) #define INT_RX (1 << INT_V_RX)
#define INT_RK (1 << INT_V_RK) #define INT_RK (1 << INT_V_RK)
#define INT_RF (1 << INT_V_RF) #define INT_RF (1 << INT_V_RF)
@ -202,8 +244,7 @@ typedef struct {
#define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */ #define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */
#define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */ #define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */
#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \ #define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \
(INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \ (INT_TTI1+INT_TTO1)
(INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4)
#define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING) #define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING)
#define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable)) #define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable))

View file

@ -1,6 +1,6 @@
/* pdp8_tt.c: PDP-8 console terminal simulator /* pdp8_tt.c: PDP-8 console terminal simulator
Copyright (c) 1993-2012, Robert M Supnik Copyright (c) 1993-2016, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -74,7 +74,7 @@ REG tti_reg[] = {
{ FLDATAD (ENABLE, int_enable, INT_V_TTI, "interrupt enable flag") }, { FLDATAD (ENABLE, int_enable, INT_V_TTI, "interrupt enable flag") },
{ FLDATAD (INT, int_req, INT_V_TTI, "interrupt pending flag") }, { FLDATAD (INT, int_req, INT_V_TTI, "interrupt pending flag") },
{ DRDATAD (POS, tti_unit.pos, T_ADDR_W, "number of characters input"), PV_LEFT }, { DRDATAD (POS, tti_unit.pos, T_ADDR_W, "number of characters input"), PV_LEFT },
{ DRDATAD (TIME, tti_unit.wait, 24, "input polling interval (if 0, the keyboard is polled synchronously with the clock)"), PV_LEFT }, { DRDATAD (TIME, tti_unit.wait, 24, "input polling interval (if 0, the keyboard is polled synchronously with the clock)"), PV_LEFT+REG_NZ },
{ NULL } { NULL }
}; };

View file

@ -1,6 +1,6 @@
/* pdp8_ttx.c: PDP-8 additional terminals simulator /* pdp8_ttx.c: PDP-8 additional terminals simulator
Copyright (c) 1993-2013, Robert M Supnik Copyright (c) 1993-2016, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
ttix,ttox PT08/KL8JA terminal input/output ttix,ttox PT08/KL8JA terminal input/output
18-Sep-16 RMS Expanded support to 16 terminals
11-Oct-13 RMS Poll TTIX immediately to pick up initial connect (Mark Pizzolato) 11-Oct-13 RMS Poll TTIX immediately to pick up initial connect (Mark Pizzolato)
18-Apr-12 RMS Revised to use clock coscheduling 18-Apr-12 RMS Revised to use clock coscheduling
19-Nov-08 RMS Revised for common TMXR show routines 19-Nov-08 RMS Revised for common TMXR show routines
@ -45,10 +46,15 @@
30-Dec-01 RMS Complete rebuild 30-Dec-01 RMS Complete rebuild
30-Nov-01 RMS Added extended SET/SHOW support 30-Nov-01 RMS Added extended SET/SHOW support
This module implements four individual serial interfaces similar in function This module implements 1-16 individual serial interfaces similar in function
to the console. These interfaces are mapped to Telnet based connections as to the console. These interfaces are mapped to Telnet based connections as
though they were the four lines of a terminal multiplexor. The connection though they were the four lines of a terminal multiplexor. The connection
polling mechanism is superimposed onto the keyboard of the first interface. polling mechanism is superimposed onto the keyboard of the first interface.
The done and enable flags are maintained locally, and only a master interrupt
request is maintained in global register dev_done. Because this is actually
an interrupt request flag, the corresponding bit in int_enable must always
be set to 1.
*/ */
#include "pdp8_defs.h" #include "pdp8_defs.h"
@ -56,29 +62,44 @@
#include "sim_tmxr.h" #include "sim_tmxr.h"
#include <ctype.h> #include <ctype.h>
#define TTX_LINES 4 #define TTX_MAXL 16
#define TTX_MASK (TTX_LINES - 1) #define TTX_INIL 4
#define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK)
extern int32 int_req, int_enable, dev_done, stop_inst; extern int32 int_req, int_enable, dev_done, stop_inst;
extern int32 tmxr_poll; extern int32 tmxr_poll;
uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ uint32 ttix_done = 0; /* input ready flags */
uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ uint32 ttox_done = 0; /* output ready flags */
int32 ttx_tps = 100; /* polls per second */ uint32 ttx_enbl = 0; /* intr enable flags */
TMLN ttx_ldsc[TTX_LINES] = { {0} }; /* line descriptors */ uint8 ttix_buf[TTX_MAXL] = { 0 }; /* input buffers */
TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */ uint8 ttox_buf[TTX_MAXL] = { 0 }; /* output buffers */
TMLN ttx_ldsc[TTX_MAXL] = { {0} }; /* line descriptors */
TMXR ttx_desc = { TTX_INIL, 0, 0, ttx_ldsc }; /* mux descriptor */
#define ttx_lines ttx_desc.lines
int32 ttix (int32 IR, int32 AC); int32 ttix (int32 IR, int32 AC);
int32 ttox (int32 IR, int32 AC); int32 ttox (int32 IR, int32 AC);
t_stat ttix_svc (UNIT *uptr); t_stat ttix_svc (UNIT *uptr);
t_stat ttix_reset (DEVICE *dptr);
t_stat ttox_svc (UNIT *uptr); t_stat ttox_svc (UNIT *uptr);
t_stat ttox_reset (DEVICE *dptr); int32 ttx_getln (int32 inst);
void ttx_new_flags (uint32 newi, uint32 newo, uint32 newe);
t_stat ttx_reset (DEVICE *dptr);
t_stat ttx_attach (UNIT *uptr, CONST char *cptr); t_stat ttx_attach (UNIT *uptr, CONST char *cptr);
t_stat ttx_detach (UNIT *uptr); t_stat ttx_detach (UNIT *uptr);
void ttx_enbdis (int32 dis); void ttx_reset_ln (int32 i);
t_stat ttx_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
#define TTIX_SET_DONE(ln) ttx_new_flags (ttix_done | (1u << (ln)), ttox_done, ttx_enbl)
#define TTIX_CLR_DONE(ln) ttx_new_flags (ttix_done & ~(1u << (ln)), ttox_done, ttx_enbl)
#define TTIX_TST_DONE(ln) ((ttix_done & (1u << (ln))) != 0)
#define TTOX_SET_DONE(ln) ttx_new_flags (ttix_done, ttox_done | (1u << (ln)), ttx_enbl)
#define TTOX_CLR_DONE(ln) ttx_new_flags (ttix_done, ttox_done & ~(1u << (ln)), ttx_enbl)
#define TTOX_TST_DONE(ln) ((ttox_done & (1u << (ln))) != 0)
#define TTX_SET_ENBL(ln) ttx_new_flags (ttix_done, ttox_done, ttx_enbl | (1u << (ln)))
#define TTX_CLR_ENBL(ln) ttx_new_flags (ttix_done, ttox_done, ttx_enbl & ~(1u << (ln)))
#define TTX_TST_ENBL(ln) ((ttx_enbl & (1u << (ln))) != 0)
/* TTIx data structures /* TTIx data structures
@ -88,23 +109,43 @@ void ttx_enbdis (int32 dis);
ttix_mod TTIx modifiers list ttix_mod TTIx modifiers list
*/ */
DIB ttix_dib = { DEV_KJ8, 8, DIB_DSP ttx_dsp[TTX_MAXL * 2] = {
{ &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } }; { DEV_TTI1, &ttix }, { DEV_TTO1, &ttox },
{ DEV_TTI2, &ttix }, { DEV_TTO2, &ttox },
{ DEV_TTI3, &ttix }, { DEV_TTO3, &ttox },
{ DEV_TTI4, &ttix }, { DEV_TTO4, &ttox },
{ DEV_TTI5, &ttix }, { DEV_TTO5, &ttox },
{ DEV_TTI6, &ttix }, { DEV_TTO6, &ttox },
{ DEV_TTI7, &ttix }, { DEV_TTO7, &ttox },
{ DEV_TTI8, &ttix }, { DEV_TTO8, &ttox },
{ DEV_TTI9, &ttix }, { DEV_TTO9, &ttox },
{ DEV_TTI10, &ttix }, { DEV_TTO10, &ttox },
{ DEV_TTI11, &ttix }, { DEV_TTO11, &ttox },
{ DEV_TTI12, &ttix }, { DEV_TTO12, &ttox },
{ DEV_TTI13, &ttix }, { DEV_TTO13, &ttox },
{ DEV_TTI14, &ttix }, { DEV_TTO14, &ttox },
{ DEV_TTI15, &ttix }, { DEV_TTO15, &ttox },
{ DEV_TTI16, &ttix }, { DEV_TTO16, &ttox }
};
DIB ttx_dib = { DEV_TTI1, TTX_INIL * 2, { &ttix, &ttox }, ttx_dsp };
UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_IDLE|UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_IDLE|UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
REG ttix_reg[] = { REG ttix_reg[] = {
{ BRDATAD (BUF, ttix_buf, 8, 8, TTX_LINES, "input buffer, lines 0 to 3") }, { BRDATAD (BUF, ttix_buf, 8, 8, TTX_MAXL, "input buffer, lines 0 to 15") },
{ GRDATAD (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1, "device done flag (line 0 rightmost)") }, { ORDATAD (DONE, ttix_done, TTX_MAXL, "device done flag (line 0 rightmost)") },
{ GRDATAD (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1, "interrupt enable flag") }, { ORDATAD (ENABLE, ttx_enbl, TTX_MAXL, "interrupt enable flag") },
{ GRDATAD (INT, int_req, 8, TTX_LINES, INT_V_TTI1, "interrupt pending flag") }, { FLDATA (SUMDONE, dev_done, INT_V_TTI1), REG_HRO },
{ FLDATA (SUMENABLE, int_enable, INT_V_TTI1), REG_HRO },
{ DRDATAD (TIME, ttix_unit.wait, 24, "initial polling interval"), REG_NZ + PV_LEFT }, { DRDATAD (TIME, ttix_unit.wait, 24, "initial polling interval"), REG_NZ + PV_LEFT },
{ DRDATAD (TPS, ttx_tps, 10, "polls per second after calibration"), REG_NZ + PV_LEFT }, { DRDATA (LINES, ttx_desc.lines, 6), REG_HRO },
{ ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },
{ NULL } { NULL }
}; };
MTAB ttix_mod[] = { MTAB ttix_mod[] = {
{ MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
&ttx_vlines, &tmxr_show_lines, (void *) &ttx_desc },
{ UNIT_ATT, UNIT_ATT, "summary", NULL, { UNIT_ATT, UNIT_ATT, "summary", NULL,
NULL, &tmxr_show_summ, (void *) &ttx_desc }, NULL, &tmxr_show_summ, (void *) &ttx_desc },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
@ -113,8 +154,6 @@ MTAB ttix_mod[] = {
NULL, &tmxr_show_cstat, (void *) &ttx_desc }, NULL, &tmxr_show_cstat, (void *) &ttx_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &ttx_desc }, NULL, &tmxr_show_cstat, (void *) &ttx_desc },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } { 0 }
}; };
@ -137,9 +176,9 @@ DEBTAB ttx_debug[] = {
DEVICE ttix_dev = { DEVICE ttix_dev = {
"TTIX", &ttix_unit, ttix_reg, ttix_mod, "TTIX", &ttix_unit, ttix_reg, ttix_mod,
1, 10, 31, 1, 8, 8, 1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &ttix_reset, &tmxr_ex, &tmxr_dep, &ttx_reset,
NULL, &ttx_attach, &ttx_detach, NULL, &ttx_attach, &ttx_detach,
&ttix_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG, &ttx_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG,
0, ttx_debug 0, ttx_debug
}; };
@ -154,16 +193,29 @@ UNIT ttox_unit[] = {
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT }
}; };
REG ttox_reg[] = { REG ttox_reg[] = {
{ BRDATAD (BUF, ttox_buf, 8, 8, TTX_LINES, "last data item processed, lines 0 to 3") }, { BRDATAD (BUF, ttox_buf, 8, 8, TTX_MAXL, "last data item processed, lines 0 to 3") },
{ GRDATAD (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1, "device done flag (line 0 rightmost)") }, { ORDATAD (DONE, ttox_done, TTX_MAXL, "device done flag (line 0 rightmost)") },
{ GRDATAD (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1, "interrupt enable flag") }, { ORDATAD (ENABLE, ttx_enbl, TTX_MAXL, "interrupt enable flag") },
{ GRDATAD (INT, int_req, 8, TTX_LINES, INT_V_TTO1, "interrupt pending flag") }, { FLDATA (SUMDONE, dev_done, INT_V_TTO1), REG_HRO },
{ FLDATA (SUMENABLE, int_enable, INT_V_TTO1), REG_HRO },
{ URDATAD (TIME, ttox_unit[0].wait, 10, 24, 0, { URDATAD (TIME, ttox_unit[0].wait, 10, 24, 0,
TTX_LINES, PV_LEFT, "line from I/O initiation to interrupt, lines 0 to 3") }, TTX_MAXL, PV_LEFT, "line from I/O initiation to interrupt, lines 0 to 3") },
{ NULL } { NULL }
}; };
@ -183,8 +235,8 @@ MTAB ttox_mod[] = {
DEVICE ttox_dev = { DEVICE ttox_dev = {
"TTOX", ttox_unit, ttox_reg, ttox_mod, "TTOX", ttox_unit, ttox_reg, ttox_mod,
4, 10, 31, 1, 8, 8, TTX_MAXL, 10, 31, 1, 8, 8,
NULL, NULL, &ttox_reset, NULL, NULL, &ttx_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DEBUG, NULL, DEV_DISABLE | DEV_DEBUG,
0, ttx_debug 0, ttx_debug
@ -195,23 +247,22 @@ DEVICE ttox_dev = {
int32 ttix (int32 inst, int32 AC) int32 ttix (int32 inst, int32 AC)
{ {
int32 pulse = inst & 07; /* IOT pulse */ int32 pulse = inst & 07; /* IOT pulse */
int32 ln = TTX_GETLN (inst); /* line # */ int32 ln = ttx_getln (inst); /* line # */
int32 itti = (INT_TTI1 << ln); /* rx intr */
int32 itto = (INT_TTO1 << ln); /* tx intr */ if (ln < 0) /* bad line #? */
return (SCPE_IERR << IOT_V_REASON) | AC;
switch (pulse) { /* case IR<9:11> */ switch (pulse) { /* case IR<9:11> */
case 0: /* KCF */ case 0: /* KCF */
dev_done = dev_done & ~itti; /* clear flag */ TTIX_CLR_DONE (ln); /* clear flag */
int_req = int_req & ~itti;
break; break;
case 1: /* KSF */ case 1: /* KSF */
return (dev_done & itti)? IOT_SKP + AC: AC; return (TTIX_TST_DONE (ln))? IOT_SKP | AC: AC;
case 2: /* KCC */ case 2: /* KCC */
dev_done = dev_done & ~itti; /* clear flag */ TTIX_CLR_DONE (ln); /* clear flag */
int_req = int_req & ~itti;
sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */ sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */
return 0; /* clear AC */ return 0; /* clear AC */
@ -220,19 +271,17 @@ switch (pulse) { /* case IR<9:11> */
case 5: /* KIE */ case 5: /* KIE */
if (AC & 1) if (AC & 1)
int_enable = int_enable | (itti + itto); TTX_SET_ENBL (ln);
else int_enable = int_enable & ~(itti + itto); else TTX_CLR_ENBL (ln);
int_req = INT_UPDATE; /* update intr */
break; break;
case 6: /* KRB */ case 6: /* KRB */
dev_done = dev_done & ~itti; /* clear flag */ TTIX_CLR_DONE (ln); /* clear flag */
int_req = int_req & ~itti;
sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */ sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */
return ttix_buf[ln]; /* return buf */ return ttix_buf[ln]; /* return buf */
default: default:
return (stop_inst << IOT_V_REASON) + AC; return (stop_inst << IOT_V_REASON) | AC;
} /* end switch */ } /* end switch */
return AC; return AC;
@ -248,83 +297,63 @@ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK; return SCPE_OK;
sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */ sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ ln = tmxr_poll_conn (&ttx_desc); /* look for connect */
if (ln >= 0) /* got one? rcv enb*/ if (ln >= 0) /* got one? */
ttx_ldsc[ln].rcve = 1; ttx_ldsc[ln].rcve = 1; /* set rcv enable */
tmxr_poll_rx (&ttx_desc); /* poll for input */ tmxr_poll_rx (&ttx_desc); /* poll for input */
for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */ for (ln = 0; ln < ttx_lines; ln++) { /* loop thru lines */
if (ttx_ldsc[ln].conn) { /* connected? */ if (ttx_ldsc[ln].conn) { /* connected? */
if (dev_done & (INT_TTI1 << ln)) /* Last character still pending? */ if (TTIX_TST_DONE (ln)) /* last char still pending? */
continue; continue;
if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */ if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */
if (temp & SCPE_BREAK) /* break? */ if (temp & SCPE_BREAK) /* break? */
c = 0; c = 0;
else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags)); else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags));
ttix_buf[ln] = c; ttix_buf[ln] = c;
dev_done = dev_done | (INT_TTI1 << ln); TTIX_SET_DONE (ln); /* set flag */
int_req = INT_UPDATE;
} }
} }
} }
return SCPE_OK; return SCPE_OK;
} }
/* Reset routine */
t_stat ttix_reset (DEVICE *dptr)
{
int32 ln, itto;
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
if (ttix_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&ttix_unit, tmxr_poll); /* activate */
else sim_cancel (&ttix_unit); /* else stop */
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
ttix_buf[ln] = 0; /* clear buf, */
itto = (INT_TTI1 << ln); /* interrupt */
dev_done = dev_done & ~itto; /* clr done, int */
int_req = int_req & ~itto;
int_enable = int_enable | itto; /* set enable */
}
return SCPE_OK;
}
/* Terminal output: IOT routine */ /* Terminal output: IOT routine */
int32 ttox (int32 inst, int32 AC) int32 ttox (int32 inst, int32 AC)
{ {
int32 pulse = inst & 07; /* pulse */ int32 pulse = inst & 07; /* pulse */
int32 ln = TTX_GETLN (inst); /* line # */ int32 ln = ttx_getln (inst); /* line # */
int32 itti = (INT_TTI1 << ln); /* rx intr */
int32 itto = (INT_TTO1 << ln); /* tx intr */ if (ln < 0) /* bad line #? */
return (SCPE_IERR << IOT_V_REASON) | AC;
switch (pulse) { /* case IR<9:11> */ switch (pulse) { /* case IR<9:11> */
case 0: /* TLF */ case 0: /* TLF */
dev_done = dev_done | itto; /* set flag */ TTOX_SET_DONE (ln); /* set flag */
int_req = INT_UPDATE; /* update intr */
break; break;
case 1: /* TSF */ case 1: /* TSF */
return (dev_done & itto)? IOT_SKP + AC: AC; return (TTOX_TST_DONE (ln))? IOT_SKP | AC: AC;
case 2: /* TCF */ case 2: /* TCF */
dev_done = dev_done & ~itto; /* clear flag */ TTOX_CLR_DONE (ln); /* clear flag */
int_req = int_req & ~itto; /* clear intr */
break; break;
case 5: /* SPI */ case 5: /* SPI */
return (int_req & (itti | itto))? IOT_SKP + AC: AC; if ((TTIX_TST_DONE (ln) || TTOX_TST_DONE (ln)) /* either done set */
&& TTX_TST_ENBL (ln)) /* and enabled? */
return IOT_SKP | AC;
return AC;
case 6: /* TLS */ case 6: /* TLS */
dev_done = dev_done & ~itto; /* clear flag */ TTOX_CLR_DONE (ln); /* clear flag */
int_req = int_req & ~itto; /* clear int req */
case 4: /* TPC */ case 4: /* TPC */
sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */ sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */
ttox_buf[ln] = AC & 0377; /* load buffer */ ttox_buf[ln] = AC & 0377; /* load buffer */
break; break;
default: default:
return (stop_inst << IOT_V_REASON) + AC; return (stop_inst << IOT_V_REASON) | AC;
} /* end switch */ } /* end switch */
return AC; return AC;
@ -350,29 +379,82 @@ if (ttx_ldsc[ln].conn) { /* connected? */
return SCPE_OK; return SCPE_OK;
} }
} }
dev_done = dev_done | (INT_TTO1 << ln); /* set done */ TTOX_SET_DONE (ln); /* set done */
int_req = INT_UPDATE; /* update intr */
return SCPE_OK; return SCPE_OK;
} }
/* Flag routine
Global dev_done is used as a master interrupt; therefore, global
int_enable must always be set
*/
void ttx_new_flags (uint32 newidone, uint32 newodone, uint32 newenbl)
{
ttix_done = newidone;
ttox_done = newodone;
ttx_enbl = newenbl;
if ((ttix_done & ttx_enbl) != 0)
dev_done |= INT_TTI1;
else dev_done &= ~INT_TTI1;
if ((ttox_done & ttx_enbl) != 0)
dev_done |= INT_TTO1;
else dev_done &= ~INT_TTO1;
int_enable |= (INT_TTI1 | INT_TTO1);
int_req = INT_UPDATE;
return;
}
/* Compute relative line number, based on table of device numbers */
int32 ttx_getln (int32 inst)
{
int32 i;
int32 device = (inst >> 3) & 077; /* device = IR<3:8> */
for (i = 0; i < (ttx_lines * 2); i++) { /* loop thru disp tbl */
if (device == ttx_dsp[i].dev) /* dev # match? */
return (i >> 1); /* return line # */
}
return -1;
}
/* Reset routine */ /* Reset routine */
t_stat ttox_reset (DEVICE *dptr) t_stat ttx_reset (DEVICE *dptr)
{ {
int32 ln, itto; int32 ln;
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ if (dptr->flags & DEV_DIS) { /* sync enables */
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ ttix_dev.flags |= DEV_DIS;
ttox_buf[ln] = 0; /* clear buf */ ttox_dev.flags |= DEV_DIS;
itto = (INT_TTO1 << ln); /* interrupt */
dev_done = dev_done & ~itto; /* clr done, int */
int_req = int_req & ~itto;
int_enable = int_enable | itto; /* set enable */
sim_cancel (&ttox_unit[ln]); /* deactivate */
} }
else {
ttix_dev.flags &= ~DEV_DIS;
ttox_dev.flags &= ~DEV_DIS;
}
if (ttix_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&ttix_unit, tmxr_poll); /* activate */
else sim_cancel (&ttix_unit); /* else stop */
for (ln = 0; ln < TTX_MAXL; ln++) /* for all lines */
ttx_reset_ln (ln); /* reset line */
int_enable |= (INT_TTI1 | INT_TTO1); /* set master enable */
return SCPE_OK; return SCPE_OK;
} }
/* Reset line n */
void ttx_reset_ln (int32 ln)
{
uint32 mask = (1u << ln);
ttix_buf[ln] = 0; /* clr buf */
ttox_buf[ln] = 0; /* clr done, set enbl */
ttx_new_flags (ttix_done & ~mask, ttox_done & ~mask, ttx_enbl | mask);
sim_cancel (&ttox_unit[ln]); /* stop output */
return;
}
/* Attach master unit */ /* Attach master unit */
t_stat ttx_attach (UNIT *uptr, CONST char *cptr) t_stat ttx_attach (UNIT *uptr, CONST char *cptr)
@ -394,23 +476,47 @@ int32 i;
t_stat r; t_stat r;
r = tmxr_detach (&ttx_desc, uptr); /* detach */ r = tmxr_detach (&ttx_desc, uptr); /* detach */
for (i = 0; i < TTX_LINES; i++) /* all lines, */ for (i = 0; i < TTX_MAXL; i++) /* all lines, */
ttx_ldsc[i].rcve = 0; /* disable rcv */ ttx_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */ sim_cancel (uptr); /* stop poll */
return r; return r;
} }
/* Enable/disable device */ /* Change number of lines */
void ttx_enbdis (int32 dis) t_stat ttx_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{ {
if (dis) { int32 newln, i, t;
ttix_dev.flags = ttix_dev.flags | DEV_DIS; t_stat r;
ttox_dev.flags = ttox_dev.flags | DEV_DIS;
if (cptr == NULL)
return SCPE_ARG;
newln = get_uint (cptr, 10, TTX_MAXL, &r);
if ((r != SCPE_OK) || (newln == ttx_lines))
return r;
if (newln == 0)
return SCPE_ARG;
if (newln < ttx_lines) {
for (i = newln, t = 0; i < ttx_lines; i++)
t = t | ttx_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < ttx_lines; i++) {
if (ttx_ldsc[i].conn) {
tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&ttx_ldsc[i]); /* reset line */
}
ttox_unit[i].flags |= UNIT_DIS;
ttx_reset_ln (i);
}
} }
else { else {
ttix_dev.flags = ttix_dev.flags & ~DEV_DIS; for (i = ttx_lines; i < newln; i++) {
ttox_dev.flags = ttox_dev.flags & ~DEV_DIS; ttox_unit[i].flags &= ~UNIT_DIS;
ttx_reset_ln (i);
}
} }
return; ttx_lines = newln;
ttx_dib.num = newln * 2;
return SCPE_OK;
} }

Binary file not shown.