/* i7070_cpu.c: IBM 7070 CPU simulator

   Copyright (c) 2005-2016, 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.

   cpu          IBM 7070 central processor

   The IBM 7070 was introduced in June 1960, as a replacement to the IBM 650.
   It had core memory up to 10,000 10 digit words.
   The 7072 was introduced November 1962 and the 7074 on November 1961.
   The 7074 is a faster version of the 7070 with the addition of memory up
   to 40,000 10 digit words. The first 100 memory locations can be used as
   index registers. Most memory reference instructions allow for a field
   of digits to be selected to operate on and not modify the rest.

   The 7070 is a decimal machine with each word consisting of 10 digits
   plus a sign. The sign can be plus, minus or alpha. Alpha data is stored
   5 characters to a word (2 digits per character).

   The system state for the IBM 7070 is:

   AC1<0:10>            AC1 register
   AC2<0:10>            AC2 register
   AC3<0:10>            AC3 register
   IC<0:5>              program counter

   The 7070 had one basic instuction format.

   <sign> 01 23 45 6789
     <sign> and 01 are opcode. Alpha is not allowed.
     23 specify an index register from memory location 01 to 99.
        or if extended addressing is enabled 10-99. 01-09 specify
        high order digit of address.
     45 encode either a field, or operands depending on instruction.
     6789 are address in memory. If index is specified they are
        added to fields <sign> [1]2345 of memory addressed by field 23.

   Accumulators may be accessed 9991/2/3 or 99991/2/3.

   Signs are stored as 9 for plus.
                       6 for minus.
                       3 for alpha.

   Options supported are Timer, Extended addressing and Floating point.
*/

#include "i7070_defs.h"
#include "sim_timer.h"

#define UNIT_V_MSIZE    (UNIT_V_UF + 0)
#define UNIT_MSIZE      (7 << UNIT_V_MSIZE)
#define UNIT_V_CPUMODEL (UNIT_V_UF + 4)
#define UNIT_MODEL      (0x01 << UNIT_V_CPUMODEL)
#define CPU_MODEL       ((cpu_unit.flags >> UNIT_V_CPUMODEL) & 0x01)
#define MODEL(x)        (x << UNIT_V_CPUMODEL)
#define MEMAMOUNT(x)    (x << UNIT_V_MSIZE)
#define OPTION_FLOAT    (1 << (UNIT_V_CPUMODEL + 1))
#define OPTION_TIMER    (1 << (UNIT_V_CPUMODEL + 2))
#define OPTION_EXTEND   (1 << (UNIT_V_CPUMODEL + 3))

#define TMR_RTC         1

#define HIST_NOEA       0x10000000
#define HIST_NOAFT      0x20000000
#define HIST_NOBEF      0x40000000
#define HIST_PC         0x10000
#define HIST_MIN        64
#define HIST_MAX        65536

struct InstHistory
{
    t_int64             op;
    uint32              ic;
    uint32              ea;
    t_int64             before;
    t_int64             after;
};

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_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 *st, DEVICE *dptr, UNIT *uptr, int32 flag,
                        const char *cptr);
const char          *cpu_description (DEVICE *dptr);

void                mem_init(void);

/* Interval timer option */
t_stat              rtc_srv(UNIT * uptr);
t_stat              rtc_reset(DEVICE * dptr);

t_uint64            M[MAXMEMSIZE] = { PSIGN };  /* memory */
t_uint64            AC[4];                      /* registers */
t_uint64            inds;                       /* Error indicators */
t_uint64            diaglatch;                  /* Diagnostic latches */
uint16              timer;                      /* Timer register */
uint32              IC;                         /* program counter */
uint16              timer_clock;                /* Timer clock */
uint8               SW = 0;                     /* Sense switch */
uint8               emode;                      /* Extended address mode */
uint16              pri_latchs[10];             /* Priority latchs */
uint32              pri_mask = 0xFFFFFF;        /* Priority masks */
uint8               pri_enb = 1;                /* Enable priority procs */
uint8               lpr_chan9[NUM_CHAN];        /* Line printer on channel 9 */
int                 cycle_time = 20;            /* Cycle time of 12us */

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


/* CPU data structures

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

UNIT                cpu_unit =
    { UDATA(&rtc_srv, OPTION_FLOAT|MEMAMOUNT(1)|MODEL(0x0), 10000), 10  };

REG                 cpu_reg[] = {
    {DRDATA(IC, IC, 20), REG_FIT},
    {HRDATA(AC1, AC[1], 44), REG_VMIO|REG_FIT},
    {HRDATA(AC2, AC[2], 44), REG_VMIO|REG_FIT},
    {HRDATA(AC3, AC[3], 44), REG_VMIO|REG_FIT},
    {HRDATA(IND, inds, 44), REG_VMIO|REG_FIT},
    {ORDATA(SW, SW, 4), REG_FIT},
    {FLDATA(SW1, SW, 0), REG_FIT},
    {FLDATA(SW2, SW, 1), REG_FIT},
    {FLDATA(SW3, SW, 2), REG_FIT},
    {FLDATA(SW4, SW, 3), REG_FIT},
    {NULL}
};

MTAB                cpu_mod[] = {
    {UNIT_MODEL, MODEL(0x0), "7070", "7070", NULL, NULL, NULL},
    {UNIT_MODEL, MODEL(0x1), "7074", "7074", NULL, NULL, NULL},
    {UNIT_MSIZE, MEMAMOUNT(0),  "5K",  "5K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(1), "10K", "10K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(2), "15K", "15K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(3), "20K", "20K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(4), "25K", "25K", &cpu_set_size},
    {UNIT_MSIZE, MEMAMOUNT(5), "30K", "30K", &cpu_set_size},
    {OPTION_FLOAT, 0, NULL, "NOFLOAT", NULL, NULL, NULL},
    {OPTION_FLOAT, OPTION_FLOAT, "FLOAT", "FLOAT", NULL, NULL, NULL},
    {OPTION_EXTEND, 0, NULL, "NOEXTEND", NULL, NULL, NULL},
    {OPTION_EXTEND, OPTION_EXTEND, "EXTEND", "EXTEND", NULL, NULL, NULL},
    {OPTION_TIMER, 0, NULL, "NOCLOCK", NULL, NULL, NULL},
    {OPTION_TIMER, OPTION_TIMER, "CLOCK", "CLOCK", NULL, NULL, 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, 10, 18, 1, 16, 44,
    &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
    NULL, DEV_DEBUG, 0, dev_debug,
    NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
};

uint32  dscale[4][16] = {
    {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 0,0,0,0,0,0},
    {0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 0,0,0,0,0,0},
    {0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 0,0,0,0,0,0},
    {0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000,
                                                                   0,0,0,0,0,0}
};

t_uint64 fdmask[11] = {
    0x0000000000LL,
    0xF000000000LL, 0xFF00000000LL, 0xFFF0000000LL, 0xFFFF000000LL,
    0xFFFFF00000LL, 0xFFFFFF0000LL, 0xFFFFFFF000LL, 0xFFFFFFFF00LL,
    0xFFFFFFFFF0LL, 0xFFFFFFFFFFLL
};

t_uint64 rdmask[11] = {
    0xFFFFFFFFFFLL, 0x0FFFFFFFFFLL, 0x00FFFFFFFFLL, 0x000FFFFFFFLL,
    0x0000FFFFFFLL, 0x00000FFFFFLL, 0x000000FFFFLL, 0x0000000FFFLL,
    0x00000000FFLL, 0x000000000FLL, 0x0LL
};

t_uint64 ldmask[11] = {
    0x0LL, 0xFLL, 0xFFLL, 0xFFFLL, 0xFFFFLL, 0xFFFFFLL, 0xFFFFFFLL, 0xFFFFFFFLL,
    0xFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFFLL
};

t_uint64 dmask[11] = {
    0x0LL, 0xFLL, 0xF0LL, 0xF00LL, 0xF000LL, 0xF0000LL,
    0xF00000LL, 0xF000000LL, 0xF0000000LL, 0xF00000000LL, 0xF000000000LL
};

#define gdigit(w, d) (((w) >> ((d) * 4)) & 0xF)
#define sdigit(d, v) ((((t_uint64)v) & 0xFLL) << ((d) * 4))
#define mdigit(d)    (0xFLL << ((d) * 4))

t_uint64 ReadP(uint32 addr) {
    sim_interval -= (CPU_MODEL == 0x0)? 2: 1;
    if (emode) {
        if (addr > MAXMEMSIZE) {
            switch(addr) {
            case 99991: return AC[1];
            case 99992: return AC[2];
            case 99993: return AC[3];
            default:    return 0LL;
            }
        }
    } else {
        if (addr >= 9990) {
            switch(addr) {
            case 9991: return AC[1];
            case 9992: return AC[2];
            case 9993: return AC[3];
            default:    return 0LL;
            }
        }
    }
    if (addr < MEMSIZE && addr < MAXMEMSIZE)
        return M[addr];
    return 0LL;
}

void WriteP(uint32 addr, t_uint64 value) {
    sim_interval -= (CPU_MODEL == 0x0)? 2: 1;
    if (emode) {
        if (addr > MAXMEMSIZE) {
            switch(addr) {
            case 99991: AC[1] = value; return;
            case 99992: AC[2] = value; return;
            case 99993: AC[3] = value; return;
            }
        }
    } else {
        if (addr >= 9990) {
            switch(addr) {
            case 9991: AC[1] = value; return;
            case 9992: AC[2] = value; return;
            case 9993: AC[3] = value; return;
            default: return;
            }
        }
    }
    if (addr < MEMSIZE && addr < MAXMEMSIZE)
        M[addr] = value;
}

t_stat
sim_instr(void)
{
    t_stat              reason;
    t_uint64            temp;
    t_uint64            MBR;
    uint16              opcode = 0;
    uint32              MA = 0;
    uint32              utmp;   /* Unsigned temp */
    int                 tmp;    /* Signed temp */
    uint8               f = 0;
    uint8               stopnext;
    uint8               IX = 0;
    uint8               f1 = 0;
    uint8               f2 = 0;
    uint8               op2 = 0;
    int                 iowait = 0;     /* Wait for IO to start */
    int                 chwait = 0;     /* Wait for channel to be inactive */
    int                 sign;
    int                 instr_count = 0; /* Number of instructions to execute */

    if (sim_step != 0) {
        instr_count = sim_step;
        sim_cancel_step();
    }

    reason = 0;

    iowait = 0;
    stopnext = 0;
    while (reason == 0) {       /* loop until halted */

/* If doing fast I/O don't sit in idle loop */
        if (iowait == 0 && chwait == 0 && stopnext)
            return SCPE_STEP;

        if (chwait != 0 && chan_active(chwait))
            sim_interval = 0;
        else
            chwait = 0;

        if (iowait)
            sim_interval = 0;

        if (sim_interval <= 0) {        /* event queue? */
            reason = sim_process_event();
            if (reason != SCPE_OK) {
                if (reason == SCPE_STEP && iowait)
                    stopnext = 1;
                else
                    break;      /* process */
            }
        }

        /* Only check for break points during actual fetch */
        if (iowait == 0 && chwait == 0
                        && sim_brk_summ && sim_brk_test(IC, SWMASK('E'))) {
            reason = STOP_IBKPT;
            break;
        }

        /* Don't do interupt if waiting on IO or channel */
        if (pri_enb && iowait == 0 && chwait == 0) {
            /* Check if we have to process one */
            if ((tmp = scan_irq()) != 0) {
                /* Save instruction counter */
                if (CPU_MODEL == 0x1)  /* On 7074 location 97 modified */
                        MBR = M[97];
                else
                        MBR = 0;        /* On 7070/2 location cleared */
                upd_idx(&MBR, IC);
                MBR &= DMASK;
                MBR |= PSIGN;
                M[97] = MBR;
                /* Save indicators */
                M[100] = inds;
                inds = PSIGN;
                pri_enb = 0;
                IC = tmp;
                sim_debug(DEBUG_TRAP, &cpu_dev, "IRQ= %d %d\n\r", IC, tmp);
            }
        }

   /* Main instruction fetch/decode loop */
       if (chwait == 0) {
            /* Split out current instruction */
            sim_interval -= 24;         /* count down */
            /* If waiting for IO don't bump IC or create history */
            if (iowait)
                /* Don't do a fetch if waiting on I/O to be ready */
                iowait = 0;
            else {
                MBR = ReadP(IC);
                if (hst_lnt) {  /* history enabled? */
                    hst_p = (hst_p + 1);        /* next entry */
                    if (hst_p >= hst_lnt)
                        hst_p = 0;
                    hst[hst_p].ic = (IC) | HIST_PC;
                    hst[hst_p].op = MBR;
                    hst[hst_p].after = 0;
                }
                IC++;
                MA = MBR & 0xf;                 MBR >>= 4;
                MA += dscale[0][MBR & 0xf];     MBR >>= 4;
                MA += dscale[1][MBR & 0xf];     MBR >>= 4;
                MA += dscale[2][MBR & 0xf];     MBR >>= 4;
                f2 = MBR & 0xf;                 MBR >>= 4;
                f1 = MBR & 0xf;                 MBR >>= 4;
                IX = MBR & 0xf;                 MBR >>= 4;
                IX += dscale[0][MBR & 0xf];     MBR >>= 4;
                opcode = MBR & 0xff;
                op2 = (opcode >> 4) & 0xf;
                if ((MBR & (SMASK >> 32)) == (MSIGN >> 32))
                    opcode |= 0x100;
            /* Check if extended addressing mode */
                if (emode && IX < 10) {
                    MA += dscale[3][IX];
                    IX = 0;
                }
            /* Handle indexing */
                if (IX > 0) {
                    sim_interval -= (CPU_MODEL == 0x0)? 10: 1;
                    MBR = M[IX];
                    utmp = dec_bin_idx(MBR);
                    if ((MBR & SMASK) == MSIGN) {       /* Change sign */
                        if (MA < utmp) {
                           if (emode)
                               MA = 100000 - MA - utmp;
                           else
                               MA = 10000 - MA - utmp;
                        } else
                           MA -= utmp;
                    } else if ((MBR & SMASK) == PSIGN) {
                        MA += utmp;
                        if (emode) {
                            if (MA > 100000)
                                MA -= 100000;
                        } else {
                            if (MA > 10000)
                                MA -= 10000;
                        }
                    } else {
                        reason = STOP_INDEX;
                        break;
                    }
                 }
                 IX = f2 + dscale[0][f1];
            /* Fetch data */
                 MBR = ReadP(MA);
                 if (hst_lnt) {  /* history enabled? */
                     hst[hst_p].ea = MA;
                     hst[hst_p].before = MBR;
                 }
             }

             switch(opcode) {
                /* Zero add absolute */
                case OP_ZAA:
                     MBR &= DMASK;
                     MBR |= PSIGN;
                     goto set_ac;
                /* Zero sub absolute */
                case OP_ZSA:
                     MBR &= DMASK;
                     MBR |= MSIGN;
                     goto set_ac;
                /* Load AC negitive from memory */
                case OP_ZS1: case OP_ZS2: case OP_ZS3:
                     if ((MBR & SMASK) != ASIGN)
                        MBR ^= SMASK;
                /* Zero add, load AC from memory */
                case OP_ZA1: case OP_ZA2: case OP_ZA3:
        set_ac:
                     MBR = (MBR & SMASK)|((rdmask[f1] & MBR) >> ((9 - f2) * 4));

                     AC[op2] = MBR;
                     sim_interval -= (CPU_MODEL == 0x0)? (f2 - f1)/3: 1;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[op2];
                     }
                     break;
                /* AC - memory */
                case OP_S1: case OP_S2: case OP_S3:
                     sign = (MBR & SMASK) != MSIGN;
                     if ((MBR & SMASK) == ASIGN)
                        sign |= 8;
                     goto add;
                /* AC - |memory| */
                case OP_SA:
                /* AC + |memory| */
                     sign = 1;
                     goto add;
                case OP_AA:
                     sign = 0;
                     goto add;
                /* AC + memory */
                case OP_A1: case OP_A2: case OP_A3:
                        /* Get field. */
                     sign = (MBR & SMASK) == MSIGN;
                     if ((MBR & SMASK) == ASIGN)
                        sign |= 8;
                add:
                     if ((AC[op2] & SMASK) == ASIGN)
                        sign |= 8;
                     MBR = (rdmask[f1] & MBR) >> ((9 - f2) * 4);
                     sim_interval -= (CPU_MODEL == 0x0)? 4*(f2 - f1)/3: 1;
                     if ((AC[op2] & SMASK) == MSIGN)
                        sign ^= 3;
                     AC[op2] &= DMASK;
                     if (sign & 1) {
                          int cy;
                          cy = dec_add(&AC[op2], NINES - MBR);
                          cy |= dec_add(&AC[op2], 1LL);
                          if (cy == 0) {
                              AC[op2] = NINES - AC[op2];
                              dec_add(&AC[op2], 1LL);
                              sim_interval -= (CPU_MODEL == 0x0)?
                                                        12*(f2 - f1)/3: 1;
                              sign ^= 3;
                          }
                     } else {
                          if(dec_add(&AC[op2], MBR))
                            inds |= 1LL << (4 * (3 - op2)); /* Set overflow */
                     }
                     AC[op2] &= DMASK;
                     if (sign & 8)
                        AC[op2] |= ASIGN;
                     else if (sign & 2)
                        AC[op2] |= MSIGN;
                     else
                        AC[op2] |= PSIGN;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[op2];
                     }
                     break;
                /* |memory| + AC */
                case OP_AAS1: case OP_AAS2: case OP_AAS3:
                     sign = ((MBR & SMASK) == MSIGN)?2:0;
                     goto addstore;
                /* mem = AC - |memory| */
                case OP_SS1: case OP_SS2: case OP_SS3:
                     sign = ((MBR & SMASK) != MSIGN)?1:2;
                     goto addstore;
                /* memory + AC */
                case OP_AS1: case OP_AS2: case OP_AS3:
                        /* Get field. */
                     sign = ((MBR & SMASK) == MSIGN)?3:0;
                addstore:
                     if ((MBR & SMASK) == ASIGN)
                        sign |= 4;
                     switch (AC[op2] & SMASK) {
                     case ASIGN: sign |= 8; break;
                     case MSIGN: sign ^= 1; break;
                     }
                     temp = (rdmask[f1] & MBR) >> ((9 - f2) * 4);
                     sim_interval -= (CPU_MODEL == 0x0)? 4*(f2 - f1)/3: 1;
                     if (sign & 1) {
                          int cy;
                          cy = dec_add(&temp, NINES - (AC[op2] & DMASK));
                          cy |= dec_add(&temp, 1LL);
                          if (cy == 0) {
                              temp = NINES - temp;
                              dec_add(&temp, 1LL);
                              sim_interval -= (CPU_MODEL == 0x0)?
                                                        12*(f2 - f1)/3: 1;
                              sign ^= 3;
                          }
                     } else {
                          if(dec_add(&temp, DMASK&AC[op2]))
                            inds |= 1LL << (4 * (3 - op2)); /* Set overflow */
                     }

                     /* Put results back */
                     utmp = (MBR & SMASK) >> 40;/* Original sign for compare */
                     MBR &= DMASK;
                     MBR &= ~(rdmask[f1] & fdmask[f2+1]); /* Clear digits. */
                     /* Check overflow */
                     if (temp & ~ldmask[f2-f1+1]) {
                        if (inds & 0x0F00000000LL) {
                           inds &= 0xFF0FFFFFFFFLL;     /* Set field */
                           inds |= 0x00900000000LL;
                        } else {
                           reason = STOP_FIELD;
                        }
                     }
                     temp &= ldmask[f2-f1+1];
                     /* Compute final sign */
                     if ((opcode & 0x10f) == (OP_AAS1 & 0x10f)) {
                          sign = utmp;
                     } else if (sign & 0xc) {
                          sign = ASIGN >> 40;
                     } else if (sign & 2) {
                          sign = MSIGN >> 40;
                     } else {
                          sign = PSIGN >> 40;
                     }
                     /* Check for sign change, and other data in word */
                     if (MBR != 0 && ((sign != utmp && f1 != 0 && f2 != 9) ||
                         (sign == (ASIGN >> 40) && utmp != (ASIGN >> 40)))) {
                        if (inds & 0xF000000000LL) {
                           inds &= 0xF0FFFFFFFFFLL;     /* Set field */
                           inds |= 0x09000000000LL;
                        } else {
                           reason = STOP_SIGN;
                        }
                     }
                     /* Restore results and sign */
                     MBR |= DMASK & temp << ((9 - f2) * 4);
                     MBR |= ((t_uint64)sign) << 40;
                     WriteP(MA, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;

                /* AC :: memory */
                case OP_C1: case OP_C2: case OP_C3:
                     temp = (rdmask[f1] & MBR) >> ((9 - f2) * 4);
                     temp |= MBR & SMASK;       /* Copy sign */
                     inds &= 0xFFFFF000FFFLL;
                     switch(dec_cmp(temp, AC[op2])) {
                     case -1: inds |= 0x0000001000LL; break;
                     case 1: inds |= 0x0000100000LL; break;
                     case 0: inds |= 0x0000010000LL; break;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[op2];
                     }
                     break;

                /* Clear Memory, store */
                case OP_ZST1: case OP_ZST2: case OP_ZST3:
                     MBR = SMASK & AC[op2];     /* Same sign as AC */
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF;
                     }
                /* Store digit */
                case OP_STD1: case OP_STD2: case OP_STD3:
                /* Store AC */
                case OP_ST1: case OP_ST2: case OP_ST3:
                     /* Check for sign change, and other data in word */
                     if ((opcode & 0x10f) == (OP_ST1 & 0x10f)) {
                         if ((AC[op2] & SMASK) != (MBR & SMASK) &&
                             (MBR & DMASK) != 0) {
                            if (inds & 0xF000000000LL) {
                               inds &= 0xF0FFFFFFFFFLL; /* Set field */
                               inds |= 0x09000000000LL;
                            } else {
                               reason = STOP_SIGN;
                               break;
                            }
                         }
                         /* Restore set */
                         MBR &= DMASK;
                         MBR |= SMASK & AC[op2];
                     }
                     MBR &= ~(rdmask[f1] & fdmask[f2+1]); /* Clear digits. */
                     temp = AC[op2] & DMASK;
                     /* Check overflow */
                     if (temp & ~ldmask[f2-f1+1]) {
                        if (inds & 0x0F00000000LL) {
                           inds &= 0xFF0FFFFFFFFLL;     /* Set field */
                           inds |= 0x00900000000LL;
                        } else {
                           reason = STOP_FIELD;
                           break;
                        }
                     }
                     temp &= ldmask[f2-f1+1];
                     /* Restore results */
                     MBR |= DMASK & (temp << ((9 - f2) * 4));
                     WriteP(MA, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;

                /* Branch AC zero */
                case OP_BZ1: case OP_BZ2: case OP_BZ3:
                     if ((AC[op2] & DMASK) == 0)
                        IC = MA;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Branch AC overflow */
                case OP_BV1: case OP_BV2: case OP_BV3:
                     if ((inds >> (4 * (3 - op2))) & 0x1) {
                        IC = MA;
                        inds &= ~(0xFLL << (4 * (3 - op2)));/* clear overflow */
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Branch AC minus */
                case OP_BM1: case OP_BM2: case OP_BM3:
                     if ((AC[op2] & SMASK) == MSIGN)
                        IC = MA;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Multiply */
                case OP_M:
                     /* Multiplicand in AC[3] */
                     AC[1] = AC[2] = 0;
                     sign = (MBR & SMASK) >> 40;
                     MBR = (rdmask[f1] & MBR) >> ((9 - f2) * 4);
                     sign = (((AC[3] & SMASK) >> 40) != sign) ? 6 : 9;
                     /* Multiply MBR * AC[3] result to AC[1],AC[2] <low> */
                     for(tmp = 36; tmp >= 0; tmp-=4) {
                         int digit = (AC[3] >> tmp) & 0xf;
                         AC[1] <<= 4;
                         AC[1] &= DMASK;
                         AC[1] |= (AC[2] >> 36) & 0xf;
                         AC[2] <<= 4;
                         AC[2] &= DMASK;
                         if (digit != 0) {
                            sim_interval -= (CPU_MODEL == 0x0)?
                                                        12*digit: digit;
                            /* Form product */
                            mul_step(&AC[2], MBR, digit);
                            digit = (AC[2] >> 40) & 0xff;
                            if (digit != 0)
                                dec_add_noov(&AC[1], digit);
                            AC[2] &= DMASK;
                         } else
                            sim_interval -= (CPU_MODEL == 0x0)? 2: 0;
                     }
                     /* Set sign */
                     AC[1] |= ((t_uint64)sign) << 40;
                     AC[2] |= ((t_uint64)sign) << 40;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                /* Divide */
                case OP_D:
                     /* dividend AC[1],AC[2] */
                     /* divisor in MBR */
                     sign = (MBR & SMASK) >> 40;
                     AC[3] = (rdmask[f1] & MBR) >> ((9 - f2) * 4);
                     if (AC[3] == 0) {
                        AC[3] |= ((t_uint64)sign) << 40;
                        reason = STOP_DIV;
                        break;
                     }
                     utmp = (AC[1] & SMASK) >> 40;
                    /* Compute sign */
                     if (utmp != 3 && utmp != sign)
                        utmp ^= 0xf;
                    /* If any are alpha, result is alpha */
                     if (sign == 3 || utmp == 3 || utmp == 0xc)
                        utmp = 3;
                     /* Divide AC1,AC2 by AC3 */
                     AC[1] &= DMASK;
                     AC[2] &= DMASK;
                     dec_comp(&AC[3]);
                     for(tmp = 10; tmp != 0; --tmp)
                         div_step(AC[3]);
                     dec_comp(&AC[3]);
                    /* Fix signs */
                     AC[1] |= ((t_uint64)utmp) << 40;
                     AC[2] |= ((t_uint64)sign) << 40;
                     AC[3] &= DMASK;
                     AC[3] |= ((t_uint64)sign) << 40;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                /* Shift control */
                case OP_SC:
                     op2 = (MA / 1000) % 10;
                     if (op2 == 0 || op2 > 3)
                        break;
                     utmp = MA % 100;
                     if (utmp > 10)
                        break;
                     temp = AC[op2] & DMASK;
                     switch ((MA / 100) % 10) {
                     case 0:
                        temp >>= utmp * 4;
                        break;
                     case 1:
                        if (utmp != 0) {
                           temp >>= (utmp - 1) * 4;
                           f1 = temp & 0xF;
                           temp >>= 4;
                           if (f1 > 5)
                              dec_add(&temp, 1LL);
                        }
                        break;
                     case 2:
                        temp <<= utmp * 4;
                        break;
                     case 3:
                        utmp = 0;
                        if (temp != 0) {
                            while((temp & dmask[10]) == 0) {
                                utmp++;
                                temp <<= 4;
                            }
                        }
                        if (IX) {
                            MBR = ReadP(IX);
                            MBR &= ~IMASK;
                            MBR &= DMASK;
                            MBR |= PSIGN;
                            if (utmp > 10)      /* BCD adjust */
                                utmp += 6;
                            MBR |= ((t_uint64)utmp) << 16;
                            WriteP(IX, MBR);
                        }
                        break;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = AC[op2];
                     }
                     AC[op2] &= SMASK;
                     AC[op2] |= DMASK & temp;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[op2];
                     }
                     break;
                /* Coupled shift control */
                case OP_CSC:
                     utmp = MA % 100;   /* Number of shifts */
                     if (utmp > 20)
                        break;
                     op2 = (MA / 100) % 10;     /* Operand */
                     f2 += f1 * 10;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = AC[1];
                     }
                     switch (op2) {
                     default:
                     case 0:    /* Shift right coupled */
                         sign = (AC[1] >> 40) & 0xf;
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             f1 = AC[1] & 0xf;
                             AC[1] >>= 4;
                             AC[2] |= ((t_uint64)f1) << 40;
                             AC[2] >>= 4;
                        }
                        break;
                     case 1:    /* Shift right coupled and round */
                         sign = (AC[1] >> 40) & 0xf;
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             f1 = AC[1] & 0xf;
                             AC[1] >>= 4;
                             AC[2] |= ((t_uint64)f1) << 40;
                             f1 = AC[2] & 0xf;
                             AC[2] >>= 4;
                        }
                        if (f1 > 5)
                           if (dec_add(&AC[2], 1LL))
                                if (dec_add(&AC[1], 1LL))
                                    inds |= 1LL << 8; /* Set overflow */
                        break;
                     case 2:    /* Shift left coupled */
                         sign = (AC[2] >> 40) & 0xf;
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             AC[1] <<= 4;
                             AC[1] &= DMASK;
                             AC[1] |= (AC[2] >> 36) & 0xf;
                             AC[2] <<= 4;
                             AC[2] &= DMASK;
                        }
                        break;
                     case 3:    /* Shift left and count coupled */
                         sign = (AC[2] >> 40) & 0xf;
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         utmp = 0;
                         if (AC[1] != 0 || AC[2] != 0) {
                             while((AC[1] & dmask[10]) == 0) {
                                 AC[1] <<= 4;
                                 AC[1] &= DMASK;
                                 AC[1] |= (AC[2] >> 36) & 0xf;
                                 AC[2] <<= 4;
                                 AC[2] &= DMASK;
                                 utmp++;
                             }
                        }
                        if (IX) {
                            MBR = ReadP(IX);
                            MBR &= ~IMASK;
                            MBR &= DMASK;
                            if (utmp > 10)      /* BCD adjust */
                                utmp += 6;
                            MBR |= ((t_uint64)utmp) << 16;
                            WriteP(IX, MBR);
                        }
                        break;
                     case 4:    /* Shift right from point ac1 */
                         sign = (AC[1] >> 40) & 0xf;
                         tmp = (MA / 1000) % 10;        /* Split point */
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             f1 = AC[1] & 0xf;
                             AC[1] = (AC[1] & fdmask[tmp]) |
                                        ((AC[1] & rdmask[tmp]) >> 4);
                             AC[2] |= ((t_uint64)f1) << 40;
                             AC[2] >>= 4;
                        }
                        break;
                     case 5:    /* Shift left from point ac1 */
                         sign = (AC[2] >> 40) & 0xf;
                         tmp = (MA / 1000) % 10;        /* Split point */
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             AC[1] = (AC[1] & rdmask[tmp]) |
                                        ((AC[1] & fdmask[tmp]) << 4);
                        }
                        break;
                     case 6:    /* Shift right from point ac2 */
                         sign = (AC[2] >> 40) & 0xf;
                         tmp = (MA / 1000) % 10;        /* Split point */
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             AC[2] = (AC[2] & fdmask[tmp]) |
                                        ((AC[2] & rdmask[tmp]) >> 4);
                        }
                        break;
                     case 7:    /* Shift left from point ac2 */
                         sign = (AC[2] >> 40) & 0xf;
                         tmp = (MA / 1000) % 10;        /* Split point */
                         AC[1] &= DMASK;
                         AC[2] &= DMASK;
                         for(;utmp != 0; utmp--) {
                             AC[1] <<= 4;
                             AC[1] &= DMASK;
                             AC[1] |= ((AC[2] & fdmask[tmp]) >> 36) & 0xf;
                             AC[2] = (AC[2] & rdmask[tmp]) |
                                        ((AC[2] & fdmask[tmp]) << 4);
                        }
                        break;
                     }
                     AC[1] |= ((t_uint64)sign) << 40;
                     AC[2] |= ((t_uint64)sign) << 40;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;
                /* AC1 : |Memory | */
                case OP_CA:
                     MBR = (rdmask[f1] & MBR) >> ((9 - f2) * 4);
                     inds &= 0xFFFFF000FFFLL;
                     switch(dec_cmp(MBR & DMASK, AC[1]&DMASK)) {
                     case -1: inds |= 0x0000001000LL; break;
                     case 1: inds |= 0x0000100000LL; break;
                     case 0: inds |= 0x0000010000LL; break;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;
                /* Compare digit */
                case OP_CD:
                     inds &= 0xFFFFF000FFFLL;
                     MBR >>= ((9 - f2) * 4);
                     MBR &= 0xF;
                     if (MBR > f1)
                        inds |= 0x0000100000LL;
                     else if (MBR < f1)
                        inds |= 0x0000001000LL;
                     else
                        inds |= 0x0000010000LL;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                     break;
                /* Branch load index */
                case OP_BLX:
                     upd_idx(&M[IX], IC);
                /* Branch */
                case OP_B:
                     IC = MA;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Branch low */
                case OP_BL:
                     if (inds & 0x0000001000LL)
                        IC = MA;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Branch high */
                case OP_BH:
                     if (inds & 0x0000100000LL)
                        IC = MA;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Branch equal */
                case OP_BE:
                     if (inds & 0x0000010000LL)
                        IC = MA;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Extended memory on 7074 */
                case OP_EXMEM:
                     if (CPU_MODEL == 0x1 && cpu_unit.flags & OPTION_EXTEND) {
                        switch(f1) {
                        case 0:
                                if (emode)
                                   IC = MA;
                                break;
                        case 1:
                                emode = 0;
                                break;
                        case 2:
                                emode = 1;
                                break;
                        }
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                case OP_HB:
                     IC = MA;
                     /* fall through */
                case OP_HP:
                     reason = STOP_HALT;
                     /* fall through */
                case OP_NOP:
                     /* fall through */
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                     }
                     break;
                /* Floating point option */
                /* Floating point: sEEMMMMMMM  EE+50*/
                case OP_FD: /* AC2 <- 0, AC1,AC2 <- AC1/M, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     AC[2] = 0;
                case OP_FDD: /* AC1,2 <- AC1/M, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((AC[1] & SMASK) == ASIGN || (MBR & SMASK) == ASIGN) {
                        reason = STOP_SIGN;
                        break;
                     }

                     /* Extract signs */
                     sign = (MBR & SMASK) == MSIGN;
                     if ((AC[1] & SMASK) == MSIGN)
                         sign ^= 3;

                     /* Extract exponents */
                     f1 = (((AC[1] >> 36) & 0xf) * 10) +
                                                ((AC[1] >> 32) & 0xf);
                     tmp = (((MBR >> 36) & 0xf) * 10) + ((MBR >> 32) & 0xf);
                     tmp = 51 + (f1 - tmp);
                     /* Clear exponents */
                     MBR &= FMASK;
                     if (MBR == 0) {
                        reason = STOP_DIV;
                        break;
                     }
                     AC[1] &= FMASK;
                     AC[2] &= FMASK;
                     AC[1] = NINES - AC[1];  /* One's compliment AC[1]&AC[2] */
                     AC[2] = FNINES - AC[2];
                     dec_add(&AC[2], 1LL);
                     if (AC[2] & EMASK) {       /* Propagate carry */
                        dec_add(&AC[1], AC[2] >> 32);
                        AC[2] &= FMASK;
                     }
                     /* Check if overflow on first try */
                     temp = AC[1];
                     if (dec_add(&temp, MBR)) {
                        /* Yes, shift right before starting */
                        AC[1] <<= 4;
                        AC[1] &= DMASK;
                        AC[2] <<= 4;
                        AC[1] |= (AC[2] >> 32) & 0xf;
                        AC[2] &= FMASK;
                        tmp--;
                     } else
                        f1++;
                     utmp = 8;
                     do {
                        int     cnt = 0;
                        /* Repeated subtract until overflow */
                        while(1) {
                            temp = AC[1];
                            if (dec_add(&temp, MBR))
                                break;
                            cnt++;
                            AC[1] = temp;       /* Restore AC if not less */
                            if (cnt > 9) {      /* Catch divide check */
                                reason = STOP_DIV;
                                goto done;
                            }
                        }
                        /* Shift right coupled */
                        AC[1] <<= 4;
                        AC[1] &= DMASK;
                        AC[2] <<= 4;
                        AC[1] |= (AC[2] >> 32) & 0xf;
                        AC[2] &= FMASK;
                        AC[2] |= cnt;   /* Put in count */
                     } while (--utmp != 0);

                     /* Restore remainder to correct value */
                     dec_comp(&AC[1]);

                     /* Now exchange AC1 & AC2 to get results in right place */
                     temp = AC[1];
                     AC[1] = AC[2];
                     AC[2] = temp;

                     /* Check overflow */
                     if (tmp > 99) {
                        inds |= 0x0001000000LL;         /* Set overflow */
                        tmp = 0;
                     }
                    /* Save exponents */
                     bin_dec(&AC[1], tmp, 8, 2);        /* Restore exponent */
                     if (f1 < 8)
                        AC[2] = 0;
                     else {
                        f1 -= 8;
                        AC[2] >>= 4;
                        if ((AC[2] & EMASK) != 0) {
                           if (f1-- != 0)
                               AC[2] >>= 4;
                           else
                               AC[2] = f1 = 0;
                        }
                        bin_dec(&AC[2], f1, 8, 2);      /* Restore exponent */
                     }

                    /* Fix signs */
                     if (sign & 1) {
                         AC[1] |= MSIGN;
                     } else {
                         AC[1] |= PSIGN;
                     }

                     if (sign & 3) {
                         AC[2] |= MSIGN;
                     } else {
                         AC[2] |= PSIGN;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                /* Floating point multiply */
                case OP_FM: /* AC1,2 <- AC1 * M, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((AC[1] & SMASK) == ASIGN || (MBR & SMASK) == ASIGN) {
                        reason = STOP_SIGN;
                        break;
                     }

                     /* Extract signs */
                     sign = (MBR & SMASK) == MSIGN;
                     sign ^= (AC[1] & SMASK) == MSIGN;

                     /* Extract exponents */
                     utmp = (((AC[1] >> 36) & 0xf) * 10) +
                                                ((AC[1] >> 32) & 0xf);
                     f1 = (((MBR >> 36) & 0xf) * 10) + ((MBR >> 32) & 0xf);
                     utmp += f1;
                     utmp -= 50;
                     /* Clear exponents */
                     MBR &= FMASK;
                     temp = AC[1];
                     AC[1] = 0;
                     AC[2] = 0;
                     /* Multiplicand in AC[3] */
                     /* Multiply MBR * AC[1] result to AC[1],AC[2] <low> */
                     for(tmp = 28; tmp >= 0; tmp-=4) {
                         int digit = (temp >> tmp) & 0xf;
                         AC[1] <<= 4;
                         AC[1] &= DMASK;
                         AC[1] |= (AC[2] >> 28) & 0xf;
                         AC[2] <<= 4;
                         AC[2] &= FMASK;
                         if (digit != 0) {
                            sim_interval -= (CPU_MODEL == 0x0)? 12*digit:digit;
                            /* Form product */
                            mul_step(&AC[2], MBR, digit);
                            digit = (AC[2] >> 32) & 0xff;
                            if (digit != 0)
                                dec_add(&AC[1], digit);
                            AC[2] &= FMASK;
                         } else
                            sim_interval -= (CPU_MODEL == 0x0)? 2: 0;
                     }
                     /* Check if needs to be normalized */
                     if ((AC[1] & NMASK) == 0) {
                         AC[1] <<= 4;
                         AC[1] |= (AC[2] >> 28) & 0xf;
                         AC[2] <<= 4;
                         AC[2] &= FMASK;
                         utmp--;
                     }
                     /* Check overflow */
                     if (utmp > 99) {
                        inds |= 0x0001000000LL;         /* Set overflow */
                        utmp = 0;
                     }
                    /* Save exponents */
                     bin_dec(&AC[1], utmp, 8, 2);       /* Restore exponent */
                     if (utmp < 8)
                        AC[2] = 0;
                     else
                        bin_dec(&AC[2], utmp-8, 8, 2);  /* Restore exponent */
                     /* Set signs */
                     if (sign) {
                        AC[1] |= MSIGN;
                        AC[2] |= MSIGN;
                     } else {
                        AC[1] |= PSIGN;
                        AC[2] |= PSIGN;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                /* Floating point round */
                case OP_FR: /* AC1 <- +.5, AC2 <- 0 */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = AC[1];
                     }
                     if (((AC[2] >> 28) & 0xf) > 5) {
                        temp = AC[1] & SMASK;
                        AC[1] &= DMASK;
                        if (dec_add(&AC[1], 1LL)) {
                            inds |= 0x0001000000LL;
                            AC[1] = 0;
                        }
                        AC[1] |= temp;          /* Restore sign */
                     }
                     AC[2] = PSIGN;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                /* Floating subtract absolute */
                case OP_FSA: /* AC2 <- 0, AC1,2 <- AC1,2-|M|, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((AC[1] & SMASK) == ASIGN || (MBR & SMASK) == ASIGN) {
                        reason = STOP_SIGN;
                        break;
                     }
                     sign = 1;
                     AC[2] = 0x65000000000LL;
                     goto float_add;
                /* Floating subtract */
                case OP_FS: /* AC2 <- 0, AC1,2 <- AC1,2 - M, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((AC[1] & SMASK) == ASIGN || (MBR & SMASK) == ASIGN) {
                        reason = STOP_SIGN;
                        break;
                     }
                     sign = (MBR & SMASK) != MSIGN;
                     AC[2] = 0x65000000000LL;
                     goto float_add;
                /* Floating add absolute */
                case OP_FAA: /* AC2 <- 0, AC1,2 <- AC1,2+|M|, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((AC[1] & SMASK) == ASIGN || (MBR & SMASK) == ASIGN) {
                        reason = STOP_SIGN;
                        break;
                     }
                     sign = 0;
                     goto float_add;
                /* Floating add */
                case OP_FA:  /* AC2 <- 0, AC1,2 <- AC1,2+M, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     AC[2] = 0x65000000000LL;
                /* Floating add double */
                case OP_FAD: /* AC1,2 <- AC1,2 + M, norm */
                /* Floating add double, suppress norm */
                case OP_FADS: /* AC1,2 <- AC1,2 + M */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((AC[1] & SMASK) == ASIGN || (MBR & SMASK) == ASIGN) {
                        reason = STOP_SIGN;
                        goto done;
                     }
                     sign = (MBR & SMASK) == MSIGN;
        float_add:
                     /* Extract sign */
                     if ((AC[1] & SMASK) == MSIGN)
                        sign ^= 3;

                     /* Compare exponents */
                     utmp = (((AC[1] >> 36) & 0xf) * 10) +
                                                ((AC[1] >> 32) & 0xf);
                     f1 = (((MBR >> 36) & 0xf) * 10) + ((MBR >> 32) & 0xf);
                     tmp = ((signed int)utmp) - ((signed int)f1);
                     /* Clear exponents and sign */
                     MBR   &= FMASK;
                     AC[1] &= FMASK;
                     AC[2] &= FMASK;
                     temp = 0;
                     if (tmp > 0) {     /* AC Bigger */
                        /* Shift MBR */
                         if (tmp > 16)
                            goto float_norm;
                         while(tmp > 0) {
                            temp |= ((t_uint64)(MBR & 0xf)) << 32;
                            MBR >>= 4;
                            temp >>= 4;
                            tmp--;
                        }
                     } else if (tmp < 0) {      /* AC Smaller */
                         utmp = f1;
                        /* Shift AC */
                         if (tmp > -16) {
                             while(tmp < 0) {
                                 AC[2] |= ((t_uint64)(AC[1] & 0xf)) << 32;
                                 AC[1] >>= 4;
                                 AC[2] >>= 4;
                                 tmp++;
                            }
                        } else {
                            AC[1] = MBR;
                            AC[2] = 0;
                            goto float_norm;
                        }
                     }
                     /* Do actual addition now */
                     if (sign & 1) {
                          /* Do compliment add */
                          dec_add(&AC[2], FNINES - temp);
                          dec_add(&AC[2], 1LL);
                          dec_add(&AC[1], FNINES - MBR);
                          /* Carry between halfs */
                          if (AC[2] & EMASK) { /* Carry out */
                             dec_add(&AC[1], (AC[2] >> 32) & 0xff);
                             AC[2] &= FMASK;
                          }

                          if ((AC[1] & EMASK) == 0) {
                              AC[2] = FNINES - (AC[2] & FMASK);
                              AC[1] = FNINES - (AC[1] & FMASK);
                              dec_add(&AC[2], 1LL);
                              if (AC[2] & EMASK) { /* Carry out */
                                 dec_add(&AC[1], (AC[2] >> 32) & 0xff);
                                 AC[2] &= FMASK;
                              }
                              sim_interval -= (CPU_MODEL == 0x0)?
                                                        12*(f2 - f1)/3: 1;
                              sign ^= 3;
                          }
                          AC[1] &= FMASK;
                     } else {
                        /* Add low then high */
                          dec_add(&AC[2], temp);
                          dec_add(&AC[1], MBR);
                          if (AC[2] & EMASK) /* Carry out */
                             dec_add(&AC[1], (AC[2] >> 32) & 0xf);
                     }
                     if (AC[1] & EMASK) {
                          AC[2] |= ((t_uint64)(AC[1] & 0xf)) << 32;
                          AC[1] >>= 4;
                          AC[2] >>= 4;
                          utmp++;
                     }
        float_norm:
                     /* Normalize result */
                     tmp = utmp;
                     if (opcode != OP_FADS && AC[1] != 0 && AC[2] != 0) {
                         while((AC[1] & NMASK) == 0) {
                             AC[1] <<= 4;
                             AC[1] |= (AC[2] >> 28) & 0xf;
                             AC[2] <<= 4;
                             AC[2] &= FMASK;
                             tmp--;
                         }
                     }
                     /* Set exponent if error */
                     if (AC[1] == 0 && AC[2] == 0)
                        tmp = 50;
                     if (tmp < 0) {
                        inds |= 0x0010000000LL;         /* Set underflow */
                        tmp = 0;
                     }
                     if (tmp > 99) {
                        inds |= 0x0001000000LL;         /* Set overflow */
                        tmp = 0;
                     }
                    /* Restore exponents */
                     bin_dec(&AC[1], tmp, 8, 2);        /* Restore exponent */
                     if (tmp < 8)
                        AC[2] = 0;
                     else
                        bin_dec(&AC[2], tmp-8, 8, 2);   /* Restore exponent */
                     /* Set signs */
                     if (sign & 2) {
                        AC[1] |= MSIGN;
                        AC[2] |= MSIGN;
                     } else {
                        AC[1] |= PSIGN;
                        AC[2] |= PSIGN;
                     }
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                /* Floating zero and add */
                case OP_FZA: /* AC2 <- 0, AC1 <- M, norm */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     /* Check sign */
                     if ((MBR & SMASK) == ASIGN) {
                         reason = STOP_SIGN;
                         break;
                     }
                     AC[2] = 0;
                     /* Extract exponent */
                     tmp = (((MBR >> 36) & 0xf) * 10) + ((MBR >> 32) & 0xf);
                     AC[1] = MBR & FMASK;
                     if (AC[1] != 0) {
                         while((AC[1] & NMASK) == 0) {
                             tmp--;
                             AC[1] <<= 4;
                         }
                     } else
                         tmp = 50;
                     if (tmp < 0) {
                        inds |= 0x0010000000LL;         /* Set underflow */
                        tmp = 0;
                     }
                     bin_dec(&AC[1], tmp, 8, 2);        /* Restore exponent */
                     AC[1] |= MBR & SMASK;
                     AC[2] |= MBR & SMASK;
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = AC[1];
                     }
                     break;

                case OP_FBU: /* Branch floating overflow */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((inds & 0x000F000000LL) != 0)
                        IC = MA;
                     inds &= 0xFFFF0FFFFFFLL;           /* Clear flag */
                     break;

                case OP_FBV: /* Branch floating underflow */
                     if ((cpu_unit.flags & OPTION_FLOAT) == 0) {
                         reason = STOP_UUO;
                         break;
                     }
                     if ((inds & 0x00F0000000LL) != 0)
                        IC = MA;
                     inds &= 0xFFF0FFFFFFFLL;           /* Clear flag */
                     break;

                /* Load with interchange */
                case OP_XLIN:
                     MBR = (MBR & (SMASK|OMASK)) | ((MBR >> 16) & AMASK) |
                                ((MBR << 16) & IMASK);
                /* Load index */
                case OP_XL:
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                     break;
                /* Unload index */
                case OP_XU:
                     MBR = ReadP(IX);
                     WriteP(MA, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;
                /* Index zero subtract */
                case OP_XZS:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     upd_idx(&MBR, MA);
                     MBR &= DMASK;
                     MBR |= MSIGN;
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;
                /* Index zero add */
                case OP_XZA:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     upd_idx(&MBR, MA);
                     MBR &= DMASK;
                     MBR |= PSIGN;
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;
                /* Index subtract */
                case OP_XS:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     temp = dec_bin_idx(MBR);
                     sign = ((MBR & SMASK)>> 40);
                     MBR &= DMASK;
                     switch(sign) {
                     case 0x6:  /* + -  tc b add */
                          temp += MA;
                          break;
                     default:
                     case 0x3:  /* + a  add res a */
                     case 0x9:  /* + +  add */
                          temp = ~temp + MA + 1;
                          if (temp & 0x8000) {
                              temp = ~temp + 1;
                              if (sign == 0x9) sign = 0x6;
                          }
                          break;
                     }
                     MBR |= ((t_uint64)sign) << 40;
                     upd_idx(&MBR, (uint32)temp);
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;
                /* Index add */
                case OP_XA:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     temp = 0;
                     upd_idx(&temp, MA);
                     sign = ((MBR & SMASK)>> 40);
                     MBR &= DMASK;
                     switch(sign) {
                     default:
                     case 0x3:  /* + a  add res a */
                     case 0x9:  /* + +  add */
                          dec_add(&temp, MBR & ((emode)?IMASK2:IMASK));
                          break;
                     case 0x6:  /* + -  tc b add */
                          if (temp == 0)
                             break;
                          dec_comp(&temp);
                          dec_add(&temp, MBR & ((emode)?IMASK2:IMASK));
                          if (temp & ((emode)?XMASK2:XMASK)) {
                              dec_comp(&temp);
                              sign = 0x9;
                          }
                          break;
                     }
                     MBR |= ((t_uint64)sign) << 40;
                     MBR &= (emode)?~IMASK2:~IMASK;
                     MBR |= temp;
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;
                /* Index set non-indexing */
                case OP_XSN:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     bin_dec(&MBR, MA, 0, 4);
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     break;
                /* Branch if index word index = 0 */
                case OP_BXN:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                     if ((MBR & IMASK) != 0)
                        IC = MA;
                     break;
                /* Branch decrement index */
                case OP_BDX:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     temp = MBR & IMASK;
                     dec_add(&temp, (emode)?0x999990000LL:0x99990000LL);
                     MBR &= (emode)?~IMASK2:~IMASK;
                     MBR |= temp & (emode)?IMASK2:IMASK;
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     goto checkix;
                /* Branch increment index */
                case OP_BIX:
                     temp = MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                     }
                     dec_add(&temp, 0x10000LL);
                     MBR &= (emode)?~IMASK2:~IMASK;
                     MBR |= temp & ((emode)?IMASK2:IMASK);
                     WriteP(IX, MBR);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].after = MBR;
                     }
                     goto checkix;
                /* Branch compared index */
                case OP_BCX:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                checkix:
                     temp = (MBR & IMASK) >> 16;
                     MBR &= AMASK;
                     dec_comp(&temp);
                     if(dec_add(&temp, MBR))
                         IC = MA;
                     break;
                /* Branch if index word index minus */
                case OP_BXM:
                     MBR = ReadP(IX);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].before = MBR;
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                     if ((MBR & SMASK) == MSIGN)
                        IC = MA;
                     break;
                /* Field over flow control */
                case OP_BFLD:
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                     }
                     switch (f2) {
                     case 0:
                           if ((inds & 0x0F00000000LL) == 0x0900000000LL) {
                                IC = MA;
                                inds ^= 0x0F00000000LL;
                           }
                           break;
                     case 1:
                           if ((inds & 0x0F00000000LL) != 0x0500000000LL) {
                                inds &= 0xFF0FFFFFFFFLL;
                                inds |= 0x00500000000LL;
                           }
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].ic |= HIST_NOEA;
                           }
                           break;
                     case 2:
                           if ((inds & 0x0F00000000LL) == 0x0900000000LL)
                                reason = STOP_SIGN;
                           else
                                inds &= 0xFF0FFFFFFFFLL;
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].ic |= HIST_NOEA;
                           }
                           break;
                     }
                     break;
                /* Sign change control */
                case OP_CS:
                     switch (f2) {
                     case 0:
                           inds &= 0xFFFFF000FFFLL;
                           utmp = ((MBR >> 40) & 0xf);
                           if (utmp > f1)
                                inds |= 0x00000100000LL;
                           else if (utmp < f1)
                                inds |= 0x00000001000LL;
                           else
                                inds |= 0x00000010000LL;
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].ic |= HIST_NOAFT;
                           }
                           break;
                      case 1:
                           MBR &= DMASK;
                           MBR |= ((t_uint64)f1) << 40;
                           WriteP(MA, MBR);
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].after = MBR;
                           }
                           break;
                      case 2:
                           if ((inds & 0xF000000000LL) == 0) {
                                inds |= 0x5000000000LL;
                           }
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].ic |= HIST_NOEA|HIST_NOBEF|HIST_NOAFT;
                           }
                           break;
                      case 3:
                           if ((inds & 0xF000000000LL) == 0x9000000000LL)
                                reason = STOP_SIGN;
                           else
                                inds &= 0xF0FFFFFFFFFLL;
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].ic |= HIST_NOEA|HIST_NOBEF|HIST_NOAFT;
                           }
                           break;
                      case 4:
                           if ((inds & 0xF000000000LL) == 0x9000000000LL) {
                                IC = MA;
                                inds ^= 0xF000000000LL;
                           }
                           if (hst_lnt) {  /* history enabled? */
                               hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                           }
                           break;
                      }
                      break;

                /* Record scatter */
                case OP_RS:
                /* Generate source address */
                     temp = M[IX];
                     utmp = dec_bin_idx(temp);
                     do {
                       uint32 dst, limit;
                       MBR = ReadP(MA++);       /* Grab next RDW */
                       get_rdw(MBR, &dst, &limit);
                       while(dst <= limit) {
                             WriteP(dst++, ReadP(utmp++));
                             if (utmp > MEMSIZE)
                                utmp = 0;
                       }
                     } while ((MBR & SMASK) != MSIGN);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                     break;
                /* Record gather */
                case OP_RG:
                     /* Generate destination address */
                     temp = M[IX];
                     utmp = dec_bin_idx(temp);
                     do {
                          uint32 src, limit;
                          MBR = ReadP(MA++);    /* Grab next RDW */
                          get_rdw(MBR, &src, &limit);
                          while(src <= limit) {
                               WriteP(utmp++, ReadP(src++));
                               if (utmp > MEMSIZE)
                               utmp = 0;
                          }
                     } while ((MBR & SMASK) != MSIGN);
                     if (hst_lnt) {  /* history enabled? */
                         hst[hst_p].ic |= HIST_NOAFT;
                     }
                     break;
                /* Edit alpha to numeric */
                case OP_ENB:
                case OP_ENS:
                case OP_ENA:
                     /* Generate source address */
                     temp = M[IX];
                     utmp = dec_bin_idx(temp);
                     do {
                          uint32 dst, limit;
                          MBR = ReadP(MA++);    /* Grab next RDW */
                          get_rdw(MBR, &dst, &limit);
                          while(dst <= limit) {
                                t_uint64   buffer;
                                f1 = (opcode == OP_ENB)? 0: 1;
                                temp = ReadP(utmp++);
                                if (utmp > MEMSIZE)
                                   utmp = 0;
                                buffer = 0x9090909090LL|ASIGN;
                                for(tmp = 9; tmp > 4; tmp--) {
                                    if (f1 == 0) {
                                        if ((temp & dmask[tmp+1]) == 0)
                                            buffer &= ~(0xFFLL << ((tmp-4)*8));
                                        else
                                            f1 = 1;
                                    }
                                    buffer |= (temp & dmask[tmp+1]) << ((tmp-4)*8);
                                }
                                WriteP(dst++, buffer);
                                if (opcode == OP_ENS) {
                                    switch(temp & SMASK) {
                                    case ASIGN:
                                        buffer = 0x9090909090LL|ASIGN;
                                        break;
                                    case PSIGN:
                                        buffer = 0x9090909060LL|ASIGN;
                                        break;
                                    case MSIGN:
                                        buffer = 0x9090909070LL|ASIGN;
                                        break;
                                    }
                                } else
                                    buffer = 0x9090909090LL|ASIGN;
                                for(; tmp >= 0; tmp--) {
                                    if (f1 == 0) {
                                        if ((temp & dmask[tmp+1]) == 0)
                                            buffer &= ~(0xFFLL << (tmp * 8));
                                        else
                                            f1 = 1;
                                    }
                                    buffer |= (temp & dmask[tmp+1]) << (tmp*8);
                                }
                                WriteP(dst++, buffer);
                          }
                        } while ((MBR & SMASK) != MSIGN);
                        if (hst_lnt) {  /* history enabled? */
                             hst[hst_p].ic |= HIST_NOAFT;
                        }
                        break;
                case OP_EAN:
                        /* Generate destination address */
                        temp = M[IX];
                        utmp = dec_bin_idx(temp);
                        do {
                          uint32 src, limit;
                          MBR = ReadP(MA++);    /* Grab next RDW */
                          get_rdw(MBR, &src, &limit);
                          while(src <= limit) {
                                t_uint64   buffer = 0;
                                temp = ReadP(src++);
                                for(tmp = 8, f1 = 16; tmp >= 0; tmp-= 2) {
                                    buffer |= (temp & dmask[tmp+1]) << f1;
                                    f1 += 4;
                                }
                                temp = ReadP(src++);
                                for(tmp = 8, f1 = 16; tmp >= 0; tmp-=2) {
                                    buffer |= (temp & dmask[tmp+1]) >> f1;
                                    f1 -= 4;
                                }
                                if ((temp & 0xF0LL) == 0x70LL)
                                    buffer |= MSIGN;
                                else
                                    buffer |= PSIGN;
                                WriteP(utmp++, buffer);
                                if (utmp > MEMSIZE)
                                   utmp = 0;
                          }
                        } while ((MBR & SMASK) != MSIGN);
                        if (hst_lnt) {  /* history enabled? */
                             hst[hst_p].ic |= HIST_NOAFT;
                        }
                        break;
                case OP_LL:
                case OP_LE:
                case OP_LEH:
                        /* Generate increment */
                        if (hst_lnt) {  /* history enabled? */
                             hst[hst_p].ic |= HIST_NOAFT;
                        }
                        temp = M[98];
                        utmp = dec_bin_idx(temp);
                        do {
                          uint32 src, limit;
                          MBR = ReadP(MA++);    /* Grab next RDW */
                          get_rdw(MBR, &src, &limit);
                          while(src <= limit) {
                                temp = ReadP(src);
                                temp = (rdmask[f1] & temp) >> ((9 - f2) * 4);
                                switch(dec_cmp(temp, AC[3])) {
                                case -1:
                                        if (opcode == OP_LL) {
                                            f = 1;
                                            AC[3] = temp;
                                            bin_dec(&M[98], src, 4,(emode)?5:4);
                                            M[98] &= DMASK;
                                            M[98] |= PSIGN;
                                        }
                                        break;
                                case 1:
                                        if (opcode != OP_LEH)
                                            break;
                                case 0:
                                        if (opcode != OP_LL) {
                                            f = 1;
                                            bin_dec(&M[98], src, 4,(emode)?5:4);
                                            M[98] &= DMASK;
                                            M[98] |= PSIGN;
                                            goto found;
                                        }
                                        break;
                                }
                                src += utmp;
                          }
                        } while ((MBR & SMASK) != MSIGN);
                found:
                        if (f)
                            IC++;
                        break;
                /* Electronic switch */
                case OP_BSW21:
                case OP_BSW22:
                case OP_BSW23:
                        /* Read flag */
                        opcode -= OP_BSW21;
                        opcode += 101;
                        MBR = ReadP(opcode);
                        if (hst_lnt) {  /* history enabled? */
                            hst[hst_p].before = MBR;
                        }
                        /* Compute mask */
                        f2 = 4 * (9 - f2);
                        temp = 0xFLL << f2;
                        switch(f1) {
                        case 0: /* Switch test */
                        case 3: /* test and turn on */
                        case 4: /* test and turn off */
                                if (MBR & temp)
                                    IC = MA;
                        }
                        if (f1 != 0)
                            MBR &= ~(temp);
                        if (f1 & 1) /* Set flag */
                            MBR |= 0x1LL << f2;
                        if (hst_lnt) {  /* history enabled? */
                            hst[hst_p].after = MBR;
                        }
                        WriteP(opcode, MBR);
                        break;

                /* Priority control */
                case OP_PC:
                      utmp = 0;
                      temp = 0xF;
                      /* Convert digits into bits */
                      for(f1 = 0; f1 < 10; f1++) {
                         if ((MBR & temp) != 0)
                            utmp |= 1;
                         temp <<= 4;
                         utmp <<= 1;
                      }
                      utmp >>= 1;
                      if (f2 == 1) {
                         utmp <<= 10;
                         pri_mask &= 0x3FF;
                         pri_mask |= utmp;
                      } else if (f2 == 0) {
                         pri_mask &= 0xFFC00;
                         pri_mask |= utmp;
                      }
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT;
                      }
                      break;

                /* Test priority latches */
                case OP_PRTST:
                      if (f1 == 0 && f2 == 0) {
                         for(tmp = 0; tmp < 10; tmp++) {
                            if (pri_latchs[tmp] != 0) {
                                IC = MA;
                                break;
                            }
                         }
                      } else {
                         if ((pri_latchs[f1] >> f2) & 1)
                             IC = MA;
                      }
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOBEF|HIST_NOAFT;
                      }
                      break;

                /* Set priority latches */
                case OP_PRION:
                      switch(f1) {
                      case 0:
                      case 8:
                      case 9:
                      case 1:
                      case 2:
                      case 3:
                      case 4:
                             pri_latchs[f1] |= 1 << f2;
                             break;
                      }
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOEA;
                      }
                      break;

                /* Clear priority latches */
                case OP_PRIOF:
                      pri_latchs[f1] &= ~(1 << f2);
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF|HIST_NOEA;
                      }
                      break;

                case OP_PR:
                      if (pri_enb == 1) /* Not in priority mode, nop */
                           break;
                      if ((tmp = scan_irq()) != 0) {
                          if (MA != 97)  {
                             /* Save instruction counter */
                             MBR = ReadP(97);
                             upd_idx(&MBR, MA);
                             MBR &= DMASK;
                             MBR |= PSIGN;
                             WriteP(97, MBR);
                             pri_enb = 0;
                             if (hst_lnt) {  /* history enabled? */
                                 hst[hst_p].after = MBR;
                             }
                          } else if (hst_lnt) {  /* history enabled? */
                              hst[hst_p].ic |= HIST_NOAFT;
                          }
                          inds = PSIGN;
                          IC = tmp;
                      } else {
                          if (MA == 97)
                             IC = dec_bin_idx(MBR);
                          else
                             IC = MA;
                          inds = ReadP(100);
                          pri_enb = 1;
                          if (hst_lnt) {  /* history enabled? */
                              hst[hst_p].ic |= HIST_NOAFT;
                          }
                      }
                      break;
                /* Check switch */
                case OP_BSWITCH:
                      if (f1 == 0 || f1 > 4) {
                           reason =  STOP_UUO;
                           break;
                      }
                      switch(f2) {
                      case 0:
                           if ((SW >> (f1 - 1)) & 1)
                              IC = MA;
                           break;
                      case 1:
                      case 2:
                           if (chan_active(((f2 - 1) * 4) + f1))
                              IC = MA;
                      }
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                      }
                      break;

                /* Inquiry station */
                case OP_INQ:
                      if (hst_lnt) { /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                      }
                      IX = 0;
                      if (f1 != 1) {    /* Only support group one */
                         reason = STOP_IOCHECK;
                         goto done;
                      }
                      switch (f2) {
                      case 0:   utmp = (IO_RDS << 8)|CHN_ALPHA; break;  /* QR */
                      case 1:   utmp = (IO_WRS << 8)|CHN_ALPHA; break;  /* QW */
                      default:
                                reason = STOP_UUO;
                                goto done;
                      }

                      /* Start off command */
                      switch (chan_cmd(4, utmp, MA)) {
                      case SCPE_BUSY:
                           iowait = 1;
                           break;
                      case SCPE_IOERR:
                           reason = STOP_IOCHECK;
                           break;
                      case SCPE_OK:
                           while(chan_active(0)) {
                               sim_interval = 0;
                               reason = sim_process_event();
                               if (reason != SCPE_OK)
                                   break;
                               chan_proc();
                           }
                           break;
                      }
                      break;
                /* Unit record I/O */
                case OP_UREC:
                      if (hst_lnt) { /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                      }
                      switch (f2) {
                      case 0:   utmp = (IO_TRS << 8); break;    /* US */
                      case 1:   utmp = (IO_RDS << 8)|CHN_ALPHA; break;/* UR */
                      case 4:                                   /* TYP */
                      case 2:                                   /* UW */
                      case 3:                                   /* UWIV */
                                utmp = (IO_WRS << 8)|CHN_ALPHA;
                                break;
                      case 9:
                               if (cpu_unit.flags & OPTION_TIMER) {
                                   if (f1 == 0)
                                        timer = 0;
                                   else if (f1 == 1)
                                        WriteP(MA, PSIGN|timer);
                                   goto done;
                                }
                                /* fall through */
                      default:
                                reason = STOP_UUO;
                                goto done;
                      }

                      /* Start off command */
                      switch (chan_cmd(f1, utmp, MA)) {
                      case SCPE_BUSY:
                           iowait = 1;
                           break;
                      case SCPE_IOERR:
                           reason = STOP_IOCHECK;
                           break;
                      case SCPE_OK:
                          while(chan_active(0)) {
                              sim_interval = 0;
                              reason = sim_process_event();
                              if (reason != SCPE_OK)
                                  break;
                              chan_proc();
                          }
                          switch (f2) {
                          case 0:                       /* US */
                                 chan_stat(0, CHS_ERR);
                                 break;
                          case 1:                       /* UR */
                                if (chan_stat(0, CHS_ERR))
                                    break;
                                IC++;
                                if (chan_stat(0, CHS_EOF))
                                    break;
                                IC++;
                                break;
                          case 4:                       /* TYP */
                                if (chan_stat(0, CHS_ERR))
                                    break;
                                IC++;
                                break;
                          case 2:                       /* UW */
                                if (chan_stat(0, CHS_ERR))
                                    break;
                                IC++;
                                if (lpr_chan9[0])
                                    break;
                                IC++;
                                break;
                          case 3:                       /* UWIV */
                                chan_stat(0, CHS_ERR);
                                break;
                          }
                      }
                done:
                      break;
                /* Tape channel channels */
                case OP_TAP1:
                case OP_TAP2:
                case OP_TAP3:
                case OP_TAP4:
                case OP_TAPP1:
                case OP_TAPP2:
                case OP_TAPP3:
                case OP_TAPP4:
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                      }
                     /* If pending IRQ, wait for it to be processed */
                      if ((pri_latchs[opcode & 0xf] >> f1) & 1) {
                            iowait = 1;
                            break;
                      }
                     /* If the channel is busy no need to continue */
                      if (chan_active(opcode & 0xf)) {
                            iowait = 1;
                            break;
                      }
                     /* Set up channel */
                      utmp = ((opcode & 0xf) << 8) + f1;
                      if ((opcode & 0x100) == 0)  /* Set priority signal */
                            utmp |= 0x1000;

                      tmp = 0;
                      switch (f2) {
                      case 0:
                          switch(MA % 10) {
                          case 0: tmp = (IO_TRS << 8);
                                  utmp &= 0xfff;
                                  break;                         /* TSEL */
                          case 1: tmp = (IO_WEF << 8); break; /* TM */
                          case 2: tmp = (IO_REW << 8);
                                  utmp &= 0xfff;
                                  break;                        /* TRW */
                          case 3: tmp = (IO_RUN << 8);
                                  utmp &= 0xfff;
                                  break;                        /* TRU */
                          case 4: tmp = (IO_BSR << 8);
                                  utmp &= 0xfff;
                                  break;                         /* TRB */
                          case 5: tmp = (IO_WRS << 8)|CHN_SEGMENT|CHN_ALPHA;
                                  break;                         /* TSM */
                          case 6: tmp = (IO_ERG << 8);
                                  utmp &= 0xfff;
                                  break;                         /* TSK */
                          case 7: chan_stat(opcode & 0xf, CHS_EOF);
                                  goto done;                     /* TEF */
                          case 8: tmp = (IO_SDL << 8);
                                  utmp &= 0xfff;
                                  break;                        /* TSDL */
                          case 9: tmp = (IO_SDH << 8);
                                  utmp &= 0xfff;
                                  break;                        /* TSDH */
                          }
                          break;
                      case 1:   tmp = (IO_RDS << 8);   break;   /* TR */
                      case 2:   tmp = (IO_RDS << 8)|CHN_RECORD;
                                                      break;    /* TRR */
                      case 3:   tmp = (IO_WRS << 8);   break;   /* TW */
                      case 4:   tmp = (IO_WRS << 8)|CHN_RECORD;
                                                      break;    /* TWR */
                      case 5:   tmp = (IO_WRS << 8)|CHN_COMPRESS;
                                                      break;    /* TWZ */
                      case 6:   tmp = (IO_WRS << 8)|CHN_COMPRESS|CHN_RECORD;
                                                      break;    /* TWC */
                      case 7:   tmp = (IO_RDS << 8)|CHN_SEGMENT|CHN_ALPHA;
                                                      break;    /* TSF */
                      case 8:   tmp = (IO_RDS << 8)|CHN_SEGMENT|CHN_RECORD|CHN_ALPHA;
                                                      break;    /* TSB */
                      case 9:   tmp = (IO_RDS << 8)|CHN_ALPHA;
                                                      break;    /* TRA */
                      }
                      MBR = ((utmp & 0x1000) ? PSIGN:MSIGN) | 0x8000000000LL |
                                (((t_uint64)f2)<<32);
                      upd_idx(&MBR, IC);
                      bin_dec(&MBR, MA, 0, 4);
                      f = (utmp >> 8) & 0xf;
                      WriteP(150 + (f * 10) + (utmp & 0xF), MBR);
                      /* Start off command */
                      switch(chan_cmd(utmp, tmp, MA)) {
                      case SCPE_BUSY:
                           iowait = 1;
                           break;
                      case SCPE_IOERR:
                           reason = STOP_IOCHECK;
                           break;
                      case SCPE_OK:
                          /* Not priority transfer, wait for channel done */
                          if ((utmp & 0x1000) == 0)
                              chwait = f;
                      }
                      break;

                /* Binary tape read channel 1 */
                case OP_TRN:
                case OP_TRNP:
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                      }
                     /* If pending IRQ, wait for it to be processed */
                      if ((pri_latchs[1] >> f1) & 1) {
                            iowait = 1;
                            break;
                      }
                     /* If the channel is busy no need to continue */
                      if (chan_active(1)) {
                            iowait = 1;
                            break;
                      }
                     /* Set up channel */
                      utmp = (1 << 8) + f1 + 020; /* Binary mode */
                      if ((opcode & 0x100) == 0)  /* Set priority signal */
                            utmp |= 0x1000;

                      switch (f2) {
                      case 1:   tmp = (IO_RDS << 8)|CHN_ALPHA; break;
                      default:  /* Anything else is error */
                                reason = STOP_UUO;
                                goto done;
                      }
                      MBR = ((utmp & 0x1000) ? PSIGN:MSIGN) | 0x8000000000LL |
                                (((t_uint64)f2)<<32);
                      upd_idx(&MBR, IC);
                      bin_dec(&MBR, MA, 0, 4);
                      f = (utmp >> 8) & 0xf;
                      WriteP(150 + (f * 10) + (utmp & 0xF), MBR);
                      /* Start off command */
                      switch(chan_cmd(utmp, tmp, MA)) {
                      case SCPE_BUSY:
                           iowait = 1;
                           break;
                      case SCPE_IOERR:
                           reason = STOP_IOCHECK;
                           break;
                      case SCPE_OK:
                          /* Not priority transfer, wait for channel done */
                          if ((utmp & 0x1000) == 0)
                              chwait = f;
                      }
                      break;

                case OP_CHNP1:
                case OP_CHNP2:
                case OP_CHNP3:
                case OP_CHNP4:
                case OP_CHN1:
                case OP_CHN2:
                case OP_CHN3:
                case OP_CHN4:
                     /* If the channel is busy no need to continue */
                      if (chan_active(opcode & 0xf)) {
                            iowait = 1;
                            break;
                      }
                      utmp = ((opcode & 0xf) << 8) + ((f1 & 3) - 1) + 0x200;
                      if ((opcode & 0x100) == 0)  /* Set priority signal */
                            utmp |= 0x1000;
                      /* Build initial status word */
                      MBR = ((t_uint64)opcode & 0xFF) << 32;
                      MBR |= (opcode & 0x100)?MSIGN:PSIGN;
                      upd_idx(&MBR, IC);
                      bin_dec(&MBR, MA, 0, 4);
                      tmp = 0xff;
                      switch (f2) {
                      case 1:   tmp = CHN_COMPRESS;           break; /* DCP */
                      case 2:   tmp = 0;                      break; /* DCUA */
                      case 3:   tmp = CHN_RECORD;             break; /* DCUR */
                      case 4:   tmp = CHN_RECORD|CHN_COMPRESS;break;/*DCPR*/
                      case 6:   tmp = CHN_NUM_MODE;        break; /* DCU */
                      }
                      if (tmp == 0xff)
                         break;
                      tmp |= IO_RDS << 8;       /* Activate channel */
                      /* Start off command */
                      switch(chan_cmd(utmp, tmp, MA)) {
                      case SCPE_BUSY:
                           iowait = 1;
                           break;
                      case SCPE_IOERR:
                           reason = STOP_IOCHECK;
                           break;
                      case SCPE_OK:
                           WriteP(350 + ((utmp >> 8) & 0xf) - 4, MBR);
                           break;
                      }
                      if (hst_lnt) {  /* history enabled? */
                          hst[hst_p].ic |= HIST_NOAFT|HIST_NOBEF;
                      }
                      break;

           /* Diagnostics instructions, not fully implimented */
           /* All of these errors can not occur on the simulation */
             case OP_DIAGT:
                      if (IX == 99) {
                        IX = 63;
                      } else if (IX == 98) {
                        IX = 63;
                        diaglatch |= 1LL << 63;
                        IC = MA;
                        break;
                      } else if (IX > 60) {
                        break;
                      }
                      if (diaglatch & (1LL << IX))
                        IC = MA;
                      diaglatch &= ~(1LL << IX);
                      break;
             case OP_DIAGR:
                      if (IX > 60)
                        break;
                      if (IX == 0)
                        diaglatch &= 1LL << 63;
                      else
                        diaglatch &= ~(1LL << IX);
                      break;
             case OP_DIAGC:
             case OP_DIAGS:
                      break;
             }


        }
        chan_proc();            /* process any pending channel events */
        if (instr_count != 0 && --instr_count == 0)
            return SCPE_STEP;
    }                           /* end while */

/* Simulation halted */

    return reason;
}

/* Decimal arithmetic routines */
/* Add a to b result in a */
int dec_add(t_uint64 *a, t_uint64 b) {
  t_uint64      t1,t2,t3;
  t1 = *a ^ b;
  t2 = *a + b;
  t3 = t2 + 0x6666666666LL;
  t2 = ((t2 < *a) || (t3 < t2));
  t2 = ((t1 ^ t3) >> 3) | (t2 << 37);
  t2 = 0x2222222222LL & ~t2;
  t1 = t3 - (3 * t2);
  if ((t1 & (~DMASK)) != 0) {
        t1 &= DMASK;
        *a = t1;
        return 1;
  }
  *a = t1;
  return 0;
}

/* Decimal arithmetic routines */
/* Add a to b result in a */
/* Don't detect overflow, and use 2 more guard digits */
void dec_add_noov(t_uint64 *a, t_uint64 b) {
  t_uint64      t1,t2,t3;
  t1 = *a ^ b;
  t2 = *a + b;
  t3 = t2 + 0x666666666666LL;
  t2 = ((t2 < *a) || (t3 < t2));
  t2 = ((t1 ^ t3) >> 3) | (t2 << 45);
  t2 = 0x222222222222LL & ~t2;
  t1 = t3 - (3 * t2);
  *a = t1;
}


/* tens compliment a */
void dec_comp(t_uint64 *a) {
  *a = 0x9999999999LL - *a;
  dec_add(a, 1LL);
}

/* Compare to words, includeing sign */
int dec_cmp(t_uint64 a, t_uint64 b) {
  t_uint64      t1,t2,t3;

  a = 0x99999999999LL - a;
  t1 = a ^ b;
  t2 = a + b;
  t3 = t2 + 0x66666666666LL;
  t2 = ((t2 < a) || (t3 < t2));
  t2 = ((t1 ^ t3) >> 3) | (t2 << 41);
  t2 = 0x22222222222LL & ~t2;
  t1 = t3 - (3 * t2);
  if (t1 == 0x99999999999LL) {
        return 0;
  }
  if ((t1 & ~(SMASK|DMASK)) != 0) {
        return 1;
  }
  return -1;
}

/* Do a multiply step */
void mul_step(t_uint64 *a, t_uint64 b, int c) {
  t_uint64      prod;
  int           i;

  for(i = 0; i < 40; i+=4) {
      /* Multiply each digit */
      prod = ((b >> i) & 0xf) * c;
      /* Convert to decimal */
      prod = ((prod / 10) << 4) + (prod % 10);
      if (prod != 0) {
          prod <<= i;   /* Move into place */
          dec_add_noov(a, prod);
      }
  }
}

void div_step(t_uint64 b) {
  t_uint64      t1,t2,t3;

  AC[1] &= DMASK;
  AC[1] <<= 4;
  AC[1] |= (AC[2] >> 36) & 0xf;
  AC[2] <<= 4;
  AC[2] &= DMASK;
/* Repeated subtract until overflow */
  while((AC[2] & 0xF) != 0x9) {
      t1 = AC[1] ^ b;
      t2 = AC[1] + b;
      t3 = t2 + 0x66666666666LL;
      t2 = ((t2 < AC[1]) || (t3 < t2));
      t2 = ((t1 ^ t3) >> 3) | (t2 << 41);
      t2 = 0x22222222222LL & ~t2;
      t1 = t3 - (3 * t2);
      if ((t1 & ~DMASK) == 0)
          return;
      AC[1] = t1 & DMASK;
      AC[2] += 1LL;
   }
}

/* Convert a binary number to BCD */
void bin_dec(t_uint64 *a, uint32 b, int s, int l) {
  s *= 4;
  l *= 4;
  l += s;
  while (s < l) {
      *a &= ~(0xFLL << s);
      *a |= ((t_uint64)(b % 10)) << s;
      b /= 10;
      s += 4;
   }
}

/* Convert index to binary */
uint32 dec_bin_idx(t_uint64 a) {
    uint32      v = (a >> 16) & 0xf;
    v += dscale[0][(a >> 20) & 0xf];
    v += dscale[1][(a >> 24) & 0xf];
    v += dscale[2][(a >> 28) & 0xf];
    if (emode)
        a += dscale[3][(a >> 32) & 0xf];
    return v;
}

uint32 dec_bin_lim(t_uint64 a, uint32 b) {
    uint32      v = a & 0xf;
    v += dscale[0][(a >> 4) & 0xf];
    v += dscale[1][(a >> 8) & 0xf];
    v += dscale[2][(a >> 12) & 0xf];
    if (emode) {
         if (v < b)
             v += dscale[3][((a >> 32) & 0xf)+1];
    }
    return v;
}

/* Extract information from a RDW */
int get_rdw(t_uint64 a, uint32 *base, uint32 *limit) {
    *base = dec_bin_idx(a);
    *limit = dec_bin_lim(a, *base);
    return (a >> 40);
}

void upd_idx(t_uint64 *a, uint32 b) {
    bin_dec(a, b, 4, (emode)?5:4);
}

/* Scan for interupt */
int scan_irq() {
    int irq = 0;
    int tmp;

    for(tmp = 0; tmp < 20 && irq == 0; tmp++) {
        if ((pri_mask & (1 << tmp)) == 0) {
           switch(tmp) {
           case 9:      /* Unit A */
                if (pri_latchs[0] & 0x002) {
                    pri_latchs[0] &= ~0x002;
                    irq = 104;
                }
                break;
           case 8:      /* Unit B */
                if (pri_latchs[0] & 0x004) {
                    pri_latchs[0] &= ~0x004;
                    irq = 105;
                }
                break;
           case 7:      /* Tape Chan 1 */
                if (pri_latchs[1]) {
                    int i;
                    for(i = 0; i < 10; i++) {
                        if (pri_latchs[1] & (1 << i)) {
                            pri_latchs[1] &= ~(1 << i);
                            irq = 150 + ((M[110+i] >> 36) & 0xf);
                            /* Save final record address */
                            upd_idx(&M[99], 110+i);
                            M[99] &= DMASK;
                            M[99] |= PSIGN;
                            break;
                        }
                    }
                }
                break;
           case 6:      /* Tape Chan 2 */
                if (pri_latchs[2]) {
                    int i;
                    for(i = 0; i < 10; i++) {
                        if (pri_latchs[2] & (1 << i)) {
                            pri_latchs[2] &= ~(1 << i);
                            irq = 150 + ((M[120+i] >> 36) & 0xf);
                            /* Save final record address */
                            upd_idx(&M[99], 120+i);
                            M[99] &= DMASK;
                            M[99] |= PSIGN;
                            break;
                        }
                    }
                }
                break;
           case 5:      /* 7300 disk seek */
                break;  /* Not implimented */
           case 4:      /* 7300 disk read and write */
                break;  /* Not implimented */
           case 3:      /* Inquiry group 1 */
                if (pri_latchs[0] & 0x080) {
                    pri_latchs[0] &= ~0x080;
                    irq = 106;
                }
                break;
           case 2:      /* Inquiry group 2 */
                if (pri_latchs[0] & 0x100) {
                    pri_latchs[0] &= ~0x100;
                    irq = 107;
                }
                break;
           case 1:      /* Tape Chan 3 */
                if (pri_latchs[3]) {
                    int i;
                    for(i = 0; i < 10; i++) {
                        if (pri_latchs[3] & (1 << i)) {
                            pri_latchs[3] &= ~(1 << i);
                            irq = 150 + ((M[130+i] >> 36) & 0xf);
                            /* Save final record address */
                            upd_idx(&M[99], 130+i);
                            M[99] &= DMASK;
                            M[99] |= PSIGN;
                            break;
                        }
                    }
                }
                break;
           case 0:      /* Tape Chan 4 */
                if (pri_latchs[4]) {
                    int i;
                    for(i = 0; i < 10; i++) {
                        if (pri_latchs[4] & (1 << i)) {
                            pri_latchs[4] &= ~(1 << i);
                            irq = 150 + ((M[140+i] >> 36) & 0xf);
                            /* Save final record address */
                            upd_idx(&M[99], 140+i);
                            M[99] &= DMASK;
                            M[99] |= PSIGN;
                            break;
                        }
                    }
                }
                break;
           case 10:     /* Channel 1 */
                if (pri_latchs[8] & 0x002) {
                    pri_latchs[8] &= ~0x002;
                    irq = 311;
                    upd_idx(&M[99], 301);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 11:     /* Channel 1 Attn */
                if (pri_latchs[9] & 0x002) {
                    pri_latchs[9] &= ~0x002;
                    irq = 321;
                    upd_idx(&M[99], 301);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 12:     /* Channel 2 */
                if (pri_latchs[8] & 0x004) {
                    pri_latchs[8] &= ~0x004;
                    irq = 312;
                    upd_idx(&M[99], 302);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 13:     /* Channel 2 Attn */
                if (pri_latchs[9] & 0x004) {
                    pri_latchs[9] &= ~0x004;
                    irq = 322;
                    upd_idx(&M[99], 302);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 14:     /* Channel 3 */
                if (pri_latchs[8] & 0x008) {
                    pri_latchs[8] &= ~0x008;
                    irq = 313;
                    upd_idx(&M[99], 303);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 15:     /* Channel 3 Attn */
                if (pri_latchs[9] & 0x008) {
                    pri_latchs[9] &= ~0x008;
                    irq = 323;
                    upd_idx(&M[99], 303);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 16:     /* Channel 4 */
                if (pri_latchs[8] & 0x010) {
                    pri_latchs[8] &= ~0x010;
                    irq = 314;
                    upd_idx(&M[99], 304);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           case 17:     /* Channel 4 Attn */
                if (pri_latchs[9] & 0x010) {
                    pri_latchs[9] &= ~0x010;
                    irq = 324;
                    upd_idx(&M[99], 304);
                    M[99] &= DMASK;
                    M[99] |= PSIGN;
                }
                break;
           }
        }
    }
    return irq;
}


/* Initialize memory to all plus zero */
void
mem_init() {
    int                 i;
    /* Force memory to have all valid signs */
    for(i = 0; i < MAXMEMSIZE; i++)
        M[i] = PSIGN;
}


/* Reset routine */
t_stat
cpu_reset(DEVICE * dptr)
{
    static int  initialized = 0;

    if (initialized == 0) {
        initialized = 1;
        mem_init();
    }

    AC[1] = PSIGN;
    AC[2] = PSIGN;
    AC[3] = PSIGN;
    inds = PSIGN;
    pri_enb = 1;
    sim_brk_types = sim_brk_dflt = SWMASK('E');
    if (cpu_unit.flags & OPTION_TIMER) {
        sim_rtcn_init_unit (&cpu_unit, cpu_unit.wait, TMR_RTC);
        sim_activate(&cpu_unit, cpu_unit.wait);
    }
    return SCPE_OK;
}

/* Interval timer routines */
t_stat
rtc_srv(UNIT * uptr)
{
    if (cpu_unit.flags & OPTION_TIMER) {
        timer_clock++;
        if (timer_clock == 300) {
            t_uint64    t = (t_uint64) timer;
            dec_add(&t, 1);
            timer = t & 0xfff;
            timer_clock = 0;
        }
        sim_activate(&cpu_unit, sim_rtcn_calb(uptr->wait, TMR_RTC));
    }
    return SCPE_OK;
}

t_stat
rtc_reset(DEVICE * dptr)
{
    if (cpu_unit.flags & OPTION_TIMER) {
        sim_activate(&cpu_unit, cpu_unit.wait);
    }
    return SCPE_OK;
}

/* Memory examine */

t_stat
cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw)
{
    if (addr > MEMSIZE)
        return SCPE_NXM;
    if (vptr != NULL)
        *vptr = M[addr];

    return SCPE_OK;
}

/* Memory deposit */

t_stat
cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw)
{
    if (addr > MEMSIZE)
        return SCPE_NXM;
    M[addr] = val;
    return SCPE_OK;
}

t_stat
cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
    t_uint64            mc = 0;
    uint32              i;
    int32               v;

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

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

    if (cptr == NULL) {
        for (i = 0; i < hst_lnt; i++)
            hst[i].ic = 0;
        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;
    char               *cptr = (char *) desc;
    t_stat              r;
    t_value             sim_eval;
    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, "IC    EA    BEFORE      AFTER       INST\n\n");
    for (k = 0; k < lnt; k++) { /* print specified */
        h = &hst[(++di) % hst_lnt];     /* entry pointer */
        if (h->ic & HIST_PC) {  /* instruction? */
            fprintf(st, "%05d ", h->ic & 0xffff);
            if (h->ic & HIST_NOEA)
                fputs("       ", st);
            else
                fprintf(st, " %05d ", h->ea);
            if (h->ic & HIST_NOBEF)
                fputs("           ", st);
            else {
                switch (h->before & SMASK) {
                case PSIGN: fputc('+', st); break;
                case MSIGN: fputc('-', st); break;
                case ASIGN: fputc('@', st); break;
                default: fputc('#', st); break;
                }
                fprint_val(st, h->before & DMASK, 16, 40, PV_RZRO);
            }
            fputc(' ', st);
            if (h->ic & HIST_NOAFT)
                fputs("           ", st);
            else {
                switch (h->after & SMASK) {
                case PSIGN: fputc('+', st); break;
                case MSIGN: fputc('-', st); break;
                case ASIGN: fputc('@', st); break;
                default: fputc('#', st); break;
                }
                fprint_val(st, h->after & DMASK, 16, 40, PV_RZRO);
            }
            fputc(' ', st);
            sim_eval = h->op;
            if (
                (fprint_sym(st, h->ic & AMASK, &sim_eval, &cpu_unit,
                  SWMASK('M'))) > 0) fputs("(undefined)", st);
            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, "The CPU can be set to a IBM 7070 or IBM 7074\n");
    fprintf (st, "The type of CPU can be set by one of the following commands\n\n");
    fprintf (st, "   sim> set CPU 7070        sets IBM 7070 emulation\n");
    fprintf (st, "   sim> set CPU 7074        sets IBM 7074 emulation\n\n");
    fprintf (st, "These switches are recognized when examining or depositing in CPU memory:\n\n");
    fprintf (st, "      -c      examine/deposit characters, 5 per word\n");
    fprintf (st, "      -m      examine/deposit IBM 7070 instructions\n\n");
    fprintf (st, "The memory of the CPU can be set in 5K incrememts from 5K to 30K with the\n\n");
    fprintf (st, "   sim> SET CPU xK\n\n");
    fprintf (st, "For the IBM 7070 the following options can be enabled\n\n");
    fprintf (st, "   sim> SET CPU FLOAT     enables Floating Point\n");
    fprintf (st, "   sim> SET CPU NOFLOAT   disables Floating Point\n\n");
    fprintf (st, "   sim> SET CPU EXTEND      enables extended memory\n");
    fprintf (st, "   sim> SET CPU NOEXTEND    disables extended memory\n\n");
    fprintf (st, "   sim> SET CPU CLOCK      enables timer clock\n");
    fprintf (st, "   sim> SET CPU NOCLOCK    disables timer clock\n\n");
    fprintf (st, "The CPU can maintain a history of the most recently executed instructions.\n");
    fprintf (st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n");
    fprintf (st, "   sim> SET CPU HISTORY                 clear history buffer\n");
    fprintf (st, "   sim> SET CPU HISTORY=0               disable history\n");
    fprintf (st, "   sim> SET CPU HISTORY=n{:file}        enable history, length = n\n");
    fprintf (st, "   sim> SHOW CPU HISTORY                print CPU history\n");
    fprint_set_help(st, dptr);
    fprint_show_help(st, dptr);
    return SCPE_OK;
}

const char *
cpu_description (DEVICE *dptr) {
    return "IBM 7070 CPU";
}

