tangent icon

Differences between PiDP-8/I software and upstream SIMH 4

tangent | PRO | 03/13/17 03:54:06 AM UTC | 0 ⭐ | 804 👁️ | Never ⏰ | []
Diff |

16.26 KB

|

None

|

0 👍

/

0 👎

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 <x> 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? */

Comments