/* sel32_cpu.c: Sel 32 CPU simulator

   Copyright (c) 2018-2023, James C. Bevier
   Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers

   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
   JAMES C. BEVIER 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.

*/

#include "sel32_defs.h"

#ifndef CPUONLY
#ifndef USE_IPU_THREAD
/* running IPU FORK on CPU, n/u in IPU thread */
int             MyIndex;
int             PeerIndex;
extern  int     fork();
extern  int     getpid();
uint32          *M = 0;                     /* Memory when we have IPU fork */
struct  ipcom   *IPC = 0;
#else /* USE_IPU_THREAD */
/* running IPU thread on CPU, n/u in IPU fork */
/* this is different than IPU defines */
extern  void   *ipu_sim_instr(void *value);
int             MyIndex;
int             PeerIndex;
pthread_t       ipuThread;                  /* thread structure */
uint32          M[MAXMEMSIZE] = { 0 };      /* Memory */
struct  ipcom   myipc = {0};
struct  ipcom   *IPC = 0;
uint32          cpustop = 0;                /* to stop reason for IPU */
uint32          got_ipu = 0;                /* set non zero when IPU thread created */
#endif
#else /* CPUONLY */
uint32          M[MAXMEMSIZE] = { 0 };      /* Memory */
#endif

LOCAL   DEVICE* my_dev = &cpu_dev;          /* current DEV pointer CPU or IPU */

LOCAL   uint32  OIR=0;                      /* Original Instruction register */
LOCAL   uint32  OPSD1=0;                    /* Original PSD1 */
LOCAL   uint32  OPSD2=0;                    /* Original PSD2 */

/* CPU registers, map cache, spad, and other variables */
LOCAL   uint32  PSD[2];                     /* the PC for the instruction */
#define PSD1 PSD[0]                         /* word 1 of PSD */
#define PSD2 PSD[1]                         /* word 2 of PSD */
LOCAL   uint32  GPR[8];                     /* General Purpose Registers */
LOCAL   uint32  BR[8];                      /* Base registers */
LOCAL   uint32  BOOTR[8] = {0};             /* Boot registers settings */
LOCAL   uint32  SPAD[256];                  /* Scratch pad memory */
/* IPU mapping cache entries */
/* 32/55 has none */
/* 32/7x has 32 8KW maps per task */
/* Concept 32/27 has 256 2KW maps per task */
/* Concept 32/X7 has 2048 2KW maps per task */
LOCAL   uint32  MAPC[1024];                 /* maps are 16bit entries on word bountries */
LOCAL   uint32  TLB[2048];                  /* Translated addresses for each map entry */
LOCAL   uint32  PC;                         /* Program counter */
LOCAL   uint32  IR;                         /* Last Instruction */
LOCAL   uint32  HIWM=0;                     /* max maps loaded so far */
LOCAL   uint32  BPIX=0;                     /* # pages loaded for O/S */
LOCAL   uint32  CPIXPL=0;                   /* highest page loaded for User */
LOCAL   uint32  CPIX=0;                     /* CPIX user MPL offset */
LOCAL   uint32  CPUSTATUS;                  /* cpu status word */
LOCAL   uint32  TRAPSTATUS;                 /* trap status word */
LOCAL   uint32  CC;                         /* Condition codes, bits 1-4 of PSD1 */
LOCAL   uint32  MODES=0;                    /* Operating modes, bits 0, 5, 6, 7 of PSD1 */
LOCAL   uint16  OPR;                        /* Top half of Instruction register */
LOCAL   uint16  OP;                         /* Six bit instruction opcode */
LOCAL   uint32  INTS[128];                  /* Interrupt status flags */
LOCAL   uint32  CMCR;                       /* Cache Memory Control Register */
LOCAL   uint32  SMCR;                       /* Shared Memory Control Register */
LOCAL   uint32  CMSMC;                      /* V9 Cache/Shadow Memory Configuration */
LOCAL   uint32  CSMCW;                      /* CPU Shadow Memory Configuration Word */
LOCAL   uint32  ISMCW;                      /* IPU Shadow Memory Configuration Word */
LOCAL   uint32  CCW = 0;                    /* Computer Configuration Word */
LOCAL   uint32  CSW = 0;                    /* Console switches going to 0x780 */
/* end of CPU simh registers */

#ifndef CPUONLY
#ifndef USE_IPU_THREAD
LOCAL   int     pid;                        /* our PID */
#endif
#endif
LOCAL   uint32  pfault;                     /* page # of fault from read/write */

/* bits 0-4 are bits 0-4 from map entry */
/* bit 0 valid */
/* bit 1 p1 write access if set */
/* bit 2 p2 write access if set */
/* bit 3 p3 write access if set MM - memory modify */
/* bit 4 p4 write access if set MA - memory accessed */
/* bit 5 hit bit means entry is setup, even if not valid map */
/* if hit bit is set and entry not valid, we will do a page fault */
/* bit 6 dirty bit, set when written to, page update required */
/* bits 8-18 has map reg contents for this page (Map << 13) */
/* bit 19-31 is zero for page offset of zero */

LOCAL   uint8           wait4int = 0;       /* waiting for interrupt if set */
#ifndef CPUONLY
LOCAL   uint8           wait4sipu = 0;      /* waiting for sipu in IPU if set */
#endif

/* define traps */
LOCAL   uint32          TRAPME = 0;         /* trap to be executed */
LOCAL   uint32          attention_trap = 0; /* set when trap is requested */

/* forward definitions */
void* create_shared_memory(size_t size) ;
t_stat cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw);
t_stat cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw);
t_stat cpu_reset(DEVICE * dptr);
t_stat cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
#ifdef DEFINE_IPU_MODELS
t_stat cpu_set_ipu(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_clr_ipu(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_ipu(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
#endif
t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc);
t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev);
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *cpu_description (DEVICE *dptr);
LOCAL  t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access);
LOCAL  t_stat load_maps(uint32 thepsd[2], uint32 lmap);
LOCAL  t_stat read_instruction(uint32 thepsd[2], uint32 *instr);
LOCAL  t_stat Mem_read(uint32 addr, uint32 *data);
LOCAL  t_stat Mem_write(uint32 addr, uint32 *data);

/* external definitions */
extern t_stat checkxio(uint16 addr, uint32 *status);    /* XIO check in chan.c */
extern t_stat startxio(uint16 addr, uint32 *status);    /* XIO start in chan.c */
extern t_stat testxio(uint16 addr, uint32 *status);     /* XIO test in chan.c */
extern t_stat stopxio(uint16 addr, uint32 *status);     /* XIO stop in chan.c */
extern t_stat rschnlxio(uint16 addr, uint32 *status);   /* reset channel XIO */
extern t_stat haltxio(uint16 addr, uint32 *status);     /* halt XIO */
extern t_stat grabxio(uint16 addr, uint32 *status);     /* grab XIO n/u */
extern t_stat rsctlxio(uint16 addr, uint32 *status);    /* reset controller XIO */
extern t_stat chan_set_devs();                          /* set up the defined devices on the simulator */
extern uint32 scan_chan(uint32 *ilev);                  /* go scan for I/O int pending */
extern uint32 cont_chan(uint16 chsa);                   /* continue channel program */
extern uint16 loading;                                  /* set when doing IPL */
extern int fprint_inst(FILE *of, uint32 val, int32 sw); /* instruction print function */
LOCAL  int irq_pend = 0;                                /* go scan for pending interrupt */
extern void rtc_setup(uint32 ss, uint32 level);         /* tell rtc to start/stop */
extern void itm_setup(uint32 ss, uint32 level);         /* tell itm to start/stop */
extern int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level); /* read/write the interval timer */
extern DIB  *dib_chan[MAX_CHAN];

/* floating point subroutines definitions */
extern uint32   s_fixw(uint32 val, uint32 *cc);
extern uint32   s_fltw(uint32 val, uint32 *cc);
extern t_uint64 s_fixd(t_uint64 val, uint32 *cc);
extern t_uint64 s_fltd(t_uint64 val, uint32 *cc);
extern uint32   s_nor(uint32 reg, uint32 *exp);
extern t_uint64 s_nord(t_uint64 reg, uint32 *exp);
extern uint32   s_adfw(uint32 reg, uint32 mem, uint32 *cc);
extern uint32   s_sufw(uint32 reg, uint32 mem, uint32 *cc);
extern t_uint64 s_adfd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern t_uint64 s_sufd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern uint32   s_mpfw(uint32 reg, uint32 mem, uint32 *cc);
extern uint32   s_dvfw(uint32 reg, uint32 mem, uint32 *cc);
extern t_uint64 s_mpfd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern t_uint64 s_dvfd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern uint32   s_normfw(uint32 mem, uint32 *cc);
extern t_uint64 s_normfd(t_uint64 mem, uint32 *cc);

/* History information */
LOCAL   int32   hst_p = 0;                  /* History pointer */
LOCAL   int32   hst_lnt = 0;                /* History length */
LOCAL   struct  InstHistory *hst = NULL;    /* History stack */

/* CPU data structures

   cpu_dev      CPU device descriptor
   cpu_unit     CPU unit descriptor
   cpu_reg      CPU register list
   cpu_mod      CPU modifiers list
*/

UNIT  cpu_unit =
    /* Unit data layout for CPU */
/*  { UDATA(rtc_srv, UNIT_BINK | MODEL(MODEL_27) | MEMAMOUNT(0),
 *  MAXMEMSIZE ), 120 }; */
    {
    NULL,       /* UNIT *next */             /* next active */
    NULL,       /* t_stat (*action) */       /* action routine */
    NULL,       /* char *filename */         /* open file name */
    NULL,       /* FILE *fileref */          /* file reference */
    NULL,       /* void *filebuf */          /* memory buffer */
    0,          /* uint32 hwmark */          /* high water mark */
    0,          /* int32 time */             /* time out */
    UNIT_IDLE|UNIT_FIX|UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(4), /* flags */
    0,          /* uint32 dynflags */        /* dynamic flags */
    0x800000,   /* t_addr capac */           /* capacity */
    0,          /* t_addr pos */             /* file position */
    0,          /* void (*io_flush) */       /* io flush routine */
    0,          /* uint32 iostarttime */     /* I/O start time */
    0,          /* int32 buf */              /* buffer */
    80,         /* int32 wait */             /* wait */
};

REG cpu_reg[] = {
    {BRDATAD(PSD, PSD, 16, 32, 2, "Program Status Doubleword"), REG_FIT},
    {BRDATAD(GPR, GPR, 16, 32, 8, "Index registers"), REG_FIT},
    {BRDATAD(BR, BR, 16, 32, 8, "Base registers"), REG_FIT},
    {BRDATAD(BOOTR, BOOTR, 16, 32, 8, "Boot registers"), REG_FIT},
    {BRDATAD(SPAD, SPAD, 16, 32, 256, "CPU Scratchpad memory"), REG_FIT},
    {BRDATAD(MAPC, MAPC, 16, 32, 1024, "CPU map cache"), REG_FIT},
    {BRDATAD(TLB, TLB, 16, 32, 2048, "CPU Translation Lookaside Buffer"), REG_FIT},
    {HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT},
    {HRDATAD(TRAPME, TRAPME, 32, "Trap Error Number"), REG_FIT},
    {HRDATAD(IR, IR, 32, "Last Instruction Loaded"), REG_FIT},
    {HRDATAD(HIWM, HIWM, 32, "Max Maps Loaded"), REG_FIT},
    {HRDATAD(BPIX, BPIX, 32, "# Maps Loaded for O/S"), REG_FIT},
    {HRDATAD(CPIXPL, CPIXPL, 32, "Maximum Map # Loaded for User"), REG_FIT},
    {HRDATAD(CPIX, CPIX, 32, "Current CPIX user MPL offset"), REG_FIT},
    {HRDATAD(CPUSTATUS, CPUSTATUS, 32, "CPU Status Word"), REG_FIT},
    {HRDATAD(TRAPSTATUS, TRAPSTATUS, 32, "TRAP Status Word"), REG_FIT},
    {HRDATAD(CC, CC, 32, "Condition Codes"), REG_FIT},
    {HRDATAD(MODES, MODES, 32, "Mode bits"), REG_FIT},
    {HRDATAD(OPR, OPR, 16, "Top half of Instruction Register"), REG_FIT},
    {HRDATAD(OP, OP, 16, "Six bit Instruction Opcode"), REG_FIT},
    {BRDATAD(INTS, INTS, 16, 32, 128, "Interrupt Status"), REG_FIT},
    {HRDATAD(CMCR, CMCR, 32, "Cache Memory Control Register"), REG_FIT},
    {HRDATAD(SMCR, SMCR, 32, "Shared Memory Control Register"), REG_FIT},
    {HRDATAD(CMSMC, CMSMC, 32, "V9 Cache/Shadow Memory Configuration Word"), REG_FIT},
    {HRDATAD(CSMCW, CSMCW, 32, "V9 CPU Shadow Memory Configuration Word"), REG_FIT},
    {HRDATAD(ISMCW, ISMCW, 32, "V9 IPU Shadow Memory Configuration Word"), REG_FIT},
    {HRDATAD(CCW, CCW, 32, "Computer Configuration Word"), REG_FIT},
    {HRDATAD(CSW, CSW, 32, "Console Switches"), REG_FIT},
#ifdef NOT_USED
    {BRDATAD(RDYQ, RDYQ, 16, 32, 128, "Channel Program Completon Status"), REG_FIT},
    {HRDATAD(RDYQIN, RDYQIN, 32, "RDYQ input index"), REG_FIT},
    {HRDATAD(RDYQOUT, RDYQOUT, 32, "RDYQ output index"), REG_FIT},
#endif
    {NULL}
};

/* Modifier table layout (MTAB) - only extended entries have disp, reg, or flags */
MTAB cpu_mod[] = {
    {
    /* MTAB table layout for cpu type */
    /* {UNIT_MODEL, MODEL(MODEL_55), "32/55", "32/55", NULL, NULL, NULL, "Concept 32/55"}, */
    UNIT_MODEL,          /* uint32 mask */          /* mask */
    MODEL(MODEL_55),     /* uint32 match */         /* match */
    "32/55",             /* cchar  *pstring */      /* print string */
    "32/55",             /* cchar  *mstring */      /* match string */
    NULL,                /* t_stat (*valid) */      /* validation routine */
    NULL,                /* t_stat (*disp)  */      /* display routine */
    NULL,                /* void *desc      */      /* value desc, REG* if MTAB_VAL, int* if not */
    "Concept 32/55",     /* cchar *help     */      /* help string */
    },
    {UNIT_MODEL, MODEL(MODEL_75), "32/75", "32/75", NULL, NULL, NULL, "Concept 32/75"},
    {UNIT_MODEL, MODEL(MODEL_27), "32/27", "32/27", NULL, NULL, NULL, "Concept 32/27"},
    {UNIT_MODEL, MODEL(MODEL_67), "32/67", "32/67", NULL, NULL, NULL, "Concept 32/67"},
    {UNIT_MODEL, MODEL(MODEL_87), "32/87", "32/87", NULL, NULL, NULL, "Concept 32/87"},
    {UNIT_MODEL, MODEL(MODEL_97), "32/97", "32/97", NULL, NULL, NULL, "Concept 32/97"},
    {UNIT_MODEL, MODEL(MODEL_V6), "V6", "V6", NULL, NULL, NULL, "Concept V6"},
    {UNIT_MODEL, MODEL(MODEL_V9), "V9", "V9", NULL, NULL, NULL, "Concept V9"},
#ifdef DEFINE_IPU_MODELS
    {UNIT_MODEL, MODEL(MODEL_6780), "32/6780", "32/6780", NULL, NULL, NULL, "Concept 32/6780"},
    {UNIT_MODEL, MODEL(MODEL_7780), "32/7780", "32/7780", NULL, NULL, NULL, "Concept 32/7780"},
    {UNIT_MODEL, MODEL(MODEL_8780), "32/8780", "32/8780", NULL, NULL, NULL, "Concept 32/8780"},
    {UNIT_MODEL, MODEL(MODEL_9780), "32/9780", "32/9780", NULL, NULL, NULL, "Concept 32/9780"},
    {UNIT_MODEL, MODEL(MODEL_V6IPU), "V6/IPU", "V6/IPU", NULL, NULL, NULL, "Concept V6 w/IPU"},
    {UNIT_MODEL, MODEL(MODEL_V9IPU), "V9/IPU", "V9/IPU", NULL, NULL, NULL, "Concept V9 w/IPU"},
#endif
    {
    /* MTAB table layout for cpu memory size */
    /* {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &cpu_set_size}, */
    UNIT_MSIZE,          /* uint32 mask */          /* mask */
    MEMAMOUNT(0),        /* uint32 match */         /* match */
    NULL,                /* cchar  *pstring */      /* print string */
    "128K",              /* cchar  *mstring */      /* match string */
    &cpu_set_size,       /* t_stat (*valid) */      /* validation routine */
    NULL,                /* t_stat (*disp)  */      /* display routine */
    NULL,                /* void *desc      */      /* value desc, REG* if MTAB_VAL, int* if not */
    NULL,                /* cchar *help     */      /* help string */
    },
    {UNIT_MSIZE, MEMAMOUNT(1),   NULL, "256K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(2),   NULL, "512K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(3),   NULL,   "1M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(4),   NULL,   "2M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(5),   NULL,   "3M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(6),   NULL,   "4M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(7),   NULL,   "6M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(8),   NULL,   "8M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(9),   NULL,  "12M", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(10),  NULL,  "16M", &cpu_set_size},
    {MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle},
    {MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL},
    {MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY",
        &cpu_set_hist, &cpu_show_hist},
#ifdef DEFINE_IPU_MODELS
    {MTAB_XTD|MTAB_VDV, 0, "IPU", "USEIPU", &cpu_set_ipu, &cpu_show_ipu},
    {MTAB_XTD|MTAB_VDV, 0, "NULL", "NOIPU", &cpu_clr_ipu, NULL},
#endif
    {0}
};

/* CPU device descriptor */
DEVICE cpu_dev = {
    /* "CPU", &cpu_unit, cpu_reg, cpu_mod,
    1, 8, 24, 1, 8, 32,
    &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
    NULL, DEV_DEBUG, 0, dev_debug,
    NULL, NULL, &cpu_help, NULL, NULL, &cpu_description */
    "CPU",               /* cchar *name */          /* device name */
    &cpu_unit,           /* UNIT *units */          /* unit array */
    cpu_reg,             /* REG *registers */       /* register array */
    cpu_mod,             /* MTAB *modifiers */      /* modifier array */
    1,                   /* uint32 numunits */      /* number of units */
    16,                  /* uint32 aradix */        /* address radix */
    32,                  /* uint32 awidth */        /* address width */
    1,                   /* uint32 aincr */         /* address increment */
    16,                  /* uint32 dradix */        /* data radix */
    8,                   /* uint32 dwidth */        /* data width */
    &cpu_ex,             /* t_stat (*examine) */    /* examine routine */
    &cpu_dep,            /* t_stat (*deposit) */    /* deposit routine */
    &cpu_reset,          /* t_stat (*reset) */      /* reset routine */
    NULL,                /* t_stat (*boot) */       /* boot routine */
    NULL,                /* t_stat (*attach) */     /* attach routine */
    NULL,                /* t_stat (*detach) */     /* detach routine */
    NULL,                /* void *ctxt */           /* (context) device information block pointer */
    DEV_DEBUG,           /* uint32 flags */         /* device flags */
    0,                   /* uint32 dctrl */         /* debug control flags */
    dev_debug,           /* DEBTAB *debflags */     /* debug flag name array */
    NULL,                /* t_stat (*msize) */      /* memory size change routine */
    NULL,                /* char *lname */          /* logical device name */
    &cpu_help,           /* t_stat (*help) */       /* help function */
    NULL,                /* t_stat (*attach_help) *//* attach help function */
    NULL,                /* void *help_ctx */       /* Context available to help routines */
    &cpu_description,    /* cchar *(*description) *//* Device description */
    NULL,                /* BRKTYPTB *brk_types */  /* Breakpoint types */
};

/* CPU Instruction decode flags */
#define INV     0x0000      /* Instruction is invalid */
#define HLF     0x0001      /* Half word instruction */
#define ADR     0x0002      /* Normal addressing mode */
#define IMM     0x0004      /* Immediate mode */
#define WRD     0x0008      /* Word addressing, no index */
#define SCC     0x0010      /* Sets CC */
#define RR      0x0020      /* Read source register */
#define R1      0x0040      /* Read destination register */
#define RB      0x0080      /* Read base register into dest */
#define SD      0x0100      /* Stores into destination register */
#define RNX     0x0200      /* Reads memory without sign extend */
#define RM      0x0400      /* Reads memory */
#define SM      0x0800      /* Stores memory */
#define DBL     0x1000      /* Double word operation */
#define SB      0x2000      /* Store Base register */
#define BT      0x4000      /* Branch taken, no PC incr */
#define SF      0x8000      /* Special flag */

LOCAL int nobase_mode[] = {
   /*    00            04             08             0C  */
   /*    00            ANR,           ORR,           EOR */ 
         HLF,        SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, 

   /*    10            14             18             1C */
   /*    CAR,          CMR,           SBR            ZBR */
         HLF,          HLF,           HLF,           HLF,

   /*    20            24             28             2C  */
   /*    ABR           TBR            REG            TRR  */
         HLF,          HLF,           HLF,           HLF, 

   /*    30            34             38             3C */
   /*    CALM          LA             ADR            SUR */
       HLF,            SD|ADR,        HLF,           HLF,

   /*    40            44             48             4C  */ 
   /*    MPR           DVR                             */
      SCC|SD|HLF,      HLF,           HLF|INV,       HLF|INV, 

   /*    50            54             58             5C */
   /*                                                 */
        HLF|INV,       HLF|INV,       HLF|INV,       HLF|INV,

   /*    60            64             68             6C   */
   /*    NOR           NORD           SCZ            SRA  */
         HLF,          HLF,           HLF,           HLF, 

   /*    70            74             78             7C */
   /*    SRL           SRC            SRAD           SRLD */ 
         HLF,          HLF,           HLF,           HLF,

   /*    80            84             88             8C   */
   /*    LEAR          ANM            ORM            EOM  */
       SD|ADR,  SD|RR|RNX|ADR,  SD|RR|RNX|ADR,  SD|RR|RNX|ADR,  

   /*    90            94             98             9C */
   /*    CAM           CMM            SBM            ZBM  */ 
      SCC|RR|RM|ADR,   RR|RM|ADR,     ADR,           ADR,

   /*    A0            A4             A8             AC  */
   /*    ABM           TBM            EXM            L    */
         ADR,          ADR,           ADR,        SCC|SD|RM|ADR,

   /*    B0            B4             B8             BC */
   /*    LM            LN             ADM            SUM  */ 
     SCC|SD|RM|ADR,    SCC|SD|RM|ADR,  SD|RR|RM|ADR,  SD|RR|RM|ADR,

   /*    C0            C4             C8             CC    */
   /*    MPM           DVM            IMM            LF  */
     SCC|SD|RM|ADR,    RM|ADR,        IMM,           ADR, 

   /*    D0            D4             D8             DC */
   /*    LEA           ST             STM            STF */ 
     SD|ADR,           RR|SM|ADR,     RR|SM|ADR,     ADR,  

   /*    E0            E4             E8             EC   */
   /*    ADF           MPF            ARM            BCT  */
     ADR,           ADR,      SM|RR|RNX|ADR,  ADR, 

   /*    F0            F4             F8             FC */
   /*    BCF           BI             MISC           IO */ 
        ADR,           RR|SD|WRD,     ADR,           IMM,  
};

LOCAL int base_mode[] = {
   /* 00        04            08         0C      */
   /* 00        AND,          OR,        EOR  */
     HLF,      SCC|R1|RR|SD|HLF,     SCC|R1|RR|SD|HLF,     SCC|R1|RR|SD|HLF,  

   /* 10        14           18        1C  */
   /* SACZ      CMR         xBR         SRx */
     HLF,       HLF,        HLF,        HLF,

   /* 20        24            28         2C   */
   /* SRxD      SRC          REG        TRR      */
     HLF,       HLF,         HLF,       HLF,    

   /* 30        34          38           3C */
   /*           LA          FLRop        SUR */
    INV,        INV,       HLF,      HLF,

   /* 40        44            48         4C     */
   /*                                        */
      INV,      INV,        INV,       INV, 

    /* 50       54          58            5C */
   /*  LA       BASE        BASE          CALLM */ 
    SD|ADR,     SM|ADR,     SB|ADR,    RM|ADR,

   /* 60        64            68         6C     */
   /*                                         */
      INV,      INV,         INV,      INV,   

   /* 70       74           78           7C */
   /*                                          */ 
    INV,     INV,        INV,        INV,  

   /* LEAR      ANM          ORM        EOM   */
   /* 80        84            88         8C   */
    SD|ADR,    SD|RR|RNX|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR, 

   /* CAM       CMM           SBM        ZBM  */ 
   /* 90        94            98         9C   */
    SCC|RR|RM|ADR, RR|RM|ADR,   ADR,     ADR,

   /* A0        A4            A8         AC   */
   /* ABM       TBM           EXM        L    */
      ADR,      ADR,          ADR,    SCC|SD|RM|ADR,

   /* B0        B4            B8         BC   */
   /* LM        LN            ADM        SUM  */ 
   SCC|SD|RM|ADR,   SCC|SD|RM|ADR,      SD|RR|RM|ADR,     SD|RR|RM|ADR,

   /* C0        C4            C8         CC   */
   /* MPM       DVM           IMM        LF   */
    SCC|SD|RM|ADR,  RM|ADR,       IMM,       ADR, 

   /*  D0       D4            D8         DC */
   /*  LEA      ST            STM        STFBR */ 
     INV,       RR|SM|ADR,    RR|SM|ADR,    ADR,  

   /* E0        E4            E8         EC     */
   /* ADF       MPF           ARM        BCT      */
    ADR,     ADR,     SM|RR|RNX|ADR,    ADR, 

   /* F0        F4            F8         FC */
  /*  BCF       BI            MISC       IO */ 
    ADR,        RR|SD|WRD,    ADR,       IMM,  
};

#define MAX32       32      /* 32/77 map limit */
#define MAX256      256     /* 32/27 and 32/87 map limit */
#define MAX2048     2048    /* 32/67, V6, and V9 map limit */

#ifdef DEBUG4IPU
/* Dump instruction history */
static void DumpHist()
{
    /* dump instruction history */
//  cpu_show_hist(stdout, (UNIT *)0, (int32)0, (void *)0);
//  fflush(stdout);
    cpu_show_hist(sim_deb, (UNIT *)0, (int32)0, (void *)0);
    fflush(sim_deb);
}
#endif

#ifndef CPUONLY
#ifdef USE_POSIX_SEM
LOCAL void set_simsem()
{
    if (IPC != 0) {
        if (sem_trywait((sem_t *)&(IPC->simsem)) == 0) {
            IPC->pass[MyIndex]++;
        } else {
            IPC->wait[MyIndex]++;
            sem_wait((sem_t *)&(IPC->simsem));
            IPC->pass[MyIndex]++;
        }
    }
}

LOCAL void clr_simsem()
{
    // in case simsem > 0 the peer process has broken the semaphore
    if (IPC) {
        sem_post((sem_t *)&(IPC->simsem));
    }
}
#else
/* use pthread mutexs */
LOCAL void lock_mutex()
{
    if (IPC != 0) {
        if (pthread_mutex_trylock((pthread_mutex_t *)&(IPC->mutex)) == 0) {
            IPC->pass[MyIndex]++;
        } else {
            IPC->wait[MyIndex]++;
            pthread_mutex_lock((pthread_mutex_t *)&(IPC->mutex));
            IPC->pass[MyIndex]++;
        }
    }
}

LOCAL void unlock_mutex()
{
    if (IPC) {
        pthread_mutex_unlock((pthread_mutex_t *)&(IPC->mutex));
    }
}
#endif
#endif /* CPUONLY */

#ifdef NOT_USED
/* this function is used to extract mode bits from PSD 1 & 2 */
LOCAL uint32 set_modes(uint32 psd[2])
{
    uint32 modes = 0;
    modes = psd[0] & 0x87000000;                    /* extract bits 0, 5, 6, 7 from PSD 1 */

    if (psd[1] & MAPBIT)                            /* is bit 0 of PSD2 set, we are mapped */
        modes |= MAPMODE;                           /* set mapped mode */

    if ((psd[1] & RETBBIT) == 0) {                  /* is it retain blocking state, bit 48(15) set */
        /* retain blocking state is off, use bit 49(16) to set new blocking state */
        if (psd[1] & SETBBIT) {                     /* no, is it set blocking state bit 49(16) set*/
             /* new blocking state is blocked when bits 48=0 & bit 49=1 */
             modes |= BLKMODE;                      /* set blocked mode */
        }
    } else {
        /* set retained blocking state in PSD2 */
        if (SPAD[0xf9] & BIT24) {                   /* see if old mode is blocked in CPUSTATUS */
            modes |= BLKMODE;                       /* set blocked mode */
        }
    }
    return modes;
}
#endif

/* set up the map registers for the current task in the cpu */
/* the PSD bpix and cpix are used to setup the maps */
/* return non-zero if mapping error */
/* if lmap set, always load maps on 67, 97, V6, and V7 */
/* The RMW and WMW macros are used to read/write memory words */
/* RMW(addr) or WMW(addr, data) where addr is a byte alligned word address */
/* The RMR and WMR macros are used to read/write the MAPC cache registers */
/* RMR(addr) or WMR(addr, data) where addr is a half word alligned address */
/* We will only get here if the retain maps bit is not set in PSD word 2 */
LOCAL t_stat load_maps(uint32 thepsd[2], uint32 lmap)
{
    uint32 num, sdc, spc, onlyos=0;
    uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl;
    uint32 cpix, bpix, i, j, map, osmsdl, osmidl;
    uint32 MAXMAP = MAX2048;                        /* default to 2048 maps */

    sim_debug(DEBUG_CMD, my_dev,
        "Load Maps Entry PSD %08x %08x STATUS %08x lmap %1x CPU Mode %2x\n",
        thepsd[0], thepsd[1], CPUSTATUS, lmap, CPU_MODEL);

    /* process 32/7X computers */
    if (CPU_MODEL < MODEL_27) {
        MAXMAP = MAX32;                             /* 32 maps for 32/77 */
        /* 32/7x machine, 8KW maps 32 maps total */
        MODES &= ~BASEBIT;                          /* no basemode on 7x */
        if ((thepsd[1] & 0xc0000000) == 0)          /* mapped mode? */
            return ALLOK;                           /* no, all OK, no mapping required */

        /* we are mapped, so load the maps for this task into the cpu map cache */
        cpix = (thepsd[1]) & 0x3ff8;                /* get cpix 12 bit offset from psd wd 2 */
        bpix = (thepsd[1] >> 16) & 0x3ff8;          /* get bpix 12 bit offset from psd wd 2 */
        num = 0;                                    /* working map number */

        /* master process list is in 0x83 of spad for 7x */
        mpl = SPAD[0x83];                           /* get mpl from spad address */

        /* diags want the mpl entries checked to make sure valid dbl wowrd address */
        if (mpl & 0x7) {                            /* test for double word address */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps MPL not on double word boundry %06x\n", mpl);
            TRAPSTATUS |= BIT20;                    /* set bit 20 of trap status */
            return MAPFLT;                          /* not dbl bound, map fault error */
        }

        /* check if valid real address */
        if ((mpl == 0) || !MEM_ADDR_OK(mpl & MASK24)) {  /* see if in memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps MEM SIZE7 %06x mpl %06x invalid\n",
                MEMSIZE, mpl);
            TRAPSTATUS |= BIT18;                    /* set bit 18 of trap status */
            return MAPFLT;                          /* no, map fault error */
        }

        /* mpl is ok, get the msdl for given cpix */
        cpixmsdl = RMW(mpl+cpix);                   /* get msdl from mpl for given cpix */

        /* if bit zero of mpl entry is set, use bpix first to load maps */
        if (cpixmsdl & BIT0) {

            /* load bpix maps first */
            bpixmsdl = RMW(mpl+bpix);               /* get bpix msdl word address */

            /* check for valid bpix msdl addr */
            if (!MEM_ADDR_OK(bpixmsdl & MASK24)) {  /* see if in memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps MEM SIZE8 %06x bpix msdl %08x invalid\n",
                    MEMSIZE, bpixmsdl);
                return NPMEM;                       /* no, none present memory error */
            }

            sdc = (bpixmsdl >> 24) & 0x3f;          /* get 6 bit segment description count */
            msdl = bpixmsdl & MASK24;               /* get 24 bit real address of msdl */
            /* check for valid msdl addr */
            if (!MEM_ADDR_OK(msdl & MASK24)) {      /* see if in memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps MEM SIZE9 %06x msdl %08x invalid\n", MEMSIZE, msdl);
                return NPMEM;                       /* no, none present memory error */
            }

            /* process all of the msdl's */
            for (i = 0; i < sdc; i++) {             /* loop through the msd's */
                spc = (RMW(msdl+i) >> 24) & 0xff;   /* get segment page count from msdl */
                midl = RMW(msdl+i) & MASK24;        /* get 24 bit real word address of midl */

                /* check for valid midl addr */
                if (!MEM_ADDR_OK(midl & MASK24)) {  /* see if in memory */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "load_maps MEM SIZEa %06x midl %08x invalid\n", MEMSIZE, midl);
                    return NPMEM;                   /* no, none present memory error */
                }

                for (j = 0; j < spc; j++, num++) {  /* loop throught the midl's */
                    uint32 pad = RMW(midl+(j<<1));  /* get page descriptor address */
                    if (num >= MAXMAP) {
                        TRAPSTATUS |= BIT5;         /* set bit 5 of trap status */
                        return MAPFLT;              /* map loading overflow, map fault error */
                    }
                    /* load 16 bit map descriptors */
                    map = RMH(pad);                 /* get 16 bit map entries */
                    WMR((num<<1), map);             /* store the map reg contents into cache */
                }
            }
        }

        /* now load cpix maps */
        /* check for valid cpix msdl addr */
        if (MEM_ADDR_OK(cpixmsdl & MASK24)) {       /* see if in memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps MEM SIZEb %06x cpix msdl %08x invalid\n", MEMSIZE, cpixmsdl);
            return NPMEM;                           /* no, none present memory error */
        }

        sdc = (cpixmsdl >> 24) & 0x3f;              /* get 6 bit segment description count */
        msdl = cpixmsdl & 0xffffff;                 /* get 24 bit real address of msdl */
        /* check for valid msdl addr */
        if (!MEM_ADDR_OK(msdl & MASK24)) {          /* see if in memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps MEM SIZEc %06x msdl %08x invalid\n", MEMSIZE, msdl);
            return NPMEM;                           /* no, none present memory error */
        }

        /* process all of the msdl's */
        for (i = 0; i < sdc; i++) {
            spc = (RMW(msdl+i) >> 24) & 0xff;       /* get segment page count from msdl */
            midl = RMW(msdl+i) & MASK24;            /* get 24 bit real word address of midl */

            /* check for valid midl addr */
            if (!MEM_ADDR_OK(midl & MASK24)) {      /* see if in memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps MEM SIZEd %06x midl %08x invalid\n", MEMSIZE, midl);
                return NPMEM;                       /* no, none present memory error */
            }

            for (j = 0; j < spc; j++, num++) {      /* loop through the midl's */
                uint32 pad = RMW(midl+(j<<1));      /* get page descriptor address */
                if (num >= MAXMAP) {
                    TRAPSTATUS |= (BIT16|BIT9);     /* set bit 5 of trap status */
                    return MAPFLT;                  /* map loading overflow, map fault error */
                }
                /* load 16 bit map descriptors */
                map = RMH(pad);                     /* get 16 bit map entries */
                WMR((num<<1), map);                 /* store the map reg unmodified into cache */
            }
        }
        /* if none loaded, map fault */
        if (num == 0) {
            TRAPSTATUS |= (BIT16|BIT9);             /* set bit 5 of trap status */
            return MAPFLT;                          /* attempt to load 0 maps, map fault error */
        }
        /* clear the rest of the previously used maps */
        for (i = num; i < HIWM; i++)                /* zero any remaining entries */
            WMR((i<<1), 0);                         /* clear the map entry to make not valid */
        HIWM = num;                                 /* set new high water mark */
        return ALLOK;                               /* all cache is loaded, return OK */
    }
    /****************** END-OF-32/7X-MAPPING ********************/

    /* process a 32/27, 32/67, 32/87, 32/97, V6, or V9 here with 2KW (8kb) maps */
    /* 32/27 & 32/87 have 256 maps. Others have 2048 maps */
    /* 32/27 & 32/87 must have all maps preallocated and loaded */ 
    /* 32/67 & 32/97 must load O/S maps and have user preallocated maps loaded on access */
    /* V6 and V9 must load O/S maps and have user maps allocated and loaded on access */

    /* See if any mapping to take place */
    if ((MODES & MAPMODE) == 0)                     /* mapped mode? */
        return ALLOK;                               /* no, all OK, no mapping required */

    /* set maximum maps for 32/27 and 32/87 processors */
    if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87))
        MAXMAP = MAX256;                            /* only 256 2KW (8kb) maps */

    /* we are mapped, so load the map definitions */
    cpix = thepsd[1] & 0x3ff8;                      /* get cpix 11 bit offset from psd wd 2 */
    num = 0;                                        /* no maps loaded yet */

    /* master process list is in 0xf3 of spad for concept machines */
    mpl = SPAD[0xf3];                               /* get mpl from spad address */

    /* diags want the mpl entries checked to make sure valid dbl word address */
    if (mpl & 0x7) {                                /* test for double word address */
        sim_debug(DEBUG_TRAP, my_dev,
            "load_maps MPL not on double word boundry %06x\n", mpl);
        if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
            TRAPSTATUS |= BIT6;                     /* set bit 6 of trap status */
        else
            TRAPSTATUS |= BIT20;                    /* set bit 20 of trap status */
        return MAPFLT;                              /* no, map fault error */
    }

    /* check if valid real address */
    mpl &= MASK24;                                  /* clean mpl address */
    if (!MEM_ADDR_OK(mpl)) {                        /* see if in our real memory */
        sim_debug(DEBUG_TRAP, my_dev,
            "load_maps MEM SIZE1 %06x mpl %06x invalid\n", MEMSIZE, mpl);
npmem:
        BPIX = 0;                                   /* no os maps loaded */
        CPIXPL = 0;                                 /* no user pages */
        CPIX = cpix;                                /* save user CPIX */
        if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
            TRAPSTATUS |= BIT1;                     /* set bit 1 of trap status */
        } else
            TRAPSTATUS |= BIT10;                    /* set bit 8 of trap status */
        return NPMEM;                               /* non present memory error */
    }

    /* output O/S and User MPL entries */
    sim_debug(DEBUG_DETAIL, my_dev,
        "#MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n",
        MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix,
        RMW(cpix+mpl), RMW(cpix+mpl+4));
    sim_debug(DEBUG_DETAIL, my_dev,
        "MEMORY2 %06x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n",
        MEMSIZE, BPIX, cpix, CPIX, CPIXPL, HIWM);

    /* load the users regs first or the O/S.  Verify the User MPL entry too. */
    /* If bit zero of cpix mpl entry is set, use msd entry 0 first to load maps */
    /* Then load the user maps after the O/S */
    /* If the cpix is zero, then only load the O/S. */
    /* This test must be made to allow sysgen to run with a zero cpix */
    /* If bit 0 of MPL[0] is 0, load the O/S maps. */
    /* Do not load O/S if bit 0 of O/S MPL[0] is set.  It is set by the */
    /* swapper on MPX startup */

    /* mpl is valid, get msdls for O/S and User */
    osmidl = RMW(mpl);                              /* get O/S map count & retain flag from MPL[0] */
    osmsdl = RMW(mpl+4);                            /* get msdl pointer for OS from MPL[1] */
    midl = RMW(mpl+cpix);                           /* get midl entry for given user cpix */
    msdl = RMW(mpl+cpix+4);                         /* get mpl entry wd 1 for given cpix */
    spc = osmidl & MASK16;                          /* get 16 bit O/S segment description count */

    /* see if we are to only load the O/S */
    if (cpix == 0) { 
        CPIX = cpix;                                /* save CPIX */
        onlyos = 1;                                 /* flag to only load O/S, nothing else */
        if (osmidl & BIT0) {                        /* see if the O/S retain bit 0 is on */
            return ALLOK;                           /* O/S retain bit is set, no mapping required */
        }

loados: /* merge point for loading O/S first */
        /* to be followed by user maps */
        /* the retain bit is not set so load the O/S */
        if ((osmidl == 0) || (spc > MAXMAP)) {
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps bad O/S map count %04x, map fault\n", spc);
nomaps:
            /* Bad map load count specified. */
            BPIX = 0;                               /* no os maps loaded */
            CPIXPL = 0;                             /* no user pages */
            CPIX = cpix;                            /* save CPIX */
            HIWM = 0;                               /* reset high water mark */
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                TRAPSTATUS |= (BIT5|BIT9);          /* set bit 5/9 of trap status */
            else
                TRAPSTATUS |= BIT16;                /* set bit 16 of trap status */
            return MAPFLT;                          /* map loading overflow, map fault error */
        }

        /* we have a valid count, load the O/S map list address */
        osmsdl &= MASK24;                           /* get 24 bit real address from mpl 0 wd2 */
        if (!MEM_ADDR_OK(osmsdl)) {                 /* see if address is within our memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps MEM SIZE2 %06x os page list address %06x invalid\n",
                MEMSIZE, osmsdl);
            goto npmem;                             /* non present memory trap */
        }

        /* load the O/S maps */
        for (j = 0; j < spc; j++, num++) {          /* copy maps from msdl to map cache */
            uint32 pad = osmsdl+(j<<1);             /* get page descriptor address */

            /* see if map overflow */
            if (num >= MAXMAP) {
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps O/S page count overflow %04x, map fault\n", num);
                goto nomaps;                        /* map overflow, map fault trap */
            }
            if (!MEM_ADDR_OK(pad)) {                /* see if address is within our memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps MEM SIZE3 %06x os page address %06x invalid\n",
                    MEMSIZE, pad);
                goto npmem;                         /* non present memeory trap */
            }
            /* load 16 bit map descriptors */
            map = RMH(pad);                         /* get page descriptor from memory */

            /* for valid maps translate the map number to a real address */
            /* put this address in the TLB for later translation */
            /* copy the map status bits too and set hit bit in the TLB */
            if (map & 0x8000) {                     /* see if map is valid */
                TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000));
                TLB[num] |= 0x04000000;             /* set HIT bit for non lmap */
                WMR((num<<1), map);                 /* store the map unmodified into cache */
            } else {
                TLB[num] = 0;                       /* clear the TLB for non valid maps */
            }
        }
        BPIX = num;                                 /* save the # maps loaded in O/S */
        CPIXPL = 0;                                 /* no user pages */

        if (!onlyos)                                /* see if only O/S to be loaded */
            goto loaduser;                          /* no, go load the user maps */

        for (i = BPIX; i < MAXMAP; i++)             /* zero any remaining entries */
            TLB[i] = 0;                             /* clear look aside buffer */

        /* Only the O/S is to be loaded, finish up & return */
        HIWM = num;                                 /* set new high water mark */
        return ALLOK;                               /* all cache is loaded, return OK */
    }

    /* The csect is not zero here, so see what we have to do */
    /* See if O/S is to be loaded first because user MPL entry has BIT 0 set */
    if (midl & BIT0) {
        /* the user wants the O/S to load first, if the O/S retain bit set? */
        if (osmidl & BIT0) {                        /* see if the O/S retain bit 0 is on */
            num = spc;                              /* yes, set the number of O/S maps loaded */
            BPIX = spc;                             /* save the # maps in O/S */
            goto loaduser;                          /* load user map only or after O/S */
        }

        /* no retain bit, load user maps only, or after O/S */
        /* validate O/S map count */
        if (spc > MAXMAP) {
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps bad O/S page count %04x, map fault\n", spc);
            goto nomaps;                            /* we have error, make way out */
        }

        /* see if any O/S maps to load */ 
        if (spc == 0) {
            BPIX = 0;                               /* no os maps loaded */
            /* O/S page count is zero, so just load the user */
            goto loaduser;                          /* load user map only or after O/S */
        }
        /* user wants to have O/S loaded first */
        onlyos = 0;                                 /* return to loaduser after loading O/S */
        goto loados;                                /* go load the O/S */
    }

    /* the user wants to only load the user maps, no O/S maps are to be retained */
    BPIX = 0;                                       /* clear O/S loaded page count */
    num = 0;                                        /* nothing loaded yet */
    /****************** END-OF-O/S-MAPPING ********************/

loaduser:
    spc = midl & MASK16;                            /* get 16 bit User page count */

    /* see if O/S has already loaded the MAXMAPS */
    /* if borrow bit is on and cpix count is zero, return ok */
    /* if borrow bit is on and cpix count not zero, map overflow error */
    if (BPIX == MAXMAP) {
        HIWM = num;                                 /* set new high water mark */
        CPIXPL = 0;                                 /* no user pages */
        if ((midl & BIT0) && (spc == 0)) {          /* see if the user had borrow bit on */
            sim_debug(DEBUG_CMD, my_dev,
                "load_maps @loaduser num %04x BPIX loaded %04x load done\n", num, BPIX);
            return ALLOK;                           /* all cache is loaded, return OK */
        }
        else {
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps map overflow BPIX %04x count %04x, map fault\n", BPIX, spc);
            goto nomaps;                            /* we have error, make way out */
        }
    }

    /* the O/S has been loaded if requested or retained, so now load the user */
    msdl &= MASK24;                                 /* get 24 bit real word address of msdl */

    /* This test fails cn.mmm diag at test 46, subtest 2 with unexpected error */
    /* Do this test if we are a LMAP instruction and not a 32/27 or 32/87 */
    if (lmap && !MEM_ADDR_OK(msdl)) {               /* see if address is within our memory */
        sim_debug(DEBUG_TRAP, my_dev,
            "load_maps MEM SIZE4 %06x user page list address %06x invalid\n",
            MEMSIZE, msdl);
        if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
            TRAPSTATUS |= BIT1;                     /* set bit 1 of trap status */
        } else
            TRAPSTATUS |= BIT28;                    /* set bit 28 of trap status */
        return NPMEM;                               /* non present memory error */
    }

    /* We have a valid user MPL[cpix] address, msdl */
    spc = midl & MASK16;                            /* get 16 bit User page count */

    /* it is OK here to have no O/S maps loaded, num can be 0 */
    if ((spc > MAXMAP) || ((spc+BPIX) > MAXMAP)) {
        sim_debug(DEBUG_TRAP, my_dev,
            "load_maps bad User page count %04x num %04x bpix %04x, map fault\n",
            spc, num, BPIX);
        /* Bad map load count specified. */
        BPIX = 0;                                   /* no os maps loaded */
        CPIXPL = 0;                                 /* no user pages */
        CPIX = cpix;                                /* save CPIX */
        HIWM = 0;                                   /* reset high water mark */
        if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
            TRAPSTATUS |= (BIT5|BIT9);              /* set bit 5/9 of trap status */
        else
            TRAPSTATUS |= BIT16;                    /* set bit 16 of trap status */
        return MAPFLT;                              /* map overflow fault error */
    }
    CPIX = cpix;                                    /* save user MPL offset (cpix) */
    CPIXPL = spc;                                   /* save user map load count */

    /* Load maps for 32/27 aand 32/87 */
    if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {

        sim_debug(DEBUG_CMD, my_dev,
            "load_maps Processing 32/27 & 32/87 Model# %02x\n", CPU_MODEL);

        /* handle non virtual page loading or diag LMAP instruction */
        /* do 32/27 and 32/87 that force load all maps */
        /* now load user maps specified by the cpix value */
        for (j = 0; j < spc; j++, num++) {          /* copy maps from midl to map cache */
            uint32 pad = msdl+(j<<1);               /* get page descriptor address */

            /* see if map overflow */
            if (num >= MAXMAP) {
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps User page count overflow %04x, map fault\n", num);
                TRAPSTATUS |= BIT16;                /* set bit 16 of trap status */
                TRAPSTATUS |= (BIT5|BIT9);          /* set bit 5 of trap status */
                goto nomaps;                        /* map overflow, map fault trap */
            }
            if (!MEM_ADDR_OK(pad)) {                /* see if address is within our memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "load_maps MEM SIZE5 %06x User page address %06x invalid\n",
                    MEMSIZE, pad);
                goto npmem;                         /* non present memeory trap */
            }
            /* load 16 bit map descriptors */
            map = RMH(pad);                         /* get page descriptor from memory */

            /* for valid maps translate the map number to a real address */
            /* put this address in the TLB for later translation */
            /* copy the map status bits too and set hit bit in the TLB */
            /* leaving out diags in next statment fails test3/1 of vm.mmm */
            if ((map & 0x8000)) {                   /* see if map is valid */
                TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000));
                TLB[num] |= 0x04000000;             /* set HIT bit on */
            } else
                TLB[num] = 0;                       /* clear the TLB for non valid maps */
            WMR((num<<1), map);                     /* store map unmodified into cache */
        }
        if (num == 0) {                             /* see if any maps loaded */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps1 No maps loaded %04x, map fault\n", num);
            goto nomaps;                            /* return map fault error */
        }

        /* All maps are now loaded, finish up & return */
        for (i = num; i < MAXMAP; i++)              /* zero any remaining TLB entries */
            TLB[i] = 0;                             /* clear look aside buffer */

        HIWM = num;                                 /* set new high water mark */
        return ALLOK;                               /* all cache is loaded, return OK */
    }
    /**************END-OF-NON-VIRTUAL-USER-MAPPING-FOR-27-87************/
   
    sim_debug(DEBUG_CMD, my_dev,
        "load_maps Processing 32/67 & 32/97 Model# %02x\n", CPU_MODEL);

    /* handle load on memory access case for 67, 97, V6 & V9 */
    /* now clear TLB & maps specified by the cpix value */
    for (j = 0; j < spc; j++, num++) {              /* clear maps in map cache */
        uint32 pad = msdl+(j<<1);                   /* get page descriptor address */

        /* if this is a LPSDCM instruction, just clear the TLB entry */
        if (!lmap) {
            /* load 16 bit map descriptors */
            map = RMH(pad);                         /* get page descriptor from memory */
            TLB[num] = 0;                           /* clear the TLB for non valid maps */
            if ((num < 0x20) || (num > (spc+BPIX) - 0x10))
                sim_debug(DEBUG_DETAIL, my_dev,
                    "UserV pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n",
                    pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000,
                    TLB[num], MAPC[num/2]);
            continue;                               /* just clear the TLBs */
        }

        /* only do the following tests for LMAP instruction, not LPSDCM */
        /* see if map overflow */
        if (num >= MAXMAP) {
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps User page count overflow %04x, map fault\n", num);
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                TRAPSTATUS |= (BIT5|BIT9);          /* set bit 5/9 of trap status */
            else
                TRAPSTATUS |= BIT16;                /* set bit 16 of trap status */
            goto nomaps;                            /* map overflow, map fault trap */
        }

        if (!MEM_ADDR_OK(pad)) {                    /* see if address is within our memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "load_maps MEM SIZE6 %06x User page address %06x non present\n",
                MEMSIZE, pad);
            goto npmem;                             /* non present memeory trap */
        }

        /* load 16 bit map descriptors */
        map = RMH(pad);                             /* get page descriptor from memory */

        if (lmap) {
            TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000));
            TLB[num] |= 0x04000000;                 /* set HIT bit for lmap */
            /* removing this store of map fails test 2 on 97 */
            WMR((num<<1), map);                     /* store the map unmodified into cache */
        }

        if ((num < 0x20) || (num > (spc+BPIX) - 0x10))
            sim_debug(DEBUG_DETAIL, my_dev,
                "UserV2 pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n",
                pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000,
                TLB[num], MAPC[num/2]);
    }

    if (num == 0) {                                 /* see if any maps loaded */
        sim_debug(DEBUG_TRAP, my_dev,
            "load_maps2 No maps loaded %04x, map fault\n", num);
        goto nomaps;
    }

    /* All maps are now loaded, finish up & return */
    /* removing this code causes diag to stop at 17/0 for 97 in cn.mmm */
    for (i = num; i < MAXMAP; i++)                  /* zero any remaining entries */
        TLB[i] = 0;                                 /* clear look aside buffer */

    HIWM = num;                                     /* set new high water mark */
    return ALLOK;                                   /* all cache is loaded, return OK */
    /****************** END-OF-VIRTUAL-USER-MAP-LOADING ********************/
}

/*
 * Return the real memory address from the logical address
 * Also return the protection status, 1 if write protected address.
 * For 67, 97, V6, & V9 return all protection bits.
 * Addr is a byte address.
 */
LOCAL t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access)
{
    uint32  word, index, map, raddr, mpl, offset;
    uint32  nix, msdl, mix;
    uint32  MAXMAP = MAX2048;                       /* default to 2048 maps */

    *prot = 0;      /* show unprotected memory as default */
                    /* unmapped mode is unprotected */

    /*****************START-7X-ADDRESS-PROCESSING****************/
    /* see what machine we have */
    if (CPU_MODEL < MODEL_27) {
        MAXMAP = MAX32;                             /* 32 maps for 32/77 */
        /* 32/7x machine with 8KW maps */
        if (MODES & EXTDBIT)
            word = addr & 0xfffff;                  /* get 20 bit logical word address */
        else
            word = addr & 0x7ffff;                  /* get 19 bit logical word address */
        if ((MODES & MAPMODE) == 0) {
            /* check if valid real address */
            if (!MEM_ADDR_OK(word)) {               /* see if address is within our memory */
                return NPMEM;                       /* no, none present memory error */
            }
            *realaddr = word;                       /* return the real address */
            return ALLOK;                           /* all OK, return instruction */
        }

        /* we are mapped, so calculate real address from map information */
        /* 32/7x machine, 8KW maps */
        index = word >> 15;                         /* get 4 or 5 bit value */
        map = RMR((index<<1));                      /* read the map reg cache contents */

        /* see if map is valid */
        if ((map & 0x4000) == 0)
            /* map is invalid, so return map fault error */
            return MAPFLT;                          /* map fault error */

        /* required map is valid, get 9 bit address and merge with 15 bit page offset */
        word = ((map & 0x1ff) << 15) | (word & 0x7fff);
        /* check if valid real address */
        if (!MEM_ADDR_OK(word))                     /* see if address is within our memory */
            return NPMEM;                           /* no, none present memory error */
        if ((MODES & PRIVBIT) == 0) {               /* see if we are in unprivileged mode */
            if (map & 0x2000)                       /* check if protect bit is set in map entry */
                *prot = 1;                          /* return memory write protection status */
        }
        *realaddr = word;                           /* return the real address */
        return ALLOK;                               /* all OK, return instruction */
    }
    /*****************END-OF-7X-ADDRESS-PROCESSING****************/

    /* Everyone else has 2KW maps */
    /* do common processing */
    /* diag wants the address to be 19 or 24 bit, use masked address */
    if (MODES & (BASEBIT | EXTDBIT))
        word = addr & 0xffffff;                     /* get 24 bit address */
    else
        word = addr & 0x7ffff;                      /* get 19 bit address */

    if ((MODES & MAPMODE) == 0) {
        /* we are in unmapped mode, check if valid real address */
        if (!MEM_ADDR_OK(word)) {                   /* see if address is within our memory */
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                if (access == MEM_RD)
                    TRAPSTATUS |= BIT1;             /* set bit 1 of trap status */
                if (access == MEM_WR)
                    TRAPSTATUS |= BIT2;             /* set bit 2 of trap status */
            } else {
                TRAPSTATUS |= BIT10;                /* set bit 10 of trap status */
            }
            return NPMEM;                           /* no, none present memory error */
        }
        *realaddr = word;                           /* return the real address */
        return ALLOK;                               /* all OK, return instruction */
    }

    mpl = SPAD[0xf3] & MASK24;                      /* get 24 bit dbl wd mpl from spad address */

    /* set maximum maps for 32/27 and 32/87 processors */
    if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87))
        MAXMAP = MAX256;                            /* only 256 2KW (8kb) maps */

    /* did not get expected machine check trap for */
    /* 27, 87, 67 in test 37/0 if code removed */
    /* unexpected machine check trap for 67 in test 37/0 cn.mmm */
    /* now check the O/S midl pointer for being valid */
    /* we may want to delay checking until we actually use it */
    if (!MEM_ADDR_OK((RMW(mpl+4) & MASK24))) {      /* check OS midl */
        sim_debug(DEBUG_TRAP, my_dev,
            "RealAddr Bad MPL Memory Address O/S msdl MPL %06x MPL[1] %06x\n",
            mpl, RMW(mpl+4));

        if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
            // 32/27, 32/87 want MACHINECHK for test 37/1 in CN.MMM
            TRAPSTATUS |= BIT10;                    /* set bit 10 of trap status */
            return MACHINECHK_TRAP;                 /* diags want machine check error */
        } else
        if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6)) {
            TRAPSTATUS |= BIT10;                    /* set bit 10 of trap status */
            return MAPFLT;                          /* map fault error */
        }
        else
        if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
            // V9 & 32/97 wants MACHINECHK for test 37/1 in CN.MMM & VM.MMM
            TRAPSTATUS |= (BIT7|BIT9);              /* set bit 7 of trap status */
            TRAPSTATUS |= BIT28;                    /* set bit 28 of trap status */
            return MACHINECHK_TRAP;                 /* diags want machine check error */
        }
    }

    /* we are mapped, so calculate real address from map information */
    /* get 11 bit page number from address bits 8-18 */
    index = (word >> 13) & 0x7ff;                   /* get 11 bit page value */
    offset = word & 0x1fff;                         /* get 13 bit page offset */

    if (MODES & MAPMODE) {
        uint32 mpl = SPAD[0xf3];                    /* get mpl from spad address */
        uint32 cpix = CPIX;                         /* get cpix 11 bit offset from psd wd 2 */
        uint32 midl = RMW(mpl+cpix);                /* get midl entry for given user cpix */
        uint32 spc = midl & MASK16;                 /* get 16 bit user segment description count */
        /* output O/S and User MPL entries */
        sim_debug(DEBUG_DETAIL, my_dev,
            "+MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n",
            MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix,
            RMW(cpix+mpl), RMW(cpix+mpl+4));
        sim_debug(DEBUG_DETAIL, my_dev,
            "+MEMORY spc %x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n",
            spc, BPIX, cpix, CPIX, CPIXPL, HIWM);
    }

    /* make sure map index is valid */
    if ((index >= (BPIX + CPIXPL)) || (index >= MAXMAP)) {
        sim_debug(DEBUG_TRAP, my_dev,
            "RealAddr %.6x word %06x loadmap gets mapfault index %04x B(%x)+C(%x) %04x\n",
            word, addr, index, BPIX, CPIXPL, BPIX+CPIXPL);
        fflush(stdout);

        if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
            TRAPSTATUS |= (BIT5|BIT9);              /* set bit 5/9 of trap status */
        else
            TRAPSTATUS |= BIT16;                    /* set bit 16 of trap status */
        return MAPFLT;                              /* map fault error */
    }

    /* continue processing non virtual machines here 32/27 & 32/87 */
    /* at this point all maps have been force loaded in load_maps */
    /* just do the conversion from logical to real address */
    if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
        map = RMR((index<<1));                      /* read the map reg cache contents */
        raddr = TLB[index];                         /* get the base address & bits */

        if (!MEM_ADDR_OK(RMW(mpl+CPIX+4) & MASK24)) {  /* check user midl */
            sim_debug(DEBUG_TRAP, my_dev,
                "RealAddr 27 & 87 map fault index %04x B+C %04x map %04x TLB %08x\n",
                index, BPIX+CPIXPL, map, TLB[index]);
            // 32/27 & 32/87 want MACHINECHK for test 37/1 in CN.MMM
            TRAPSTATUS |= BIT10;                    /* set bit 10 of trap status */
            return MACHINECHK_TRAP;                 /* diags want machine check error */
        }

        if (((map & 0x8000) == 0) || ((raddr & BIT0) == 0)) {   /* see if valid map */
            sim_debug(DEBUG_TRAP, my_dev,
                "RealAddr loadmap 0a map fault index %04x B+C %04x map %04x TLB %08x\n",
                index, BPIX+CPIXPL, map, TLB[index]);
            TRAPSTATUS |= BIT10;                    /* set bit 10 of trap status */
            return MAPFLT;                          /* no, map fault error */
        }

        // needed for 32/27 & 32/87
        /* check if valid real address */
        if (!MEM_ADDR_OK(raddr & MASK24)) {         /* see if address is within our memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "RealAddr loadmap 0c non present memory fault addr %06x raddr %08x index %04x\n",
                word, raddr, index);
            TRAPSTATUS |= BIT28;                    /* set bit 28 of trap status */
            return NPMEM;                           /* no, none present memory error */
        }
        word = (raddr & 0xffe000) | offset;         /* combine real addr and offset */
        *realaddr = word;                           /* return the real address */
        if (MODES & PRIVBIT)                        /* all OK if privledged */
            return ALLOK;                           /* all OK, return instruction */

        /* get user protection status of map */
        offset = (word >> 11) & 0x3;                /* see which 1/4 page we are in */
        if ((BIT1 >> offset) & raddr) {             /* is 1/4 page write protected */
            *prot = 1;                              /* return memory write protection status */
        }
        sim_debug(DEBUG_DETAIL, my_dev,
            "RealAddrRa address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n",
            word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
        return ALLOK;                               /* all OK, return instruction */
    }
    /*****************END-OF-27-87-ADDRESS-PROCESSING****************/

    /* handle 32/67, 32/97 and V6 & V9 here */
    /* Concept 32 machine, 2KW maps */
    /* the index is less than B+C, so setup to get a map */
    if (TLB[index] & 0x04000000) {                  /* is HIT bit on in TLB */
        /* handle HIT bit already on in TLB here */
        /* diags wants a NPMEM error if physical addr is exceeded */
        index &= 0x7ff;                             /* map # */
        raddr = TLB[index];                         /* get the base address & bits */
        /* check if valid real address */
        if (!MEM_ADDR_OK(raddr & MASK24)) {         /* see if address is within our memory */
            sim_debug(DEBUG_TRAP, my_dev,
                "RealAddr loadmap 2a non present memory fault addr %08x raddr %08x index %04x\n",
                addr, raddr, index);
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                if (access == MEM_RD)
                    TRAPSTATUS |= BIT1;             /* set bit 1 of trap status */
                else
                if (access == MEM_WR)
                    TRAPSTATUS |= BIT2;             /* set bit 2 of trap status */
            } else
                TRAPSTATUS |= BIT28;                /* set bit 28 of trap status */
            return NPMEM;                           /* none present memory error */
        }
        map = RMR((index<<1));                      /* read the map reg contents */
        word = (raddr & 0xffe000) | offset;         /* combine map and offset */
        *realaddr = word;                           /* return the real address */

        /* handle 32/67 & 32/97 protection here */
        if (CPU_MODEL < MODEL_V6) {
            /* process 32/67 & 32/97 load map on access */
            /* handle 32/67 & 32/97 */
            if (MODES & PRIVBIT)                    /* all OK if privledged */
                return ALLOK;                       /* all OK, return instruction */

            /* get protection status of map */
            offset = (word >> 11) & 0x3;            /* see which 1/4 page we are in */
            if ((BIT1 >> offset) & raddr) {         /* is 1/4 page write protected */
                *prot = 1;                          /* return memory write protection status */
            }
            sim_debug(DEBUG_DETAIL, my_dev,
                "RealAddrR address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n",
                word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
            return ALLOK;                           /* all OK, return instruction */
        }

        /* handle valid V6 & V9 HIT bit on */
        /* get protection status of map */
        offset = ((map >> 12) & 0x6);               /* get bits p1 & p2 from map into bits 13 & 14 */
        if (MODES & PRIVBIT)                        /* all access if privledged */
            *prot = offset | 0x8;                   /* set priv bit */ 
        else
            *prot = offset;                         /* return memory write protection status */

        sim_debug(DEBUG_DETAIL, my_dev,
            "RealAddrX address %06x, TLB %06x MAPC[%03x] %08x wprot %02x prot %02x\n",
            word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
        return ALLOK;                               /* all OK, return instruction */
    }

    /* Hit bit is off in TLB, so lets go get some maps */
    sim_debug(DEBUG_DETAIL, my_dev,
        "$MEMORY %06x HIT MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n",
        MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), CPIX, RMW(CPIX+mpl), RMW(CPIX+mpl+4));

    /* check user msdl address now that we are going to access it */
    msdl = RMW(mpl+CPIX+4);                         /* get msdl entry for given CPIX */
    if (!MEM_ADDR_OK(msdl & MASK24)) {              /* check user midl */
        sim_debug(DEBUG_TRAP, my_dev,
            "RealAddr User CPIX Non Present Memory User msdl %06x CPIX %04x\n",
            msdl, CPIX);

        if (CPU_MODEL == MODEL_67) {
            /* test 37/0 wants MAPFLT trap for 67 */
            TRAPSTATUS |= BIT28;                    /* set bit 28 of trap status */
            return MAPFLT;                          /* map fault error on memory access */
        } else
        if (CPU_MODEL == MODEL_97) {
            /* 32/97 wants MAPFLT for test 37/1 in CN.MMM */
            TRAPSTATUS |= BIT12;                    /* set bit 12 of trap status */
            TRAPSTATUS |= (BIT7|BIT9);              /* set bit 7/9 of trap status */
            TRAPSTATUS |= BIT10;                    /* set bit 10 of trap status */
            return MAPFLT;                          /* no, map fault error */
        } else
        if (CPU_MODEL == MODEL_V6) {
            /* V6 wants MAPFLT for test 37/1 in CN.MMM & VM.MMM */
            TRAPSTATUS |= BIT28;                    /* set bit 28 of trap status */
            /* OK for V6 */
            return MAPFLT;                          /* map fault error */
        }
        else
        if (CPU_MODEL == MODEL_V9) {
            /* V9 wants MAPFLT for test 37/1 in CN.MMM & VM.MMM */
            /* V9 fails test 46/subtest 2 with "did not get expected map trap */
            TRAPSTATUS |= BIT12;                    /* set bit 12 of trap status */
            TRAPSTATUS |= (BIT7|BIT9);              /* set bit 7 of trap status */
            TRAPSTATUS |= BIT10;                    /* set bit 10 of trap status */
            return MAPFLT;                          /* map fault error */
        }
    }

    /* get os or user msdl, index < BPIX; os, else user */
    if (index < BPIX)
        msdl = RMW(mpl+4);                          /* get mpl entry wd 1 for os */
    else
        /* check user msdl address now that we are going to access it */
        msdl = RMW(mpl+CPIX+4);                     /* get mpl entry wd 1 for given cpix */

    /* HIT bit is off, we must load the map entries from memory */
    /* turn on the map hit flag if valid and set maps real base addr */
    nix = index & 0x7ff;                            /* map # or mapc index */
    word = (TLB[nix] & 0xffe000) | offset;          /* combine map and offset */
    if (index < BPIX)
        mix = nix;                                  /* get map index in memory */
    else
        mix = nix-BPIX;                             /* get map index in memory */
    map = RMH(msdl+(mix<<1));                       /* map content from memory */      
    sim_debug(DEBUG_DETAIL, my_dev,
        "Addr %06x RealAddr %06x Map0[%04x] HIT %04x TLB[%3x] %08x MAPC[%03x] %08x\n",
        addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]);

    /* process HIT bit off V6 & V9 here */
    if ((map & 0x8000) == 0) {
        *realaddr = word;                           /* return the real address */
        /* for V6 & V9 handle demand paging */
        if (CPU_MODEL >= MODEL_V6) {
            /* map is not valid, so we have map fault */
            sim_debug(DEBUG_EXP, my_dev,
                "AddrMa %06x RealAddr %06x Map0 MISS %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
                addr, word, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
            /* do a demand page request for the required page */
            pfault = nix;                           /* save page number */
            sim_debug(DEBUG_EXP, my_dev,
                "Mem_write Daddr2 %06x page %04x demand page bits set TLB %08x map %04x\n",
                addr, nix, TLB[nix], map);
            return DMDPG;                           /* demand page request */
        }
        /* handle 67 & 97 map invalid here */
        if (CPU_MODEL == MODEL_97) {
            if (access == MEM_RD)
                TRAPSTATUS |= BIT1;                 /* set bit 1 of trap status */
            else
            if (access == MEM_WR)
                TRAPSTATUS |= BIT2;                 /* set bit 2 of trap status */
        } else
            TRAPSTATUS |= BIT28;                    /* set bit 28  of trap status */
        return MAPFLT;                              /* map fault error */
    }

    /* map is valid, process it */
    TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000;
    word = (TLB[nix] & 0xffe000) | offset;          /* combine map and offset */
    WMR((nix<<1), map);                             /* store the map reg contents into MAPC cache */
    sim_debug(DEBUG_DETAIL, my_dev,
        "RealAddrm RMH %04x mix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n",
        map, mix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1));

    sim_debug(DEBUG_DETAIL, my_dev,
        "Addr1c %06x RealAddr %06x Map1[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n",
        addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1));

    *realaddr = word;                               /* return the real address */
    raddr = TLB[nix];                               /* get the base address & bits */

    if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97)) {
        /* get protection status of map */
        if ((MODES & PRIVBIT) == 0) {               /* OK if privledged */
            /* otherwise check protection bit */
            offset = (word >> 11) & 0x3;            /* see which 1/4 page we are in */
            if ((BIT1 >> offset) & raddr)           /* is 1/4 page write protected */
                *prot = 1;                          /* return memory write protection status */
        }
    } else {
        /* get protection status of map */
        offset = ((map >> 12) & 0x6);               /* get bits p1 & p2 from map into bits 13 & 14 */
        if (MODES & PRIVBIT)                        /* all access if privledged */
            *prot = offset | 0x8;                   /* set priv bit */ 
        else
            *prot = offset;                         /* return memory write protection status */
    }

    /* now do the other halfword of the memory map pair */
    /* calc index of previous or next halfword */
    if ((mix & 1) == 0) {
        mix += 1;                                   /* we are at lf hw, so do next hw */
        nix += 1;                                   /* point to next map in MAPC */
        /* This is really a firmware error where the CPU loads the */
        /* right halfword map information even though it exceeds */
        /* the allowed map count.  It does not hurt anything, so OK */
        /* 32/67 & V6 allow loading the extra rt hw map entry */
        if ((nix == BPIX) || (nix > (BPIX+CPIXPL)))
            return ALLOK;                           /* no other map is valid, we are done */
    } else
    if ((mix & 1) == 1) {
        if (nix == BPIX)
            return ALLOK;                           /* no other map is valid, we are done */
        mix -= 1;                                   /* we are at rt hw, so backup hw */
        nix -= 1;                                   /* point to last map in MAPC */
    }

    sim_debug(DEBUG_DETAIL, my_dev,
        "RealAddrp mix %04x nix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n",
         mix, nix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1));

    /* allow the excess map entry to be loaded, even though bad */
    if (nix <= (BPIX+CPIXPL)) {                     /* needs to be a mapped reg */
        sim_debug(DEBUG_DETAIL, my_dev,
            "Addr1d BPIX %03x CPIXPL %03x RealAddr %06x TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n",
            BPIX, CPIXPL, word, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1));

        /* mix & nix has other map correct index */
        if ((TLB[nix] & 0x04000000) == 0) {         /* is HIT bit already on */
            /* hit not on, so load the map */
            /* allow the excess map entry to be loaded, even though bad */
            if (nix <= (BPIX+CPIXPL)) {             /* needs to be a mapped reg */
                map = RMH(msdl+(mix<<1));           /* map content from memory */      
                sim_debug(DEBUG_DETAIL, my_dev,
                    "Addr2a %06x MapX[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
                    addr, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]);

                if (map & 0x8000) {                 /* must be valid to load */
                    /* setting access bit fails test 15/0 in vm.mmm diag */
                    TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000;
                    word = (TLB[nix] & 0xffe000);   /* combine map and offset */
                    WMR((nix<<1), map);             /* store the map reg contents into MAPC cache */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "Addr2b %06x RealAddr %06x Map2[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
                        addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
                }
            }
        }
    }
    /*****************END-OF-V6-V9-ADDRESS-HIT-PROCESSING****************/
    /*****************END-OF-67-97-ADDRESS-HIT-PROCESSING****************/
    return ALLOK;                                   /* all OK, return instruction */
}

/* fetch the current instruction from the PC address */
LOCAL t_stat read_instruction(uint32 thepsd[2], uint32 *instr)
{
    uint32 status, addr;

    if (CPU_MODEL < MODEL_27) {
        /* 32/7x machine with 8KW maps */
        /* instruction must be in first 512KB of address space */
        addr = thepsd[0] & 0x7fffc;                 /* get 19 bit logical word address */
    } else {
        /* 32/27, 32/67, 32/87, 32/97 2KW maps */
        /* Concept 32 machine, 2KW maps */
        if (thepsd[0] & BASEBIT) {                  /* bit 6 is base mode? */
            addr = thepsd[0] & 0xfffffc;            /* get 24 bit address */
        }
        else
            addr = thepsd[0] & 0x7fffc;             /* get 19 bit address */
    }

    /* go read the memory location */
    status = Mem_read(addr, instr);
    if ((status == MAPFLT) && (TRAPSTATUS == BIT1)) {
        /* if map fault on read, change code to read instruction */
        TRAPSTATUS &= ~BIT1;                        /* clear error on read memory */
        TRAPSTATUS |= BIT0;                         /* set error on instruction read */
    } else
    if (status == DMDPG)
        pfault |= 0x80000000;                       /* set instruction fetch paging error */
    sim_debug(DEBUG_DETAIL, my_dev, "read_instr status %02x @ %06x\n", status, addr);
    return status;                                  /* return ALLOK or ERROR status */
}

/*
 * Read a full word from memory
 * Return error type if failure, ALLOK if
 * success.  Addr is logical byte address.
 */
LOCAL t_stat Mem_read(uint32 addr, uint32 *data)
{
    uint32 status, realaddr=0, prot, page, map, mix, nix, msdl, mpl, nmap;

    status = RealAddr(addr, &realaddr, &prot, MEM_RD);  /* convert address to real physical address */

    if (status == ALLOK) {
        *data = RMW(realaddr);                      /* valid address, get physical address contents */
        if (((CPU_MODEL >= MODEL_V6) || (CPU_MODEL == MODEL_97) ||
            (CPU_MODEL == MODEL_67)) && (MODES & MAPMODE)) {

            page = (addr >> 13) & 0x7ff;            /* get 11 bit value */
            if (CPU_MODEL >= MODEL_V6) {
                /* check for v6 & v9 if we have read access */
                switch (prot & 0x0e) {
                case 0x0: case 0x2:
                    /* O/S or user has no read/execute access, do protection violation */
                    sim_debug(DEBUG_EXP, my_dev,
                        "Mem_readA protect error @ %06x prot %02x modes %08x page %04x\n",
                        addr, prot, MODES, page);
                    if (CPU_MODEL == MODEL_V9)
                        TRAPSTATUS |= BIT2;         /* set bit 2 of trap status */
                    else
                        TRAPSTATUS &= ~BIT12;       /* clear bit 12 of trap status */
                    return MPVIOL;                  /* return memory protection violation */
                case 0x4: case 0x6: case 0x8: case 0xa: case 0xc: case 0xe:
                    /* O/S or user has read/execute access, no protection violation */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "Mem_readB protect is ok @ %06x prot %02x modes %08x page %04x\n",
                        addr, prot, MODES, page);
                }
                mpl = SPAD[0xf3];                   /* get mpl from spad address */
                nix = page & 0x7ff;                 /* map # or mapc index */
                if (page < BPIX) {
                    mix = nix;                      /* get map index in memory */
                    msdl = RMW(mpl+4);              /* get mpl entry for o/s */
                } else {
                    mix = nix-BPIX;                 /* get map index in memory */
                    msdl = RMW(mpl+CPIX+4);         /* get mpl entry for given cpix */
                }
                nmap = RMH(msdl+(mix<<1));          /* map content from memory */      
                map = RMR((page<<1));               /* read the map reg contents */
                /* if I remove this test, we fail at test 14/0 */
                if (((map & 0x800) == 0)) {
                    map |= 0x800;                   /* set the accessed bit in the map cache entry */
                    WMR((page<<1), map);            /* store the map reg contents into cache */
                    TLB[page] |= 0x0c000000;        /* set the accessed bit in TLB too */
                    WMH(msdl+(mix<<1), map);        /* save modified map with access bit set */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "Mem_read Yaddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n",
                        addr, page, TLB[page], map, nmap);
                }
            }
            /* everybody else has read access */
        }
        sim_debug(DEBUG_DETAIL, my_dev,
            "Mem_read addr %06x realaddr %06x data %08x prot %02x\n",
            addr, realaddr, *data, prot);
    } else {
        /* RealAddr returned an error */
        sim_debug(DEBUG_EXP, my_dev,
            "Mem_read error addr %06x realaddr %06x data %08x prot %02x status %04x\n",
            addr, realaddr, *data, prot, status);
        if (status == NPMEM) {                      /* operand nonpresent memory error */
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                TRAPSTATUS |= BIT1;                 /* set bit 1 of trap status */
            } else
                TRAPSTATUS |= BIT10;                /* set bit 10 of trap status */
        }
        if (status == MAPFLT) {
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                TRAPSTATUS |= (BIT12|BIT16);        /* set bit 12 of trap status */
            else
                TRAPSTATUS |= BIT10;                /* set bit 10 of trap status */
        }
        sim_debug(DEBUG_EXP, my_dev, "Mem_read MISS %02x @ %06x TRAPSTATUS %08x\n",
            status, addr, TRAPSTATUS);
    }
    return status;                                  /* return ALLOK or ERROR status */
}

/*
 * Write a full word to memory, checking protection
 * and alignment restrictions. Return 1 if failure, 0 if
 * success.  Addr is logical byte address, data is 32bit word
 */
LOCAL t_stat Mem_write(uint32 addr, uint32 *data)
{
    uint32 status, realaddr=0, prot=0, raddr, page, nmap, msdl, mpl, map, nix, mix;

    status = RealAddr(addr, &realaddr, &prot, MEM_WR);  /* convert address to real physical address */

    if (prot) {
        sim_debug(DEBUG_DETAIL, my_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %02x\n",
            addr, realaddr, *data, prot);
    }

    if (status == ALLOK) {
        if (((CPU_MODEL >= MODEL_V6) || (CPU_MODEL == MODEL_97) ||
            (CPU_MODEL == MODEL_67)) && (MODES & MAPMODE)) {
            page = (addr >> 13) & 0x7ff;            /* get 11 bit value */
            if (CPU_MODEL >= MODEL_V6) {
                /* check for v6 & v9 if we have write access */
                switch (prot &0x0e) {
                case 0x0: case 0x2: case 0x6: case 0xa: case 0xe:
                    /* O/S or user has read/execute access, do protection violation */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "Mem_writeA protect error @ %06x prot %02x modes %08x\n",
                        addr, prot, MODES);
                    if (CPU_MODEL == MODEL_V9)
                        TRAPSTATUS |= BIT1;         /* set bit 1 of trap status */
                    else
                        TRAPSTATUS |= BIT12;        /* set bit 12 of trap status */
                    return MPVIOL;                  /* return memory protection violation */
                case 0x4: case 0x8: case 0xc:
                    /* O/S or user has write access, no protection violation */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "Mem_writeB protect is ok @ %06x prot %02x modes %08x\n",
                        addr, prot, MODES);
                }
                map = RMR((page<<1));               /* read the map reg contents */
                raddr = TLB[page];                  /* get the base address & bits */
                nix = page & 0x7ff;                 /* map # or mapc index */
                mpl = SPAD[0xf3];                   /* get mpl from spad address */
                if (page < BPIX) {
                    mix = nix;                      /* get map index in memory */
                    msdl = RMW(mpl+4);              /* get mpl entry for o/s */
                } else {
                    mix = nix-BPIX;                 /* get map index in memory */
                    msdl = RMW(mpl+CPIX+4);         /* get mpl entry for given cpix */
                }
                nmap = RMH(msdl+(mix<<1));          /* map content from memory */      
                if ((nmap & 0x1000) == 0) {
                    nmap |= 0x1800;                 /* set the modify/accessed bit in the map cache entry */
                    WMR((page<<1), nmap);           /* store the map reg contents into cache */
                    TLB[page] |= 0x18000000;        /* set the modify/accessed bits in TLB too */
                    WMH((msdl+(mix << 1)), nmap);   /* save modified map with access bit set */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "Mem_write Waddr %06x page %04x set access bit TLB %08x map %04x nmap %04x raddr %08x\n",
                        addr, page, TLB[page], map, nmap, raddr);
                }
                sim_debug(DEBUG_DETAIL, my_dev,
                    "Mem_write Xaddr %06x page %04x MA bits set TLB %08x map %04x prot %04x modes %04x\n",
                    addr, page, TLB[page], map, prot, MODES);
            } else {
                if (prot) {                         /* check for write protected memory */
                    sim_debug(DEBUG_EXP, my_dev,
                        "Mem_writeB 32/67 protect error @ %06x prot %02x page %04x\n",
                        addr, prot, page);
                    if (CPU_MODEL == MODEL_97)
                        TRAPSTATUS |= BIT1;         /* set bit 1 of trap status */
                    else
                        TRAPSTATUS |= BIT12;        /* set bit 12 of trap status */
                    return MPVIOL;                  /* return memory protection violation */
                }
            }
            /* everything else has write access */
        } else {
            if (prot) {                             /* check for write protected memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "Mem_writeC protect error @ %06x prot %02x\n", addr, prot);
                TRAPSTATUS |= BIT12;                /* set bit 12 of trap status */
                return MPVIOL;                      /* return memory protection violation */
            }
        }
        WMW(realaddr, *data);                       /* valid address, put physical address contents */
    } else {
        /* RealAddr returned an error */
        sim_debug(DEBUG_TRAP, my_dev,
            "Mem_write error addr %.8x realaddr %.8x data %.8x prot %02x status %04x\n",
            addr, realaddr, *data, prot, status);
        if (status == NPMEM) {                      /* operand nonpresent memory error */
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                TRAPSTATUS |= BIT2;                 /* set bit 2 of trap status */
            } else
                TRAPSTATUS |= BIT10;                /* set bit 10 of trap status */
        }
        if (status == MAPFLT) {
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                TRAPSTATUS |= (BIT12|BIT16);        /* set bit 12 of trap status */
            else
                TRAPSTATUS |= BIT10;                /* set bit 10 of trap status */
        }
        sim_debug(DEBUG_TRAP, my_dev,
            "Mem_write error %02x @ %06x TRAPSTATUS %08x pfaualt %04x\n",
            status, addr, TRAPSTATUS, pfault);
    }
    return status;                                  /* return ALLOK or ERROR */
}

/* function to set the CCs in PSD1 */
/* ovr is setting for CC1 */
LOCAL void set_CCs(uint32 value, int ovr)
{
    PSD1 &= 0x87FFFFFE;                             /* clear the old CC's */
    if (ovr)
        CC = CC1BIT;                                /* CC1 value */
    else
        CC = 0;                                     /* CC1 off */
    if (value & FSIGN)
        CC |= CC3BIT;                               /* CC3 for neg */
    else if (value == 0)
        CC |= CC4BIT;                               /* CC4 for zero */
    else 
        CC |= CC2BIT;                               /* CC2 for greater than zero */
    PSD1 |= (CC & 0x78000000);                      /* update the CC's in the PSD */
}

LOCAL uint32  skipinstr = 0;                        /* Skip test for interrupt on this instruction */
LOCAL uint32  drop_nop = 0;                         /* Set if right hw instruction is a nop */
LOCAL uint32  TPSD[2];                              /* Temp PSD */
#define TPSD1 TPSD[0]                               /* word 1 of PSD */
#define TPSD2 TPSD[1]                               /* word 2 of PSD */

/* Opcode definitions */
/* called from simh simulator code */
t_stat sim_instr(void) {
    t_stat              reason = 0;                 /* reason for stopping */
    t_uint64            dest = 0;                   /* Holds destination/source register */
    t_uint64            source = 0;                 /* Holds source or memory data */
    t_uint64            td;                         /* Temporary */
    t_int64             int64a;                     /* temp int */
    t_int64             int64b;                     /* temp int */
    t_int64             int64c;                     /* temp int */
    uint32              addr;                       /* Holds address of last access */
    uint32              temp;                       /* General holding place for stuff */
//  uint32              IR;                         /* Instruction register */
    uint32              i_flags=0;                  /* Instruction description flags from table */
    uint32              t;                          /* Temporary */
    uint32              temp2;                      /* Temporary */
    uint32              bc=0;                       /* Temporary bit count */
//  uint16              OPR;                        /* Top half of Instruction register */
//  uint16              OP;                         /* Six bit instruction opcode */
    uint16              chan;                       /* I/O channel address */
    uint16              lchan;                      /* Logical I/O channel address */
    uint16              suba;                       /* I/O subaddress */
    uint16              lchsa;                      /* logical I/O channel & subaddress */
    uint16              rchsa;                      /* real I/O channel & subaddress */
    uint8               FC;                         /* Current F&C bits */
    uint8               EXM_EXR=0;                  /* PC Increment for EXM/EXR instructions */
    uint8               BM, MM, BK;                 /* basemode, mapped mode, blocked mode */
    uint32              reg;                        /* GPR or Base register bits 6-8 */
    uint32              sreg;                       /* Source reg in from bits 9-11 reg-reg instructions */
    uint32              ix = 0;                     /* index register */
    uint32              dbl;                        /* Double word */
    uint32              ovr=0;                      /* Overflow flag */
//FORSTEP    uint32              stopnext = 0;      /* Stop on next instruction */
//  uint32              int_icb;                    /* interrupt context block address */
    uint32              rstatus;                    /* temp return status */
    int32               int32a;                     /* temp int */
    int32               int32b;                     /* temp int */
    int32               int32c;                     /* temp int */

    reason = SCPE_OK;

    /* loop here until time out or error found */
wait_loop:
    while (reason == SCPE_OK) {                     /* loop until halted */

        if (sim_interval <= 0) {                    /* event queue? */
            reason = sim_process_event();           /* process */
            if (reason != SCPE_OK) {
                sim_debug(DEBUG_EXP, my_dev,
                    "Process Event any reason %08x interval %08x\n",
                    reason, sim_interval);
                fflush(sim_deb);
#ifdef DEBUG4IPU
                DumpHist();
#else
//    cpu_show_hist(sim_deb, (UNIT *)0, (int32)0, (void *)0);
//    fflush(sim_deb);
#endif
                return reason;
                break;                              /* process */
            }
        }

#if 1
        /* stop simulator if user break requested */
        if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
            reason = STOP_IBKPT;
            sim_debug(DEBUG_EXP, my_dev, "Process Event test reason %08x interval %08x\n",
               reason, sim_interval);
            sim_interval= 0;                        /* count down */
            break;
        }
#endif

        sim_interval--;                             /* count down */

        if (skipinstr) {                            /* need to skip interrupt test? */
            skipinstr = 0;                          /* skip only once */
            sim_debug(DEBUG_IRQ, my_dev,
                "%s Skip instruction PSD %08x %08x irq_pend %d wait4int %d\n",
                (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                PSD1, PSD2, irq_pend, wait4int);
                sim_debug(DEBUG_IRQ, my_dev,
                "Skip instruction OPSD %08x %08x PSD %08x %08x CPUSTATUS %08x\n",
                OPSD1, OPSD2, PSD1, PSD2, CPUSTATUS);
            goto skipi;                             /* skip int test */
        }

        /* we are booting the system, so see if boot channel prog is completed */
        if (loading) {
#ifdef USE_IPU_THREAD
            int rstat;
#endif
            uint32 il;
            uint32 chsa  = scan_chan(&il);          /* go scan for load complete pending */
            if (chsa != 0) {                        /* see if a boot channel/subaddress was returned */
                /* take interrupt, store the PSD, fetch new PSD */
                PSD1 = TPSD[0];                     /* PSD1 from location 0 */
                PSD2 = TPSD[1];                     /* PSD2 from location 4 */
                CC = PSD1 & 0x78000000;             /* extract bits 1-4 from PSD1 */
                MODES = PSD1 & 0x87000000;          /* extract bits 0, 5, 6, 7 from PSD 1 */
                CPUSTATUS &= ~0x87000000;           /* reset bits in CPUSTATUS */
                CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */
                sim_debug(DEBUG_TRAP, my_dev, "Boot Loading PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n",
                    PSD1, PSD2, CPUSTATUS, CCW);
                PSD2 &= ~RETMBIT;                   /* turn off retain map bit in PSD2 */
                PSD2 &= ~RETBBIT;                   /* turn off retain block mode bit in PSD2 */
                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                /* set interrupt blocking state in CPUSTATUS */
                CPUSTATUS |= BIT24;                 /* set blocked state in cpu status, bit 24 too */
                MODES |= BLKMODE;                   /* set blocked in mode too */
                if (IPU_MODEL)                      /* see if loading an IPU model */
                    CCW |= HASIPU;                  /* this is BIT19 for IPU configured */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                if (!IPU_MODEL) {                   /* done loading if not an IPU model */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "Boot Non IPU PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n",
                        PSD1, PSD2, CPUSTATUS, CCW);
                    goto loadend;                   /* done with cpu */
                }
                sim_debug(DEBUG_TRAP, my_dev,
                    "Boot use IPU PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n",
                    PSD1, PSD2, CPUSTATUS, CCW);
#ifndef CPUONLY
#ifndef USE_IPU_THREAD
                /* Process IPU fork model */
                /* now fork another copy of simh for ipu */
                /* Create InterProcessor Com data */
                /* we piggyback on the main memory that we created larger */
                IPC = (struct ipcom *)&M[MAXMEMSIZE];
#else
                /* IPC set in reset code for thread IPU */
#endif

#ifndef CPUONLY
                /* init semaphore */
#ifndef USE_IPU_THREAD
                /* shared by forked tasks */
                if (sem_init((sem_t *)&(IPC->simsem), 1, 1) != 0) {
                    if (errno == ENOSYS)
                        fprintf(stderr,"POSIX semaphores not valid for this processsor\r\n");
                }
#else
#ifdef USE_POSIX_SEM
                /* shared by threads */
                if (sem_init((sem_t *)&(IPC->simsem), 0, 1) != 0) {
                    if (errno == ENOSYS)
                        fprintf(stderr,"POSIX semaphores not valid for this processsor\r\n");
                }
                fprintf(stderr,"POSIX semaphores completed for this processsor\r\n");
                fflush(stdout);
#else
                /* the pthread mutex is initialized in the CPU */
                sim_debug(DEBUG_TRAP, my_dev,
                    "IPU pthread mutex completed for this processsor\n");
#endif
#endif
#endif

#ifndef USE_IPU_THREAD
                pid = fork();
#else
                /* if we have a thread already, do't do it again */
                if (got_ipu == 0) {
                    rstat = pthread_create(&ipuThread, NULL, ipu_sim_instr, NULL);
                    if (rstat) {
                        sim_printf("IPU thread create failed rstat = %x\n", rstat);
                        exit(1);
                    } else {
                        sim_printf("IPU thread created successfully\n");
                        got_ipu = 1;                /* we have an ipu thread */
                    }
                } else {
                    cpustop = STOP_RESET;           /* tell IPU to reset for reboot */
                }
#endif
                /*
                 * right now we are two processes with copy of variables
                 * M is shared as main memory by CPU and IPU
                 * IPC structure also shared to signal SIPU traps
                 */

#ifndef USE_IPU_THREAD
                /* the newly created child process in IPU */
                if (pid == 0) {
                    /* running on IPU */
                    MyIndex = 1;
                    PeerIndex = 0;
                    /* both CPU and IPU */
                    IPC->pid[MyIndex] = getpid();

                    /* we will be running with an ipu, set it up */
                    /* clear I/O and interrupt entries in SPAD. */
                    /* They are not used in the IPU */
                    for (il=0; il<0xf0; il++)
                        SPAD[il] = 0;
                    SPAD[0xf7] = 0x13254768;        /* set SPAD key for IPU */
                    SPAD[0xf0] = 0x20;              /* default Trap Table Address (TTA) */
                    CPUSTATUS |= ONIPU;             /* set ipu state in cpu status, BIT27 */
                    CPUSTATUS |= BIT25;             /* set ipu traps enabled status, BIT25 */
                    TRAPSTATUS |= ONIPU;            /* set IPU in trap status too */
                    /* This would be BIT20 set to 0 for V9 IPU iconfigured status */
                    /* If no IPU configured, BIT19 is set */
                    /* FIXME */
                    CCW |= HASIPU;                  /* this is BIT19 for IPU configured */
                    SPAD[0xf9] = CPUSTATUS;         /* save the cpu status in SPAD */
                    PSD1 = 0x80000000;              /* PSD1 privledged */
                    PSD2 = 0x00000000;              /* PSD2 unmapped, unblocked */
                    CC = PSD1 & 0x78000000;         /* extract bits 1-4 from PSD1 */
                    MODES = PSD1 & 0x87000000;      /* extract bits 0, 5, 6, 7 from PSD 1 */
                    CPUSTATUS &= ~0x87000000;       /* reset bits in CPUSTATUS */
                    CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "IPU Boot Loading PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n",
                        PSD1, PSD2, CPUSTATUS, CCW);
                    SPAD[0xf5] = PSD2;              /* save the current PSD2 */
                    /* set interrupt blocking state in CPUSTATUS */
                    CPUSTATUS &= ~BIT24;            /* clear blocked state in cpu status, bit 24 */
                    wait4sipu = 1;                  /* now wait for 1st sipu */
                    loading = 0;                    /* we are done loading */
                    fclose(stdin);                  /* close stdin for terminal */

                    sim_debug(DEBUG_TRAP, my_dev,
                        "Starting IPU WAIT in fork\n");
#ifdef USE_POSIX_SEM
                    sim_os_ms_sleep(10);            /* wait 10 ms */
//                  millinap(1);                    /* wait 1 ms */
#endif
                    goto wait_loop;                 /* continue waiting */
                }
#endif /* USE_IPU_THREAD */
#endif /* CPUONLY */
                {
                    /* running on CPU with forked IPU */
#ifndef CPUONLY
                    MyIndex = 0;
                    PeerIndex = 1;
#endif
                    CPUSTATUS &= ~BIT27;            /* This a CPU, not IPU */
                    SPAD[0xf9] = CPUSTATUS;         /* save the cpu status in SPAD */
#ifndef CPUONLY
#ifndef USE_IPU_THREAD
                    /* both CPU and IPU */
                    IPC->pid[MyIndex] = getpid();
#else
                    IPC->pid[MyIndex] = 0;
#endif
#endif
                    /* This would be BIT20 set to 0 for V9 IPU iconfigured status */
                    /* If no IPU configured, BIT19 is set.  Backward of other models */
                    /* FIXME */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "CPU Boot Loading PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n",
                        PSD1, PSD2, CPUSTATUS, CCW);
                    CCW |= HASIPU;                  /* this is BIT19 for IPU present */
                }
loadend:
                loading = 0;                        /* we are done loading */
#ifdef CPUONLY
                sim_debug(DEBUG_EXP, my_dev,
                    "Load complete, start @PSD %08x %08x CPUSTATUS %08x\n",
                    PSD1, PSD2, CPUSTATUS);
#endif
                goto skipi;                         /* skip int test */
            }
            goto wait_loop;                         /* continue waiting */
        }

        /* we get here when not booting */
#ifndef CPUONLY
        /* process SIPU if IPU present */
        if (IPU_MODEL) {
#ifdef USE_POSIX_SEM
            /* process any pending sipu traps from the ipu here on cpu */
            /* interrupts must be unblocked to take the sipu trap */
            if (((CPUSTATUS & ONIPU) == 0) && IPC && ((CPUSTATUS & BIT24) == 0) &&
                IPC->atrap[MyIndex]) {
                TRAPME = IPC->atrap[MyIndex];
                IPC->atrap[MyIndex] = 0;
                IPC->received[MyIndex]++;
                sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x Index %x PeerIndex %x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, MyIndex, PeerIndex);
                sim_debug(DEBUG_TRAP, my_dev,
                    "%s: PC %08x PSD1 %08x PSD2 %08x 0x4c %x 0xac %x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                    PC, PSD1, PSD2, M[0x4c>>2], M[0xac>>2]);
                wait4int = 0;                       /* wait is over for int */
                skipinstr = 1;                      /* skip interrupt test */
                goto newpsd;                        /* go process trap */
            }
            /* wait for sipu to start us on ipu */
            /* interrupts must be unblocked on IPU too! */
            if ((CPUSTATUS & ONIPU) && ((CPUSTATUS & BIT24) == 0)) {
                if (IPC && IPC->atrap[MyIndex]) {
                    wait4sipu = 0;                  /* wait is over for sipu */
                    TRAPME = IPC->atrap[MyIndex];   /* get trap number */
                    IPC->atrap[MyIndex] = 0;        /* clear flag */
                    IPC->received[MyIndex]++;
                    sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x SPAD[0xf0] %08x\n",
                        (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, SPAD[0xf0]);
                    sim_debug(DEBUG_TRAP, my_dev,
                        "%s: PC %08x PSD1 %08x PSD2 %08x 0x4c %x 0x4ac%x\n",
                        (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                        PC, PSD1, PSD2, M[0x4c>>2], M[0xac>>2]);
                    skipinstr = 1;                  /* skip interrupt test */
                    goto newpsd;                    /* go process trap */
                }
                if (wait4sipu) {
                    sim_os_ms_sleep(10);            /* wait 10 ms */
//                  millinap(1);                    /* wait 1 ms */
                    goto wait_loop;                 /* continue waiting */
                }
            }
#else   /* USE_POSIX_SEM */
            /* process any pending sipu traps from the ipu here on cpu */
            /* interrupts must be unblocked to take the sipu trap */
            if (((CPUSTATUS & ONIPU) == 0) && IPC && ((CPUSTATUS & BIT24) == 0) &&
                IPC->atrap[MyIndex]) {
                TRAPME = IPC->atrap[MyIndex];
                IPC->atrap[MyIndex] = 0;
                IPC->received[MyIndex]++;
                sim_debug(DEBUG_TRAP, my_dev,
                    "%s: (%d) Async TRAP %02x Index %x PeerIndex %x rec'd %08x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, MyIndex,
                    PeerIndex, IPC->received[MyIndex]);
                sim_debug(DEBUG_TRAP, my_dev,
                    "%s: PC %08x PSD1 %08x PSD2 %08x 0x4c %x 0xac %x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                    PC, PSD1, PSD2, M[0x4c>>2], M[0xac>>2]);
                wait4int = 0;                       /* wait is over for int */
                skipinstr = 1;                      /* skip interrupt test */
                goto newpsd;                        /* go process trap */
            }
            /* we may or may not be waiting for sipu */
            /* wait for sipu to start us on ipu */
            /* interrupts must be unblocked on IPU to receive SIPU */
            if ((CPUSTATUS & ONIPU) && ((CPUSTATUS & BIT24) == 0) && IPC &&
                (IPC->atrap[MyIndex] != 0)) {
                /* we are unblocked, look for SIPU */
                /* we have a trap available, lock and get it */
cond_go:
                if (IPC && IPC->atrap[MyIndex]) {
                    lock_mutex();                   /* lock mutex */
                    TRAPME = IPC->atrap[MyIndex];   /* get trap number */
                    IPC->atrap[MyIndex] = 0;        /* clear trap value location */
                    unlock_mutex();                 /* unlock mutex */
                    IPC->received[MyIndex]++;       /* count it received */
                    wait4sipu = 0;                  /* wait is over for sipu */
                    sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x SPAD[0xf0] %02x rec'd %08x\n",
                        (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, SPAD[0xf0], IPC->received[MyIndex]);
                    sim_debug(DEBUG_TRAP, my_dev,
                        "%s: PC %08x PSD %08x %08x 0x4c %x 0xac %x\n",
                        (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                        PC, PSD1, PSD2, M[0x4c>>2], M[0xac>>2]);
                    skipinstr = 1;                  /* skip interrupt test */
                    goto newpsd;                    /* go process trap */
                }
                /* unblocked and locked and no async trap */
                if (wait4sipu) {                    /* are we to wait */
                    lock_mutex();                   /* lock mutex */
                    while (IPC->atrap[MyIndex]==0)  /* sleep on the condition */
                        pthread_cond_wait(&IPC->cond, &IPC->mutex); /* wait for wakeup */
                    unlock_mutex();                 /* unlock mutex and continue */
                    goto cond_go;                   /* go process */
                }
                /* not waiting for sipu, so continue processing */
            }
            /* we are blocked or no pending sipu, contine */
            /* continue processing */
#endif  /* USE_POSIX_SEM */
        }
#endif /* CPU_ONLY*/

        /* process any pending interrupts */
        if (irq_pend || wait4int) {
            /* see if ints are pending */
            uint32 int_icb;                         /* interrupt context block address */
            uint32 ilev;
            int32 oldstatus = CPUSTATUS;            /* keep for retain blocking state */
            SPAD[0xf9] = CPUSTATUS;                 /* save the cpu status in SPAD */

            int_icb = scan_chan(&ilev);             /* no, go scan for I/O int pending */
            if (int_icb != 0) {                     /* was ICB returned for an I/O or interrupt */
                uint32 il = ilev;                   /* get the interrupt level */
                sim_debug(DEBUG_IRQ, my_dev,
                    "<|>Normal int return icb %06x level %02x irq_pend %1x wait4int %1x\n",
                    int_icb, il, irq_pend, wait4int);

                /* take interrupt, store the PSD, fetch new PSD */
                bc = PSD2 & 0x3ff8;                 /* get copy of cpix */
                M[int_icb>>2] = PSD1&0xfffffffe;    /* store PSD 1 */
                M[(int_icb>>2)+1] = PSD2;           /* store PSD 2 */
                TPSD1 = PSD1;                       /* save the current PSD */
                TPSD2 = PSD2;
                PSD1 = M[(int_icb>>2)+2];           /* get new PSD 1 */
                PSD2 = (M[(int_icb>>2)+3] & ~0x3fff) | bc;  /* get new PSD 2 w/old cpix */

                sim_debug(DEBUG_IRQ, my_dev,
                    "<|>Normal int cpix %04x OPSD %08x %08x NPSD %08x %08x CPUSTATUS %08x\n",
                    bc, TPSD1, TPSD2, PSD1, PSD2, CPUSTATUS);
#ifdef DUMP_REGS
                for (ix=0; ix<8; ix+=2) {
                    sim_debug(DEBUG_IRQ, my_dev,
                        "<|> GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]);
                }
#endif
                /* test for retain blocking state */
                if (PSD2 & RETBBIT) {               /* is it retain blocking state */
                    /* BIT 49 has new blocking state */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        PSD2 |= SETBBIT;            /* yes, set to blocked state */
                        MODES |= BLKMODE;           /* set blocked mode */
                        CPUSTATUS |= BIT24;         /* set blocked mode */
                    } else {
                        PSD2 &= ~SETBBIT;           /* set to unblocked state */
                        MODES &= ~RETMODE;          /* reset retain block mode bit */
                        CPUSTATUS &= ~BIT24;        /* reset block state in cpu status bit 8 */
                    }
                    PSD2 &= ~RETBBIT;               /* clear bit 48 retain blocking bit */
                }

                if (PSD2 & SETBBIT) {               /* no, is it set blocking state bit 49 set*/
                    /* new blocking state is blocked when bits 48=0 & bit 49=1 */
                    /* This test fixed the hangs on terminal input for diags & UTX! */
                    t = SPAD[il+0x80];              /* get spad entry for interrupt */
                    /* Class F I/O spec says to reset active interrupt if user's */
                    /* interrupt service routine runs with interrupts blocked */
                    if (((t & 0x0f800000) == 0x0f000000) || /* if class F clear interrupt */
                        ((t & 0x0f80ffff) == 0x00807f06) || /* RT Clock */
                        ((t & 0x0f00ffff) == 0x03007f04)) { /* Interval timer */
                        /* if this is F class I/O interrupt, clear the active level */
                        /* SPAD entries for interrupts begin at 0x80 */
                        sim_debug(DEBUG_IRQ, my_dev,
                            "<|>Auto-reset interrupt INTS[%02x] %08x SPAD[%02x] %08x\n",
                            il, INTS[il], il+0x80, SPAD[il+0x80]);
                        INTS[il] &= ~INTS_ACT;      /* deactivate specified int level */
                        SPAD[il+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
                    }
                } else {
                    sim_debug(DEBUG_IRQ, my_dev,
                        "<|>RUN ACTIVE interrupt INTS[%02x] %08x SPAD[%02x] %08x\n",
                        il, INTS[il], il+0x80, SPAD[il+0x80]);
                }

                /* set new map mode and interrupt blocking state in CPUSTATUS & MODES */
                /* I/O status DW address will be in WD 6 */
                /* set new map mode and interrupt blocking state in CPUSTATUS */
                CC = PSD1 & 0x78000000;             /* extract bits 1-4 from PSD1 */
                MODES = PSD1 & 0x87000000;          /* extract bits 0, 5, 6, 7 from PSD 1 */
                CPUSTATUS &= ~0x87000080;           /* reset bits in CPUSTATUS */
                CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */

                if (PSD2 & SETBBIT) {               /* is it set blocking state bit 49 set*/
                    /* set new blocking state bit 49=1 */
                    CPUSTATUS |= BIT24;             /* yes, set blk state in cpu status bit 24 */
                    MODES |= BLKMODE;               /* set blocked mode */
                } else {
                    CPUSTATUS &= ~BIT24;            /* reset block state in cpu status bit 8 */
                    MODES &= ~BLKMODE;              /* reset block mode bits */
                }
                /* bit 0 of PSD wd 2 sets new mapping state */
                if (PSD2 & MAPBIT) {
                    CPUSTATUS |= BIT8;              /* set bit 8 of cpu status to mapped */
                    MODES |= MAPMODE;               /* set mapped mode */
                } else {
                    CPUSTATUS &= ~BIT8;             /* reset bit 8 of cpu status */
                    MODES &= ~MAPMODE;              /* reset mapped mode */
                }

                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                sim_debug(DEBUG_IRQ, my_dev,
                    "<|>Int %02x OPSD %08x %08x NPSD %08x %08x\n",
                    il, RMW(int_icb), RMW(int_icb+4), PSD1, PSD2);
#ifndef DUMP_REGS
                for (ix=0; ix<8; ix+=2) {
                    sim_debug(DEBUG_IRQ, my_dev,
                        "<|> GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]);
                }
#endif
                bc = RMW(int_icb+20) & 0xffffff;
                t = SPAD[il+0x80];                  /* get spad entry for interrupt */
                if (t & 0x00800000) {               /* is this a non I/O interrupt */
                    // non-I/O interrupt
                    sim_debug(DEBUG_IRQ, my_dev,
                        "<|>Int2 %02x ICBA %06x IOCLA %06x STAT %06x\n",
                        il, int_icb, RMW(int_icb+16), RMW(int_icb+20));
                } else {
                    // I/O interrupt ICB
                    sim_debug(DEBUG_IRQ, my_dev,
                        "<|>Int3 %02x ICBA %06x IOCLA %06x STAT %08x SW1 %08x SW2 %08x\n",
                        il, int_icb, RMW(int_icb+16), RMW(int_icb+20), RMW(bc), RMW(bc+4));
                }
                if (wait4int)
                    sim_debug(DEBUG_IRQ, my_dev,
                    "End %s WAIT OPSD %.8x %.8x NPSD %.8x %.8x OSTAT %08x NSTAT %08x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                    RMW(int_icb), RMW(int_icb+4), PSD1, PSD2, oldstatus, CPUSTATUS);

                wait4int = 0;                       /* wait is over for int */
                goto skipi;                         /* skip int test */
            }
        }

        /* see if in wait instruction */
        if (wait4int) {                             /* keep waiting */
            /* tell simh we will be waiting */
            sim_idle(TMR_RTC, 0);                   /* wait for clock tick */
            PC = OPSD1 & 0xfffffe;                  /* get 24 bit addr from PSD1 */
            goto wait_loop;                         /* continue waiting */
        }

        /* Check for external interrupt here */
        /* see if we have an attention request from console */
        if (!skipinstr && attention_trap) {
            TRAPME = attention_trap;                /* get trap number */
            attention_trap = 0;                     /* clear flag */
            sim_debug(DEBUG_TRAP, my_dev, "Attention TRAP %04x\n", TRAPME);
            goto newpsd;                            /* go process trap */
        }

skipi:
        i_flags = 0;                                /* do not update pc if MF or NPM */
        TRAPSTATUS = CPUSTATUS & 0x57;              /* clear all trap status except cpu type */
        PC = PSD1 & 0xfffffe;                       /* get 24 bit addr from PSD1 */
        //FIXME added change 112922
        OPSD1 = PSD1;                               /* save the old PSD1 */
        OPSD2 = PSD2;                               /* save the old PSD2 */

        /* fill IR from logical memory address */
        if ((TRAPME = read_instruction(PSD, &IR))) {
            sim_debug(DEBUG_TRAP, my_dev,
                "read_instr TRAPME %02x PSD %08x %08x i_flags %04x\n",
                TRAPME, PSD1, PSD2, i_flags);
            if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) ||
                (CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) {
                if ((TRAPME == MAPFLT) || (TRAPME == NPMEM)) {
                    i_flags |= HLF;                 /* assume half word instr */
                    PSD1 &= ~BIT31;                 /* force off last right */
                    // fix for 32/67 test 32/3 in MMM diag
                    if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_67))
                        i_flags |= BT;              /* do not update pc if MF or NPM */
                    else
                        i_flags &= ~BT;             /* update pc */
                }
            } else {
                if ((TRAPME == PRIVVIOL_TRAP) && (CPU_MODEL == MODEL_V9)) {
                    i_flags |= HLF;                 /* assume half word instr */
                    i_flags &= ~BT;                 /* no branch taken */
                    PSD1 &= ~BIT31;                 /* force off last right */
                }
            }
            sim_debug(DEBUG_TRAP, my_dev,
                "read_instr2 TRAPME %02x PSD %08x %08x i_flags %04x\n",
                TRAPME, PSD1, PSD2, i_flags);
            goto newpsd;                            /* go process trap */
        }

        if (PSD1 & 2) {                             /* see if executing right half */
            /* we have a rt hw instruction */
            IR <<= 16;                              /* put instruction in left hw */
            if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) ||
                    (CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                goto exec;                          /* machine does not drop nop instructions */
            }
            /* We have 67 or V6 and have a rt hw instruction */
            if (IR == 0x00020000) {                 /* is this a NOP from rt hw? */
                PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);    /* skip this instruction */
                if (skipinstr)
                    sim_debug(DEBUG_IRQ, my_dev,
                        "2Rt HW instruction skipinstr %1x is set PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
                        skipinstr, PSD1, PSD2, CPUSTATUS);
                goto skipi;                         /* go read next instruction */
            }
            if (skipinstr)
                sim_debug(DEBUG_IRQ, my_dev,
                "3Rt HW instruction skipinstr %1x is set PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
                skipinstr, PSD1, PSD2, CPUSTATUS);
        } else {
            /* we have a left hw or fullword instruction */
            /* see if we can drop a rt hw nop instruction */
            OP = (IR >> 24) & 0xFC;                 /* this is a 32/67 or above, get OP */
            if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) ||
                    (CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                goto exec;                          /* old machines did not drop nop instructions */
            if (PSD1 & BASEBIT)
                i_flags = base_mode[OP>>2];         /* set the BM instruction processing flags */
            else
                i_flags = nobase_mode[OP>>2];       /* set the NBM instruction processing flags */
            if (i_flags & HLF) {                    /* this is left HW instruction */
                if ((IR & 0xffff) == 0x0002) {      /* see if rt hw is a nop */
                    /* treat this as a fw instruction */
                    drop_nop = 1;                   /* we need to skip nop next time */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "CPU setting Drop NOP OPSD1 %08x PSD1 %08x PC %08x IR %08x\n", OPSD1, PSD1, PC, IR);
                    goto exec2;
                }
            }
        }

exec:   /* we re-enter here for EXR, EXRR, or EXM op */
        OP = (IR >> 24) & 0xFC;                     /* get OP */
        if (PSD1 & BASEBIT)
            i_flags = base_mode[OP>>2];             /* set the BM instruction processing flags */
        else
            i_flags = nobase_mode[OP>>2];           /* set the NBM instruction processing flags */
exec2:
        /* temp saves for debugging */
        OIR = IR;                                   /* save the instruction */
        OPSD1 = PSD1;                               /* save the old PSD1 */
        OPSD2 = PSD2;                               /* save the old PSD2 */
        TRAPSTATUS = CPUSTATUS & 0x57;              /* clear all trap status except cpu type */

        /* Split instruction into pieces */
        PC = PSD1 & 0xfffffe;                       /* get 24 bit addr from PSD1 */
        sim_debug(DEBUG_DETAIL, my_dev,
            "-----Instr @ PC %08x PSD1 %08x PSD2 %08x IR %08x drop_nop %x\n",
            PC, PSD1, PSD2, IR, drop_nop);

        OPR = (IR >> 16) & MASK16;                  /* use upper half of instruction */
        OP = (OPR >> 8) & 0xFC;                     /* Get opcode (bits 0-5) left justified */
        FC =  ((IR & F_BIT) ? 0x4 : 0) | (IR & 3);  /* get F & C bits for addressing */
        reg = (OPR >> 7) & 0x7;                     /* dest reg or xr on base mode */
        sreg = (OPR >> 4) & 0x7;                    /* src reg for reg-reg instructions or BR instr */
        dbl = 0;                                    /* no doubleword instruction */
        ovr = 0;                                    /* no overflow or arithmetic exception either */
        dest = (t_uint64)IR;                        /* assume memory address specified */
        CC = PSD1 & 0x78000000;                     /* save CC's if any */
        MODES = PSD1 & 0x87000000;                  /* insert bits 0, 5, 6, 7 from PSD 1 */
        CPUSTATUS &= ~0x87000000;                   /* reset those bits in CPUSTATUS */
        CPUSTATUS |= (MODES & 0x87000000);          /* now insert into CPUSTATUS */
        if (PSD2 & MAPBIT) {
            CPUSTATUS |= BIT8;                      /* set bit 8 of cpu status to mapped */
            MODES |= MAPMODE;                       /* set mapped mode */
        } else {
            CPUSTATUS &= ~BIT8;                     /* reset bit 8 of cpu status */
            MODES &= ~MAPMODE;                      /* reset mapped mode */
        }

        /* Update history for this instruction */
        if (hst_lnt) {
            hst_p += 1;                             /* next history location */
            if (hst_p >= hst_lnt)                   /* check for wrap */
                hst_p = 0;                          /* start over at beginning */
            hst[hst_p].opsd1 = OPSD1;               /* set original psd1 */ 
            hst[hst_p].opsd2 = OPSD2;               /* set original psd2 */ 
            hst[hst_p].oir = OIR;                   /* set original instruction */ 
            hst[hst_p].modes = MODES;               /* save current mode bits */
            hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */
            if (CPUSTATUS & BIT24)
                hst[hst_p].modes |= INTBLKD;        /* save blocking mode bit */
            if (CPUSTATUS & BIT27)
                hst[hst_p].modes |= IPUMODE;        /* save cpu/ipu status bit */
        }

        if (MODES & BASEBIT) {
            addr = IR & RMASK;                      /* get address offset from instruction */
            sim_debug(DEBUG_DETAIL, my_dev,
                "Base OP %04x i_flags %04x addr %08x\n", OP, i_flags, addr);
            switch(i_flags & 0xf) {
            case HLF:
                source = GPR[sreg];                 /* get the src reg from instruction */
                break;
            case IMM:
                if (PC & 02) {                      /* if pc is on HW boundry, bad address */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC1 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                break;
            case ADR:
                ix = (IR >> 20) & 7;                /* get index reg from instruction */
                if (ix != 0)
                    addr += (GPR[ix] & MASK24);     /* if not zero, add in reg contents */
            case WRD:
                if (PC & 02) {                      /* if pc is on HW boundry, bad address */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC2 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                ix = (IR >> 16) & 7;                /* get base reg from instruction */
                if (ix != 0)     
                    addr += (BR[ix] & MASK24);      /* if not zero, add to base reg contents */
                FC = ((IR & F_BIT) ? 4 : 0);        /* get F bit from original instruction */
                FC |= addr & 3;                     /* set new C bits to address from orig or regs */
                addr &= MASK24;                     /* make pure 24 bit addr */
                break;
            case INV:
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
                break;
             }
        } else {
            addr = IR & 0x7ffff;                    /* get 19 bit address from instruction */
            if (PC >= 0x80000) {
                TRAPME = MAPFAULT_TRAP;             /* Map Fault Trap */
                // DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails
                if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) || 
                    (CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) {
                    // DIAG fix for 32/87 test 33/2, clear psd bit 31
                    if ((CPU_MODEL == MODEL_87))
                        PSD1 &= ~BIT31;             /* force off last right */
                    // DIAG fix 32/27 32/67 for diag MMM test 33/2
                    if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67))
                        i_flags |= BT;              /* do not update pc if MAPFAULT on 27 */
                    else
                        i_flags &= ~BT;             /* do not update pc if MF or NPM */
                    i_flags |= HLF;                 /* assume half word instr */
                }
                if ((CPU_MODEL <= MODEL_27)) {
                    /* 77, 27 rolls to zero, not 80000 */
                    PSD1 &= 0xff07ffff;             /* remove overflow bits */
                } else {
                    PSD1 &= 0xff0fffff;             /* leave overflow bit for trap addr */
                }
                sim_debug(DEBUG_TRAP, my_dev,
            "PC over 80000 PC %08x Base OP %02x i_flags %04x addr %06x PSD %08x %08x\n",
                    PC, OP, i_flags, addr, PSD1, PSD2);
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                else
                    TRAPSTATUS |= BIT19;            /* set bit 19 of trap status */
                goto newpsd;                        /* handle trap */
            }
            sim_debug(DEBUG_DETAIL, my_dev,
                "Non Based i_flags %04x addr %08x\n", i_flags, addr);
            /* non base mode instructions have bit 0 of the instruction set */
            /* for word length instructions and zero for halfword instructions */
            /* the LA (op=0x34) is the only exception.  So test for PC on a halfword */
            /* address and trap if word opcode is in right hw */
            /* if pc is on HW boundry, addr trap if bit zero set */
            if (PC & 02) {
                if ((OP == 0x34) || (OP & 0x80)) {
                    i_flags |= HLF;                 /* diags treats these as hw instructions */
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    goto newpsd;                    /* go execute the trap now */
                }
            }
            switch(i_flags & 0xf) {
            case HLF:                               /* halfword instruction */
                source = GPR[sreg];                 /* get the src reg contents */
                break;

            case IMM:       /* Immediate mode */
                if (PC & 02) {                      /* if pc is on HW boundry, bad address */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC3 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                break;

            case ADR:       /* Normal addressing mode */
                ix = (IR >> 21) & 3;                /* get the index reg if specified */
                if (ix != 0) {
                    addr += GPR[ix];                /* if not zero, add in reg contents */
                    FC = ((IR & F_BIT) ? 4 : 0);    /* get F bit from original instruction */
                    FC |= addr & 3;                 /* set new C bits to address from orig or regs */
                }

                /* wart alert! */
                /* the lea instruction requires special handling for indirection. */
                /* Bits 0,1 are set to 1 in result addr if indirect bit is zero in */
                /* instruction.  Bits 0 & 1 are set to the last word */
                /* or instruction in the chain bits 0 & 1 if indirect bit set */
                  /* if IX == 00 => dest = IR */
                  /* if IX == 0x => dest = IR + reg */
                  /* if IX == Ix => dest = ind + reg */

                /* fall through */
            case WRD:       /* Word addressing, no index */
                bc = 0xC0000000;                    /* set bits 0, 1 for instruction if not indirect */
                t = IR;                             /* get current IR */
                addr &= MASK24;                     /* make pure 24 bit addr */
                while ((t & IND) != 0) {            /* process indirection */
                    if ((TRAPME = Mem_read(addr, &temp))) {   /* get the word from memory */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "case WRD Mem_read status %02x @ %08x OP %04x\n", TRAPME, addr, OP);
                        if (CPU_MODEL == MODEL_V9)  /* V9 wants bit0 set in pfault */
                            if (TRAPME == DMDPG)    /* demand page request */
                                pfault |= 0x80000000;   /* set instruction fetch paging error */
                        goto newpsd;                /* memory read error or map fault */
                    }
                    bc = temp & 0xC0000000;         /* save new bits 0, 1 from indirect location */
                    CC = (temp & 0x78000000);       /* save CC's from the last indirect word */
                    /* process new X, I, ADDR fields */
                    addr = temp & MASK19;           /* get just the addr */
                    ix = (temp >> 21) & 3;          /* get the index reg from indirect word */
                    if (ix != 0)
                        addr += (GPR[ix] & MASK19); /* add the register to the address */
                    /* if no F or C bits set, use original, else new */
                    if ((temp & F_BIT) || (addr & 3)) 
                        FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3);
                    else {
                        addr |= (IR & F_BIT);       /* copy F bit from instruction */
                        addr |= (FC & 3);           /* copy in last C bits */
                    }
                    t = temp;                       /* go process next indirect location */
                    temp &= MASK19;                 /* go process next indirect location */
                    addr &= ~F_BIT;                 /* turn off F bit */
                }
                dest = (t_uint64)addr;              /* make into 64 bit variable */
                break;

            case INV:       /* Invalid instruction */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
                break;
            }
        }

        /* Read memory operand */
        if (i_flags & RM) { 
            if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "case RM Mem_read status %02x @ %08x\n", TRAPME, addr);
                // DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails
                if ((TRAPME == MAPFLT) || (TRAPME == NPMEM) || (TRAPME == MPVIOL))
                    PSD1 &= ~BIT31;                 /* force off last right */
                goto newpsd;                        /* memory read error or map fault */
            }
            source = (t_uint64)temp;                /* make into 64 bit value */
            switch(FC) {
            case 0:                                 /* word address, extend sign */
                source |= (source & MSIGN) ? D32LMASK : 0;
                break;
            case 1:                                 /* left hw */
                source >>= 16;                      /* move left hw to right hw*/
                /* Fall through */
            case 3:                                 /* right hw or right shifted left hw */
                source &= RMASK;                    /* use just the right hw */
                if (source & 0x8000) {              /* check sign of 16 bit value */
                    /* sign extend the value to leftmost 48 bits */
                    source = LMASK | (source & RMASK);  /* extend low 32 bits */
                    source |= (D32LMASK);           /* extend hi bits */
                }
                break;
            case 2:                                 /* double word address */
                if ((addr & 7) != 2) {              /* must be double word adddress */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC4 case RM wd 1/3 Mem_read DW status %02x @ %08x src %08x\n",
                        TRAPME, addr, (uint32)source);
                    goto newpsd;                    /* go execute the trap now */
                }
                if ((TRAPME = Mem_read(addr+4, &temp))) {   /* get the 2nd word from memory */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "case RM wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4);
                    goto newpsd;                    /* memory read error or map fault */
                }
                source = (source << 32) | (t_uint64)temp;   /* merge in the low order 32 bits */
                dbl = 1;                            /* double word instruction */
                break;
            case 4:                                 /* byte mode, byte 0 */
            case 5:                                 /* byte mode, byte 1 */
            case 6:                                 /* byte mode, byte 2 */
            case 7:                                 /* byte mode, byte 3 */
                source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */
                break;
           }
        }

        /* Read memory operand without doing sign extend for EOMX/ANMX/ORMX/ARMX */
        if (i_flags & RNX) { 
            if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
                sim_debug(DEBUG_TRAP, my_dev,
                    "case RNX 2 Mem_read status %02x @ %08x\n", TRAPME, addr);
                goto newpsd;                        /* memory read error or map fault */
            }
            source = (t_uint64)temp;                /* make into 64 bit value */
            switch(FC) {
            case 0:                                 /* word address and no sign extend */
                source &= D32RMASK;                 /* just l/o 32 bits */
                break;
            case 1:                                 /* left hw */
                source >>= 16;                      /* move left hw to right hw*/
                /* Fall through */
            case 3:                                 /* right hw or right shifted left hw */
                source &= RMASK;                    /* use just the right hw */
                break;
            case 2:                                 /* double word address */
                if ((addr & 7) != 2) {              /* must be double word adddress */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC5 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                if ((TRAPME = Mem_read(addr+4, &temp))) {   /* get the 2nd word from memory */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "case RNX wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4);
                    goto newpsd;                    /* memory read error or map fault */
                }
                source = (source << 32) | (t_uint64)temp;   /* merge in the low order 32 bits */
                dbl = 1;                            /* double word instruction */
                break;
            case 4:                                 /* byte mode, byte 0 */
            case 5:                                 /* byte mode, byte 1 */
            case 6:                                 /* byte mode, byte 2 */
            case 7:                                 /* byte mode, byte 3 */
                source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */
                break;
           }
        }

        /* Read in if from register */
        if (i_flags & RR) {
            if (FC == 2 && (i_flags & HLF) == 0)    /* double dest? */
                dbl = 1;                            /* src must be dbl for dbl dest */
            dest = (t_uint64)GPR[reg];              /* get the register content */
            if (dbl) {                              /* is it double regs */
                if (reg & 1) {                      /* check for odd reg load */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC6 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                /* merge the regs into the 64bit value */
                dest = (((t_uint64)dest) << 32) | ((t_uint64)GPR[reg+1]);
            } else {
                /* sign extend the data value */
                dest |= (dest & MSIGN) ? D32LMASK : 0;
            }
        }

        /* For Base mode */
        if (i_flags & RB) {
            dest = (t_uint64)BR[reg];               /* get base reg contents */
        }

        /* For register instructions */
        if (i_flags & R1) {
            source = (t_uint64)GPR[sreg];
            if (dbl) {
                if (sreg & 1) {
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC7 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                /* merge the regs into the 64bit value */
                source = (source << 32) | ((t_uint64)GPR[reg+1]);
            } else {
                /* sign extend the data value */
                source |= (source & MSIGN) ? ((t_uint64)MASK32) << 32: 0;
            }
        }

        /* process instruction op code */
        sim_debug(DEBUG_DETAIL, my_dev,
            "PSD %08x %08x SW OP %04x IR %08x addr %08x\n",
            PSD1, PSD2, OP, IR, addr);

        /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
        /* start processing the opcodes */
        /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
        switch (OP>>2) {
        /*
         * For op-codes=00,04,08,0c,10,14,28,2c,38,3c,40,44,60,64,68
         */
        /* Reg - Reg instruction Format (16 bit) */
        /* |--------------------------------------| */
        /* |0 1 2 3 4 5|6 7 8 |9 10 11|12 13 14 15| */
        /* | Op Code   | DReg | SReg  | Aug Code  | */
        /* |--------------------------------------| */
        case 0x00>>2:       /* HLF - HLF */         /* CPU General operations */
            switch(OPR & 0xF) {                     /* switch on aug code */
            case 0x0:   /* HALT */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged to halt */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* Privlege violation trap */
                }
                if (CPUSTATUS & BIT23) {            /* Priv mode halt must be enabled */
                    TRAPME = PRIVHALT_TRAP;         /* set the trap to take */
                    goto newpsd;                    /* Privlege mode halt trap */
                }

#ifndef CPUONLY
                /* if on the IPU simulate a wait instead */
                if (CPUSTATUS & ONIPU) {
                    /* wait for any trap, knowing there will be no interrupts */
                    if (wait4sipu == 0) {
                        sim_debug(DEBUG_DETAIL, my_dev,
                            "Starting %s HALT PSD %.8x %.8x TRAPME %02x CPUSTATUS %08x\n",
                            (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                            PSD1, PSD2, TRAPME, CPUSTATUS);
                    }
                    else {
#ifdef USE_POSIX_SEM
                        sim_os_ms_sleep(10);        /* wait 10 ms */
                        goto wait_loop;             /* continue waiting */
#else
                        wait4sipu = 1;              /* show we are waiting for SIPU */
                        goto cond_go;               /* start waiting for sipu */
#endif
                    }
                    wait4sipu = 1;                  /* show we are waiting for SIPU */
                    i_flags |= BT;                  /* keep PC from being incremented while waiting */
                    break;                          /* keep going */
                }
#endif
                /* we need to do an actual halt here if on CPU */
                sim_debug(DEBUG_EXP, my_dev,
                    "\n[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\n");
                sim_debug(DEBUG_EXP, my_dev,
                    "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                    PSD1, PSD2, TRAPME, CPUSTATUS);
                for (ix=0; ix<8; ix+=2) {
                    sim_debug(DEBUG_EXP, my_dev,
                        "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]);
                }
                sim_debug(DEBUG_EXP, my_dev,
                    "[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\n");

                fprintf(stdout, "\r\n[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\r\n");
                fprintf(stdout, "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x\r\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                    PSD1, PSD2, TRAPME, CPUSTATUS);
                for (ix=0; ix<8; ix+=2) {
                    fprintf(stdout, "GPR[%d] %.8x GPR[%d] %.8x\r\n",
                        ix, GPR[ix], ix+1, GPR[ix+1]);
                }
                if (MODES & BASEBIT) {              /* see if based */
                    for (ix=0; ix<8; ix+=2) {
                        fprintf(stdout, " BR[%d] %.8x  BR[%d] %.8x\r\n",
                           ix, BR[ix], ix+1, BR[ix+1]);
                }
            }
            fprintf(stdout, "[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\r\n");
#ifdef CPUDEBUG
            DumpHist();
#endif
#ifndef CPUONLY
#ifndef USE_IPU_THREAD
            if ((IPU_MODEL) && (IPC->pid[1] != 0)) {
                /* If we have an forked IPU model, and we are on the CPU: destroy the IPU */
                kill(IPC->pid[1], SIGKILL);         /* destroy the IPU */
            }
#endif
#endif
            reason = STOP_HALT;                     /* do halt for now */
#ifdef USE_IPU_THREAD
            cpustop = STOP_HALT;                    /* tell the IPU */
#endif
            fflush(sim_deb);
            return STOP_HALT;                       /* exit to simh for halt */
            break;

            case 0x1:   /* WAIT */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged to wait */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* Privlege violation trap */
                }
                /* if interrupts are blocked, system check trap */
                if (CPUSTATUS & BIT24) {            /* status word bit 24 says blocked */
                    TRAPME = SYSTEMCHK_TRAP;        /* trap condition if F class */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT12;        /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT20;        /* set bit 20 of trap status */
                    goto newpsd;                    /* System check trap */
                }
                PC = OPSD1 & 0xfffffe;              /* get 24 bit addr from PSD1 */
#ifndef CPUONLY
                if (IPU_MODEL && (CPUSTATUS & ONIPU)) {
                    /* Hack around it when on IPU side: wait by expensive method */
                    /* wait for any trap, knowing there will be no interrupts */
                    if (wait4sipu == 0) {
                        sim_debug(DEBUG_DETAIL, my_dev,
                            "Starting %s WAIT1 PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x\n",
                            (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                            PSD1, PSD2, TRAPME, CPUSTATUS);
                    }
                    else {
#ifdef USE_POSIX_SEM
                        sim_os_ms_sleep(10);        /* wait 10 ms */
                        goto wait_loop;             /* continue waiting */
#else
                        wait4sipu = 1;              /* show we are waiting for SIPU */
                        goto cond_go;               /* start waiting for sipu */
#endif /* USE_POSIX_SEM */
                    }
                    wait4sipu = 1;                  /* show we are waiting for SIPU */
                    i_flags |= BT;                  /* keep PC from being incremented while waiting */
                } else
#endif /* CPU_ONLY */
                {
                    if (wait4int == 0) {
                        sim_debug(DEBUG_DETAIL, my_dev,
                            "Starting %s WAIT2 PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x\n",
                            (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                            PSD1, PSD2, TRAPME, CPUSTATUS);
                    }
                    /* tell simh we will be waiting */
                    wait4int = 1;                   /* show we are waiting for interrupt */
                    i_flags |= BT;                  /* keep PC from being incremented while waiting */
                }
                break;
            case 0x2:   /* NOP */
                break;
            case 0x3:   /* LCS */
                /* get console switches from memory loc 0x780 */
                if ((TRAPME = Mem_read(0x780, &GPR[reg]))) /* get the word from memory */
                    goto newpsd;                    /* memory read error or map fault */
                set_CCs(GPR[reg], 0);               /* set the CC's, CC1 = 0 */
                break;
            case 0x4:   /* ES */
                if (reg & 1) {                      /* see if odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC7a OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                /* reg is reg to extend sign into from reg+1 */
                GPR[reg] = (GPR[reg+1] & FSIGN) ? FMASK : 0;
                set_CCs(GPR[reg], 0);               /* set CCs, CC2 & CC3 */
                break;
            case 0x5:   /* RND */
                if (reg & 1) {                      /* see if odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC7b OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                temp = GPR[reg];                    /* save the current contents of specified reg */
                t = (temp & FSIGN) != 0;            /* set flag for sign bit not set in temp value */
                bc = 1;
                t |= ((bc & FSIGN) != 0) ? 2 : 0;   /* ditto for the bit value */
                if (GPR[reg+1] & FSIGN) {           /* if sign of R+1 is set, incr R by 1 */
                    temp += bc;                     /* add the bit value to the reg */
                    /* if both signs are neg and result sign is positive, overflow */
                    /* if both signs are pos and result sign is negative, overflow */
                    if ((t == 3 && (temp & FSIGN) == 0) ||
                        (t == 0 && (temp & FSIGN) != 0)) {
                        ovr = 1;                    /* we have an overflow */
                    }
                    GPR[reg] = temp;                /* update the R value */
                } else
                    ovr = 0;
                set_CCs(temp, ovr);                 /* set the CC's, CC1 = ovr */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (ovr && (MODES & AEXPBIT)) {
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
                    goto newpsd;                    /* handle trap */
                }
                break;
            case 0x6:   /* BEI */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged to BEI */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* Privlege violation trap */
                }
                if (IPU_MODEL && (CPUSTATUS & ONIPU)) {
                    /* on IPU :  */
                    TRAPME = IPUUNDEFI_TRAP;
                    sim_debug(DEBUG_TRAP, my_dev,
                        "IPU BEI PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n",
                        PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                    goto newpsd;
                }
                PSD2 &= ~(SETBBIT|RETBBIT);         /* clear bit 48 & 49 */
                MODES &= ~(BLKMODE|RETBLKM);        /* reset blocked & retain mode bits */
                PSD2 |= SETBBIT;                    /* set to blocked state */
                CPUSTATUS |= BIT24;                 /* into status word bit 24 too */
                MODES |= BLKMODE;                   /* set blocked mode */

                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;

            case 0x7:   /* UEI */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged to UEI */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* Privlege violation trap */
                }
                if (CPUSTATUS & BIT24) {            /* see if old mode is blocked */
                    if (!(CPUSTATUS & ONIPU))
                        irq_pend = 1;               /* start scanning interrupts again */
                }
                CPUSTATUS &= ~BIT24;                /* clear status word bit 24 */
                MODES &= ~(BLKMODE|RETBLKM);        /* reset blocked & retain mode bits */
                PSD2 &= ~(SETBBIT|RETBBIT);         /* clear bits 48 & 49 to be unblocked */
                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;
            case 0x8:   /* EAE */
                PSD1 |= AEXPBIT;                    /* set the enable AEXP flag in PSD 1 */
                MODES |= AEXPBIT;                   /* enable arithmetic exception in modes & PSD 1 */
                CPUSTATUS |= AEXPBIT;               /* into status word too */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;
            case 0x9:   /* RDSTS */
                GPR[reg] = CPUSTATUS;               /* get CPU status word */
                sim_debug(DEBUG_EXP, my_dev, "RDSTS CCW %08x CPUSTATUS %8x\n", CCW, CPUSTATUS);
                break;
            case 0xA:   /* SIPU */                  /* ignore for now */
                /* if we have an IPU, process SIPU instruction */
                sim_debug(DEBUG_TRAP, my_dev,
                    "SIPU @%s CPUSTATUS %08x SPAD[0xf9] %08x CCW %0x PSD %08x %08x\n",
                    (CPUSTATUS & ONIPU)? "IPU": "CPU",
                    CPUSTATUS, SPAD[0xf9], CCW, PSD1, PSD2);

#ifndef CPUONLY
                if (CCW & HASIPU) {
                    /* CPU side = [0] IPU side = [1] */
                    //GR if (IPC && IPC->atrap[PeerIndex]) {
#ifdef USE_POSIX_SEM
                    if (IPC->atrap[PeerIndex]) {
                        /* previous atrap not yet handled */
                        IPC->blocked[MyIndex]++;
                        sim_debug(DEBUG_TRAP, my_dev,
                            "%s: Async SIPU blocked CPUSTATUS %08x CCW %08x\n",
                            (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW);

                        //GR  Give it a millisec to unblock the atrap
                        sim_os_ms_sleep(10);        /* wait 10 ms */
                    }

                    if (IPC->atrap[PeerIndex] == 0) {
                        IPC->sent[MyIndex]++;
                        IPC->atrap[PeerIndex] = SIGNALIPU_TRAP;
                        sim_debug(DEBUG_TRAP, my_dev,
                            "%s: Async SIPU sent CPUSTATUS %08x CCW %02x\n",
                            (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW);
                    }
                    else
                        IPC->dropped[MyIndex]++;
#else
                    if (IPC->atrap[PeerIndex]) {
                        /* previous atrap not yet handled if not zero */
                        IPC->blocked[MyIndex]++;    /* count as blocked */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "%s: Async SIPU blocked IPUSTATUS %08x CCW %08x SPAD[0xf0] %02x block %08x\n",
                            (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW, SPAD[0xf0], IPC->blocked[MyIndex]);
                        //GR  Give it a millisec to unblock the atrap
                        sim_os_ms_sleep(10);        /* wait 10 ms */
                    }
                    if (IPC->atrap[PeerIndex] == 0) {
                        lock_mutex();               /* lock mutex */
                        IPC->atrap[PeerIndex] = SIGNALIPU_TRAP;
                        pthread_cond_signal(&IPC->cond);    /* wake any waiters */
                        unlock_mutex();             /* unlock mutex */
                        IPC->sent[MyIndex]++;
                        sim_debug(DEBUG_TRAP, my_dev,
                            "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %02x sent %08x\n",
                            (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW, SPAD[0xf0], IPC->sent[MyIndex]);
                    } else {
                        IPC->dropped[MyIndex]++;    /* count dropped SIPU */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %02x drop %08x\n",
                            (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW, SPAD[0xf0], IPC->dropped[MyIndex]);
                    }
#endif /* USE_POSIX_SEM */
                } else
#endif
                {
                    sim_debug(DEBUG_TRAP, my_dev,
                    "SIPU CPUSTATUS %08x CCW %08x\n", CPUSTATUS, CCW);
                }
                break;
            case 0xB:   /* RWCS */                  /* RWCS ignore for now */
                /* reg = specifies reg containing the ACS/WCS address */
                /* sreg = specifies the ACS/WCS address */
                /* if the WCS option is not present, address spec error */
                /* if the mem addr is not a DW, address spec error */
                /* If 0<-Rs<=fff and Rs bit 0=0, then PROM address */
                /* If 0<-Rs<=fff and Rs bit 0=1, then ACS address */
                /* if bit 20 set, WCS enables, else addr spec error */
                if ((CPUSTATUS & 0x00000800) == 0) {
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC7c OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                /* Maybe TODO copy something from WCS */
                break;
            case 0xC:   /* WWCS */                  /* WWCS ignore for now */
                /* reg = specifies the logical address in memory that */
                /* is to receive the ACS/WCS contents */
                /* sreg = specifies the ACS/WCS address */
                /* bit 20 of cpu stat must be set=1 to to write to ACS or WCS */
                /* bit 21 of CPU stat must be 0 to write to ACS */
                /* if bit 20 set, WCS enables, else addr spec error */
                if ((CPUSTATUS & 0x00000800) == 0) {
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC7d OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                /* Maybe TODO copy something to WCS */
                break;
            case 0xD:   /* SEA */
                if (MODES & BASEBIT)                /* see if based */
                    goto inv;                       /* invalid instruction in based mode */
                sim_debug(DEBUG_IRQ, my_dev,
                    "SEA for extended mode PSD %08x %08x STATUS %08x\r\n",
                    PSD1, PSD2, CPUSTATUS);
                MODES |= EXTDBIT;                   /* set new extended flag (bit 5) in modes & PSD */
                PSD1 |= EXTDBIT;                    /* set the enable AEXP flag in PSD1 */
                CPUSTATUS |= EXTDBIT;               /* into status word too */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;
            case 0xE:   /* DAE */
                MODES &= ~AEXPBIT;                  /* disable arithmetic exception in modes & PSD */
                PSD1 &= ~AEXPBIT;                   /* disable AEXP flag in PSD */
                CPUSTATUS &= ~AEXPBIT;              /* into status word too */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;

            case 0xF:   /* CEA */
                if (MODES & BASEBIT)                /* see if based */
                    goto inv;                       /* invalid instruction in based mode */
                MODES &= ~EXTDBIT;                  /* disable extended mode in modes and PSD */
                PSD1 &= ~EXTDBIT;                   /* disable extended mode (bit 5) flag in PSD */
                CPUSTATUS &= ~EXTDBIT;              /* into status word too */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;
            }
            break;
        case 0x04>>2:       /* 0x04 RR|R1|SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */
            i_flags &=  ~SCC;                       /* make sure we do not set CC's for dest value */
            switch(OPR & 0xF) {
            case 0x0:   /* ANR */
                dest &= source;                     /* just an and reg to reg */
                if (dest & MSIGN)
                    dest |= D32LMASK;               /* force upper word to all ones */
                i_flags |=  SCC;                    /* make sure we set CC's for dest value */
                break; 

            case 0xA:       /* CMC */               /* Cache Memory Control - Diag use only */
                if (CPU_MODEL == MODEL_87)
                    break;                          /* just ignore */
                if (CPU_MODEL < MODEL_67) {
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                if (CPU_MODEL <= MODEL_V6) {
                    /* Cache memory control bit assignments for reg */
                    /* 0-22 reserved, must be zero */
                    /* 23 - Initialize Instruction Cache Bank 0 On = 1 Off = 0 */
                    /* 24 - Initialize Instruction Cache Bank 1 On = 1 Off = 0 */
                    /* 25 - Initialize Operand Cache Bank 0 On = 1 Off = 0 */
                    /* 26 - Initialize Operand Cache Bank 1 On = 1 Off = 0 */
                    /* 27 - Enable Instruction Cache Bank 0 On = 1 Off = 0 */
                    /* 28 - Enable Instruction Cache Bank 1 On = 1 Off = 0 */
                    /* 29 - Enable Operand Cache Bank 0 On = 1 Off = 0 */
                    /* 30 - Enable Operand Cache Bank 1 On = 1 Off = 0 */
                    /* 31 - Bypass Instruction Cache Bank 1 On = 1 Off = 0 */
                    sim_debug(DEBUG_EXP, my_dev,
                        "CMC V6/67 GPR[%02x] = %04x CMCR = %08x CPU STATUS SPAD[f9] = %08x\r\n",
                        reg, GPR[reg], CMCR, SPAD[0xf9]);
                    CMCR = GPR[reg];                /* write reg bits 23-31 to cache memory controller */
                    i_flags &= ~SD;                 /* turn off store dest for this instruction */
                } else
                if (CPU_MODEL == MODEL_V9) {
                    sim_debug(DEBUG_EXP, my_dev,
                        "CMC V9 GPR[%02x] = %08x CMCR = %08x CPU STATUS SPAD[f9] = %08x\r\n",
                        reg, GPR[reg], CMCR, SPAD[0xf9]);
                    CMCR = GPR[reg];                /* write reg bits 23-31 to cache memory controller */
                    i_flags &= ~SD;                 /* turn off store dest for this instruction */
                }
                break;

            case 0x7:       /* SMC */               /* Shared Memory Control - Diag use only */
                if (CPU_MODEL < MODEL_67) {
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                /* Shared memory control bit assignments for reg */
                /*    0 - Reserved */
                /*    1 - Shared Memory Enabled (=1)/Disabled (=0) */
                /*  2-6 - Upper Bound of Shared Memory */
                /*    7 - Read & Lock Enabled (=1)/Disabled (=0) */
                /* 8-12 - Lower Bound of Shared Memory */
                /* 3-31 - Reserved and must be zero */
                sim_debug(DEBUG_CMD, my_dev,
                    "SMC V6/67 GPR[%02x] = %08x SMCR = %08x CPU STATUS SPAD[f9] = %08x\n",
                    reg, GPR[reg], SMCR, SPAD[0xf9]);
                SMCR = GPR[reg];                    /* write reg bits 0-12 to shared memory controller */
                i_flags &= ~SD;                     /* turn off store dest for this instruction */
                break;

/* 67, 97, V6 Computer Configuration Word is copied when bit zero of Rd set to one (0x80000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00|01|02 03 04 05 06|07|08 09 10 11 12|13 14 15|16|17|18|19|20 21|22|23 24 25 26|27|28|29|30|31| */
/* |  | S| Upper Bound  |RL| Lower Bound  |Reserved|4k|8k|SM|P2| Res |AP| Reserved  |I0|I1|D0|D1|BY| */
/* | 0| x| x  x  x  x  x| x| x  x  x  x  x| 0  0  0| x| x| x| x| 0  0| 0| 0  0  0  0| x| x| x| x| x| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits:    0   Reserved */
/*          1   Shared Memory Enabled (=1)/Disabled (=0) */
/*        2-6   Upper Bound of Shared Memory */
/*          7   Read & Lock Enabled (=1)/Disabled (=0) */
/*       8-12   Lower Bound of Shared Memory */
/*      13-15   Reserved */
/*         16   4K WCS Option Present (=1)/Not Present (=0) */
/*         17   8K WCS Option Present (=1)/Not Present (=0) */
/*         18   Firmware Control Store Mode ROMSIM (=1)/PROM (=0) */
/*         19   IPU Present (=1)/Not Present (=0) */
/*      20-21   Reserved */
/*         22   Access Protection ECO Present (=0)/No Access Protection (=0) V6 & V9 */
/*      23-26   Reserved */
/*         27   Instruction Cache Bank 0 on (=1)/Off (=0) */
/*         28   Instruction Cache Bank 1 on (=1)/Off (=0) */
/*         29   Data Cache Bank 0 on (=1)/Off (=0) */
/*         30   Data Cache Bank 1 on (=1)/Off (=0) */
/*         31   Instruction Cache Enabled (=1)/Disabled (=0) */
/* */
/* V9 Computer Configuration Word when bit zero of Rd set to one (0x80000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02 03|04 05 06 07|08 09 10 11|12 13 14 15|16|17|18|19|20|21|22|23|24 25 26 27|28 29 30 31| */
/* | CPU Bank1 | CPU Bank2 | IPU Bank0 | IPU Bank1 |M1|M2|C1|C2|P2|SM|AP|  | CPU FW Ver| CPU FW Rev| */
/* | x  x  x  x| x  x  x  x| x  x  x  x| x  x  x  x| x| x| x| x| x| x| x| x| x  x  x  x| x  x  x  x| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits: 0-15   Cache/Shadow Unit Present (=1)/Not Present (=0) */
/*         16   MACC Present in CP1 (=1)/Not Present (=0) */
/*         17   MACC Present in CP2 (=1)/Not Present (=0) */
/*         18   CP1 Present (=1)/CP1 Not Present (=0) */
/*         19   CP2 Present (=1)/CP2 Not Present (=0) */
/*         20   IPU Present (=1)/Not Present (=0) */
/*         21   Shared Memory Present (=1)/Not Present (=0) */
/*         22   Access Protection ECO Present (=0)/No Access Protection (=0) V6 & V9 */
/*         23   Reserved */
/*      24-27   CPU Firmware Version */
/*      28-31   CPU Formware Revision Level */
/* */
/* V9 CPU Shadow Memory Configuration Word when bit one of Rd set to one (0x40000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02|03 04 05 06 07|08 09 10 11 12 13 14 15|16 17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */
/* | SMU #  |   Not Used   | CPU Unit 1 Base Addr  | CPU Unit 2 Base Addr  | CPU Unit 3 Base Addr  | */
/* | x  x  x| 0  0  0  0  0| x  x  x  x  x  x  x  0| x  x  x  x  x  x  x  0| x  x  x  x  x  x  x  0| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits:    0   Shadow Memory Unit 1 Present (=1)/Not Present (=0) */
/*          1   Shadow Memory Unit 2 Present (=1)/Not Present (=0) */
/*          2   Shadow Memory Unit 3 Present (=1)/Not Present (=0) */
/*        3-7   Not Used */
/*       8-14   Shadow Memory Unit 1 Base Address (bits 08-14 of address) */
/*         15   Always zero */
/*      16-22   Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/*         23   Always zero */
/*      24-30   Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/*         31   Always zero */
/* */
/* V9 IPU Shadow Memory Configuration Word when bit two of Rd set to one (0x20000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02|03 04 05 06 07|08 09 10 11 12 13 14 15|16 17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */
/* | SMU #  |   Not Used   | IPU Unit 1 Base Addr  | IPU Unit 2 Base Addr  | IPU Unit 3 Base Addr  | */
/* | x  x  x| 0  0  0  0  0| x  x  x  x  x  x  x  0| x  x  x  x  x  x  x  0| x  x  x  x  x  x  x  0| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits:    0   Shadow Memory Unit 1 Present (=1)/Not Present (=0) */
/*          1   Shadow Memory Unit 2 Present (=1)/Not Present (=0) */
/*          2   Shadow Memory Unit 3 Present (=1)/Not Present (=0) */
/*        3-7   Not Used */
/*       8-14   Shadow Memory Unit 1 Base Address (bits 08-14 of address) */
/*         15   Always zero */
/*      16-22   Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/*         23   Always zero */
/*      24-30   Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/*         31   Always zero */
/* */
/* When bit zero of Rd is zero, PSW word 2 is copies to Rd (0x00000000) */
/* */
            case 0xB:   /* RPSWT */                 /* Read Processor Status Word 2 (PSD2) */
                if ((GPR[reg] & 0x80000000) && (CPU_MODEL < MODEL_V9)) {
                    /* if bit 0 of reg set, return (default 0) CPU Configuration Word */
                    dest = CCW;                     /* no cache or shared memory */
                    /* bit 22 set for access ECO present */
                    dest |= 0x00000200;             /* set ECO bit for DIAGS */
                    /* Try setting cache on bits 27-31 */
                    dest |= 0x0000001f;             /* set SIM bit for DIAGS */
                } else
                /* FIXME */
                if ((GPR[reg] & 0x80000000) && (CPU_MODEL == MODEL_V9)) {
                    /* if bit 0 of reg set, return Cache/Shadow Configuration Word */
                    CMSMC = 0xffff0000;             /* no CPU/IPU Cache/Shadow unit present */
                    CMSMC |= 0x00000000;            /* CPU Cache/Shadow unit present */
                    if (CCW & BIT27)
                        /* IPU is present, reset the status bit */
                        dest &= ~BIT20;             /* reset IPU status bit */
                    else
                        /* IPU is not present, set the status bit */
                        CMSMC |= BIT20;             /* set IPU status bit */
//                  CMSMC |= 0x00000800;            /* bit 20, IPU not present */
                    CMSMC |= 0x00000200;            /* bit 22, Access Protection ECO present */
                    CMSMC |= 0x0000001f;            /* CPU Firmware Version 1/Rev level 0 */
                    dest = CMSMC;                   /* return status */
                } else
                if ((GPR[reg] & 0x40000000) && (CPU_MODEL == MODEL_V9)) {
                    /* if bit 1 of reg set, return CPU Shadow Memory Configuration Word */
                    CSMCW = 0x00000000;             /* no Shadow unit present */
                    dest = CSMCW;                   /* return status */
                } else
                if ((GPR[reg] & 0x20000000) && (CPU_MODEL ==  MODEL_V9)) {
                    /* if bit 2 of reg set, return Cache Memory Configuration Word */
                    ISMCW = 0x00000000;             /* no Shadow unit present */
                    dest = ISMCW;                   /* return status */
                } else
                if ((GPR[reg] & BIT0) == 0x00000000) {
                    /* if bit 0 of reg not set, return PSD2 */
                    /* make sure bit 49 (block state is current state */
                    dest = SPAD[0xf5];              /* get PSD2 for user from SPAD 0xf5 */
                    dest &= ~(SETBBIT|RETBBIT);     /* clear bit 48 & 49 to be unblocked */
                    if (CPUSTATUS & BIT24) {        /* see if old mode is blocked */
                        dest |= SETBBIT;            /* set bit 49 for blocked */
                    }
                }
                break;

            case 0x08:      /* 0x0408 INV (Diag Illegal instruction) */
                /* HACK HACK HACK for DIAGS */
                if (CPU_MODEL <= MODEL_27) {        /* DIAG error for 32/27 only */
                    if ((PSD1 & 2) == 0)            /* if lf hw instruction */
                        i_flags |= HLF;             /* if nop in rt hw, bump pc a word */
                }
                /* drop through */
            default:        /* INV */               /* everything else is invalid instruction */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
                break;
            }
            break;

        case 0x08>>2:       /* 0x08 SCC|RR|R1|SD|HLF - */ /* ORR or ORRM */
            dest |= source;                         /* or the regs into dest reg */
            switch(OPR & 0x0f) {
            case 0x8:                               /* this is ORRM op */
                 dest &= GPR[4];                    /* mask with reg 4 contents */
                 /* drop thru */
            case 0x0:                               /* this is ORR op */
                if (dest & MSIGN)                   /* see if we need to sign extend */
                    dest |= D32LMASK;               /* force upper word to all ones */
                break;
            default:    /* INV */                   /* everything else is invalid instruction */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            break;

        case 0x0C>>2:       /* 0x0c SCC|RR|R1|SD|HLF - SCC|SD|HLF */ /* EOR or EORM */
            dest ^= source;                         /* exclusive or the regs into dest reg */
            switch(OPR & 0x0f) {
            case 0x8:                               /* this is EORM op */
                 dest &= GPR[4];                    /* mask with reg 4 contents */
                /* drop thru */
            case 0x0:                               /* this is EOR op */
                if (dest & MSIGN)                   /* see if we need to sign extend */
                    dest |= D32LMASK;               /* force upper word to all ones */
                break;
            default:    /* INV */                   /* everything else is invalid instruction */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            break;

        case 0x10>>2:       /* 0x10 HLF - HLF */    /* CAR or (basemode SACZ ) */
            if ((OPR & 0xF) == 0) {                 /* see if CAR instruction */
                /* handle non basemode/basemode CAR instr */
                if ((int32)GPR[reg] < (int32)GPR[sreg])
                    CC = CC3BIT;                    /* Rd < Rs; negative */
                else
                if (GPR[reg] == GPR[sreg])
                    CC = CC4BIT;                    /* Rd == Rs; zero */
                else
                    CC = CC2BIT;                    /* Rd > Rs; positive */
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
            } else {
                if ((MODES & BASEBIT) == 0) {       /* if not basemode, error */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    goto newpsd;                    /* handle trap */
                }
                /* handle basemode SACZ instruction */
sacz:           /* non basemode SCZ enters here */
                temp = GPR[reg];                    /* get destination reg contents to shift */
                CC = 0;                             /* zero the CC's */
                t = 0;                              /* start with zero shift count */
                if (temp == 0) {
                    CC = CC4BIT;                    /* set CC4 showing dest is zero & cnt is zero too */
                }
#ifdef NOT_FOR_DIAG
                /* The doc says the reg is not shifted if bit 0 is set on entry. */
                /* diags says it does, so that is what we will do */
                /* set count to zero, but shift reg 1 left */
                else
                if (temp & BIT0) {
                    CC = 0;                         /* clear CC4 & set count to zero */
                }
#endif
                else
                if (temp != 0) {                    /* shift non zero values */
                    while ((temp & FSIGN) == 0) {   /* shift the reg until bit 0 is set */
                        temp <<= 1;                 /* shift left 1 bit */
                        t++;                        /* increment shift count */
                    }
                    temp <<= 1;                     /* shift the sign bit out */
                }
                GPR[reg] = temp;                    /* save the shifted values */
                GPR[sreg] = t;                      /* set the shift cnt into the src reg */
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
            }
            break;

        case 0x14>>2:       /* 0x14 HLF - HLF */    /* CMR compare masked with reg */
            if (OPR & 0xf) {                        /* any subop not zero is error */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            temp = GPR[reg] ^ GPR[sreg];            /* exclusive or src and destination values */
            temp &= GPR[4];                         /* and with mask reg (GPR 4) */
            CC = 0;                                 /* set all CCs zero */
            if (temp == 0)                          /* if result is zero, set CC4 */
                CC = CC4BIT;                        /* set CC4 to show result 0 */
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's */
            PSD1 |= (CC & 0x78000000);              /* update the CC's in the PSD */
            break;

        case 0x18>>2:       /* 0x18 HLF - HLF */    /* SBR, (basemode ZBR, ABR, TBR */
            if (MODES & BASEBIT) {                  /* handle basemode ZBR, ABR, TBR */
                if ((OPR & 0xC) == 0x0)             /* SBR instruction */
                    goto sbr;                       /* use nonbase SBR code */
                if ((OPR & 0xC) == 0x4)             /* ZBR instruction */
                    goto zbr;                       /* use nonbase ZBR code */
                if ((OPR & 0xC) == 0x8)             /* ABR instruction */
                    goto abr;                       /* use nonbase ABR code */
                if ((OPR & 0xC) == 0xC)             /* TBR instruction */
                    goto tbr;                       /* use nonbase TBR code */
inv:
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                 if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */

            } else {                                /* handle non basemode SBR */
                if (OPR & 0xc) {                    /* any subop not zero is error */
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    goto newpsd;                    /* handle trap */
                }
sbr:                                                /* handle basemode too */
                /* move the byte field bits 14-15 to bits 27-28 */
                /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
                bc = (((OPR << 3) & 0x18) | reg);   /* get # bits to shift right */
                bc = BIT0 >> bc;                    /* make a bit mask of bit number */
                t = (PSD1 & 0x70000000) >> 1;       /* get old CC bits 1-3 into CCs 2-4*/
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                if (GPR[sreg] & bc)                 /* test the bit in src reg */
                    t |= CC1BIT;                    /* set CC1 to the bit value */
                GPR[sreg] |=  bc;                   /* set the bit in src reg */
                PSD1 |= t;                          /* update the CC's in the PSD */
            }
            break;

        case 0x1C>>2:       /* 0x1C HLF - HLF */    /* ZBR (basemode SRA, SRL, SLA, SLL) */
            if (MODES & BASEBIT) {                  /* handle basemode SRA, SRL, SLA, SLL */
                bc = OPR & 0x1f;                    /* get bit shift count */
                if ((OPR & 0x60) == 0x00) {         /* SRA instruction */
                    temp = GPR[reg];                /* get reg value to shift */
                    t = temp & FSIGN;               /* sign value */
                    for (ix=0; ix<bc; ix++) {
                        temp >>= 1;                 /* shift bit 0 right one bit */
                        temp |= t;                  /* restore original sign bit */
                    }
                    GPR[reg] = temp;                /* save the new value */
                    break;
                }
                if ((OPR & 0x60) == 0x20) {         /* SRL instruction */
                    GPR[reg] >>= bc;                /* value to be output */
                    break;
                }
                if ((OPR & 0x60) == 0x40) {         /* SLA instruction */
                    temp = GPR[reg];                /* get reg value to shift */
                    t = temp & FSIGN;               /* sign value */
                    ovr = 0;                        /* set ovr off */
                    for (ix=0; ix<bc; ix++) {
                        temp <<= 1;                 /* shift bit into sign position */
                        if ((temp & FSIGN) ^ t)     /* see if sign bit changed */
                            ovr = 1;                /* set arithmetic exception flag */
                    }
                    temp &= ~BIT0;                  /* clear sign bit */
                    temp |= t;                      /* restore original sign bit */
                    GPR[reg] = temp;                /* save the new value */
                    PSD1 &= 0x87FFFFFE;             /* clear the old CC's */
                    if (ovr)
                        PSD1 |= BIT1;               /* CC1 in PSD */
                    /* the arithmetic exception will be handled */
                    /* after instruction is completed */
                    /* check for arithmetic exception trap enabled */
                    if (ovr && (MODES & AEXPBIT)) {
                        TRAPME = AEXPCEPT_TRAP;     /* set the trap type */
                        goto newpsd;                /* go execute the trap now */
                    }
                    break;
                }
                if ((OPR & 0x60) == 0x60) {         /* SLL instruction */
                    GPR[reg] <<= bc;                /* value to be output */
                    break;
                }
                break;
            } else {                                /* handle nonbase ZBR */
                if (OPR & 0xc) {                    /* any subop not zero is error */
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    goto newpsd;                    /* handle trap */
                }
zbr:            /* handle basemode too */
                /* move the byte field bits 14-15 to bits 27-28 */
                /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
                bc = (((OPR << 3) & 0x18) | reg);   /* get # bits to shift right */
                bc = BIT0 >> bc;                    /* make a bit mask of bit number */
                t = (PSD1 & 0x70000000) >> 1;       /* get old CC bits 1-3 into CCs 2-4*/
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                if (GPR[sreg] & bc)                 /* test the bit in src reg */
                    t |= CC1BIT;                    /* set CC1 to the bit value */
                GPR[sreg] &= ~bc;                   /* reset the bit in src reg */
                PSD1 |= t;                          /* update the CC's in the PSD */
            }
            break;

        case 0x20>>2:       /* 0x20 HLF - HLF */    /* ABR (basemode SRAD, SRLD, SLAD, SLLD) */
            if (MODES & BASEBIT) {                  /* handle basemode SRAD, SRLD, SLAD, SLLD */
                if (reg & 1) {                      /* see if odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC7e OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                dest = (t_uint64)GPR[reg+1];        /* get low order reg value */
                dest |= (((t_uint64)GPR[reg]) << 32);   /* insert upper reg value */
                bc = OPR & 0x1f;                    /* get bit shift count */
                source = dest & DMSIGN;             /* 64 bit sign value */
                switch (OPR & 0x60) {
                case 0x00:                          /* SRAD instruction */
                    for (ix=0; ix<bc; ix++) {
                        dest >>= 1;                 /* shift bit 0 right one bit */
                        dest |= source;             /* restore original sign bit */
                    }
                    break;

                case 0x20:                          /* SRLD */
                    dest >>= bc;                    /* shift right #bits */
                    break;

                case 0x40:                          /* SLAD instruction */
                    ovr = 0;                        /* set ovr off */
                    for (ix=0; ix<bc; ix++) {
                        dest <<= 1;                 /* shift bit into sign position */
                        if ((dest & DMSIGN) ^ source)   /* see if sign bit changed */
                            ovr = 1;                /* set arithmetic exception flag */
                    }
                    dest &= ~DMSIGN;                /* clear sign bit */
                    dest |= source;                 /* restore original sign bit */
                    GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                    GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                    PSD1 &= 0x87FFFFFE;             /* clear the old CC's */
                    if (ovr)
                        PSD1 |= BIT1;               /* CC1 in PSD */
                    /* the arithmetic exception will be handled */
                    /* after instruction is completed */
                    /* check for arithmetic exception trap enabled */
                    if (ovr && (MODES & AEXPBIT)) {
                        TRAPME = AEXPCEPT_TRAP;     /* set the trap type */
                        goto newpsd;                /* go execute the trap now */
                    }
                    break;

                case 0x60:                          /* SLLD */
                    dest <<= bc;                    /* shift left #bits */
                    break;
                }
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                break;

            } else {                                /* handle nonbase mode ABR */
                if (OPR & 0xc) {                    /* any subop not zero is error */
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    goto newpsd;                    /* handle trap */
                }
abr:                                                /* basemode ABR too */
                /* move the byte field bits 14-15 to bits 27-28 */
                /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
                bc = (((OPR << 3) & 0x18) | reg);   /* get # bits to shift right */
                bc = BIT0 >> bc;                    /* make a bit mask of bit number */
                temp = GPR[sreg];                   /* get reg value to add bit to */
                t = (temp & FSIGN) != 0;            /* set flag for sign bit not set in temp value */
                t |= ((bc & FSIGN) != 0) ? 2 : 0;   /* ditto for the bit value */
                temp += bc;                         /* add the bit value to the reg */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if ((t == 3 && (temp & FSIGN) == 0) ||
                    (t == 0 && (temp & FSIGN) != 0)) {
                    ovr = 1;                        /* we have an overflow */
                }
                GPR[sreg] = temp;                   /* save the new value */
                set_CCs(temp, ovr);                 /* set the CC's, CC1 = ovr */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (ovr && (MODES & AEXPBIT)) {
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
                    goto newpsd;                    /* handle trap */
                }
            }
            break;

        case 0x24>>2:       /* 0x24 HLF - HLF */    /* TBR (basemode SRC)  */
            if (MODES & BASEBIT) {                  /* handle SRC basemode */
                bc = OPR & 0x1f;                    /* get bit shift count */
                temp = GPR[reg];                    /* get reg value to shift */
                if ((OPR & 0x60) == 0x40) {         /* SLCBR instruction */
                    for (ix=0; ix<bc; ix++) {
                        t = temp & BIT0;            /* get sign bit status */
                        temp <<= 1;                 /* shift the bit out */
                        if (t)
                            temp |= 1;              /* the sign bit status */
                    }
                } else {                            /* this is SRCBR */
                    for (ix=0; ix<bc; ix++) {
                        t = temp & 1;               /* get bit 31 status */
                        temp >>= 1;                 /* shift the bit out */
                        if (t)
                            temp |= BIT0;           /* put in new sign bit */
                    }
                }
                GPR[reg] = temp;                    /* shift result */
            } else {                                /* handle TBR non basemode */
                if (OPR & 0xc) {                    /* any subop not zero is error */
                    TRAPME = UNDEFINSTR_TRAP;       /* Undefined Instruction Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    goto newpsd;                    /* handle trap */
                }
tbr:                                                /* handle basemode TBR too */
                /* move the byte field bits 14-15 to bits 27-28 */
                /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
                bc = (((OPR << 3) & 0x18) | reg);   /* get # bits to shift right */
                bc = BIT0 >> bc;                    /* make a bit mask of bit number */
                t = (PSD1 & 0x70000000) >> 1;       /* get old CC bits 1-3 into CCs 2-4*/
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                if (GPR[sreg] & bc)                 /* test the bit in src reg */
                    t |= CC1BIT;                    /* set CC1 to the bit value */
                PSD1 |= t;                          /* update the CC's in the PSD */
            }
            break;

        case 0x28>>2:       /* 0x28 HLF - HLF */    /* Misc OP REG instructions */
            switch(OPR & 0xF) {
            case 0x0:       /* TRSW */
                if (MODES & BASEBIT)
                    temp = 0x78FFFFFE;              /* bits 1-4 and 24 bit addr for based mode */
                else
                    temp = 0x7807FFFE;              /* bits 1-4 and 19 bit addr for non based mode */
                addr = GPR[reg];                    /* get reg value */
                /* we are returning to the addr in reg, set CC's from reg */
                /* update the PSD with new address from reg */
                PSD1 &= ~temp;                      /* clean the bits to be changed */
                PSD1 |= (addr & temp);              /* insert the CC's and address */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "TRSW REG %01x PSD %08x %08x modes %08x temp %06x\n",
                    reg, PSD1, PSD2, MODES, temp);
                i_flags |= BT;                      /* we branched, so no PC update */
                break;

            case 0x2:       /* XCBR */              /* Exchange base registers */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                temp = BR[reg];                     /* get dest reg value */
                BR[reg] = BR[sreg];                 /* put source reg value int dest reg */
                BR[sreg] = temp;                    /* put dest reg value into src reg */
                break;

            case 0x4:       /* TCCR */              /* Transfer condition codes to GPR bits 28-31 */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                temp = CC >> 27;                    /* right justify CC's in reg */
                GPR[reg] = temp;                    /* put dest reg value into src reg */
                break;

            case 0x5:       /* TRCC */              /* Transfer GPR bits 28-31 to condition codes */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                PSD1 = ((PSD1 & 0x87fffffe)|((GPR[reg] & 0xf) << 27));  /* insert CCs from reg */
                break;

            case 0x8:       /* BSUB */              /* Procedure call */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */

                /* if Rd field is 0 (reg is b6-b8), this is a BSUB instruction */
                /* otherwise it is a CALL instruction (Rd != 0) */
                if (reg == 0) {
                    /* BSUB instruction */
                    uint32 cfp = BR[2];             /* get dword bounded frame pointer from BR2 */
                    if ((BR[2] & 0x7) != 0)  {
                        /* Fault, must be dw bounded address */
                        TRAPME = ADDRSPEC_TRAP;     /* bad address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPEC7f OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }
                    cfp = BR[2] & 0x00fffff8;       /* clean the cfp address to 24 bit dw */

                    M[cfp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC into frame */
                    M[(cfp>>2)+1] = 0x80000000;     /* show frame created by BSUB instr */
                    BR[1] = BR[sreg] & MASK24;      /* Rs reg to BR 1 */
                    PSD1 = (PSD1 & 0xff000000) | (BR[1] & MASK24); /* New PSD address */
                    BR[3] = GPR[0];                 /* GPR 0 to BR 3 (AP) */
                    BR[0] = cfp;                    /* set frame pointer from BR 2 into BR 0 */
                    i_flags |= BT;                  /* we changed the PC, so no PC update */
                } else
                {
                    /* CALL instruction */
                    /* get frame pointer from BR2-16 words & make it a dword addr */
                    uint32 cfp = ((BR[2]-0x40) & 0x00fffff8);

                    /* if cfp and cfp+15w are in different maps, then addr exception error */
                    if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) {
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPEC7g OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }

                    temp = (PSD1+2) & 0x01fffffe;   /* save AEXP bit and PC from PSD1 in to frame */
                    if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */
                        goto newpsd;                /* memory write error or map fault */
                    }

                    temp = 0x00000000;              /* show frame created by CALL instr */
                    if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */
                        goto newpsd;                /* memory write error or map fault */
                    }

                    /* Save BR 0-7 to stack */
                    for (ix=0; ix<8; ix++) {
                        if ((TRAPME = Mem_write(cfp+(4*ix)+8, &BR[ix]))) { /* Save into memory */
                            goto newpsd;            /* memory write error or map fault */
                        }
                    }

                    /* save GPR 2-8 to stack */
                    for (ix=2; ix<8; ix++) {
                        if ((TRAPME = Mem_write(cfp+(4*ix)+32, &GPR[ix]))) { /* Save into memory */
                            goto newpsd;            /* memory write error or map fault */
                        }
                    }

                    /* keep bits 0-7 from old PSD */ 
                    PSD1 = (PSD1 & 0xff000000) | ((BR[sreg]) & MASK24); /* New PSD address */
                    BR[1] = BR[sreg];               /* Rs reg to BR 1 */
                    BR[3] = GPR[reg];               /* Rd to BR 3 (AP) */
                    BR[0] = cfp;                    /* set current frame pointer into BR[0] */
                    BR[2] = cfp;                    /* set current frame pointer into BR[2] */
                    i_flags |= BT;                  /* we changed the PC, so no PC update */
                }
                break;

            case 0xC:       /* TPCBR */             /* Transfer program Counter to Base Register */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                BR[reg] = PSD1 & 0xfffffe;          /* save PC from PSD1 into BR */
                break;

            case 0xE:       /* RETURN */            /* procedure return for basemode calls */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                t = BR[0];                          /* get frame pointer from BR[0] */
                if ((TRAPME = Mem_read(t+4, &temp)))   /* get the word from memory */
                    goto newpsd;                    /* memory read error or map fault */
                /* if Bit0 set, restore all saved regs, else restore only BRs */
                if ((temp & BIT0) == 0) {           /* see if GPRs are to be restored */
                    /* Bit 0 is not set, so restore all GPRs */
                    for (ix=2; ix<8; ix++)
                        if ((TRAPME = Mem_read(t+ix*4+32, &GPR[ix])))   /* get the word from memory */
                            goto newpsd;            /* memory read error or map fault */
                }
                for (ix=0; ix<8; ix++) {
                    if ((TRAPME = Mem_read(t+ix*4+8, &BR[ix])))   /* get the word from memory */
                        goto newpsd;                /* memory read error or map fault */
                }
                PSD1 &= ~0x1fffffe;                 /* leave everything except AEXP bit and PC */
                if ((TRAPME = Mem_read(t, &temp)))  /* get the word from memory */
                    goto newpsd;                    /* memory read error or map fault */
                PSD1 |= (temp & 0x01fffffe);        /* restore AEXP bit and PC from call frame */
                i_flags |= BT;                      /* we changed the PC, so no PC update */
                break;

            case 0x1:                               /* INV */
            case 0x3:                               /* INV */
            case 0x6:                               /* INV */
            case 0x7:                               /* INV */
            case 0x9:                               /* INV */
            case 0xA:                               /* INV */
            case 0xB:                               /* INV */
            case 0xD:                               /* INV */
            case 0xF:                               /* INV */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
                break;
            }
            break;

        case 0x2C>>2:       /* 0x2C HLF - HLF */    /* Reg-Reg instructions */
            temp = GPR[reg];                        /* reg contents specified by Rd */
            addr = GPR[sreg];                       /* reg contents specified by Rs */
            bc = 0;

            switch(OPR & 0xF) {
            case 0x0:       /* TRR */               /* SCC|SD|R1 */
                temp = addr;                        /* set value to go to GPR[reg] */
                bc = 1;                             /* set CC's at end */
                break;

            case 0x1:       /* TRBR */              /* Transfer GPR to BR  */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                BR[reg] = GPR[sreg];                /* copy GPR to BR */
                break;

            case 0x2:       /* TBRR */              /* transfer BR to GPR */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                temp = BR[sreg];                    /* set base reg value */
                bc = 1;                             /* set CC's at end */
                break;

            case 0x3:       /* TRC */               /* Transfer register complement */
                temp = addr ^ FMASK;                /* complement Rs */
                bc = 1;                             /* set CC's at end */
                break;

            case 0x4:       /* TRN */               /* Transfer register negative */
                temp = NEGATE32(addr);              /* negate Rs value */
                if (temp == addr)                   /* overflow if nothing changed */
                    ovr = 1;                        /* set overflow flag */
                /* reset ovr if val == 0, not set for DIAGS */
                if ((temp == 0) & ovr)
                    ovr = 0;
                bc = 1;                             /* set the CC's */
                break;

            case 0x5:       /* XCR */               /* exchange registers Rd & Rs */
                GPR[sreg] = temp;                   /* Rd to Rs */
                set_CCs(temp, ovr);                 /* set the CC's from original Rd */
                temp = addr;                        /* save the Rs value to Rd reg */
                break;

            case 0x6:       /* INV */
                goto inv;
                break;

            case 0x7:       /* LMAP */              /* Load map reg - Diags only */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                /* cpu must be unmapped */
                if (MODES & MAPMODE) {              /* must be unmapped cpu */
                    TRAPME = MAPFAULT_TRAP;         /* Map Fault Trap */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT8;         /* set bit 8 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                {   /* load the cpu maps using diag psd */
                    uint32  DPSD[2];                /* the PC for the instruction */
                    /* get PSD pointed to by real addr in Rd (temp) */
                    DPSD[0] = RMW(temp);            /* get word one of psd */
                    DPSD[1] = RMW(temp+4);          /* get word two of psd */
                    sim_debug(DEBUG_CMD, my_dev,
                        "LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp %06x\n",
                        PSD1, PSD2, DPSD[0], DPSD[1], MODES, temp);
                    if ((DPSD[1] & MAPBIT) == 0)    /* if PSD2 is unmapped, treat as NOP */
                        goto skipit;
                    if (PSD2 & RETMBIT)             /* don't load maps if retain bit set */
                        goto skipit;
                    temp2 = MODES;                  /* save modes bits through load_maps call */
                    MODES = DPSD[0] & 0x87000000;   /* extract bits 0, 5, 6, 7 from PSD 1 */
                    MODES |= MAPMODE;               /* set mapped mode flag for load_maps call */
                    sim_debug(DEBUG_CMD, my_dev,
                        "LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp2 %08x\n",
                        PSD1, PSD2, DPSD[0], DPSD[1], MODES, temp2);
                    /* we need to load the new maps */
                    TRAPME = load_maps(DPSD, 1);    /* load maps for new PSD */
                    sim_debug(DEBUG_CMD, my_dev,
                        "LMAP TRAPME %02x MAPC[8-c] %08x %08x %08x %08x %08x %08x\n",
                        TRAPME, MAPC[7], MAPC[8], MAPC[9], MAPC[10], MAPC[11], MAPC[12]);
                    MODES = temp2;                  /* restore modes flags */
                    if (TRAPME) {
                        /* DIAGS wants the cpix for the psd to be the requested one */
                        PSD2 = (PSD2 & 0xffffc000) | (DPSD[1] & 0x3ff8);
                        SPAD[0xf5] = PSD2;          /* save the current PSD2 */
                        goto newpsd;                /* handle trap */
                    }
                    goto skipit;
                    break;
                }
                break;

            case 0x8:       /* TRRM */              /* SCC|SD|R1 */
                temp = addr & GPR[4];               /* transfer reg-reg masked */
                bc = 1;                             /* set CC's at end */
                break;

            /* CPUSTATUS bits */
            /* Bits 0-19 reserved */
            /* Bit 20   =0 Write to writable control store is disabled */
            /*          =1 Write to writable control store is enabled */
            /* Bit 21   =0 Enable PROM mode */
            /*          =1 Enable Alterable Control Store Mode */
            /* Bit 22   =0 Enable High Speed Floating Point Accelerator */
            /*          =1 Disable High Speed Floating Point Accelerator */
            /* Bit 23   =0 Disable privileged mode halt trap */
            /*          =1 Enable privileged mode halt trap */
            /* Bit 24 is reserved */
            /* bit 25   =0 Disable software trap handling (enable automatic trap handling) */
            /*          =1 Enable software trap handling */
            /* Bits 26-31 reserved */
            case 0x9:       /* SETCPU */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                temp2 = CPUSTATUS;                  /* save original */
                /* bits 20-23 and bit 25 can change */
                CPUSTATUS &= 0xfffff0bf;            /* zero bits that can change */
                CPUSTATUS |= (temp & 0x0f40);       /* or in the new status bits */
                CPUSTATUS |= BIT22;                 /* HS Floating is set to off */
                /* make sure WCS is off and prom mode set to 0 (on) */ 
                CPUSTATUS &= ~(BIT20|BIT21);        /* make zero */
                sim_debug(DEBUG_CMD, my_dev,
                    "SETCPU orig %08x user bits %08x New CPUSTATUS %08x SPAD[f9] %08x\n",
                    temp2, temp, CPUSTATUS, SPAD[0xf9]);
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                break;

            case 0xA:       /* TMAPR */             /* Transfer map to Reg - Diags only */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                if (CPU_MODEL <= MODEL_27) {        /* 7X & 27 must be unmapped */
                    if (MODES & MAPMODE) {          /* must be unmapped cpu */
                        TRAPME = MAPFAULT_TRAP;     /* Map Fault Trap */
                        goto newpsd;                /* handle trap */
                    }
                }
                /* Rs has map number for even/odd pair loading */
                if (CPU_MODEL < MODEL_27) {
                    /* 32/77 with 32 map regs */
                    addr &= 0x1e;                   /* make 0-15 */
                    temp = MAPC[addr>>1];           /* get even/odd maps */
                } else
                if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
                    /* 32/27 & 32/87 have 256 maps */
                    addr &= 0xfe;                   /* make 0-255 */
                    temp = MAPC[addr>>1];           /* get even/odd maps */
                } else {
                    /* 32/67, 32/97, V6 & V9 have 2048 maps demand paging */
                    addr &= 0x7ff;                  /* make 0-2047 */
                    temp = MAPC[addr>>1];           /* get even/odd maps */
                    if ((addr & 1) == 0)            /* if even reg, use left hw */
                        temp >>= 16;                /* move over reg value */
                    temp &= 0xffff;                 /* just 16 bits */
                    if (TLB[addr] & 0x04000000)     /* see if HIT bit set */
                        temp |= 0x80000000;         /* show hit BIT is set */
                    temp |= ((TLB[addr] & 0xf8000000) >> 16);  /* add in protect bits */
                    if ((addr < 0x26) || (addr > 0x7f8))
                        sim_debug(DEBUG_CMD, my_dev,
                            "TMAPR #%4x val %08x TLB %08x RMR %04x MAPC %08x\n",
                            addr, temp, TLB[addr], RMR(addr<<1), MAPC[addr/2]);
                }
                GPR[reg] = temp;                    /* save the temp value to Rd reg */
                goto skipit;
                break;

            case 0xB:       /* TRCM */              /* Transfer register complemented masked */
                temp = (addr ^ FMASK) & GPR[4];     /* compliment & mask */
                bc = 1;                             /* set the CC's */
                break;

            case 0xC:       /* TRNM */              /* Transfer register negative masked */
                temp = NEGATE32(addr);              /* complement GPR[reg] */
                if (temp == addr)                   /* check for overflow */
                    ovr = 1;                        /* overflow */
                /* reset ovr if val == 0, not set for DIAGS */
                if ((temp == 0) & ovr)
                    ovr = 0;
                temp &= GPR[4];                     /* and with negative reg */
                bc = 1;                             /* set the CC's */
                break;

            case 0xD:       /* XCRM */              /* Exchange registers masked */
                addr &= GPR[4];                     /* and Rs with mask reg */
                temp &= GPR[4];                     /* and Rd with mask reg */
                GPR[sreg] = temp;                   /* Rs to get Rd masked value */
                set_CCs(temp, ovr);                 /* set the CC's from original Rd */
                temp = addr;                        /* save the Rs value to Rd reg */
                break;

            case 0xE:       /* TRSC */              /* transfer reg to SPAD */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                t = (GPR[reg] >> 16) & 0xff;        /* get SPAD address from Rd (6-8) */
                temp2 = SPAD[t];                    /* get old SPAD data */
                SPAD[t] = GPR[sreg];                /* store Rs into SPAD */
                sim_debug(DEBUG_TRAP, my_dev,
                    "TRSC SPAD[%04x] B4 %08x New %08x\n", t, temp2, GPR[sreg]);
                break;

            case 0xF:       /* TSCR */              /* Transfer scratchpad to register */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* handle trap */
                }
                t = (GPR[sreg] >> 16) & 0xff;       /* get SPAD address from Rs (9-11) */
                temp = SPAD[t];                     /* get SPAD data into Rd (6-8) */
                sim_debug(DEBUG_TRAP, my_dev,
                    "TSCR SPAD[%04x] Val %08x\n", t, temp);
                break;
            }
            GPR[reg] = temp;                        /* save the temp value to Rd reg */
            if (bc)                                 /* set cc's if bc set */
                set_CCs(temp, ovr);                 /* set the CC's */
            /* the arithmetic exception will be handled */
            /* after instruction is completed */
            /* check for arithmetic exception trap enabled */
            if (ovr && (MODES & AEXPBIT)) {
                TRAPME = AEXPCEPT_TRAP;             /* set the trap type */
                goto newpsd;                        /* handle trap */
            }
skipit:        
            /* for retain, leave PSD2 alone */
            break;

        case 0x30>>2:       /* 0x30 */              /* CALM */
            /* Process CALM for 32/27 when in left hw, else invalid */
            if ((CPU_MODEL <= MODEL_87) && (CPU_MODEL != MODEL_67)) {
                /* DIAG error for 32/27 or 32/87 only */
                if ((PSD1 & 2) != 0)                /* is it lf hw instruction */
                    goto inv;                       /* invalid instr if in rt hw */
                addr = SPAD[0xf0];                  /* get trap table memory address from SPAD (def 80) */
                if ((addr == 0) || ((addr&MASK24) == MASK24)) {  /* see if secondary vector table set up */
                    TRAPME = ADDRSPEC_TRAP;         /* Not setup, error */
                    goto newpsd;                    /* program error */
                }
                addr = addr + (0x0A << 2);          /* addr has mem addr of CALM trap vector (def A8) */
                t = M[addr >> 2];                   /* get the ICB address from memory */
                if ((t == 0) || ((t&MASK24) == MASK24)) {   /* see if ICB set up */
                    TRAPME = ADDRSPEC_TRAP;         /* Not setup, error */
                    goto newpsd;                    /* program error */
                }
                bc = PSD2 & 0x3ff8;                 /* get copy of cpix */
                /* this will skip over rt hw instruction if any */
                PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);    /* bump pc by 1 wd */
                M[t>>2] = PSD1 & 0xfffffffe;        /* store PSD 1 + 1HW to point to next instruction */
                M[(t>>2)+1] = PSD2;                 /* store PSD 2 */
                TPSD1 = PSD1;                       /* save old PSD1 */
                TPSD2 = PSD2;                       /* save old PSD2 */
                PSD1 = M[(t>>2)+2];                 /* get new PSD 1 */
                PSD2 = (M[(t>>2)+3] & ~0x3fff) | bc;    /* get new PSD 2 w/old cpix */
                M[(t>>2)+4] = OPR & 0x03FF;         /* store calm number in bits 6-15 */
                PSD2 &= ~RETMBIT;                   /* turn off retain bit in PSD2 */
                sim_debug(DEBUG_IRQ, my_dev,
                    "CALM @ %.6x NPSD %08x %04x OPSD %08x %04x SPAD %x STATUS %08x\n",
                    addr, PSD1, PSD2, TPSD1, TPSD2, SPAD[0xf5], CPUSTATUS);

                /* test for retain blocking state */
                if (PSD2 & RETBBIT) {               /* is it retain blocking state */
                    /* BIT 49 has new blocking state */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        PSD2 |= SETBBIT;            /* yes, set to blocked state */
                        MODES |= BLKMODE;           /* set blocked mode */
                        CPUSTATUS |= BIT24;         /* set blocked mode */
                    } else {
                        PSD2 &= ~SETBBIT;           /* set to unblocked state */
                        MODES &= ~RETMODE;          /* reset retain block mode bit */
                        CPUSTATUS &= ~BIT24;        /* reset block state in cpu status bit 8 */
                    }
                    PSD2 &= ~RETBBIT;               /* clear bit 48 retain blocking bit */
                }

                /* set the mode bits and CCs from the new PSD */
                CC = PSD1 & 0x78000000;             /* extract bits 1-4 from PSD1 */
                MODES = PSD1 & 0x87000000;          /* extract bits 0, 5, 6, 7 from PSD 1 */
                CPUSTATUS &= ~0x87000000;           /* reset bits in CPUSTATUS */
                CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */

                if ((PSD2 & SETBBIT) == 0) {        /* see if new mode is unblocked */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        /* we changed from blocked to unblocked */
                        if (!(CPUSTATUS & ONIPU))
                            irq_pend = 1;           /* start scanning interrupts again */
                    }
                }

                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                TRAPME = 0;                         /* not to be processed as trap */
                drop_nop = 0;                       /* nothing to drop */
                i_flags |= BT;                      /* do not update pc */
            } else {
//              fprintf(stderr, "got CALM trap\r\n");
                goto inv;                           /* invalid instr */
            }
            break;

        case 0x34>>2:       /* 0x34 SD|ADR - inv */ /* LA non-basemode */
            if (MODES & BASEBIT)                    /* see if based */
                goto inv;                           /* invalid instruction in based mode */
            if (MODES & EXTDBIT) {                  /* see if extended mode */
                dest = (t_uint64)(addr&MASK24);     /* just pure 24 bit address */
            } else {                                /* use bits 13-31 */
                dest = (t_uint64)((addr&0x7ffff) | ((FC & 4) << 17));   /* F bit to bit 12 */
            }
            break;

        case 0x38>>2:       /* 0x38 HLF - HLF */    /* REG - REG floating point */
            switch(OPR & 0xF) {
            case 0x0:       /* ADR */
                temp = GPR[reg];                    /* reg contents specified by Rd */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                t = (temp & FSIGN) != 0;            /* set flag for sign bit not set in temp value */
                t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
                temp = temp + addr;                 /* add the values */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if ((t == 3 && (temp & FSIGN) == 0) || (t == 0 && (temp & FSIGN) != 0)) {
                    ovr = 1;                        /* we have an overflow */
                }
                i_flags |= SF;                      /* special processing */
                break;

            case 0x1:       /* ADRFW */
            case 0x3:       /* SURFW */
                /* TODO not on 32/27 */
                temp = GPR[reg];                    /* reg contents specified by Rd */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */
                if ((OPR & 0xF) == 0x3) {
                    addr = NEGATE32(addr);          /* subtract, so negate source */
                }
                temp2 = s_adfw(temp, addr, &CC);    /* do ADFW */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "%s GPR[%d] %08x addr %08x result %08x CC %08x\n",
                    (OPR&0xf)==3 ? "SURFW":"ADRFW",
                    reg, GPR[reg], GPR[sreg], temp2, CC);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg] = temp2;                   /* dest - reg contents specified by Rd */
                break;

            case 0x2:       /* MPRBR */
                /* TODO not on 32/27 */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                if (reg & 1) {
                    /* Spec fault if not even reg */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                temp = GPR[reg+1];                  /* get multiplicand */
                addr = GPR[sreg];                   /* multiplier */

                /* change value into a 64 bit value */
                dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
                source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0);
                dest = dest * source;               /* do the multiply */
                i_flags |= (SD|SCC);                /* save dest reg and set CC's */
                dbl = 1;                            /* double reg save */
                break;

            case 0x4:       /* DVRFW */
                /* TODO not on 32/27 */
                temp = GPR[reg];                    /* reg contents specified by Rd */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */
                temp2 = (uint32)s_dvfw(temp, addr, &CC);    /* divide reg by sreg */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "DVRFW GPR[%d] %08x src %08x result %08x\n",
                    reg, GPR[reg], addr, temp2);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg] = temp2;                   /* dest - reg contents specified by Rd */
                break;

            case 0x5:       /* FIXW */
                /* TODO not on 32/27 */
                /* convert from 32 bit float to 32 bit fixed */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                temp2 = s_fixw(addr, &CC);          /* do conversion */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "FIXW GPR[%d] %08x result %08x\n",
                    sreg, GPR[sreg], temp2);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg] = temp2;                   /* dest - reg contents specified by Rd */
                break;                              /* go set CC's */

            case 0x6:       /* MPRFW */
                /* TODO not on 32/27 */
                temp = GPR[reg];                    /* reg contents specified by Rd */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */
                temp2 = s_mpfw(temp, addr, &CC);    /* mult reg by sreg */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "MPRFW GPR[%d] %08x src %08x result %08x\n",
                    reg, GPR[reg], addr, temp2);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg] = temp2;                   /* dest - reg contents specified by Rd */
                break;

            case 0x7:       /* FLTW */
                /* TODO not on 32/27 */
                /* convert from 32 bit integer to 32 bit float */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                GPR[reg] = s_fltw(addr, &CC);       /* do conversion & set CC's */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "FLTW GPR[%d] %08x result %08x\n",
                    sreg, GPR[sreg], GPR[reg]);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                break;

            case 0x8:       /* ADRM */
                temp = GPR[reg];                    /* reg contents specified by Rd */
                addr = GPR[sreg];                   /* reg contents specified by Rs */
                t = (temp & FSIGN) != 0;            /* set flag for sign bit not set in temp value */
                t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
                temp = temp + addr;                 /* add the values */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if ((t == 3 && (temp & FSIGN) == 0) ||
                    (t == 0 && (temp & FSIGN) != 0))
                    ovr = 1;                        /* we have an overflow */
                temp &= GPR[4];                     /* mask the destination reg */
                i_flags |= SF;                      /* special processing */
                break;

            case 0x9:       /* ADRFD */
            case 0xB:       /* SURFD */
                /* TODO not on 32/27 */
                if ((reg & 1) || (sreg & 1)) {      /* see if any odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                td = (((t_uint64)GPR[reg]) << 32);  /* get upper reg value */
                td |= (t_uint64)GPR[reg+1];         /* insert low order reg value */
                source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
                source |= (t_uint64)GPR[sreg+1];    /* insert low order reg value */
                if ((OPR & 0xF) == 0xb) {
                    source = NEGATE32(source);      /* make negative for subtract */
                }
                dest = s_adfd(td, source, &CC);     /* do ADFD */

                sim_debug(DEBUG_DETAIL, my_dev,
                    "%s GPR[%d] %08x %08x src %016llx result %016llx\n",
                    (OPR&0xf)==8 ? "ADRFD":"SURFD", reg, GPR[reg], GPR[reg+1], source, dest);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                break;

            case 0xA:       /* DVRBR */
                /* TODO not on 32/27 */
                if ((MODES & BASEBIT) == 0)         /* see if nonbased */
                    goto inv;                       /* invalid instruction in nonbased mode */
                if (reg & 1) {
                    /* Spec fault if not even reg */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                /* get Rs divisor value */
                source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0);
                /* merge the dividend regs into the 64bit value */
                dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]);
                if (source == 0) {
                    goto doovr4;
                    break;
                }
                td = (t_int64)dest % (t_int64)source;   /* remainder */
                if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
                    td = NEGATE32(td);              /* dividend and remainder must be same sign */
                dest = (t_int64)dest / (t_int64)source; /* now do the divide */
                /* test for overflow */
                if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) {
doovr4:
                    ovr = 1;                        /* the quotient exceeds 31 bit, overflow */
                    /* the arithmetic exception will be handled */
                    /* after instruction is completed */
                    /* check for arithmetic exception trap enabled */
                    if (ovr && (MODES & AEXPBIT)) {
                        TRAPME = AEXPCEPT_TRAP;     /* set the trap type */
                    }
                    /* the original regs must be returned unchanged if aexp */
                    set_CCs(temp, ovr);             /* set the CC's */
                } else {
                    GPR[reg] = (uint32)(td & FMASK);    /* reg gets remainder, reg+1 quotient */
                    GPR[reg+1] = (uint32)(dest & FMASK);    /* store quotient in reg+1 */
                    set_CCs(GPR[reg+1], ovr);       /* set the CC's, CC1 = ovr */
                }
                break;

            case 0xC:       /* DVRFD */
                /* TODO not on 32/27 */
                if ((reg & 1) || (sreg & 1)) {      /* see if any odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                td = (((t_uint64)GPR[reg]) << 32);  /* get upper reg value */
                td |= (t_uint64)GPR[reg+1];         /* insert low order reg value */
                source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
                source |= (t_uint64)GPR[sreg+1];    /* insert low order reg value */
                dest = s_dvfd(td, source, &CC);     /* divide double values */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "DVRFD GPR[%d] %08x %08x src %016llx result %016llx\n",
                    reg, GPR[reg], GPR[reg+1], source, dest);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                break;

            case 0xD:       /* FIXD */
                /* dest - reg contents specified by Rd & Rd+1 */
                /* source - reg contents specified by Rs & Rs+1 */
                if (sreg & 1) {
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                /* merge the sregs into the 64bit value */
                source = (((t_uint64)GPR[sreg]) << 32) | ((t_uint64)GPR[sreg+1]);
                /* convert from 64 bit double to 64 bit int */
                dest = s_fixd(source, &CC);
                sim_debug(DEBUG_DETAIL, my_dev,
                    "FIXD GPR[%d] %08x %08x result %016llx\n",
                    sreg, GPR[sreg], GPR[sreg+1], dest);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                break;

            case 0xE:       /* MPRFD */
                /* TODO not on 32/27 */
                if ((reg & 1) || (sreg & 1)) {      /* see if any odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                td = (((t_uint64)GPR[reg]) << 32);  /* get upper reg value */
                td |= (t_uint64)GPR[reg+1];         /* insert low order reg value */
                source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
                source |= (t_uint64)GPR[sreg+1];    /* insert low order reg value */
                dest = s_mpfd(td, source, &CC);     /* multiply double values */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "MPRFD GPR[%d] %08x %08x src %016llx result %016llx\n",
                    reg, GPR[reg], GPR[reg+1], source, dest);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                if (CC & CC1BIT) {                  /* check for arithmetic exception */
                    ovr = 1;                        /* exception */
                    /* leave Rd & Rs unchanged if AEXPBIT is set */
                    if (MODES & AEXPBIT) {
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                }
                /* AEXPBIT not set, so save the fixed return value */
                /* return result to destination reg */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                break;

            case 0xF:       /* FLTD */
                /* TODO not on 32/27 */
                /* convert from 64 bit integer to 64 bit float */
                if ((reg & 1) || (sreg & 1)) {      /* see if any odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
                source |= (t_uint64)GPR[sreg+1];    /* insert low order reg value */
                dest = s_fltd(source, &CC);         /* do conversion & set CC's */
                sim_debug(DEBUG_DETAIL, my_dev,
                    "FLTD GPR[%d] %08x %08x result %016llx\n",
                    sreg, GPR[sreg], GPR[sreg+1], dest);
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                break;
            }
            if (i_flags & SF) {                     /* see if special processing */
                GPR[reg] = temp;                    /* temp has destination reg value */
                set_CCs(temp, ovr);                 /* set the CC's */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (ovr && (MODES & AEXPBIT)) {
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
                    goto newpsd;                    /* go execute the trap now */
                }
            }
            break;

        case 0x3C>>2:       /* 0x3C HLF - HLF */    /* SUR and SURM */
            temp = GPR[reg];                        /* get negative value to add */
            temp2 = GPR[sreg];                      /* get negative value to add */
            addr = NEGATE32(GPR[sreg]);             /* reg contents specified by Rs */
            switch(OPR & 0xF) {
            case 0x0:       /* SUR */
                t = (temp & FSIGN) != 0;            /* set flag for sign bit not set in temp value */
                t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
                temp = temp + addr;                 /* add the values */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if ((t == 3 && (temp & FSIGN) == 0) ||
                    (t == 0 && (temp & FSIGN) != 0))
                    ovr = 1;                        /* we have an overflow */
                if (addr == FSIGN)
                    ovr = 1;                        /* we have an overflow */
                break;

            case 0x8:       /* SURM */
                t = (temp & FSIGN) != 0;            /* set flag for sign bit not set in temp value */
                t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
                temp = temp + addr;                 /* add the values */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if ((t == 3 && (temp & FSIGN) == 0) ||
                    (t == 0 && (temp & FSIGN) != 0))
                    ovr = 1;                        /* we have an overflow */
                temp &= GPR[4];                     /* mask the destination reg */
                if (addr == FSIGN)
                    ovr = 1;                        /* we have an overflow */
                break;
            default:
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
                break;
            }
            GPR[reg] = temp;                        /* save the result */
            set_CCs(temp, ovr);                     /* set CCs for result */
            /* the arithmetic exception will be handled */
            /* after instruction is completed */
            /* check for arithmetic exception trap enabled */
            if (ovr && (MODES & AEXPBIT)) {
                TRAPME = AEXPCEPT_TRAP;             /* set the trap type */
                goto newpsd;                        /* go execute the trap now */
            }
            break;

        case 0x40>>2:       /* 0x40 SCC|SD|HLF - INV */ /* MPR */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction in basemode */
            if (reg & 1) {                          /* odd reg specified? */
                /* Spec fault */
                /* HACK HACK HACK for DIAGS */
                if (CPU_MODEL <= MODEL_27) {        /* DIAG error for 32/27 only */
                    if ((PSD1 & 2) == 0)            /* if lf hw instruction */
                        i_flags &= ~HLF;            /* if nop in rt hw, bump pc a word */
                    else
                        PSD1 &= ~3;                 /* fake out 32/27 diag error */
                }
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if (OPR & 0xf) {                        /* any subop not zero is error */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            temp = GPR[reg+1];                      /* get multiplicand */
            addr = GPR[sreg];                       /* multiplier */

            /* change immediate value into a 64 bit value */
            dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
            source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0);
            dest = dest * source;                   /* do the multiply */
            dbl = 1;                                /* double reg save */
            break;

        case 0x44>>2:       /* 0x44 ADR - ADR */    /* DVR */
            /* sreg has Rs */
            if (reg & 1) {
                /* Spec fault */
                /* HACK HACK HACK for DIAGS */
                if (CPU_MODEL <= MODEL_27) {        /* DIAG error for 32/27 only */
                    if ((PSD1 & 2) == 0)            /* if lf hw instruction */
                        i_flags &= ~HLF;            /* if nop in rt hw, bump pc a word */
                    else
                        PSD1 &= ~3;                 /* fake out 32/27 diag error */
                }
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if (OPR & 0xf) {                        /* any subop not zero is error */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                goto newpsd;                        /* handle trap */
            }
            /* get Rs divisor value */
            source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0);
            /* merge the dividend regs into the 64bit value */
            dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]);
            if (source == 0)
                goto doovr3;
            td = (t_int64)dest % (t_int64)source;   /* remainder */
            if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
                td = NEGATE32(td);                  /* dividend and remainder must be same sign */
            dest = (t_int64)dest / (t_int64)source; /* now do the divide */
            int64a = dest;
            if (int64a < 0)
                int64a = -int64a;
            if (int64a > 0x7fffffff)                /* if more than 31 bits, we have an error */
                goto doovr3;
            if (((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) ||
                (((dest & D32LMASK) == D32LMASK) && ((dest & D32RMASK) == 0))) {  /* test for overflow */
doovr3:
                dest = (((t_uint64)GPR[reg]) << 32);/* insert upper reg value */
                dest |= (t_uint64)GPR[reg+1];       /* get low order reg value */
                ovr = 1;                            /* the quotient exceeds 31 bit, overflow */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (ovr && (MODES & AEXPBIT)) {
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
                }
                /* the original regs must be returned unchanged if aexp */
                CC = CC1BIT;                        /* set ovr CC bit */
                if (dest == 0)
                    CC |= CC4BIT;                   /* dw is zero, so CC4 */
                else
                if (dest & DMSIGN)
                    CC |= CC3BIT;                   /* it is neg dw, so CC3  */
                else
                    CC |= CC2BIT;                   /* then dest > 0, so CC2 */
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's from PSD1 */
                PSD1 |= CC;                         /* update the CC's in the PSD */
            } else {
                GPR[reg] = (uint32)(td & FMASK);    /* reg gets remainder, reg+1 quotient */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* store quotient in reg+1 */
                set_CCs(GPR[reg+1], ovr);           /* set the CC's, CC1 = ovr */
            }
            break;

        case 0x48>>2:       /* 0x48 INV - INV */    /* unused opcodes */
        case 0x4C>>2:       /* 0x4C INV - INV */    /* unused opcodes */
        default:
            TRAPME = UNDEFINSTR_TRAP;               /* Undefined Instruction Trap */
            if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                TRAPSTATUS |= BIT0;                 /* set bit 0 of trap status */
            goto newpsd;                            /* handle trap */
            break;

        case 0x50>>2:       /* 0x50 INV - SD|ADR */ /* LA basemode LABRM */
            if ((MODES & BASEBIT) == 0)             /* see if nonbased */
                goto inv;                           /* invalid instruction in nonbased mode */
            dest = (t_uint64)(addr&MASK24);         /* just pure 24 bit address */
            break;

        case 0x54>>2:       /* 0x54 SM|ADR - INV */ /* (basemode STWBR) */
            if ((MODES & BASEBIT) == 0)             /* see if nonbased */
                goto inv;                           /* invalid instruction in nonbased mode */
            if (FC != 0) {                          /* word address only */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                sim_debug(DEBUG_TRAP, my_dev,
                    "ADDRSPEC8 OP %04x addr %08x\n", OP, addr);
                goto newpsd;                        /* go execute the trap now */
            }
            dest = BR[reg];                         /* save the BR to memory */
            break;

        case 0x58>>2:       /* 0x58 SB|ADR - INV */ /* (basemode SUABR and LABR) */
            if ((MODES & BASEBIT) == 0)             /* see if nonbased */
                goto inv;                           /* invalid instruction in nonbased mode */
            if ((FC & 4) == 0) {                    /* see if SUABR F=0 0x5800 */
                dest = BR[reg] - addr;              /* subtract addr from the BR and store back to BR */
            } else {                                /* LABR if F=1  0x5808 */
                dest = addr;                        /* addr goes to specified BR */
            }
            break;

        case 0x5C>>2:       /* 0x5C RM|ADR - INV */  /* (basemode LWBR and BSUBM) */
            if ((MODES & BASEBIT) == 0)             /* see if nonbased */
                goto inv;                           /* invalid instruction in nonbased mode */
            if ((FC & 3) != 0) {                    /* word address only */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                sim_debug(DEBUG_TRAP, my_dev,
                    "ADDRSPEC9 OP %04x addr %08x\n", OP, addr);
                goto newpsd;                        /* go execute the trap now */
            }
            if ((FC & 0x4) == 0) {                  /* this is a LWBR 0x5C00 instruction */
                BR[reg] = (uint32)source;           /* load memory location into BR */
            } else
            {                                       /* this is a CALLM/BSUBM instruction */
                /* if Rd field is 0 (reg is b6-8), this is a BSUBM instruction */
                /* otherwise it is a CALLM instruction (Rd != 0) */
                if (reg == 0) {
                    /* BSUBM instruction */
                    uint32 cfp = BR[2];             /* get dword bounded frame pointer from BR2 */

                    if ((BR[2] & 0x7) != 0)  {
                        /* Fault, must be dw bounded address */
                        TRAPME = ADDRSPEC_TRAP;     /* bad address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPEC9a OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }

                    temp = (PSD1+4) & 0x01fffffe;   /* save AEXP bit and PC from PSD1 into frame */
                    if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */
                        goto newpsd;                /* memory write error or map fault */
                    }

                    temp = 0x80000000;              /* show frame created by BSUBM instr */
                    if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */
                        goto newpsd;                /* memory write error or map fault */
                    }

                    temp = addr & 0xfffffe;         /* CALL memory address */
                    if ((temp & 0x3) != 0) {        /* check for word aligned */
                        /* Fault, must be word bounded address */
                        TRAPME = ADDRSPEC_TRAP;     /* bad address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPEC9b OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }

                    if ((TRAPME = Mem_read(temp, &addr)))   /* get the word from memory */
                        goto newpsd;                /* memory read error or map fault */

                    BR[1] = addr;                   /* effective address contents to BR 1 */
                    /* keep bits 0-7 from old PSD */ 
                    PSD1 = ((PSD1 & 0xff000000) | (BR[1] & 0x01fffffe)); /* New PSD address */
                    BR[3] = GPR[0];                 /* GPR[0] to BR[3] (AP) */
                    BR[0] = cfp;                    /* set current frame pointer into BR[0] */
                    i_flags |= BT;                  /* we changed the PC, so no PC update */
                } else {
                    /* CALLM instruction */

                    /* get frame pointer from BR2 - 16 words & make it a dword addr */
                    uint32 cfp = ((BR[2]-0x40) & 0x00fffff8);

                    /* if cfp and cfp+15w are in different maps, then addr exception error */
                    if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) {
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPEC9c OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }

                    temp = (PSD1+4) & 0x01fffffe;   /* save AEXP bit and PC from PSD1 in to frame */
                    if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */
                        goto newpsd;                /* memory write error or map fault */
                    }

                    temp = 0x00000000;              /* show frame created by CALL instr */
                    if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */
                        goto newpsd;                /* memory write error or map fault */
                    }

                    /* save the BRs 0-7 on stack */
                    for (ix=0; ix<8; ix++) {
                        if ((TRAPME = Mem_write(cfp+(4*ix)+8, &BR[ix]))) { /* Save into memory */
                            goto newpsd;            /* memory write error or map fault */
                        }
                    }

                    /* save GPRs 2-7 on stack */
                    for (ix=2; ix<8; ix++) {
                        if ((TRAPME = Mem_write(cfp+(4*ix)+32, &GPR[ix]))) { /* Save into memory */
                            goto newpsd;            /* memory write error or map fault */
                        }
                    }

                    temp = addr & 0xfffffe;         /* CALL memory address */
                    if ((temp & 0x3) != 0) {        /* check for word aligned */
                        /* Fault, must be word bounded address */
                        TRAPME = ADDRSPEC_TRAP;     /* bad address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPEC9d OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }

                    if ((TRAPME = Mem_read(temp, &addr)))   /* get the word from memory */
                        goto newpsd;                /* memory read error or map fault */

                    BR[1] = addr;                   /* effective address contents to BR 1 */
                    /* keep bits 0-6 from old PSD */ 
                    PSD1 = (PSD1 & 0xff000000) | ((BR[1]) & 0x01fffffe); /* New PSD address */
                    BR[3] = GPR[reg];               /* Rd to BR 3 (AP) */
                    BR[0] = cfp;                    /* set current frame pointer into BR[0] */
                    BR[2] = cfp;                    /* set current frame pointer into BR[2] */
                    i_flags |= BT;                  /* we changed the PC, so no PC update */
                }
            }
            break;

        case 0x60>>2:       /* 0x60 HLF - INV */    /* NOR Rd,Rs */
            if ((MODES & BASEBIT)) {                /* only for nonbased mode */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            if (OPR & 0xf) {                        /* any subop not zero is error */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            /* exponent must not be zero or all 1's */
            /* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */
            temp = s_nor(GPR[reg], &GPR[sreg]);
            sim_debug(DEBUG_DETAIL, my_dev,
                "NOR GPR[%d] %08x result %08x exp %02x\n",
                reg, GPR[reg], temp, GPR[sreg]);
            GPR[reg] = temp;
            break;

        case 0x64>>2:       /* 0x64 SD|HLF - INV */ /* NORD */
            if ((MODES & BASEBIT)) {                /* only for nonbased mode */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            if (reg & 1) {                          /* see if odd reg specified */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if (OPR & 0xf) {                        /* any subop not zero is error */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            /* shift until upper 5 bits are neither 0 or all 1's */
            /* merge the GPR[reg] & GPR[reg+1] into a 64bit value */
            td = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]);
            /* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */
            dest = s_nord(td, &GPR[sreg]);
            sim_debug(DEBUG_DETAIL, my_dev,
                "NORD GPR[%d] %08x %08x result %016llx exp %02x\n",
                reg, GPR[reg], GPR[reg+1], dest, GPR[sreg]);
            GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
            GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
            break;

        case 0x68>>2:       /* 0x68 HLF - INV */    /* non basemode SCZ */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction */
            if (OPR & 0xf) {                        /* any subop not zero is error */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* handle trap */
            }
            goto sacz;                              /* use basemode sacz instruction */

        case 0x6C>>2:       /* 0x6C HLF - INV */    /* non basemode SRA & SLA */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction */
            bc = OPR & 0x1f;                        /* get bit shift count */
            temp = GPR[reg];                        /* get reg value to shift */
            t = temp & FSIGN;                       /* sign value */
            if (OPR & 0x0040) {                     /* is this SLA */
                ovr = 0;                            /* set ovr off */
                for (ix=0; ix<bc; ix++) {
                    temp <<= 1;                     /* shift bit into sign position */
                    if ((temp & FSIGN) ^ t)         /* see if sign bit changed */
                        ovr = 1;                    /* set arithmetic exception flag */
                }
                temp &= ~BIT0;                      /* clear sign bit */
                temp |= t;                          /* restore original sign bit */
                GPR[reg] = temp;                    /* save the new value */
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                if (ovr)
                    PSD1 |= BIT1;                   /* CC1 in PSD */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (ovr && (MODES & AEXPBIT)) {
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
                    goto newpsd;                    /* go execute the trap now */
                }
            } else {                                /* this is a SRA */
                for (ix=0; ix<bc; ix++) {
                    temp >>= 1;                     /* shift bit 0 right one bit */
                    temp |= t;                      /* restore original sign bit */
                }
                GPR[reg] = temp;                    /* save the new value */
            }
            break;

        case 0x70>>2:       /* 0x70 SD|HLF - INV */ /* non-basemode SRL & SLL */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction in basemode */
            bc = OPR & 0x1f;                        /* get bit shift count */
            if (OPR & 0x0040)                       /* is this SLL, bit 9 set */
                GPR[reg] <<= bc;                    /* shift left #bits */
            else
                GPR[reg] >>= bc;                    /* shift right #bits */
            break;

        case 0x74>>2:       /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction in basemode */
            bc = OPR & 0x1f;                        /* get bit shift count */
            temp = GPR[reg];                        /* get reg value to shift */
            if (OPR & 0x0040) {                     /* is this SLC, bit 9 set */
                for (ix=0; ix<bc; ix++) {
                    t = temp & BIT0;                /* get sign bit status */
                    temp <<= 1;                     /* shift the bit out */
                    if (t)
                        temp |= 1;                  /* the sign bit status */
                }
            } else {                                /* this is SRC, bit 9 not set */
                for (ix=0; ix<bc; ix++) {
                    t = temp & 1;                   /* get bit 31 status */
                    temp >>= 1;                     /* shift the bit out */
                    if (t)
                        temp |= BIT0;               /* put in new sign bit */
                }
            }
            GPR[reg] = temp;                        /* shift result */
            break;

        case 0x78>>2:       /* 0x78 HLF - INV */    /* non-basemode SRAD & SLAD */
            if (MODES & BASEBIT)                    /* Base mode? */
                goto inv;                           /* invalid instruction in basemode */
            if (reg & 1) {                          /* see if odd reg specified */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            bc = OPR & 0x1f;                        /* get bit shift count */
            dest = (t_uint64)GPR[reg+1];            /* get low order reg value */
            dest |= (((t_uint64)GPR[reg]) << 32);   /* insert upper reg value */
            source = dest & DMSIGN;                 /* 64 bit sign value */
            if (OPR & 0x0040) {                     /* is this SLAD */
                ovr = 0;                            /* set ovr off */
                for (ix=0; ix<bc; ix++) {
                    dest <<= 1;                     /* shift bit into sign position */
                    if ((dest & DMSIGN) ^ source)   /* see if sign bit changed */
                        ovr = 1;                    /* set arithmetic exception flag */
                }
                dest &= ~DMSIGN;                    /* clear sign bit */
                dest |= source;                     /* restore original sign bit */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                if (ovr)
                    PSD1 |= BIT1;                   /* CC1 in PSD */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (ovr && (MODES & AEXPBIT)) {
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
                    goto newpsd;                    /* go execute the trap now */
                }
            } else {                                /* this is a SRAD */
                for (ix=0; ix<bc; ix++) {
                    dest >>= 1;                     /* shift bit 0 right one bit */
                    dest |= source;                 /* restore original sign bit */
                }
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
            }
            break;

        case 0x7C>>2:       /* 0x7C HLF - INV */    /* non-basemode SRLD & SLLD */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction in basemode */
            if (reg & 1) {                          /* see if odd reg specified */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            dest = (t_uint64)GPR[reg+1];            /* get low order reg value */
            dest |= (((t_uint64)GPR[reg]) << 32);   /* insert upper reg value */
            bc = OPR & 0x1f;                        /* get bit shift count */
            if (OPR & 0x0040)                       /* is this SLL, bit 9 set */
                dest <<= bc;                        /* shift left #bits */
            else
                dest >>= bc;                        /* shift right #bits */
            GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
            GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
            break;

        case 0x80>>2:       /* 0x80 SD|ADR - SD|ADR */  /* LEAR */
            /* convert address to real physical address */
            TRAPME = RealAddr(addr, &temp, &t, MEM_RD);
            // diag allows any addr if mapped
            if (TRAPME != ALLOK) {
                sim_debug(DEBUG_TRAP, my_dev,
                    "At LEAR with TRAPME %02x addr %08x\n", TRAPME, addr);
                goto newpsd;                        /* memory read error or map fault */
            }
            /* set access bit for mapped addresses */
            if ((CPU_MODEL >= MODEL_V6) && (MODES & MAPMODE)) {
                uint32 map, mix, nix, msdl, mpl, Mmap;

                nix = (addr >> 13) & 0x7ff;         /* get 11 bit map value */
                /* check our access to the memory */
                switch (t & 0x0e) {
                case 0x0: case 0x2:
                    /* O/S or user has no read/execute access, do protection violation */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "LEAR read protect error @ %06x prot %02x modes %08x page %04x\n",
                        addr, t, MODES, nix);
                    if (CPU_MODEL == MODEL_V9)
                        TRAPSTATUS |= BIT1;         /* set bit 1 of trap status */
                    else
                        TRAPSTATUS |= BIT12;        /* set bit 12 of trap status */
                    TRAPME = MPVIOL;                /* memory protection violation */
                    goto newpsd;                    /* process error */
                case 0x4: case 0x6: case 0x8: case 0xc: case 0xa: case 0xe:
                    /* O/S or user has read/execute access, no protection violation */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "LEAR read protect is ok @ %06x prot %02x modes %08x page %04x\n",
                        addr, t, MODES, nix);
                }
                /* we have read access, so go set the access bit in the map entry */
                mpl = SPAD[0xf3];                   /* get mpl from spad address */
                if (nix < BPIX) {
                    mix = nix;                      /* get map index in memory */
                    msdl = RMW(mpl+4);              /* get mpl entry for O/S */
                } else {
                    mix = nix-BPIX;                 /* get map index in memory */
                    msdl = RMW(mpl+CPIX+4);         /* get mpl entry for given CPIX */
                }
                Mmap = RMH(msdl+(mix<<1));          /* map content from memory */      
                map = RMR((nix<<1));                /* read the map cache contents */
                if (((map & 0x800) == 0)) {         /* see if access bit is already on */
                    Mmap |= 0x800;                  /* set the accessed bit in the map cache entry */
                    map |= 0x800;                   /* set the accessed bit in the memory map entry */
                    WMR((nix<<1), map);             /* store the map reg contents into cache */
                    TLB[nix] |= 0x0c000000;         /* set the accessed & hit bits in TLB too */
                    WMH(msdl+(mix<<1), Mmap);       /* save modified memory map with access bit set */
                    sim_debug(DEBUG_EXP, my_dev,
                        "LEAR Laddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n",
                        addr, nix, TLB[nix], map, Mmap);
                }
            }

            /* OS code says F bit is not transferred, so just ignore it */
            /* DIAGS needs it, so put it back */
            if (FC & 4)                             /* see if F bit was set */
                temp |= 0x01000000;                 /* set bit 7 of address */
            dest = temp;                            /* put in dest to go out */
            break;

        case 0x84>>2:       /* 0x84 SD|RR|RNX|ADR - SD|RNX|ADR */ /* ANMx */
            td = dest & source;                     /* DO ANMX */
            CC = 0;
            switch(FC) {                            /* adjust for hw or bytes */
            case 4: case 5: case 6: case 7:         /* byte address */
                /* ANMB */
                td &= 0xff;                         /* mask out right most byte */
                dest &= 0xffffff00;                 /* make place for byte */
                if (td == 0)
                    CC |= CC4BIT;                   /* byte is zero, so CC4 */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            case 1:                                 /* left halfword addr */
            case 3:                                 /* right halfword addr */
                /* ANMH */
                td &= RMASK;                        /* mask out right most 16 bits */
                dest &= LMASK;                      /* make place for halfword */
                if (td == 0)
                    CC |= CC4BIT;                   /* hw is zero, so CC4 */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            case 0:                                 /* 32 bit word */
                /* ANMW */
                td &= D32RMASK;                     /* mask out right most 32 bits */
                dest = 0;                           /* make place for 64 bits */
                if (td == 0)
                    CC |= CC4BIT;                   /* word is zero, so CC4 */
                else
                if (td & 0x80000000)
                    CC |= CC3BIT;                   /* it is neg wd, so CC3  */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            case 2:                                 /* 64 bit double */
                /* ANMD */
                dest = 0;                           /* make place for 64 bits */
                if (td == 0)
                    CC |= CC4BIT;                   /* dw is zero, so CC4 */
                else
                if (td & DMSIGN)
                    CC |= CC3BIT;                   /* it is neg dw, so CC3  */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            }
            dest |= td;                             /* insert result into dest */
            if (FC != 2) {                          /* do not sign extend DW */
                if (dest & 0x80000000)              /* see if we need to sign extend */
                    dest |= D32LMASK;               /* force upper word to all ones */
            }
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            PSD1 |= CC;                             /* update the CC's in the PSD */
            break;

        case 0x88>>2:       /* 0x88 SD|RR|RNX|ADR - SD|RNX|ADR */ /* ORMx */
            td = dest | source;                     /* DO ORMX */
meoa:       /* merge point for eor, and, or */
            CC = 0;
            switch(FC) {                            /* adjust for hw or bytes */
            case 4: case 5: case 6: case 7:         /* byte address */
                /* ORMB */
                td &= 0xff;                         /* mask out right most byte */
                dest &= 0xffffff00;                 /* make place for byte */
                dest |= td;                         /* insert result into dest */
                if (dest == 0)
                    CC |= CC4BIT;                   /* byte is zero, so CC4 */
                else
                if (dest & MSIGN) {
                    CC |= CC3BIT;                   /* assume negative */
                    dest |= D32LMASK;               /* force upper word to all ones */
                }
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            case 1:                                 /* left halfword addr */
            case 3:                                 /* right halfword addr */
                /* ORMH */
                td &= RMASK;                        /* mask out right most 16 bits */
                dest &= LMASK;                      /* make place for halfword */
                dest |= td;                         /* insert result into dest */
                if (dest == 0)
                    CC |= CC4BIT;                   /* byte is zero, so CC4 */
                else
                if (dest & MSIGN) {
                    CC |= CC3BIT;                   /* assume negative */
                    dest |= D32LMASK;               /* force upper word to all ones */
                }
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            case 0:                                 /* 32 bit word */
                /* ORMW */
                td &= D32RMASK;                     /* mask out right most 32 bits */
                dest = 0;                           /* make place for 64 bits */
                dest |= td;                         /* insert result into dest */
                if (dest == 0)
                    CC |= CC4BIT;                   /* byte is zero, so CC4 */
                else
                if (dest & MSIGN) {
                    CC |= CC3BIT;                   /* assume negative */
                    dest |= D32LMASK;               /* force upper word to all ones */
                }
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            case 2:                                 /* 64 bit double */
                /* ORMD */
                dest = 0;                           /* make place for 64 bits */
                dest |= td;                         /* insert result into dest */
                if (dest == 0)
                    CC |= CC4BIT;                   /* byte is zero, so CC4 */
                else
                if (dest & DMSIGN)
                    CC |= CC3BIT;                   /* assume negative */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
                break;
            }
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            PSD1 |= CC;                             /* update the CC's in the PSD */
            break;

        case 0x8C>>2:       /* 0x8C  SD|RR|RNX|ADR - SD|RNX|ADR */  /* EOMx */
            /* must special handle because we are getting bit difference */
            /* for word, halfword, & byte zero the upper 32 bits of dest */
            /* Diags require CC's to be set on result value of byte, hw, wd, or dw */
            td = dest ^ source;                     /* DO EOMX */
            goto meoa;
            break;

        case 0x90>>2:       /* 0x90 SCC|RR|RM|ADR - RM|ADR */   /* CAMx */
            if (dbl == 0) {
                int32a = dest & D32RMASK;           /* mask out right most 32 bits */
                int32b = source & D32RMASK;         /* mask out right most 32 bits */
                int32c = int32a - int32b;           /* signed diff */
                td = int32c;
                if (int32a > int32b) dest = 1;
                else
                if (int32a == int32b) dest = 0;
                else dest = -1;
            } else {
                int64a = dest;                      /* mask out right most 32 bits */
                int64b = source;                    /* mask out right most 32 bits */
                int64c = int64a - int64b;           /* signed diff */
                td = int64c;
                if (int64a > int64b) dest = 1;
                else
                if (int64a == int64b) dest = 0;
                else dest = -1;
            }
            break;

        case 0x94>>2:       /* 0x94 RR|RM|ADR - RM|ADR */   /* CMMx */
            /* CMMD needs both regs to be masked with R4 */
            if (dbl) {
                /* we need to and both regs with R4 */
                t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK);
                td = dest;                          /* save dest */
                dest ^= source;
                dest &= nm;                         /* mask both regs with reg 4 contents */
            } else {
                td = dest;                          /* save dest */
                dest ^= source;                     /* <= 32 bits, so just do lower 32 bits */
                dest &= (((t_uint64)GPR[4]) & D32RMASK);    /* mask with reg 4 contents */
            }           
            CC = 0;
            if (dest == 0ll)
                CC |= CC4BIT;
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            PSD1 |= CC;                             /* update the CC's in the PSD */
            break;

        case 0x98>>2:       /* 0x98 ADR - ADR */    /* SBM */
            if ((FC & 04) == 0)  {
                /* Fault, f-bit must be set for SBM instruction */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
#ifndef CPUONLY
            /* if we have an IPU set the semaphore or wait */
            if (CCW & HASIPU) {
#ifdef USE_POSIX_SEM
                set_simsem();
#else
                lock_mutex();
#endif
            }
#endif
            if ((TRAPME = Mem_read(addr, &temp)))   /* get the word from memory */
            {
#ifndef CPUONLY
                /* unlock the semaphore */
                if (CCW & HASIPU)
#ifdef USE_POSIX_SEM
                    clr_simsem();
#else
                    unlock_mutex();
#endif
#endif
                goto newpsd;                        /* memory read error or map fault */
            }
            t = (PSD1 & 0x70000000) >> 1;           /* get old CC bits 1-3 into CCs 2-4*/
            /* use C bits and bits 6-8 (reg) to generate shift bit count */
            bc = ((FC & 3) << 3) | reg;             /* get # bits to shift right */
            bc = BIT0 >> bc;                        /* make a bit mask of bit number */
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            if (temp & bc)                          /* test the bit in memory */
                t |= CC1BIT;                        /* set CC1 to the bit value */
            PSD1 |= t;                              /* update the CC's in the PSD */
            temp |= bc;                             /* set the bit in temp */
            if ((TRAPME = Mem_write(addr, &temp))) {  /* put word back into memory */
#ifndef CPUONLY
                /* unlock the semaphore */
                if (CCW & HASIPU)
#ifdef USE_POSIX_SEM
                    clr_simsem();
#else
                    unlock_mutex();
#endif
#endif
                goto newpsd;                        /* memory write error or map fault */
            }
#ifndef CPUONLY
            /* unlock the semaphore */
            if (CCW & HASIPU)
#ifdef USE_POSIX_SEM
                clr_simsem();
#else
                unlock_mutex();
#endif
#endif
                sim_debug(DEBUG_IRQ, my_dev,
                    "SBM @ PSD %08x %08x bit %08x addr %06x CCs %08x\r\n",
                    PSD1, PSD2, bc, addr, PSD1 & 0x78000000);
            break;
                  
        case 0x9C>>2:       /* 0x9C ADR - ADR */    /* ZBM */
            if ((FC & 04) == 0)  {
                /* Fault, byte address not allowed */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
#ifndef CPUONLY
            /* if we have an IPU set the semaphore or wait */
            if (CCW & HASIPU) {
#ifdef USE_POSIX_SEM
                set_simsem();
#else
                lock_mutex();
#endif
            }
#endif
            if ((TRAPME = Mem_read(addr, &temp)))   /* get the word from memory */
            {
#ifndef CPUONLY
                /* unlock the semaphore */
                if (CCW & HASIPU)
#ifdef USE_POSIX_SEM
                    clr_simsem();
#else
                    unlock_mutex();
#endif
#endif
                goto newpsd;                        /* memory read error or map fault */
            }

            t = (PSD1 & 0x70000000) >> 1;           /* get old CC bits 1-3 into CCs 2-4*/
            /* use C bits and bits 6-8 (reg) to generate shift bit count */
            bc = ((FC & 3) << 3) | reg;             /* get # bits to shift right */
            bc = BIT0 >> bc;                        /* make a bit mask of bit number */
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            if (temp & bc)                          /* test the bit in memory */
                t |= CC1BIT;                        /* set CC1 to the bit value */
            PSD1 |= t;                              /* update the CC's in the PSD */
            temp &= ~bc;                            /* reset the bit in temp */
            if ((TRAPME = Mem_write(addr, &temp))) {  /* put word into memory */
#ifndef CPUONLY
                /* unlock the semaphore */
                if (CCW & HASIPU)
#ifdef USE_POSIX_SEM
                    clr_simsem();
#else
                    unlock_mutex();
#endif
#endif
                goto newpsd;                        /* memory write error or map fault */
            }
#ifndef CPUONLY
            /* unlock the semaphore */
            if (CCW & HASIPU)
#ifdef USE_POSIX_SEM
                clr_simsem();
#else
                unlock_mutex();
#endif
#endif
                sim_debug(DEBUG_IRQ, my_dev,
                    "ZBM @ PSD %08x %08x bit %08x addr %06x CCs %08x\r\n",
                    PSD1, PSD2, bc, addr, PSD1 & 0x78000000);
            break;

        case 0xA0>>2:       /* 0xA0 ADR - ADR */    /* ABM */
            if ((FC & 04) == 0)  {
                /* Fault, byte address not allowed */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if ((TRAPME = Mem_read(addr, &temp)))   /* get the word from memory */
                goto newpsd;                        /* memory read error or map fault */

            /* use C bits and bits 6-8 (reg) to generate shift bit count */
            bc = ((FC & 3) << 3) | reg;             /* get # bits to shift right */
            bc = BIT0 >> bc;                        /* make a bit mask of bit number */
            t = (temp & FSIGN) != 0;                /* set flag for sign bit not set in temp value */
            t |= ((bc & FSIGN) != 0) ? 2 : 0;       /* ditto for the bit value */
            temp += bc;                             /* add the bit value to the reg */
            /* if both signs are neg and result sign is positive, overflow */
            /* if both signs are pos and result sign is negative, overflow */
            if ((t == 3 && (temp & FSIGN) == 0) ||
                (t == 0 && (temp & FSIGN) != 0)) {
                ovr = 1;                            /* we have an overflow */
            }
            set_CCs(temp, ovr);                     /* set the CC's, CC1 = ovr */
            if ((TRAPME = Mem_write(addr, &temp))) {    /* put word into memory */
                goto newpsd;                        /* memory write error or map fault */
            }
            /* the arithmetic exception will be handled */
            /* after instruction is completed */
            /* check for arithmetic exception trap enabled */
            if (ovr && (MODES & AEXPBIT)) {
                TRAPME = AEXPCEPT_TRAP;             /* set the trap type */
                goto newpsd;                        /* handle trap */
            }
            break;

        case 0xA4>>2:       /* 0xA4 ADR - ADR */    /* TBM */
            if ((FC & 04) == 0)  {
                /* Fault, byte address not allowed */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if ((TRAPME = Mem_read(addr, &temp)))   /* get the word from memory */
                goto newpsd;                        /* memory read error or map fault */

            t = (PSD1 & 0x70000000) >> 1;           /* get old CC bits 1-3 into CCs 2-4*/
            /* use C bits and bits 6-8 (reg) to generate shift bit count */
            bc = ((FC & 3) << 3) | reg;             /* get # bits to shift right */
            bc = BIT0 >> bc;                        /* make a bit mask of bit number */
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            if (temp & bc)                          /* test the bit in memory */
                t |= CC1BIT;                        /* set CC1 to the bit value */
            PSD1 |= t;                              /* update the CC's in the PSD */
            break;

        case 0xA8>>2:       /* 0xA8 RM|ADR - RM|ADR */ /* EXM */
            if ((FC & 04) != 0 || FC == 2) {        /* can not be byte or doubleword */
                /* Fault */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
                if (CPU_MODEL == MODEL_V9)          /* V9 wants bit0 set in pfault */
                    if (TRAPME == DMDPG)            /* demand page request */
                        pfault |= 0x80000000;       /* set instruction fetch paging error */
                goto newpsd;                        /* memory read error or map fault */
            }

            IR = temp;                              /* get instruction from memory */
            if (FC == 3)                            /* see if right halfword specified */
                IR <<= 16;                          /* move over the HW instruction */
            if (IPU_MODEL && (CPUSTATUS & ONIPU)) {
                /* on IPU :  */
                sim_debug(DEBUG_INST, my_dev,
                    "IPU EXM IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n",
                    IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                if ((IR & 0xFC000000) == 0xFC000000 ||  /* No I/O targets */
                    (IR & 0xFFFF0000) == 0x00060000) {  /* No BEI target */
                    TRAPME = IPUUNDEFI_TRAP;
                    i_flags |= BT;                  /* leave PC unchanged, so no PC update */
                    goto newpsd;
                }
            } else {
                sim_debug(DEBUG_INST, my_dev,
                    "CPU EXM IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n",
                    IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
            }
#ifdef DIAG_SAYS_OK_TO_EXECUTE_ANOTHER_EXECUTE
            /* 32/67 diag says execute of execute is OK */
            if ((IR & 0xFC7F0000) == 0xC8070000 ||  /* No EXR target */
                (IR & 0xFF800000) == 0xA8000000) {  /* No EXM target */
                /* Fault, attempt to execute another EXR, EXRR, or EXM  */
                goto inv;                           /* invalid instruction */
            }
#endif
            goto dohist;                            /* merge with EXR code */
            break;
 
        case 0xAC>>2:       /* 0xAC SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* Lx */
            dest = source;                          /* set value to load into reg */
            break;

        case 0xB0>>2:       /* 0xB0 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* LMx */
            /* LMD needs both regs to be masked with R4 */
            if (dbl) {
                /* we need to and both regs with R4 */
                t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK);
                dest = source & nm;                 /* mask both regs with reg 4 contents */
            } else {
                dest = source;                      /* <= 32 bits, so just do lower 32 bits */
                dest &= (((t_uint64)GPR[4]) & D32RMASK);    /* mask with reg 4 contents */
                if (dest & 0x80000000)              /* see if we need to sign extend */
                    dest |= D32LMASK;               /* force upper word to all ones */
            }           
            break;
 
        case 0xB4>>2:       /* 0xB4 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* LNx */
            dest = NEGATE32(source);                /* set the value to load into reg */
            td = dest;
            if (dest != 0 && (dest == source || dest == 0x80000000))
                ovr = 1;                            /* set arithmetic exception status */
            if (FC != 2) {                          /* do not sign extend DW */
                if (dest & 0x80000000)              /* see if we need to sign extend */
                    dest |= D32LMASK;               /* force upper word to all ones */
            }
            /* the arithmetic exception will be handled */
            /* after instruction is completed */
            /* check for arithmetic exception trap enabled */
            if (dest != 0 && ovr && (MODES & AEXPBIT)) {
                TRAPME = AEXPCEPT_TRAP;             /* set the trap type */
            }
            break;

        case 0xBC>>2:       /* 0xBC SD|RR|RM|ADR - SD|RR|RM|ADR */ /* SUMx */
            source = NEGATE32(source);
            /* Fall through */

        case 0xB8>>2:       /* 0xB8 SD|RR|RM|ADR - SD|RR|RM|ADR */ /* ADMx */
            ovr = 0;
            CC = 0;
            /* DIAG fixs */
            if (dbl == 0) {
                source &= D32RMASK;                 /* just 32 bits */
                dest &= D32RMASK;                   /* just 32 bits */
                t = (source & MSIGN) != 0;
                t |= ((dest & MSIGN) != 0) ? 2 : 0;
                td = dest + source;                 /* DO ADMx*/
                td &= D32RMASK;                     /* mask out right most 32 bits */
                dest = 0;                           /* make place for 64 bits */
                dest |= td;                         /* insert 32 bit result into dest */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if (((t == 3) && ((dest & MSIGN) == 0)) || 
                    ((t == 0) && ((dest & MSIGN) != 0)))
                    ovr = 1;
                if ((td == 0) && ((source & MSIGN) == MSIGN) && ovr)
                    ovr = 0;                        /* Diags want 0 and no ovr on MSIGN - MSIGN */
                if (dest & MSIGN)
                    dest = (D32LMASK | dest);       /* sign extend */
                else
                    dest = (D32RMASK & dest);       /* zero fill */
                if (td == 0)
                    CC |= CC4BIT;                   /* word is zero, so CC4 */
                else
                if (td & 0x80000000)
                    CC |= CC3BIT;                   /* it is neg wd, so CC3  */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
            } else {
                /* ADMD */
                t = (source & DMSIGN) != 0;
                t |= ((dest & DMSIGN) != 0) ? 2 : 0;
                td = dest + source;                 /* get sum */
                dest = td;                          /* insert 64 bit result into dest */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if (((t == 3) && ((dest & DMSIGN) == 0)) || 
                    ((t == 0) && ((dest & DMSIGN) != 0)))
                    ovr = 1;
                if (td == 0)
                    CC |= CC4BIT;                   /* word is zero, so CC4 */
                else
                if (td & DMSIGN)
                    CC |= CC3BIT;                   /* it is neg wd, so CC3  */
                else
                    CC |= CC2BIT;                   /* then td > 0, so CC2 */
            }
            if (ovr)
                CC |= CC1BIT;                       /* set overflow CC */
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            PSD1 |= CC;                             /* update the CC's in the PSD */

            /* the arithmetic exception will be handled */
            /* after instruction is completed */
            /* check for arithmetic exception trap enabled */
            if (ovr && (MODES & AEXPBIT)) {
                TRAPME = AEXPCEPT_TRAP;             /* set the trap type */
            }
            break;

        case 0xC0>>2:       /* 0xC0 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* MPMx */
            if (reg & 1) {                          /* see if odd reg specified */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if (FC == 2) {                          /* must not be double word adddress */
                TRAPME = ADDRSPEC_TRAP;             /* bad address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            td = dest;
            dest = GPR[reg+1];                      /* get low order reg value */
            if (dest & MSIGN)
                dest = (D32LMASK | dest);           /* sign extend */
            dest = (t_uint64)((t_int64)dest * (t_int64)source);
            dbl = 1;
            break;

        case 0xC4>>2:       /* 0xC4 RM|ADR - RM|ADR */  /* DVMx */
            if (reg & 1) {                          /* see if odd reg specified */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if (FC == 2) {                          /* must not be double word adddress */
                TRAPME = ADDRSPEC_TRAP;             /* bad address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            if (source == 0)
                goto doovr;                         /* we have div by zero */
            dest = (((t_uint64)GPR[reg]) << 32);    /* insert upper reg value */
            dest |= (t_uint64)GPR[reg+1];           /* get low order reg value */
            td = ((t_int64)dest % (t_int64)source); /* remainder */
            if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
                td = NEGATE32(td);                  /* dividend and remainder must be same sign */
            dest = (t_int64)dest / (t_int64)source; /* now do the divide */
            int64a = dest;
            if (int64a < 0)
                int64a = -int64a;
            if (int64a > 0x7fffffff)                /* if more than 31 bits, we have an error */
                goto doovr;
            if (((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) ||
                (((dest & D32LMASK) == D32LMASK) && ((dest & D32RMASK) == 0))) {  /* test for overflow */
doovr:
                dest = (((t_uint64)GPR[reg]) << 32);/* insert upper reg value */
                dest |= (t_uint64)GPR[reg+1];       /* get low order reg value */
                ovr = 1;                            /* the quotient exceeds 31 bit, overflow */
                /* the original regs must be returned unchanged if aexp */
                CC = CC1BIT;                        /* set ovr CC bit */
                if (dest == 0)
                    CC |= CC4BIT;                   /* dw is zero, so CC4 */
                else
                if (dest & DMSIGN)
                    CC |= CC3BIT;                   /* it is neg dw, so CC3  */
                else
                    CC |= CC2BIT;                   /* then dest > 0, so CC2 */
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's from PSD1 */
                PSD1 |= CC;                         /* update the CC's in the PSD */
                /* the arithmetic exception will be handled */
                /* after instruction is completed */
                /* check for arithmetic exception trap enabled */
                if (MODES & AEXPBIT)
                    TRAPME = AEXPCEPT_TRAP;         /* set the trap type */
            } else {
                GPR[reg] = (uint32)(td & FMASK);    /* reg gets remainder, reg+1 quotient */
                GPR[reg+1] = (uint32)(dest & FMASK);    /* store quotient in reg+1 */
                set_CCs(GPR[reg+1], ovr);           /* set the CC's, CC1 = ovr */
            }
            break;

        case 0xC8>>2:       /* 0xC8 IMM - IMM */    /* Immedate */
            temp = GPR[reg];                        /* get reg contents */
            addr = IR & RMASK;                      /* sign extend 16 bit imm value from IR */
            if (addr & 0x8000)                      /* negative */
                addr |= LMASK;                      /* extend sign */

            switch(OPR & 0xF) {                     /* switch on aug code */
            case 0x0:       /* LI */                /* SCC | SD */
                GPR[reg] = addr;                    /* put immediate value into reg */
                set_CCs(addr, ovr);                 /* set the CC's, CC1 = ovr */
                break;

            case 0x2:       /* SUI */
                addr = NEGATE32(addr);              /* just make value a negative add */
                /* drop through */
            case 0x1:       /* ADI */
               t = (temp & FSIGN) != 0;             /* set flag for sign bit not set in reg value */
               t |= ((addr & FSIGN) != 0) ? 2 : 0;  /* ditto for the extended immediate value */
               temp = temp + addr;                  /* now add the numbers */
               /* if both signs are neg and result sign is positive, overflow */
               /* if both signs are pos and result sign is negative, overflow */
               if ((t == 3 && (temp & FSIGN) == 0) ||
                    (t == 0 && (temp & FSIGN) != 0))
                    ovr = 1;                        /* we have an overflow */
               GPR[reg] = temp;                     /* save the result */
               set_CCs(temp, ovr);                  /* set the CC's, CC1 = ovr */
               /* the arithmetic exception will be handled */
               /* after instruction is completed */
               /* check for arithmetic exception trap enabled */
               if (ovr && (MODES & AEXPBIT)) {
                   TRAPME = AEXPCEPT_TRAP;          /* set the trap type */
                   goto newpsd;                     /* go execute the trap now */
                }
                break;

            case 0x3:       /* MPI */
                if (reg & 1) {                      /* see if odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                /* change immediate value into a 64 bit value */
                source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
                temp = GPR[reg+1];                  /* get reg multiplier */
                dest = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0);
                dest = dest * source;               /* do the multiply */
                i_flags |= (SD|SCC);                /* save regs and set CC's */
                dbl = 1;                            /* double reg save */
                break;

            case 0x4:       /* DVI */
                if (reg & 1) {                      /* see if odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                /* change immediate value into a 64 bit value */
                source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
                if (source == 0) {
                    goto doovr2;
                }
                dest = (((t_uint64)GPR[reg]) << 32);    /* get upper reg value */
                dest |= (t_uint64)GPR[reg+1];       /* insert low order reg value */
                td = ((t_int64)dest % (t_int64)source); /* remainder */
                /* fix double reg if neg remainder */
                if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
                    td = NEGATE32(td);              /* dividend and remainder must be same sign */
                dest = (t_int64)dest / (t_int64)source; /* now do the divide */
                int64a = dest;
                if (int64a < 0)
                    int64a = -int64a;
                if (int64a > 0x7fffffff)            /* if more than 31 bits, we have an error */
                    goto doovr2;
                if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) {  /* test for overflow */
doovr2:
                    dest = (((t_uint64)GPR[reg]) << 32);    /* get upper reg value */
                    dest |= (t_uint64)GPR[reg+1];   /* insert low order reg value */
                    ovr = 1;                        /* the quotient exceeds 31 bit, overflow */
                    /* the arithmetic exception will be handled */
                    /* after instruction is completed */
                    /* check for arithmetic exception trap enabled */
                    if (MODES & AEXPBIT)
                        TRAPME = AEXPCEPT_TRAP;     /* set the trap type */
                    /* the original regs must be returned unchanged if aexp */
                    /* put reg values back in dest for CC test */
                    CC = CC1BIT;                    /* set ovr CC bit */
                    if (dest == 0)
                        CC |= CC4BIT;               /* dw is zero, so CC4 */
                    else
                    if (dest & DMSIGN)
                        CC |= CC3BIT;               /* it is neg dw, so CC3  */
                    else
                        CC |= CC2BIT;               /* then dest > 0, so CC2 */
                    PSD1 &= 0x87FFFFFE;             /* clear the old CC's from PSD1 */
                    PSD1 |= CC;                     /* update the CC's in the PSD */
                } else {
                    GPR[reg] = (uint32)(td & FMASK);    /* reg gets remainder, reg+1 quotient */
                    GPR[reg+1] = (uint32)(dest & FMASK);    /* store quotient in reg+1 */
                    set_CCs(GPR[reg+1], ovr);       /* set the CC's, CC1 = ovr */
                }
                break;

            case 0x5:       /* CI */    /* SCC */
                temp = ((int)temp - (int)addr);     /* subtract imm value from reg value */
                set_CCs(temp, ovr);                 /* set the CC's, CC1 = ovr */
                break;

/* SVC instruction format C806 */
/* |-------+-------+-------+-------+-------+-------+-------+-------| */
/* |0 0 0 0 0 0|0 0 0|0 1 1|1 1 1 1|1 1 1 1|2 2 2 2 2 2 2 2 2 2 3 3| */
/* |0 1 2 3 4 5|6 7 8|8 0 1|2 3 4 5|6 7 8 9|0 1 2 3 4 5 6 7 8 9 0 1| */
/* |  Op Code  | N/U | N/U |  Aug  |SVC num|    SVC Call Number    | */
/* |1 1 0 0 1 0|0 0 0|0 0 0|0 1 1 0|x x x x|x x x x x x x x x x x x| */
/* |-------+-------+-------+-------+-------+-------+-------+-------| */
/* */
            case 0x6:       /* SVC  none - none */  /* Supervisor Call Trap */
            {
                int32c = CPUSTATUS;                 /* keep for retain blocking state */
                addr = SPAD[0xf0];                  /* get trap table memory addr from SPAD (def 80, 20) */
                int32a = addr;
                if (addr == 0 || ((addr&MASK24) == MASK24)) {  /* see if secondary vector table set up */
                    TRAPME = ADDRSPEC_TRAP;         /* Not setup, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPECS1 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* program error */
                }
                addr = addr + (0x06 << 2);          /* addr has mem addr of SVC trap vector (def 98, 38) */
                temp = M[addr >> 2];                /* get the secondary trap table address from memory */
                if (temp == 0 || ((temp&MASK24) == MASK24)) {  /* see if ICB set up */
                    TRAPME = ADDRSPEC_TRAP;         /* Not setup, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPECS2 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* program error */
                }
                temp2 = ((IR>>12) & 0x0f) << 2;     /* get SVC index from IR */
                t = M[(temp+temp2)>>2];             /* get secondary trap vector address ICB address */
                if (t == 0 || ((t&MASK24) == MASK24)) {  /* see if ICB set up */
                    TRAPME = ADDRSPEC_TRAP;         /* Not setup, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPECS3 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* program error */
                }
                bc = PSD2 & 0x3ff8;                 /* get copy of cpix */
                M[t>>2] = (PSD1+4) & 0xfffffffe;    /* store PSD 1 + 1W to point to next instruction */
                M[(t>>2)+1] = PSD2;                 /* store PSD 2 */
                M[(t>>2)+4] = IR&0xFFF;             /* store call number */
                TPSD1 = PSD1;                       /* save the PSD for the instruction */
                TPSD2 = PSD2;
                PSD1 = M[(t>>2)+2];                 /* get new PSD 1 */
                PSD2 = (M[(t>>2)+3] & ~0x3ff8) | bc; /* get new PSD 2 w/old cpix */
                PSD2 &= ~RETMBIT;                   /* turn off retain bit in PSD2 */

                if (PSD2 & MAPBIT) {                /* see if new PSD is mapped */
                    uint32  mpl = SPAD[0xf3];       /* get mpl from spad address */
                    uint32  osmidl = RMW(mpl);      /* get midl entry for O/S */
                    uint32  MAXMAP = MAX2048;       /* default to 2048 maps */

                    if (CPU_MODEL < MODEL_27)
                        MAXMAP = MAX32;             /* 32 maps for 32/77 */
                    if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87))
                        MAXMAP = MAX256;            /* only 256 2KW (8kb) maps */

                    /* New PSD is mapped, check for valid msd and mpl counts */
                    if ((mpl != 0) && (osmidl != 0) && ((osmidl & MASK16) <= MAXMAP)) {
                        sim_debug(DEBUG_TRAP, my_dev,
                    "OK SVC %x,%x @ %.8x %.8x mpl %.6x osmidl %06x MAPS %04x MAXMAPS %04x\n",
                    temp2>>2, IR&0xFFF, TPSD1, TPSD2, mpl, osmidl, osmidl & MASK16, MAXMAP);
                        sim_debug(DEBUG_TRAP, my_dev,
                    "OK SVC %x,%x @ %.8x %.8x PSD %.8x %.8x SPADF5 PSD2 %x CPUSTATUS %08x\n",
                    temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                    } else {
                        sim_debug(DEBUG_TRAP, my_dev,
                    "Error SVC %x,%x @ %.8x %.8x mpl %.6x osmidl %06x MAPS %04x MAXMAPS %04x\n",
                    temp2>>2, IR&0xFFF, TPSD1, TPSD2, mpl, osmidl, osmidl & MASK16, MAXMAP);
                        sim_debug(DEBUG_TRAP, my_dev,
                    "Error SVC %x,%x @ %.8x %.8x PSD %.8x %.8x SPADF5 PSD2 %x CPUSTATUS %08x\n",
                    temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                        TRAPME = MACHINECHK_TRAP;   /* trap condition */
                        PSD1 = TPSD1;               /* restore PSD 1 */
                        PSD2 = PSD2;                /* diag wants new PSD 2, not old?? */
                        goto newpsd;                /* program error */
                    }
                }
                sim_debug(DEBUG_TRAP, my_dev,
                    "SVC %x,%x @ %.8x %.8x NPSD %.8x %.8x SPADF5 %x CPUSTATUS %08x\n",
                    temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                sim_debug(DEBUG_TRAP, my_dev,
                    "   R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]);
                sim_debug(DEBUG_TRAP, my_dev,
                    "   R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
#ifdef FOR_DEBUG_SVC
                bc = 0;
                addr = GPR[1] & 0xffffff;
                RealAddr(addr, &t, &bc, MEM_RD);
                sim_debug(DEBUG_TRAP, my_dev,
                    "SVC addr %x raddr %x GPR[1] %x\n", addr, t, GPR[1]);
                fflush(sim_deb);
#endif
                /* test for retain blocking state */
                if (PSD2 & RETBBIT) {               /* is it retain blocking state */
                    /* BIT 49 has new blocking state */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        PSD2 |= SETBBIT;            /* yes, set to blocked state */
                        MODES |= BLKMODE;           /* set blocked mode */
                        CPUSTATUS |= BIT24;         /* set blocked mode */
                    } else {
                        PSD2 &= ~SETBBIT;           /* set to unblocked state */
                        MODES &= ~RETMODE;          /* reset retain block mode bit */
                        CPUSTATUS &= ~BIT24;        /* reset block state in cpu status bit 8 */
                    }
                    PSD2 &= ~RETBBIT;               /* clear bit 48 retain blocking bit */
                }

                /* set the mode bits and CCs from the new PSD */
                CC = PSD1 & 0x78000000;             /* extract bits 1-4 from PSD1 */
                MODES = PSD1 & 0x87000000;          /* extract bits 0, 5, 6, 7 from PSD 1 */
                MODES &= ~RETMODE;                  /* reset retain map mode bit in status */
                CPUSTATUS &= ~0x87000000;           /* reset bits in CPUSTATUS */
                CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */

                if (PSD2 & SETBBIT) {               /* is it set blocking state bit 49 set*/
                    /* set new blocking state bit 49=1 */
                    CPUSTATUS |= BIT24;             /* yes, set blk state in cpu status bit 24 */
                    MODES |= BLKMODE;               /* set blocked mode */
                } else {
                    CPUSTATUS &= ~BIT24;            /* reset block state in cpu status bit 8 */
                    MODES &= ~BLKMODE;              /* reset block mode bits */
                }

                /* bit 0 of PSD wd 2 sets new mapping state */
                if (PSD2 & MAPBIT) {
                    CPUSTATUS |= BIT8;              /* set bit 8 of cpu status to mapped */
                    MODES |= MAPMODE;               /* set mapped mode */
                } else {
                    CPUSTATUS &= ~BIT8;             /* reset bit 8 of cpu status */
                    MODES &= ~MAPMODE;              /* reset mapped mode */
                }

                if ((PSD2 & SETBBIT) == 0) {        /* see if new mode is unblocked */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        /* we changed from blocked to unblocked */
                        if (!(CPUSTATUS & ONIPU))
                            irq_pend = 1;           /* start scanning interrupts again */
                    }
                }

                sim_debug(DEBUG_TRAP, my_dev,
                    "SVCX %x,%x @ %.8x %.8x NPSD %.8x %.8x SPADF5 %x CPUSTATUS %08x\n",
                    temp2>>2, IR&0xFFF, OPSD1, OPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                sim_debug(DEBUG_TRAP, my_dev,
                    "   R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]);
                sim_debug(DEBUG_TRAP, my_dev,
                    "   R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                TRAPME = 0;                         /* not to be processed as trap */
                drop_nop = 0;                       /* nothing to drop */
                i_flags |= BT;                      /* do not update pc */
            }
            break;

            case 0x7:       /* EXR */
                IR = temp;                          /* get instruction to execute */
                /* if bit 30 set, instruction is in right hw, do EXRR */
                if (addr & 2)
                    IR <<= 16;                      /* move instruction to left HW */
                if (IPU_MODEL && (CPUSTATUS & ONIPU)) {
                    /* on IPU :  */
                    sim_debug(DEBUG_INST, my_dev,
                        "IPU EXR IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n",
                        IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                    if ((IR & 0xFC000000) == 0xFC000000 ||  /* No I/O targets */
                        (IR & 0xFFFF0000) == 0x00060000) {  /* No BEI target */
                        TRAPME = IPUUNDEFI_TRAP;
                        i_flags |= BT;              /* leave PC unchanged, so no PC update */
                        goto newpsd;
                    }
                }
#ifndef USE_IPU_THREAD
                else {
                    sim_debug(DEBUG_INST, my_dev,
                        "CPU EXR IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n",
                        IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                }
#endif
#ifdef DIAG_SAYS_OK_TO_EXECUTE_ANOTHER_EXECUTE
                /* 32/67 diag says execute of execute is OK */
                if ((IR & 0xFC7F0000) == 0xC8070000 ||
                    (IR & 0xFF800000) == 0xA8000000) {
                    /* Fault, attempt to execute another EXR, EXRR, or EXM  */
                    goto inv;                       /* invalid instruction */
                }
#endif
dohist:
                EXM_EXR = 4;                        /* set PC increment for EXR/EXP */
                OPSD1 &= 0x87FFFFFE;                /* clear the old CC's */
                OPSD1 |= PSD1 & 0x78000000;         /* update the CC's in the PSD */
                /* TODO Update other history information for this instruction */
                if (hst_lnt) {
                    hst[hst_p].opsd1 = OPSD1;       /* update the CC in opsd1 */
                    hst[hst_p].npsd1 = PSD1;        /* save new psd1 */
                    hst[hst_p].npsd2 = PSD2;        /* save new psd2 */
                    hst[hst_p].modes = MODES;       /* save current mode bits */
                    hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */
                    if (CPUSTATUS & BIT24)
                        hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */
                    if (CPUSTATUS & BIT27)
                        hst[hst_p].modes |= IPUMODE; /* save cpu/ipu status bit */
                    for (ix=0; ix<8; ix++) {
                        hst[hst_p].reg[ix] = GPR[ix];   /* save reg */
                        hst[hst_p].reg[ix+8] = BR[ix];  /* save breg */
                    }
                }
                /* DEBUG_INST support code */
                OPSD1 &= 0x87FFFFFE;                /* clear the old CC's */
                OPSD1 |= PSD1 & 0x78000000;         /* update the CC's in the PSD */
                /* output mapped/unmapped */
                if (MODES & BASEBIT)
                    BM = 'B';
                else
                    BM = 'N';
                if (MODES & MAPMODE)
                    MM = 'M';
                else
                    MM = 'U';
                if (CPUSTATUS & BIT24)
                    BK = 'B';
                else
                    BK = 'U';
                sim_debug(DEBUG_INST, my_dev, "%s %c%c%c %.8x %.8x %.8x ",
                    (CPUSTATUS & BIT27) ? "IPU": "CPU",
                    BM, MM, BK, OPSD1, PSD2, OIR);
                sim_debug(DEBUG_INST, my_dev, "%c%c%c %.8x %.8x %.8x ",
                    BM, MM, BK, OPSD1, PSD2, OIR);
                if (cpu_dev.dctrl & DEBUG_INST) {
                    fprint_inst(sim_deb, OIR, 0);   /* display instruction */
                sim_debug(DEBUG_INST, my_dev,
                    "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
                sim_debug(DEBUG_INST, my_dev,
                    " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
                    if (MODES & BASEBIT) {
                        sim_debug(DEBUG_INST, my_dev,
                            "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]);
                        sim_debug(DEBUG_INST, my_dev,
                            " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]);
                    }
                }
                goto exec;                          /* go execute the instruction */
                break;

            /* these instruction were never used by MPX, only diags */
            /* diags treat them as invalid halfword instructions */
            /* so set the HLF flag to get proper PC increment */
            case 0x8:                               /* SEM */
            case 0x9:                               /* LEM */
            case 0xA:                               /* CEMA */
            case 0xB:                               /* INV */
            case 0xC:                               /* INV */
            case 0xD:                               /* INV */
            case 0xE:                               /* INV */
            case 0xF:                               /* INV */
            default:
                goto inv;                           /* invalid instruction */
                break;
            }
            break;

        case 0xCC>>2:       /* 0xCC ADR - ADR */    /* LF */
            /* For machines with Base mode 0xCC08 stores base registers */
            if ((FC & 3) != 0) {                    /* must be word address */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                sim_debug(DEBUG_TRAP, my_dev,
                    "ADDRSPECS4 OP %04x addr %08x\n", OP, addr);
                goto newpsd;                        /* go execute the trap now */
            }
            temp = addr & 0xffe000;                 /* get 11 bit map # */
            bc = addr & 0x20;                       /* bit 26 initial value */
            while (reg < 8) {
                if (bc != (addr & 0x20)) {          /* test for crossing file boundry */
                    if (CPU_MODEL < MODEL_27) {
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPECS5 OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }
                }
                if (temp != (addr & 0xffe000)) {    /* test for crossing map boundry */
                    if (CPU_MODEL >= MODEL_V6) {
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "ADDRSPECS6 OP %04x addr %08x\n", OP, addr);
                        goto newpsd;                /* go execute the trap now */
                    }
                }
                if (FC & 0x4)                       /* LFBR? 0xCC08 */
                    TRAPME = Mem_read(addr, &BR[reg]);  /* read the base reg */
                else                                /* LF? 0xCC00 */
                    TRAPME = Mem_read(addr, &GPR[reg]); /* read the GPR reg */
                if (TRAPME)                         /* TRAPME has error */
                    goto newpsd;                    /* go execute the trap now */
                reg++;                              /* next reg to write */
                addr += 4;                          /* next addr */
            }
            break;

        case 0xD0>>2:       /* 0xD0 SD|ADR - INV */ /* LEA  none basemode only */
            if (MODES & BASEBIT) 
                goto inv;                           /* invalid instruction in basemode */
            /* bc has last bits 0,1 for indirect addr of both 1 for no indirection */
            addr &= 0x3fffffff;                     /* clear bits 0-1 */
            addr |= bc;                             /* insert bits 0,1 values into address */
            if (FC & 0x4)
                addr |= F_BIT;                      /* copy F bit from instruction */
            dest = (t_uint64)(addr);
            break;

        case 0xD4>>2:       /* 0xD4 RR|SM|ADR - RR|SM|ADR */ /* STx */
            break;

        case 0xD8>>2:       /* 0xD8 RR|SM|ADR - RR|SM|ADR */ /* STMx */
            /* STMD needs both regs to be masked with R4 */
            if (dbl) {
                /* we need to and both regs */
                t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK);
                dest &= nm;                         /* mask both regs with reg 4 contents */
            } else {
                dest &= (((t_uint64)GPR[4]) & D32RMASK);    /* mask with reg 4 contents */
            }           
            break;

        case 0xDC>>2:       /* 0xDC INV - ADR */    /* INV nonbasemode (STFx basemode) */
            /* DC00 STF */ /* DC08 STFBR */
            if ((FC & 0x4) && (CPU_MODEL <= MODEL_27))  {
                /* basemode undefined for 32/7x & 32/27 */
                TRAPME = UNDEFINSTR_TRAP;           /* Undefined Instruction Trap */
                goto newpsd;                        /* handle trap */
            }
            /* For machines with Base mode 0xDC08 stores base registers */
            if ((FC & 3) != 0) {                    /* must be word address */
                TRAPME = ADDRSPEC_TRAP;             /* bad reg address, error */
                goto newpsd;                        /* go execute the trap now */
            }
            bc = addr & 0x20;                       /* bit 26 initial value */
            temp = addr & 0xffe000;                 /* get 11 bit map # */
            while (reg < 8) {
                if (bc != (addr & 0x20)) {          /* test for crossing file boundry */
                    if (CPU_MODEL < MODEL_27) {
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        goto newpsd;                /* go execute the trap now */
                    }
                }
                if (temp != (addr & 0xffe000)) {    /* test for crossing map boundry */
                    if (CPU_MODEL >= MODEL_V6) {
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        goto newpsd;                /* go execute the trap now */
                    }
                }
                if (FC & 0x4)                       /* STFBR? */
                    TRAPME = Mem_write(addr, &BR[reg]);     /* store the base reg */
                else                                /* STF */
                    TRAPME = Mem_write(addr, &GPR[reg]);    /* store the GPR reg */
                if (TRAPME)                         /* TRAPME has error */
                    goto newpsd;                    /* go execute the trap now */
                reg++;                              /* next reg to write */
                addr += 4;                          /* next addr */
            }
            break;

        case 0xE0>>2:       /* 0xE0 ADR - ADR */    /* ADFx, SUFx */
                if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
                    goto newpsd;                    /* memory read error or map fault */
                }
                source = (t_uint64)temp;            /* make into 64 bit value */
                if (FC & 2) {                       /* see if double word addr */
                    if ((TRAPME = Mem_read(addr+4, &temp))) {   /* get the 2nd word from memory */
                        goto newpsd;                /* memory read error or map fault */
                    }
                    source = (source << 32) | (t_uint64)temp;   /* merge in the low order 32 bits */
                    dbl = 1;                        /* double word instruction */
                } else {
                    source |= (source & MSIGN) ? D32LMASK : 0;
                    dbl = 0;                        /* not double wd */
                }
                PSD1 &= 0x87FFFFFE;                 /* clear the old CC's */
                CC = 0;                             /* clear the CC'ss */
                /* handle float or double add/sub instructions */
                if (dbl == 0) {
                    /* do ADFW or SUFW instructions */
                    temp2 = GPR[reg];               /* dest - reg contents specified by Rd */
                    addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */
                    if ((OPR & 8) == 0) {           /* Was it SUFW? */
                        addr = NEGATE32(addr);      /* take negative for add */
                    }
                    temp = s_adfw(temp2, addr, &CC);    /* do ADFW */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "%s GPR[%d] %08x addr %08x result %08x CC %08x\n",
                        (OPR&8) ? "ADFW":"SUFW", reg, GPR[reg], addr, temp, CC);
                    ovr = 0;
                    if (CC & CC1BIT)
                        ovr = 1;
                    PSD1 |= (CC & 0x78000000);      /* update the CC's in the PSD */
                    /* check if we had an arithmetic exception on the last instruction*/
                    if (ovr && (MODES & AEXPBIT)) {
                        /* leave regs unchanged */
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                    /* AEXP not enabled, so apply fix here */
                    /* return temp to destination reg */
                    GPR[reg] = temp;                /* dest - reg contents specified by Rd */
                } else {
                    /* handle ADFD or SUFD */
                    if (reg & 1) {                  /* see if odd reg specified */
                        TRAPME = ADDRSPEC_TRAP;     /* bad reg address, error */
                        goto newpsd;                /* go execute the trap now */
                    }
                    /* do ADFD or SUFD instructions */
                    td = (((t_uint64)GPR[reg]) << 32);  /* get upper reg value */
                    td |= (t_uint64)GPR[reg+1];     /* insert low order reg value */
                    /* source has 64 bit memory data */
                    if ((OPR & 8) == 0) {           /* Was it SUFD? */
                        source = NEGATE32(source);  /* make negative for subtract */
                    }
                    dest = s_adfd(td, source, &CC); /* do ADFD */
                    sim_debug(DEBUG_DETAIL, my_dev,
                        "%s GPR[%d] %08x %08x src %016llx result %016llx CC %08x\n",
                        (OPR&8) ? "ADFD":"SUFD", reg, GPR[reg], GPR[reg+1], source, dest, CC);
                    ovr = 0;
                    if (CC & CC1BIT)                /* test for overflow detection */
                        ovr = 1;
                    PSD1 |= (CC & 0x78000000);      /* update the CC's in the PSD */
                    /* check if we had an arithmetic exception on the last instruction */
                    if (ovr && (MODES & AEXPBIT)) {
                        /* leave regs unchanged */
                        TRAPME = AEXPCEPT_TRAP;     /* trap the system now */
                        goto newpsd;                /* process the trap */
                    }
                    /* dest will be returned to destination regs */
                    /* if AEXP not enabled, apply fix here */
                    /* return dest to destination reg */
                    GPR[reg] = (uint32)((dest & D32LMASK) >> 32);   /* get upper reg value */
                    GPR[reg+1] = (uint32)(dest & D32RMASK); /* get lower reg value */
                }
                break;

        case 0xE4>>2:       /* 0xE4 ADR - ADR */    /* MPFx, DVFx */
            if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
                goto newpsd;                        /* memory read error or map fault */
            }
            source = (t_uint64)temp;                /* make into 64 bit value */
            if (FC & 2) {                           /* see if double word addr */
                if ((TRAPME = Mem_read(addr+4, &temp))) {   /* get the 2nd word from memory */
                    goto newpsd;                    /* memory read error or map fault */
                }
                source = (source << 32) | (t_uint64)temp;   /* merge in the low order 32 bits */
                dbl = 1;                            /* double word instruction */
            } else {
                source |= (source & MSIGN) ? D32LMASK : 0;
                dbl = 0;                            /* not double wd */
            }
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's */
            CC = 0;                                 /* clear the CC'ss */
            /* handle float or double mul/div instructions */
            if (dbl == 0) {
                /* do MPFW or DVFW instructions */
                temp2 = GPR[reg];                   /* dest - reg contents specified by Rd */
                addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */
                if (OPR & 8) {                      /* Was it MPFW? */
                    temp = s_mpfw(temp2, addr, &CC);    /* do MPFW */
                } else {
                    temp = (uint32)s_dvfw(temp2, addr, &CC);    /* do DVFW */
                }
                sim_debug(DEBUG_DETAIL, my_dev,
                    "%s GPR[%d] %08x addr %08x result %08x\n",
                    (OPR&8) ? "MPFW":"DVFW", reg, GPR[reg], addr, temp);
                if (CC & CC1BIT)
                    ovr = 1;
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                /* check if we had an arithmetic exception on the last instruction*/
                if (ovr && (MODES & AEXPBIT)) {
                    /* leave regs unchanged */
                    TRAPME = AEXPCEPT_TRAP;         /* trap the system now */
                    goto newpsd;                    /* process the trap */
                }
                /* if AEXP not enabled, apply fix here */
                /* return temp to destination reg */
                GPR[reg] = temp;                    /* dest - reg contents specified by Rd */
            } else {
                /* handle MPFD or DVFD */
                if (reg & 1) {                      /* see if odd reg specified */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    goto newpsd;                    /* go execute the trap now */
                }
                /* do MPFD or DVFD instructions */
                td = (((t_uint64)GPR[reg]) << 32);  /* get upper reg value */
                td |= (t_uint64)GPR[reg+1];         /* insert low order reg value */
                /* source has 64 bit memory data */
                if (OPR & 8) {                      /* Was it MPFD? */
                    dest = s_mpfd(td, source, &CC); /* do MPFD */
                } else {
                    dest = s_dvfd(td, source, &CC); /* do DVFD */
                }
                sim_debug(DEBUG_DETAIL, my_dev,
                    "%s GPR[%d] %08x %08x src %016llx result %016llx\n",
                    (OPR&8) ? "MPFD":"DVFD", reg, GPR[reg], GPR[reg+1], source, dest);
                if (CC & CC1BIT)                    /* test for overflow detection */
                    ovr = 1;
                PSD1 |= (CC & 0x78000000);          /* update the CC's in the PSD */
                /* check if we had an arithmetic exception on the last instruction*/
                if (ovr && (MODES & AEXPBIT)) {
                    /* leave regs unchanged */
                    TRAPME = AEXPCEPT_TRAP;         /* trap the system now */
                    goto newpsd;                    /* process the trap */
                }
                /* dest will be returned to destination regs */
                /* if AEXP not enabled, apply fix here */
                /* return dest to destination reg */
                GPR[reg] = (uint32)((dest & D32LMASK) >> 32);   /* get upper reg value */
                GPR[reg+1] = (uint32)(dest & D32RMASK); /* get lower reg value */
            }
            break;

        case 0xE8>>2:       /* 0xE8 SM|RR|RNX|ADR - SM|RM|ADR */ /* ARMx */
            ovr = 0;
            CC = 0;
            switch(FC) {                            /* adjust for hw or bytes */
            case 4: case 5: case 6: case 7:         /* byte address */
                /* ARMB */
                td = dest + source;                 /* DO ARMB */
                td &= 0xff;                         /* mask out right most byte */
                dest &= 0xffffff00;                 /* make place for byte */
                dest |= td;                         /* insert result into dest */
                if (td == 0)
                    CC |= CC4BIT;                   /* byte is zero, so CC4 */
                break;
            case 1:                                 /* left halfword addr */
            case 3:                                 /* right halfword addr */
                /* ARMH */
                td = dest + source;                 /* DO ARMH */
                td &= RMASK;                        /* mask out right most 16 bits */
                dest &= LMASK;                      /* make place for halfword */
                dest |= td;                         /* insert result into dest */
                if (td == 0)
                    CC |= CC4BIT;                   /* hw is zero, so CC4 */
                break;
            case 0:                                 /* 32 bit word */
                /* ARMW */
                /* dest and source are really 32 bit values */
                t = (source & MSIGN) != 0;
                t |= ((dest & MSIGN) != 0) ? 2 : 0;
                td = dest + source;                 /* DO ARMW */
                td &= D32RMASK;                     /* mask out right most 32 bits */
                dest = 0;                           /* make place for 64 bits */
                dest |= td;                         /* insert result into dest */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if (((t == 3) && ((dest & MSIGN) == 0)) || 
                    ((t == 0) && ((dest & MSIGN) != 0)))
                    ovr = 1;
                if (dest & MSIGN)
                    dest = (D32LMASK | dest);       /* sign extend */
                else
                    dest = (D32RMASK & dest);       /* zero fill */
                if (td == 0)
                    CC |= CC4BIT;                   /* word is zero, so CC4 */
                else {
                    if (td & 0x80000000)
                        CC |= CC3BIT;               /* it is neg wd, so CC3  */
                    else
                        CC |= CC2BIT;               /* then td > 0, so CC2 */
                }
                break;
            case 2:                                 /* 64 bit double */
                /* ARMD */
                t = (source & DMSIGN) != 0;
                t |= ((dest & DMSIGN) != 0) ? 2 : 0;
                td = dest + source;                 /* DO ARMD */
                dest = td;                          /* insert result into dest */
                /* if both signs are neg and result sign is positive, overflow */
                /* if both signs are pos and result sign is negative, overflow */
                if (((t == 3) && ((dest & DMSIGN) == 0)) || 
                    ((t == 0) && ((dest & DMSIGN) != 0)))
                    ovr = 1;
                if (td == 0)
                    CC |= CC4BIT;                   /* dw is zero, so CC4 */
                else {
                    if (td & DMSIGN)
                        CC |= CC3BIT;               /* it is neg dw, so CC3  */
                    else
                        CC |= CC2BIT;               /* then td > 0, so CC2 */
                }
                break;
            }
            if (ovr)
                CC |= CC1BIT;                       /* set overflow CC */
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's from PSD1 */
            PSD1 |= CC;                             /* update the CC's in the PSD */
            /* the arithmetic exception will be handled */
            /* after instruction is completed */
            /* check for arithmetic exception trap enabled */
            if (ovr && (MODES & AEXPBIT)) {
                TRAPME = AEXPCEPT_TRAP;             /* set the trap type */
            }
            break;

        case 0xEC>>2:       /* 0xEC ADR - ADR */    /* Branch unconditional BU or Branch True BCT */
            /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/
            /* so just test for F bit and go on */
            /* if ((FC & 5) != 0) { */
            if ((FC & 4) != 0) {
                TRAPME = ADDRSPEC_TRAP;             /* bad address, error */
                sim_debug(DEBUG_TRAP, my_dev,
                    "ADDRSPEC10 OP %04x addr %08x FC %02x PSD %08x %08x\n",
                    OP, addr, FC, PSD1, PSD2);
                goto newpsd;                        /* go execute the trap now */
            }
            temp2 = CC;                             /* save the old CC's */
            CC = PSD1 & 0x78000000;                 /* get CC's if any */
            switch(reg) {
            case 0:     t = 1; break;
            case 1:     t = (CC & CC1BIT) != 0; break;
            case 2:     t = (CC & CC2BIT) != 0; break;
            case 3:     t = (CC & CC3BIT) != 0; break;
            case 4:     t = (CC & CC4BIT) != 0; break;
            case 5:     t = (CC & (CC2BIT|CC4BIT)) != 0; break;
            case 6:     t = (CC & (CC3BIT|CC4BIT)) != 0; break;
            case 7:     t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) != 0; break;
            }
            if (t) {                                /* see if we are going to branch */
#if 0           /* set #if to 1 to stop branch to self while ipu tracing, for now */
                if (PC == (addr & 0xFFFFFC)) {      /* BU to current PC, go to wait */
                    fprintf(stderr, "BR stopping BU $ addr %x PC %x\r\n", addr, PC);
                    goto do_ipu_wait;
                }
#endif
                /* we are taking the branch, set CC's if indirect, else leave'm */
                /* update the PSD with new address */
                PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
                i_flags |= BT;                      /* we branched, so no PC update */
                if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */
                    PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */
                if ((MODES & (BASEBIT|EXTDBIT)) == 0)   /* see if basemode */
                    PSD1 &= 0xff07ffff;             /* only 19 bit address allowed */
            }
            /* branch not taken, go do next instruction */
            break;

        case 0xF0>>2:       /* 0xF0 ADR - ADR */    /* Branch False BCF or Branch Function True BFT */
            /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/
            /* so just test for F bit and go on */
            /* if ((FC & 5) != 0) { */
            if ((FC & 4) != 0) {
                TRAPME = ADDRSPEC_TRAP;             /* bad address, error */
                sim_debug(DEBUG_TRAP, my_dev,
                    "ADDRSPEC11 OP %04x addr %08x FC %02x PSD %08x %08x\n",
                    OP, addr, FC, PSD1, PSD2);
                goto newpsd;                        /* go execute the trap now */
            }
            temp2 = CC;                             /* save the old CC's */
            CC = PSD1 & 0x78000000;                 /* get CC's if any */
            switch(reg) {
            case 0:     t = (GPR[4] & (0x8000 >> ((CC >> 27) & 0xf))) != 0; break;
            case 1:     t = (CC & CC1BIT) == 0; break;
            case 2:     t = (CC & CC2BIT) == 0; break;
            case 3:     t = (CC & CC3BIT) == 0; break;
            case 4:     t = (CC & CC4BIT) == 0; break;
            case 5:     t = (CC & (CC2BIT|CC4BIT)) == 0; break;
            case 6:     t = (CC & (CC3BIT|CC4BIT)) == 0; break;
            case 7:     t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) == 0; break;
            }
            if (t) {                                /* see if we are going to branch */
                /* we are taking the branch, set CC's if indirect, else leave'm */
                /* update the PSD with new address */
                PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
                i_flags |= BT;                      /* we branched, so no PC update */
                if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */
                    PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */
                if ((MODES & (BASEBIT|EXTDBIT)) == 0)   /* see if basemode */
                    PSD1 &= 0xff07ffff;             /* only 19 bit address allowed */
            }
            break;

        case 0xF4>>2:       /* 0xF4 RR|SD|ADR - RR|SB|WRD */ /* Branch increment */
            dest += ((t_uint64)1) << ((IR >> 21) & 3);  /* use bits 9 & 10 to incr reg */
            if (dest != 0) {                        /* if reg is not 0, take the branch */
                /* we are taking the branch, set CC's if indirect, else leave'm */
                /* update the PSD with new address */

#if 0           /* set #if to 1 to stop branch to self while tracing, for now */
                if (PC == (addr & 0xFFFFFC)) {      /* BIB to current PC, bump branch addr */
                    addr += 4;
//                  fprintf(stderr, "BI? stopping BIB $ addr %x PC %x\r\n", addr, PC);
                    dest = 0;                       /* force reg to zero */
                }
#endif
                PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
                if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */
                    PSD1 = (PSD1 & 0x87fffffe) | CC;    /* insert last CCs */
                i_flags |= BT;                      /* we branched, so no PC update */
                if ((MODES & (BASEBIT|EXTDBIT)) == 0)     /* see if basemode */
                    PSD1 &= 0xff07ffff;             /* only 19 bit address allowed */
            }
            break;

        case 0xF8>>2:       /* 0xF8 SM|ADR - SM|ADR */  /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, TRP */
            switch((OPR >> 7) & 0x7) {              /* use bits 6-8 to determine instruction */
            case 0x0:       /* ZMx F80x */          /* SM */
                dest = 0;                           /* destination value is zero */
                i_flags |= SM;                      /* SM not set so set it to store value */
                break;
            case 0x1:       /* BL F880 */
                /* copy CC's from instruction and PC incremented by 4 */
                GPR[0] = ((PSD1 & 0xff000000) | ((PSD1 + 4) & 0xfffffe));
                if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */
                    PSD1 = (PSD1 & 0x87fffffe) | CC;    /* insert last CCs */
                /* update the PSD with new address */
                if (MODES & BASEBIT) 
                    PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* bit 8-30 */
                else
                    PSD1 = (PSD1 & 0xff000000) | (addr & 0x07fffe); /* bit 13-30 */
                i_flags |= BT;                      /* we branched, so no PC update */
                if ((MODES & (BASEBIT|EXTDBIT)) == 0)     /* see if basemode */
                    PSD1 &= 0xff07ffff;             /* only 19 bit address allowed */
                break;

            case 0x3:       /* LPSD F980 */
                /* fall through */;
            case 0x5:       /* LPSDCM FA80 */
                if ((MODES & PRIVBIT) == 0) {       /* must be privileged */
                    TRAPME = PRIVVIOL_TRAP;         /* set the trap to take */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                        TRAPSTATUS |= BIT0;         /* set bit 0 of trap status */
                    else
                        TRAPSTATUS |= BIT19;        /* set bit 19 of trap status */
                    goto newpsd;                    /* Privlege violation trap */
                }
                CPUSTATUS |= BIT25;                 /* enable software traps */
                                                    /* this will allow attn and */
                                                    /* power fail traps */
                if ((FC & 04) != 0 || FC == 2) {    /* can not be byte or doubleword */
                    /* Fault */
                    TRAPME = ADDRSPEC_TRAP;         /* bad reg address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n",
                        OP, addr, FC, PSD1, PSD2);
                    goto newpsd;                    /* go execute the trap now */
                }
                if ((TRAPME = Mem_read(addr, &temp))) { /* get PSD1 from memory */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                        TRAPSTATUS |= BIT10;        /* set bit 10 of trap status */
                        TRAPSTATUS |= BIT7;         /* set bit 7 of trap status */
                    } else {
                        TRAPSTATUS |= BIT18;        /* set bit 18 of trap status */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "LPSD TRAP1 %02x SPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n",
                        TRAPME, OP, addr, FC, PSD1, PSD2);
                    }
                    goto newpsd;                    /* memory read error or map fault */
                }
                bc = CPUSTATUS;                     /* save the CPU STATUS */
                TPSD1 = PSD1;                       /* save the PSD for the instruction */
                TPSD2 = PSD2;
                t = MODES;                          /* save modes too */
                ix = SPAD[0xf5];                    /* save the current PSD2 */
                reg = irq_pend;                     /* save intr status */

                if ((TRAPME = Mem_read(addr+4, &temp2))) {   /* get PSD2 from memory */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                        TRAPSTATUS |= BIT10;        /* set bit 10 of trap status */
                        TRAPSTATUS |= BIT7;         /* set bit 7 of trap status */
                    } else {
                        TRAPSTATUS |= BIT18;        /* set bit 18 of trap status */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "LPSD TRAP2 %02x SPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n",
                            TRAPME, OP, addr, FC, PSD1, PSD2);
                    }
                    goto newpsd;                    /* memory read error or map fault */
                }
                if (OPR & 0x0200) {                 /* Was it LPSDCM? */
                    /* LPSDCM */
                    PSD1 = temp;                    /* PSD1 good, so set it */
                    PSD2 = temp2 & 0xfffffff8;      /* PSD2 access good, clean & save it */
                    if (PSD2 & RETMBIT)             /* is retain mapping bit set */
                        PSD2 = ((PSD2 & 0x3ff8) | (temp2 & 0xffffc000)); /* use current cpix */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "LPSDCM %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n",
                        addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS);
                } else {
                    /* LPSD */
                    PSD1 = temp;                    /* PSD1 good, so set it */
                    /* lpsd can not change cpix, so keep it */
                    PSD2 = ((PSD2 & 0x3ff8) | (temp2 & 0xffffc000)); /* use current cpix */
                    PSD2 &= ~RETMBIT;               /* turn off retain bit in PSD2 n/u */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "LPSD %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n",
                        addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS);
                }

                /* test for retain blocking state */
                if (PSD2 & RETBBIT) {               /* is it retain blocking state */
                    /* BIT 49 has new blocking state */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        PSD2 |= SETBBIT;            /* yes, set to blocked state */
                        MODES |= BLKMODE;           /* set blocked mode */
                        CPUSTATUS |= BIT24;         /* set blocked mode */
                    } else {
                        PSD2 &= ~SETBBIT;           /* set to unblocked state */
                        MODES &= ~RETMODE;          /* reset retain block mode bit */
                        CPUSTATUS &= ~BIT24;        /* reset block state in cpu status bit 8 */
                    }
                    PSD2 &= ~RETBBIT;               /* clear bit 48 retain blocking bit */
                }

                /* set the mode bits and CCs from the new PSD */
                CC = PSD1 & 0x78000000;             /* extract bits 1-4 from PSD1 */
                MODES = PSD1 & 0x87000000;          /* extract bits 0, 5, 6, 7 from PSD 1 */
                MODES &= ~RETMODE;                  /* reset retain map mode bit in status */
                CPUSTATUS &= ~0x87000000;           /* reset bits in CPUSTATUS */
                CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */

                if (PSD2 & SETBBIT) {               /* is it set blocking state bit 49 set*/
                    /* set new blocking state bit 49=1 */
                    CPUSTATUS |= BIT24;             /* yes, set blk state in cpu status bit 24 */
                    MODES |= BLKMODE;               /* set blocked mode */
                } else {
                    CPUSTATUS &= ~BIT24;            /* reset block state in cpu status bit 8 */
                    MODES &= ~BLKMODE;              /* reset block mode bits */
                }

                /* bit 0 of PSD wd 2 sets new mapping state */
                if (PSD2 & MAPBIT) {
                    CPUSTATUS |= BIT8;              /* set bit 8 of cpu status to mapped */
                    MODES |= MAPMODE;               /* set mapped mode */
                } else {
                    CPUSTATUS &= ~BIT8;             /* reset bit 8 of cpu status */
                    MODES &= ~MAPMODE;              /* reset mapped mode */
                }

                if ((PSD2 & SETBBIT) == 0) {        /* see if new mode is unblocked */
                    if (TPSD2 & SETBBIT) {          /* see if old mode is blocked */
                        /* we changed from blocked to unblocked */
                        if (!(CPUSTATUS & ONIPU))
                            irq_pend = 1;           /* start scanning interrupts again */
                    }
                }

                /* see what mapping we are to do if LPSDCM */
                if (OPR & 0x0200) {                 /* Was it LPSDCM? */
                    if (PSD2 & MAPBIT) {
                        /* this mod fixes MPX 1.X 1st swapr load */
                        /* any O/S or user maps yet? */
                        if (((CPIX != 0) && (CPIXPL == 0)) && (PSD2 & RETMBIT)) {
                            PSD2 &= ~RETMBIT;       /* no, turn off retain bit in PSD2 */
                            sim_debug(DEBUG_TRAP, my_dev, "Turn off retain bit\n");
                        }

                        /* test if user count is equal to CPIXPL, if not load maps */
                        /* this fixes software error in MPX3X where count is changed */
                        /* but the retain bit was left set, so new maps were not loaded */
                        /* until the next context switch and causes loading error */
                        /* CHANGED 041420 maybe not right */
                        if ((PSD2 & RETMBIT)) {     /* don't load maps if retain bit set */
                            uint32 mpl = SPAD[0xf3];    /* get mpl from spad address */
                            uint32 cpix = PSD2 & 0x3ff8;    /* get cpix 11 bit offset from psd wd 2 */
                            uint32 osmidl = RMW(mpl);   /* get midl entry for given O/S */
                            uint32 midl = RMW(mpl+cpix);    /* get midl entry for given user cpix */
                            uint32 spc = midl & MASK16; /* get 16 bit user segment description count */

                        sim_debug(DEBUG_TRAP, my_dev,
              "LPSDCM FIX %.8x %.8x mpl %.6x osmidl %06x umidl %06x OSMAPS %04x UMAPS %04x CPIXPL %04x\n",
                    TPSD1, TPSD2, mpl, osmidl, midl, osmidl & MASK16, spc, CPIXPL);
                            /* if this code is not present, MPX3X will not boot correctly */
                            if (spc != CPIXPL) {
                                PSD2 &= ~RETMBIT;   /* no, turn off retain bit in PSD2 */
                            } else {
                                /* if this code is not present MPX3X will abort */
                                /* when trying to mount a secondary disk */
                                if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97) ||
                                    (CPU_MODEL == MODEL_V6) || (CPU_MODEL == MODEL_V9)) {
                                    PSD2 &= ~RETMBIT;   /* no, turn off retain bit in PSD2 */
                                }
                            }
                            sim_debug(DEBUG_TRAP, my_dev,
                "LPSDCM FIX MAP TRAPME %02x PSD %08x %08x spc %02x BPIX %02x CPIXPL %02x retain %01x\n",
                                TRAPME, PSD1, PSD2, spc, BPIX, CPIXPL, PSD2&RETMBIT?1:0);
                        }
                        sim_debug(DEBUG_TRAP, my_dev,
                "LPSDCML %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n",
                            addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS);
                        /* load the new maps and test for errors */
                        if ((PSD2 & RETMBIT) == 0) {    /* don't load maps if retain bit set */
                            /* we need to load the new maps */
                            TRAPME = load_maps(PSD, 0); /* load maps for new PSD */
                        }
                        sim_debug(DEBUG_TRAP, my_dev,
                "LPSDCM MAPS LOADED TRAPME %02x PSD %08x %08x BPIX %02x CPIXPL %02x retain %01x\n",
                            TRAPME, PSD1, PSD2, BPIX, CPIXPL, PSD2&RETMBIT?1:0);
                    }
                    PSD2 &= ~RETMBIT;           /* turn off retain bit in PSD2 */
                } else {
                    /* LPSD */
                    /* if cpix is zero, copy cpix from PSD2 in SPAD[0xf5] */
                    if ((PSD2 & 0x3ff8) == 0) {
                        PSD2 |= (SPAD[0xf5] & 0x3ff8);  /* use new cpix */
                    }
                    sim_debug(DEBUG_TRAP, my_dev,
                        "LPSDL @ %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n",
                        addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS);
                    sim_debug(DEBUG_TRAP, my_dev,
                        "   R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]);
                    sim_debug(DEBUG_TRAP, my_dev,
                        "   R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
                }

                /* TRAPME can be error from LPSDCM or OK here */
                if (TRAPME) {                       /* if we have an error, restore old PSD */
                    sim_debug(DEBUG_TRAP, my_dev,
            "LPSDCM BAD MAPS LOAD TRAPME %02x PSD %08x %08x CPUSTAT %08x SPAD[f9] %08x\n",
                        TRAPME, PSD1, PSD2, CPUSTATUS, SPAD[0xf9]);
                    PSD1 = TPSD1;                   /* restore PSD1 */
                    /* HACK HACK HACK */
                    /* Diags wants the new PSD2, not the original on error??? */
                    /* if old one was used, we fail test 21/0 in cn.mmm for 32/67 */
                    CPUSTATUS = bc;                 /* restore the CPU STATUS */
                    MODES = t;                      /* restore modes too */
                    SPAD[0xf5] = ix;                /* restore the current PSD2 to SPAD */
                    SPAD[0xf9] = CPUSTATUS;         /* save the cpu status in SPAD */
                    irq_pend = reg;                 /* restore intr status */
                    if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
                        TRAPSTATUS |= BIT10;        /* set bit 10 of trap status */
                        TRAPSTATUS |= BIT7;         /* set bit 7 of trap status */
                    } else
                        TRAPSTATUS |= BIT18;        /* set bit 18 of trap status */
                    goto newpsd;                    /* go process error */
                }
                SPAD[0xf5] = PSD2;                  /* save the current PSD2 */
                SPAD[0xf9] = CPUSTATUS;             /* save the cpu status in SPAD */
                drop_nop = 0;                       /* nothing to drop */
                i_flags |= BT;                      /* do not update pc */
                break;                              /* load the new psd, or process error */

            case 0x4:       /* JWCS */              /* not used in simulator */
                sim_debug(DEBUG_EXP, my_dev, "Got JWCS\n");
                break;
            case 0x2:       /* BRI */               /* TODO - only for 32/55 or 32/7X in PSW mode */
            case 0x6:       /* TRP */
            case 0x7:       /* TPR */
                TRAPME = UNDEFINSTR_TRAP;           /* trap condition */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* undefined instruction trap */
                break;
            }
            break;

/* F Class I/O device instruction format */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02 03 04 05|06 07 08|09 10 11 12|13 14 15|16|17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */
/* |     Op Code     |  Reg   |  I/O type |  Aug   |0 |   Channel Address  |  Device Sub-address   | */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* E Class I/O device instruction format */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02 03 04 05|06 07 08 09 10 11 12|13 14 15|16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| */
/* |     Op Code     |     Device Number  |  Aug   |                  Command Code                 | */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
        case 0xFC>>2:       /* 0xFC IMM - IMM */    /* XIO, CD, TD, Interrupt Control */
            if ((MODES & PRIVBIT) == 0) {           /* must be privileged to do I/O */
                TRAPME = PRIVVIOL_TRAP;             /* set the trap to take */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                else
                    TRAPSTATUS |= BIT19;            /* set bit 19 of trap status */
                goto newpsd;                        /* Privlege violation trap */
            }
            if (IPU_MODEL && (CPUSTATUS & ONIPU)) {
                /* on IPU :  */
                TRAPME = IPUUNDEFI_TRAP;
                sim_debug(DEBUG_TRAP, my_dev,
                    "IPU SIO PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n",
                    PSD1, PSD2, SPAD[0xf5], CPUSTATUS);
                goto newpsd;
            }
            if ((OPR & 0x7) != 0x07) {              /* aug is 111 for XIO instruction */
                /* Process Non-XIO instructions */
                uint32 status = 0;                  /* status returned from device */
                uint32 device = (OPR >> 3) & 0x7f;  /* get device code */
                uint32 prior = device;              /* interrupt priority */
                uint32 maxlev = 0x5f;               /* max lev for all but 32/27 in diags */
//MAYBEBAD      uint32 maxlev = 0x6f;               /* max lev for all but 32/27 in diags */

                t = SPAD[prior+0x80];               /* get spad entry for interrupt */
                addr = SPAD[0xf1] + (prior<<2);     /* vector address in SPAD */
                addr = M[addr>>2];                  /* get the interrupt context block addr */
                prior = (OPR >> 3) & 0x7f;          /* get priority level */
                if (CPU_MODEL <= MODEL_27) {
                    maxlev = 0x6f;                  /* 27 uses 112 */
                }

                switch(OPR & 0x7) {                 /* use bits 13-15 to determine instruction */
                case 0x0:   /* EI  FC00  Enable Interrupt */
                    if (prior > maxlev)             /* ignore for invalid levels */
                        break;                      /* ignore */
                    /* SPAD entries for interrupts begin at 0x80 */
                    t = SPAD[prior+0x80];           /* get spad entry for interrupt */
                    if ((t == 0) || ((t&MASK24) == MASK24))  /* if unused, ignore instruction */
                        break;                      /* ignore */
      
                    if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */
                        break;                      /* ignore for F class */

                    sim_debug(DEBUG_IRQ, my_dev,
                        "EI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                    /* does not effect REQ status */
                    INTS[prior] |= INTS_ENAB;       /* enable specified int level */
                    SPAD[prior+0x80] |= SINT_ENAB;  /* enable in SPAD too */
                    irq_pend = 1;                   /* start scanning interrupts again */

                    /* test for clock at address 0x7f06 and interrupt level 0x18 */
                    /* the diags want the type to be 0 */
                    /* UTX wants the type to be 3?? */
                    /* UTX would be 0x03807f06 Diags would be 0x00807f06 */
                    if ((SPAD[prior+0x80] & 0x0000ffff) == 0x00007f06) {
                        sim_debug(DEBUG_IRQ, my_dev,
                            "Clock EI %02x SPAD %08x Turn on\n", prior, t);
                        rtc_setup(1, prior);        /* tell clock to start */
                    }
                    break;

                case 0x1:   /* DI FC01 */
                    if (prior > maxlev)             /* ignore for invalid levels */
                        break;                      /* ignore */
                    /* SPAD entries for interrupts begin at 0x80 */
                    t = SPAD[prior+0x80];           /* get spad entry for interrupt */
     
                    if ((t == 0) || ((t&MASK24) == MASK24)) /* if unused, ignore instruction */
                        break;                      /* ignore */
         
                    if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */
                        break;                      /* ignore for F class */

                    sim_debug(DEBUG_IRQ, my_dev,
                        "DI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                    /* active state is left alone */
                    INTS[prior] &= ~INTS_ENAB;      /* disable specified int level */
                    SPAD[prior+0x80] &= ~SINT_ENAB; /* disable in SPAD too */
                    INTS[prior] &= ~INTS_REQ;       /* clears any requests also */
                    irq_pend = 1;                   /* start scanning interrupts again */

                    /* test for clock at address 0x7f06 and interrupt level 0x18 */
                    /* the diags want the type to be 0 */
                    /* UTX wants the type to be 3?? */
                    /* UTX would be 0x03807f06 Diags would be 0x00807f06 */
                    if ((SPAD[prior+0x80] & 0x0000ffff) == 0x00007f06) {
                        sim_debug(DEBUG_IRQ, my_dev,
                            "Clock DI %02x SPAD %08x Turn off\n", prior, t);
                        rtc_setup(0, prior);        /* tell clock to stop */
                    }
                    break;

                case 0x2:   /* RI FC02 */
                    if (prior > maxlev)             /* ignore for invalid levels */
                        break;                      /* ignore */
                    /* SPAD entries for interrupts begin at 0x80 */
                    t = SPAD[prior+0x80];           /* get spad entry for interrupt */
                    if ((t == 0) || ((t&MASK24) == MASK24))  /* if unused, ignore instruction */
                        break;                      /* ignore */
           
                    if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */
                        break;                      /* ignore for F class */

                    sim_debug(DEBUG_IRQ, my_dev,
                        "RI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                    INTS[prior] |= INTS_REQ;        /* set the request flag for this level */
                    irq_pend = 1;                   /* start scanning interrupts again */
                    break;

                case 0x3:   /* AI FC03 */
                    if (prior > maxlev)             /* ignore for invalid levels */
                        break;                      /* ignore */
                    /* SPAD entries for interrupts begin at 0x80 */
                    t = SPAD[prior+0x80];           /* get spad entry for interrupt */
                    if ((t == 0) || ((t&MASK24) == MASK24))  /* if unused, ignore instruction */
                        break;                      /* ignore */
      
                    if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */
                        break;                      /* ignore for F class */

                    sim_debug(DEBUG_IRQ, my_dev,
                        "AI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                    INTS[prior] |= INTS_ACT;        /* activate specified int level */
                    SPAD[prior+0x80] |= SINT_ACT;   /* activate in SPAD too */
                    irq_pend = 1;                   /* start scanning interrupts again */
                    break;

                case 0x4:   /* DAI FC04 */
                    if (prior > maxlev)             /* ignore for invalid levels */
                        break;                      /* ignore */
                    /* SPAD entries for interrupts begin at 0x80 */
                    t = SPAD[prior+0x80];           /* get spad entry for interrupt */
                    if ((t == 0) || ((t&MASK24) == MASK24))  /* if unused, ignore instruction */
                        break;                      /* ignore */

                    if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */
                        break;                      /* ignore for F class */

                    sim_debug(DEBUG_IRQ, my_dev,
                        "DAI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                    INTS[prior] &= ~INTS_ACT;       /* deactivate specified int level */
                    SPAD[prior+0x80] &= ~SINT_ACT;  /* deactivate in SPAD too */
                    irq_pend = 1;                   /* start scanning interrupts again */
                    /* instruction following a DAI can not be interrupted */
                    /* skip tests for interrupts if this is the case */
                    skipinstr = 1;                  /* skip interrupt test */
                    break;

                case 0x5:   /* TD FC05 */           /* bits 13-15 is test code type */
                case 0x6:   /* CD FC06 */
                    /* If CD or TD, make sure device is not F class device */
                    /* the channel must be defined as a non class F I/O channel in SPAD */
                    /* if class F, the system will generate a system check trap */
                    t = SPAD[device];               /* get spad entry for channel */
                    if ((t & 0x0f000000) == 0x0f000000) {   /* class in bits 4-7 */
                        TRAPME = SYSTEMCHK_TRAP;    /* trap condition if F class */
                        TRAPSTATUS &= ~BIT0;        /* class E error bit */
                        TRAPSTATUS &= ~BIT1;        /* I/O processing error */
                        goto newpsd;                /* machine check trap */
                    }
                    /* t has spad entry for device */
                    /* get the 1's comp of interrupt address from bits 9-15 SPAD entry */
                    ix = ((~t)>>16)&0x7f;           /* get positive number for interrupt */
                    prior = ix;                     /* set prior for CD instruction */
                    if (OPR & 0x1) {                /* see if CD or TD */
                        sim_debug(DEBUG_IRQ, my_dev,
                            "TD spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                        /* TODO process a TD */
                        if (device == 0x7f) {
                            /* if this is for the interval timer check cmd type */
                            /* if TD 8000 or 4000, set all cc's zero */
                            temp = (IR & 0xf000);   /* get cmd from instruction */
                            if ((temp == 0x4000) || (temp == 0x8000))
                                status = 0;         /* no CC's */
                            else
                                /* if TD 2000 set CC2 for caller */
                                if (temp == 0x2000)
                                    status = CC2BIT;    /* set CC2 */
                            /* return status has new CC's in bits 1-4 of status word */
                            /* insert status CCs */
                            PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000));
                        } else {
#if 0
                            /* may want to handle class E someday */
                            if ((TRAPME = testEIO(device, testcode, &status)))
                                goto newpsd;        /* error returned, trap cpu */
                             /* return status has new CC's in bits 1-4 of status word */
                             /* insert status CCs */
                             PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000));
#endif
                             goto inv;               /* invalid instruction until I fix it */
                        }
                    } else {
                        /* TODO process a CD */
#if 0
                        if ((TRAPME = startEIO(device, &status)))
                            goto newpsd;            /* error returned, trap cpu */
#endif
                        sim_debug(DEBUG_IRQ, my_dev,
                            "CD spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]);
                        if (device == 0x7f) {
                            temp = (IR & 0x7f);     /* get cmd from instruction */
                            status = itm_rdwr(temp, GPR[0], ix);    /* read/write the interval timer */
                            /* see if the cmd does not return value */
                            /* if bit 25 set, read reg val into R0 */
                            if (temp & 0x40) 
                                GPR[0] = status;    /* return count in reg 0 */
                            /* No CC's going out */
                        } else {
                            goto inv;               /* invalid instruction until I fix it */
                        }
                    }
                    break;
                case 0x7:   /* XIO FC07*/           /* should never get here */
                    goto inv;                       /* invalid instruction until I fix it */
                    break;
                }
                break;                              /* skip over XIO code */
            }

            /* Process XIO instructions */
            /* see if valid instruction */
            /* DIAGS wants this tested first */
            switch((OPR >> 3) & 0xf) {              /* use bits 9-12 to determine I/O instruction */
            case 0x00:      /* Unassigned */
            case 0x01:      /* Unassigned */
            case 0x0A:      /* Unassigned */
                TRAPME = UNDEFINSTR_TRAP;           /* trap condition */
                if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
                    TRAPSTATUS |= BIT0;             /* set bit 0 of trap status */
                goto newpsd;                        /* undefined instruction trap */
            }

            /* if reg is non-zero, add reg to 15 bits from instruction */
            if (reg)
                temp2 = (IR & 0x7fff) + (GPR[reg] & 0x7fff);    /* set new chan/suba into IR */
            else
                temp2 = (IR & 0x7fff);              /* set new chan/suba into IR */
            lchan = (temp2 & 0x7F00) >> 8;          /* get 7 bit logical channel address */
            suba = temp2 & 0xFF;                    /* get 8 bit subaddress */
            lchsa = (lchan << 8) | suba;            /* logical address */
            /* the channel must be defined as a class F I/O channel in SPAD */
            /* if not class F, the system will generate a system check trap */
            t = SPAD[lchan];                        /* get spad entry for channel */
            if ((t == 0) || ((t&MASK24) == MASK24) || /* if not set up, system check */
                ((t & 0x0f800000) != 0x0f000000)) {   /* class in bits 4-7 */
                TRAPME = SYSTEMCHK_TRAP;            /* trap condition if F class */
                TRAPSTATUS |= BIT0;                 /* class F error bit */
                TRAPSTATUS &= ~BIT1;                /* I/O processing error */
                goto newpsd;                        /* system check trap */
            }
            /* get real channel from spad device entry */
            chan = (t & 0x7f00) >> 8;               /* real channel */
            rchsa = (chan << 8) | suba;             /* real ch & sa */
            /* get the 1's comp of interrupt address from bits 9-15 SPAD entry */
            ix = ((~t)>>16)&0x7f;                   /* get positive number for interrupt */
            bc = SPAD[ix+0x80];                     /* get interrupt spad entry for channel */
            /* SPAD address F1 has interrupt table address */
            temp = SPAD[0xf1] + (ix<<2);            /* vector address in SPAD */
            sim_debug(DEBUG_XIO, my_dev,
                "$$ XIO chsa %04x spad %08x BLK %1x INTS[%02x] %08x\n",
                rchsa, t, CPUSTATUS&0x80?1:0, ix, INTS[ix]);
            sim_debug(DEBUG_XIO, my_dev,
                "$$ XIO chsa %04x PSD1 %08x PSD2 %08x IR %08x ICBA %06x\n",
                rchsa, PSD1, PSD2, IR, temp);
            if ((TRAPME = Mem_read(temp, &addr))) { /* get interrupt context block addr */
mcheck:
                /* machine check if not there */
                TRAPME = MACHINECHK_TRAP;           /* trap condition */
                TRAPSTATUS |= BIT0;                 /* class F error bit */
                TRAPSTATUS &= ~BIT1;                /* I/O processing error */
                goto newpsd;                        /* machine check trap */
            }
            /* the context block contains the old PSD, */
            /* new PSD, IOCL address, and I/O status address */
            if ((addr == 0) || (addr == 0xffffffff)) {  /* must be initialized address */
                goto mcheck;                        /* bad int icb address */
            }
            if ((TRAPME = Mem_read(addr+16, &temp))) { /* get iocl address from icb wd 4 */
                goto mcheck;                        /* machine check if not there */
            }
            /* iocla must be valid addr if it is a SIO instruction */
            if (((temp & MASK24) == 0) && (((OPR >> 2) & 0xf) == 2))  {
                goto mcheck;                        /* bad iocl address */
            }

            sim_debug(DEBUG_XIO, my_dev,
                "XIO rdy PSD1 %08x chan %02x irq %02x icb %06x iocla %06x iocd %08x %08x\n",
                PSD1, chan, ix, addr, addr+16, RMW(temp), RMW(temp+4));
            /* at this point, the channel has a valid SPAD channel entry */
            /* t is SPAD entry contents for chan device */
            /* temp2 has logical channel address */
            /* lchan - logical channel address */
            /* lchsa - logical channel & subaddress */
            /* chan - channel address */
            /* suba - channel device subaddress */
            /* rchsa - real chan & sub address from spad for logical channel */
            /* ix - positive interrupt level */
            /* addr - ICBA for specified interrupt level, points to 6 wd block */
            /* temp - First IOCD address */
            sim_debug(DEBUG_XIO, my_dev,
                "XIO switch %02x lchan %02x irq %02x rchsa %04x IOCDa %08x CPUSTATUS %08x BLK %1x\n",
                ((OPR>>3)&0x0f), lchan, ix, rchsa, temp, CPUSTATUS, CPUSTATUS&0x80?1:0);

            /* 0x00, 0x01, & 0x0A already tested above */
            switch((OPR >> 3) & 0xf) {              /* use bits 9-12 to determine I/O instruction */
            case 0x09:      /* Enable write channel ECWCS */
            case 0x0B:      /* Write channel WCS WCWCS */
                /* TODO, provide support code */
                /* for now or maybe forever, return unsupported transaction */
                PSD1 = ((PSD1 & 0x87fffffe) | (CC2BIT|CC4BIT)); /* insert status 5 */
                sim_debug(DEBUG_XIO, my_dev,
                    "XIO unsupported WCS chan %04x chsa %04x status %08x\n",
                    chan, rchsa, rstatus);
#ifdef JUST_RETURN_STATUS
                /* just give unsupported transaction */
                TRAPME = SYSTEMCHK_TRAP;            /* trap condition if F class */
                TRAPSTATUS |= BIT0;                 /* class F error bit */
                TRAPSTATUS &= ~BIT1;                /* I/O processing error */
                goto newpsd;                        /* undefined instruction trap */
#endif
                break;

            case 0x02:      /* Start I/O SIO */
                sim_debug(DEBUG_XIO, my_dev,
                    "SIO b4 call PSD1 %08x %08x rchsa %04x lchsa %04x BLK %1x\n",
                    PSD1, PSD2, rchsa, lchsa, CPUSTATUS&0x80?1:0);
                if ((TRAPME = startxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                sim_debug(DEBUG_XIO, my_dev,
                    "SIO ret PSD1 %08x %08x chsa %04x status %08x BLK %1x\n",
                    PSD1, PSD2, lchsa, rstatus, CPUSTATUS&0x80?1:0);
                break;
                            
            case 0x03:      /* Test I/O TIO */
                if ((TRAPME = testxio(lchsa, &rstatus))) {
                    sim_debug(DEBUG_TRAP, my_dev,
                        "TIO ret PSD1 %x rchsa %x lchsa %x status %x BLK %1x\n",
                        PSD1, rchsa, lchsa, rstatus, CPUSTATUS&0x80?1:0);
                        goto newpsd;                /* error returned, trap cpu */
               }
               PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
               sim_debug(DEBUG_XIO, my_dev,
                   "TIO ret PSD1 %08x lchsa %04x stat %08x spad %08x INTS[%02x] %08x BLK %1x\n",
                   PSD1, lchsa, rstatus, t, ix, INTS[ix], CPUSTATUS&0x80?1:0);
                break;
                            
            case 0x04:      /* Stop I/O STPIO */
                if ((TRAPME = stopxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                sim_debug(DEBUG_XIO, my_dev, "STPIO ret rchsa %04x lchsa %04x status %08x\n",
                    rchsa, lchsa, rstatus);
                break;

            case 0x05:      /* Reset channel RSCHNL */
                if ((TRAPME = rschnlxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                /* SPAD entries for interrupts begin at 0x80 */
                INTS[ix] &= ~INTS_REQ;              /* clears any requests */
                INTS[ix] &= ~INTS_ACT;              /* deactivate specified int level */
                SPAD[ix+0x80] &= ~SINT_ACT;         /* deactivate in SPAD too */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                sim_debug(DEBUG_XIO, my_dev, "RSCHNL rschnlxio ret rchsa %04x lchsa %04x status %08x\n",
                    rchsa, lchsa, rstatus);
                break;

            case 0x06:      /* Halt I/O HIO */
                if ((TRAPME = haltxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                sim_debug(DEBUG_XIO, my_dev,
                    "HIO haltxio ret rchsa %04x lchsa %04x status %08x\n",
                    rchsa, lchsa, rstatus);
                break;

            case 0x07:      /* Grab controller GRIO n/u */
                if ((TRAPME = grabxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                sim_debug(DEBUG_XIO, my_dev, "GRIO ret rchsa %04x lchsa %04x status %08x\n",
                    rchsa, lchsa, rstatus);
                break;

            case 0x08:      /* Reset controller RSCTL */
                 if ((TRAPME = rsctlxio(lchsa, &rstatus)))
                     goto newpsd;                   /* error returned, trap cpu */
                 PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                 sim_debug(DEBUG_XIO, my_dev, "RSCTL ret rchsa %04x lchsa %04x status %08x\n",
                     rchsa, lchsa, rstatus);
                 break;

            case 0x0C:      /* Enable channel interrupt ECI */
                /* disable int only */
                sim_debug(DEBUG_XIO, my_dev,
                    "ECI chsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n",
                    rchsa, lchsa, t, ix, INTS[ix]);
                if ((TRAPME = checkxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                sim_debug(DEBUG_XIO, my_dev,
                    "ECI after checkxio rchsa %04x suba %04x status %08x\n",
                    rchsa, suba, rstatus);
    
                if ((INTS[ix] & INTS_ACT) == 0)
                    sim_debug(DEBUG_XIO, my_dev,
                        "ECI INT %02x is NOT set rchsa %04x lchsa %04x status %08x\n",
                        ix, rchsa, lchsa, rstatus);
                /* SPAD entries for interrupts begin at 0x80 */
                INTS[ix] |= INTS_ENAB;              /* enable specified int level */
                SPAD[ix+0x80] |= SINT_ENAB;         /* enable in SPAD too */
                irq_pend = 1;                       /* start scanning interrupts again */
                /* return status of zero for present and functioning */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                break;

            case 0x0D:  /* Disable channel interrupt DCI */
                /* disable int, leave req */
                sim_debug(DEBUG_XIO, my_dev,
                "DCI rchsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n",
                    rchsa, lchsa, t, ix, INTS[ix]);

                if ((TRAPME = checkxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                sim_debug(DEBUG_XIO, my_dev,
                    "DCI After checkxio call rstatus %08x\n", rstatus);
                /* doc says we need to drop 1 queued status entry too */
                if ((INTS[ix] & INTS_ACT) == 0)
                    sim_debug(DEBUG_XIO, my_dev,
                        "DCI INT %02x is NOT set rchsa %04x lchsa %04x status %08x\n",
                        ix, rchsa, lchsa, rstatus);
                /* SPAD entries for interrupts begin at 0x80 */
                INTS[ix] &= ~INTS_ENAB;             /* disable specified int level */
                SPAD[ix+0x80] &= ~SINT_ENAB;        /* disable in SPAD too */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                break;

            case 0x0E:      /* Activate channel interrupt ACI */
                /* Set int active, clear request */
                sim_debug(DEBUG_XIO, my_dev,
                    "ACI rchsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n",
                    rchsa, lchsa, t, ix, INTS[ix]);

                if ((TRAPME = checkxio(lchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                if ((INTS[ix] & INTS_ACT) == 0)
                    sim_debug(DEBUG_XIO, my_dev,
                        "ACI INT %02x is NOT set rchsa %04x lchsa %04x status %08x\n",
                        ix, rchsa, lchsa, rstatus);
                /* SPAD entries for interrupts begin at 0x80 */
                INTS[ix] |= INTS_ACT;               /* activate specified int level */
                SPAD[ix+0x80] |= SINT_ACT;          /* enable in SPAD too */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                break;

            case 0x0F:      /* Deactivate channel interrupt DACI */
                /* Clear active and leave any request */
                /* Note, instruction following DACI is not interruptable */
                sim_debug(DEBUG_XIO, my_dev,
                    "DACI rchsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n",
                    rchsa, lchsa, t, ix, INTS[ix]);

                if ((TRAPME = checkxio(rchsa, &rstatus)))
                    goto newpsd;                    /* error returned, trap cpu */
                if ((INTS[ix] & INTS_ACT) == 0)
                    sim_debug(DEBUG_XIO, my_dev,
                        "DACI INT %02x is NOT set chan %04x suba %04x status %08x\n",
                        ix, chan, suba, rstatus);
                /* SPAD entries for interrupts begin at 0x80 */
                INTS[ix] &= ~INTS_ACT;              /* deactivate specified int level */
                SPAD[ix+0x80] &= ~SINT_ACT;         /* deactivate in SPAD too */
                irq_pend = 1;                       /* start scanning interrupts again */
                skipinstr = 1;                      /* skip interrupt test */
                PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000));   /* insert status */
                sim_debug(DEBUG_XIO, my_dev,
                    "DACI ret lchsa %04x status %08x spad %08x INTS[%02x] %08x BLK %1x\n",
                    lchsa, rstatus, t, ix, INTS[ix], CPUSTATUS&0x80?1:0);
                break;
            }                                       /* end of XIO switch */
            break;
        }                                           /* End of Instruction Switch */

        /* [*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*] */

        /* any instruction with an arithmetic exception will still end up here */
        /* after the instruction is done and before incrementing the PC, */
        /* we will trap the cpu if ovl is set nonzero by an instruction */

        /* Store result to register */
        if (i_flags & SD) {
            if (dbl) {                              /* if double reg, store 2nd reg */
                if (reg & 1) {                      /* is it double regs into odd reg */
                    TRAPME = ADDRSPEC_TRAP;         /* bad address, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC13 OP %04x addr %08x reg %x\n", OP, addr, reg);
                    goto newpsd;                    /* go execute the trap now */
                }
                GPR[reg+1] = (uint32)(dest & FMASK);    /* save the low order reg */
                GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
            } else {
                GPR[reg] = (uint32)(dest & FMASK);  /* save the reg */
            }
        }

        /* Store result to base register */
        if (i_flags & SB) {
            if (dbl)  {                             /* no dbl wd store to base regs */
                TRAPME = ADDRSPEC_TRAP;             /* bad address, error */
                sim_debug(DEBUG_TRAP, my_dev,
                    "ADDRSPEC14 OP %04x addr %08x\n", OP, addr);
                goto newpsd;                        /* go execute the trap now */
            }
            BR[reg] = (uint32)(dest & FMASK);       /* save the base reg */
        }

        /* Store result to memory */
        if (i_flags & SM) {
            /* Check if byte of half word */
            if (((FC & 04) || (FC & 5) == 1)) {     /* hw or byte requires read first */
                if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
                    goto newpsd;                    /* memory read error or map fault */
                }
            }
            switch(FC) {
            case 2:         /* double word store */
                if ((addr & 7) != 2) {
                    TRAPME = ADDRSPEC_TRAP;         /* address not on dbl wd boundry, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC14 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                temp = (uint32)(dest & MASK32);/* get lo 32 bit */
                if ((TRAPME = Mem_write(addr + 4, &temp)))
                    goto newpsd;                    /* memory write error or map fault */
                temp = (uint32)(dest >> 32);        /* move upper 32 bits to lo 32 bits */
                break;

            case 0:         /* word store */
                temp = (uint32)(dest & FMASK);      /* mask 32 bit of reg */
                if ((addr & 3) != 0) {
                    /* Address fault */
                    TRAPME = ADDRSPEC_TRAP;         /* address not on wd boundry, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC15 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                break;

            case 1:         /* left halfword write */
                temp &= RMASK;                      /* mask out 16 left most bits */
                temp |= (uint32)(dest & RMASK) << 16;   /* put into left most 16 bits */
                if ((addr & 1) != 1) {
                    /* Address fault */
                    TRAPME = ADDRSPEC_TRAP;         /* address not on hw boundry, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC16 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                break;

            case 3:         /* right halfword write */
                temp &= LMASK;                      /* mask out 16 right most bits */
                temp |= (uint32)(dest & RMASK);     /* put into right most 16 bits */
                if ((addr & 3) != 3) {
                    TRAPME = ADDRSPEC_TRAP;         /* address not on hw boundry, error */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "ADDRSPEC17 OP %04x addr %08x\n", OP, addr);
                    goto newpsd;                    /* go execute the trap now */
                }
                break;

            case 4:
            case 5:
            case 6:
            case 7:         /* byte store operation */
                temp &= ~(0xFF << (8 * (7 - FC)));  /* clear the byte to store */
                temp |= (uint32)(dest & 0xFF) << (8 * (7 - FC));    /* insert new byte */
                break;
            }
            /* store back the modified memory location */
            if ((TRAPME = Mem_write(addr, &temp)))  /* store back to memory */
                goto newpsd;                        /* memory write error or map fault */
        }

        /* Update condition code registers */
        if (i_flags & SCC) {
            PSD1 &= 0x87FFFFFE;                     /* clear the old CC's */
            if (ovr)                                /* if overflow, set CC1 */
                CC = CC1BIT;                        /* show we had AEXP */
            else
                CC = 0;                             /* no CC's yet */   
            if (dest & DMSIGN)                      /* if neg, set CC3 */
                CC |= CC3BIT;                       /* if neg, set CC3 */
            else if (dest == 0)
                CC |= CC4BIT;                       /* if zero, set CC4 */
            else
                CC |= CC2BIT;                       /* if gtr than zero, set CC2 */
            PSD1 |= CC & 0x78000000;                /* update the CC's in the PSD */
        }

        /* check if we had an arithmetic exception on the last instruction*/
        if (ovr && (MODES & AEXPBIT)) {
            TRAPME = AEXPCEPT_TRAP;                 /* trap the system now */
            goto newpsd;                            /* process the trap */
        }

        /* Update instruction pointer to next instruction */
        if ((i_flags & BT) == 0) {                  /* see if PSD was replaced on a branch instruction */
            /* branch not taken, so update the PC */
            if (EXM_EXR != 0) {                     /* special handling for EXM, EXR, EXRR */
                PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
                EXM_EXR = 0;                        /* reset PC increment for EXR */
            } else
            if (i_flags & HLF) {                    /* if nop in rt hw, bump pc a word */
                if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6))) {    
                    PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
                } else {
                    PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);
                }
            } else {
                PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
            }
        } else {
            EXM_EXR = 0;                            /* reset PC increment for EXR */
        }
        drop_nop = 0;                               /* no NOP to drop */

        OPSD1 &= 0x87FFFFFE;                        /* clear the old CC's */
        OPSD1 |= PSD1 & 0x78000000;                 /* update the CC's in the PSD */
        /* TODO Update other history information for this instruction */
        if (hst_lnt) {
            hst[hst_p].opsd1 = OPSD1;               /* update the CC in opsd1 */
            hst[hst_p].npsd1 = PSD1;                /* save new psd1 */
            hst[hst_p].npsd2 = PSD2;                /* save new psd2 */
            hst[hst_p].modes = MODES;               /* save current mode bits */
            hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */
            if (CPUSTATUS & BIT24)
                hst[hst_p].modes |= INTBLKD;        /* save blocking mode bit */
            if (CPUSTATUS & BIT27)
                hst[hst_p].modes |= IPUMODE;        /* save cpu/ipu status bit */
            for (ix=0; ix<8; ix++) {
                hst[hst_p].reg[ix] = GPR[ix];       /* save reg */
                hst[hst_p].reg[ix+8] = BR[ix];      /* save breg */
            }
        }

        /* DEBUG_INST support code */
        /* output mapped/unmapped */
        if (MODES & BASEBIT)
            BM = 'B';
        else
            BM = 'N';
        if (MODES & MAPMODE)
            MM = 'M';
        else
            MM = 'U';
        if (CPUSTATUS & BIT24)
            BK = 'B';
        else
            BK = 'U';
        sim_debug(DEBUG_INST, my_dev, "%s %c%c%c %.8x %.8x %.8x ",
            (CPUSTATUS & BIT27) ? "IPU": "CPU",
            BM, MM, BK, OPSD1, PSD2, OIR);
        if (cpu_dev.dctrl & DEBUG_INST) {
            fprint_inst(sim_deb, OIR, 0);           /* display instruction */
        sim_debug(DEBUG_INST, my_dev,
            "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
        sim_debug(DEBUG_INST, my_dev,
            " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
            if (MODES & BASEBIT) {
                sim_debug(DEBUG_INST, my_dev,
                    "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]);
                sim_debug(DEBUG_INST, my_dev,
                    " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]);
            }
        }
        continue;                                   /* keep running */

newpsd:
        /* Trap Context Block - 6 words */
        /* WD1  Old PSD Wd 1 */
        /* WD2  Old PSD Wd 2 */
        /* WD3  New PSD WD 1 */
        /* WD4  New PSD Wd 2 */
        /* WD5  Multi Use */            /* N/U for Interrupts */
        /* WD6  Multi Use */            /* N/U for Interrupts */

        /* WD5  Multi Use */            /* IOCL address for I/O */
        /* WD6  Multi Use */            /* Status address for I/O */

        /* WD5  Multi Use */            /* Secondary vector table for SVC */
        /* WD6  Multi Use */            /* N/U for SVC */

        /* WD5  Multi Use */            /* Trap status word for traps */
        /* WD6  Multi Use */            /* N/U for traps */

        /* WD5  Multi Use */            /* Trap status word for page faults */
        /* WD6  Multi Use */            /* Page fault status word */
            /* Bit 0 = 0  The map fault was caused by an instruction fetch */
            /*       = 1  The mp fault was caused by an operand access */
            /* Bits 1-20  Always zero */
            /* Map register number (logical map block number) */

        /* we get here from a LPSD, LPSDCM, INTR, or TRAP */
        if (TRAPME) {
            /* SPAD location 0xf0 has trap vector base address */
            uint32 tta = SPAD[0xf0];                /* get trap table address in memory */
            uint32 tvl;                             /* trap vector location */
            if ((tta == 0) || ((tta&MASK24) == MASK24)) {
                if (CPUSTATUS & ONIPU) {
                    tta = 0x20;                     /* if not set, assume 0x20 FIXME */
                } else {
                    tta = 0x80;                     /* if not set, assume 0x80 FIXME */
                }
            }
            /* Trap Table Address in memory is pointed to by SPAD 0xF0 */
            /* TODO update cpu status and trap status words with reason too */
            switch(TRAPME) {
            case POWERFAIL_TRAP:                    /* 0x80 PL00/PL01 power fail trap */
            case POWERON_TRAP:                      /* 0x84 PL00/PL01 Power-On trap */
            case MEMPARITY_TRAP:                    /* 0x88 PL02 Memory Parity Error trap */
            case NONPRESMEM_TRAP:                   /* 0x8C PL03 Non Present Memory trap */
            case UNDEFINSTR_TRAP:                   /* 0x90 PL04 Undefined Instruction Trap */
            case PRIVVIOL_TRAP:                     /* 0x94 PL05 Privlege Violation Trap */
//MOVED     case SVCCALL_TRAP:                      /* 0x98 PL06 Supervisor Call Trap */
            case MACHINECHK_TRAP:                   /* 0x9C PL07 Machine Check Trap */
            case SYSTEMCHK_TRAP:                    /* 0xA0 PL08 System Check Trap */
            case MAPFAULT_TRAP:                     /* 0xA4 PL09 Map Fault Trap */
//MOVED     case IPUUNDEFI_TRAP:                    /* 0xA8 PL0A IPU Undefined Instruction Trap */
            case IPUUNDEFI_TRAP:                    /* 0xA8 PL0A IPU Undefined Instruction Trap */
//MOVED     case CALM_TRAP:                         /* 0xA8 PL0A Call Monitor Instruction Trap */
//MOVED     case SIGNALIPU_TRAP:                    /* 0xAC PL0B Signal IPU/CPU Trap */
            case ADDRSPEC_TRAP:                     /* 0xB0 PL0C Address Specification Trap */
//BAD HERE  case CONSOLEATN_TRAP:                   /* 0xB4 PL0D Console Attention Trap */
            case PRIVHALT_TRAP:                     /* 0xB8 PL0E Privlege Mode Halt Trap */
            case AEXPCEPT_TRAP:                     /* 0xBC PL0F Arithmetic Exception Trap */
            case CACHEERR_TRAP:                     /* 0xC0 PL10 Cache Error Trap (V9 Only) */
                /* drop through */
            default:
                sim_debug(DEBUG_EXP, my_dev,
                    "##TRAPME @%s %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %1x i_flags %04x\n",
                    (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
                    TRAPME, PSD1, PSD2, CPUSTATUS, drop_nop, i_flags);
                /* adjust PSD1 to next instruction */
                /* Update instruction pointer to next instruction */
                if ((i_flags & BT) == 0) {          /* see if PSD was replaced on a branch instruction */
                    /* branch not taken, so update the PC */
                    if (EXM_EXR != 0) {             /* special handling for EXM, EXR, EXRR */
                        PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
                        EXM_EXR = 0;                /* reset PC increment for EXR */
                    } else
                    if (i_flags & HLF) {            /* if nop in rt hw, bump pc a word */
                        if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6))) {    
                            PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
                        } else {
                            PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);
                        }
                    } else {
                        PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
                        //DIAG fix for test 34/10 in MMM diag, reset bit 31
                        if ((CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97) ||
                            (CPU_MODEL == MODEL_V9))
                            PSD1 &= ~BIT31;         /* force off last right */
                    }
                } else {
                    EXM_EXR = 0;                    /* reset PC increment for EXR */
                    if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL >= MODEL_V6)))
                        PSD1 &= ~BIT31;             /* force off last right */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "##GOT BT TRAPME %02x LOAD MAPS PSD1 %08x PSD2 %08x\n",
                        TRAPME, PSD1, PSD2);
                }
                drop_nop = 0;
                /* fall through */
                /* do not update pc for page fault */
            case DEMANDPG_TRAP:                     /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
                if (TRAPME == DEMANDPG_TRAP) {      /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
                    /* Set map number */
                    if (CPU_MODEL >= MODEL_V9)
                        PSD1 &= ~BIT31;             /* force off last right */
                    /* pfault will have 11 bit page number and bit 0 set if op fetch */
                    sim_debug(DEBUG_TRAP, my_dev,
                    "##PAGEFAULT TRAPS %02x page# %04x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
                    TRAPME, pfault, PSD1, PSD2, CPUSTATUS);
                }
                /* Moved here 05/28/2021 so PC gets incremented correctly */
                /* This caused the 2nd instruction of an int service routine to be skipped */
                /* The attn trap had to be on 2nd instruction */
            case CONSOLEATN_TRAP:                   /* 0xB4 PL0D Console Attention Trap */
//112522    case IPUUNDEFI_TRAP:                    /* 0xA8 PL0A IPU Undefined Instruction Trap */
            case SIGNALIPU_TRAP:                    /* 0xAC PL0B Signal IPU/CPU Trap */
                sim_debug(DEBUG_TRAP, my_dev,
                    "At %s TRAP %02x IR %08x PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %01x\n",
                    (CPUSTATUS & ONIPU)? "IPU": "CPU",
                    TRAPME, IR, PSD1, PSD2, CPUSTATUS, drop_nop);
                sim_debug(DEBUG_TRAP, my_dev,
                    "R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]);
                sim_debug(DEBUG_TRAP, my_dev,
                    "R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);

                tta = tta + (TRAPME - 0x80);        /* tta has mem addr of trap vector */
                tvl = M[tta>>2] & 0xFFFFFC;         /* get 24 bit trap address from trap vector loc */
                sim_debug(DEBUG_TRAP, my_dev,
                    "CPU tvl %08x, tta %02x CCW %08x status %08x\n",
                    tvl, tta, CCW, CPUSTATUS);
                if (!MEM_ADDR_OK(tvl & MASK24)) {   /* see if in memory */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "CPU Bad trap PSD1 %08x PSD2 %08x TRAPME %02x\r\n", PSD1, PSD2, TRAPME);
                    /* bad address for trap vector, lets halt */
                    fprintf(stderr, "CPU Bad trap PSD1 %08x PSD2 %08x TRAPME %02x\r\n", PSD1, PSD2, TRAPME);
                    fprintf(stderr, "CPU Bad trap address tvl %08x, tta %02x CCW %08x status %08x\r\n",
                        tvl, tta, CCW, CPUSTATUS);
                    fflush(stderr);
                    fprintf(stderr, "M[tta] %08x M[tvl] %08x M[tvl+1] %08x M[tvl+2] %08x M[tvl+3]] %08x\r\n",
                    M[tta>>2], M[(tvl>>2)+0], M[(tvl>>2)+1], M[(tvl>>2)+2], M[(tvl>>2)+3]);
                    fflush(stderr);
                    goto doahalt;
                }
                sim_debug(DEBUG_TRAP, my_dev,
                    "M[tta] %08x M[tvl] %08x M[tvl+1] %08x M[tvl+2] %08x M[tvl+3]] %08x\n",
                    M[tta>>2], M[(tvl>>2)+0], M[(tvl>>2)+1], M[(tvl>>2)+2], M[(tvl>>2)+3]);
#ifndef TEMP_CHANGE_FOR_MPX3X_DEBUG
                if (tvl == 0 || (CPUSTATUS & 0x40) == 0) {
#else
                /* next line changed to force halt on halt trap */
                /* TRIED 041320 for MPX3.X install and testing */
                if (((tvl == 0) || (CPUSTATUS & 0x40) == 0) || 
                    (TRAPME == PRIVHALT_TRAP)) {    /* 0xB8 PL0E Privlege Mode Halt Trap */
#endif
doahalt:
                    /* vector is zero or software has not enabled traps yet */
                    /* execute a trap halt */
                    /* set the PSD to trap vector location */
                    fprintf(stderr, "[][][][][][][][][][] HALT TRAP [2][][][][][][][][][]\r\n");
                    fprintf(stderr, "PSD1 %08x PSD2 %08x TRAPME %02x\r\n", PSD1, PSD2, TRAPME);
                    PSD1 = 0x80000000 + tta;        /* just priv and PC to trap vector */
                    PSD2 = 0x00004000;              /* unmapped, blocked interrupts mode */
                    /*
                     * Some illegal traps result in automatic TRAP HALT
                     * as per V6 TM page 2-50 locations for saving status
                     * obviously differ for CPU and IPU
                     */
                    if (CPUSTATUS & ONIPU) {
                        /* for IPU */
                        M[0x690>>2] = PSD1;         /* store PSD 1 */
                        M[0x694>>2] = PSD2;         /* store PSD 2 */
                        M[0x698>>2] = TRAPSTATUS;   /* store trap status */
                        M[0x69C>>2] = 0;            /* This will be device table entry later TODO */
                    } else {
                        /* for CPU */
                        M[0x680>>2] = PSD1;         /* store PSD 1 */
                        M[0x684>>2] = PSD2;         /* store PSD 2 */
                        M[0x688>>2] = TRAPSTATUS;   /* store trap status */
                        M[0x68C>>2] = 0;            /* This will be device table entry later TODO */
                    }
                    for (ix=0; ix<8; ix+=2) {
                        fprintf(stderr, "GPR[%d] %08x GPR[%d] %08x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]);
                    }
                    if (MODES & BASEBIT) {
                        for (ix=0; ix<8; ix+=2) {
                            fprintf(stderr, "BR[%d] %08x BR[%d] %08x\r\n", ix, BR[ix], ix+1, BR[ix+1]);
                        }
                    }
                    fprintf(stderr, "[][][][][][][][][][] HALT TRAP [2][][][][][][][][][]\r\n");
                    fflush(stderr);
                    if (IPU_MODEL && (CPUSTATUS & ONIPU)) {
                        sim_debug(DEBUG_TRAP, my_dev,
                            "%s: Halt TRAP CPUSTATUS %08x CCW %08x\n",
                            (CPUSTATUS & ONIPU)? "IPU": "CPU",
                            CPUSTATUS, CCW);

#ifndef CPUONLY
#ifdef NO_KILL_112422
                        /* If we have an IPU, and we are on the CPU: destroy the IPU */
                        if ((CCW & HASIPU) && IPC != 0 && !(CPUSTATUS & ONIPU)) {
                            kill(IPC->pid[1], SIGKILL); /* destroy the IPU */
                        }
#endif
#endif
                    }
#ifndef USE_IPU_THREAD
                    reason = STOP_HALT;             /* do halt for now */
                    fflush(sim_deb);
                    return STOP_HALT;               /* exit to simh for halt */
#else
                    reason = STOP_HALT;             /* do halt for now */
                    cpustop = STOP_HALT;            /* tell IPU to stop */
                    sim_debug(DEBUG_TRAP, my_dev,
                        "[][][][][][][][][][] Send HALT to IPU [][][][][][][][][][]\n");
                    fflush(sim_deb);
                    return STOP_HALT;               /* exit to simh for halt */
#endif
                } else {
                    uint32 oldstatus = CPUSTATUS;   /* keep for retain blocking state */
                    /* valid vector, so store the PSD, fetch new PSD */
                    bc = PSD2 & 0x3ff8;             /* get copy of cpix */
                    if ((TRAPME) && ((CPU_MODEL <= MODEL_27))) {
                            /* Traps on 27 have bit 31 reset */
                            M[tvl>>2] = PSD1 & 0xfffffffe;  /* store PSD 1 */
                    } else
                        M[tvl>>2] = PSD1 & 0xffffffff;  /* store PSD 1 */
                    M[(tvl>>2)+1] = PSD2;           /* store PSD 2 */
                    PSD1 = M[(tvl>>2)+2];           /* get new PSD 1 */
                    PSD2 = (M[(tvl>>2)+3] & ~0x3ff8) | bc;  /* get new PSD 2 w/old cpix */
                    M[(tvl>>2)+4] = TRAPSTATUS;     /* store trap status */
                    if (TRAPME == DEMANDPG_TRAP) {  /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
                        M[(tvl>>2)+5] = pfault;     /* store page fault number */
                        sim_debug(DEBUG_TRAP, my_dev,
                            "DPAGE tvl %06x PSD1 %08x PSD2 %08x TRAPME %02x TRAPSTATUS %08x\n",
                            tvl, PSD1, PSD2, TRAPME, pfault);
                    }

                    /* set the mode bits and CCs from the new PSD */
                    CC = PSD1 & 0x78000000;         /* extract bits 1-4 from PSD1 */
                    MODES = PSD1 & 0x87000000;      /* extract bits 0, 5, 6, 7 from PSD 1 */
                    CPUSTATUS &= ~0x87000000;       /* reset bits in CPUSTATUS */
                    CPUSTATUS |= (MODES & 0x87000000);  /* now insert into CPUSTATUS */

                    /* set new map mode and interrupt blocking state in CPUSTATUS */
                    if (PSD2 & MAPBIT) {
                        CPUSTATUS |= BIT8;          /* set bit 8 of cpu status */
                        MODES |= MAPMODE;           /* set mapped mode */
                    } else {
                        CPUSTATUS &= ~BIT8;         /* reset bit 8 of cpu status */
                        MODES &= ~MAPMODE;          /* reset mapped mode */
                    }

                    /* set interrupt blocking state */
                    if ((PSD2 & RETBBIT) == 0) {    /* is it retain blocking state */
                        if (PSD2 & SETBBIT) {       /* no, is it set blocking state */
                            CPUSTATUS |= BIT24;     /* yes, set blk state in cpu status bit 24 */
                            MODES |= BLKMODE;       /* set blocked mode */
                        } else {
                            CPUSTATUS &= ~BIT24;    /* no, reset blk state in cpu status bit 24 */
                            MODES &= ~BLKMODE;      /* reset blocked mode */
                        }
                    } else {
                        /* handle retain blocking state */
                        PSD2 &= ~RETMBIT;           /* turn off retain map bit in PSD2 */
                        /* set new blocking state in PSD2 */
                        PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */
                        MODES &= ~(BLKMODE|RETBLKM);/* reset blocked & retain mode bits */
                        if (oldstatus & BIT24) {    /* see if old mode is blocked */
                            PSD2 |= SETBBIT;        /* set to blocked state */
                            MODES |= BLKMODE;       /* set blocked mode */
                        }
                    }

                    SPAD[0xf5] = PSD2;              /* save the current PSD2 */
                    SPAD[0xf9] = CPUSTATUS;         /* save the cpu status in SPAD */

                    sim_debug(DEBUG_TRAP, my_dev,
                        "Process %s TRAPME %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x MODE %08x\n",
                        (CPUSTATUS & ONIPU)? "IPU": "CPU",
                        tta, PSD1, PSD2, CPUSTATUS, MODES);
                    /* TODO provide page fault data to word 6 */
                    if (TRAPME == DEMANDPG_TRAP) {  /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
                        /* Set map number */
                        /* pfault will have 11 bit page number and bit 0 set if op fetch */
                        sim_debug(DEBUG_TRAP, my_dev,
            "PAGE TRAP %02x TSTAT %08x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTAT %08x pfault %08x\n",
                            TRAPME, TRAPSTATUS, PSD1, PSD2, CPUSTATUS, pfault);
                    }
                    TRAPSTATUS = CPUSTATUS & 0x57;  /* clear all trap status except cpu type */
                    TRAPME = 0;                     /* to be safe */
                    break;                          /* Go execute the trap */
                }
                break;
            }
        }
        continue;                                   /* single step cpu just for now */
    }   /* end wait loop while */

    /* Simulation halted */
    sim_debug(DEBUG_EXP, my_dev,
        "Process Event other reason %08x interval %08x\n",
        reason, sim_interval);

    /* we need to do an actual halt here if on IPU */
    sim_debug(DEBUG_EXP, my_dev,
        "\n[][][][][][][][][][] HALT [3][][][][][][][][][]\n");
    sim_debug(DEBUG_EXP, my_dev,
        "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x\n",
        (CPUSTATUS & ONIPU) ? "IPU" : "CPU",
        PSD1, PSD2, TRAPME, CPUSTATUS);
    for (ix=0; ix<8; ix+=2) {
        sim_debug(DEBUG_EXP, my_dev,
        "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]);
    }
    sim_debug(DEBUG_EXP, my_dev,
        "[][][][][][][][][][] HALT [3][][][][][][][][][]\n");
    fflush(sim_deb);

#ifndef USE_IPU_THREAD
#ifdef DEBUG4IPU
    DumpHist();
#endif
#endif
    fprintf(stdout, "[][][][][][][][][][] IPU HALT3 [3][][][][][][][][][]\r\n");
    fflush(stdout);
#ifdef USE_IPU_THREAD
    pthread_exit((void *)&reason);
#endif
    return reason;                                  /* exit to simh for halt */
}

/* these are the default ipl devices defined by the CPU jumpers */
/* they can be overridden by specifying IPL device at ipl time */
#ifndef USE_IPU_THREAD
LOCAL uint32 def_disk = 0x0800;                     /* disk channel 8, device 0 */
LOCAL uint32 def_floppy = 0x7ef0;                   /* IOP floppy disk channel 7e, device f0 */
#endif
LOCAL uint32 def_tape = 0x1000;                     /* tape device 10, device 0 */

/* Reset routine */
/* do any one time initialization here for cpu */
t_stat cpu_reset(DEVICE *dptr)
{
    int     i;
    t_stat  devs = SCPE_OK;

    /* leave regs alone so values can be passed to boot code */
    PSD1 = 0x80000000;                              /* privileged, non mapped, non extended, address 0 */
    PSD2 = 0x00004000;                              /* blocked interrupts mode */
    MODES = (PRIVBIT | BLKMODE);                    /* set modes to privileged and blocked interrupts */
    CC = 0;                                         /* no CCs too */
    CPUSTATUS = CPU_MODEL;                          /* clear all cpu status except cpu type */
    CPUSTATUS |= PRIVBIT;                           /* set privleged state bit 0 */
    CPUSTATUS |= BIT24;                             /* set blocked mode state bit 24 */
    CPUSTATUS |= BIT22;                             /* set HS floating point unit not present bit 22 */
    TRAPSTATUS = CPU_MODEL;                         /* clear all trap status except cpu type */
    CMCR = 0;                                       /* No Cache Enabled */
    SMCR = 0;                                       /* No Shared Memory Enabled */
    CMSMC = 0x00ff0a10;                             /* No V9 Cache/Shadow Memory Configuration */
    CSMCW = 0;                                      /* No V9 CPU Shadow Memory Configuration */
    ISMCW = 0;                                      /* No V9 IPU Shadow Memory Configuration */
#ifdef NOT_USED
    RDYQIN = RDYQOUT = 0;                           /* initialize channel ready queue */
#endif

#ifndef CPUONLY
#ifndef USE_IPU_THREAD
    /* allocate the memory here and now, but only once */
    /* add extra for IPU structure for IPU when running forked */
    if (M == 0) {
        /* first pass of cpu_reset: alloc our SELbus memory */
        M = (uint32 *)create_shared_memory(4 * MAXMEMSIZE + sizeof(struct ipcom));
        for (i = 0; i < MAXMEMSIZE + ((sizeof(struct ipcom)+3)/4) - 1; i++)
            M[i] = 0;                               /* zero all of the new memory & IPC */
        /* Create InterProcessor Com data */
        /* we piggyback on the main memory that we created larger */
        IPC = (struct ipcom *)&M[MAXMEMSIZE];
    }
#else
    /* local memory is shared, and is defined as M[MAXMEMSIZE] */
    /* no special allocation is required for 2nd thread */
    IPC = (struct ipcom *)&myipc;
#endif
#else /* CPUONLY */
    /* local memory is not shared, and is defined as M[MAXMEMSIZE] */
    /* no special allocation is required on CPU only */
#endif /* CPUONLY */

#ifdef USE_IPU_THREAD
    ipu_unit.flags = cpu_unit.flags;                /* tell ipu about cpu flags */
    ipu_unit.capac = cpu_unit.capac;                /* tell ipu about memory */
#endif

    if (IPU_MODEL)
        CCW |= HASIPU;                              /* this is BIT19 */

    devs = chan_set_devs();                         /* set up the defined devices on the simulator */

    /* set default breaks to execution tracing */
    sim_brk_types = sim_brk_dflt = SWMASK('E');

    /* zero regs */
    for (i = 0; i < 8; i++) {
        GPR[i] = BOOTR[i];                          /* set boot register values */
        BR[i] = 0;                                  /* clear the registers */
    }
#ifndef USE_IPU_THREAD
    /* set console switch settings */
    M[0x780>>2] = CSW;                              /* set console switch settings */
#endif

    /* zero interrupt status words */
    for (i = 0; i < 112; i++)
        INTS[i] = 0;                                /* clear interrupt status flags */

    /* add code here to initialize the SEL32 cpu scratchpad on initial start */
    /* see if spad setup by software, if yes, leave spad alone */
    /* otherwise set the default values into the spad */
    /* CPU key is 0xECDAB897, IPU key is 0x13254768 */
    /* Keys are loaded by the O/S software during the boot loading sequence */
    /*
     * SPAD init for both CPU and IPU unless they have the right key
     */
    if (SPAD[0xf7] != 0xecdab897 && SPAD[0xf7] != 0x13254768) {
        int ival = 0;                               /* init value for concept 32 */

#ifndef CPUONLY
#ifndef USE_IPU_THREAD
        /* If we have a forked IPU, and we are on the CPU: destroy the IPU */
        if ((CCW & HASIPU) && IPC != 0 && !(CPUSTATUS & ONIPU) && (IPC->pid[1] != 0)) {
            fprintf(stdout,"CCW %x IPC %p CPUSTATUS %x\r\n", CCW, IPC, CPUSTATUS);
            fprintf(stdout,"Killing IPU pid=%d 0x80=%x\r\n", IPC->pid[1], SPAD[0xf0]);
            fflush(stdout);
            kill(IPC->pid[1], SIGKILL); /* destroy the IPU */
        }
#else
#ifndef USE_POSIX_SEM
        /* intialize the pthread mutex and cond on thread IPU/CPU */
        pthread_mutex_init(&IPC->mutex, NULL);
        pthread_cond_init(&IPC->cond, NULL);
#endif
#endif
#endif
        if (CPU_MODEL < MODEL_27)
            ival = 0xfffffff;                       /* init value for 32/7x int and dev entries */
        for (i = 0; i < 1024; i++)
            MAPC[i] = 0;                            /* clear 2048 halfword map cache */
        for (i = 0; i < 224; i++)
            SPAD[i] = ival;                         /* init 128 devices and 96 ints in the spad */
        for (i = 224; i < 256; i++)                 /* clear the last 32 extries */
            SPAD[i] = 0;                            /* clear the spad */
#ifndef CPUONLY
        if (CPUSTATUS & ONIPU)
            SPAD[0xf0] = 0x20;                      /* default Trap Table Address (TTA) */
        else
            SPAD[0xf0] = 0x80;                      /* default Trap Table Address (TTA) */
#else 
        SPAD[0xf0] = 0x80;                          /* default Trap Table Address (TTA) */
#endif
        SPAD[0xf1] = 0x100;                         /* Interrupt Table Address (ITA) */
        SPAD[0xf2] = 0x700;                         /* IOCD Base Address */
        SPAD[0xf3] = 0x788;                         /* Master Process List (MPL) table address */
        SPAD[0xf4] = def_tape;                      /* Default IPL address from console IPL command or jumper */
        SPAD[0xf5] = PSD2;                          /* current PSD2 defaults to blocked */
        SPAD[0xf6] = 0;                             /* reserved (PSD1 ??) */
#ifndef CPUONLY
        if (CPUSTATUS & ONIPU)
            SPAD[0xf7] = 0x13254768;                /* set SPAD key for IPU */
        else
            SPAD[0xf7] = 0xecdab897;                /* load the CPU key */
#else
        SPAD[0xf7] = 0xecdab897;                    /* load the CPU key */
#endif
        SPAD[0xf8] = 0x0f000000;                    /* set DRT to class f (anything else is E) */
        SPAD[0xf9] = CPUSTATUS;                     /* set default cpu type in cpu status word */
        SPAD[0xff] = 0x00ffffff;                    /* interrupt level 7f 1's complament */
    }

#if 0
    /* set low memory bootstrap code */
    /* moved to boot code in sel32_chan.c so we can reset system and not destroy memory */
    M[0] = 0x02000000;                              /* 0x00 IOCD 1 read into address 0 */
    M[1] = 0x60000078;                              /* 0x04 IOCD 1 CMD Chain, Suppress incor len, 120 bytes */
    M[2] = 0x53000000;                              /* 0x08 IOCD 2 BKSR or RZR to re-read boot code */
    M[3] = 0x60000001;                              /* 0x0C IOCD 2 CMD chain,Supress incor length, 1 byte */
    M[4] = 0x02000000;                              /* 0x10 IOCD 3 Read into address 0 */
    M[5] = 0x000006EC;                              /* 0x14 IOCD 3 Read 0x6EC bytes */
#endif

#ifndef LEAVE_THIS_CODE_FOR_AWHILE
#ifndef CPUONLY
#ifndef USE_IPU_THREAD
    /* the IPU should never get to this code! */
//  fprintf(stdout,"LEAVE CCW %x IPC %p CPUSTATUS %x\r\n", CCW, IPC, CPUSTATUS);
    if (CPUSTATUS & ONIPU) {
        /* I am the IPU */
        if (IPC != 0) {
            fprintf(stdout,"IPU IPC %p pid=%d 0x80=%x\r\n", IPC, IPC->pid[1], SPAD[0xf0]);
            fflush(stdout);
        }
    } else {
        /* I am the CPU */
        if (IPC != 0 && !(CPUSTATUS & ONIPU) && (IPC->pid[1] != 0)) {
            fprintf(stdout,"CPU IPC %p pid=%d IPU pid %d 0x80=%x\r\n", IPC, IPC->pid[0], IPC->pid[1], SPAD[0xf0]);
            fflush(stdout);
            fprintf(stdout,"Killing IPU pid=%d 0x80=%xi\r\n", IPC->pid[1], SPAD[0xf0]);
            fflush(stdout);
            kill(IPC->pid[1], SIGKILL); /* destroy the IPU */
        }
    }
#endif
#endif
#endif
    fflush(sim_deb);
    loading = 0;                                    /* not loading yet */
    /* we are good to go or error from device setup */
    if (devs != SCPE_OK)
        return devs;
    return SCPE_OK;
}

/* Memory examine */
/* examine a 32bit memory location and return a byte */
t_stat cpu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw)
{
    uint32 status, realaddr, prot;
    uint32 addr = (baddr & 0xfffffc) >> 2;          /* make 24 bit byte address into word address */

    if (sw & SWMASK('V')) {
        /* convert address to real physical address */
        status = RealAddr(addr, &realaddr, &prot, MEM_RD);
        sim_debug(DEBUG_CMD, my_dev, "cpu_ex Mem_read status = %02x\n", status);
        if (status == ALLOK) {
            *vptr = (M[realaddr] >> (8 * (3 - (baddr & 0x3))));  /* return memory contents */
            return SCPE_OK;                         /* we are all ok */
        }
        return SCPE_NXM;                            /* no, none existant memory error */
    }
    /* MSIZE is in 32 bit words */
    if (!MEM_ADDR_OK(addr))                         /* see if address is within our memory */
        return SCPE_NXM;                            /* no, none existant memory error */
    if (vptr == NULL)                               /* any address specified by user */
        return SCPE_OK;                             /* no, just ignore the request */
    *vptr = (M[addr] >> (8 * (3 - (baddr & 0x3)))); /* return memory contents */
    return SCPE_OK;                                 /* we are all ok */
}

/* Memory deposit */
/* modify a byte specified by a 32bit memory location */
/* address is byte address with bits 30,31 = 0 */
t_stat cpu_dep(t_value val, t_addr baddr, UNIT *uptr, int32 sw)
{
    uint32 addr = (baddr & 0xfffffc) >> 2;          /* make 24 bit byte address into word address */
    static const uint32 bmasks[4] = {0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00};

    /* MSIZE is in 32 bit words */
    if (!MEM_ADDR_OK(addr))                         /* see if address is within our memory */
        return SCPE_NXM;                            /* no, none existant memory error */
    val = (M[addr] & bmasks[baddr & 0x3]) | (val << (8 * (3 - (baddr & 0x3))));
    M[addr] = val;                                  /* set new value */
    return SCPE_OK;                                 /* all OK */
}

/* set the CPU memory size */
/* table values are in words, not bytes */
uint32 memwds [] = {
    0x008000,   /* size index 0 - 128KB =  32KW */
    0x010000,   /*            1 - 256KB =  64KW */
    0x020000,   /*            2 - 512KB = 128KW */
    0x040000,   /*            3 -   1MB = 256KW */
    0x080000,   /*            4 -   2MB = 512KW */
    0x0c0000,   /*            5 -   3MB = 768KW */
    0x100000,   /*            6 -   4MB =   1MW */
    0x180000,   /*            7 -   6MB = 1.5MW */
    0x200000,   /*            8 -   8MB =   2MW */
    0x300000,   /*            9 -  12MB =   3MW */
    0x400000,   /*           10 -  16MB =   4MW */
};

t_stat cpu_set_size(UNIT *uptr, int32 sval, CONST char *cptr, void *desc)
{
    uint32      i;
    uint32      sz;
    int32       val = (int32)sval;
    t_addr      msize;

//  sim_printf("cpu_set_size sval %x cptr %s desc %s\n", sval, cptr, (char *)desc);
    val >>= UNIT_V_MSIZE;                           /* shift index right 19 bits */

    if (val >= (int32)(sizeof(memwds)/sizeof(uint32)))  /* is size valid */
        return SCPE_ARG;                            /* nope, argument error */
    sz = memwds[val];                               /* (128KB/4) << index == memory size in KW */
    if ((sz <= 0) || (sz > MAXMEMSIZE))             /* is size valid */
        return SCPE_ARG;                            /* nope, argument error */
    msize = sz << 2;                                /* Convert to words */

    if (msize < MEMSIZE) {                          /* is size smaller */
        uint32 mc = 0;                              /* yes, see if larger memory was used */
        for (i = sz-1; i < (MEMSIZE>>2); i++)
            mc = mc | M[i];                         /* or in any bits we might find */
        if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
            return SCPE_OK;                         /* forget update */
    }
    for (i = (MEMSIZE>>2) - 1; i < sz; i++)
        M[i] = 0;                                   /* zero all of the new memory */
    cpu_unit.flags &= ~UNIT_MSIZE;                  /* clear old size value 0-31 */
    cpu_unit.flags |= (val << UNIT_V_MSIZE);        /* set new memory size index value (0-31) */
    cpu_unit.capac = (t_addr)msize;                 /* set new size */
#ifdef USE_IPU_THREAD
    ipu_unit.flags = cpu_unit.flags;                /* tell ipu about cpu flags */
    ipu_unit.capac = cpu_unit.capac;                /* tell ipu about memory */
#endif
    return SCPE_OK;                                 /* we done */
}

#ifdef DEFINE_IPU_MODELS
t_stat cpu_set_ipu(UNIT *uptr, int32 sval, CONST char *cptr, void *desc)
{
//  sim_printf("cpu_set_ipu sval %x cptr %s desc %s\n", sval, cptr, (char *)desc);
#ifdef CPUONLY
    sim_printf("IPU not available for this version of sel32\n");  
    return SCPE_ARG;                                /* error, we done */
#endif
    if ((CPU_MODEL == MODEL_55) || (CPU_MODEL == MODEL_27)) {
       sim_printf("IPU not available for model 32/55 or 32/27\n");  
        return SCPE_ARG;                                /* error, we done */
    } else {
        cpu_unit.flags |= (1 << UNIT_V_IPU);        /* enable IPU for this MODEL */
#ifdef USE_IPU_THREAD
        ipu_unit.flags = cpu_unit.flags;            /* tell ipu about cpu flags */
#endif
        sim_printf("IPU enabled\n");
    }
    return SCPE_OK;                                 /* we done */
}

t_stat cpu_clr_ipu(UNIT *uptr, int32 sval, CONST char *cptr, void *desc)
{
    cpu_unit.flags &= ~UNIT_IPU;                    /* disable IPU for this MODEL */
#ifdef USE_IPU_THREAD
    ipu_unit.flags = cpu_unit.flags;                /* tell ipu about cpu flags */
#endif
    sim_printf("IPU disabled\n");
    return SCPE_OK;                                 /* we done */
}

t_stat cpu_show_ipu(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
    if (IPU_MODEL)
        sim_printf("IPU enabled\n");
    else
        sim_printf("IPU disabled\n");
    return SCPE_OK;                                 /* we done */
}
#endif

/* Handle execute history */

/* Set history */
t_stat
cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
    int32               i, lnt;
    t_stat              r;

//  sim_printf("cpu_set_hist val %x cptr %s desc %s\n", val, cptr, (char *)desc);
    if (cptr == NULL) {                             /* check for any user options */
        for (i = 0; i < hst_lnt; i++)               /* none, so just zero the history */
            hst[i].opsd1 = 0;                       /* just psd1 for now */
        hst_p = 0;                                  /* start at the beginning */
        return SCPE_OK;                             /* all OK */
    }
    /* the user has specified options, process them */
    lnt = (int32)get_uint(cptr, 10, HIST_MAX, &r);
    if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
        return SCPE_ARG;                            /* arg error for bad input or too small a value */
    hst_p = 0;                                      /* start at beginning */
    if (hst_lnt) {                                  /* if a new length was input, resize history buffer */
        free(hst);                                  /* out with the old */
        hst_lnt = 0;                                /* no length anymore */
        hst = NULL;                                 /* and no pointer either */
    }
    if (lnt) {                                      /* see if new size specified, if so get new resized bfer */
        hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);
        if (hst == NULL)
            return SCPE_MEM;                        /* allocation error, so tell user */
        hst_lnt = lnt;                              /* set new length */
    }
    return SCPE_OK;                                 /* we are good to go */
}

/* Show history */
t_stat cpu_show_hist(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
    int32               k, di, lnt;
    char               *cptr = (char *) desc;
    t_stat              r;
    uint8               BM, MM, BK;                 /* basemode, mapped mode, blocked mode */
    struct InstHistory *h;

    if (hst_lnt == 0)                               /* see if show history is enabled */
        return SCPE_NOFNC;                          /* no, so we are out of here */
    if (cptr) {                                     /* see if user provided a display count */
        lnt = (int32)get_uint(cptr, 10, hst_lnt, &r);   /* get the count */
        if ((r != SCPE_OK) || (lnt == 0))           /* if error or 0 count */
            return SCPE_ARG;                        /* report argument error */
    } else
        lnt = hst_lnt;                              /* dump all the entries */
    di = hst_p - lnt;                               /* work forward */
    if (di < 0)
        di = di + hst_lnt;                          /* wrap */
    for (k = 0; k < lnt; k++) {                     /* print specified entries */
        h = &hst[(++di) % hst_lnt];                 /* entry pointer */
        /* display the instruction and results */
        if (h->modes & BASEBIT)                     /* basemode? */
            BM = 'B';
        else
            BM = 'N';
        if (h->modes & MAPMODE)                     /* copy of PSD2 bit 0 */
            MM = 'M';
        else
            MM = 'U';
        if (h->modes & INTBLKD)                     /* get blocked bit 0x10 */
            BK = 'B';
        else
            BK = 'U';
        fprintf(st, "%s %c%c%c %.8x %.8x %.8x ",
            (h->modes & IPUMODE)? "IPU": "CPU",
            BM, MM, BK, h->opsd1, h->npsd2, h->oir);
        if (h->modes & BASEBIT)
            fprint_inst(st, h->oir, SWMASK('M'));   /* display basemode instruction */
        else
            fprint_inst(st, h->oir, SWMASK('N'));   /* display non basemode instruction */
        fprintf(st, " --->NPSD %.8x %.8x", h->npsd1, h->npsd2);
        fprintf(st, "\n");
        fprintf(st, "\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", h->reg[0], h->reg[1], h->reg[2], h->reg[3]);
        fprintf(st, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x", h->reg[4], h->reg[5], h->reg[6], h->reg[7]);
        if (h->modes & BASEBIT) {
            fprintf(st, "\n");
            fprintf(st, "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", h->reg[8], h->reg[9], h->reg[10], h->reg[11]);
            fprintf(st, " B4=%.8x B5=%.8x B6=%.8x B7=%.8x", h->reg[12], h->reg[13], h->reg[14], h->reg[15]);
        }
        fprintf(st, "\n");
    }                                               /* end for */
    fflush(sim_deb);
    return SCPE_OK;                                 /* all is good */
}

/* return description for the specified device */
const char *cpu_description (DEVICE *dptr) 
{
    return "SEL 32 CPU";                            /* return description */
}

t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
    fprintf(st, "The CPU can maintain a history of the most recently executed instructions.\n");
    fprintf(st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n");
    fprintf(st, "   sim> SET CPU HISTORY            clear history buffer\n");
    fprintf(st, "   sim> SET CPU HISTORY=0          disable history\n");
    fprintf(st, "   sim> SET CPU HISTORY=n{:file}   enable history, length = n\n");
    fprintf(st, "   sim> SHOW CPU HISTORY           print CPU history\n");
    return SCPE_OK;
}

#ifndef CPUONLY
#ifndef USE_IPU_THREAD
#include <sys/mman.h>

void* create_shared_memory(size_t size) {
  // Our memory buffer will be readable and writable:
  int protection = PROT_READ | PROT_WRITE;

  // The buffer will be shared (meaning other processes can access it), but
  // anonymous (meaning third-party processes cannot obtain an address for it),
  // so only this process and its children will be able to use it:
  int visibility = MAP_SHARED | MAP_ANONYMOUS;

  // The remaining parameters to `mmap()` are not important for this use case,
  // but the manpage for `mmap` explains their purpose.
  return mmap(NULL, size, protection, visibility, -1, 0);
}
#endif
#endif
