diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c
index 1ae1b9357381b399640f59c2325ffeccb2c62873..e6cf3e362eca528ee37cd4a667d2c7857e106d46 100644
--- a/AltairZ80/altairZ80_sio.c
+++ b/AltairZ80/altairZ80_sio.c
@@ -148,7 +148,6 @@ extern const t_bool rtc_avail;
 extern uint32 PCX;
 extern int32 sim_switches;
 extern int32 sim_quiet;
-extern const char *scp_error_messages[];
 extern int32 SR;
 extern UNIT cpu_unit;
 extern volatile int32 stop_cpu;
@@ -1180,7 +1179,7 @@ static void attachCPM(UNIT *uptr) {
     sim_quiet = sim_switches & SWMASK ('Q');    /* -q means quiet                       */
     lastCPMStatus = attach_unit(uptr, cpmCommandLine);
     if ((lastCPMStatus != SCPE_OK) && (simh_device.dctrl & VERBOSE_MSG))
-        printf("SIMH: " ADDRESS_FORMAT " Cannot open '%s' (%s)." NLP, PCX, cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]);
+        printf("SIMH: " ADDRESS_FORMAT " Cannot open '%s' (%s)." NLP, PCX, cpmCommandLine, sim_error_text(lastCPMStatus));
 }
 
 /* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */
diff --git a/scp.c b/scp.c
index f64196a2af078a6650540cca902b294959fc957b..c8b3bf44a75add82b81c3f911be7c44df9559dd3 100644
--- a/scp.c
+++ b/scp.c
@@ -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.
 
+   22-Jan-11    MP      Added SET ON, SET NOON, ON, GOTO and RETURN command support
    08-Feb-09    RMS     Fixed warnings in help printouts
    29-Dec-08    RMS     Fixed implementation of MTAB_NC
    24-Nov-08    RMS     Revised RESTORE unit logic for consistency
@@ -182,6 +183,7 @@
 #include "sim_rev.h"
 #include <signal.h>
 #include <ctype.h>
+#include <time.h>
 
 #define EX_D            0                               /* deposit */
 #define EX_E            1                               /* examine */
@@ -201,7 +203,7 @@
 #define SSH_SH          1                               /* show */
 #define SSH_CL          2                               /* clear */
 
-#define DO_NEST_LVL     10                              /* DO cmd nesting level */
+#define MAX_DO_NEST_LVL 10                              /* DO cmd nesting level */
 #define SRBSIZ          1024                            /* save/restore buffer */
 #define SIM_BRK_INILNT  4096                            /* bpt tbl length */
 #define SIM_BRK_ALLTYP  0xFFFFFFFF
@@ -286,6 +288,7 @@ t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *
 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
+t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg);
@@ -347,6 +350,8 @@ t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr,
     UNIT *uptr, int32 dfltinc);
 t_stat step_svc (UNIT *ptr);
 void sub_args (char *instr, char *tmpbuf, int32 maxstr, char *do_arg[]);
+t_stat set_on (int32 flag, char *cptr);
+
 
 /* Global data */
 
@@ -363,7 +368,7 @@ int32 sim_is_running = 0;
 uint32 sim_brk_summ = 0;
 uint32 sim_brk_types = 0;
 uint32 sim_brk_dflt = 0;
-char *sim_brk_act = NULL;
+char *sim_brk_act[MAX_DO_NEST_LVL];
 BRKTAB *sim_brk_tab = NULL;
 int32 sim_brk_ent = 0;
 int32 sim_brk_lnt = 0;
@@ -380,6 +385,13 @@ t_value *sim_eval = NULL;
 int32 sim_deb_close = 0;                                /* 1 = close debug */
 FILE *sim_log = NULL;                                   /* log file */
 FILE *sim_deb = NULL;                                   /* debug file */
+
+static FILE *sim_gotofile;
+static int32 sim_do_depth = 0;
+
+static int32 sim_on_check[MAX_DO_NEST_LVL+1];
+static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
+
 static SCHTAB sim_stab;
 
 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0)  };
@@ -393,7 +405,7 @@ static const char *sim_sa64 = "64b addresses";
 #else
 static const char *sim_sa64 = "32b addresses";
 #endif
-#if defined USE_NETWORK
+#if defined USE_NETWORK || defined USE_SHARED
 static const char *sim_snet = "Ethernet support";
 #else
 static const char *sim_snet = "no Ethernet";
@@ -404,51 +416,54 @@ static const char *sim_snet = "no Ethernet";
 const char save_vercur[] = "V3.5";
 const char save_ver32[] = "V3.2";
 const char save_ver30[] = "V3.0";
-const char *scp_error_messages[] = {
-    "Address space exceeded",
-    "Unit not attached",
-    "I/O error",
-    "Checksum error",
-    "Format error",
-    "Unit not attachable",
-    "File open error",
-    "Memory exhausted",
-    "Invalid argument",
-    "Step expired",
-    "Unknown command",
-    "Read only argument",
-    "Command not completed",
-    "Simulation stopped",
-    "Goodbye",
-    "Console input I/O error",
-    "Console output I/O error",
-    "End of file",
-    "Relocation error",
-    "No settable parameters",
-    "Unit already attached",
-    "Hardware timer error",
-    "SIGINT handler setup error",
-    "Console terminal setup error",
-    "Subscript out of range",
-    "Command not allowed",
-    "Unit disabled",
-    "Read only operation not allowed",
-    "Invalid switch",
-    "Missing value",
-    "Too few arguments",
-    "Too many arguments",
-    "Non-existent device",
-    "Non-existent unit",
-    "Non-existent register",
-    "Non-existent parameter",
-    "Nested DO command limit exceeded",
-    "Internal error",
-    "Invalid magtape record length",
-    "Console Telnet connection lost",
-    "Console Telnet connection timed out",
-    "Console Telnet output stall",
-    "Assertion failed"
-    };
+const struct scp_error {
+    char *code;
+    char *message;
+    } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
+        {{"NXM",     "Address space exceeded"},
+         {"UNATT",   "Unit not attached"},
+         {"IOERR",   "I/O error"},
+         {"CSUM",    "Checksum error"},
+         {"FMT",     "Format error"},
+         {"NOATT",   "Unit not attachable"},
+         {"OPENERR", "File open error"},
+         {"MEM",     "Memory exhausted"},
+         {"ARG",     "Invalid argument"},
+         {"STEP",    "Step expired"},
+         {"UNK",     "Unknown command"},
+         {"RO",      "Read only argument"},
+         {"INCOMP",  "Command not completed"},
+         {"STOP",    "Simulation stopped"},
+         {"EXIT",    "Goodbye"},
+         {"TTIERR",  "Console input I/O error"},
+         {"TTOERR",  "Console output I/O error"},
+         {"EOF",     "End of file"},
+         {"REL",     "Relocation error"},
+         {"NOPARAM", "No settable parameters"},
+         {"ALATT",   "Unit already attached"},
+         {"TIMER",   "Hardware timer error"},
+         {"SIGERR",  "SIGINT handler setup error"},
+         {"TTYERR",  "Console terminal setup error"},
+         {"SUB",     "Subscript out of range"},
+         {"NOFNC",   "Command not allowed"},
+         {"UDIS",    "Unit disabled"},
+         {"NORO",    "Read only operation not allowed"},
+         {"INVSW",   "Invalid switch"},
+         {"MISVAL",  "Missing value"},
+         {"2FARG",   "Too few arguments"},
+         {"2MARG",   "Too many arguments"},
+         {"NXDEV",   "Non-existent device"},
+         {"NXUN",    "Non-existent unit"},
+         {"NXREG",   "Non-existent register"},
+         {"NXPAR",   "Non-existent parameter"},
+         {"NEST",    "Nested DO command limit exceeded"},
+         {"IERR",    "Internal error"},
+         {"MTRLNT",  "Invalid magtape record length"},
+         {"LOST",    "Console Telnet connection lost"},
+         {"TTMO",    "Console Telnet connection timed out"},
+         {"STALL",   "Console Telnet output stall"},
+         {"AFAIL",   "Assertion failed"},
+};
 
 const size_t size_map[] = { sizeof (int8),
     sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
@@ -543,6 +558,8 @@ static CTAB cmd_table[] = {
       "set <unit> ENABLED       enable unit\n"
       "set <unit> DISABLED      disable unit\n"
       "set <unit> arg{,arg...}  set unit parameters\n"
+      "set on                   enables error checking after command execution\n"
+      "set noon                 disables error checking after command execution\n"
       },
     { "SHOW", &show_cmd, 0,
       "sh{ow} br{eak} <list>    show breakpoints\n"
@@ -560,9 +577,18 @@ static CTAB cmd_table[] = {
       "sh{ow} <dev> MODIFIERS   show device modifiers\n"
       "sh{ow} <dev} NAMES       show device logical name\n"
       "sh{ow} <dev> {arg,...}   show device parameters\n"
-      "sh{ow} <unit> {arg,...}  show unit parameters\n"  },
+      "sh{ow} <unit> {arg,...}  show unit parameters\n"
+      "sh{ow} on                show on condition actions\n"  },
     { "DO", &do_cmd, 1,
       "do <file> {arg,arg...}   process command file\n" },
+    { "GOTO", &goto_cmd, 1,
+      "goto <label>             goto label in command file\n" },
+    { "RETURN", &return_cmd, 0,
+      "return                   return from command file with last command status\n"
+      "return <status>          return from command file with specific status\n" },
+    { "ON", &on_cmd, 0,
+      "on <condition> <action>  perform action after condition\n"
+      "on <condition>           clear action for specific condition\n" },
     { "ECHO", &echo_cmd, 0,
       "echo <string>            display <string>\n" },
     { "ASSERT", &assert_cmd, 0,
@@ -632,7 +658,7 @@ sim_timer_init ();
 
 if ((stat = sim_ttinit ()) != SCPE_OK) {
     fprintf (stderr, "Fatal terminal initialization error\n%s\n",
-        scp_error_messages[stat - SCPE_BASE]);
+        sim_error_text (stat));
     return 0;
     }
 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
@@ -641,12 +667,12 @@ if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
     };
 if ((stat = reset_all_p (0)) != SCPE_OK) {
     fprintf (stderr, "Fatal simulator initialization error\n%s\n",
-        scp_error_messages[stat - SCPE_BASE]);
+        sim_error_text (stat));
     return 0;
     }
 if ((stat = sim_brk_init ()) != SCPE_OK) {
     fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",
-        scp_error_messages[stat - SCPE_BASE]);
+        sim_error_text (stat));
     return 0;
     }
 if (!sim_quiet) {
@@ -687,9 +713,9 @@ while (stat != SCPE_EXIT) {                             /* in case exit */
         stat = cmdp->action (cmdp->arg, cptr);          /* if found, exec */
     else stat = SCPE_UNK;
     if (stat >= SCPE_BASE) {                            /* error? */
-        printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);
+        printf ("%s\n", sim_error_text (stat));
         if (sim_log)
-            fprintf (sim_log, "%s\n", scp_error_messages[stat - SCPE_BASE]);
+            fprintf (sim_log, "%s\n", sim_error_text (stat));
         }
     if (sim_vm_post != NULL)
         (*sim_vm_post) (TRUE);
@@ -769,6 +795,7 @@ return SCPE_OK;
 
 t_stat spawn_cmd (int32 flag, char *cptr)
 {
+t_stat status;
 if ((cptr == NULL) || (strlen (cptr) == 0))
     cptr = getenv("SHELL");
 if ((cptr == NULL) || (strlen (cptr) == 0))
@@ -780,12 +807,12 @@ if ((cptr == NULL) || (strlen (cptr) == 0))
 fflush(stdout);                                         /* flush stdout */
 if (sim_log)                                            /* flush log if enabled */
     fflush (sim_log);
-system (cptr);
+status = system (cptr);
 #if defined (VMS)
 printf ("\n");
 #endif
 
-return SCPE_OK;
+return status;
 }
 
 /* Echo command */
@@ -831,7 +858,7 @@ t_stat do_cmd (int32 flag, char *fcptr)
 char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE], *c, quote, *do_arg[10];
 FILE *fpin;
 CTAB *cmdp;
-int32 echo, nargs, errabort;
+int32 echo, nargs, errabort, i;
 t_bool interactive, isdo, staying;
 t_stat stat;
 char *ocptr;
@@ -875,6 +902,9 @@ if ((fpin = fopen (do_arg[0], "r")) == NULL) {          /* file failed to open?
     }
 if (flag < 1)                                           /* start at level 1 */
     flag = 1;
+++sim_do_depth;
+if (errabort)                                           /* -e flag? */
+    set_on (1, NULL);                                   /* equivalent to ON ERROR RETURN */
 
 do {
     ocptr = cptr = sim_brk_getact (cbuf, CBUFSIZE);     /* get bkpt action */
@@ -891,13 +921,18 @@ do {
         printf("do> %s\n", cptr);
     if (echo && sim_log)
         fprintf (sim_log, "do> %s\n", cptr);
+    if (*cptr == ':')                                   /* ignore label */
+        continue;
     cptr = get_glyph (cptr, gbuf, 0);                   /* get command glyph */
     sim_switches = 0;                                   /* init switches */
     isdo = FALSE;
+    sim_gotofile = fpin;
     if (cmdp = find_cmd (gbuf)) {                       /* lookup command */
+        if ((cmdp->action == &return_cmd))              /* RETURN command? */
+            break;                                      /*    done! */
         isdo = (cmdp->action == &do_cmd);
         if (isdo) {                                     /* DO command? */
-            if (flag >= DO_NEST_LVL)                    /* nest too deep? */
+            if (flag >= MAX_DO_NEST_LVL)                /* nest too deep? */
                 stat = SCPE_NEST;
             else stat = do_cmd (flag + 1, cptr);        /* exec DO cmd */
             }
@@ -907,6 +942,10 @@ do {
     staying = (stat != SCPE_EXIT) &&                    /* decide if staying */
               (stat != SCPE_AFAIL) &&
               (!errabort || (stat < SCPE_BASE) || (stat == SCPE_STEP));
+    if ((stat == SCPE_AFAIL) &&                         /* handle special case AFAIL */
+        sim_on_check[sim_do_depth] &&                   /* and use trap action if defined */
+        sim_on_actions[sim_do_depth][stat])             /* otherwise exit */
+        staying = TRUE;
     if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&   /* error from cmd? */
         (stat != SCPE_STEP)) {
         if (!echo && !sim_quiet &&                      /* report if not echoing */
@@ -919,19 +958,42 @@ do {
         }
     if ((staying || !interactive) &&                    /* report error if staying */
         (stat >= SCPE_BASE)) {                          /* or in cmdline file */
-        printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);
+        printf ("%s\n", sim_error_text (stat));
         if (sim_log)
-            fprintf (sim_log, "%s\n", scp_error_messages[stat - SCPE_BASE]);
+            fprintf (sim_log, "%s\n", sim_error_text (stat));
         }
+    if (staying &&
+        (sim_on_check[sim_do_depth]) && 
+        (stat != SCPE_OK) &&
+        (stat != SCPE_STEP))
+        if (sim_on_actions[sim_do_depth][stat])
+            sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][stat];
+        else
+            sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][0];
     if (sim_vm_post != NULL)
         (*sim_vm_post) (TRUE);
     } while (staying);
 
 fclose (fpin);                                          /* close file */
-return stat;
+sim_gotofile = NULL;
+for (i=0; i<SCPE_MAX_ERR; i++) {                        /* release any on commands */
+    free (sim_on_actions[sim_do_depth][i]);
+    sim_on_actions[sim_do_depth][i] = NULL;
+    }
+sim_on_check[sim_do_depth] = 0;                         /* clear on mode */
+sim_brk_clract ();                                      /* defang breakpoint actions */
+--sim_do_depth;                                         /* unwind nesting */
+if (cmdp && (cmdp->action == &return_cmd)) {            /* return command? */
+    if (0 == *cptr)
+        return stat;                                    /* return with last command status */
+    sim_string_to_stat (cptr, &stat);
+    return stat;                                        /* return with explicit return status */
+    }
+return (stat == SCPE_EXIT) ? SCPE_EXIT : SCPE_OK;
 }
 
 /* Substitute_args - replace %n tokens in 'instr' with the do command's arguments
+                     and other enviroment variables
 
    Calling sequence
    instr        =       input string
@@ -957,16 +1019,49 @@ for (ip = instr, op = tmpbuf; *ip && (op < oend); ) {
         ip++;                                           /* skip '\' */
         *op++ = *ip++;                                  /* copy escaped char */
         }
-    else if ((*ip == '%') &&                            /* %n = sub */
-             ((ip[1] >= '0') && (ip[1] <= ('9')))) {
-        ap = do_arg[ip[1] - '0'];
-        ip = ip + 2;
-        if (ap) {                                       /* non-null arg? */
-            while (*ap && (op < oend))                  /* copy the argument */
-                *op++ = *ap++;
+    else
+        if (*ip == '%') {                               /* sub? */
+            if ((ip[1] >= '0') && (ip[1] <= ('9'))) {   /* %n = sub */
+                ap = do_arg[ip[1] - '0'];
+                ip = ip + 2;
+                }
+            else {                                      /* environment variable */
+                char gbuf[CBUFSIZE];
+
+                ap = NULL;
+                get_glyph_gen (ip+1, gbuf, '%', FALSE);
+                ip += 1 + strlen (gbuf);
+                if (*ip == '%') ++ip;
+                ap = getenv(gbuf);
+                if (!ap) {
+                    static char rbuf[CBUFSIZE];
+                    time_t now;
+                    struct tm *tmnow;
+
+                    time(&now);
+                    tmnow = localtime(&now);
+                    if (!strcmp ("DATE", gbuf)) {
+                        sprintf (rbuf, "%4d/%02d/%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday);
+                        ap = rbuf;
+                        }
+                    else if (!strcmp ("TIME", gbuf)) {
+                        sprintf (rbuf, "%02d:%02d:%02d", tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec);
+                        ap = rbuf;
+                        }
+                    else if (!strcmp ("CTIME", gbuf)) {
+                        strcpy (rbuf, ctime(&now));
+                        rbuf[strlen (rbuf)-1] = '\0';    /* remove trailing \n */
+                        ap = rbuf;
+                        }
+                    }
+                }
+            if (ap) {                                   /* non-null arg? */
+                while (*ap && (op < oend))              /* copy the argument */
+                    *op++ = *ap++;
+                }
             }
-        }
-    else *op++ = *ip++;                                 /* literal character */
+        else
+            *op++ = *ip++;                              /* literal character */
     }
 *op = 0;                                                /* term buffer */
 strcpy (instr, tmpbuf);
@@ -1025,6 +1120,92 @@ if (test_search (val, &sim_stab))                       /* test condition */
 return SCPE_AFAIL;                                      /* condition fails */
 }
 
+
+/* Goto command */
+
+t_stat goto_cmd (int32 flag, char *fcptr)
+{
+char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
+long fpos;
+
+if (NULL == sim_gotofile) return SCPE_UNK;		/* only valid inside of do_cmd */
+get_glyph (fcptr, gbuf1, 0);
+if ('\0' == gbuf1[0]) return SCPE_ARG;                  /* unspecified goto target */
+fpos = ftell(sim_gotofile);                             /* Save start position */
+rewind(sim_gotofile);                                   /* start search for label */
+while (1) {
+    cptr = read_line (cbuf, CBUFSIZE, sim_gotofile);    /* get cmd line */
+    if (cptr == NULL) break;                            /* exit on eof */
+    if (*cptr == 0) continue;                           /* ignore blank */
+    if (*cptr != ':') continue;                         /* ignore non-labels */
+    ++cptr;                                             /* skip : */
+    while (isspace (*cptr)) ++cptr;                     /* skip blanks */
+    cptr = get_glyph (cptr, gbuf, 0);                   /* get label glyph */
+    if (0 == strcmp(gbuf, gbuf1)) {
+        sim_brk_clract ();                              /* goto defangs current actions */
+        return SCPE_OK;
+        }
+    }
+fseek(sim_gotofile, fpos, SEEK_SET);                    /* resture start position */
+return SCPE_ARG;
+}
+
+/* Return command */
+/* The return command is invalid unless encountered in a do_cmd context, */
+/* and in that context, it is handled as a special case inside of do_cmd() */
+/* and not dispatched here, so if we get here a return has been issued from */
+/* interactive input */
+
+t_stat return_cmd (int32 flag, char *fcptr)
+{
+return SCPE_UNK;                                        /* only valid inside of do_cmd */
+}
+
+/* On command */
+
+t_stat on_cmd (int32 flag, char *cptr)
+{
+char gbuf[CBUFSIZE];
+int32 cond;
+
+cptr = get_glyph (cptr, gbuf, 0);
+if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified condition */
+if (0 == strcmp("ERROR", gbuf))
+    cond = 0;
+else
+    if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
+        return SCPE_ARG;
+if ((NULL == cptr) || ('\0' == *cptr)) {                /* Empty Action */
+    free(sim_on_actions[sim_do_depth][cond]);           /* Clear existing condition */
+    sim_on_actions[sim_do_depth][cond] = NULL; }
+else {
+    sim_on_actions[sim_do_depth][cond] = 
+        realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
+    strcpy(sim_on_actions[sim_do_depth][cond], cptr);
+    }
+return SCPE_OK;
+}
+
+t_stat set_on (int32 flag, char *cptr)
+{
+if (cptr && (*cptr != 0))                               /* now eol? */
+    return SCPE_2MARG;
+sim_on_check[sim_do_depth] = flag;
+if ((sim_do_depth != 0) && 
+    (NULL == sim_on_actions[sim_do_depth][0])) {        /* default handler set? */
+    sim_on_actions[sim_do_depth][0] =                   /* No, so make "RETURN" */
+        malloc(1+strlen("RETURN"));                     /* be the default action */
+    strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
+    }
+if ((sim_do_depth != 0) && 
+    (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {/* handler set for AFAIL? */
+    sim_on_actions[sim_do_depth][SCPE_AFAIL] =          /* No, so make "RETURN" */
+        malloc(1+strlen("RETURN"));                     /* be the action */
+    strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
+    }
+return SCPE_OK;
+}
+
 /* Set command */
 
 t_stat set_cmd (int32 flag, char *cptr)
@@ -1049,6 +1230,8 @@ static CTAB set_glob_tab[] = {
     { "NODEBUG", &sim_set_deboff, 0 },                  /* deprecated */
     { "THROTTLE", &sim_set_throt, 1 },
     { "NOTHROTTLE", &sim_set_throt, 0 },
+    { "ON", &set_on, 1 },
+    { "NOON", &set_on, 0 },
     { NULL, NULL, 0 }
     };
 
@@ -1311,6 +1494,7 @@ static SHTAB show_glob_tab[] = {
     { "TELNET", &sim_show_telnet, 0 },                  /* deprecated */
     { "DEBUG", &sim_show_debug, 0 },                    /* deprecated */
     { "THROTTLE", &sim_show_throt, 0 },
+    { "ON", &show_on, 0 },
     { NULL, NULL, 0 }
     };
 
@@ -1618,6 +1802,31 @@ if (dptr->flags & DEV_DEBUG) {
 else return SCPE_NOFNC;
 }
 
+/* Show On actions */
+
+t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
+{
+int32 lvl, i;
+if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
+for (lvl=sim_do_depth; lvl >= 0; --lvl) {
+    if (lvl > 0)
+        fprintf(st, "On Processing at Do Nest Level: %d", lvl);
+    else
+        fprintf(st, "On Processing for input commands");
+    fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
+    for (i=1; i<SCPE_BASE; ++i) {
+        if (sim_on_actions[lvl][i])
+            fprintf(st, "    on %5d    %s\n", i, sim_on_actions[lvl][i]); }
+    for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
+        if (sim_on_actions[lvl][i])
+            fprintf(st, "    on %-5s    %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
+    if (sim_on_actions[lvl][0])
+        fprintf(st, "    on ERROR    %s\n", sim_on_actions[lvl][0]);
+    fprintf(st, "\n");
+    }
+return SCPE_OK;
+}
+
 /* Show modifiers */
 
 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr)
@@ -2686,7 +2895,7 @@ t_addr k;
 t_value pcval;
 
 if (v >= SCPE_BASE) fprintf (st, "\n%s, %s: ",
-    scp_error_messages[v - SCPE_BASE], pc->name);
+    sim_error_text (v), pc->name);
 else fprintf (st, "\n%s, %s: ", sim_stop_messages[v], pc->name);
 pcval = get_rval (pc, 0);
 if (sim_vm_fprint_addr)
@@ -4397,7 +4606,7 @@ sim_brk_tab = (BRKTAB *) calloc (sim_brk_lnt, sizeof (BRKTAB));
 if (sim_brk_tab == NULL)
     return SCPE_MEM;
 sim_brk_ent = sim_brk_ins = 0;
-sim_brk_act = NULL;
+sim_brk_act[sim_do_depth] = NULL;
 sim_brk_npc (0);
 return SCPE_OK;
 }
@@ -4598,7 +4807,7 @@ if ((bp = sim_brk_fnd (loc)) && (btyp & bp->typ)) {     /* in table, type match?
     bp->cnt = 0;                                        /* reset count */
     sim_brk_ploc[spc] = loc;                            /* save location */
     sim_brk_pend[spc] = TRUE;                           /* don't do twice */
-    sim_brk_act = bp->act;                              /* set up actions */
+    sim_brk_act[sim_do_depth] = bp->act;                /* set up actions */
     return (btyp & bp->typ);
     }
 sim_brk_pend[spc] = FALSE;
@@ -4612,21 +4821,21 @@ char *sim_brk_getact (char *buf, int32 size)
 char *ep;
 size_t lnt;
 
-if (sim_brk_act == NULL)                                /* any action? */
+if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
     return NULL;
-while (isspace (*sim_brk_act))                          /* skip spaces */
-    sim_brk_act++;
-if (*sim_brk_act == 0)                              /* now empty? */
-    return (sim_brk_act = NULL);
-if (ep = strchr (sim_brk_act, ';')) {                   /* cmd delimiter? */
-    lnt = ep - sim_brk_act;                             /* cmd length */
-    memcpy (buf, sim_brk_act, lnt + 1);                 /* copy with ; */
+while (isspace (*sim_brk_act[sim_do_depth]))            /* skip spaces */
+    sim_brk_act[sim_do_depth]++;
+if (*sim_brk_act[sim_do_depth] == 0)                    /* now empty? */
+    return (sim_brk_act[sim_do_depth] = NULL);
+if (ep = strchr (sim_brk_act[sim_do_depth], ';')) {     /* cmd delimiter? */
+    lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
+    memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
     buf[lnt] = 0;                                       /* erase ; */
-    sim_brk_act = sim_brk_act + lnt + 1;                /* adv ptr */
+    sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
     }
 else {
-    strncpy (buf, sim_brk_act, size);                   /* copy action */
-    sim_brk_act = NULL;                                 /* no more */
+    strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
+    sim_brk_act[sim_do_depth] = NULL;                   /* no more */
     }
 return buf;
 }
@@ -4635,7 +4844,7 @@ return buf;
 
 void sim_brk_clract (void)
 {
-sim_brk_act = NULL;
+sim_brk_act[sim_do_depth] = NULL;
 }
 
 /* New PC */
@@ -4664,6 +4873,43 @@ if (spc < SIM_BKPT_N_SPC) {
 return;
 }
 
+/* Message Text */
+
+char *sim_error_text (t_stat stat)
+{
+static char msgbuf[64];
+
+stat &= ~(SCPE_KFLAG|SCPE_BREAK);                       /* remove any flags */
+if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
+    return scp_errors[stat-SCPE_BASE].message;
+sprintf(msgbuf, "Error %d", stat);
+return msgbuf;
+}
+
+t_stat sim_string_to_stat (char *cptr, t_stat *stat)
+{
+char gbuf[CBUFSIZE];
+int32 cond;
+
+*stat = SCPE_ARG;
+cptr = get_glyph (cptr, gbuf, 0);
+if (0 == memcmp("SCPE_", gbuf, 5))
+    strcpy (gbuf, gbuf+5);   /* skip leading SCPE_ */
+for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
+    if (0 == strcmp(scp_errors[cond].code, gbuf)) {
+        cond += SCPE_BASE;
+        break;
+        }
+if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
+    if (0 == (cond = strtol(gbuf, NULL, 0)))  /* try explicit number */
+        return SCPE_ARG;
+    }
+if (cond > SCPE_MAX_ERR)
+    return SCPE_ARG;
+*stat = cond;
+return SCPE_OK;    
+}
+
 /* Debug printout routines, from Dave Hittner */
 
 const char* debug_bstates = "01_^";
diff --git a/scp.h b/scp.h
index cdb2c33a6edcdafbad433a286ccbcbe4706e3ede..cb22baa005ba301354cd4e4ed5564cff94369991 100644
--- a/scp.h
+++ b/scp.h
@@ -69,6 +69,9 @@ t_stat set_cmd (int32 flag, char *ptr);
 t_stat show_cmd (int32 flag, char *ptr);
 t_stat brk_cmd (int32 flag, char *ptr);
 t_stat do_cmd (int32 flag, char *ptr);
+t_stat goto_cmd (int32 flag, char *ptr);
+t_stat return_cmd (int32 flag, char *ptr);
+t_stat on_cmd (int32 flag, char *ptr);
 t_stat assert_cmd (int32 flag, char *ptr);
 t_stat help_cmd (int32 flag, char *ptr);
 t_stat spawn_cmd (int32 flag, char *ptr);
@@ -113,6 +116,8 @@ BRKTAB *sim_brk_fnd (t_addr loc);
 uint32 sim_brk_test (t_addr bloc, uint32 btyp);
 void sim_brk_clrspc (uint32 spc);
 char *match_ext (char *fnam, char *ext);
+char *sim_error_text (t_stat stat);
+t_stat sim_string_to_stat (char *cptr, t_stat *cond);
 t_stat sim_cancel_step (void);
 void sim_debug_u16 (uint32 dbits, DEVICE* dptr, const char* const* bitdefs,
     uint16 before, uint16 after, int terminate);
diff --git a/sim_defs.h b/sim_defs.h
index 66f67d4450decc9382f15395253ff4821aabb50b..89ea0f8320be85ba4242cc7523be2d3218c2ad7e 100644
--- a/sim_defs.h
+++ b/sim_defs.h
@@ -242,6 +242,8 @@ typedef uint32          t_addr;
 #define SCPE_TTMO       (SCPE_BASE + 40)                /* Telnet conn timeout */
 #define SCPE_STALL      (SCPE_BASE + 41)                /* Telnet conn stall */
 #define SCPE_AFAIL      (SCPE_BASE + 42)                /* assert failed */
+
+#define SCPE_MAX_ERR    (SCPE_BASE + 43)                /* Maximum SCPE Error Value */
 #define SCPE_KFLAG      0010000                         /* tti data flag */
 #define SCPE_BREAK      0020000                         /* tti break flag */