From cf1a6e83def7d2dfe3aebaab267fbda7ee64132b Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 10 Oct 2016 16:29:40 -0700 Subject: [PATCH] PDP8: Add support for 16 terminals in the TTIX device --- PDP8/pdp8_cpu.c | 46 +++++-- PDP8/pdp8_defs.h | 71 ++++++++--- PDP8/pdp8_tt.c | 17 ++- PDP8/pdp8_ttx.c | 321 +++++++++++++++++++++++++++++++---------------- doc/pdp8_doc.doc | Bin 101888 -> 104448 bytes 5 files changed, 310 insertions(+), 145 deletions(-) diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index 4d790ea9..88af056b 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 */ @@ -241,7 +243,6 @@ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ - t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -339,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; @@ -1497,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 867d1f8a..882cfdba 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 aaac733f..a1ce3447 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-2015, 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,7 +25,7 @@ tti,tto KL8E terminal input/output - 27-Mar-15 RMS Backported Dave Gesswein's fix to prevent data loss + 25-Sep-16 RMS Backported Dave Gesswein's fix to prevent data loss 18-Apr-12 RMS Revised to use clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 18-Oct-06 RMS Synced keyboard to clock @@ -66,7 +66,7 @@ t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); DIB tti_dib = { DEV_TTI, 1, { &tti } }; -UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_KSR, 0), 0 }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_KSR, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -74,7 +74,7 @@ REG tti_reg[] = { { FLDATA (ENABLE, int_enable, INT_V_TTI) }, { FLDATA (INT, int_req, INT_V_TTI) }, { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT+REG_NZ }, { NULL } }; @@ -164,7 +164,7 @@ switch (IR & 07) { /* decode IR<9:11> */ case 6: /* KRB */ dev_done = dev_done & ~INT_TTI; /* clear flag */ int_req = int_req & ~INT_TTI; - sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); /* check soon for more input */ + sim_activate_abs (&tti_unit, tti_unit.wait); /* check soon for more input */ return (tti_unit.buf); /* return buffer */ default: @@ -178,10 +178,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll))); - /* continue poll */ -if (dev_done & INT_TTI) /* prior character still pending? */ - return SCPE_OK; +sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; if (c & SCPE_BREAK) /* break? */ @@ -202,7 +199,7 @@ dev_done = dev_done & ~INT_TTI; /* clear done, int */ int_req = int_req & ~INT_TTI; int_enable = int_enable | INT_TTI; /* set enable */ if (!sim_is_running) /* RESET (not CAF)? */ - sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); + sim_activate (&tti_unit, tmxr_poll); return SCPE_OK; } diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index 81fb9295..a202d7ae 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-2015, 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 27-Mar-15 RMS Backported Dave Gesswein's fix to prevent data loss 11-Oct-13 RMS Poll TTIX immediately to pick up initial connect (Mark Pizzolato) 18-Apr-12 RMS Revised to use clock coscheduling @@ -46,10 +47,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" @@ -57,30 +63,43 @@ #include "sim_tmxr.h" #include -#define TTX_LINES 4 -#define TTX_MASK (TTX_LINES - 1) - -#define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) +#define TTX_MAXL 16 +#define TTX_INIL 4 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 DEVICE ttix_dev, ttox_dev; 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, 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, 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 @@ -90,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 } + }; -UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_IDLE|UNIT_ATTABLE, 0), KBD_POLL_WAIT }; +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[] = { - { BRDATA (BUF, ttix_buf, 8, 8, TTX_LINES) }, - { GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1) }, - { GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1) }, - { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTI1) }, + { BRDATA (BUF, ttix_buf, 8, 8, TTX_MAXL) }, + { ORDATA (DONE, ttix_done, TTX_MAXL) }, + { ORDATA (ENABLE, ttx_enbl, TTX_MAXL) }, + { FLDATA (SUMDONE, dev_done, INT_V_TTI1), REG_HRO }, + { FLDATA (SUMENABLE, int_enable, INT_V_TTI1), REG_HRO }, { DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPS, ttx_tps, 10), 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", @@ -115,17 +154,15 @@ 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 } }; 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_NET | DEV_DISABLE + &ttx_dib, DEV_MUX | DEV_DISABLE }; /* TTOx data structures @@ -139,16 +176,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[] = { - { BRDATA (BUF, ttox_buf, 8, 8, TTX_LINES) }, - { GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1) }, - { GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1) }, - { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) }, + { BRDATA (BUF, ttox_buf, 8, 8, TTX_MAXL) }, + { ORDATA (DONE, ttox_done, TTX_MAXL) }, + { ORDATA (ENABLE, ttx_enbl, TTX_MAXL) }, + { FLDATA (SUMDONE, dev_done, INT_V_TTO1), REG_HRO }, + { FLDATA (SUMENABLE, int_enable, INT_V_TTO1), REG_HRO }, { URDATA (TIME, ttox_unit[0].wait, 10, 24, 0, - TTX_LINES, PV_LEFT) }, + TTX_MAXL, PV_LEFT) }, { NULL } }; @@ -168,8 +218,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 }; @@ -179,23 +229,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 */ @@ -204,19 +253,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; @@ -232,83 +279,63 @@ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; sim_activate (uptr, clk_cosched (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; @@ -334,29 +361,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, char *cptr) @@ -378,23 +458,48 @@ 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, 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 de027e9ec404636a34367ad98f05a0814a226792..6b5770b063321954bbc82ac10ef631208ea1eca8 100644 GIT binary patch delta 13995 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 delta 11461 zcmciId3;P~+raVrWM9M*dnz)hrGzMIuO<>|O+wXL+C-vBL=s7?#h{8(5jjamy-Jm; zdeo93Av|s3DX~P*(w5TL+ai|QDoWnpm6?g9_&lHYk9XSdoHKLIoO`?O<(!zl(P{cp zr_`49b}H+uvQpo%tKmUuX{mghi@Z(!_G_);XDd}vg~x=)cy{sZBF7$oxjNKPE$lRv zFhG@wpQc}TsH?}?wK6Vtvz#j1KWkd{pSP{{$d$=QSw@^{S-yPQ_9ll)IQ}Z3)2ou;FY~>-zPO9ht5h3<98Kp2idxlAqkQMwk_F8W6LX= z^Cq*M<}aU=`k=W|L9~HT1-%cJ#@uE%Q%)U;bHt!FhQrTb9eeeIiKy`8{cOsrS#X zEm@VWXsDpnR&#Hc0?n~Q^MHgza~-$So@Qt7#tpm;O`=B`TKXE2qaqEXBPWH&hb2aM zxR$-5lk{MJAE%MA@gqmSWIpa6aqmVM21LfjMJ5}PB9oG$Ekk(rNG1$kwwTEj^NN_hY)ke1qX{oi*PX+q$ zUM0p$pWfYF9~@GP? zJ#%4SerQND=nm<=)t~x9eQZXGel=y0-AzqD^ogIoX<={`&tvqmTeyuoNc*_+Gk#su z^jleKap`5Lxq1dwQtBO~Ee?A6Ps|$@hia0H=9#vnjqb4Y>1AFbW&V7bonC7x#s2L1 z#UA4Hu-Hq>i~SkJ{`{H6UTG=zk4_JZeTbRwGKz5pX{$Ovx3>GblqVbaxwZVQswfqV zwAIfn|LXGcuc7>FpI-homNs8Y;nzLC@SWVtb5XFiyzuKN{Q74WeuJg(TiqWPzR**t zi@1c#NZa`Q!uxrYCmXlkTKE=KmFk7G%x4xpv%K(|DSXz`3%}V?_$&&)_4$SOu3Vmr zf~@kwZ>8`#&n*0QOW~JPepvWTOd|(Sh=WMm@%+M9p;uY^SzL~_@O7&z)e&jmJhSlM zlovji!tZ=~;d3p8-$~)Wdw$_dtCi=XU}t&ZzoYQGpIP{POW~(fe^~fctPXOKhn+~< z^Zdf!s8OD5+-_^(?OD(HAZ=e~?{tYO z;SzfJC{@XzR9{qN8P*4%;tE_EC{+QoF%Mp>wd!IonzLL;XiPLWWr@*Dsm1sdUt%+I zaU8$Hr#b7w7OW3iBM>3*ZJ|^+<{*t#(@Gq`j+RQ5!slgXP58BJ|L`#V;Nh2z<2f`Hn{XE1)T-3*K*)kiYWfREZEu4{P1|by1@-C zK$`R_+OnK!hw+$zgRrN09Uf_7ADVcNwW-gs)fy_*5cePE!)!c4CgjVWh(`vt<20O! z4~dZ$D8W6%6E6}ob1)a*;wWxF)`C9hh+rgO7M3ClhjAU%Ut$>wYevk+3u|insls9U zsiSU2trATkM@QfztjEu|huTDH5T;@|3Lw#Y37JHx8OLDfOLbr?wjtOWuoKuWMFIYV z1aNcMg805NA1$mSnF-bp{_bJ4)RbmN?A&gWv0-@|xc#eM-K?$6;osu25un2aUZ zjwky>bNWOJyas=a!n>FTBUV5=WFC8bp=Ol+Bj?$US8GEhVl-m$85X=kzOWRl;Mtbe zZbxu=yTLOT&zot5hPs!}t%D0KnXUn9Ewxtk4OkmySEz%7uDKQK_K zbTkU0lVd+FbfZ(FdUpzdyGZJxR1Wsz8k+W`AD|0n^x_&=iS_s%<9f4?Eq%BaickKO ze=>X3vb4wkd-3s)PyM9y5%azDxT3f9;v!FX$XFC48sI` zf*hPiRa)HI-Sp#yI~WXSnod>JIvO>5Yi!FI5+7~Q9}*{%Fc~Yb8C!4y5-$a*Gc$yPLopSfU^`C0jv(!T zcOgOhKF&je_dXt=9zpyn-o|u%iDQu9{u8+bcpk1mg58N=cSh3yJ@H(qe(FpXwKI;f z=#l(1<#>05V-~(Z0i>gp!kdmF9VQ6f5R2)Ufi;khv=^@QAv%<53F%XV5Q{O;A${y$ zScg4{p{B+B#(b`)lwO{(^MU2CoxC2*XF%gL`O5 zhaCjz#L2h{TPJSTQ&0RoP%^{VnDuz&G^2A*gArTl)Z1{_+QIGV+yR(?iTE1Q;dfy- zuEK|oAAoSofeZ#&xC9v#?EBJJ&=!%HgZoN9TG&VTF8+%ANMm{Ee;lr4tVHa|;Wa42 zRb0cAVCom?xD>)=(J@r1PKZPXKE^%#jZOWSPp}8Sz_mZ^h8N$Un(!tDVhrLiANNUO z^|9WjjhYrfrY=5SNm3BWjV&jVvZT5WW@O`A{EQPAK&nF_xscQ)HMcjF`Uy9&co5MH z=fNx>;0Z6ZMmv0p;GsscH22*-nUjpXt;0tAfvfK_^hOb4IDujei)H|ULk!K1 z5(LIldW=9e@{m4;3}bK{;RG#SsSUV+u(2eHDL9HEWF}H`HIm33N=z%9w3?=kPMXVq z`Q~JuP~43pq;*$gH_qY#>I`5c!Vt{GHk^aBk^3XHd)505^V?J zLu47y%^GEIu^o=Fn2%M+$2m9>eNE8=5{=QA1BuG@*nl5#8O87-N?(9eSKfw=u;uNs z)tlt25;Y`I{T9|jqWdT$!ksW0u~-C&?60sEdvF2TJ4)3;EA&DHW@0&Z;WTceI=!I- z2Es|Y$AmCjo*r4=PT)WWr0?v&zi|#FxQ8b6rI!#2>01-2K2S zdRY73B(@dkZqf%kAQB58%i9ZO%Uj6|^P8QuYUE%FaEbJL1 zWWZ>M*D)FkAp=M@e!vmjg$yWFMl(d>MFb)WA7TymLgtezL#)yKA6fq!DY-ptRU~Jf zM+JtW29O~t2>VfhWQL}3&>=%r4z}YAWZ1e3+t4+U;Y%@W$q-f#T@i`7kRfd&oC
Q)?O*!*1l`3_@wcJLo^1>c_Sj z1O{%uPxa2?7#u$!b65fSlU>P`Gcr|FwLemDM0U2DHacs5_P2b~bwg2gedPS=++?^L zTP~!4wJ3xXG7wVGWE{hBEVLGEHQR000{+gn6NT)Ic$5{G?Od$JcQ_BniOer}8R1C5 zdYr_48ip0avBFxmWwZ5`Sq?f=d+iVgsmZx$Kux}gR}qaE*lIY3{VLR~)O2UqYI`sH zQsb^vtgY6=*&m6ekP6=nOJ+V{(9M_HdJTqzsn^aIPCjmldNkHvEQ z011r0&~LgWKw{bI$i*4lMF~D6VCG>fYyotH{Y3;(8g9WBP|gI@x5&k9NPv}P$^3I+ z?eg~WE1QjM!RJKa#b7j2VGG93*^eV2<7YDj%%bai@W&E=%~5{rmQ`7^tD|{k+xu!$ zHB)+X?XoGtF-FC*6}^lU(%FJcRTgM3m|8B-LX8aYYAgslRy2&vWMC6N@~+JV z>sTJ4$%86+G$hYq4z;q}UCVu|+%C#3n%o)5-H6-*$f8XaNU{=oeXU6IJ>Kb}CE zW-6JljWUf1)?7w-lhAAus!Qa|B$4H4Kti`jXa)&gBcXf}+DAfZBy@v>+(@JWhLX@Y z61q%6lSpVh2`wO@tt52XlF$#qT8i-_LSIKN@^OX8y@d*1jIQ_<=h2BYdSa(P=iwGg z(3!96@cDg5lFkT@P-*i;@qAq^S$7@uGXKE>E+Dm%5GHb^s_?XUS8#}h77(4{8% zML;bI3V#N^?l@M5O2jSvjj=w2Buw>aMaZ8Be!^K?Mz{Ke7~aPmtVbq(L=pbefB_Jf z@Mi-;r?4>wleyw@Jf*tq<7jO-4wqYJY;49P+cA*fjwWZeZ z8!jQbol=Ro)}By8vkuHvNP!7H9a$2gJ9-*<%jiT4;U?}QpbH040(qnu@fx=@NWo%g z^jHtf3}l|c2AGkL{pcM;p%9DND8_X-GOxH|5tiU97}xW59vAUs_a4-naKeXuh+E_! z7dLPR%R=dBIEgFh+>gwoYJZvrzG#VfBx5!{L^g8p`T*L$_W*v3I~e#TV;(+43O2%w zUvL^%a2@&}%j1kYgQ+D%3?Xh{!cu&LJp6&H_#36TIGk%BX9R(W=5HIx;oC$pc3?ja zq4GP7GiZm72uBp|g>xaKkEF?viS4)wErK;OUO`4ARg4|@7QdkwHyMKdLS_`TfJ3tI zI0lbs0s|p<1Lhbqh2uC0$I(nZ7#mObgWRL#p%6d8Wh|pT+M^2+kc?%?G!Z6^BVMo! zpJN{iVZ6cH9dsDa4-twtFaxt>exOOrk(=dXEJqY~z(} zcyeM0a))(zvS&QXo;pbDV`o}0NULmAykeb*Yplc9$ih+F#vRmiCR7oIaLmDKVhKA^gD13-{_!H^Ks8?hBA{}^@_;A<4(AWGon!TgQR=#NC`NJkEi z;~xG-{faD7FcJ}%j?a*XohU*n43(%&yoR?C=QOQsf-p@Vs=aPnI8+h=;cN(F%RaNr0FL}vopXsLTrSV?sZ$DjA2OTLCgt zjMlh)LGDIsxGW|0d;RoYH+O0N@{`FotI0o#l)9)2*-8#%D|xfe4*Nh`?v$PIftKpT zRhwuZPtgiIC0lZezjf<3E&JCgTB9m;