From 5270c4411796cd64ebbcf2b848a1b5a7f3806f82 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:21:13 -0600 Subject: [PATCH 1/9] SDS: Fix bugs in Monitor-to-User Transition 1. When transitioning from monitor to user mode with the trap enabled, the trap was latching the monitor address of the transferring branch rather than the user-mode address of the branch target. 2. When executing a BRU, BRX or BRM in monitor mode, if the effective address was in user mode, the code neglected to transition the machine to user mode. And after doing so, it is necessary to check for an armed monitor-to-user trap. Also removed superfluous trailing blanks from lines in file. --- SDS/sds_cpu.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index c80ce356..78fe8ede 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -448,6 +448,8 @@ while (reason == 0) { /* loop until halted */ } /* end if r == 0 */ if (reason < 0) { /* mm (fet or ex)? */ pa = -reason; /* get vector */ + if (reason == MM_MONUSR) /* record P of user-mode */ + save_P = P; /* transition point */ reason = 0; /* defang */ tinst = ReadP (pa); /* get inst */ if (I_GETOP (tinst) != BRM) { /* not BRM? */ @@ -505,7 +507,7 @@ if (inst & I_POP) { /* POP? */ if ((r = Write (0, dat))) return r; } - } + } else { /* mon mode */ dat = (OV << 21) | dat; /* ov in <2> */ WriteP (0, dat); /* store return */ @@ -776,7 +778,7 @@ switch (op) { /* case on opcode */ return r; inst = dat; goto EXU_LOOP; - + case BRU: if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */ if ((r = Ea (inst, &va))) /* decode eff addr */ @@ -785,6 +787,11 @@ switch (op) { /* case on opcode */ return r; PCQ_ENTRY; P = va & VA_MASK; /* branch */ + if ((va & VA_USR) && !nml_mode && !usr_mode) { /* user ref from mon. mode? */ + usr_mode = 1; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } break; case BRX: @@ -796,6 +803,11 @@ switch (op) { /* case on opcode */ return r; PCQ_ENTRY; P = va & VA_MASK; /* branch */ + if ((va & VA_USR) && !nml_mode && !usr_mode) { /* user ref from mon. mode? */ + usr_mode = 1; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } } break; @@ -810,6 +822,11 @@ switch (op) { /* case on opcode */ return r; PCQ_ENTRY; P = (va + 1) & VA_MASK; /* branch */ + if ((va & VA_USR) && !nml_mode && !usr_mode) { /* user ref from mon. mode? */ + usr_mode = 1; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } break; case BRR: @@ -1191,7 +1208,7 @@ uint32 nml = nml_mode, usr = usr_mode; uint32 pa, pgn, map; if (sw & SWMASK ('N')) /* -n: normal */ - nml = 1; + nml = 1; else if (sw & SWMASK ('X')) /* -x: mon */ nml = usr = 0; else if (sw & SWMASK ('U')) { /* -u: user */ @@ -1269,7 +1286,7 @@ return; /* Divide - the SDS 940 uses a non-restoring divide. The algorithm runs even for overflow cases. Hence it must be emulated precisely - to give the right answers for diagnostics. If the dividend is + to give the right answers for diagnostics. If the dividend is negative, AB are 2's complemented starting at B<22>, and B<23> is unchanged. */ From d5acbc6f7a6934444068b3668958b0ff0024378f Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:22:20 -0600 Subject: [PATCH 2/9] SDS: Fix clock pulse interrupt bug The single-instruction Clock Pulse interrupt (75 octal) may be a MIN or SKR instruction. The function rtc_inst increments (MIN) or decrements (SKR) the operand and tests for zero and generates a Clock Sync interrupt (74 octal) if so. However, the SDS 940 reference manual is incorrect; in the SKR case, the test should be if the result is negative. --- SDS/sds_cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index 78fe8ede..70dc2429 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1589,7 +1589,7 @@ if ((r = Read (va, &dat))) /* get operand */ dat = AddM24 (dat, val); /* mem +/- 1 */ if ((r = Write (va, dat))) /* rewrite */ return r; -if (dat == 0) /* set clk sync int */ +if ((op == MIN && dat == 0) || (dat & SIGN)) /* set clk sync int */ int_req = int_req | INT_RTCS; return SCPE_OK; } From 5b479c7ab2c8d550cdfeed738c8db817720be45b Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:24:28 -0600 Subject: [PATCH 3/9] SDS: Do not reload channel interlace register if already alerted From actual monitor code, sequence used to read drum: EOD* 10000B Alert Interlace GDAC3: EOD 14202 I/O control mode EOD (mode 1) A=0 High order memory address bits Hicount=2 (Word count=04000=2KW) POT GDBCL+2 Low-order memory address bits. RRF (EOD 2226) Read RAD file (mode 0) Problem is that RRF is clearing the interlace information saved by the previous POT and sets up for a new POT. That is, in sds_io.c, mod 0 of op_eomd always assumes that a POT will follow if the channel is C or greater. Have to add tests of chan_flag. If interlace is active, do not capture new information from this EOM/EOD. Also removed superfluous trailing blanks from lines in file. --- SDS/sds_io.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/SDS/sds_io.c b/SDS/sds_io.c index dc5e7618..dea1a804 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -148,7 +148,7 @@ extern void set_dyn_map (void); Channels could, optionally, handle 12b or 24b characters. The simulator can support all widths. */ - + t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc); struct aldisp { @@ -233,11 +233,11 @@ t_stat (*dev3_dsp[64])() = { NULL }; struct aldisp dev_alt[] = { { NULL, NULL }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, - { NULL, &pot_ilc }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, - { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, - { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { &pin_adr, NULL }, { &pin_adr, NULL }, @@ -330,15 +330,22 @@ switch (mod) { if (INV_DEV (dev, ch)) /* inv dev? err */ CRETDEV; chan_war[ch] = chan_cnt[ch] = 0; /* init chan */ - chan_flag[ch] = chan_dcr[ch] = 0; - chan_mode[ch] = chan_uar[ch] = 0; - if (ch >= CHAN_E) - chan_mode[ch] = CHM_CE; + chan_dcr[ch] = 0; + chan_uar[ch] = 0; + if (!(chan_flag[ch] & CHF_ILCE) && /* ignore if ilc */ + !QAILCE (alert)) { /* already alerted */ + chan_flag[ch] = chan_mode[ch] = 0; + if (ch >= CHAN_E) + chan_mode[ch] = CHM_CE; + } if ((r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)))/* connect */ return r; - if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ - alert = POT_ILCY + ch; - chan_mar[ch] = chan_wcr[ch] = 0; + if (!(chan_flag[ch] & CHF_ILCE) && /* ignore if ilc */ + !QAILCE (alert)) { /* already alerted */ + if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ + alert = POT_ILCY + ch; + chan_mar[ch] = chan_wcr[ch] = 0; + } } if (chan_flag[ch] & CHF_24B) /* 24B? 1 ch/wd */ chan_cpw[ch] = 0; @@ -390,7 +397,7 @@ switch (mod) { } /* end else change scan */ } /* end else term output */ } /* end else chan EOM */ - break; + break; case 2: /* internal */ if (ch >= CHAN_E) { /* EOD? */ @@ -494,7 +501,7 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ if (dev3_dsp[dev]) - dev3_dsp[dev] (IO_SKS, inst, dat); + dev3_dsp[dev] (IO_SKS, inst, dat); else CRETINS; } /* end case */ @@ -568,7 +575,7 @@ return SCPE_OK; Note that the channel can be disconnected if CHN_EOR is set, but must not be if XFR_REQ is set */ - + t_stat chan_read (int32 ch) { uint32 dat = 0; @@ -626,7 +633,7 @@ if (TST_EOR (ch)) { /* end record? */ } /* end else if cnt */ return chan_eor (ch); /* eot/eor int */ } -return r; +return r; } void chan_write_mem (int32 ch) From a07addf5fa2e027b42dfb5eaaac79e375325cc91 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:26:44 -0600 Subject: [PATCH 4/9] SDS: Various fixes to asynchronous communication mux 1. In pot_fork, the permanently asserted interrupt, the interrupt bits were assigned in the wrong order -- bit 8 is interrupt 0 and bit 23 is interrupt 017 in each group of 16. Also, the group number was incorrectly calculated -- need to subtract 0200 before dividing by 020. 2. In case 3 of EOM and SKS when in SDS mode, it does not dispatch properly. The device table is set for Genie mode. Add test for device 077 in SDS mode and switch to device 1, which is Mux in Genie mode. 3. Add test to PIN to verify that scanner is locked before returning PIN data. 4. Mux should not queue a new interrupt for a flag type if it is already queued and pending for a different channel. If do so, when the CPU clears the interrupt, the second interrupt is lost. 5. If POT specifies interrupt but no Tx character present, queue a Tx interrupt immediately if the transmitter is not active. This technique is used by the 940 monitor to start output of the transmit character buffer. 6. Per the 940 reference manual, after servicing the highest priority interrupt on a particular channel, the scanner should look at all other channels before looking for additional interrupt types on the first channel. Change scanner to always resume scan with the Rx interrupt on the next channel from where the scanner paused. Also removed superfluous trailing blanks from lines in file. --- SDS/sds_io.c | 8 ++++++-- SDS/sds_mux.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/SDS/sds_io.c b/SDS/sds_io.c index dea1a804..e021cf5f 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -439,6 +439,8 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ + if (dev == DEV3_SMUX && !(cpu_unit.flags & UNIT_GENIE)) + dev = DEV3_GMUX; if (dev3_dsp[dev]) /* defined? */ return dev3_dsp[dev] (IO_CONN, inst, NULL); CRETINS; @@ -500,6 +502,8 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ + if (dev == DEV3_SMUX && !(cpu_unit.flags & UNIT_GENIE)) + dev = DEV3_GMUX; if (dev3_dsp[dev]) dev3_dsp[dev] (IO_SKS, inst, dat); else CRETINS; @@ -547,9 +551,9 @@ return SCPE_OK; t_stat pot_fork (uint32 num, uint32 *dat) { uint32 igrp = SYI_GETGRP (*dat); /* get group */ -uint32 fbit = (1 << (VEC_FORK & 017)); /* bit in group */ +uint32 fbit = (0100000 >> (VEC_FORK & 017)); /* bit in group */ -if (igrp == (VEC_FORK / 020)) { /* right group? */ +if (igrp == ((VEC_FORK-0200) / 020)) { /* right group? */ if ((*dat & SYI_ARM) && (*dat & fbit)) /* arm, bit set? */ int_req = int_req | INT_FORK; if ((*dat & SYI_DIS) && !(*dat & fbit)) /* disarm, bit clr? */ diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index 2b5054ab..abc8a5d4 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -54,6 +54,7 @@ #define MUX_SETFLG(l,x) mux_flags[((l) * MUX_FLAGS) + (x)] = 1 #define MUX_SETINT(x) int_req = int_req | (INT_MUXR >> (x)) #define MUX_CLRINT(x) int_req = int_req & ~(INT_MUXR >> (x)) +#define MUX_CHKINT(x) (int_req & (INT_MUXR >> (x))) /* PIN/POT */ @@ -274,7 +275,7 @@ switch (fnc) { ((inst & SKS_DSR) && !(mux_sta[ln] & MUX_SDSR))) *dat = 0; /* no skip if fail */ } - else CRETINS; + else CRETINS; default: return SCPE_IERR; @@ -290,6 +291,8 @@ t_stat pin_mux (uint32 num, uint32 *dat) uint32 ln = mux_scan >> 2; uint32 flag = mux_scan & MUX_FLAGMASK; +if (!mux_slck) /* scanner must be locked */ + return SCPE_IERR; mux_scan = mux_scan & MUX_SCANMASK; /* mask scan */ mux_flags[mux_scan] = 0; /* clear flag */ if (flag == MUX_FRCV) { /* rcv event? */ @@ -333,6 +336,12 @@ else { /* enabled */ else mux_sta[ln] = mux_sta[ln] & ~MUX_SXIE; mux_sta[ln] = mux_sta[ln] | MUX_SLNE; /* line is enabled */ mux_ldsc[ln].rcve = 1; + if ((*dat & POT_NOX) && /* if no transmit char && */ + (mux_sta[ln] & MUX_SXIE) && /* line enabled && */ + !sim_is_active (&muxl_unit[ln])) { /* tx buffer empty */ + MUX_SETFLG (ln, MUX_FXMT); /* then set flag to request */ + mux_scan_next (); /* a tx interrupt */ + } } return SCPE_OK; } @@ -407,7 +416,23 @@ if (mux_sta[ln] & MUX_SXIE) { return SCPE_OK; } -/* Kick scanner */ +/* Kick scanner +* +* Per 940 Ref Man: +* If more than one raised flag is encountered by the scanner, only +* the one of highest priority will result in an interrupt. The others +* will be ignored until the scanner has completed scanning all other +* channels. The receive flag will be given highest priority, followed +* by the transmit flag, the carrier-on flag, and the carrier-off flag. +* +* To implement, advance mux_scan to last flag of current channel (by +* merging MUX_FLAGMASK) so scan loop commences with receive flag of next +* channel. +* +* When two or more channels are active, do not queue an interrupt +* request if the same interrupt is already requesting. To do so will +* cause an interrupt to be lost. +*/ void mux_scan_next (void) { @@ -415,9 +440,12 @@ int32 i; if (mux_slck) /* locked? */ return; +mux_scan |= MUX_FLAGMASK; /* last flag of current ch. */ + /* will be Rx flag of next ch. */ for (i = 0; i < MUX_SCANMAX; i++) { /* scan flags */ mux_scan = (mux_scan + 1) & MUX_SCANMASK; /* next flag */ - if (mux_flags[mux_scan]) { /* flag set? */ + if (mux_flags[mux_scan] && /* flag set */ + !MUX_CHKINT (mux_scan & MUX_FLAGMASK)) { /* and not requesting int? */ mux_slck = 1; /* lock scanner */ MUX_SETINT (mux_scan & MUX_FLAGMASK); /* request int */ return; From 0c6c4c791699d8242baa85cfcf1fc78f9cee4099 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:27:45 -0600 Subject: [PATCH 5/9] SDS: Fixed head disk addressing corrected when start new sector rad_adjda was setting sba=0 at a sector boundary, which did not reflect that the first 12-bits of the sector have already be read or written. Must set sba=1 for proper addressing. Removed superfluous end-of-line spaces from file. --- SDS/sds_rad.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SDS/sds_rad.c b/SDS/sds_rad.c index 4194c755..d1475230 100644 --- a/SDS/sds_rad.c +++ b/SDS/sds_rad.c @@ -116,7 +116,7 @@ DEVICE rad_dev = { }; /* Fixed head disk routine - + conn - inst = EOM0, dat = NULL eom1 - inst = EOM1, dat = NULL sks - inst = SKS, dat = ptr to result @@ -157,7 +157,7 @@ switch (fnc) { /* case function */ if (new_ch != rad_dib.chan) /* wrong chan? */ return SCPE_IERR; if ((inst & 00600) == 00200) /* alert for sec */ - alert = POT_RADS; + alert = POT_RADS; else if ((inst & 06600) == 0) { /* alert for addr */ if (sim_is_active (&rad_unit)) /* busy? */ rad_err = 1; @@ -287,7 +287,7 @@ if (rad_sba >= (RAD_NUMWD * 2)) { /* next sector? */ ((rad_da + 1) & RAD_SCMASK); else rad_da = (rad_da & ~RAD_TRSCMASK) + /* cross band */ ((rad_da + 1) & RAD_TRSCMASK); - sba = 0; /* start new sec */ + sba = 1; /* start new sec */ } return sba; } From 614fe87af498270493c77f30d9755cf0ca09eed0 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:44:35 -0600 Subject: [PATCH 6/9] SDS: Alter display and entering of ASCII data SDS internal ASCII differs from standard external ASCII. Alter the examine and deposit functions with -A switch to properly adjust between the two forms. Also allow strings rather than one-character per word as was in the original code. Clean up six-bit character display logic to use a loop. Remove superfluous trailing blanks from lines in file. --- SDS/sds_sys.c | 55 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index b446169a..964975b7 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -212,7 +212,7 @@ for (i = wd = 0; i < 4; ) { } return wd; } - + t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, wd, buf[8]; @@ -227,7 +227,7 @@ for (i = 0; i < 8; i++) { /* read boot */ if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_FMT; buf[i] = wd; - } + } if ((buf[0] != 023200012) || /* 2 = WIM 12,2 */ (buf[1] != 004100002) || /* 3 = BRX 2 */ (buf[2] != 007100011) || /* 4 = LDX 11 */ @@ -260,15 +260,15 @@ return SCPE_NXM; #define I_V_OPO 006 /* opcode only */ #define I_V_CHC 007 /* chan cmd */ #define I_V_CHT 010 /* chan test */ -#define I_NPN (I_V_NPN << I_V_FL) -#define I_PPO (I_V_PPO << I_V_FL) -#define I_IOI (I_V_IOI << I_V_FL) -#define I_MRF (I_V_MRF << I_V_FL) -#define I_REG (I_V_REG << I_V_FL) -#define I_SHF (I_V_SHF << I_V_FL) +#define I_NPN (I_V_NPN << I_V_FL) +#define I_PPO (I_V_PPO << I_V_FL) +#define I_IOI (I_V_IOI << I_V_FL) +#define I_MRF (I_V_MRF << I_V_FL) +#define I_REG (I_V_REG << I_V_FL) +#define I_SHF (I_V_SHF << I_V_FL) #define I_OPO (I_V_OPO << I_V_FL) #define I_CHC (I_V_CHC << I_V_FL) -#define I_CHT (I_V_CHT << I_V_FL) +#define I_CHT (I_V_CHT << I_V_FL) static const int32 masks[] = { 037777777, 010000000, 017700000, @@ -299,7 +299,7 @@ static const char *opcode[] = { "SKM", "LDX", "SKA", "SKG", "SKD", "LDB", "LDA", "EAX", - "BRU*", + "BRU*", "MIY*", "BRI*", "MIW*", "POT*", "ETR*", "MRG*", "EOR*", "EXU*", @@ -430,17 +430,17 @@ va = inst & VA_MASK; shf = inst & I_SHFMSK; nonop = inst & 077777; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); +if (sw & SWMASK ('A')) { /* SDS internal ASCII? */ + for (i = 16; i >= 0; i -= 8) { + ch = (inst >> i) & 0377; /* map printable chars */ + ch = ch <= 0137 ? ch += 040 : '.'; /* from int. to ext. ASCII */ + fprintf (of, "%c", ch); + } return SCPE_OK; } -if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, "%c", sds_to_ascii[(inst >> 18) & 077]); - fprintf (of, "%c", sds_to_ascii[(inst >> 12) & 077]); - fprintf (of, "%c", sds_to_ascii[(inst >> 6) & 077]); - fprintf (of, "%c", sds_to_ascii[inst & 077]); +if (sw & SWMASK ('C')) { /* six-bit character? */ + for (i = 18; i >= 0; i -= 6) + fprintf (of, "%c", sds_to_ascii[(inst >> i) & 077]); return SCPE_OK; } if (!(sw & SWMASK ('M'))) return SCPE_ARG; @@ -539,7 +539,7 @@ return cptr; /* no change */ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 i, j, k; +int32 i, j, k, ch; t_value d, tag; t_stat r; char gbuf[CBUFSIZE]; @@ -554,10 +554,21 @@ for (i = 1; (i < 4) && (cptr[i] != 0); i++) { if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) /* must have 1 char */ return SCPE_ARG; - val[0] = (t_value) cptr[0] | 0200; + for (i = j = 0, val[0] = 0; i < 3; i++) { + if (cptr[i] == 0) /* latch str end */ + j = 1; + ch = cptr[i] & 0377; + if (ch <= 037 || ch >= 0200) + k = -1; + else + k = ch - 040; /* map ext. to int. ASCII */ + if (j || (k < 0)) /* bad, end? spc */ + k = 0; + val[0] = (val[0] << 8) | k; + } return SCPE_OK; } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string? */ +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string of 6-bit chars? */ if (cptr[0] == 0) /* must have 1 char */ return SCPE_ARG; for (i = j = 0, val[0] = 0; i < 4; i++) { From 396e78cb268cc4f1f55a372c915c51573de67c04 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:47:39 -0600 Subject: [PATCH 7/9] SDS: Allow specifying breakpoints as being in monitor, user or normal mode only Breakpoint logic now allows four execution-type breakpoints: -E as before, break if PC equals address, unqualified by mode -M break if PC equals address and machine is in monitor mode -N break if PC equals address and machine is in normal (SDS 930) mode -U break if PC equals address and machine is in user mode --- SDS/sds_cpu.c | 31 +++++++++++++++++++++++++++---- SDS/sds_defs.h | 5 ++++- SDS/sds_sys.c | 5 ++++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index 70dc2429..9fda030c 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -428,9 +428,31 @@ while (reason == 0) { /* loop until halted */ int_reqhi = api_findreq (); /* recalc int req */ } else { /* normal instr */ - if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; + if (sim_brk_summ) { + uint32 btyp = SWMASK ('E'); + + if (nml_mode) + btyp = SWMASK ('E') | SWMASK ('N'); + else + btyp = usr_mode ? SWMASK ('E') | SWMASK ('U') + : SWMASK ('E') | SWMASK ('M'); + btyp = sim_brk_test (P, btyp); + if (btyp) { + if (btyp & SWMASK ('E')) /* unqualified breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + else switch (btyp) { /* qualified breakpoint */ + case SWMASK ('M'): /* monitor mode */ + reason = STOP_MBKPT; /* stop simulation */ + break; + case SWMASK ('N'): /* normal (SDS 930) mode */ + reason = STOP_NBKPT; /* stop simulation */ + break; + case SWMASK ('U'): /* user mode */ + reason = STOP_UBKPT; /* stop simulation */ + break; + } + break; + } } reason = Read (save_P = P, &inst); /* get instr */ P = (P + 1) & VA_MASK; /* incr PC */ @@ -1473,7 +1495,8 @@ pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); +sim_brk_dflt = SWMASK ('E'); +sim_brk_types = SWMASK ('E') | SWMASK ('M') | SWMASK ('N') | SWMASK ('U'); return SCPE_OK; } diff --git a/SDS/sds_defs.h b/SDS/sds_defs.h index 8277a144..82955c8b 100644 --- a/SDS/sds_defs.h +++ b/SDS/sds_defs.h @@ -1,4 +1,4 @@ -/* sds_defs.h: SDS 940 simulator definitions +/* sds_defs.h: SDS 940 simulator definitions Copyright (c) 2001-2010, Robert M. Supnik @@ -52,6 +52,9 @@ #define STOP_RTCINS 12 /* rtc inst not MIN/SKR */ #define STOP_ILLVEC 13 /* zero vector */ #define STOP_CCT 14 /* runaway CCT */ +#define STOP_MBKPT 15 /* monitor-mode breakpoint */ +#define STOP_NBKPT 16 /* normal-mode breakpoint */ +#define STOP_UBKPT 17 /* user-mode breakpoint */ /* Trap codes */ diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index 964975b7..14a03c82 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -96,7 +96,10 @@ const char *sim_stop_messages[] = { "Trap instruction not BRM", "RTC instruction not MIN or SKR", "Interrupt vector zero", - "Runaway carriage control tape" + "Runaway carriage control tape", + "Monitor-mode Breakpoint", + "Normal-mode Breakpoint", + "User-mode Breakpoint" }; /* Character conversion tables */ From cf56b113217dea164138565156c3e726557bded8 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:49:04 -0600 Subject: [PATCH 8/9] SDS: Adjust real-time clock pulse interrupt period Clock is running twice as fast as it should -- 120 interrupts per second instead of 60. Cannot find problem in initialization or calibration or count-down code, so for now, divide rtc_tps by 2 prior to invoking sim_rtcn_calb. Now 940 Executive reports wall-clock time advancing at proper rate. --- SDS/sds_cpu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index 9fda030c..382221e4 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1582,13 +1582,17 @@ return SCPE_OK; a unit service routine and a reset routine. The service routine sets an interrupt that invokes the clock counter. The clock counter is a "one instruction interrupt", and only MIN/SKR are valid. + + Temporarily divide rtc_tps by 2 because clock is running twice as + fast as it should. Eventually have to find problem in the clock + calibration or setup code. */ t_stat rtc_svc (UNIT *uptr) { if (rtc_pie) /* set pulse intr */ int_req = int_req | INT_RTCP; -sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */ +sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps/2, TMR_RTC)); /* reactivate */ return SCPE_OK; } From a98c9f92fad957974361e2677976dee4935d5d18 Mon Sep 17 00:00:00 2001 From: Mark Emmer Date: Sun, 2 Mar 2014 22:58:08 -0600 Subject: [PATCH 9/9] SDS: Minor additions to SDS documentation Document new breakpoint types and display and input of packed SDS internal ASCII characters. Add note describing memory map options for display and input discovered in code. Word change tracking enabled. --- doc/sds_doc.doc | Bin 74240 -> 98304 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/sds_doc.doc b/doc/sds_doc.doc index 6e694c44d233b894f95868c0a47f7c5e9cca498b..4460270f5fefe429594c32a73301be3cd7abcb07 100644 GIT binary patch literal 98304 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 G@c#pwMGSBN literal 74240 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ⅈJ^3 zVgTcNsVpv@I;TsdDvm~<>K2v-nJ|KqA|fCcOZ~0BHOhc)jm*1jJ3DUJmfYBt!m*LT zv#>tX%+2GElpt?1Ki^J=1sYjSF|D)YFq+*~FDo}eyDQllnOAB_w|yd-GuE0)J*XGEydqMpyhuY> z=89Ekkw^oARHGfPbWh9zh;;}4_?lF}_Vj`4SiBcJQ`N=Lc z$wlH4Lqa7-%X!=CQH;@0#Wl;Vj58P$OHirXkeK_X+~aZ__q{xk+T&E?kP0BvPZ=(H<_aS2)Y?ZtDdi^E7r^h8ycRTov<4TO2a_ zMOsE`MrPzrcX_4Eex&uK5HixMkrf-nyfva8DY&UO>_QNZYK-o+GS6O2~5HG7NCR-{HL5WDADP9O) zlUjtQEuxYmE#qfeqhs3#_u#dn zPp|}r0jLKHi349?qJl)66`y*asjIen6gE4iIz5KLUUaaY3yGefv(Q(pS%#&_n0rP# zTYDg+mY!*GCC<99NOi|`w!X=VHA$$Zi^f>-B3<5Kkcp=dz@!l zt*d@fL|rdRSi&Axi~|;QY}nlVTx@=P7ID@aE+mm?PHTG(BT^X&cp!VV>q={_j-WK| zetST1u~_DjEZ7SLqUR$E1=#P!YH5eeSh)~`1)I)VR_GpD{Dp+JCj4Sr_8hdXrWgm8 zTU(ei_-hL@#_zankCaYN;@~lJ&8S!y2{b zgZ&Y)%On2k7-?Z;e~q@>)pW>>oz%5r*j|NmzSW02lf~CLdJd>IeW;kZPjVfpC)`?C zQOsui>|i9YM=!GJqA-oaKo$>n2e)}!J?*kxOoTPt<+hijD($sUMnARfLst>*kuGbc zT*vlW>%(7W=I7Buomd{hfFF;ME>jbhxHvk?{ifdPA@gx&h*{jK48!9geTY zIbzn@%ULRHXS4;>vVp9-D9xhm4i>Uv@+)4L@H*6r4uLy7G}~mYS51y+Q5q z;zC8_iY&HJ7O5DKZtb9D_RwRoS)gGZ!>VJe`bxy5vQTiLgPd8_t(Dj%;O zXSbfndSs8d(YTMA8g zam}>y8oegMtb}T_{9;N&O!10~OgW-Z;8NXFqf>_f&N96gJlkAatekVmtQSu}gNIaP zg>W4r*5JX1q31XeeN1hrsiE`@S$m{^;7+2^Wz(asV8$Z$6ryIBMz3QavKhEV1|{FKW)h-s>jXPFDA;W#TI`Aq{O!hE%hv zK49<4k*h4yiiqf58R<%>5G_5CRbG)^<-!(kgG}eFX?#R@aXsOzVb{Fm%+fmS1rMM! zWFtPk&Wb?%Y_TV05r0f%@8!PwPa$)$o76eBIHqP zC{hD#kg&Gv+Krg0yaVjXRXt6@SiMauPQ|GTN6(1VhlrByk+L&JEqKU%(S5*mCZkXb zYqkv?!5}$^Epaq_ox8}*l1_PXB)BYJ(@lL1x}xn_f3&(>QPGH&L@nA_HK7F|+8iQc z_V^Xif?APB6{)(Zuf9QYje)03OdN!gWAVgDIw3PhdSbpT7UMy*Lt(bb;u>2`Ol^5~ z3w=_2Xysm%P5KFfi>tOyjLbZI+l;BI8!1n1rj-MwlGN#(Oly&Ex@2ue^g^z3pJNpi zD<8`YilPUDNSjHF(bdz6V%gpyUJ)yp47#HH)T*_+Mx39NG@_I&AFZgJ5I!A$qwd(AQWAPMOdD3wO9_P=DiY7%Vq)O8boRW@1aji3iu zPbIPsBNu1Bipg5AVCtbxBf2=+D6d`-k%bTmO?5`sKrr!()Z8bJzqL%30c&a0OKG++FI0PzA{XmB5z6k|*IE+%lK3tx%qhYKjwfcD+P>zM_?_-7FEeYyWtVRU5?!x?84jv0Fe@0CZwc(*ChT zyz5$7kE!&uURIjT2GgE)snad%POxlnnajw7d)DH5y{{ErCnIQ^husBY@ihiT7wWdu zX0Y0us!!;#(KdqFDT~!yd_t*6mQ2oL16lKOf-JA)i85=aYHT0@_U zMI3KE^~8_azn1sbeWF&0T~yV7q8_f0*Bj$`_(F88`1P6ftdXhthO%B{-Nx=|vTOCg zU0dDdjnS%yRp>?ZDti~VTeh&v!x?PlcK4}6$()!is>*ms(3vpe)xNGuw@g7}I+L1D z`+Mk960&=riVGg;T9Le~Wj&o8%jc#xC(CM)HK}NzhS}HI;1TC4N`c|Ja-o_;p&mNe zeuU-DC~jZ3m4M`?xTvP6cwU>O1+1Ld0hM+kDsxH>8_6OOu{A?au(Vjmj>0KnirZIOS}hw( z(2|UGS%Ic3@q1WPsKrH=(V{HdENdaWnVr4bGO0VE+_q}g_}VS&QBA(Ox$0vrhaOem z;uvKqDcHVKwXn|IO7=|2P8NG{on3%3+*uRc8K0Ex(few(s=bIUfhV-dv`ro!8IWab zSG*3i><788tHO)9)MG?lt%)v@*|W}*E%}L`9Mj{qZFNU?*~Ex>$bRe$T^)JsOgZ=H zoF&#djHO7gR9j+gXQ-Or+nb<8&189ytw>ZMv#74Pyga%Gi2x1p0h;)(2j+2V9xoX! ztdE9ffXot2WycpI#%7zJZTD>BWP?GudUlq%pnA5tTVBOd(i>W1{S65qRkMt_HR~G=wp?weMF-6yoBZ z@2G6GN1W%A&=2c9^2iYHq<)xvP}lx|I3t*^G|GbmexAl~mX_DLYN~6@DKcH=>Qti0 zlsVGZGsB+dGubCoV-^->=H}$Mm>Fhlf^MU4uVtWz$(vS7zqsxMZ?v3xwLXNT{NUViOmGzQ&plcS6c@S8lU*)x z(&&cM6KU0yRDCg_K&5~4gdzS!tDe0SZ5(Cp6^N)2bJT@gkLhUVlld(Z^#%Mc4 zm$=5;X-PJ_T$`j5i4D=cAjVi7DmK4Xs5HsHF{(h6;`SV`%Ih>dZJo7B4a5 zif)J2*QWGzZInTKj{#}_qrjGdLf&tI3*ZrW2i}Dn2O7prFm;e&91GX-6{Ro3EATL~ zA+jTKGn@AR9y|rp4l#`L;6JfVANS$i*eeJ9;a{<__5X*&<@tMTM&my0j=hrj1O0E9 z;d(ILNZFCP{%9j(&`|wpw?jS|&LPI3n}3r!Wb>|+(>Si=XgK%|=CmP3>LiC}lEWA$ z?JwW+{84Oz$@gE08c18g&;cMBDffCfm`9#r*}Sm-!1oDcguC(zOUn!j-5~M^hC~l{EDBfH2ONefg6o( zYw8|!ZQn))QA>Rv8G0K55{(*t8yR{VRLHdmnLzoOpx}t4Q_|K;BMFs_riVf zI6MJQ!XM#J@MjRc{xm!T@4&n89{dMBgpa_5&Oa1}z*IOE{`UC&+wZ^eiW|?q;>If; z-~M>V_Ks7nGmFWq&h;8bzTVqXkK+GgB>ZIBN~e2MX$cxjX4AQQ468)UrBfn2DBDyW7Ur~@}NLksxeY}gFnhVQ^Ra4yK0e?EK{ zegZeZjc^m(0=L3%;C^@jo`ct(e{JWEop+2Tw>U(-=;r+FQPWxpop?#}kh0EYJh>Z689seJ|%h31M*DbtQ z-_uJA_idE;y_V3v)$!+g{Fgev9qxcT;V!rvME~Cd+u?C|0-l6F!qe~!{2Shcw_pfk z#84Ophrw_d0WyY+g3*u<)8W$?|K~7<^{zAe*0R53-qLre`n-?-MY=SJ<$Z#*M*$SV zY?uS9U^RH)>+lUY6TS&&!A20f;9GDuTnAfW8~hNiho8VN;Fs_#cnY3|zUcpH$W!la zsrCPz=%-Jnt+aM1(D5a%tuKWBzgPE!zUij%(k9Qqv+x`|4`T1_ffwK-*arsoowyDM zz(5!SV__UjhXN>snJ^1xgV>C7VIG_er@*PO0#1XKupT;L16&Gy*Z(4AeQ$l;!c+A< zy|i%Ow8YI?Li<+7pKJXub$%IK4p+iea5adne=XQ{{`_H#@vsU0c^EdpaBO^-4yDil z&G1vW4R*pVn8Z)=74q|S8~Dk%%f=bT2XM%E#tJauIB-s2&Ir};_~FPMyat2#*|q{$ z0;j-gSO?o+{1NCP(=Z-_w_xd!%wyp2iP$D^8O%Nkdjqz>d6V!>9F6Y*)cAAP_20kx z0RGVv481nfeGMk@YR(}st5<#V<@Dx7>Wddj%llEZV6U2VuFT244(GyU@FTb#?tuS; z$KY9b1>S^xkbw-0f{Bm|^T3vm8s2XNk&~<88u%SN3va<-WamSvMEmun{_wtCN;&qi zq;JLEbI>1RB13h{N|0U!(sM&&g0zPT1yBYnp%X5F8{p3%{ry!~Nq=4y)3+bv{ZaI9 z>EkCr5Uzq9@Bv7_p8@<#s4)OKLG-|TF`4?zKD-l~Xdges)qWrE`J4rdDYXOlwl#!D z;248XA4*^~d>d|p$KfNGFc$wG_~HAo z6W)O%(f`Y!kDVbI?31pls6dD;94>9K4rFY;9ArGs1UGcTjqoVQ7@ZL_PS^1M)x-5T z{Q*ZAtJ7gE$QXSNTn;i;{}9G8Udx!B2l?=MZrJyub@chp=z&zCE}N|j4wtrA4jW(_ zJP5DCp(b(wtKlrz2oHkTTYKOwcpKc_D>K zFZX<&h2cQ*W~f)B{l!kc8E%35VGpEZFN^Iw2Wuh9NHWv=i(!V zjd|=5fji-4xMn)Of&#-h1MV+my#Qv;Kd}IwSI3D?i<^{}e;2uaT!k&dy@N<~55PJrWhefaiYT+z68!m*)!6>G_ zO4#QHD@&O(!(DLHBEz@>-hj5n_)=h8x!zm#;hP8d@0Ax{=`jX!6M3b}7D3MvEUyvb z-LN+d%HBYAw)<>V&0G-I+oHrMk0KKL2j5i>@=!uz@T`1@c4<8=qDg{wiv?>|5~ z(3(#%JCn{_rVgG&TdgkMjWzp$kiU9D=Pi2Tp>s z;0GW!*aNT^#1?a6gJpo&WV67w%XagAEVh~0XSt9E<**t$;3~Ki9)iC>8n)Y1_!Nu$ zDMlUFlRm|CKESS2)2XR+K+&3Z{L8uz1y<8-{tro44uQ? zQCI@aa4}pDJKzO447*%x^n5rG#8&?lOW4P#-;eDYeZ1#O5Ufl4OIxgmPS^@EhuRMI zJjy$db0G7nr$OdaX;5IzttvTIK^vR{TVXpq0efK}^DYx=p$%j%b|HNDiPrvCv@H*$ z61%j&w8hOJ^W(?i33wldEui1R@vs17?%V=Df_q>)q%v=od2}||bLs!(z09ZI2YXJv zi+S^7u+N%5k7f>iAX)#c?)g$nlc8P_{V#1X24=%j2*4J&9v*}};K0{09x9<3E(Gy` z+y)PW_(EQUmtZ8mkWr8Wxgb80Rd5B^zLL9n|5>%=S2Uf(B5bw4L$3uME^RS!k@jDe za14R?v95%@ApWeu__C(MG7#UEAD#vAaix}_17JKXgwtRXTn9VhZ;(>1ePQD{-UVNR zHhD)^qyF3f9}?GSY(9D4&Hk76kmo<+V(4;H^5d7X24wx$VH&v?wK$Hreb+Se_TBT2 zy#1H~6XB?fwhovCN8kRXEP1j}ks3IYcMRJH^-ACMyMJ`P_p?WaZTXgQlX1e0holf) zIvfhC47U+58jL(6*C^m$KIHHZUy||FOdRi7|CPL76URT;eM_gjx^a^*jDCD3qcr8 zF&qmVggJ#fokp4A<*r6z_Z!Uyz9#M+O=<%tIWi_2hb(d!!~gqrW5j>YH5N=ZjISBi zml&Q?!fFr%;C~=i_3d)>|*f8B2^b74MQB;}wlInh+}9)cAN) zaiFMpCrB+w9xIFiDz1ti;}RV)f)E*#)8Zpa8xbk}IEjivZ6m8(%YSEG=UK`I`RmhNpXQapkX8IuRb$1{+fLb!<}2lIQpQ!M!rgvgjY zDE`ht0}YyzQdE$h+~0G3h&?=l5E+xxGGy}( zzFl$$3S=_6p?f%yr3`X3Wb^H5D?!4I?IE1VN(MO^vU%%(l_259^$<=ZBZC|b*?iH! zl_259_Yh7bAcGtY*}QSkN?@(pSi0bc#>I|oOX50>c3LG!D@hxzA^c!NKh~|k|CJMl ztdWuB%jNw(UUD1*6X7VB1X2@H$}MmKJOb~)yKo~a^Cp-|{TvI|64}e}3Or01AAwyk zn{s>)o`PxQ^*neH7UE024&DW~lket$kr}MB!ETW6zPJXy50Anwu)ojiHQs*+8G~7u zg^4f?d|p$KfNGFp@pc;D_(SPIw279L0Jmtb@zoayV`@&s2dMI^jlm6r2cC1{@F7Py?@y z<=Hy;00xc2oepb3p4B@C?1A(nkY|_!Vb}r}z*3WX zfpg(J*b3WVJ3I+*!l6gf9?%5efpg$>*b77GbVH#KX241~1A=fB*v~RO!TTp+7#(y9 zOohGh1{_6)odk1WF4RIhY=P_HVb}*p9F2^^d^jGwAkQ^j09#=j{1$!(X_FbpVGKM6 z&%@wjkS&-5M?(>u3Y~Bv+yIZj2XM?3_Thm%KXD1%1iyh7;IH7Aisc1UU@Fu=Bgp>! zEg<{%AAqOf85n;ovIz^J1$^*LI17FZ*TXO1m+%z)8{UNW<9J>Nw!qO@=v6ooYT-Wk z8QhW0o=$ifUV*vO==(4thdrOL7OsYC;17_F**71Khjusv&V}>fR`?4Xl1F>MNpKeY z0PcqeU@yD@&V2d_%!FC+AUqGdVeEAJ0pvm+l*4L}J<3p?16XTJs3KJeUGpNn&D!&9(KSBaM(=p0{L(v)WUk`gspH7 zY==sQsYdX^Js|ropN7=gCUyU-&t^4^!q-kFX0KgMDBePd|V$FdLRa z0JgyO@F45~#{y&&Dxn!Jgj?Y@co-gm7vUusS;RO4IgktXUb8EBeUT5AD)HhAhm?Dg6wlz2&cg&xDIy0-yo$F8H4d4&wSkjR~qOf zWL&*A@^@qMjIIphGpLQB-DYDs*JCC|i4U9vX547H(qfiqz*kaf8DUXVN! z+wT2e8@dHE61JeMa>ln{@=Ra}6u#+Bb$m*3i!-&>a7+?C(m zl;2*I-`|tpV3XhBlHX#I@8g#5V_{;+US;;`LJqJ+PCazS_O-}fW44&F_g-zeV)GLF z>4;Z;&qsdKMSj;~**NaOPb}Z@F5mMkdj(&})ZfP~-}@-v{U_i5Cf@-j-vcH4obB&} zA((o?jvxkG%M7-R83Z-h_Qh^}_KX2ru8f7it?D}@xSbvGhOrpRfMW3U126I>Wy<2M z>~nqz{sseaZjFTkm;p0E_CTKkemEbtzy%=tqHlwH;R%pmx%?BzUg`JXP}~~FLMCK^ z?4PcN7T65mfpb9iRNn~q!}G8QUI5u=oyJ7}NSFu5!vc`K*Y)sCxEij7?}O~e{uTTQ z{ta)z+aPxNPSa@%?36_Q}su@nk~cFB?gGEx(uhruTBKpqFcfyg@`m1V4 zR{a*b{GP4+#&s2Wc#}Njl85h-hhxaYDDvw!WcLbCP6mj!W@v_Q7?xISOzDNYz(E~2VK9sY`TgG`VG`s( zKFozS#;x`64?5s$FnJi`3Y0STl*6g83eu0G?qD;6+Ig@Yehz!#Z3r{aodts#=!U@} z>h?q!#yB+&_A%HEVz6^E01bwGD1=|b1K?m#lJ6z`FSs1;WK6pcwk%-$0JDU=!&JzD zGN=IA=eru#Kme|WAAs!p{UONr9NrFhz+Lcb_$@pEe*)PT{15myyaTdFcp$i77>G;` zGA4WpNZU^t#&carR8~5d@l+Z$2J+<7&H?mrdV};5=^bx?^o|syPkP4?klryKq<0(x z(mSSu^o}Bs-cb#)y`z!O(mTQ+y<;Ot@3;V@cgU}qOYgV=q<7p6(kp%s(kuQ5(kos7 z=@tJ1=@s&e*wQP~KzhXxkX|t!q*ojR(klvK6PyF`B-3_~Us3!M45nuchp%IyodwUq z-=S>;PfftlBe6PQBG%hvSOKeH6PynpjwOA1(-rUom@pp6hUqX9PJ$KibvO%t2-m|y z@CSGe_QDXf+HlB%Jn%phEISbnXIvfjG@RMVCS_}5TDW0(4bQ?0FgTBNVKtl%|Au$q5H!qC7>`+f1bhRogwxSD z0k{}0g%=8uTlfcB=xwM&6P*Mb;7ph?n|gq1sDod@LvZUHv<5s0e}>_6DFZmrOaovn z91gdFXshN0T3bEJ@d@}FyaJ;cS;oN|U@oMdVKT@s)hvb%SPO5#J1_*3d>9nK@vt0L zf;{Q)SCA(i2EuV*YeV^VS6ds}+E1Q*cnoYUXKOdD)$-}>Nj^VyAR79UZV!Xk7@*S| zx5FLqBD@4Lm%H{5r1=QOI2cQye7Iv0+8x~V=m2~R&W7*NgRTa7j!2#xI(LB{pHD$z zgD?uo%m@3~npCW}17i@+>7sV2k9s4-6Wr}Q+w0@$-g@S$vyBzZR^=-RJNQlmuX=tv zWSBgq?dO{cOrwr-VgBjwEC>-gK8_X4d)xUZPYgG3mxPq3z)fP6Paf{5RM&!>4?z=W zR~XBA7bFF_zk@RYqn4B!IIiUwG&+eP#NG1ARCmeeMp(sP$!|7SaF!Bl`g}x?v7!bYd#wJAm7<=yMyP{Z+EQbGd)6X zvu;g|y-nVyj&X47f|OyKcYLUBU68`93sP3|nOh}%HaFY1(*@&RsblzV0ein@`H4m& zH4=TLj!7e$*NJARj^=fV=5?YOD$z*b*l4n;+L)+NE74c#m;pq!F>To9jqj@*ZA>Go zjcKd-OjHuKYgE}3H8whovB)cR%s`?WI$+r5*Z-rU8#;jKh7MTGXQGp!Jw=yI!^cHA zBoZTaHi#&<66IpK#9-e(ooM8^z_HPxrb{wqT5-u@<6g(T4tXyxQPuKF z8LE%UceFsJ)BMp<3^JCY1=m2pSjS&En{I`cLnNVnGCSYLUpW_jFQU14)J5bfC1qgh zfV2TAscGkIFicKwwBxbz%=co52JoWgOun7QOL`{SG@!nt#?K7}#FJtS7~n{83>ug+ zz!q>j^Mo)q%AY#4ZW}rxfHr6BnXFPjWMEo~yb`8fgtitfEB7oOc9COa203=7r3^?< zO(Xlf2Bk-nN>OJjNy}8@f*(!ZLW)?p`||gh#-UAzH)Ew0sI&*AI#W^xq@*QGyO=vW zRQfVz*rjL2K=(N#{oFCe>$^y>MP*~yKd)Kzuc!X-9m#-vqlxw^cH*sY7#R87kvepP zT(n+VtLPFir%5$lkCws?lRWmV27Wwn$Dq57yNyko@^a$uxO7qc=iWcbv(4RKTBg+b zyt7Y~cCvd&_ptiRzI}&TmqsIrB}y7+;m6BChV*zU-*Y4Oi&!ZpeOYXgX8M+Xb+sIN z9$l@#$-@_>20lUqqb9rMSG2(HZ(sMud(|yNe|mAcaojO?Jtcz77@>w8xqcDIomYa` zCHF!aJOHB2p8)Z@?gml8uY!_OZkFMH1V@odlVb+Qxg2q_7-bw~5O#AED}FUc89_y> ziAHMYIGp2pj*|Y1B#N^_%~R@1>daZwbIdwlTSu!W90;0AL!M@@x-NN>mxPsk)Q39S z{k}EbuEmCv{8R;kZJyTb#z0u#E9Vvl>diWRd*uFHJPH!`2&nWm1OuT!Q`lS{2sWCt zvZ=fUoHx>bdzjRfdVlDW|4D!A{~YRl_{^~v*8I*P*C>{%Pgw(!&!VyAn0zH`AXx*+ z8c5bavIdehkgS1Z4J2zISp&%$NY+5I1`f0a63zc*UY+vf!%tqDJ$~qaUBUc6^F7%L zV+`nWu7b&GI>?+@=B+ItbM_BRVUP` zbK=7&;(Qu$tmY{3OsA&gxWf9(L4B5bJpy#9`n~u`dfxr0zeheczGYTC91bWxmT=?p zS96f@vB4rPz9k14-}El=l^kSzY!Hdd-~5A&4>wU|$8FzS>pojv?D!8f zzMM#Wqf~w}t!bCUVV)u|;1F76N(3zrc-=QOs zt`vFg8289{+2is(&TO>K+I!|Bfj;J&3?n6yzT~4Xw^v9YQC_@q*-Pr72ew9by6N+M z{d*|hI|qU7I_S%NZUWVdQsHGk70~sG1bub?f5%b&fdm@>eJ#JlI`MM(EBDFn_%^k3 zR@%NCDQHrA0Oj`{?PnWw*q;7QIe_}#AQ4&hKfv0>AAJ_%8BCh$Ep8s#iZ{* z^UJ>Bb~Jju(zJ51@2|s1UnG7Ie4P3hoh~n(syqi0W;~I;C|bVnFZuO8yX=Y5xBH!a zjE!AnH>t;CYw)Y}-a+f9W@y>%s=LL0>#~orB+$^&=Jkh_O;}kcdmA~WIQxi