From 9c0b0ffb46ee5376e45f3fa7cc2902969553f5bd Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 10 Oct 2016 16:59:03 -0700 Subject: [PATCH] PDP8: Add support for 16 terminals in the TTIX device --- PDP8/pdp8_cpu.c | 45 +++++-- PDP8/pdp8_defs.h | 71 ++++++++--- PDP8/pdp8_tt.c | 4 +- PDP8/pdp8_ttx.c | 316 +++++++++++++++++++++++++++++++---------------- doc/pdp8_doc.doc | Bin 96768 -> 98304 bytes 5 files changed, 303 insertions(+), 133 deletions(-) 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 79fa21de1725b428514d8393937a30bf7d021b96..4c22ce7fc9b419aabd5e7f188ebfa1aca9d9cad3 100644 GIT binary patch delta 16994 zcmd7a30xKB-oWu^KoC>}6$KUaXe4Tiz&UJgiHI92xaXP(7$}=8nd<>9wKPRXC9T|Y zDOVJe%t~AA?WU$^n`LSDUhk`xc1`qFUiJMwXU@nuaNzCJ=e@lh`!Z+ddCtr;|L6Za zGiT5WDqIQ*T#JI+91_--mk@99R>8gd_wUQCWq4!X(Bn#I+h>JnC?-#xJoV14JGW$+ z{mZ>hGZFNY5NkIK9xt^mRBzO2rKUTDn&&jos>)?WbM1X?OK+P!(+*2R+*)WG9W8fJ zbb#`Iv((G4Msh69q@<-Vi*?RI3~a6Kpr+-+1|i;a65_wx3UPv}r4I>_$})`|u~|%G zDPO;389=>ny9#lT53cG_Ux;~ZSk4ZbszaTc)YH$sWdN(q%<{qMtEqtySOXtp7N!6v?ziS;~e9$NQj;iihhQRja+?lQo@2t14dU56P za(EjZA;bvv#^2-2{?;Ao2huyYSEtpRHn%+^6VLL}x3_68#E?2dtY!}l^+J{-*^f+; zH(3U=l$|YKuTXCm%f>w|t0Jot@wcw~5eVTQNjrx0*2}e8l}RbvCwHZvnZDE`r?1m- zH|n%&Te+(3NMF}GY&l1()6U5fu6AAZ(yB|n@m051uB(1^*N5tDuH0;Y(CXVcc+WP~ zH)|i0W3eaRERAzJp}0hJj!()f^{aQm#VytEXsG&lqX@ku)V9Q^9%~e&ml)MajURl* zq_%Awu9ui>OTyGejl(>(QwR++j88Qv-jV8bA78z8xcYr#qh2B0L4^o)a1)bWJ3<}m z{otsPYDtq2y(H4MBue%2j?zn_Y)Xv5>Qmm)))H3U^)~1$A?g+H;L4RYO&^qmssozp zXJ-smFIJWq)xAwScxh*6G-{0xG1{D-(WJUH3)O3w9MuR@r&iXmM#z32;p&NIJ@l4^ ztBrgfv@Al6@@cP^M5yJJC6Ve1pGdtV(zYZ@{lzCzZ&8%BMd3DWHU+DRzCqS5F$G&| zs7mAJ*8Q16)FZxKth+FUSS#4}swq@$)m#szDYSG{^X<;{IvMh_4S89HknqyGe&&ES z9v&VeQd10hDLENwnThF!w9M@MJVRQpAu}r{BQZUFrn)w|wK*pxF}-tMT1JW?DLpG` zT99ExmLc)Uth8i9a$;VhAw4TMx04~!ke!vz9&!!2NvSEx`ROUihQJX62FC`n*WA3E z{G`0Jtjt_P;uMZ%$m6In2_p^cI+<;Tq}0Tm#3V|BJUrqCMaCLN=uL{xFFh4K#&uL~ zT1I|)VqR8`AvZreJ1ZwI*ASweiXkyMIZf`I6VT6u2F*yzOEn~Ba&!tQN=})Qn4g|! z$eLm>8Pd}-Q*wh022~l@Lhadqg*h`nV>0cc&{AYMkL;ABv?*zvhqf!j@YoTCq^yjL z#LVQb9v<#;b;O7Pj~NCH7!o_YN2a^Gdu~dep>j_)?b3Eiml2e{cOG^2F?M1_soU9CjKhqLT`gBC9>Xk6uIV5a?Iq*s{KYn|XKW~+6Dp~!k{BJ=?c4GFBUfL|r&z4P7eL`-CW~r||`iZ*dx#sSb zYp0+4u^wARm|J1Y!1n6)C66gSo0mGdUG@;74%ge2%hLUBUp{kW?~8kj3X8G|iwcjt zc;xc!%VVrtxWKga?darI=sfjTj^yg5*dFWjbKdI3BG=AywW3CDg_bsmk#0&xe^DnB z`EH88^HkYXy;O}}-qcUF$)<`3Y$_XXJ%#61_%dmOJ7-s+y^?l$LjbooOzYqTTM zHV7hkU~}8uH`1DAdqBTMoc&@MfueLZZ{?tl)47r3^z>F%Ifp9EsdDhH)elfxbE=%| z!}e!V&-+0e)T1kWBV}Cd1NxAqKW1<*Rda($oz$WLwa&@}HE&tl@Dy&bYObtx@MUhH zt9Nj#+RshBx2&0ZQEkwsdNcns{obP8b*-mt62#Kq_A&BP6IOEit5VgaML~_vyEr;E znY$ey*NPs*++-_4M0DEp0n+ZK=7kmbSaN3jfZu-SkJM?S8GNY%<4j+HU0Z zH*0CT(bLhXS)3z^Af_<2Y@%ar&=nX*-{eu6}Bkv~|&n zerwt;)&gmB@IN+fd+=PaCsyvz()O38wRNn0+V1=_r0xA$<1N#62mQ87OWSKcwVj=o zw%J;pDn0U>?r(Shk!kxRy=I?-j?;FRuUcnMfcbAc7O&e zwcQX0?Jr4iYURfH8!#5Da2gGG9NZTLeroxdr`5rw^VMFZL zidh!O{)mL^lhN1)**6FA9?J0zet_(+U(l;9&)ZReLY#vKeb*3rzZKGV9qBvSe|?dJ zMYt;-yh_anX@uOk6Xp09{ORl%q(OFk5ysQ`6HpGB2v=|wZ8``MfsvSuLcD|$oWVbE z5566RFk(1nU?r>#DgCO%M^P`9j8iX`)iW#H82HQ5qqq*QM}+8#37Cy-xB!Lp3xZ6^ z!SE&(o1z<%k%AUMJQzU<_Te1vA*c)eg=JWd4{!x{Md@cHezGw`)QcZ_n6*GDP8`jX zW|8TlExKbM3fWZ=R%0vVA>=Og-Bs{Q3zrZfx}a645Q!+ne5^1Eu?c^{MLZcsU~m$j zz$sh^^N;+viF6Q;;6g6yuXkX?2HCsBdAbe|i#pf_SL6|!3wA)c;H zKp|u|uf;mNjdQpIKe{~z`LG5<{i@_GQuifNxCP_M)vP#MlUG)fxv~ZaAamwxoQE@c z(+oc737Jb{un#h)&f^=j?7>umdDw@q;X$s+oa=}f^ua5TIe55dY57HiKDccfbC|-n zZ~=GVPlEPD)uc7`5+V!<7>ZIHz;T?wkEkClL}v^^KDOfsj$&DF1~}frU7@;^jZv== zm{XTMSbC__-u6(vt}M4MO$4l=nRwOl6i+0}%adi;`^nK`c>?D@8d(9fmeTKEwn@*WSRLG~yo+O~xOCy%N!vda?^Il{{;}JB?qtQu za~CQu@x!{kqwUA!d*RnKwe^&#+GAl6KhQ}|JYpzIb?y>>W}gOTZH}^Rm$hG?xYa@J ziF`sd(;fob?nQ2olldXL@>6_;QItic;N2boj1V4GK`$)j>>E;S;3 zV)R^MnT>j+l1!*z?DF*rUe$)znV7!1+s1_nk|URUH5+QV!!I-IQ| zMDAe%7U2+N;(m^yB&wdc&-4BwzC#NVv?Yv?iJO8~a1Jto8|C`;36~n zggX7iQ0BON_52AB_0)-R=AVSk>-Vf!K3;ilE}p{k>C;XVq0Is(WE&VfPva2eU@FHM zxF#?#!WmU#umW;~y#jrd^<$*1XQXYwHONut%ixkDZvggSFOsbTZ8pngBUI(x4(i6G zf$I6A(W=+Gf$DDFZ(M4!3REXJc|4flE1T}Oj8Ds<`Zm58Ndm%+VJnBO0d3F|V=xnI zun(v30~#>AyCEILki-2Q=tKThhW(u}T)?Ommu znNH##xC+?-xfA)}FAzA9%Pn5O2E2lu_y8Z_7qpy2XwWcGh>3Uur|>zx!e4O*_Ypgp zD`PSpoNVSz3TKILQ9gyc@+Y`Lp;sz%FOu*QHc#cQAMK_w{bC~;rgIHI8PYO@*p1tn zOv_pPMh#Puhkn^K81<*~c?6;(4m`n+$vJcZyz@9Xx?nL@A|;(~TunMo?Bm4k&Qc9*(NA$O(7q<;8vr&xQ z*n_We9?oQ(%)X9z1~LoxLuTRy%qJTc;Pe#x%aM~cGN&n%8G8pZYdhhHHG6+x=}Xqi zERIG7GVvm0HkaZ6{tFlIGa99_AM{5Op2kMJhYP4c^QjKTZ*zu4H%!1>$f5EI-h~`8 zmvIGN3>i6m0-+C~O*X?Qh+%ZlI-I^_`72s6q2xhVC5NNcptDu(^h>F50H5L(d>QrKAZLIim{EYOkTb&Dcn3G(oy(I8jKxf> z!$Ew53dq@`DPF?Mh-KF3i{yL<9hOXioLZJ(DM}%ynU7&R)f~4@HMgzPO(0XsQaq2| zOe=DF8H04lY34;-pUK@n+RoyM6}qAu#=z2HW9TsXHOP8%rDwDJyrupe9!AV%pE!or z^SF{=F0SAz_$#HNF6yHR5^%hLDGxIXnR>7q&hv%X0ha}I71Ez3f$-Ww<_7GL&zas> z#N@D;=MIp6$+qIU<W;4z^vfhIJ>pLUu_2hG8LO_v}O+x<__XYxG4fRzr5%Zgi*HdSDv#Zd}CsK6E2# zwe|2I#@qX(RjRzn8LcSRNm7=_;#KI~{wD8p==EH@h8>Vua0vcnK`X>S&x(<}Z$oCZ zeO8-@PkPF~667K;Pfhm!bDEP!IDd&ZlD`QX&Yuvq{O9cITRiRRh$!{O&CLIGTc`-G zR?qRa5C`=v+w58ry2e$pZ<~WH>W??8)TzFuc)DBF9a%Qnol&R=bI>ZwHv3ks-c)sG za!ZwcML5`(Wt;uJszpCkZmF`b>d_B%&?80%(RaM9di0It0X=NjHe(tNo$70GRk%>Fp1EzeR0ZK#rd8~%QEK%%3MWpEspk3jKxJB%89aq zhRXW7N{h1A&6MU&F}=mTE%=Iw0Wy)*DuVp9}mcLQ&#;uSCw=WI3(ZCkw5Bax+ zu3>p29@RHyvc>aFm;$}IyG2%0ragA@F2?(?zs}l2WBHXyUNPkbE0+EDLw^jwKn&uR z)7VbwU>?oNL?nY-Et<`XhP=wb_pw9&=JJ;?+HXSS?;GS3e)-H;KC_jNOy$!_%R|B5 z^0^3iI_zD3QdB-eoROJn#c5f!{b-2xFVY%+hOO?Dh$jMl?xG!yp zE56ZA=~7%YP4O+>HBB*iaPJ|w&k)>Oh^NXD1C=M7oZ1$aecVB5<7BoOBO-*k)htuv*H(tCX25&oER(R4KGAt2r{v za5a98S*?~bB4e&0+(r>v%Li+YjFE1usSAywdSuM{)zwIE*ZjenBO_x}^XF=g3^S1Y zoY`TrnMlQ&cFLq9Rx!pVFtF$NbAuPi_+e~)!T`R6sUdt*W{ia~#4{fWl&>i;_9f%t0=5kOB_! zcMhNg@vV}BjOHNm9ONAivYLauz(Ha;$Tkl0HV60|9%J~L!$97^F*4-XY**dnIBuQ z6Y{ItNmSrpnExc*jrVX2y=F1ZA`i1*;tNSv$S)~RAY%^qzxaMG7a-)$V?M_^tj7-Q z#vbg$egwVFkDWwe9~u_$lpV3?j{z8j!AL+rVcFbJWtCzs@a9e*XAOJ>!uE&Q2`=FZ zf;-SUeEbM~3HMGUIpptFQWFp6 zOe9UKFgg$YF$`sRA6vt@{m1K!jze;UbR~Sa){TocycsR>7jH>D2pO__(HM-6rcd!9 zKEgloE0VZGX2FZgn>X5{Q(r=Ln5**umeBf2ApT|9Tg@-$oFJ!Js1#x0f<8$=3xz9hMwJv=7{!U>72@R*0c8z z-SQ4%3$*MFC=_Lp(6qLB8r1 zua8k$57O>UNdxO1Ws!pWy_5n)$YVdvv@*-bONw3kC@IRg;%R-9+g=^T z#n}PksJpeo{o?7d$~B`hc%UUR4|6L_3K4?y^lTFm%^IiTb+y{ot7R+tDvv9!-xcuN zr2_fSA?rI)NqaRYd$hmuu2NP|Pf1k{4pfFJN<{InI3+M_abh##EPBa$hU`O06~`3I z`+GAM$$zBk%w`TwoU~TR<@t=VJ#k7a&&IM5a)WG?Tz*$j{OwrfP3I8NviQYuNNuhN+sqPOQBwAp`%JnNY+YzmSsWpN_-QlQfZc>O5~E=p7I=3 zBI)cZWjdD=kx2N%rDjBO(8s(@`WyG~OB{-^78F8)BKu47- zBkpf$Tc7Hc69`WyG~gEgV&3%jug@_(C9 z!g3$>qZ9}5Iu1gX-?e&^^~2U}a{D{-{l3Jy%9>0i-Q8>UddokFf4ew8Q!y*Eif^%S zT|}Lrp2f4W*z{BJuUX10WqWacHfwu}Z)Gc4{f-WP#`3YM|DvAHiPNHw_=>L#eZ}Wu zlsGTWi4VjXzF&OBH~0j$4;Q1wW8#?jNJJO!oUTN9R@qtE&FM;#OF&3ORBvN!OmOFj lnDDU9rkL39&QZ~^k)2J(KD|v*;bF01(ZOZ2W+)4t{s)SWaZ&&P delta 16047 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 b4<|;)JRFx`icd+1@12lZF>9`}(Br=WE)5fK