/* icl1900_cpu.c: ICL 1900 cpu simulator

   Copyright (c) 2017, Richard Cornwell

   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
   RICHARD CORNWELL 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.

   The ICL1900 was a 24 bit CPU that supported either 32Kwords of memory or
   4Mwords of memory, depending on model.

   Level A:   lacked 066, 116 and 117 instructions and 22 bit addressing.
   Level B:   Adds 066, 116 and 117 instructions, but lack 22 bit addressing.
   Level C:   All primary and 22 bit addressing.

   Sub-level 1:  Norm 114,115 available only if FP option.
   Sub-level 2:  Norm 114,115 always available.
*/

#include "icl1900_defs.h"
#include <time.h>
#include "sim_timer.h"

#define UNIT_V_MSIZE    (UNIT_V_UF + 0)
#define UNIT_MSIZE      (0x1ff << UNIT_V_MSIZE)
#define MEMAMOUNT(x)    (x << UNIT_V_MSIZE)
#define UNIT_V_MODEL    (UNIT_V_MSIZE + 9)
#define UNIT_MODEL      (0x3f << UNIT_V_MODEL)
#define MODEL(x)        (UNIT_MODEL & (x << UNIT_V_MODEL))


#define TMR_RTC         1

#define HIST_PC         BM1
#define HIST_MAX        500000
#define HIST_MIN        64

/* Level A Primary no 066, 116, 117 15AM and DBM only */
/* Level B All Primary              15AM and DBM only */
/* Level C All Primary              15AM and 22AM, DBM and EBM */

/* Level x1, NORM when FP */
/* Level x2, NORM always */

#define MOD1            0       /* Ax OPT */
#define MOD1A           1       /* A1 OPT 04x -076 111-3 */
#define MOD1S           2       /* Ax OPT 04x -076 111-3 */
#define MOD1T           3       /* Ax OPT 04x -076 111-3 */
#define MOD2            4       /* Ax OPT 04x -076 111-3 */
#define MOD2A           5       /* B1 OPT */
#define MOD2S           6       /* B1 or C1 OPT 04x -076 111-3 */
#define MOD2T           7       /* B1 or C1 OPT 04x -076 111-3 */
#define MOD3            8       /* A1 or A2 OPT 04x -076 111-3 */
#define MOD3A           9       /* B1 or C1 OPT 04x -076 111-3 */
#define MOD3S           10      /* B1 or C1 OPT 04x -076 111-3 */
#define MOD3T           11      /* A1 or A2 OPT */
#define MOD4            12      /* A2 OPT */
#define MOD4A           13      /* C2 OPT */
#define MOD4E           14      /* C2 OPT */
#define MOD4F           15
#define MOD4S           16      /* Ax OPT */
#define MOD5            17      /* A2 FP */
#define MOD5A           18      /* Ax FP */
#define MOD5E           19      /* C2 FP */
#define MOD5F           20
#define MOD5S           21      /* Ax FP */
#define MOD6            22      /* C2 OPT */
#define MOD6A           23      /* Ax OPT 076 131 */
#define MOD6E           24      /* Ax OPT 076 */
#define MOD6F           25
#define MOD6S           26      /* Ax OPT */
#define MOD7            27      /* C2 FP */
#define MOD7A           28      /* Ax FP */
#define MOD7E           29      /* Ax FP */
#define MOD7F           30
#define MOD7S           31      /* Ax FP */
#define MOD8            32      /* Ax FP */
#define MOD8A           33      /* Ax FP */
#define MOD8S           34      /* Ax FP */
#define MOD9            35      /* A2 FP */
#define MODXF           36      /* C2 FP */



int                 cpu_index;                  /* Current running cpu */
uint32              M[MAXMEMSIZE] = { 0 };      /* memory */
uint32              RA;                         /* Temp register */
uint32              RB;                         /* Temp register */
uint32              RC;                         /* Instruction Code */
uint32              RD;                         /* Datum pointer */
uint16              RK;                         /* Counter */
uint8               RF;                         /* Function code */
uint32              RL;                         /* Limit register */
uint8               RG;                         /* General register */
uint32              RM;                         /* M field register */
uint32              RP;                         /* Temp register */
uint32              RS;                         /* Temp register */
uint32              RT;                         /* Temp register */
uint8               RX;                         /* X field register */
uint32              XR[8];                      /* Index registers */
uint32              faccl;                      /* Floating point accumulator low */
uint32              facch;                      /* Floating point accumulator high */
uint8               fovr;                       /* Floating point overflow */
uint8               BCarry;                     /* Carry bit */
uint8               BV;                         /* Overflow flag */
uint8               Mode;                       /* Mode */
uint8               Zero;                       /* Zero suppression flag */
uint8               exe_mode = 1;               /* Executive mode */
#define     EJM     040                            /* Extended jump Mode */
#define     DATUM   020                            /* Datum mode */
#define     AM22    010                            /* 22 bit addressing */
#define     EXTRC   004                            /* Executive trace mode */
/*                  002       */                   /* unused mode bit */
uint8               OIP;                        /* Obey instruction */
uint8               PIP;                        /* Pre Modify instruction */
uint8               OPIP;                       /* Saved Pre Modify instruction */
uint32              SR1;                        /* Mill timer */
uint32              SR2;                        /* Typewriter I/P */
uint32              SR3;                        /* Typewriter O/P */
uint32              SR64;                       /* Interrupt status */
uint32              SR65;                       /* Interrupt status */
uint32              adrmask;                    /* Mask for addressing memory */
uint32              memmask;                    /* Memory address range mask */
uint8               loading;                    /* Loading bootstrap */


struct InstHistory
{
    uint32    rc;
    uint32    op;
    uint32    ea;
    uint32    xr;
    uint32    ra;
    uint32    rb;
    uint32    rr;
    uint8     c;
    uint8     v;
    uint8     e;
    uint8     mode;
};

struct InstHistory *hst = NULL;
int32               hst_p = 0;
int32               hst_lnt = 0;


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);
t_stat              cpu_show_size(FILE * st, UNIT * uptr, int32 val,
                                  CONST void *desc);
t_stat              cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr,
                                 void *desc);
t_stat              cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr,
                                 void *desc);
t_stat              cpu_show_float(FILE * st, UNIT * uptr, int32 val,
                                  CONST void *desc);
t_stat              cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr,
                                 void *desc);
t_stat              cpu_show_mult(FILE * st, UNIT * uptr, int32 val,
                                  CONST void *desc);
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);
t_stat              cpu_help(FILE *, DEVICE *, UNIT *, int32, const char *);
/* Interval timer */
t_stat              rtc_srv(UNIT * uptr);
void                time_read(uint32 *word);
int32               rtc_tps = 60 ;
int32               tmxr_poll = 10000;



CPUMOD  cpu_modtab[] = {
     { "1901",   MOD1,    TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
     { "1901A",  MOD1A,   TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
     { "1901S",  MOD1S,   TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
     { "1901T",  MOD1T,   TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
     { "1902",   MOD2,    TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
     { "1902A",  MOD2A,   TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
     { "1902S",  MOD2S,   TYPE_C1|FLOAT_STD|FLOAT_OPT|MULT|SV, EXT_IO, 10 },
     { "1902T",  MOD2T,   TYPE_C1|FLOAT_STD|FLOAT_OPT|MULT|SV, EXT_IO, 10 },
     { "1903",   MOD3,    TYPE_A2|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
     { "1903A",  MOD3A,   TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
     { "1903S",  MOD3S,   TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, EXT_IO, 10 },
     { "1903T",  MOD3T,   TYPE_A2|FLOAT_STD|FLOAT_OPT|MULT_OPT|WG, 0, 10 },
     { "1904",   MOD4,    TYPE_B2|FLOAT_OPT|MULT|WG, 0, 1 },
     { "1904A",  MOD4A,   TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1904E",  MOD4E,   TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1904F",  MOD4F,   TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1904S",  MOD4S,   TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1905",   MOD5,    TYPE_A2|FLOAT|MULT|WG, 0, 1 },
     { "1905A",  MOD5A,   TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
     { "1905E",  MOD5E,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1905F",  MOD5F,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1905S",  MOD5S,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1906",   MOD6,    TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
     { "1906A",  MOD6A,   TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 100 },
     { "1906E",  MOD6E,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1906F",  MOD6F,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1906S",  MOD6S,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 100 },
     { "1907",   MOD7,    TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
     { "1907A",  MOD7A,   TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
     { "1907E",  MOD7E,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1907F",  MOD7F,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1907S",  MOD7S,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1908",   MOD8,    TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
     { "1908A",  MOD8A,   TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
     { "1908S",  MOD8S,   TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
     { "1909",   MOD9,    TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 1 },
     { NULL, 0, 0, 0, 0},
};

uint16   cpu_flags = TYPE_C2|FLOAT_OPT|MULT;
uint8    io_flags  = EXT_IO;

/* 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[] =
    {{ UDATA(rtc_srv, MODEL(MOD4A)|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }};

REG                 cpu_reg[] = {
    {ORDATAD(C, RC,  22, "Instruction code"), REG_FIT},
    {ORDATAD(F, RF,   7, "Order Code"), REG_FIT},
    {ORDATAD(G, RG,   3, "General register"), REG_FIT},
    {ORDATAD(D, RD,  22, "Datum"), REG_FIT},
    {ORDATAD(L, RL,  22, "Limit"), REG_FIT},
    {ORDATAD(M, Mode, 7, "Mode Register"), REG_FIT},
    {BRDATAD(X, XR,   8, 24, 8, "Index Register"), REG_FIT},
    {NULL}
};

MTAB                cpu_mod[] = {
    /* Stevenage */
    {UNIT_MODEL, MODEL(MOD1),  "1901",  "1901",  &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD1A), "1901A", "1901A", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD1S), "1901S", "1901S", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD1T), "1901T", "1901T", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD2),  "1902",  "1902",  &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD2A), "1902A", "1902A", &cpu_set_model, NULL, NULL},  /* C1 */
    {UNIT_MODEL, MODEL(MOD2S), "1902S", "1902S", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD2T), "1902T", "1902T", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD3),  "1903",  "1903",  &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD3A), "1903A", "1903A", &cpu_set_model, NULL, NULL},  /* C1 */
    {UNIT_MODEL, MODEL(MOD3S), "1903S", "1903S", &cpu_set_model, NULL, NULL},
    /* West Gorton */
    {UNIT_MODEL, MODEL(MOD3T), "1903T", "1903T", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD4),  "1904",  "1904",  &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD4A), "1904A", "1904A", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD4E), "1904E", "1904E", &cpu_set_model, NULL, NULL},  /* C */
    {UNIT_MODEL, MODEL(MOD4F), "1904F", "1904F", &cpu_set_model, NULL, NULL},  /* C */
    {UNIT_MODEL, MODEL(MOD4S), "1904S", "1904S", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD5),  "1905",  "1905",  &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD5E), "1905E", "1905E", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD5F), "1905F", "1905F", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD5S), "1905S", "1905S", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD6),  "1906",  "1906",  &cpu_set_model, NULL, NULL},    /* C */
    {UNIT_MODEL, MODEL(MOD6A), "1906A", "1906A", &cpu_set_model, NULL, NULL},  /* C */
    {UNIT_MODEL, MODEL(MOD6E), "1906E", "1906E", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD6F), "1906F", "1906F", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD7),  "1907",  "1907",  &cpu_set_model, NULL, NULL},    /* C */
    {UNIT_MODEL, MODEL(MOD7E), "1907E", "1907E", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD7F), "1907F", "1907F", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD8A), "1908A", "1908A", &cpu_set_model, NULL, NULL},
    {UNIT_MODEL, MODEL(MOD9),  "1909",  "1909",  &cpu_set_model, NULL, NULL},
    {MTAB_XTD|MTAB_VDV, 0,  NULL, "NOFLOAT", &cpu_set_float, NULL, NULL, "Disable floating point"},
    {MTAB_XTD|MTAB_VDV, 1,  "FLOAT",  "FLOAT", &cpu_set_float, &cpu_show_float, NULL, "Enable floating point"},
    {MTAB_XTD|MTAB_VDV,  0, NULL, "NOMULT", &cpu_set_mult, NULL, NULL, "Disable hardware multiply"},
    {MTAB_XTD|MTAB_VDV,  1, "MULT",   "MULT", &cpu_set_mult, &cpu_show_mult, NULL, "Enable hardware multiply"},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(0), NULL, "4K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(1), NULL, "8K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(3), NULL, "16K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(11), NULL, "48K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(15), NULL, "64K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(23), NULL, "96K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(31), NULL, "128K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(63), NULL, "256K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(127), NULL, "512K", &cpu_set_size},
    {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(254), NULL, "1024K", &cpu_set_size},
    {MTAB_VDV, 0, "MEMORY", NULL, NULL, &cpu_show_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},
    {0}
};

DEVICE              cpu_dev = {
    "CPU", cpu_unit, cpu_reg, cpu_mod,
    1, 8, 22, 1, 8, 24,
    &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
    NULL, DEV_DEBUG, 0, dev_debug,
    NULL, NULL, &cpu_help
};




/* Test if we can access a word */
uint8 Mem_test(uint32 addr) {
    addr &= M22;

    if (!exe_mode) {
        if (addr < 8)
            return 0;
        addr = addr + RD;
    } else if (addr < 8)
        return 0;

    if (!exe_mode && RL && (addr < RD || addr >= RL)) {
        SR64 |= B1;
        return 1;
    }
    addr &= memmask;
    if (addr > MEMSIZE) {
        SR64 |= B1;
        return 1;
    }
    return 0;
}

uint8 Mem_read(uint32 addr, uint32 *data, uint8 flag) {
    addr &= M22;

    SR1++;
    if (!exe_mode) {
        if (addr < 8) {
            *data = XR[addr];
            return 0;
        }
        addr = addr + RD;
    } else if (flag && (Mode & DATUM) != 0) {
        addr = addr + RD;
    } else if (addr < 8) {
        *data = XR[addr];
        return 0;
    }

    if (!exe_mode && RL && (addr < RD || addr >= RL)) {
        SR64 |= B1;
        return 1;
    }
    addr &= memmask;
    if (addr > MEMSIZE) {
        SR64 |= B1;
        return 1;
    }
    *data = M[addr];
    return 0;
}

uint8 Mem_write(uint32 addr, uint32 *data, uint8 flag) {
    addr &= M22;

    if (!exe_mode) {
        if (addr < 8) {
            XR[addr] = *data;
            return 0;
        }
        addr = addr + RD;
    } else if (flag && (Mode & DATUM) != 0) {
        addr = addr + RD;
    } else if (addr < 8) {
        XR[addr] = *data;
        return 0;
    }
    if (!exe_mode && RL && (addr < RD || addr >= RL)) {
        SR64 |= B1;
        return 1;
    }
    addr &= memmask;
    if (addr > MEMSIZE) {
        SR64 |= B1;
        return 1;
    }
    M[addr] = *data;
    return 0;
}

t_stat
sim_instr(void)
{
    t_stat              reason;
    uint32              temp;           /* Hol order code being obeyed */
    int                 m;              /* Holds index register for address modification */
    int                 n;              /* Generic short term temp register */
    int                 e1,e2;          /* Temp for exponents */
    int                 f;              /* Used to hold flags */

    memmask = (CPU_TYPE < TYPE_C1) ? M15: M22;
    adrmask = (Mode & AM22) ? M22 : M15;
    reason = chan_set_devs();

    while (reason == SCPE_OK) {        /* loop until halted */
       if (sim_interval <= 0) {        /* event queue? */
           reason = sim_process_event();
           if (reason != SCPE_OK) {
                break; /* process */
           }
       }

       if (sim_brk_summ) {
           if(sim_brk_test(RC, SWMASK('E'))) {
               reason = SCPE_STOP;
               break;
           }
       }

       while (loading) {        /* event queue? */
           reason = sim_process_event();
           if (reason != SCPE_OK) {
                break; /* process */
           }
           if ((SR64 | SR65) != 0) {
              loading = 0;
              exe_mode = 1;
              RC = 020;
           }
       }

intr:
       if (!exe_mode && (SR64 | SR65) != 0) {
            if (CPU_TYPE < TYPE_C1 && !exe_mode)
                RC += RD;
            exe_mode = 1;
            loading = 0;
            /* Store registers */
            if (cpu_flags & FLOAT && cpu_flags & SL_FLOAT) {
                Mem_write(RD+12, &faccl, 0);
                RT = facch;
                if (fovr)
                    RT |= B0;
                Mem_write(RD+13, &RT, 0);  /* Save F.P.U. */
            }
            RA = 0;         /* Build ZSTAT */
            if (cpu_flags & SV) {
                Mem_read(RD+9, &RA, 0);
                RA &= M15;
                RA |= ((Mode|DATUM) << 16);
                if (Mode & DATUM)
                   RA |= 1 << 16;
                if (BCarry)
                   RA |= B1;
            } else {
                if (CPU_TYPE >= TYPE_C1)  {
                    Mem_read(RD+9, &RA, 0);
                    RA &= M15;
                    if (Zero)
                        RA |= B3;
                    if (OPIP | PIP)
                        RA |= B2;
                    Mem_write(RD+9, &RA, 0);
                }
            }
            RA = RC & memmask;
            if (io_flags & EXT_IO) {
                if (BCarry)
                  RA |= B1;
            } else {
                RC &= M15;
                if (Zero)
                    RA |= B8;
            }
            if (BV)
                RA |= B0;
            Mem_write(RD+8, &RA, 0);
            for (n = 0; n < 8; n++)
               Mem_write(RD+n, &XR[n], 0);
            BV = BCarry = Mode = Zero = 0;
            adrmask = M15;
            RC = 020;
            PIP = 0;
       }

fetch:
       if (!exe_mode && (Mode & 7) == 1)
           SR64 |= B2;

       if (Mem_read(RC, &temp, 0)) {
           if (hst_lnt) {      /* history enabled? */
               hst_p = (hst_p + 1);    /* next entry */
               if (hst_p >= hst_lnt)
                   hst_p = 0;
               hst[hst_p].rc = RC | HIST_PC;
               hst[hst_p].ea = RC;
               hst[hst_p].op = 0;
               hst[hst_p].xr = 0;
               hst[hst_p].ra = 0;
               hst[hst_p].rb = 0;
               hst[hst_p].rr = 0;
               hst[hst_p].c = BCarry;
               hst[hst_p].v = BV;
               hst[hst_p].e = exe_mode;
               hst[hst_p].mode = Mode;
           }
           RC = (RC + 1) & ((Mode & (EJM|AM22)) ? M22: M15);
           goto intr;
       }
obey:
       RM = temp & 037777;
       RF = 0177 & (temp >> 14);
       RX = 07 & (temp >> 21);
       /* Check if branch opcode */
       if (RF >= 050 && RF < 0100) {
           RA = XR[RX];
           RM = RB = temp & 077777;
           /* Handle PC relative addressing */
           if ((Mode & EJM) != 0 && (RF & 1) == 0) {
               RB = RB | ((RB & 020000) ? 017740000 : 0); /* Sign extend RB */
               RB = (RB + RC) & M22;
           }
       } else {
           RA = XR[RX];
           m = 03 & (RM >> 12);
           RB = RM & 07777;
           if (PIP)
             RB = (RB + RP) & adrmask;
           if (m != 0)
             RB = (RB + XR[m]) & adrmask;
           RS = RB;
           if (RF < 050) {
              if (Mem_read(RS, &RB, 1)) {
                  if (hst_lnt) {      /* history enabled? */
                      hst_p = (hst_p + 1);    /* next entry */
                      if (hst_p >= hst_lnt)
                          hst_p = 0;
                      hst[hst_p].rc = (RC - 1) | HIST_PC;
                      hst[hst_p].ea = RS;
                      hst[hst_p].op = temp;
                      hst[hst_p].xr = XR[RX];
                      hst[hst_p].ra = RA;
                      hst[hst_p].rb = RB;
                      hst[hst_p].rr = RB;
                      hst[hst_p].c = BCarry;
                      hst[hst_p].v = BV;
                      hst[hst_p].e = exe_mode;
                      hst[hst_p].mode = Mode;
                  }
                  RC = (RC + 1) & ((Mode & (EJM|AM22)) ? M22: M15);
                  goto intr;
              }
              if (RF & 010) {
                 uint32 t;
                 t = RA;
                 RA = RB;
                 RB = t;
              }
           }
       }
       OPIP = PIP;
       PIP = 0;

       if (hst_lnt && RC != 7) {      /* history enabled? */
           hst_p = (hst_p + 1);    /* next entry */
           if (hst_p >= hst_lnt)
               hst_p = 0;
           hst[hst_p].rc = RC | HIST_PC;
           hst[hst_p].ea = RS;
           hst[hst_p].op = temp;
           hst[hst_p].xr = XR[RX];
           hst[hst_p].ra = RA;
           hst[hst_p].rb = RB;
           hst[hst_p].rr = RB;
           hst[hst_p].c = BCarry;
           hst[hst_p].v = BV;
           hst[hst_p].e = exe_mode;
           hst[hst_p].mode = Mode;
       }

       /* Advance to next location, except on OBEY order */
       if (RF != OP_OBEY)
           RC = (RC + 1) & ((Mode & (EJM|AM22)) ? M22: M15);
       OIP = 0;

       switch (RF) {
       case OP_LDX:          /* Load to X */
       case OP_LDXC:         /* Load into X with carry */
       case OP_LDN:          /* Load direct to X */
       case OP_LDNC:         /* Load direct into X with carry */
       case OP_STO:          /* Store contents of X */
       case OP_STOC:         /* Store contents of X with carry */
       case OP_NGS:          /* Negative into Store */
       case OP_NGSC:         /* Negative into Store with carry */
       case OP_NGN:          /* Negative direct to X */
       case OP_NGNC:         /* Negative direct to X with carry */
       case OP_NGX:          /* Negative to X */
       case OP_NGXC:         /* Negative to X with carry */
                     RA = 0;
                     /* Fall through */

       case OP_SBX:          /* Subtract from X */
       case OP_SBXC:         /* Subtract from X with carry */
       case OP_SBS:          /* Subtract from store */
       case OP_SBSC:         /* Subtract from store with carry */
       case OP_SBN:          /* Subtract direct from X */
       case OP_SBNC:         /* Subtract direct from X with carry */
       case OP_ADX:          /* Add to X */
       case OP_ADXC:         /* Add to X with carry */
       case OP_ADN:          /* Add direct to X */
       case OP_ADNC:         /* Add direct to X with carry */
       case OP_ADS:          /* Add X to store */
       case OP_ADSC:         /* Add X to store with carry */
                     if (RF & 02) {
                         RB = RB ^ FMASK;
                         BCarry = !BCarry;
                     }
                     n = (RA & B0) != 0;
                     RA = RA + RB + BCarry;
                     if (RF & 04) {
                        if (RF & 02)
                            BCarry = (RA & BM1) == 0;
                        else
                            BCarry = (RA & B0) != 0;
                        RA &= M23;
                     } else {
                        int t2 = (RB & B0) != 0;
                        int tr = (RA & B0) != 0;
                        if ((n && t2 && !tr) || (!n && !t2 && tr)) {
                           BV = 1;
                           if (!exe_mode && (Mode & 7) == 4)
                               SR64 |= B2;
                        }
                        BCarry = 0;
                     }
                     RA &= FMASK;
                     if (RF & 010) {
                         if (Mem_write(RS, &RA, 1)) {
                             goto intr;
                         }
                     } else {
                         XR[RX] = RA;
                     }
                     break;

       case OP_ANDX:         /* Logical AND into X */
       case OP_ANDS:         /* Logical AND into store */
       case OP_ANDN:         /* Logical AND direct into X */
                     RA = RA & RB;
                     BCarry = 0;
                     if (RF & 010) {
                         if (Mem_write(RS, &RA, 1)) {
                             goto intr;
                         }
                     } else {
                         XR[RX] = RA;
                     }
                     break;

       case OP_ORX:          /* Logical OR into X */
       case OP_ORS:          /* Logical OR into store */
       case OP_ORN:          /* Logical OR direct into X */
                     RA = RA | RB;
                     BCarry = 0;
                     if (RF & 010) {
                         if (Mem_write(RS, &RA, 1)) {
                             goto intr;
                         }
                     } else {
                         XR[RX] = RA;
                     }
                     break;

       case OP_ERX:          /* Logical XOR into X */
       case OP_ERS:          /* Logical XOR into store */
       case OP_ERN:          /* Logical XOR direct into X */
                     RA = RA ^ RB;
                     BCarry = 0;
                     if (RF & 010) {
                         if (Mem_write(RS, &RA, 1)) {
                             goto intr;
                         }
                     } else {
                         XR[RX] = RA;
                     }
                     break;

       case OP_OBEY:         /* Obey instruction at N */
                     temp = RB;
                     OIP = 1;
                     goto obey;

       case OP_LDCH:         /* Load Character to X */
                     m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
                     RA = RB >> (6 * (3 - m));
                     RA = XR[RX] = RA & 077;
                     BCarry = 0;
                     break;

       case OP_LDEX:         /* Load Exponent */
                     RA = XR[RX] = RB & M9;
                     BCarry = 0;
                     break;

       case OP_TXU:          /* Test X unequal */
                     if (RA != RB)
                       BCarry = 1;
                     break;

       case OP_TXL:          /* Test X Less */
                     RB += BCarry;
                     if (RB != RA)
                         BCarry = (RB > RA);
                     break;

       case OP_STOZ:         /* Store Zero */
                     /* Stevenage Machines */
                     if ((cpu_flags & SV) != 0 && exe_mode && RX != 0)
                         XR[RX] = RA;
                     RB = 0;
                     BCarry = 0;
                     if (Mem_write(RS, &RB, 1)) {
                         goto intr;
                     }
                     break;

       case OP_DCH:          /* Deposit Character to X */
                     m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
                     m = 6 * (3 - m);
                     RB = (RB & 077) << m;
                     RA &= ~(077 << m);
                     RA |= RB;
                     BCarry = 0;
                     if (Mem_write(RS, &RA, 1)) {
                         goto intr;
                     }
                     break;

       case OP_DEX:          /* Deposit Exponent */
                     RA &= ~M9;
                     RA = RA | (RB & M9);
                     BCarry = 0;
                     if (Mem_write(RS, &RA, 1)) {
                         goto intr;
                     }
                     break;

       case OP_DSA:          /* Deposit Short Address */
                     RA &= ~M12;
                     RA |= (RB & M12);
                     BCarry = 0;
                     if (Mem_write(RS, &RA, 1)) {
                         goto intr;
                     }
                     break;

       case OP_DLA:          /* Deposit Long Address */
                     RA &= ~M15;
                     RA |= (RB & M15);
                     BCarry = 0;
                     if (Mem_write(RS, &RA, 1)) {
                         goto intr;
                     }
                     break;

       case OP_MPY:          /* Multiply */
       case OP_MPR:          /* Multiply and Round  */
       case OP_MPA:          /* Multiply and Accumulate */
                     if ((cpu_flags & MULT) == 0)
                         goto voluntary;
                     if (RA == B0 && RB == B0) {
                         if (RF != OP_MPA || (XR[(RX + 1) & 7] & B0) == 0) {
                             BV = 1;
                             if (!exe_mode && (Mode & 7) == 4)
                                 SR64 |= B2;
                         }
                     }
                     RP = RA;
                     RA = RB;
                     n = RP & 1;
                     RP >>= 1;
                     if (RF & 1)  /* Multiply and Round  */
                         RP |= B0;
                     RB = 0;
                     for(RK = 23; RK != 0; RK--) {
                        if (n)
                           RB += RA;
                        n = RP & 1;
                        RP >>= 1;
                        if (RB & 1)
                           RP |= B0;
                        if (RB & B0)
                           RB |= BM1;
                        RB >>= 1;
                     }

                     if (n) {
                         RB += (RA ^ FMASK) + 1;
                     }
                     n = RP & 1;         /* Check for MPR */
                     if (n && RP & B0)
                        RB++;
                     RP >>= 1;
                     if (RF == OP_MPA) {
                         RA = XR[(RX + 1) & 7];
                         RP += RA;
                         if (RA & B0)
                             RB--;
                         else if (RP & B0)
                             RB++;
                     }

                     XR[RX] = RB & FMASK;
                     RA = XR[(RX+1) & 7] = RP & M23;
                     BCarry = 0;
                     break;

       case OP_CDB:          /* Convert Decimal to Binary */
                     m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
                     RB = (RB >> (6 * (3 - m))) & 077;
                     if (RB > 9) {
                        BCarry = 1;
                        break;
                     }
                     /* Fall through */

       case OP_CBD:          /* Convert Binary to Decimal */
                     RT = RB;
                     RB = XR[(RX+1) & 7];
                     /* Multiply by 10 */
                     RB <<= 2;
                     RA <<= 2;
                     RA |= (RB >> 23) & 07;
                     RB &= M23;
                     RB += XR[(RX+1) & 7];
                     if (RB & B0)
                        RA++;
                     RA += XR[RX];
                     RB <<= 1;
                     RA <<= 1;
                     if (RB & B0)
                        RA++;
                     RB &= M23;
                     if (RF == OP_CDB) {
                         /* Add in RT */
                         RB += RT;
                         if (RB & B0)
                            RA++;
                         RB &= M23;
                         if (RA & ~(M23)) {
                             BV = 1;
                             if (!exe_mode && (Mode & 7) == 4)
                                 SR64 |= B2;
                         }
                         RA &= M23;
                     } else {
                         /* Save bits over 23 to char */
                         m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
                         m = 6 * (3 - m);
                         RP = (RA >> 23) & 017;
                         if (Zero && RP == 0)
                             RP = 020;
                         else
                             Zero = 0;
                         RA &= M23;
                         RT &= ~(077 << m);
                         RT |= (RP << m);
                         if (Mem_write(RS, &RT, 1)) {
                             goto intr;
                         }
                     }
                     XR[(RX+1) & 7] = RB;
                     XR[RX] = RA;
                     break;

       case OP_DVD:          /* Unrounded Double Length Divide */
       case OP_DVR:          /* Rounded Double Length Divide */
       case OP_DVS:          /* Single Length Divide */
                     if ((cpu_flags & MULT) == 0)
                         goto voluntary;
                     RP = XR[(RX+1) & 7];            /* VR */
                     RA = RB;  /* Divisor to RA */
                     RB = XR[RX];  /* Dividend to RB/RP */
//fprintf(stderr, "DVD0: %08o %08o %08o - %3o C=%08o\n\r", RA, RB, RP, RF, RC);

                     if (RA == 0) { /* Exit on zero divisor */  /* VI */
                         BV = 1;
                         if (!exe_mode && (Mode & 7) == 4)
                             SR64 |= B2;
                         BCarry = 0;
                         break;
                     }

                     /* Setup for specific divide order code */ /* V11 */
                     if (RF & 2) {     /* DVS */
                         if (RP & B0) { /* RC22 */ /* Sign extend RB */
                             RB = FMASK;
                         } else {
                             RB = 0;
                         }
                     }

// {
//   long int   divsor;
//   long int   dividend;
//   int sign;
//
//   dividend = (((long int)(RB)) << 23) | (long int)(RP);
//   if (RB & B0)   {
//      dividend |= 0xffff800000000000;
//   }
//   sign = 1;
//   divsor = (long int)(RA);
//   if (RA & B0) {
//      divsor |= 0xffffffffff000000;
//      sign = -1;
//   }
//fprintf(stderr, "DVD1: %08o %08o %08o %ld (%lo) / %ld (%lo) = %ld (%lo) m %ld (%lo) %o\n\r", RA, RB, RP,
//  dividend, dividend, divsor, divsor, dividend/divsor, dividend/divsor,
//   sign* (dividend%divsor), sign *(dividend % divsor), BV);
//}
                     BCarry = 0;
                     if ((RB | RP) == 0)
                         goto dvd_zero;
                     RP <<= 1;
                     RP &= FMASK;
                     BCarry = 0;

                     /* First partial remainder */   /* V12 */
                     if (((RB ^ RA) & B0) == 0) {
                         RS = RB + (RA ^ FMASK) + 1;
                         RK=1;
                     } else {
                         RS = RB + RA;
                         RK=0;
                     }
                     /* Check if potiential overflow */
                     if (((RS ^ RA) & B0) != 0)
                         BCarry = 1;
                     BCarry = RK != BCarry;
                     /* Shift left quotent and remainder */
                     RP <<= 1;
                     if (((RS ^ RA) & B0) == 0) {
                         RP |= 1;    /* First quotient digit */
                     }
                     RB = RS << 1;
                     if (RP & BM1)
                         RB |= 1;
                     RB &= FMASK;
                     RP &= FMASK;
//fprintf(stderr, "DVD2: %08o %08o %08o \n\r", RA, RP, RB);

                     /* Main divide loop */         /* V13 */
                     for (RK = 22; RK != 0; RK--) {
                         if (((RS ^ RA) & B0) == 0) {
                             RS = RB + (RA ^ FMASK) + 1;
                         } else {
                             RS = RB + RA;
                         }
                         RP <<= 1;
                         if (((RS ^ RA) & B0) == 0) {
                             RP |= 1;
                         }
                         RB = RS << 1;
                         if (RP & BM1)
                             RB |= 1;
                         RB &= FMASK;
                         RP &= FMASK;
//fprintf(stderr, "DVD3: %08o %08o %08o %08o \n\r", RA, RP, RB, RS);
                     }

                     /* Final product */
                     if (((RS ^ RA) & B0) == 0) {   /* V14 */
                         RS = RB + (RA ^ FMASK) + 1;
                     } else {
                         RS = RB + RA;
                     }
                     RP <<= 1;
                     if (((RS ^ RA) & B0) == 0) {
                         RP |= 1;
                     }
                     RP &= FMASK;
                     RB = RS & FMASK;
//fprintf(stderr, "DVD4: %08o %08o %08o %08o \n\r", RA, RP, RB, RS);
                     /* End correction */
                     if ((RP & 1) == 0) {
                         RB = (RB + RA) & FMASK;
                     }
//fprintf(stderr, "DVD5: %08o %08o %08o \n\r", RA, RP, RB);
                     if ((RF & 1) == 0 || RB == 0) {
//fprintf(stderr, "DVD7: %08o %08o %08o \n\r", RA, RP, RB);
                         /* If remainder same as divisor, bump quotent zero remainder */
                         if (RB == RA) {
                             RT = RP;
                             RP++;
                             if ((RT & B0) != (RP & B0))
                                 BCarry = !BCarry;
                             RB = 0;
                         }
                     } else {   /* DVR */
                         RT = RB + (RA ^ FMASK) + 1;
//fprintf(stderr, "DVDA: %08o %08o %08o %08o \n\r", RA, RP, RB, RT);
                         RA = RB;
                         if ((((RT + RA) ^ RA) & B0) == 0) {
                             RB = RT & FMASK;
//fprintf(stderr, "DVD6: %08o %08o %08o \n\r", RA, RP, RB);
                             RT = RP;
                             RP++;
                             if ((RT ^ RP) & B0)
                                 BCarry = !BCarry;
                             if (RP & BM1)
                                 BCarry = 1;
                         }
                     }
dvd_zero:
                     /* Set overflow if BCarry still set */
                     if (BCarry) {
                         BV = 1;
                         if (!exe_mode && (Mode & 7) == 4)
                             SR64 |= B2;
                     }
                     BCarry = 0;
// {
//   int32   a;
//   int32   b;
//
//   a = RB;
//   if (RB & B0)
//      a |= 0xff000000;
//   b = RP;
//   if (RP & B0)
//      b |= 0xff000000;
//fprintf(stderr, "DVD8: q=%08o(%d) r=%08o(%d) %d %d %d\n\r", RP, b, RB, a, BV);
//}
                     XR[RX] = RB & FMASK;
                     XR[(RX+1) & 7] = RP & FMASK;
                     break;

       case OP_BZE:          /* Branch if X is Zero */
       case OP_BZE1:
                     BCarry = 0;
                     if (RA == 0)
                         goto branch;
                     break;

       case OP_BNZ:          /* Branch if X is not Zero */
       case OP_BNZ1:
                     BCarry = 0;
                     if (RA != 0)
                         goto branch;
                     break;

       case OP_BPZ:          /* Branch if X is Positive or zero */
       case OP_BPZ1:
                     BCarry = 0;
                     if ((RA & B0) == 0)
                         goto branch;
                     break;

       case OP_BNG:          /* Branch if X is Negative */
       case OP_BNG1:
                     BCarry = 0;
                     if ((RA & B0) != 0)
                         goto branch;
                     break;

       case OP_BUX:          /* Branch on Unit indexing */
       case OP_BUX1:
                     BCarry = 0;
                     if (Mode & AM22) {
                        RA = ((RA+1) & M22) | (RA & CMASK);
                        XR[RX] = RA;
                        goto branch;
                     } else {
                        RS = CNTMSK + RA;  /* Actualy a subtract 1 */
                        RS &= CNTMSK;
                        RA = ((RA + 1) & M15) | RS;
                     }
                     XR[RX] = RA;
                     if (RS != 0)
                        goto branch;
                     break;

       case OP_BDX:          /* Branch on Double Indexing */
       case OP_BDX1:
                     BCarry = 0;
                     if (Mode & AM22) {
                        RA = ((RA+2) & M22) | (RA & CMASK);
                        XR[RX] = RA;
                        goto branch;
                     } else {
                        RS = CNTMSK + RA;  /* Actualy a subtract 1 */
                        RS &= CNTMSK;
                        RA = ((RA + 2) & M15) | RS;
                     }
                     XR[RX] = RA;
                     if (RS != 0)
                        goto branch;
                     break;

       case OP_BCHX:         /* Branch on Character Indexing */
       case OP_BCHX1:
                     BCarry = 0;
                     RA += B1;
                     n = (RA & BM1) != 0;
                     if (Mode & AM22) {
                        RA = ((RA + n) & M22) | (RA & CMASK);
                        XR[RX] = RA;
                        goto branch;
                     } else {
                        RS = CHCMSK + RA;  /* Actually a subtract 1 */
                        RS &= CHCMSK;
                        RA = ((RA + n) & M15) | RS | (RA & CMASK);
                     }
                     XR[RX] = RA;
                     if (RS != 0)
                        goto branch;
                     break;

        /* Not on A */
       case OP_BCT:          /* Branch on Count - BC */
       case OP_BCT1:
                     BCarry = 0;
                     if (Mode & AM22) {
                        RA = ((RA-1) & M22) | (RA & CMASK);
                        RS = RA & M22;
                     } else {
                        RA = ((RA - 1) & M15) | (CNTMSK & RA);
                        RS = RA & M15;
                     }
                     XR[RX] = RA;
                     if (RS != 0)
                        goto branch;
                     break;

       case OP_CALL:         /* Call Subroutine */
       case OP_CALL1:
                     RA = RC;
                     if ((Mode & (AM22|EJM)) == 0) {
                        RA &= adrmask;
                        if (Zero)
                           RA |= B8;
                     } else {
                        if (Zero)
                           RA |= B1;
                     }
                     if (BV)
                       RA |= B0;
                     BV = 0;
                     BCarry = 0;
                     XR[RX] = RA;
branch:
                     /* Monitor mode 3 -> int */
                     if (!exe_mode && (Mode & 7) == 3) {
                         SR64 |= B2;
                         break;
                     }
                     /* Handle replace jump */
                     if ((Mode & EJM) != 0 && (RF & 1) != 0) {
                         RB &= 037777;
                         if (Mem_read(RB, &RB, 0)) {
                             goto intr;
                         }
                     }
                     /* Handle SMO */
                     if (OPIP)
                          RB = (RB + RP) & adrmask;
                     if (hst_lnt) {      /* history enabled? */
                         hst[hst_p].ea = RB;
                     }
                     /* Don't transfer if address not valid */
                     if (Mem_test(RB))
                         goto intr;
                     /* Monitor mode 2 -> Exec Mon */
                     /* Read address to store from location 262. */
                     /* Store address transfer address at location, increment 262 mod 128 */
                     if (!exe_mode && (Mode & 7) == 2) {
                         temp = M[262];
                         M[temp & adrmask] = RB;
                         M[262] =  (temp & ~ 0177) + ((temp + 1) & 0177);
                     }
                     if ((Mode & (EJM|AM22)) == 0)
                         RB &= M15;
                     else
                         RB &= M22;
                     RC = RB;
                     break;

       case OP_EXIT:         /* Exit Subroutine */
       case OP_EXIT1:
                     if (RA & B0) {
                         BV = 1;
                         if (!exe_mode && (Mode & 7) == 4)
                             SR64 |= B2;
                     }
                     Zero = 0;
                     if ((Mode & (AM22|EJM)) == 0) {
                        if (RA & B8)
                           Zero = 1;
                     } else {
                        if (RA & B1)
                           Zero = 1;
                     }
                     BCarry = 0;
                     RM = RM | ((RM & 040000) ? 017740000 : 0); /* Sign extend RM */
                     RA = RA + RM;
                     if (OPIP)
                         RA = RA + RP;
                     if (hst_lnt) {      /* history enabled? */
                         hst[hst_p].ea = RA;
                     }
                     if ((Mode & (EJM|AM22)) == 0)
                         RA &= M15;
                     else
                         RA &= M22;
                     if (Mem_test(RA)) {  /* Verify memory location accessable */
                         goto intr;
                     }
                     RC = RA;
                     break;

       case OP_BRN:          /* Branch unconditional */
       case OP_BRN1:
                    /* If priorit mode -> 164 */
                    switch(RX) {
                    case 0:  /* BRN */
                          goto branch;

                    case 1:  /* BVS */
                          if (BV)
                              goto branch;
                          break;

                    case 2:  /* BVSR */
                          n = BV;
                          BV = 0;
                          if (n)
                              goto branch;
                          break;

                    case 3:   /* BVC */
                          if (BV == 0)
                              goto branch;
                          break;

                    case 4:   /* BVCR */
                          if (BV == 0)
                              goto branch;
                          BV = 0;
                          break;

                    case 5:  /* BCS */
                          n = BCarry;
                          BCarry = 0;
                          if (n)
                              goto branch;
                          break;

                    case 6:  /* BCC */
                          n = BCarry;
                          BCarry = 0;
                          if (!n)
                              goto branch;
                          break;

                    case 7:   /* BVC */
                          n = BV;
                          BV = !BV;
                          if (!exe_mode && (Mode & 7) == 4 && BV)
                              SR64 |= B2;
                          if (n == 0)
                              goto branch;
                          break;
                    }
                    break;

       /* B with Floating or C */
       case OP_BFP:          /* Branch state of floating point accumulator */
       case OP_BFP1:
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    if ((RX & 04) == 0 && fovr)
                        BV = 1;
                    switch (RX & 06) {
                    case 0:  n = (faccl | facch) != 0; break;
                    case 2:  n = (faccl & B0) != 0; break;
                    case 4:  n = fovr; break;
                    case 6:  SR64 |= B1; goto intr;
                    }
                    if (n == (RX & 1))
                        goto branch;
                    break;

       case OP_SLL:          /* Shift Left */
                    m = (RB >> 10) & 03;
                    RK = RB & 01777;
                    BCarry = 0;
                    while (RK != 0) {
                       n = 0;
                       switch (m) {
                       case 0: n = (RA & B0) != 0; break;
                       case 1: break;
                       case 2:
                       case 3: temp = RA & B0;
                       }
                       RA <<= 1;
                       RA |= n;
                       if ((m & 2) && temp != (RA & B0)) {
                          BV = 1;
                          if (!exe_mode && (Mode & 7) == 4)
                              SR64 |= B2;
                       }
                       RA &= FMASK;
                       RK--;
                    }
                    XR[RX] = RA;
                    break;

       case OP_SLD:          /* Shift Left Double */
                    m = (RB >> 10) & 03;
                    RK = RB & 01777;
                    BCarry = 0;
                    RB = XR[(RX+1) & 07];
                    while (RK != 0) {
                       switch (m) {
                       case 0:
                               RB <<= 1;
                               RA <<= 1;
                               if (RA & BM1)
                                   RB |= 1;
                               if (RB & BM1)
                                   RA |= 1;
                               break;
                       case 1:
                               RB <<= 1;
                               RA <<= 1;
                               if (RB & BM1)
                                   RA |= 1;
                               break;
                       case 2:
                       case 3:
                               RB <<= 1;
                               RA <<= 1;
                               if (RB & B0)
                                   RA |= 1;
                               RB &= M23;
                               n = (RA & B0) != 0;
                               temp = (RA & BM1) != 0;
                               if (n != temp) {
                                   BV = 1;
                                   if (!exe_mode && (Mode & 7) == 4)
                                       SR64 |= B2;
                               }
                       }
                       RA &= FMASK;
                       RB &= FMASK;
                       RK--;
                    }
                    XR[RX] = RA;
                    XR[(RX+1) & 07] = RB;
                    break;

       case OP_SRL:          /* Shift Right */
                    m = (RB >> 10) & 03;
                    RK = RB & 01777;
                    RT = RA & B0;
                    BCarry = 0;
                    switch(m) {
                    case 0: break;
                    case 1: RT = 0; break;
                    case 2: break;
                    case 3: if (BV) {
                                RT = B0 ^ RT;
                                BV = 0;
                            }
                    }
                    while (RK != 0) {
                       if (m == 0)
                          RT = (RA & 1) ? B0 : 0;
                       temp = RA & 1;
                       RA >>= 1;
                       RA |= RT;
                       RK--;
                    }
                    if (m > 1 && temp == 1)
                      RA = (RA + 1) & FMASK;
                    XR[RX] = RA;
                    break;

       case OP_SRD:          /* Shift Right Double */
                    m = (RB >> 10) & 03;
                    RK = RB & 01777;
                    RB = XR[(RX+1) & 07];
                    BCarry = 0;
                    RT = RA & B0;
                    if (m == 3 && RK != 0 && BV)  {
                         RT = B0^RT;
                         BV = 0;
                    }
                    while (RK != 0) {
                       switch (m) {
                       case 0:
                               if (RA & 1)
                                  RB |= BM1;
                               if (RB & 1)
                                  RA |= BM1;
                               RA >>= 1;
                               RB >>= 1;
                               break;
                       case 1:
                               RB >>= 1;
                               if (RA & 1)
                                  RB |= B0;
                               RA >>= 1;
                               break;
                       case 2:
                       case 3:
                               RB >>= 1;
                               if (RA & 1)
                                  RB |= B1;
                               RA >>= 1;
                               RA |= RT;
                       }
                       RK--;
                    }
                    XR[RX] = RA;
                    XR[(RX+1) & 07] = RB;
                    break;

       case OP_NORM:         /* Nomarlize Single -2 +FP */
       case OP_NORMD:        /* Normalize Double -2 +FP */
                    if ((cpu_flags & NORM_OP) == 0)
                        goto voluntary;
                    RT = RB;
                    RB = (RF & 1) ? XR[(RX+1) & 07] & M23 : 0;
//fprintf(stderr, "Norm0: %08o %08o %08o\n\r", RA, RB, RT);
                    if (RT & 04000) {
                         RT = 0;
                    } else {
                         RT &= 01777;
                    }
                    if (RT == 0) {
                        RA = RB = 0;
                    } else if (BV) {
                        RT++;
                        RP = (RA & B0) ^ B0;
                        if (RA & 1 && RF & 1)
                           RB |= B0;
                        RB >>= 1;
                        RA >>= 1;
                        RA |= RP;
                        if ((RF & 1) == 0) {
                            RB = RT;
                            goto norm3;
                        }
//fprintf(stderr, "Norm1: %08o %08o %08o\n\r", RA, RB, RT);
                    }  else if (RA != 0 || RB != 0) {
                        /* Shift left until sign and B1 not same */
//fprintf(stderr, "Norm2: %08o %08o %08o\n\r", RA, RB, RT);
                        while ((((RA >> 1) ^ RA) & B1) == 0) {
                           RT--;
                           RA <<= 1;
                           if (RB & B1)
                             RA |= 1;
                           RB <<= 1;
                           RA &= FMASK;
                           RB &= M23;
                        }
//fprintf(stderr, "Norm3: %08o %08o %08o\n\r", RA, RB, RT);
                        /* Check for overflow */
                        if (RT & B0) { /* < 0 */
                           RA = RB = 0;
                           goto norm1;
                        }
                        if (RT > M9)   /* NO Round if overflow */
                           goto norm2;
                    } else
                        RT = 0;
                    if (RF & 1) {   /* Round only on NORMD order codes */
//fprintf(stderr, "Norm4: %08o %08o %08o\n\r", RA, RB, RT);
                        /* Round RB if needed */
                        RP = RB;
                        RB += 0400;
//fprintf(stderr, "Norm4a: %08o %08o %08o\n\r", RA, RB, RT);
                        if (RB & B0 && RT <= M9)  {
                            RB = RP;
                            if (((RA & M23) + 1) & B0)
                               RA = RB = 0;
                        }
                    }
norm2:
                    RB = (RB & (MMASK|B0)) | (RT & M9);
norm3:
                    BV = 0;
                    if (RT > M9) {  /* Exponent overlfow */
                        BV = 1;
                        if (!exe_mode && (Mode & 7) == 4)
                            SR64 |= B2;
                    }
norm1:
//fprintf(stderr, "Norm5: %08o %08o %08o\n\r", RA, RB, RT);
                    XR[(RX+1) & 07] = RB;
                    XR[RX] = RA;
                    break;

        /* Not on A*/
       case OP_MVCH:         /* Move Characters - BC */
                    if (CPU_TYPE < TYPE_B1)
                        goto voluntary;
                    RK = RB;
                    RB = XR[(RX+1) & 07];
                    do {
                        if (Mem_read(RA & adrmask, &RT, 1)) {
                            goto intr;
                        }
                        m = (RA >> 22) & 3;
                        RT = (RT >> (6 * (3 - m))) & 077;
                        if (Mem_read(RB & adrmask, &RS, 1)) {
                            goto intr;
                        }
                        m = (RB >> 22) & 3;
                        m = 6 * (3 - m);
                        RS &= ~(077 << m);
                        RS |= (RT & 077) << m;
                        if (Mem_write(RB & adrmask, &RS, 1)) {
                            goto intr;
                        }
                        RA += 020000000;
                        m = (RA & BM1) != 0;
                        RA = ((RA + m) & M22) | (RA & CMASK);
                        RB += 020000000;
                        m = (RB & BM1) != 0;
                        RB = ((RB + m) & M22) | (RB & CMASK);
                        RK = (RK - 1) & 0777;
                     } while (RK != 0);
                     XR[RX] = RA;
                     XR[(RX+1)&07] = RB;
                     break;

        /* Not on A*/
       case OP_SMO:          /* Supplementary Modifier - BC  */
                    if (CPU_TYPE < TYPE_C1)
                        goto voluntary;
                    if (OPIP) {      /* Error */
                        SR64 |= B1;
                        goto intr;
                    }
                    if (Mem_read(RS, &RP, 1)) {
                        goto intr;
                    }
                    PIP = 1;
                    goto fetch;

       case OP_NULL:        /* No Operation */
                    if (!exe_mode && RX == 7 && (Mode & 7) > 0 && (Mode & 7) < 5)
                        SR64 |= B2;
                    break;

       case OP_LDCT:        /* Load Count */
                    RA = CNTMSK & (RB << 15);
                    XR[RX] = RA;
                    break;

       case OP_MODE:         /* Set Mode */
                    /* Stevenage Machines */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                       if (RX == 0) {
                           /* Remap modes settings */
                           Mode = 0;
                           if (RB & 02)
                               Mode |= DATUM;
                           if (RB & 020)
                               Mode |= AM22;
                           if (RB & 0100)
                               Mode |= EJM;
                           if (RB & 0200)
                               BCarry = 1;
                        } else if (RX == 1) {
                           temp = RB; /* Set interrupt enable mode */
                        }
                    } else if (exe_mode)
                       Mode = RB & 076;
                    Zero = RB & 1;
                    adrmask = (Mode & AM22) ? M22 : M15;
                    break;

       case OP_MOVE:        /* Copy N words */
                    if (CPU_TYPE < TYPE_B1)
                        goto voluntary;
                    RK = RB;
                    RA &= adrmask;
                    RB = XR[(RX+1) & 07] & adrmask;
                    do {
                        if (Mem_read(RA, &RT, 1)) {
                            goto intr;
                        }
                        if (Mem_write(RB, &RT, 1)) {
                            goto intr;
                        }
                        RA++;
                        RB++;
                        RK = (RK - 1) & 0777;
                    } while (RK != 0);
                    break;

       case OP_SUM:         /* Sum N words */
                    if (CPU_TYPE < TYPE_B1)
                        goto voluntary;
                    RK = RB;
                    RB = XR[(RX+1) & 07] & adrmask;
                    RA = 0;
                    do {
                        if (Mem_read(RB, &RT, 1)) {
                            goto intr;
                        }
                        RA = (RA + RT) & FMASK;
                        RB++;
                        RK = (RK - 1) & 0777;
                    } while (RK != 0);
                    XR[RX] = RA;
                    break;

/* B or C with Floating Point */
       case OP_FLOAT:        /* Convert Fixed to Float +FP */
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                     if (Mem_read(RS, &RA, 1)) {
                        goto intr;
                     }
                     RS++;
                     if (Mem_read(RS, &RB, 1)) {
                        goto intr;
                     }
                     faccl = RA;
                     facch = RB;
                     fovr = (RB & B0) != 0;
                     e1 = 23;
//fprintf(stderr, "FLOAT: %08o %08o %08o %o\n\r", faccl, facch, RC, RX);
                     RX = 0;
                     goto fn;
       case OP_FIX:          /* Convert Float to Fixed +FP */
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    RA = faccl;
                    RB = facch & MMASK;
                    e1 = 279 - (facch & M9);
//fprintf(stderr, "FIX: %08o %08o %08o %o %d\n\r", faccl, facch, RC, RX, e1);
                    if (e1 < 46) {
                       while (e1 > 0) {
                         if (RA & 1)
                             RB |= B0;
                         if (RA & B0)
                             RA |= BM1;
                         RA >>= 1;
                         RB >>= 1;
                         e1--;
                       }
                       while (e1 < 0) {
                         RA <<= 1;
                         if (RB & B1)
                           RA |= 1;
                         RB <<= 1;
                         RA &= FMASK;
                         RB &= M23;
                         e1++;
                       }
                    } else {
                        RB = RA = 0;
                        e1 = 0;
                    }
                    if (e1 != 0 || fovr) {
                        BV = 1;
                        if (!exe_mode && (Mode & 7) == 4)
                            SR64 |= B2;
                    }
//fprintf(stderr, "FIX1: %08o %08o %08o %o %d\n\r", RA, RB, RC, RX, e1);
                    if (Mem_write(RS, &RA, 1)) {
                       goto intr;
                    }
                    RS++;
                    if (Mem_write(RS, &RB, 1)) {
                       goto intr;
                    }
                    break;

       case OP_FAD:          /* Floating Point Add +FP */
       case OP_FSB:          /* Floating Point Subtract +FP */
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    if (Mem_read(RS, &RA, 1)) { /* Read lower */
                        goto intr;
                    }
                    RS++;
                    if (Mem_read(RS, &RB, 1)) { /* Read high + exp */
                        goto intr;
                    }
//fprintf(stderr, "FAD0: %08o %08o %08o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RX);
                    fovr |= (RB & B0) != 0;
                    RB &= M23;
                    if (RX & 4) { /* See if we should swap operands */
                        RT = facch;
                        facch = RB;
                        RB = RT;
                        RT = faccl;
                        faccl = RA;
                        RA = RT;
//fprintf(stderr, "FAD1: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                    }
                    if (RF == OP_FSB) { /* If subtract invert RA&RB */
                        RA ^= FMASK;
                        RB ^= MMASK;
                        RB += 01000;
                        if (RB & B0)
                           RA = (RA + 1) & FMASK;
                        RB &= M23;
//fprintf(stderr, "FAD2: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                    }
                    /* Extract exponents and numbers */
                    e1 = ((facch & M9)) - 256;
                    facch &= MMASK;
                    e2 = ((RB & M9)) - 256;
                    RB &= MMASK;
                    n = e1 - e2;
//fprintf(stderr, "FAD3: %08o %08o %08o %08o %08o %d %d %d\n\r", RA, RB, RC, faccl, facch, e1, e2, n);
                    /* Align mantissa's to add */
                    if (n < 0) {
                        e1 = e2;
                        if (n < -37) {  /* See if more then 37 bits difference */
                            faccl = RA;
                            facch = RB;
                            goto fn;
                        }
                        while(n < 0) {
                            if (faccl & B0)
                               faccl |= BM1;
                            if (faccl & 1)
                               facch |= B0;
                            facch >>= 1;
                            faccl >>= 1;
                            n++;
//fprintf(stderr, "FAD4a: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                        }
                    } else if (n > 0) {
                        if (n > 37) { /* See if more then 37 bits difference */
                            goto fn;
                        }
                        while(n > 0) {
                            if (RA & B0)
                               RA |= BM1;
                            if (RA & 1)
                               RB |= B0;
                            RA >>= 1;
                            RB >>= 1;
                            n--;
//fprintf(stderr, "FAD4b: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                        }
                    }
//fprintf(stderr, "FAD5: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                    /* Add the numbers */
                    n = (faccl & B0) != 0;  /* Save signs */
                    if (RA & B0)
                       n |= 2;
                    faccl += RA;
                    facch += RB;
                    if (facch & B0) {
                        facch &= M23;
                        faccl ++;
                    }
                    /* Sign of result */
                    if ((faccl & B0) != 0)
                       n |= 4;
//fprintf(stderr, "FAD6: %08o %08o %08o %o\n\r", faccl, facch, RC, n);
                    /* Result sign not equal same sign as addens */
                    if (n == 3 || n == 4) {
                        if (faccl & 1)
                           facch |= B0;
                        faccl >>= 1;
                        facch >>= 1;
                        facch &= MMASK;
                        if ((n & 4) == 0)
                           faccl |= B0;   /* Set sign */
                        e1++;
//fprintf(stderr, "FAD6a: %08o %08o %08o\n\r", faccl, facch, RC);
                    }
                    if (n == 7)   /* Handle minus with overflow */
                       e1--;
fn:
                    /* Common normalize routine */
                    faccl &= FMASK;
//fprintf(stderr, "FAD7: %08o %08o %08o %03o %d\n\r",  faccl, facch, RC,  e1, e1);
                    if ((facch | faccl) == 0)
                         break;
//fprintf(stderr, "FAD8: %08o %08o %08o %o\n\r",faccl, facch, RC, RX );
                    /* Shift left until sign and B1 not same */
                    if ((RX & 2) == 0 ) {
                        while ((((faccl >> 1) ^ faccl) & B1) == 0) {
                            e1--;
                            facch <<= 1;
                            faccl <<= 1;
                            if (facch & B0)
                              faccl |= 1;
                            faccl &= FMASK;
                            facch &= M23;
//fprintf(stderr, "FAD9: %08o %08o %08o %03o %d\n\r", faccl, facch, RC,  e1, e1);
                        }
                    }
                    /* Do rounding if needed */
                    if ((RX & 1) == 0 && (facch & B16) != 0) {
                        facch += B16;
                        if (facch & B0)
                           faccl ++;
                        facch &= M23;
                        faccl &= FMASK;
                        /* renormalize if things changed */
                        if ((RX & 2) == 0 && (((faccl >> 1) ^ faccl) & B1) == 0) {
                            e1--;
                            facch <<= 1;
                            faccl <<= 1;
                            if (facch & B0)
                              faccl |= 1;
                            faccl &= FMASK;
                            facch &= M23;
//fprintf(stderr, "FADr: %08o %08o %08o %03o %d\n\r", faccl, facch, RC,  e1, e1);
                        }
//fprintf(stderr, "FADR: %08o %08o %08o %03o\n\r",  faccl, facch, RC,  e1);
                    }
                    faccl &= FMASK;
                    facch &= MMASK;
                    /* Check if exponent in range */
                    if (e1 < -256) {
                        facch = faccl = 0;
                        e1 = -256;
                    }
                    if (e1 > 255)  {
                        fovr = 1;
                        e1 = (- e1);
                    }
                    if (fovr == 0 && ((faccl & FMASK) | (facch & MMASK)) == 0)
                        facch = faccl = 0;
                    else
                        facch |= (e1 + 256) & M9;
                    RA = faccl;
//fprintf(stderr, "FADA: %08o %08o %08o %03o %o\n\r", faccl, facch, RC, e1, fovr);
                    break;

       case OP_FMPY:         /* Floating Point Multiply +FP */
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    if (Mem_read(RS, &RA, 1)) { /* Read lower */
                        goto intr;
                    }
                    RS++;
                    if (Mem_read(RS, &RB, 1)) { /* Read high + exp */
                        goto intr;
                    }
//fprintf(stderr, "FMP0: %08o %08o %08o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RX);
                    fovr |= (RB & B0) != 0;
                    RB &= M23;
                    /* Not really needed for Multiply */
                    if (RX & 4) { /* See if we should swap operands */
                        RT = facch;
                        facch = RB;
                        RB = RT;
                        RT = faccl;
                        faccl = RA;
                        RA = RT;
//fprintf(stderr, "FMP1: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                    }
                    /* Extract exponents and mantissa's */
                    e1 = ((facch & M9)) - 256;
                    facch &= MMASK;
                    e2 = ((RB & M9)) - 256;
                    RB &= MMASK;
                    e1 += e2;  /* Exponent is sum of exponents */
                    /* Make both numbers positive and compute final size */
                    f = 0;
                    if (faccl & B0) {
                        f = 1;
                        faccl ^= FMASK;
                        facch ^= MMASK;
                        facch += B15;
                        if (facch & B0) {
                           faccl += 1;
                           faccl &= FMASK;
                           facch &= MMASK;
                        }
                    }
                    if (RA & B0) {
                        f = !f;
                        RA ^= FMASK;
                        RB ^= MMASK;
                        RB += B15;
                        if (RB & B0) {
                           RA += 1;
                           RA &= FMASK;
                           RB &= MMASK;
                        }
                    }
//fprintf(stderr, "FMP2: %08o %08o %08o %08o %08o %03o %d %o\n\r", RA, RB, RC, faccl, facch, e1, e1, f);
                    RT = faccl;
                    RP = facch;
                    faccl =  facch = 0; /* Clear product */
                    /* Do actual multiply */

                    for(RK = 37; RK != 0; RK--) {
                        /* If High order bit one, add in RB,RA */
                        if (RP & B15) {
                            facch += RB;
                            faccl += RA;
                            if (facch & B0)
                                faccl++;
                            facch &= M23;
                        }
                        /* Shift faccl,fach,RT,t right one */
                        if (RT & 1)
                            RP |= B0;
                        if (facch & 1)
                            RT |= B0;
                        if (faccl & 1)
                            facch |= B0;
                        RP >>= 1;
                        RT >>= 1;
                        facch >>= 1;
                        faccl >>= 1;
//fprintf(stderr, "FMP3: %08o %08o %08o %08o %08o %08o %08o %02o\n\r", RA, RB, RC, faccl, facch, RT, RP, RK);
                    }
                    /* Check if still negative multiplican */
                    if (RP & B15) {
                        facch += RB;
                        faccl += RA;
                        if (facch & B0)
                            faccl++;
                        facch &= M23;
                    }

                    /* Check if underflow */
                    if ((RX & 2) == 0 && faccl == 0 && facch != 0) {
                        while ((faccl & B1) == 0) {
                            e1--;
                            RP <<= 1;
                            RT <<= 1;
                            facch <<= 1;
                            faccl <<= 1;
                            if (RP & B0)
                                RT |= 1;
                            if (RT & B0)
                                facch |= 1;
                            if (facch & B0)
                                faccl |= 1;
                            faccl &= FMASK;
                            facch &= M23;
                            RT &= M23;
                            RP &= M23;
                        }
                    }
                    /* Fix up if over flow */
                    if (faccl & B0) {
                        if (faccl & 1)
                           facch |= B0;
                        faccl >>= 1;
                        facch >>= 1;
                        facch &= MMASK;
                        e1++;
                    }

//fprintf(stderr, "FMP4: %08o %08o\n\r", faccl, facch);
                    /* Fix sign */
                    if (f) {
                        faccl ^= FMASK;
                        facch ^= M23;
                        facch ++;
                        if (facch & B0) {
                           faccl ++;
                           faccl &= FMASK;
                           facch &= MMASK;
                        }
                    }
//fprintf(stderr, "FMP5: %08o %08o\n\r", faccl, facch);
                    /* Go normalize and round */
                    goto fn;

       case OP_FDVD:         /* Floating Point Divide +FP */
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    if (Mem_read(RS, &RA, 1)) { /* Read lower */
                        goto intr;
                    }
                    RS++;
                    if (Mem_read(RS, &RB, 1)) { /* Read high + exp */
                        goto intr;
                    }
//fprintf(stderr, "FDV0: %08o %08o %08o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RX);
                    fovr |= (RB & B0) != 0;
                    RB &= M23;
                    if (RX & 4) { /* See if we should swap operands */
                        RT = facch;
                        facch = RB;
                        RB = RT;
                        RT = faccl;
                        faccl = RA;
                        RA = RT;
//fprintf(stderr, "FDV1: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
                    }
                    /* Extract exponents and mantissas */
                    e1 = ((facch & M9)) - 256;
                    facch &= MMASK;
                    e2 = ((RB & M9)) - 256;
                    RB &= MMASK;
                    e1 -= e2; /* Final exponent is difference of terms */
                    /* Make both positive and comupte final sign */
                    f = 0;
                    if (faccl & B0) {
                        f = 1;
                        faccl ^= FMASK;
                        facch ^= MMASK;
                        facch += B15;
                        if (facch & B0) {
                            faccl += 1;
                            faccl &= FMASK;
                            facch &= MMASK;
                        }
                    }
                    if ((RA & B0) != 0){
                        f = !f;
                        RA ^= FMASK;
                        RB ^= MMASK;
                        RB += B15;
                        if (RB & B0) {
                            RA += 1;
                            RA &= FMASK;
                            RB &= MMASK;
                        }
                    }
                    /* Handle zero divide */
                    if ((RA | RB) == 0) {
                        faccl = 0;
                        facch = 0400;
                        fovr=1;
                        break;
                    }
                    RA ^= M23;       /* precompliment */
                    RB ^= M23;
                    RP = faccl;   /* Set dividend into upper half */
                    RT = facch;
                    faccl = 0;
                    facch = 0;
                    n = 0;
                    /* DO actual divide */
                    for (RK=46; RK != 0; RK--) {
                         uint32    t0, t1;
                         t0 = RT + RB + 1;
                         t1 = RP + RA;
                         if (t0 & B0)
                             t1++;
                         if (n || (t1 & B0)) {
                             RT = t0;
                             RP = t1;
                             facch |= 1;
                         }
                         facch <<= 1;
                         faccl <<= 1;
                         RT <<= 1;
                         RP <<= 1;
                         if (facch & B0)
                             faccl |= 1;
                         if (RT & B0)
                             RP |= 1;
                         n = (RP & B0) != 0;
                         RT &= M23;
                         RP &= M23;
                         facch &= M23;
//fprintf(stderr, "FDV3: %08o %08o %08o %08o %08o %08o %08o %02o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RP, RT, RK,t1, t0, n);
                    }
                    /* If rounding and positive and negative result, adjust */
                    if (((RX & 2) == 0 || f == 0) && faccl & B0) {
                        if (faccl & 1)
                            facch |= B0;
                        faccl >>= 1;
                        facch >>= 1;
                        e1++;
                    }
                    /* Fix sign */
                    if (f) {
                        if (faccl & B0 && (RX & 2)) {
                            if (faccl != B0)
                                e1++;
                            facch = (e1 + 256) & M9;
                            faccl = B0;
                            fovr=1;
                            break;
                        } else {
                            faccl ^= FMASK;
                            facch ^= M23;
                            facch ++;
                            if (facch & B0)
                               faccl ++;
                            faccl &= FMASK;
                            facch &= M23;
                            if (faccl == B0)
                                fovr=1;
                        }
                    }
//fprintf(stderr, "FDV4: %08o %08o %o\n\r", faccl, facch, f);
                    goto fn;

       case OP_LFP:          /* Load Floating Point +FP */
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    if (RX & 1) {
                       faccl = facch = fovr = 0;
//fprintf(stderr, "LFPZ: %08o %08o %o\n\r", faccl, facch, RX);
                       break;
                    }
                    if (Mem_read(RB, &RA, 1)) {  /* Read low order */
                        goto intr;
                    }
                    RB++;
                    if (Mem_read(RB, &RS, 1)) {  /* Read high order + exp */
                        goto intr;
                    }
                    faccl = RA;
                    facch = RS & M23;
                    fovr = (RS & B0) != 0;
//fprintf(stderr, "LFP: %08o %08o %08o %o\n\r", faccl, facch, RC, fovr);
                    break;

       case OP_SFP:          /* Store Floating Point +FP */
//fprintf(stderr, "SFP: %08o %08o %o\n\r", faccl, facch, fovr);
                    if ((cpu_flags & FLOAT) == 0)
                        goto voluntary;
                    if (Mem_write(RB, &faccl, 1)) {
                       goto intr;
                    }
                    RA = facch;
                    if (fovr) {
                        RA |= B0;
                        BV = 1;
                        if (!exe_mode && (Mode & 7) == 4)
                            SR64 |= B2;
                    }
                    RB++;
                    if (Mem_write(RB, &RA, 1)) {
                       goto intr;
                    }
                    if (RX & 1)
                       faccl = facch = fovr = 0;
                    break;

       case 0160:   /* Stevenage machines */   /* Load accumulators */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                         /* Restore registers */
                         for (n = 0; n < 8; n++)     /* Restore user mode registers */
                             Mem_read(RB+n, &XR[n], 0);
                         break;
                    }
                    /* Fall through */

       case 0161:   /* Stevenage machines */   /* Store accumulators */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                         /* Dump registers */
                         for (n = 0; n < 8; n++)     /* Restore user mode registers */
                             Mem_write(RB+n, &XR[n], 0);
                         break;
                    }
                    /* Fall through */

       case 0162:   /* Stevenage machines */
       case 0163:   /* Stevenage machines */   /* Stop and Display */
       case 0164:   /* Stevenage machines */   /* Search List N for Word X */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                        RK = RB;
                        RB = XR[(RX+1) & 07] & adrmask;
                        do {
                            if (Mem_read(RA, &RT, 1)) {
                                goto intr;
                            }
                            RB++;
                            if (RA == RT)
                               BCarry = 1;
                            RK = (RK - 1) & 0777;
                        } while (RA != RT && RK != 0);
                        XR[(RX+1) & 07] = RB;
                        break;
                    }
                    /* Fall through */
                        
       case 0165:   /* Stevenage machines */   /* Parity Search */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                        RK = RB;
                        RB = XR[(RX+1) & 07] & adrmask;
                        do {
                            if (Mem_read(RA, &RT, 1)) {
                                goto intr;
                            }
                            RA++;
                            RB++;
                            RK = (RK - 1) & 0777;
                        } while (RK != 0);
                        XR[RX] = RA;
                        XR[(RX+1) & 07] = RB;
                        break;
                    }
                    /* Fall through */

       case 0166:   /* Stevenage machines */   /* Test X unequal */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                        if (RA != RB)
                            BCarry = 1;
                        break;
                    }
                    /* Fall through */

       case 0167:   /* Stevenage machines */   /* Test X Less */
                    if ((cpu_flags & SV) != 0 && exe_mode) {
                        RB += BCarry;
                        if (RB != RA)
                            BCarry = (RB > RA);
                        break;
                    }

                    /* If we get here and not in executive mode do volintary */
                    if (exe_mode) {
                        reason = SCPE_STOP;
                        break;
                    }
                    /* Fall through */

       case 0170:            /* Read special register */
                    if (exe_mode) {
                         RA = 0;
                         switch(RB) {
                         case 0: /* Time of day clock */
                                 time_read(&RA);
                                 break;
                         case 1: RA = SR1; SR1 = 0; break;
                         case 64: RA = SR64; SR64 &= 003777777; break;
                         case 65: RA = SR65; break;
                         default: if (RB < 64)
                                      chan_nsi_status(RB, &RA);
                                  break;
                         }
                         XR[RX] = RA;
                         break;
                    }
                    /* Fall through */
       case 0171:            /* Write special register */
                    if (exe_mode) {
//fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
                         if (RB < 64)
                             chan_nsi_cmd(RB, RA);
                         break;
                    }
                    /* Fall through */
       case 0172:            /* Exit from executive */
       case 0173:            /* Load Datum limit and G */
                     if (exe_mode) {
                         if (CPU_TYPE < TYPE_C1) {
                             /* For non extended address processors. */
                             Mem_read(RB, &RA, 0);
                             RG = RA & 077;
                             RD = RA & 077700;
                             RL = (RA >> 9) & 077700;
                         } else {
                             Mem_read(RB, &RA, 0); /* Read datum */
                             RD = RA & (M22 & ~077);
                             RG = (RA & 17) << 3;
                             Mem_read(RB+1, &RA, 0); /* Read Limit */
                             RL = RA & (M22 & ~077);
                             RG |= (RA & 07);
                             Mode = RA & 077;
                         }
                         adrmask = (Mode & (AM22)) ? M22 : M15;
//fprintf(stderr, "Load C=%08o limit: %08o D:=%08o %02o\n\r", RC, RL, RD, Mode);
                         if (RF & 1)                 /* Check if 172 or 173 order code */
                             break;
                         /* Restore registers */
                         for (n = 0; n < 8; n++)     /* Restore user mode registers */
                             Mem_read(RD+n, &XR[n], 0);
                         Mem_read(RD+9, &RA, 0);     /* Read ZStatus and mode */
                         Mem_read(RD+8, &RC, 0);     /* Restore C register */
//fprintf(stderr, "Load PC: %08o D:=%08o z=%08o\n\r", RC, RD, RA);
                         BV = (RC & B0) != 0;
                         BCarry = (RC & B1) != 0;
                         Zero = 0;
                         /* Type A & B */
                         if (CPU_TYPE < TYPE_C1) {
                             if (RC & B8)
                                 Zero = 1;
                             RC &= M15;
                             RC -= RD;
                         } else {
                             if (RA & B3)
                                 Zero = 1;
                         }
                         RC &= (Mode & (EJM|AM22)) ? M22 : M15;
                         if (cpu_flags & FLOAT && cpu_flags & SL_FLOAT) {
                             /* Restore floating point ACC from D12/D13 */
                             Mem_read(RD+12, &faccl, 0);  /* Restore F.P.U. */
                             Mem_read(RD+13, &facch, 0);  /* Restore F.P.U. */
                             fovr = (facch & B0) != 0;
                             facch &= M23;
                         }
                         exe_mode = 0;
                         break;
                    }
                    /* Fall through */
       case 0174:            /* Send control character to peripheral */
                    if (exe_mode) {
                         chan_send_cmd(RB, RA & 07777, &RT);
//fprintf(stderr, "CMD  C=%08o %04o %04o %08o\n\r", RC, RT, RB, RA);
                         m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
                         m = 6 * (3 - m);
                         RT = (RT & 077) << m;
                         RA &= ~(077 << m);
                         RA |= RT;
                         XR[RX] = RA;
                         break;
                    }
                    /* Fall through */
       case 0175:                          /* Null operation in Executive mode */
                    if (exe_mode) {
//fprintf(stderr, "CMD 175 C=%08o %04o %08o\n\r", RC, RB, RA);
                         break;
                    }
       case 0176:
                    if (exe_mode) {
//fprintf(stderr, "CMD 176 C=%08o %04o %08o\n\r", RC, RB, RA);
                         break;
                    }
                    /* Fall through */
       case 0177:            /* Test Datum and Limit */
                    if (exe_mode) {
                        if (RA < RD || RA >= RL)
                            BCarry = 1;
                        break;
                    }
       case 0140:
       case 0141:
       case 0142:
       case 0143:
       case 0144:
       case 0145:
       case 0146:
       case 0147:
       case 0150:
       case 0151:
       case 0152:
       case 0153:
       case 0154:
       case 0155:
       case 0156:
       case 0157:
       default:
                    /* Voluntary entry to executive */
voluntary:
                    if (exe_mode) {
                        reason = SCPE_STOP;
                        break;
                    }
                    if ((CPU_TYPE < TYPE_C1) && !exe_mode)
                        RC += RD;
                    exe_mode = 1;
                    if (cpu_flags & FLOAT && cpu_flags & SL_FLOAT) {
                       /* Store registers */
                       Mem_write(RD+12, &faccl, 0);
                       RT = facch;
                       if (fovr)
                           RT |= B0;
                       Mem_write(RD+13, &RT, 0);  /* Save F.P.U. */
                    }
                    if (CPU_TYPE >= TYPE_C1) {
                        Mem_read(RD+9, &RT, 0);
                        RT &= M15;
                        /* Build ZSTAT and ASTAT */
                        if (Zero)
                            RT |= B3;
                        if (OPIP)
                            RT |= B2;
                        Mem_write(RD+9, &RT, 0);
                    }
                    RT = RC;
                    if (BV)
                        RT |= B0;
                    if (BCarry)
                        RT |= B1;
                    /* Type A & B */
                    if (CPU_TYPE < TYPE_C1 && Zero)
                        RT |= B8;
                    Mem_write(RD+8, &RT, 0);
                    for (n = 0; n < 8; n++)
                        Mem_write(RD+n, &XR[n], 0);
                    Zero = Mode = 0;
                    BCarry = BV = 0;
                    adrmask = M15;
                    if ((cpu_flags & SV) != 0) {
                        if ((RF & 0170) == 0140 || (RF & 0170) == 0110)
                           XR[1] = RD+RX;
                        XR[2] = RB;
                        XR[3] = RF & 07;
                        RC = 020 + ((RF >> 3) & 017);
                    } else {
                        XR[1] = RB;
                        XR[2] = temp;
                        RC = 040;
                    }
                    break;
       }

       if (hst_lnt) {      /* history enabled? */
           hst[hst_p].rr = RA;
       }
       sim_interval--;
    }                           /* end while */

/* Simulation halted */

    return reason;
}

/* Interval timer routines */
t_stat
rtc_srv(UNIT * uptr)
{
    int32 t;

    t = sim_rtcn_calb(rtc_tps, TMR_RTC);
    sim_activate_after(uptr, 1000000/rtc_tps);
    SR64 |= B3;
    return SCPE_OK;
}

int
bcd_2d(int n)
{
    uint8               d1, d2;

    d1 = n / 10;
    d2 = n % 10;
    return (d1 << 4) | d2;
}

void
time_read(uint32 *word)
{
    time_t              curtim;
    struct tm          *tptr;

    curtim = time(NULL);        /* get time */
    tptr = localtime(&curtim);  /* decompose */
    if (tptr == NULL)
        return;                 /* error? */

    /* Convert and fill buffer */
    *word = bcd_2d(tptr->tm_sec);
    *word |= bcd_2d(tptr->tm_min) << 7;
    *word |= bcd_2d(tptr->tm_hour) << 14;
    return;
}
/* Reset routine */

t_stat
cpu_reset(DEVICE * dptr)
{
    sim_brk_types = sim_brk_dflt = SWMASK('E') | SWMASK('A') | SWMASK('B');
    hst_p = 0;

    sim_register_clock_unit (&cpu_unit[0]);
    sim_rtcn_init (cpu_unit[0].wait, TMR_RTC);
    sim_activate(&cpu_unit[0], cpu_unit[0].wait) ;
    SR64 = SR65 = 0;

    return SCPE_OK;
}


/* Memory examine */

t_stat
cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw)
{
    if (addr >= MAXMEMSIZE)
        return SCPE_NXM;
    if (vptr != NULL) {
        if (addr < 010)
           *vptr = (t_value)XR[addr];
        else
           *vptr = (t_value)M[addr];
    }
    return SCPE_OK;
}

/* Memory deposit */

t_stat
cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw)
{
    if (addr >= MAXMEMSIZE)
        return SCPE_NXM;
    if (addr < 010)
       XR[addr] = val;
    else
       M[addr] = val;
    return SCPE_OK;
}

t_stat
cpu_show_size(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
    fprintf(st, "%dK", MEMSIZE/1024);
    return SCPE_OK;
}

t_stat
cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
    uint32     mc = 0;
    uint32     i;

    cpu_unit[0].flags &= ~UNIT_MSIZE;
    cpu_unit[0].flags |= val;
    val >>= UNIT_V_MSIZE;
    val = (val + 1) * 4096;
    if ((val < 0) || (val > MAXMEMSIZE))
        return SCPE_ARG;
    for (i = val - 1; i < MEMSIZE; i++)
        mc |= M[i];
    if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE)))
        return SCPE_OK;
    MEMSIZE = val;
    for (i = MEMSIZE; i < MAXMEMSIZE; i++)
        M[i] = 0;
    return SCPE_OK;
}

t_stat
cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
    CPUMOD    *ptr;

    val >>= UNIT_V_MODEL;
    for(ptr = &cpu_modtab[0]; ptr->name != NULL; ptr++) {
        if (ptr->mod_num == val) {
           cpu_flags = ptr->cpu_flags;
           io_flags = ptr->io_flags;
           rtc_tps = ptr->ticker;
           cpu_unit[0].flags &= ~(UNIT_MODEL);
           cpu_unit[0].flags |= MODEL(val);
           return SCPE_OK;
        }
    }
    return SCPE_ARG;
}

t_stat
cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
    int32 oval = val;
    cpu_flags &= ~FLOAT;
    if (val)
        cpu_flags |= FLOAT;
    if (oval != val)
       return SCPE_ARG;
    return SCPE_OK;
}

t_stat
cpu_show_float(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
    fprintf(st, "%s", (cpu_flags & FLOAT) ? "FLOAT":"NOFLOAT");
    return SCPE_OK;
}

t_stat
cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
    int32 oval = val;
    cpu_flags &= ~MULT;
    if (val)
        cpu_flags |= MULT;
    if (oval != val)
       return SCPE_ARG;
    return SCPE_OK;
}

t_stat
cpu_show_mult(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
    fprintf(st, "%s", (cpu_flags & MULT) ? "MULT":"NOMULT");
    return SCPE_OK;
}

/* Handle execute history */

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

    if (cptr == NULL) {
        hst_p = 0;
        return SCPE_OK;
    }
    lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r);
    if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
        return SCPE_ARG;
    hst_p = 0;
    if (hst_lnt) {
        free(hst);
        hst_lnt = 0;
        hst = NULL;
    }
    if (lnt) {
        hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);

        if (hst == NULL)
            return SCPE_MEM;
        hst_lnt = lnt;
    }
    return SCPE_OK;
}

/* Show history */

t_stat
cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc)
{
    int32               k, di, lnt;
    const char          *cptr = (const char *) desc;
    t_stat              r;
    t_value             v[1];
    struct InstHistory *h;

    if (hst_lnt == 0)
        return SCPE_NOFNC;      /* enabled? */
    if (cptr) {
        lnt = (int32) get_uint(cptr, 10, hst_lnt, &r);
        if ((r != SCPE_OK) || (lnt == 0))
            return SCPE_ARG;
    } else
        lnt = hst_lnt;
    di = hst_p - lnt;           /* work forward */
    if (di < 0)
        di = di + hst_lnt;
    fprintf(st, "       C       EA       XR        A        B   Result c v e M  Op\n\n");
    for (k = 0; k < lnt; k++) { /* print specified */
        h = &hst[(++di) % hst_lnt];     /* entry pointer */

        if (h->rc & HIST_PC) {   /* instruction? */
            fprintf(st, " %07o %08o %08o %08o %08o %08o %o %o %o %02o ",
                    h->rc & M22 , h->ea, h->xr, h->ra, h->rb, h->rr,
                    h->c, h->v, h->e, h->mode);
            v[0] = h->op;
            (void)fprint_sym(st, h->rc & M22, v, &cpu_unit[0], SWMASK('M'));
            fputc('\n', st);    /* end line */
        }                       /* end else instruction */
    }                           /* end for */
    return SCPE_OK;
}


t_stat
cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
    fprintf(st, "ICL1900 CPU\n\n");
    fprintf(st, "The ICL1900 \n");
    fprint_set_help(st, dptr);
    fprint_show_help(st, dptr);
    return SCPE_OK;
}
