diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index 594fc047..463ec4c2 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -1,6 +1,6 @@ /* 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 copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ 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) 28-Apr-07 RMS Removed clock initialization 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_cdf = 0; /* TSC8-75 CDF flag */ int32 tsc_enb = 0; /* TSC8-75 enabled */ +int32 cpu_astop = 0; /* address stop */ int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ @@ -338,6 +340,12 @@ reason = 0; 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 ((reason = sim_process_event ())) 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 */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ - 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 */ + if (dibp->dsp_tbl) { /* dispatch table? */ + DIB_DSP *dspp = dibp->dsp_tbl; /* set ptr */ + for (j = 0; j < dibp->num; j++, dspp++) { /* loop thru tbl */ + if (dspp->dsp) { /* any dispatch? */ + if (dev_tab[dspp->dev]) { /* already filled? */ + sim_printf ("%s device number conflict at %02o\n", + sim_dname (dptr), dibp->dev + j); + return TRUE; + } + 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 for i */ return FALSE; diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 25c02dd3..3cc84227 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -1,6 +1,6 @@ /* 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 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 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-Apr-12 RMS Removed separate timer for additional terminals; Added clock_cosched prototype @@ -88,10 +89,16 @@ #define DEV_MAXBLK 8 /* max dev block */ #define DEV_MAX 64 /* total devices */ +typedef struct { + uint32 dev; /* device number */ + int32 (*dsp)(int32 IR, int32 dat); /* dispatch */ + } DIB_DSP; + typedef struct { uint32 dev; /* base dev number */ uint32 num; /* number of slots */ int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat); + DIB_DSP *dsp_tbl; /* optional table */ } DIB; /* Standard device numbers */ @@ -115,6 +122,41 @@ typedef struct { #define DEV_DTA 076 /* TC08 */ #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 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_CLK (INT_V_START+5) /* clock */ #define INT_V_TTO1 (INT_V_START+6) /* tto1 */ -#define INT_V_TTO2 (INT_V_START+7) /* tto2 */ -#define INT_V_TTO3 (INT_V_START+8) /* tto3 */ -#define INT_V_TTO4 (INT_V_START+9) /* tto4 */ +//#define INT_V_TTO2 (INT_V_START+7) /* tto2 */ +//#define INT_V_TTO3 (INT_V_START+8) /* tto3 */ +//#define INT_V_TTO4 (INT_V_START+9) /* tto4 */ #define INT_V_TTI1 (INT_V_START+10) /* tti1 */ -#define INT_V_TTI2 (INT_V_START+11) /* tti2 */ -#define INT_V_TTI3 (INT_V_START+12) /* tti3 */ -#define INT_V_TTI4 (INT_V_START+13) /* tti4 */ +//#define INT_V_TTI2 (INT_V_START+11) /* tti2 */ +//#define INT_V_TTI3 (INT_V_START+12) /* tti3 */ +//#define INT_V_TTI4 (INT_V_START+13) /* tti4 */ #define INT_V_DIRECT (INT_V_START+14) /* direct start */ #define INT_V_RX (INT_V_DIRECT+0) /* RX8E */ #define INT_V_RK (INT_V_DIRECT+1) /* RK8E */ @@ -177,13 +219,13 @@ typedef struct { #define INT_TTI (1 << INT_V_TTI) #define INT_CLK (1 << INT_V_CLK) #define INT_TTO1 (1 << INT_V_TTO1) -#define INT_TTO2 (1 << INT_V_TTO2) -#define INT_TTO3 (1 << INT_V_TTO3) -#define INT_TTO4 (1 << INT_V_TTO4) +//#define INT_TTO2 (1 << INT_V_TTO2) +//#define INT_TTO3 (1 << INT_V_TTO3) +//#define INT_TTO4 (1 << INT_V_TTO4) #define INT_TTI1 (1 << INT_V_TTI1) -#define INT_TTI2 (1 << INT_V_TTI2) -#define INT_TTI3 (1 << INT_V_TTI3) -#define INT_TTI4 (1 << INT_V_TTI4) +//#define INT_TTI2 (1 << INT_V_TTI2) +//#define INT_TTI3 (1 << INT_V_TTI3) +//#define INT_TTI4 (1 << INT_V_TTI4) #define INT_RX (1 << INT_V_RX) #define INT_RK (1 << INT_V_RK) #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_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */ #define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \ - (INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \ - (INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4) + (INT_TTI1+INT_TTO1) #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)) diff --git a/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index 539389b1..d0d30e5e 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -1,6 +1,6 @@ /* 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 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 (INT, int_req, INT_V_TTI, "interrupt pending flag") }, { 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 } }; diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index acf3da02..087294e8 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -1,6 +1,6 @@ /* 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 copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ 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) 18-Apr-12 RMS Revised to use clock coscheduling 19-Nov-08 RMS Revised for common TMXR show routines @@ -45,10 +46,15 @@ 30-Dec-01 RMS Complete rebuild 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 though they were the four lines of a terminal multiplexor. The connection 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" @@ -56,29 +62,44 @@ #include "sim_tmxr.h" #include -#define TTX_LINES 4 -#define TTX_MASK (TTX_LINES - 1) +#define TTX_MAXL 16 +#define TTX_INIL 4 #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) extern int32 int_req, int_enable, dev_done, stop_inst; extern int32 tmxr_poll; -uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ -uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ -int32 ttx_tps = 100; /* polls per second */ -TMLN ttx_ldsc[TTX_LINES] = { {0} }; /* line descriptors */ -TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */ +uint32 ttix_done = 0; /* input ready flags */ +uint32 ttox_done = 0; /* output ready flags */ +uint32 ttx_enbl = 0; /* intr enable flags */ +uint8 ttix_buf[TTX_MAXL] = { 0 }; /* input buffers */ +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 ttox (int32 IR, int32 AC); t_stat ttix_svc (UNIT *uptr); -t_stat ttix_reset (DEVICE *dptr); 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_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 @@ -88,23 +109,43 @@ void ttx_enbdis (int32 dis); ttix_mod TTIx modifiers list */ -DIB ttix_dib = { DEV_KJ8, 8, - { &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } }; +DIB_DSP ttx_dsp[TTX_MAXL * 2] = { + { 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 }; REG ttix_reg[] = { - { BRDATAD (BUF, ttix_buf, 8, 8, TTX_LINES, "input buffer, lines 0 to 3") }, - { GRDATAD (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1, "device done flag (line 0 rightmost)") }, - { GRDATAD (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1, "interrupt enable flag") }, - { GRDATAD (INT, int_req, 8, TTX_LINES, INT_V_TTI1, "interrupt pending flag") }, + { BRDATAD (BUF, ttix_buf, 8, 8, TTX_MAXL, "input buffer, lines 0 to 15") }, + { ORDATAD (DONE, ttix_done, TTX_MAXL, "device done flag (line 0 rightmost)") }, + { ORDATAD (ENABLE, ttx_enbl, TTX_MAXL, "interrupt enable 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 (TPS, ttx_tps, 10, "polls per second after calibration"), REG_NZ + PV_LEFT }, - { ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO }, + { DRDATA (LINES, ttx_desc.lines, 6), REG_HRO }, { NULL } }; MTAB ttix_mod[] = { + { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", + &ttx_vlines, &tmxr_show_lines, (void *) &ttx_desc }, { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tmxr_show_summ, (void *) &ttx_desc }, { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", @@ -113,8 +154,6 @@ MTAB ttix_mod[] = { NULL, &tmxr_show_cstat, (void *) &ttx_desc }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, (void *) &ttx_desc }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, { 0 } }; @@ -137,9 +176,9 @@ DEBTAB ttx_debug[] = { DEVICE ttix_dev = { "TTIX", &ttix_unit, ttix_reg, ttix_mod, 1, 10, 31, 1, 8, 8, - &tmxr_ex, &tmxr_dep, &ttix_reset, + &tmxr_ex, &tmxr_dep, &ttx_reset, NULL, &ttx_attach, &ttx_detach, - &ttix_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG, + &ttx_dib, DEV_MUX | DEV_DISABLE | DEV_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+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[] = { - { BRDATAD (BUF, ttox_buf, 8, 8, TTX_LINES, "last data item processed, lines 0 to 3") }, - { GRDATAD (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1, "device done flag (line 0 rightmost)") }, - { GRDATAD (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1, "interrupt enable flag") }, - { GRDATAD (INT, int_req, 8, TTX_LINES, INT_V_TTO1, "interrupt pending flag") }, + { BRDATAD (BUF, ttox_buf, 8, 8, TTX_MAXL, "last data item processed, lines 0 to 3") }, + { ORDATAD (DONE, ttox_done, TTX_MAXL, "device done flag (line 0 rightmost)") }, + { ORDATAD (ENABLE, ttx_enbl, TTX_MAXL, "interrupt enable 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, - 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 } }; @@ -183,8 +235,8 @@ MTAB ttox_mod[] = { DEVICE ttox_dev = { "TTOX", ttox_unit, ttox_reg, ttox_mod, - 4, 10, 31, 1, 8, 8, - NULL, NULL, &ttox_reset, + TTX_MAXL, 10, 31, 1, 8, 8, + NULL, NULL, &ttx_reset, NULL, NULL, NULL, NULL, DEV_DISABLE | DEV_DEBUG, 0, ttx_debug @@ -195,23 +247,22 @@ DEVICE ttox_dev = { int32 ttix (int32 inst, int32 AC) { int32 pulse = inst & 07; /* IOT pulse */ -int32 ln = TTX_GETLN (inst); /* line # */ -int32 itti = (INT_TTI1 << ln); /* rx intr */ -int32 itto = (INT_TTO1 << ln); /* tx intr */ +int32 ln = ttx_getln (inst); /* line # */ + +if (ln < 0) /* bad line #? */ + return (SCPE_IERR << IOT_V_REASON) | AC; switch (pulse) { /* case IR<9:11> */ case 0: /* KCF */ - dev_done = dev_done & ~itti; /* clear flag */ - int_req = int_req & ~itti; + TTIX_CLR_DONE (ln); /* clear flag */ break; case 1: /* KSF */ - return (dev_done & itti)? IOT_SKP + AC: AC; + return (TTIX_TST_DONE (ln))? IOT_SKP | AC: AC; case 2: /* KCC */ - dev_done = dev_done & ~itti; /* clear flag */ - int_req = int_req & ~itti; + TTIX_CLR_DONE (ln); /* clear flag */ sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */ return 0; /* clear AC */ @@ -220,19 +271,17 @@ switch (pulse) { /* case IR<9:11> */ case 5: /* KIE */ if (AC & 1) - int_enable = int_enable | (itti + itto); - else int_enable = int_enable & ~(itti + itto); - int_req = INT_UPDATE; /* update intr */ + TTX_SET_ENBL (ln); + else TTX_CLR_ENBL (ln); break; case 6: /* KRB */ - dev_done = dev_done & ~itti; /* clear flag */ - int_req = int_req & ~itti; + TTIX_CLR_DONE (ln); /* clear flag */ sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */ return ttix_buf[ln]; /* return buf */ default: - return (stop_inst << IOT_V_REASON) + AC; + return (stop_inst << IOT_V_REASON) | AC; } /* end switch */ return AC; @@ -248,83 +297,63 @@ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */ ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ -if (ln >= 0) /* got one? rcv enb*/ - ttx_ldsc[ln].rcve = 1; +if (ln >= 0) /* got one? */ + ttx_ldsc[ln].rcve = 1; /* set rcv enable */ 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 (dev_done & (INT_TTI1 << ln)) /* Last character still pending? */ + if (TTIX_TST_DONE (ln)) /* last char still pending? */ continue; if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags)); ttix_buf[ln] = c; - dev_done = dev_done | (INT_TTI1 << ln); - int_req = INT_UPDATE; + TTIX_SET_DONE (ln); /* set flag */ } } } 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 */ int32 ttox (int32 inst, int32 AC) { int32 pulse = inst & 07; /* pulse */ -int32 ln = TTX_GETLN (inst); /* line # */ -int32 itti = (INT_TTI1 << ln); /* rx intr */ -int32 itto = (INT_TTO1 << ln); /* tx intr */ +int32 ln = ttx_getln (inst); /* line # */ + +if (ln < 0) /* bad line #? */ + return (SCPE_IERR << IOT_V_REASON) | AC; switch (pulse) { /* case IR<9:11> */ case 0: /* TLF */ - dev_done = dev_done | itto; /* set flag */ - int_req = INT_UPDATE; /* update intr */ + TTOX_SET_DONE (ln); /* set flag */ break; case 1: /* TSF */ - return (dev_done & itto)? IOT_SKP + AC: AC; + return (TTOX_TST_DONE (ln))? IOT_SKP | AC: AC; case 2: /* TCF */ - dev_done = dev_done & ~itto; /* clear flag */ - int_req = int_req & ~itto; /* clear intr */ + TTOX_CLR_DONE (ln); /* clear flag */ break; 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 */ - dev_done = dev_done & ~itto; /* clear flag */ - int_req = int_req & ~itto; /* clear int req */ + TTOX_CLR_DONE (ln); /* clear flag */ case 4: /* TPC */ sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */ ttox_buf[ln] = AC & 0377; /* load buffer */ break; default: - return (stop_inst << IOT_V_REASON) + AC; + return (stop_inst << IOT_V_REASON) | AC; } /* end switch */ return AC; @@ -350,29 +379,82 @@ if (ttx_ldsc[ln].conn) { /* connected? */ return SCPE_OK; } } -dev_done = dev_done | (INT_TTO1 << ln); /* set done */ -int_req = INT_UPDATE; /* update intr */ +TTOX_SET_DONE (ln); /* set done */ 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 */ -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 */ -for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ - ttox_buf[ln] = 0; /* clear buf */ - 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 */ +if (dptr->flags & DEV_DIS) { /* sync enables */ + ttix_dev.flags |= DEV_DIS; + ttox_dev.flags |= DEV_DIS; } +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; } +/* 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 */ t_stat ttx_attach (UNIT *uptr, CONST char *cptr) @@ -394,23 +476,47 @@ int32 i; t_stat r; 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 */ sim_cancel (uptr); /* stop poll */ 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) { - ttix_dev.flags = ttix_dev.flags | DEV_DIS; - ttox_dev.flags = ttox_dev.flags | DEV_DIS; +int32 newln, i, t; +t_stat r; + +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 { - ttix_dev.flags = ttix_dev.flags & ~DEV_DIS; - ttox_dev.flags = ttox_dev.flags & ~DEV_DIS; + for (i = ttx_lines; i < newln; i++) { + ttox_unit[i].flags &= ~UNIT_DIS; + ttx_reset_ln (i); + } } -return; +ttx_lines = newln; +ttx_dib.num = newln * 2; +return SCPE_OK; } diff --git a/doc/pdp8_doc.doc b/doc/pdp8_doc.doc index 79fa21de..4c22ce7f 100644 Binary files a/doc/pdp8_doc.doc and b/doc/pdp8_doc.doc differ