From 651faa78aeb02bfa1b0fbd9cf516d0f1a482c61c Mon Sep 17 00:00:00 2001
From: Seth Morabito <web@loomcom.com>
Date: Wed, 27 Dec 2017 15:11:30 -0800
Subject: [PATCH] 3b2: Allow handling of TRACE and BREAKPOINT traps

The 3B2 emulator did not have support for traps, rendering debugging
under the simulator fairly useless. This change adds support for
trap handling. The 'sdb' UNIX debugger under SVR3 should now work
correctly.
---
 3B2/3b2_cpu.c  | 251 +++++++++++++++++++++++++------------------------
 3B2/3b2_cpu.h  |   1 +
 3B2/3b2_defs.h |  17 ++--
 3B2/3b2_iu.c   |   2 +-
 4 files changed, 138 insertions(+), 133 deletions(-)

diff --git a/3B2/3b2_cpu.c b/3B2/3b2_cpu.c
index 9d5f2fd0..b55a8b4f 100644
--- a/3B2/3b2_cpu.c
+++ b/3B2/3b2_cpu.c
@@ -74,7 +74,7 @@ int8   cpu_etype      = -1;        /* Currently set expanded datatype */
 
 t_bool cpu_nmi        = FALSE;     /* If set, there has been an NMI */
 
-uint8  cpu_ilen       = 0;         /* Length (in bytes) of instruction
+int32  pc_incr        = 0;         /* Length (in bytes) of instruction
                                      currently being executed */
 t_bool cpu_ex_halt    = FALSE;     /* Flag to halt on exceptions /
                                       traps */
@@ -133,6 +133,7 @@ static DEBTAB cpu_deb_tab[] = {
     { "IRQ",        IRQ_MSG,        "Interrupt Handling"    },
     { "IO",         IO_D_MSG,       "I/O Dispatch"          },
     { "TRACE",      TRACE_MSG,      "Call Trace"            },
+    { "ERROR",      ERR_MSG,        "Error"                 },
     { NULL,         0                                       }
 };
 
@@ -202,7 +203,7 @@ mnemonic hword_ops[HWORD_OP_COUNT] = {
 
 /* Lookup table of operand types. */
 mnemonic ops[256] = {
-    {0x00, -1, OP_NONE, NA, "???",    -1, -1, -1, -1},
+    {0x00,  0, OP_NONE, NA, "halt",   -1, -1, -1, -1},
     {0x01, -1, OP_NONE, NA, "???",    -1, -1, -1, -1},
     {0x02,  2, OP_COPR, WD, "SPOPRD", -1, -1, -1, -1},
     {0x03,  3, OP_COPR, WD, "SPOPD2", -1, -1, -1, -1},
@@ -1314,10 +1315,6 @@ t_bool cpu_on_interrupt(uint8 ipl)
     uint32 new_pcbp;
     uint16 id = ipl; /* TODO: Does this need to be uint16? */
 
-    sim_debug(IRQ_MSG, &cpu_dev,
-              "[%08x] [cpu_on_interrupt] ipl=%d\n",
-              R[NUM_PC], ipl);
-
     /*
      * "If a nonmaskable interrupt request is received, an auto-vector
      * interrupt acknowledge cycle is performed (as if an autovector
@@ -1330,7 +1327,7 @@ t_bool cpu_on_interrupt(uint8 ipl)
 
     cpu_km = TRUE;
 
-    if ((R[NUM_PSW] & PSW_QIE_MASK) >> PSW_QIE) {
+    if (R[NUM_PSW] & PSW_QIE_MASK) {
         /* TODO: Maybe implement quick interrupts at some point, but
            the 3B2 ROM and SVR3 don't appear to use them. */
         assert(0);
@@ -1363,7 +1360,7 @@ t_bool cpu_on_interrupt(uint8 ipl)
 
 t_stat sim_instr(void)
 {
-    uint8 et, isc;
+    uint8 et, isc, trap;
 
     /* Temporary register used for overflow detection */
     t_uint64 result;
@@ -1396,10 +1393,10 @@ t_stat sim_instr(void)
             return STOP_EX;
         }
 
-        if (abort_reason == ABORT_EXC) {
-            et  = R[NUM_PSW] & PSW_ET_MASK;
-            isc = (R[NUM_PSW] & PSW_ISC_MASK) >> PSW_ISC;
+        et  = R[NUM_PSW] & PSW_ET_MASK;
+        isc = (R[NUM_PSW] & PSW_ISC_MASK) >> PSW_ISC;
 
+        if (abort_reason == ABORT_EXC) {
             switch(abort_context) {
             case C_NORMAL_GATE_VECTOR:
                 cpu_on_normal_exception(N_GATE_VECTOR);
@@ -1442,13 +1439,12 @@ t_stat sim_instr(void)
                 }
                 break;
             }
-        } else {
-            /* TODO: Handle traps */
-            stop_reason = STOP_EX;
         }
+        /* Traps are handled at the end of instruction execution */
     }
 
     while (stop_reason == 0) {
+        trap = 0;
         abort_context = C_NONE;
 
         if (sim_brk_summ && sim_brk_test(R[NUM_PC], SWMASK ('E'))) {
@@ -1469,7 +1465,6 @@ t_stat sim_instr(void)
         /* Process DMA requests */
         dmac_service_drqs();
 
-
         /*
          * Post-increment IU mode pointers (if needed).
          *
@@ -1490,7 +1485,6 @@ t_stat sim_instr(void)
             cpu_on_interrupt(cpu_ipl());
             cpu_nmi = FALSE;
             cpu_in_wait = FALSE;
-            continue;
         }
 
         if (cpu_in_wait) {
@@ -1501,7 +1495,6 @@ t_stat sim_instr(void)
         }
 
         /* Reset the TM bits */
-        R[NUM_PSW] &= ~PSW_TM;
         R[NUM_PSW] |= PSW_TM_MASK;
 
         /* Record the instruction for history */
@@ -1513,8 +1506,8 @@ t_stat sim_instr(void)
         }
 
         /* Decode the instruction */
-        memset(cpu_instr, 0, sizeof(instr));
-        cpu_ilen = decode_instruction(cpu_instr);
+        clear_instruction(cpu_instr);
+        pc_incr = decode_instruction(cpu_instr);
 
         /* Make sure to update the valid bit for history keeping (if
          * enabled) */
@@ -1590,63 +1583,53 @@ t_stat sim_instr(void)
         case BEH:
         case BEH_D:
             if (cpu_z_flag() == 1) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BEB:
         case BEB_D:
             if (cpu_z_flag() == 1) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BGH:
             if ((cpu_n_flag() | cpu_z_flag()) == 0) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BGB:
             if ((cpu_n_flag() | cpu_z_flag()) == 0) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BGEH:
             if ((cpu_n_flag() == 0) | (cpu_z_flag() == 1)) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BGEB:
             if ((cpu_n_flag() == 0) | (cpu_z_flag() == 1)) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BGEUH:
             if (cpu_c_flag() == 0) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BGEUB:
             if (cpu_c_flag() == 0) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BGUH:
             if ((cpu_c_flag() | cpu_z_flag()) == 0) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BGUB:
             if ((cpu_c_flag() | cpu_z_flag()) == 0) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BITW:
@@ -1661,118 +1644,104 @@ t_stat sim_instr(void)
             break;
         case BLH:
             if ((cpu_n_flag() == 1) && (cpu_z_flag() == 0)) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BLB:
             if ((cpu_n_flag() == 1) && (cpu_z_flag() == 0)) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BLEH:
             if ((cpu_n_flag() | cpu_z_flag()) == 1) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BLEB:
             if ((cpu_n_flag() | cpu_z_flag()) == 1) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BLEUH:
             if ((cpu_c_flag() | cpu_z_flag()) == 1) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BLEUB:
             if ((cpu_c_flag() | cpu_z_flag()) == 1) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BLUH:
             if (cpu_c_flag() == 1) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BLUB:
             if (cpu_c_flag() == 1) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BNEH:
         case BNEH_D:
             if (cpu_z_flag() == 0) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BNEB:
         case BNEB_D:
             if (cpu_z_flag() == 0) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BPT:
-            /* TODO: Confirm that a breakpoint trap will increment the
-               PC. Otherwise, change 'break' to 'continue' */
-            cpu_abort(NORMAL_EXCEPTION, BREAKPOINT_TRAP);
+        case HALT:
+            trap = BREAKPOINT_TRAP;
             break;
         case BRH:
-            R[NUM_PC] += sign_extend_h(dst->embedded.h);
-            continue;
+            pc_incr = sign_extend_h(dst->embedded.h);
+            break;
         case BRB:
-            R[NUM_PC] += sign_extend_b(dst->embedded.b);
-            continue;
+            pc_incr = sign_extend_b(dst->embedded.b);
+            break;
         case BSBH:
-            cpu_push_word(R[NUM_PC] + cpu_ilen);
-            R[NUM_PC] += sign_extend_h(dst->embedded.h);
-            continue;
+            cpu_push_word(R[NUM_PC] + pc_incr);
+            pc_incr = sign_extend_h(dst->embedded.h);
+            break;
         case BSBB:
-            cpu_push_word(R[NUM_PC] + cpu_ilen);
-            R[NUM_PC] += sign_extend_b(dst->embedded.b);
-            continue;
+            cpu_push_word(R[NUM_PC] + pc_incr);
+            pc_incr = sign_extend_b(dst->embedded.b);
+            break;
         case BVCH:
             if (cpu_v_flag() == 0) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BVCB:
             if (cpu_v_flag() == 0) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case BVSH:
             if (cpu_v_flag() == 1) {
-                R[NUM_PC] += sign_extend_h(dst->embedded.h);
-                continue;
+                pc_incr = sign_extend_h(dst->embedded.h);
             }
             break;
         case BVSB:
             if (cpu_v_flag() == 1) {
-                R[NUM_PC] += sign_extend_b(dst->embedded.b);
-                continue;
+                pc_incr = sign_extend_b(dst->embedded.b);
             }
             break;
         case CALL:
             a = cpu_effective_address(src1);
             b = cpu_effective_address(dst);
             write_w(R[NUM_SP] + 4, R[NUM_AP]);
-            write_w(R[NUM_SP], R[NUM_PC] + cpu_ilen);
+            write_w(R[NUM_SP], R[NUM_PC] + pc_incr);
             R[NUM_SP] += 8;
             R[NUM_PC] = b;
             R[NUM_AP] = a;
-            continue;
+            pc_incr = 0;
+            break;
         case CFLUSH:
             break;
         case CALLPS:
@@ -1808,7 +1777,8 @@ t_stat sim_instr(void)
             abort_context = C_NONE;
 
             cpu_km = FALSE;
-            continue;
+            pc_incr = 0;
+            break;
         case CLRW:
         case CLRH:
         case CLRB:
@@ -1975,7 +1945,8 @@ t_stat sim_instr(void)
             }
             mmu_enable();
             R[NUM_PC] = R[0];
-            continue;
+            pc_incr = 0;
+            break;
         case DISVJMP:
             if (cpu_execution_level() != EX_LVL_KERN) {
                 cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
@@ -1983,7 +1954,8 @@ t_stat sim_instr(void)
             }
             mmu_disable();
             R[NUM_PC] = R[0];
-            continue;
+            pc_incr = 0;
+            break;
         case EXTFW:
         case EXTFH:
         case EXTFB:
@@ -2039,27 +2011,21 @@ t_stat sim_instr(void)
             break;
         case JMP:
             R[NUM_PC] = cpu_effective_address(dst);
-            continue;
+            pc_incr = 0;
+            break;
         case JSB:
-            cpu_push_word(R[NUM_PC] + cpu_ilen);
+            cpu_push_word(R[NUM_PC] + pc_incr);
             R[NUM_PC] = cpu_effective_address(dst);
-            continue;
+            pc_incr = 0;
+            break;
         case LLSW3:
-            result = (t_uint64)cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
-            cpu_write_op(dst, (uint32)(result & WORD_MASK));
-            cpu_set_nz_flags((uint32)(result & WORD_MASK), dst);
-            break;
         case LLSH3:
-            a = cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
-            cpu_write_op(dst, a);
-            cpu_set_nz_flags(a, dst);
-            break;
         case LLSB3:
-            a = cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
-            cpu_write_op(dst, a);
-            cpu_set_nz_flags(a, dst);
+            result = (t_uint64)cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
+            cpu_write_op(dst, result);
+            cpu_set_nz_flags(result, dst);
             cpu_set_c_flag(0);
-            cpu_set_v_flag_op(a, dst);
+            cpu_set_v_flag_op(result, dst);
             break;
         case ARSW3:
         case ARSH3:
@@ -2135,10 +2101,11 @@ t_stat sim_instr(void)
 
             /* Finish push of PC and PSW */
             R[NUM_SP] += 8;
-            continue;
+            pc_incr = 0;
+            break;
         case MCOMW:
         case MCOMH:
-        case MCOMB:
+        case MCOMB: /* One's complement */
             a = ~(cpu_read_op(src1));
             cpu_write_op(dst, a);
             cpu_set_nz_flags(a, dst);
@@ -2147,7 +2114,7 @@ t_stat sim_instr(void)
             break;
         case MNEGW:
         case MNEGH:
-        case MNEGB:
+        case MNEGB: /* Two's complement */
             a = ~cpu_read_op(src1) + 1;
             cpu_write_op(dst, a);
             cpu_set_nz_flags(a, dst);
@@ -2220,7 +2187,7 @@ t_stat sim_instr(void)
             /* However, if a move to PSW set the O bit, we have to
                generate an overflow exception trap */
             if (op_is_psw(dst) && (R[NUM_PSW] & PSW_OE_MASK)) {
-                cpu_abort(NORMAL_EXCEPTION, INTEGER_OVERFLOW);
+                trap = INTEGER_OVERFLOW;
             }
             break;
         case MODW2:
@@ -2347,10 +2314,10 @@ t_stat sim_instr(void)
         case NOP:
             break;
         case NOP2:
-            cpu_ilen += 1;
+            pc_incr += 1;
             break;
         case NOP3:
-            cpu_ilen += 2;
+            pc_incr += 2;
             break;
         case ORW2:
         case ORH2:
@@ -2399,26 +2366,26 @@ t_stat sim_instr(void)
         case RGEQ:
             if (cpu_n_flag() == 0 || cpu_z_flag() == 1) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RGEQU:
             if (cpu_c_flag() == 0) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RGTR:
             if ((cpu_n_flag() | cpu_z_flag()) == 0) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RNEQ:
         case RNEQU:
             if (cpu_z_flag() == 0) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RET:
@@ -2428,7 +2395,8 @@ t_stat sim_instr(void)
             R[NUM_AP] = b;
             R[NUM_PC] = c;
             R[NUM_SP] = a;
-            continue;
+            pc_incr = 0;
+            break;
         case RETG:
             abort_context = C_STACK_FAULT;
             a = read_w(R[NUM_SP] - 4, ACC_AF);   /* PSW */
@@ -2465,7 +2433,8 @@ t_stat sim_instr(void)
             R[NUM_PC] = b;
 
             R[NUM_SP] -= 8;
-            continue;
+            pc_incr = 0;
+            break;
         case RETPS:
             if (cpu_execution_level() != EX_LVL_KERN) {
                 cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
@@ -2512,12 +2481,21 @@ t_stat sim_instr(void)
 
             /* Un-force kernel memory access */
             cpu_km = FALSE;
-            continue;
+            pc_incr = 0;
+            break;
         case SPOP:
+        case SPOPD2:
+        case SPOPS2:
+        case SPOPT2:
         case SPOPRD:
         case SPOPRS:
+        case SPOPRT:
+        case SPOPWD:
+        case SPOPWS:
+        case SPOPWT:
             /* Memory fault is signaled when no support processor is
                active */
+            csr_data |= CSRTIMO;
             cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
             break;
         case SUBW2:
@@ -2550,36 +2528,37 @@ t_stat sim_instr(void)
         case RLEQ:
             if ((cpu_n_flag() | cpu_z_flag()) == 1) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RLEQU:
             if ((cpu_c_flag() | cpu_z_flag()) == 1) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RLSS:
             if ((cpu_n_flag() == 1) & (cpu_z_flag() == 0)) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case REQL:
             if (cpu_z_flag() == 1) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case REQLU:
             if (cpu_z_flag() == 1) {
                 R[NUM_PC] = cpu_pop_word();
-                continue;
+                pc_incr = 0;
             }
             break;
         case RSB:
             R[NUM_PC] = cpu_pop_word();
-            continue;
+            pc_incr = 0;
+            break;
         case SAVE:
             /* Save the FP register */
             write_w(R[NUM_SP], R[NUM_FP]);
@@ -2626,6 +2605,10 @@ t_stat sim_instr(void)
             cpu_set_v_flag(0);
             break;
         case WAIT:
+            if (cpu_execution_level() != EX_LVL_KERN) {
+                cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
+                break;
+            }
             cpu_in_wait = TRUE;
             break;
         case XORW2:
@@ -2652,7 +2635,21 @@ t_stat sim_instr(void)
         };
 
         /* Increment the PC appropriately */
-        R[NUM_PC] += cpu_ilen;
+        R[NUM_PC] += pc_incr;
+
+        /* If TE and TM are both set, generate a trace trap */
+        if ((R[NUM_PSW] & PSW_TE_MASK) && (R[NUM_PSW] & PSW_TM_MASK)) {
+            trap = TRACE_TRAP;
+        }
+
+        /* Handle traps */
+        if (trap) {
+            R[NUM_PSW] &= ~(PSW_ET_MASK);
+            R[NUM_PSW] &= ~(PSW_ISC_MASK);
+            R[NUM_PSW] |= NORMAL_EXCEPTION;
+            R[NUM_PSW] |= (uint32) (trap << PSW_ISC);
+            cpu_on_normal_exception(trap);
+        }
     }
 
     return stop_reason;
@@ -2661,6 +2658,9 @@ t_stat sim_instr(void)
 static SIM_INLINE void cpu_on_process_exception(uint8 isc)
 {
     /* TODO: Handle */
+    sim_debug(ERR_MSG, &cpu_dev,
+              "[%08x] CPU_ON_PROCESS_EXCEPTION not yet implemented.\n",
+              R[NUM_PC]);
     stop_reason = STOP_EX;
     return;
 }
@@ -2751,13 +2751,14 @@ static SIM_INLINE void cpu_on_normal_exception(uint8 isc)
 
     /* Set context for STACK (FAULT) */
     abort_context = C_STACK_FAULT;
+    /* Save address of next instruction to stack */
     write_w(R[NUM_SP], R[NUM_PC]);
 
     /* Write 0, 3 to TM, ET fields of PSW */
     R[NUM_PSW] &= ~(PSW_TM_MASK|PSW_ET_MASK);
     R[NUM_PSW] |= (3 << PSW_ET);
 
-    /* Save address of next instruction and PSW to stack */
+    /* Save PSW to stack */
     write_w(R[NUM_SP] + 4, R[NUM_PSW]);
 
     /* Set context for RESET (GATE VECTOR) */
@@ -2865,7 +2866,7 @@ static uint32 cpu_effective_address(operand *op)
         return read_w(R[op->reg] + sign_extend_b(op->embedded.b), ACC_AF);
     }
 
-    assert(0);
+    stop_reason = STOP_OPCODE;
 
     return 0;
 }
@@ -3405,11 +3406,13 @@ void cpu_abort(uint8 et, uint8 isc)
 {
     /* We don't trap Integer Overflow if the OE bit is not set */
     if ((R[NUM_PSW] & PSW_OE_MASK) || isc != INTEGER_OVERFLOW) {
-        R[NUM_PSW] &= ~(PSW_ISC_MASK); /* Clear ISC */
         R[NUM_PSW] &= ~(PSW_ET_MASK);  /* Clear ET  */
-        R[NUM_PSW] |= et;              /* Set ET    */
+        R[NUM_PSW] &= ~(PSW_ISC_MASK); /* Clear ISC */
+        R[NUM_PSW] |= et;                         /* Set ET    */
         R[NUM_PSW] |= (uint32) (isc << PSW_ISC);  /* Set ISC   */
 
+        /* TODO: We no longer use ABORT_TRAP or ABORT_EXC, so
+         * it would be nice to clean this up. */
         if (et == 3 && (isc == BREAKPOINT_TRAP ||
                         isc == INTEGER_OVERFLOW ||
                         isc == TRACE_TRAP)) {
diff --git a/3B2/3b2_cpu.h b/3B2/3b2_cpu.h
index e2a382c0..2640a1f5 100644
--- a/3B2/3b2_cpu.h
+++ b/3B2/3b2_cpu.h
@@ -85,6 +85,7 @@
  * Opcodes
  */
 typedef enum {
+    HALT    = 0x00, /* Undocumented instruction */
     SPOPRD  = 0x02,
     SPOPD2  = 0x03,
     MOVAW   = 0x04,
diff --git a/3B2/3b2_defs.h b/3B2/3b2_defs.h
index c9b55acd..cfa235c6 100644
--- a/3B2/3b2_defs.h
+++ b/3B2/3b2_defs.h
@@ -124,14 +124,15 @@ noret __libc_longjmp (jmp_buf buf, int val);
 #define C_STACK_FAULT        9
 
 /* Debug flags */
-#define READ_MSG     0x01
-#define WRITE_MSG    0x02
-#define DECODE_MSG   0x04
-#define EXECUTE_MSG  0x08
-#define INIT_MSG     0x10
-#define IRQ_MSG      0x20
-#define IO_D_MSG     0x40
-#define TRACE_MSG    0x80
+#define READ_MSG     0x001
+#define WRITE_MSG    0x002
+#define DECODE_MSG   0x004
+#define EXECUTE_MSG  0x008
+#define INIT_MSG     0x010
+#define IRQ_MSG      0x020
+#define IO_D_MSG     0x040
+#define TRACE_MSG    0x080
+#define ERR_MSG      0x100
 
 /* Data types operated on by instructions. NB: These integer values
    have meaning when decoding instructions, so this is not just an
diff --git a/3B2/3b2_iu.c b/3B2/3b2_iu.c
index 357ad4d0..51737b77 100644
--- a/3B2/3b2_iu.c
+++ b/3B2/3b2_iu.c
@@ -302,7 +302,7 @@ t_stat contty_reset(DEVICE *dtpr)
 
     memset(&iu_state, 0, sizeof(IU_STATE));
     memset(&iu_contty, 0, sizeof(IU_PORT));
-    tmxr_set_config_line(&contty_ldsc[0], "115200-8N1");
+    tmxr_set_config_line(&contty_ldsc[0], "9600-8N1");
 
     /* Start the CONTTY polling loop */
     if (!sim_is_active(contty_rcv_unit)) {