diff -ru /usr/local/src/pidp8i/trunk/simh-update-temp/simh/ours/PDP8/pdp8_cpu.c ./src/PDP8/pdp8_cpu.c --- /usr/local/src/pidp8i/trunk/simh-update-temp/simh/ours/PDP8/pdp8_cpu.c 2017-03-18 20:42:31.000000000 -0600 +++ ./src/PDP8/pdp8_cpu.c 2017-03-18 19:46:38.000000000 -0600 @@ -23,6 +23,35 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + ---------------------------------------------------------------------------- + + Portions copyright (c) 2015-2017, Oscar Vermeulen and Warren Young + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the authors above shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in this Software without prior written authorization from those + authors. + + ---------------------------------------------------------------------------- + cpu central processor 09-Mar-17 RMS Fixed PCQ_ENTRY for interrupts (COVERITY) @@ -192,7 +221,10 @@ pdp8_sys.c add sim_devices table entry */ -#include "pdp8_defs.h" +/* ---PiDP change------------------------------------------------------------------------------------------- */ +#include "gpio-common.h" +#include "pidp8i.h" +/* ---PiDP end---------------------------------------------------------------------------------------------- */ #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) @@ -339,10 +371,33 @@ int_req = INT_UPDATE; reason = 0; + +/* ---PiDP add--------------------------------------------------------------------------------------------- */ +// PiDP-8/I specific flag, set when the last instruction was an IOT +// instruction to a real device. SIMH doesn't track this, but the front +// panel needs it. +int Pause = 0; + +// Set our initial IPS value from the throttle, if given. +static time_t last_update = 0; +static size_t max_skips = 0; +static const size_t pidp8i_updates_per_sec = 3200; +max_skips = get_pidp8i_initial_max_skips (pidp8i_updates_per_sec); +srand48 (time (&last_update)); + +// Reset display info in case we're re-entering the simulator from Ctrl-E +extern display display_bufs[2]; +memset (display_bufs, 0, sizeof(display_bufs)); +static size_t skip_count, dither, inst_count; +skip_count = dither = inst_count = 0; +/* ---PiDP end---------------------------------------------------------------------------------------------- */ + + /* Main instruction fetch/decode loop */ while (reason == 0) { /* loop until halted */ + // Allow clean exit to SCP: https://github.com/simh/simh/issues/387 if (cpu_astop != 0) { cpu_astop = 0; reason = SCPE_STOP; @@ -350,10 +405,64 @@ } if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event ())) + if ((reason = sim_process_event ())) { +/* ---PiDP add--------------------------------------------------------------------------------------------- */ + // We're about to leave the loop, so repaint one last time + // in case this is a Ctrl-E and we later get a "cont" + // command. Set a flag that will let us auto-resume. + extern int resumeFromInstructionLoopExit, swStop, swSingInst; + resumeFromInstructionLoopExit = swStop = swSingInst = 1; + set_pidp8i_leds (PC, MA, MB, IR, LAC, MQ, IF, DF, SC, + int_req, Pause); + + // Also copy SR hardware value to software register in case + // the user tries poking at it from the sim> prompt. + SR = get_switch_register(); +/* ---PiDP end---------------------------------------------------------------------------------------------- */ break; + } } +/* ---PiDP add--------------------------------------------------------------------------------------------- */ + + switch (handle_flow_control_switches(M, &PC, &MA, &MB, &LAC, &IF, + &DF, &int_req)) { + case pft_stop: + // Tell the SIMH event queue to keep running even though + // we're stopped. Without this, it will ignore Ctrl-E + // until the simulator is back in free-running mode. + sim_interval = sim_interval - 1; + + // Have to keep display updated while stopped. This does + // mean if the software starts with the STOP switch held + // down, we'll put garbage onto the display for MA, MB, and + // IR, but that's what the real hardware does, too. See + // https://github.com/simh/simh/issues/386 + set_pidp8i_leds (PC, MA, MB, IR, LAC, MQ, IF, DF, SC, + int_req, Pause); + + // Go no further in STOP mode. In particular, fetch no more + // instructions, and do not touch PC! + continue; + + case pft_halt: + // Clear all registers and halt simulator + PC = saved_PC = 0; + IF = saved_PC = 0; + DF = saved_DF = 0; + LAC = saved_LAC = 0; + MQ = saved_MQ = 0; + int_req = 0; + reason = STOP_HALT; + continue; + + case pft_normal: + // execute normally + break; + } + +/* ---PiDP end---------------------------------------------------------------------------------------------- */ + if (int_req > INT_PENDING) { /* interrupt? */ int_req = int_req & ~INT_ION; /* interrupts off */ SF = (UF << 6) | (IF >> 9) | (DF >> 12); /* form save field */ @@ -923,10 +1032,19 @@ tsc_cdf = 0; /* clear flag */ } else { - if (IR & 04) /* OSR */ + if (IR & 04) { /* OSR */ +/* ---PiDP add--------------------------------------------------------------------------------------------- */ + SR = get_switch_register(); /* get current SR */ +/* ---PiDP end---------------------------------------------------------------------------------------------- */ LAC = LAC | SR; - if (IR & 02) /* HLT */ - reason = STOP_HALT; + } + if (IR & 02) { /* HLT */ +//--- PiDP change----------------------------------------------------------------------- + // reason = STOP_HALT; + extern int swStop; + swStop = 1; + } +//--- end of PiDP change---------------------------------------------------------------- } break; } /* end if group 2 */ @@ -1346,6 +1464,10 @@ default: /* I/O device */ if (dev_tab[device]) { /* dev present? */ +/* ---PiDP add--------------------------------------------------------------------------------------------- */ + // Any other device will trigger IOP, so light pause + Pause = 1; +/* ---PiDP end---------------------------------------------------------------------------------------------- */ iot_data = dev_tab[device] (IR, iot_data); LAC = (LAC & 010000) | (iot_data & 07777); if (iot_data & IOT_SKP) @@ -1358,6 +1480,72 @@ } /* end switch device */ break; /* end case IOT */ } /* end switch opcode */ + +/* ---PiDP add--------------------------------------------------------------------------------------------- */ + // Update the front panel with this instruction's final state. + // + // There's no point saving *every* LED "on" count. We just need a + // suitable amount of oversampling. We can skip this if we called + // set_pidp8i_leds recently enough, avoiding all the expensive bit + // shift and memory update work it does. + // + // The trick here is figuring out what "recently enough" means + // without making expensive OS timer calls. These timers aren't + // hopelessly slow (http://stackoverflow.com/a/13096917/142454) but + // we still don't want to be taking dozens of cycles per instruction + // just to keep our update estimate current in the face of system + // load changes and SET THROTTLE updates. + // + // Instead, we maintain a model of the current IPS value — seeded + // with the initial "SET THROTTLE" value, if any — to figure out + // how many calls we can skip while still meeting our other goals. + // This involves a bit of math, but when paid only once a second, + // it amortizes much nicer than estimating the skip count directly + // based on a more accurate time source which is more expensive + // to call. It's also cheaper than continually asking SIMH to + // estimate the SIMH IPS value, since it uses FP math. + // + // Each LED panel repaint takes about 10 ms, so we do about 100 + // full-panel updates per second. We need a bare minimum of 32 + // discernible brightness values per update for ILS, so if we don't + // update the LED status data at least 3,200 times per second, we + // don't have enough data for smooth panel updates. Fortunately, + // computers are pretty quick, and our slowest script runs at 30 + // kIPS. (5.script.) + // + // We deliberately add some timing jitter here to get stochastic + // sampling of the incoming instructions to avoid beat frequencies + // between our update rate and the instruction pattern being + // executed by the front panel. It's a form of dithering. + // + // You might think to move this code to the top of set_pidp8i_leds, + // but the function call itself is a nontrivial hit. In fact, you + // don't even want to move all of this to a function here in this + // module and try to get GCC to inline it: that's good for a 1 MIPS + // speed hit in my testing! (GCC 4.9.2, Raspbian Jessie on Pi 3B.) + + if (++skip_count >= (max_skips - dither)) { + // Save skips to inst counter and reset + inst_count += skip_count; + skip_count = 0; + + // We need to update the LED data again + set_pidp8i_leds (PC, MA, MB, IR, LAC, MQ, IF, DF, SC, int_req, Pause); + Pause = 0; + + // Has it been ~1s since we updated our max_skips value? + time_t now; + if (time(&now) > last_update) { + // Yep; simulator IPS may have changed, so freshen it. + last_update = now; + max_skips = inst_count / pidp8i_updates_per_sec; + //printf("Inst./repaint: %zu - %zu; %.2f MIPS\r\n", + // max_skips, dither, inst_count / 1e6); + inst_count = 0; + } + dither = max_skips > 32 ? lrand48() % (max_skips >> 3) : 0; // 12.5% + } +/* ---PiDP end---------------------------------------------------------------------------------------------- */ } /* end while */ /* Simulation halted */ diff -ru /usr/local/src/pidp8i/trunk/simh-update-temp/simh/ours/scp.c ./src/scp.c --- /usr/local/src/pidp8i/trunk/simh-update-temp/simh/ours/scp.c 2017-03-18 20:42:31.000000000 -0600 +++ ./src/scp.c 2017-03-18 20:21:21.000000000 -0600 @@ -23,6 +23,35 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + ---------------------------------------------------------------------------- + + Portions copyright (c) 2015-2017, Oscar Vermeulen and Warren Young + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the authors above shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in this Software without prior written authorization from those + authors. + + ---------------------------------------------------------------------------- + 08-Mar-16 RMS Added shutdown flag for detach_all 20-Mar-12 MP Fixes to "SHOW SHOW" commands 06-Jan-12 JDB Fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) @@ -214,6 +243,11 @@ /* Macros and data structures */ +#ifdef PIDP8I +#include "gpio-common.h" // for start/stop_pidp8i_gpio_thread() +#include "PDP8/pidp8i.h" // for build_pidp8i_scp_cmd() +#endif + #define NOT_MUX_USING_CODE /* sim_tmxr library provider or agnostic */ #include "sim_defs.h" @@ -1997,6 +2031,10 @@ t_bool lookswitch; t_stat stat; +#ifdef PIDP8I +if (start_pidp8i_gpio_thread ("PiDP-8/I simulator", 1) != 0) exit (EXIT_FAILURE); +#endif + #if defined (__MWERKS__) && defined (macintosh) argc = ccommand (&argv); #endif @@ -2140,6 +2178,11 @@ sim_cleanup_sock (); /* cleanup sockets */ fclose (stdnul); /* close bit bucket file handle */ free (targv); /* release any argv copy that was made */ + +#ifdef PIDP8I +stop_pidp8i_gpio_thread (); +#endif + return 0; } @@ -2152,6 +2195,11 @@ stat = SCPE_BARE_STATUS(stat); /* remove possible flag */ while (stat != SCPE_EXIT) { /* in case exit */ +#ifdef PIDP8I + if (cptr = build_pidp8i_scp_cmd (cbuf, sizeof (cbuf))) + printf ("Running '%s'...\n", cptr); + else +#endif if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf)))) /* pending action? */ printf ("%s%s\n", sim_prompt, cptr); /* echo */ else if (sim_vm_read != NULL) { /* sim routine? */