/* id32_cpu.c: Interdata 32b CPU simulator

   Copyright (c) 2000-2004, Robert M. Supnik

   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
   ROBERT M SUPNIK 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.

   Except as contained in this notice, the name of Robert M Supnik shall not
   be used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   cpu			Interdata 32b CPU

   25-Jan-04	RMS	Revised for device debug support
   31-Dec-03	RMS	Fixed bug in cpu_set_hist
   22-Sep-03	RMS	Added additional instruction decode types
			Added instruction history

   The register state for an Interdata 32b CPU is:

   REG[0:F][2]<0:31>	general register sets
   F[0:7]<0:31>		single precision floating point registers
   D[0:7]<0:63>		double precision floating point registers
   PSW<0:63>		processor status word, including
    STAT<0:11>		status flags
    CC<0:3>		condition codes
    PC<0:31>		program counter
   int_req[n]<0:31>	interrupt requests
   int_enb[n]<0:31>	interrupt enables
   
   The Interdata 32b systems have seven instruction formats: register to
   register, short format, register and memory (three formats), and register
   and immediate (two formats).  The formats are:

     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     R2    |	register-register
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     N     |	short format
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     RX    |	register-memory 1
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+	(absolute 14b)
   | 0| 0|              address                    |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     RX    |	register-memory 2
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+	(relative)
   | 1|                 address                    |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     RX    |	register-memory 3
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+	(double index)
   | 0| 1| 0| 0|    RX2    |       address hi      |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |                   address lo                  |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     RX    |	register-immediate 1
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |                   immediate                   |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |           op          |     R1    |     RX    |	register-immediate 2
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |                  immediate hi                 |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   |                  immediate lo                 |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   For register-memory 1 and register-immediate 1 and 2 an instructions, an
   effective address is calculated as follows:

	effective addr = address + RX (if RX > 0)

   For register-memory 2, an effective address is calculated as follows:

	effective addr = address + PC + RX (if RX > 0)

   For register-memory 3, an effective address is calculated as follows:

	effective addr = address + RX (if RX > 0) + RX2 (if RX2 > 0)

   Register-memory instructions can access an address space of 16M bytes.
*/

/* This routine is the instruction decode routine for the Interdata CPU.
   It is called from the simulator control program to execute
   instructions in simulated memory, starting at the simulated PC.
   It runs until 'reason' is set non-zero.

   General notes:

   1. Reasons to stop.  The simulator can be stopped by:

	HALT instruction
	breakpoint encountered
	wait state and no I/O outstanding
	invalid instruction
	I/O error in I/O simulator

   2. Interrupts.  Each device has an interrupt armed flag, an interrupt
      request flag, and an interrupt enabled flag.  To facilitate evaluation,
      all interrupt requests are kept in int_req, and all enables in int_enb.
      Interrupt armed flags are local to devices.  If external interrupts are
      enabled in the PSW, and a request is pending, an interrupt occurs.

   3. Non-existent memory.  On the Interdata 32b, reads to non-existent
      memory return zero, and writes are ignored.  In the simulator, the
      largest possible memory is instantiated and initialized to zero.
      Thus, only writes need be checked against actual memory size.

   4. Adding I/O devices.  These modules must be modified:

	id_defs.h	add device interrupt definitions
	id32_sys.c	add sim_devices table entry
*/

#include "id_defs.h"
#include <setjmp.h>

#define PCQ_SIZE	64				/* must be 2**n */
#define PCQ_MASK	(PCQ_SIZE - 1)
#define PCQ_ENTRY	pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = oPC
#define VAMASK		VAMASK32
#define NRSETS		2				/* 2 gen reg sets */
#define PSW_MASK	PSW_x32
#define ABORT(val)	longjmp (save_env, (val))
#define MPRO		(-1)

#define UNIT_V_MSIZE	(UNIT_V_UF + 0)			/* dummy mask */
#define UNIT_V_DPFP	(UNIT_V_UF + 1)
#define UNIT_V_832	(UNIT_V_UF + 2)
#define UNIT_MSIZE	(1 << UNIT_V_MSIZE)
#define UNIT_DPFP	(1 << UNIT_V_DPFP)
#define UNIT_832	(1 << UNIT_V_832)
#define UNIT_TYPE	(UNIT_DPFP | UNIT_832)

#define HIST_PC		0x40000000
#define HIST_MIN	64
#define HIST_MAX	65536
struct InstHistory {
	uint32		pc;
	uint32		ir1;
	uint32		ir2;
	uint32		ir3;
	uint32		r1;
	uint32		ea;
	uint32		opnd; };

#define SEXT32(x)	(((x) & SIGN32)? ((int32) ((x) | ~0x7FFFFFFF)): \
			((int32) ((x) & 0x7FFFFFFF)))
#define SEXT16(x)	(((x) & SIGN16)? ((int32) ((x) | ~0x7FFF)): \
			((int32) ((x) & 0x7FFF)))
#define SEXT15(x)	(((x) & 0x4000)? ((int32) ((x) | ~0x3FFF)): \
			((int32) ((x) & 0x3FFF)))
#define CC_GL_16(x)	if ((x) & SIGN16) cc = CC_L; \
			else if (x) cc = CC_G; \
			else cc = 0
#define CC_GL_32(x)	if ((x) & SIGN32) cc = CC_L; \
			else if (x) cc = CC_G; \
			else cc = 0
#define BUILD_PSW(x)	(((PSW & ~CC_MASK) | (x)) & PSW_MASK)
#define NEG(x)		((~(x) + 1) & DMASK32)
#define ABS(x)		(((x) & SIGN32)? NEG (x): (x))
#define DNEG(x,y)	y = NEG (y); \
			x = (~(x) + (y == 0)) & DMASK32

/* Logging */

#define LOG_CPU_I	0x0001				/* intr/exception */
#define LOG_CPU_C	0x0002				/* context change */

uint32 GREG[16 * NRSETS] = { 0 };			/* general registers */
uint32 *M = NULL;					/* memory */
uint32 *R = &GREG[0];					/* working reg set */
uint32 F[8] = { 0 };					/* sp fp registers */
dpr_t D[8] = { 0 };					/* dp fp registers */
uint32 PSW = 0;						/* processor status word */
uint32 PC = 0;						/* program counter */
uint32 oPC = 0;						/* PC at inst start */
uint32 SR = 0;						/* switch register */
uint32 DR = 0;						/* display register */
uint32 DRX = 0;						/* display extension */
uint32 drmod = 0;					/* mode */
uint32 srpos = 0;					/* switch register pos */
uint32 drpos = 0;					/* display register pos */
uint32 mac_reg[MAC_LNT] = { 0 };			/* mac registers */
uint32 mac_sta = 0;					/* mac status */
uint32 int_req[INTSZ] = { 0 };				/* interrupt requests */
uint32 int_enb[INTSZ] = { 0 };				/* interrupt enables */
uint32 qevent = 0;					/* events */
uint32 stop_inst = 0;					/* stop on ill inst */
uint32 stop_wait = 0;					/* stop on wait */
uint32 pcq[PCQ_SIZE] = { 0 };				/* PC queue */
int32 pcq_p = 0;					/* PC queue ptr */
REG *pcq_r = NULL;					/* PC queue reg ptr */
uint32 dec_flgs = 0;					/* decode flags */
uint32 fp_in_hwre = 0;					/* ucode vs hwre fp */
uint32 pawidth = PAWIDTH32;				/* addr mask */
uint32 hst_p = 0;					/* history pointer */
uint32 hst_lnt = 0;					/* history length */
struct InstHistory *hst = NULL;				/* instruction history */
jmp_buf save_env;					/* abort handler */
struct BlockIO blk_io;					/* block I/O status */
uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };

extern int32 sim_interval;
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ;	/* breakpoint info */
extern UNIT pic_unit, lfc_unit, pas_unit;		/* timers */
extern FILE *sim_deb;

uint32 ReadB (uint32 loc, uint32 rel);
uint32 ReadH (uint32 loc, uint32 rel);
void WriteB (uint32 loc, uint32 val, uint32 rel);
void WriteH (uint32 loc, uint32 val, uint32 rel);
uint32 RelocT (uint32 va, uint32 base, uint32 rel, uint32 *pa);
uint32 int_auto (uint32 dev, uint32 cc);
uint32 addtoq (uint32 ea, uint32 val, uint32 flg);
uint32 remfmq (uint32 ea, uint32 r1, uint32 flg);
uint32 exception (uint32 loc, uint32 cc, uint32 flg);
uint32 newPSW (uint32 val);
uint32 testsysq (uint32 cc);
uint32 display (uint32 dev, uint32 op, uint32 dat);
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, char *cptr, void *desc);
t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
void set_r_display (uint32 *rbase);

extern t_bool devtab_init (void);
extern void int_eval (void);
extern uint32 int_getdev (void);
extern void sch_cycle (uint32 ch);
extern t_bool sch_blk (uint32 dev);
extern uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_fix32 (uint32 op, uint32 r1, uint32 r2);
extern uint32 f_flt32 (uint32 op, uint32 r1, uint32 r2);

/* Instruction decoding table */

const uint16 decrom[256] = {
	0,				/* 00 */
	OP_RR,				/* BALR */
	OP_RR, 				/* BTCR */
	OP_RR,				/* BFCR */
	OP_RR,				/* NR */
	OP_RR,				/* CLR */
	OP_RR,				/* OR */
	OP_RR,				/* XR */
	OP_RR,				/* LR */
	OP_RR,				/* CR */
	OP_RR,				/* AR */
	OP_RR,				/* SR */
	OP_RR,				/* MHR */
	OP_RR,				/* DHR */
	0, 0,				/* 0E:0F */
	OP_NO,				/* SRLS */
	OP_NO,				/* SLLS */
	OP_RR,				/* CHVR */
	0, 0, 0, 0, 0,			/* 13:17 */
	OP_RR | OP_PRV,			/* LPSWR */
	0, 0, 0,			/* 19:1B */
	OP_RR,				/* MR */
	OP_RR,				/* DR */
	0, 0,				/* 1E:1F */
	OP_NO,				/* BTBS */
	OP_NO,				/* BTFS */
	OP_NO,				/* BFBS */
	OP_NO, 				/* BFFS */
	OP_NO,				/* LIS */
	OP_NO,				/* LCS */
	OP_NO,				/* AIS */
	OP_NO,				/* SIS */
	OP_NO,				/* LER */
	OP_NO,				/* CER */
	OP_NO,				/* AER */
	OP_NO,				/* SER */
	OP_NO,				/* MER */
	OP_NO,				/* DER */
	OP_NO,				/* FXR */
	OP_NO,				/* FLR */
	0,				/* MPBSR - 8/32C */
	0,				/* 31 */
	0,				/* PBR - 8/32C */
	0,				/* 33 */
	OP_RR,				/* EXHR */
	0, 0, 0,			/* 35:37 */
	OP_NO | OP_DPF,			/* LDR */
	OP_NO | OP_DPF,			/* CDR */
	OP_NO | OP_DPF,			/* ADR */
	OP_NO | OP_DPF,			/* SDR */
	OP_NO | OP_DPF,			/* MDR */
	OP_NO | OP_DPF,			/* DDR */
	OP_NO | OP_DPF,			/* FXDR */
	OP_NO | OP_DPF,			/* FLDR */
	OP_RX,				/* STH */
	OP_RX,				/* BAL */
	OP_RX,				/* BTC */
	OP_RX,				/* BFC */
	OP_RXH,				/* NH */
	OP_RXH,				/* CLH */
	OP_RXH,				/* OH */
	OP_RXH,				/* XH */
	OP_RXH,				/* LH */
	OP_RXH,				/* CH */
	OP_RXH,				/* AH */
	OP_RXH,				/* SH */
	OP_RXH,				/* MH */
	OP_RXH,				/* DH */
	0, 0,				/* 4E:4F */
	OP_RX,				/* ST */
	OP_RXF,				/* AM */
	0, 0,				/* 52:53 */
	OP_RXF,				/* N */
	OP_RXF,				/* CL */
	OP_RXF,				/* O */
	OP_RXF,				/* X */
	OP_RXF,				/* L */
	OP_RXF,				/* C */
	OP_RXF,				/* A */
	OP_RXF,				/* S */
	OP_RXF,				/* M */
	OP_RXF,				/* D */
	OP_RXH,				/* CRC12 */
	OP_RXH,				/* CRC16 */
	OP_RX,				/* STE */
	OP_RXH,				/* AHM */
	0,				/* PB - 8/32C */
	OP_RX,				/* LRA */
	OP_RX,				/* ATL */
	OP_RX,				/* ABL */
	OP_RX,				/* RTL */
	OP_RX,				/* RBL */
	OP_RX,				/* LE */
	OP_RX,				/* CE */
	OP_RX,				/* AE */
	OP_RX,				/* SE */
	OP_RX,				/* ME */
	OP_RX,				/* DE */
	0, 0,				/* 6E:6F */
	OP_RX | OP_DPF,			/* STD */
	OP_RX,				/* SME */
	OP_RX,				/* LME */
	OP_RXH,				/* LHL */
	OP_RX,				/* TBT */
	OP_RX,				/* SBT */
	OP_RX,				/* RBT */
	OP_RX,				/* CBT */
	OP_RX | OP_DPF,			/* LD */
	OP_RX | OP_DPF,			/* CD */
	OP_RX | OP_DPF,			/* AD */
	OP_RX | OP_DPF,			/* SD */
	OP_RX | OP_DPF,			/* MD */
	OP_RX | OP_DPF,			/* DD */
	OP_RX | OP_DPF,			/* STMD */
	OP_RX | OP_DPF,			/* LMD */
	0, 0, 0, 0, 0, 0, 0, 0,		/* 80:8F */
	0, 0, 0, 0, 0, 0, 0, 0,
	OP_NO,				/* SRHLS */
	OP_NO,				/* SLHLS */
	OP_NO,				/* STBR */
	OP_RR,				/* LDBR */
	OP_RR,				/* EXBR */
	OP_NO | OP_PRV,			/* EPSR */
	OP_RR | OP_PRV,			/* WBR */
	OP_RR | OP_PRV,			/* RBR */
	OP_RR | OP_PRV,			/* WHR */
	OP_RR | OP_PRV,			/* RHR */
	OP_RR | OP_PRV,			/* WDR */
	OP_RR | OP_PRV,			/* RDR */
	0,				/* 9C */
	OP_RR | OP_PRV,			/* SSR */
	OP_RR | OP_PRV,			/* OCR */
	0,				/* 9F */
	0, 0, 0, 0, 0, 0, 0, 0,		/* A0:AF */
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,		/* B0:BF */
	0, 0, 0, 0, 0, 0, 0, 0,
	OP_RX,				/* BXH */
	OP_RX,				/* BXLE */
	OP_RXF | OP_PRV,		/* LPSW */
	OP_RI1,				/* THI */
	OP_RI1,				/* NHI */
	OP_RI1,				/* CLHI */
	OP_RI1,				/* OHI */
	OP_RI1,				/* XHI */
	OP_RI1,				/* LHI */
	OP_RI1,				/* CHI */
	OP_RI1,				/* AHI */
	OP_RI1,				/* SHI */
	OP_RI1,				/* SRHL */
	OP_RI1,				/* SLHL */
	OP_RI1,				/* SRHA */
	OP_RI1,				/* SLHA */
	OP_RX,				/* STM */
	OP_RX,				/* LM */
	OP_RX,				/* STB */
	OP_RXB,				/* LDB */
	OP_RXB,				/* CLB */
	OP_RX | OP_PRV,			/* AL */
	OP_RXF | OP_PRV,		/* WB */
	OP_RXF | OP_PRV,		/* RB */
	OP_RX | OP_PRV,			/* WH */
	OP_RX | OP_PRV,			/* RH */
	OP_RX | OP_PRV,			/* WD */
	OP_RX | OP_PRV,			/* RD */
	0,				/* DC */
	OP_RX | OP_PRV,			/* SS */
	OP_RX | OP_PRV,			/* OC */
	0,				/* DF */
	OP_RXH,				/* TS */
	OP_RX,				/* SVC */
	OP_RI1 | OP_PRV,		/* SINT */
	OP_RXH | OP_PRV,		/* SCP */
	0, 0,				/* E4:E5 */
	OP_RX,				/* LA */
	OP_RXF,				/* TLATE */
	0, 0,				/* E8:E9 */
	OP_RI1,				/* RRL */
	OP_RI1,				/* RLL */
	OP_RI1,				/* SRL */
	OP_RI1,				/* SLL */
	OP_RI1,				/* SRA */
	OP_RI1,				/* SLA */
	0, 0, 0,			/* F0:F2 */
	OP_RI2,				/* TI */
	OP_RI2,				/* NI */
	OP_RI2,				/* CLI */
	OP_RI2,				/* OI */
	OP_RI2,				/* XI */
	OP_RI2,				/* LI */
	OP_RI2,				/* CI */
	OP_RI2,				/* AI */
	OP_RI2,				/* SI */
	0, 0, 0, 0 };			/* FC:FF */

/* CPU data structures

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

DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display };

UNIT cpu_unit = { UDATA (NULL, UNIT_FIX | UNIT_BINK, MAXMEMSIZE32) };

REG cpu_reg[] = {
	{ HRDATA (PC, PC, 20) },
	{ HRDATA (OPC, oPC, 20), REG_HRO },
	{ HRDATA (R0, GREG[0], 32) },
	{ HRDATA (R1, GREG[1], 32) },
	{ HRDATA (R2, GREG[2], 32) },
	{ HRDATA (R3, GREG[3], 32) },
	{ HRDATA (R4, GREG[4], 32) },
	{ HRDATA (R5, GREG[5], 32) },
	{ HRDATA (R6, GREG[6], 32) },
	{ HRDATA (R7, GREG[7], 32) },
	{ HRDATA (R8, GREG[8], 32) },
	{ HRDATA (R9, GREG[9], 32) },
	{ HRDATA (R10, GREG[10], 32) },
	{ HRDATA (R11, GREG[11], 32) },
	{ HRDATA (R12, GREG[12], 32) },
	{ HRDATA (R13, GREG[13], 32) },
	{ HRDATA (R14, GREG[14], 32) },
	{ HRDATA (R15, GREG[15], 32) },
	{ HRDATA (FR0, F[0], 32) },
	{ HRDATA (FR2, F[1], 32) },
	{ HRDATA (FR4, F[2], 32) },
	{ HRDATA (FR6, F[3], 32) },
	{ HRDATA (FR8, F[4], 32) },
	{ HRDATA (FR10, F[5], 32) },
	{ HRDATA (FR12, F[6], 32) },
	{ HRDATA (FR14, F[7], 32) },
	{ HRDATA (D0H, D[0].h, 32) },
	{ HRDATA (D0L, D[0].l, 32) },
	{ HRDATA (D2H, D[1].h, 32) },
	{ HRDATA (D2L, D[1].l, 32) },
	{ HRDATA (D4H, D[2].h, 32) },
	{ HRDATA (D4L, D[2].l, 32) },
	{ HRDATA (D6H, D[3].h, 32) },
	{ HRDATA (D6L, D[3].l, 32) },
	{ HRDATA (D8H, D[4].h, 32) },
	{ HRDATA (D8L, D[4].l, 32) },
	{ HRDATA (D10H, D[5].h, 32) },
	{ HRDATA (D10L, D[5].l, 32) },
	{ HRDATA (D12L, D[6].l, 32) },
	{ HRDATA (D12H, D[6].h, 32) },
	{ HRDATA (D14H, D[7].h, 32) },
	{ HRDATA (D14L, D[7].l, 32) },
	{ HRDATA (PSW, PSW, 16) },
	{ HRDATA (CC, PSW, 4) },
	{ HRDATA (SR, SR, 32) },
	{ HRDATA (DR, DR, 32) },
	{ HRDATA (DRX, DRX, 8) },
	{ FLDATA (DRMOD, drmod, 0) },
	{ FLDATA (SRPOS, srpos, 0) },
	{ HRDATA (DRPOS, drpos, 3) },
	{ BRDATA (IRQ, int_req, 16, 32, INTSZ) },
	{ BRDATA (IEN, int_enb, 16, 32, INTSZ) },
	{ BRDATA (MACREG, mac_reg, 16, 32, MAC_LNT) },
	{ HRDATA (MACSTA, mac_sta, 5) },
	{ HRDATA (QEVENT, qevent, 4), REG_HRO },
	{ FLDATA (STOP_INST, stop_inst, 0) },
	{ FLDATA (STOP_WAIT, stop_wait, 0) },
	{ BRDATA (PCQ, pcq, 16, 20, PCQ_SIZE), REG_RO+REG_CIRC },
	{ HRDATA (PCQP, pcq_p, 6), REG_HRO },
	{ HRDATA (WRU, sim_int_char, 8) },
	{ HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO },
	{ HRDATA (BLKIOC, blk_io.cur, 20), REG_HRO },
	{ HRDATA (BLKIOE, blk_io.end, 20), REG_HRO },
	{ BRDATA (GREG, GREG, 16, 32, 16 * NRSETS) },
	{ NULL }  };

MTAB cpu_mod[] = {
	{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
	{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
	{ UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size },
	{ UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size },
	{ UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size },
	{ UNIT_TYPE, 0, "7/32, single precision fp", "732", NULL },
	{ UNIT_DPFP, UNIT_DPFP, NULL, "DPFP", NULL },
	{ UNIT_TYPE, UNIT_DPFP, "7/32, double precision fp", NULL, NULL },
	{ UNIT_TYPE, UNIT_DPFP | UNIT_832, "8/32", "832", NULL },
	{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
		&cpu_set_consint, NULL, NULL },
	{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY",
	  &cpu_set_hist, &cpu_show_hist },
	{ 0 }  };

DEBTAB cpu_deb[] = {
	{ "INTEXC", LOG_CPU_I },
	{ "CONTEXT", LOG_CPU_C },
	{ NULL, 0 }  };

DEVICE cpu_dev = {
	"CPU", &cpu_unit, cpu_reg, cpu_mod,
	1, 16, 20, 1, 16, 8,
	&cpu_ex, &cpu_dep, &cpu_reset,
	NULL, NULL, NULL,
	&cpu_dib, DEV_DEBUG, 0,
	cpu_deb, NULL, NULL };

t_stat sim_instr (void)
{
volatile uint32 cc;					/* set before setjmp */
t_stat reason;						/* set after setjmp */
int abortval;

/* Restore register state */

if (devtab_init ()) return SCPE_STOP;			/* check conflicts */
if (cpu_unit.flags & (UNIT_DPFP | UNIT_832)) {
	fp_in_hwre = 1;					/* fp in hwre */
	dec_flgs = 0;  }				/* all instr ok */
else {	fp_in_hwre = 0;					/* fp in ucode */
	dec_flgs = OP_DPF;  }				/* sp only */
int_eval ();						/* eval interrupts */
cc = newPSW (PSW & PSW_MASK);				/* split PSW, eval wait */
sim_rtcn_init (lfc_unit.wait, TMR_LFC);			/* init clock */
sim_rtcn_init (pic_unit.wait, TMR_PIC);			/* init timer */
sim_rtcn_init (pas_unit.wait, TMR_PAS);			/* init pas */
reason = 0;

/* Abort handling

   If an abort occurs in memory protection, the relocation routine
   executes a longjmp to this area OUTSIDE the main simulation loop.
   Memory protection errors are the only sources of aborts in the
   Interdata 32b systems.  All referenced variables must be globals,
   and all sim_instr scoped automatic variables must be volatile or
   set after the call on setjmp.
*/

abortval = setjmp (save_env);				/* set abort hdlr */
if (abortval != 0) {					/* mem mgt abort? */
	qevent = qevent | EV_MAC;			/* set MAC intr */
	if (cpu_unit.flags & UNIT_832) PC = oPC;  }	/* 832? restore PC */

/* Event handling */

while (reason == 0) {					/* loop until halted */
uint32 dev, drom, opnd, inc, lim, bufa;
uint32 op, r1, r1p1, r2, rx2, ea;
uint32 mpy, mpc, dvr;
uint32 i, rslt, rlo, t;
uint32 ir1, ir2, ir3, ityp;
int32 sr, st;

if (sim_interval <= 0) {				/* check clock queue */
	if (reason = sim_process_event ()) break;
	int_eval ();  }

if (qevent) {						/* any events? */
	if (qevent & EV_MAC) {				/* MAC interrupt? */
	    qevent = 0;					/* clr all events */
	    cc = exception (MPRPSW, cc, 0);		/* take exception */
	    int_eval ();				/* re-eval intr */
	    continue;  }

	if (qevent & EV_BLK) {				/* block I/O in prog? */
	    dev = blk_io.dfl & DEV_MAX;			/* get device */
	    cc = dev_tab[dev] (dev, IO_SS, 0) & 0xF;	/* sense status */
	    if (cc == STA_BSY) {			/* just busy? */
		sim_interval = 0;			/* force I/O event */
		continue;  }
	    else if (cc == 0) {				/* ready, no err? */
		if (blk_io.dfl & BL_RD) {		/* read? */
		    t = dev_tab[dev] (dev, IO_RD, 0);	/* get byte */
		    if ((t == 0) && (blk_io.dfl & BL_LZ)) continue;
		    blk_io.dfl = blk_io.dfl & ~BL_LZ;	/* non-zero seen */
		    WriteB (blk_io.cur, t, VW);  }	/* write mem */
		else {					/* write */
		    t = ReadB (blk_io.cur, VR);		/* read mem */
		    dev_tab[dev] (dev, IO_WD, t);  }	/* put byte */
		if (blk_io.cur != blk_io.end) {		/* more to do? */
	            blk_io.cur = (blk_io.cur + 1) & VAMASK;	/* incr addr */
		    continue;  }  }
	    qevent = qevent & ~EV_BLK;			/* clr blk I/O flag */
	    int_eval ();				/* re-eval intr */
	    continue;  }

	if ((qevent & EV_INT) && (PSW & PSW_EXI)) {	/* interrupt? */
	    dev = int_getdev ();			/* get int dev */
	    cc = int_auto (dev, cc);			/* do auto intr */
	    int_eval ();				/* re-eval intr */
	    continue;  }

	if (PSW & PSW_WAIT) {				/* wait state? */
	    t = sim_qcount ();				/* events in queue */
	    if ((t == 0) || ((t == 1) && stop_wait))	/* empty, or kbd only? */
		reason = STOP_WAIT;			/* then stop */
	    else sim_interval = 0;			/* force check */
	    continue;  }

	qevent = 0;  }					/* no events */

/* Instruction fetch and decode */

if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) {	/* breakpoint? */
	reason = STOP_IBKPT;				/* stop simulation */
	break;  }

sim_interval = sim_interval - 1;

ir1 = ReadH (oPC = PC, VE);				/* fetch instr */
op = (ir1 >> 8) & 0xFF;					/* extract op,R1,R2 */
r1 = (ir1 >> 4) & 0xF;
r2 = ir1 & 0xF;
drom = decrom[op];					/* get decode flags */
ityp = drom & OP_MASK;					/* instruction type */

if ((drom == 0) || (drom & dec_flgs)) {			/* not in model? */
	if (stop_inst) reason = STOP_RSRV;		/* stop or */
	else cc = exception (ILOPSW, cc, 0);		/* exception */
  	continue;  }
if ((drom & OP_PRV) && (PSW & PSW_PRO)) {		/* priv & protected? */
	cc = exception (ILOPSW, cc, 0);			/* exception */
	continue;  }

switch (ityp) {						/* decode instruction */
case OP_NO:						/* no operand */
	opnd = r2;					/* assume short */
	PC = (PC + 2) & VAMASK;				/* increment PC */
	break;

case OP_RR:						/* reg-reg */
	opnd = R[r2];					/* ea/operand is R2 */
	PC = (PC + 2) & VAMASK;				/* increment PC */
	break;

case OP_RI1:						/* reg-imm 1 */
	ir2 = ReadH ((PC + 2) & VAMASK, VE);		/* fetch immed */
	opnd = SEXT16 (ir2);				/* sign extend */
	if (r2) opnd = (opnd + R[r2]) & DMASK32;	/* index calculation */
	PC = (PC + 4) & VAMASK;				/* increment PC */
	break;

case OP_RI2:						/* reg-imm 2 */
	ir2 = ReadH ((PC + 2) & VAMASK, VE);		/* fetch imm hi */
	ir3 = ReadH ((PC + 4) & VAMASK, VE);		/* fetch imm lo */
	opnd = (ir2 << 16) | ir3;			/* 32b immediate */
	if (r2) opnd = (opnd + R[r2]) & DMASK32;	/* index calculation */
	PC = (PC + 6) & VAMASK;				/* increment PC */
	break;

case OP_RX: case OP_RXB: case OP_RXH: case OP_RXF:	/* reg-mem */
	ir2 = ReadH ((PC + 2) & VAMASK, VE);		/* fetch addr */
	if ((ir2 & 0xC000) == 0) {			/* displacement? */
	    PC = (PC + 4) & VAMASK;			/* increment PC */
	    ea = ir2;  }				/* abs 14b displ */
	else if (ir2 & 0x8000) {			/* relative? */
	    PC = (PC + 4) & VAMASK;			/* increment PC */
	    ea = PC + SEXT15 (ir2);  }			/* add to incr PC */
	else {						/* absolute */
	    rx2 = (ir2 >> 8) & 0xF;			/* get second index */
	    ea = (ir2 & 0xFF) << 16;			/* shift to place */
	    ir3 = ReadH ((PC + 4) & VAMASK, VE);	/* fetch addr lo */
	    ea = ea | ir3;				/* finish addr */
	    if (rx2) ea = ea + R[rx2];			/* index calc 2 */
	    PC = (PC + 6) & VAMASK;  }			/* increment PC */
	if (r2) ea = ea + R[r2];			/* index calculation */
	ea = ea & VAMASK;
	if (ityp == OP_RXF) opnd = ReadF (ea, VR);	/* get fw operand? */
	else if (ityp == OP_RXH) {			/* get hw operand? */
	    t = ReadH (ea, VR);				/* read halfword */
	    opnd = SEXT16 (t);  }			/* sign extend */
	else if (ityp == OP_RXB) opnd = ReadB (ea, VR);	/* get byte opnd? */
	else opnd = ea;					/* just address */
	break;

default:
	return SCPE_IERR;  }

if (hst_lnt) {						/* instruction history? */
	hst[hst_p].pc = oPC | HIST_PC;			/* save decode state */
	hst[hst_p].ir1 = ir1;
	hst[hst_p].ir2 = ir2;
	hst[hst_p].ir3 = ir3;
	hst[hst_p].r1 = R[r1];
	hst[hst_p].ea = ea;
	hst[hst_p].opnd = opnd;
	hst_p = hst_p + 1;
	if (hst_p >= hst_lnt) hst_p = 0;  }
if (qevent & EV_MAC) continue;				/* MAC abort on fetch? */
switch (op) {						/* case on opcode */

/* Load/store instructions */

case 0x08:						/* LR - RR */
case 0x24:						/* LIS - NO */
case 0x48:						/* LH - RXH */
case 0x58:						/* L - RXF */
case 0xC8:						/* LHI - RI1 */
case 0xF8:						/* LI - RI2 */
	R[r1] = opnd;					/* load operand */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

case 0x73:						/* LHL - RXH */
	R[r1] = opnd & DMASK16;				/* get op, zero ext */
	CC_GL_32 (R[r1]);				/* set G, L */
	break;

case 0x25:						/* LCS - NO */
	R[r1] = NEG (opnd);				/* load complement */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

case 0xE6:						/* LA - RX */
	R[r1] = ea;					/* load addr */
	break;

case 0x63:						/* LRA - RX */
	cc = RelocT (R[r1] & VAMASK, ea, VR, &R[r1]);	/* test reloc */
	break;

case 0x40:						/* STH - RX */
	WriteH (ea, R[r1], VW);				/* store register */
	break;

case 0x50:						/* ST - RX */
	WriteF (ea, R[r1], VW);				/* store register */
	break;

case 0xD1:						/* LM - RX */
	for ( ; r1 <= 0xF; r1++) {			/* loop thru reg */
	    R[r1] = ReadF (ea, VR);			/* load register */
	    ea = (ea + 4) & VAMASK;  }			/* incr mem addr */
	break;

case 0xD0:						/* STM - RX */
	for ( ; r1 <= 0xF; r1++) {			/* loop thru reg */
	    WriteF (ea, R[r1], VW);			/* store register */
	    ea = (ea + 4) & VAMASK;  }			/* incr mem addr */
	break;

case 0xE0:						/* TS - RXH */
	CC_GL_16 (opnd);				/* set cc's */
	WriteH (ea, opnd | SIGN16, VW);			/* set MSB */
	break;

case 0x93:						/* LDBR - RR */
case 0xD3:						/* LDB - RXB */
	R[r1] = opnd & DMASK8;				/* load byte */
	break;

case 0x92:						/* STBR - NO */
	R[r2] = (R[r2] & ~DMASK8) | (R[r1] & DMASK8);	/* store byte */
	break;
case 0xD2:						/* STB - RX */
	WriteB (ea, R[r1], VW);				/* store byte */
	break;

case 0x34:						/* EXHR - RR */
	R[r1] = ((opnd >> 16) & DMASK16) | ((opnd & DMASK16) << 16);
	break;

case 0x94:						/* EXBR - RR */
	R[r1] = (R[r1] & ~DMASK16) |
	    ((opnd >> 8) & DMASK8) | ((opnd & DMASK8) << 8);
	break;

/* Control instructions */

case 0x01:						/* BALR - RR */
case 0x41:						/* BAL - RX */
	PCQ_ENTRY;					/* save old PC */
	R[r1] = PC;					/* save cur PC */
	PC = opnd;					/* branch */
	break;

case 0x02:						/* BTCR - RR */
case 0x42:						/* BTC - RX */
	if (cc & r1) {					/* test CC's */
	    PCQ_ENTRY;					/* branch if true */
	    PC = opnd;  }
	break;

case 0x20:						/* BTBS - NO */
	if (cc & r1) {					/* test CC's */
	    PCQ_ENTRY;					/* branch if true */
	    PC = (oPC - r2 - r2) & VAMASK;  }
	break;

case 0x21:						/* BTFS - NO */
	if (cc & r1) {					/* test CC's */
	    PCQ_ENTRY;					/* branch if true */
	    PC = (oPC + r2 + r2) & VAMASK;  }
	break;

case 0x03:						/* BFCR - RR */
case 0x43:						/* BFC - RX */
	if ((cc & r1) == 0) {				/* test CC's */
	    PCQ_ENTRY;					/* branch if false */
	    PC = opnd;  }
	break;

case 0x22:						/* BFBS - NO */
	if ((cc & r1) == 0) {				/* test CC's */
	    PCQ_ENTRY;					/* branch if false */
	    PC = (oPC - r2 - r2) & VAMASK;  }
	break;

case 0x23:						/* BFFS - NO */
	if ((cc & r1) == 0) {				/* test CC's */
	    PCQ_ENTRY;					/* branch if false */
	    PC = (oPC + r2 + r2) & VAMASK;  }
	break;

case 0xC0:						/* BXH - RX */
	inc = R[(r1 + 1) & 0xF];			/* inc = R1 + 1 */
	lim = R[(r1 + 2) & 0xF];			/* lim = R1 + 2 */
	R[r1] = (R[r1] + inc) & DMASK32;		/* R1 = R1 + inc */
	if (R[r1] > lim) {				/* if R1 > lim */
	    PCQ_ENTRY;					/* branch */
	    PC = opnd;  }
	break;

case 0xC1:						/* BXLE - RX */
	inc = R[(r1 + 1) & 0xF];			/* inc = R1 + 1 */
	lim = R[(r1 + 2) & 0xF];			/* lim = R1 + 2 */
	R[r1] = (R[r1] + inc) & DMASK32;		/* R1 = R1 + inc */
	if (R[r1] <= lim) {				/* if R1 <= lim */
	    PCQ_ENTRY;					/* branch */
	    PC = opnd;  }
	break;

/* Logical instructions */

case 0x04:						/* NR - RR */
case 0x44:						/* NH - RXH */
case 0x54:						/* N - RXF */
case 0xC4:						/* NHI - RI1 */
case 0xF4:						/* NI - RI2 */
	R[r1] = R[r1] & opnd;				/* result */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

case 0x06:						/* OR - RR */
case 0x46:						/* OH - RXH */
case 0x56:						/* O - RXF */
case 0xC6:						/* OHI - RI1 */
case 0xF6:						/* OI - RI2 */
	R[r1] = R[r1] | opnd;				/* result */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

case 0x07:						/* XR - RR */
case 0x47:						/* XH - RXH */
case 0x57:						/* X - RXF */
case 0xC7:						/* XHI - RI1 */
case 0xF7:						/* XI - RI2 */
	R[r1] = R[r1] ^ opnd;				/* result */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

case 0xC3:						/* THI - RI1 */
case 0xF3:						/* TI - RI2 */
	rslt = R[r1] & opnd;				/* result */
	CC_GL_32 (rslt);				/* set G, L */
	break;

case 0x05:						/* CLR - RR */
case 0x45:						/* CLH - RXH */
case 0x55:						/* CL - RXF */
case 0xC5:						/* CLHI - RI1 */
case 0xF5:						/* CI - RI2 */
	rslt = (R[r1] - opnd) & DMASK32;		/* result */
	CC_GL_32 (rslt);				/* set G,L */
	if (R[r1] < opnd) cc = cc | CC_C;		/* set C if borrow */
	if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) cc = cc | CC_V;
	break;

case 0xD4:						/* CLB - RXB */
	t = R[r1] & DMASK8;
	rslt = (t - opnd) & DMASK16;			/* result */
	CC_GL_16 (rslt);				/* set G,L 16b */
	if (t < opnd) cc = cc | CC_C;			/* set C if borrow */
	break;

case 0x12:						/* CHVR - RR */
	t = cc & CC_C;					/* save C */
	R[r1] = (SEXT16 (opnd & DMASK16)) & DMASK32;	/* result */
	CC_GL_32 (R[r1]);				/* set G, L */
	if (R[r1] != opnd) cc = cc | CC_V;		/* wont fit? set V */
	cc = cc | t;					/* restore C */
	break;

/* Shift instructions */

case 0xCC:						/* SRHL - RI1 */
	opnd = opnd & 0xF;				/* shift count */
case 0x90:						/* SRHLS - NO */
	rslt = (R[r1] & DMASK16) >> opnd;		/* result */
	CC_GL_16 (rslt);				/* set G,L 16b */
	if (opnd && (((R[r1] & DMASK16) >> (opnd - 1)) & 1)) cc = cc | CC_C;
	R[r1] = (R[r1] & ~DMASK16) | rslt;		/* store result */
	break;

case 0xCD:						/* SLHL - RI1 */
	opnd = opnd & 0xF;				/* shift count */
case 0x91:						/* SLHLS - NO */
	rslt = R[r1] << opnd;				/* result */
	CC_GL_16 (rslt & DMASK16);			/* set G,L 16b */
	if (opnd && (rslt & 0x10000)) cc = cc | CC_C;	/* set C if shft out */
	R[r1] = (R[r1] & ~DMASK16) | (rslt & DMASK16);	/* store result */
	break;

case 0xCE:						/* SRHA - RI1 */
	opnd = opnd & 0xF;				/* shift count */
	rslt = (SEXT16 (R[r1]) >> opnd) & DMASK16;	/* result */
	CC_GL_16 (rslt);				/* set G,L 16b */
	if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
	R[r1] = (R[r1] & ~DMASK16) | rslt;		/* store result */
	break;

case 0xCF:						/* SLHA - RI1 */
	opnd = opnd & 0xF;				/* shift count */
	rslt = R[r1] << opnd;				/* raw result */
	R[r1] = (R[r1] & ~MMASK16) | (rslt & MMASK16);
	CC_GL_16 (R[r1] & DMASK16);			/* set G,L 16b */
	if (opnd && (rslt & SIGN16)) cc = cc | CC_C;	/* set C if shft out */
	break;

case 0xEC:						/* SRL - RI1 */
	opnd = opnd & 0x1F;				/* shift count */
case 0x10:						/* SRLS - NO */
	rslt = R[r1] >> opnd;				/* result */
	CC_GL_32 (rslt);				/* set G,L */
	if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
	R[r1] = rslt;					/* store result */
	break;

case 0xED:						/* SLL - RI1 */
	opnd = opnd & 0x1F;				/* shift count */
case 0x11:						/* SLLS - NO */
	rslt = (R[r1] << opnd) & DMASK32;		/* result */
	CC_GL_32 (rslt);				/* set G,L */
	if (opnd && ((R[r1] << (opnd - 1)) & SIGN32)) cc = cc | CC_C;
	R[r1] = rslt;					/* store result */
	break;

case 0xEE:						/* SRA - RI1 */
	opnd = opnd & 0x1F;				/* shift count */
	rslt = (SEXT32 (R[r1]) >> opnd) & DMASK32;	/* result */
	CC_GL_32 (rslt);				/* set G,L */
	if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
	R[r1] = rslt;					/* store result */
	break;

case 0xEF:						/* SLA - RI1 */
	opnd = opnd & 0x1F;				/* shift count */
	rslt = (R[r1] << opnd) & DMASK32;		/* raw result */
	R[r1] = (R[r1] & SIGN32) | (rslt & MMASK32);	/* arith result */
	CC_GL_32 (R[r1]);				/* set G,L */
	if (opnd && (rslt & SIGN32)) cc = cc | CC_C;	/* set C if shft out */
	break;

case 0xEA:						/* RRL - RI1 */
	opnd = opnd & 0x1F;				/* shift count */
	if (opnd) R[r1] = (R[r1] >> opnd) | 		/* if cnt > 0 */
	    ((R[r1] << (32 - opnd)) & DMASK32);		/* rotate */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

case 0xEB:						/* RLL - RI1 */
	opnd = opnd & 0x1F;				/* shift count */
	if (opnd) R[r1] = ((R[r1] << opnd) & DMASK32) | /* if cnt > 0 */
	    (R[r1] >> (32 - opnd));			/* rotate */
	CC_GL_32 (R[r1]);				/* set G,L */
	break;

/* Bit instructions */

case 0x74:						/* TBT - RX */
	t = 1u << (15 - (R[r1] & 0xF));			/* bit mask in HW */
	ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK;	/* HW location */
	opnd = ReadH (ea, VR);				/* read HW */
	if (opnd & t) cc = CC_G;			/* test bit */
	else cc = 0;
	break;

case 0x75:						/* SBT - RX */
	t = 1u << (15 - (R[r1] & 0xF));			/* bit mask in HW */
	ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK;	/* HW location */
	opnd = ReadH (ea, VR);				/* read HW */
	WriteH (ea, opnd | t, VW);			/* set bit, rewr */
	if (opnd & t) cc = CC_G;			/* test bit */
	else cc = 0;
	break;

case 0x76:						/* RBT - RX */
	t = 1u << (15 - (R[r1] & 0xF));			/* bit mask in HW */
	ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK;	/* HW location */
	opnd = ReadH (ea, VR);				/* read HW */
	WriteH (ea, opnd & ~t, VW);			/* clr bit, rewr */
	if (opnd & t) cc = CC_G;			/* test bit */
	else cc = 0;
	break;

case 0x77:						/* CBT - RX */
	t = 1u << (15 - (R[r1] & 0xF));			/* bit mask in HW */
	ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK;	/* HW location */
	opnd = ReadH (ea, VR);				/* read HW */
	WriteH (ea, opnd ^ t, VW);			/* com bit, rewr */
	if (opnd & t) cc = CC_G;			/* test bit */
	else cc = 0;
	break;

/* Arithmetic instructions */

case 0x0A:						/* AR - RR */
case 0x26:						/* AIS - NO */
case 0x4A:						/* AH - RXH */
case 0x5A:						/* A - RXF */
case 0xCA:						/* AHI - RI1 */
case 0xFA:						/* AI - RI2 */
	rslt = (R[r1] + opnd) & DMASK32;		/* result */
	CC_GL_32 (rslt);				/* set G,L */
	if (rslt < opnd) cc = cc | CC_C;		/* set C if carry */
	if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN32) cc = cc | CC_V;
	R[r1] = rslt;
	break;

case 0x51:						/* AM - RXF */
	rslt = (R[r1] + opnd) & DMASK32;		/* result */
	WriteF (ea, rslt, VW);				/* write result */
	CC_GL_32 (rslt);				/* set G,L */
	if (rslt < opnd) cc = cc | CC_C;		/* set C if carry */
	if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN32) cc = cc | CC_V;
	break;

case 0x61:						/* AHM - RXH */
	rslt = (R[r1] + opnd) & DMASK16;		/* result */
	WriteH (ea, rslt, VW);				/* write result */
	CC_GL_16 (rslt);				/* set G,L 16b */
	if (rslt < (opnd & DMASK16)) cc = cc | CC_C;	/* set C if carry */
	if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) cc = cc | CC_V;
	break;

case 0x0B:						/* SR - RR */
case 0x27:						/* SIS - NO */
case 0x4B:						/* SH - RXH */
case 0x5B:						/* S - RXF */
case 0xCB:						/* SHI - RI1 */
case 0xFB:						/* SI - RI2 */
	rslt = (R[r1] - opnd) & DMASK32;		/* result */
	CC_GL_32 (rslt);				/* set G,L */
	if (R[r1] < opnd) cc = cc | CC_C;		/* set C if borrow */
	if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) cc = cc | CC_V;
	R[r1] = rslt;
	break;

case 0x09:						/* CR - RR */
case 0x49:						/* CH - RXH */
case 0x59:						/* C - RXF */
case 0xC9:						/* CHI - RI1 */
case 0xF9:						/* CI - RI2 */
	if (R[r1] == opnd) cc = 0;			/* =? */
	else if ((R[r1] ^ opnd) & SIGN32)		/* unlike signs? */
	    cc = (R[r1] & SIGN32)? (CC_C | CC_L): CC_G;
	else cc = (R[r1] > opnd)? CC_G: (CC_C | CC_L);	/* like signs */
	if (((R[r1] ^ opnd) & (~opnd ^ (R[r1] - opnd))) & SIGN32)
	    cc = cc | CC_V;
	break;

case 0x0C:						/* MHR - RR */
case 0x4C:						/* MH - RXH */
	R[r1] = (SEXT16 (R[r1]) * SEXT16 (opnd)) & DMASK32;	/* multiply */
	break;

case 0x1C:						/* MR - RR */
case 0x5C:						/* M - RXF */
	r1p1 = (r1 + 1) & 0xF;
	mpc = ABS (opnd);				/* |mpcnd| */
	mpy = ABS (R[r1p1]);				/* |mplyr| */
	rslt = rlo = 0;					/* clr result */
	for (i = 0; i < 32; i++) {			/* develop 32b */
	    t = 0;					/* no cout */
	    if (mpy & 1) {				/* cond add */
		rslt = (rslt + mpc) & DMASK32;
		if (rslt < mpc) t = SIGN32;  }
	    rlo = (rlo >> 1) | ((rslt & 1) << 31);	/* shift result */
	    rslt = (rslt >> 1) | t;
	    mpy = mpy >> 1;  }				/* shift mpylr */
	if ((opnd ^ R[r1p1]) & SIGN32) {
	    DNEG (rslt, rlo); }
	R[r1] = rslt;					/* store result */
	R[r1p1] = rlo;
	break;

case 0x0D:						/* DHR - RR */
case 0x4D:						/* DH - RXH */
	r1p1 = (r1 + 1) & 0xF;
	opnd = opnd & DMASK16;				/* force HW opnd */
	if (opnd) {					/* if divisor != 0 */
	    st = SEXT32 (R[r1]) / SEXT16 (opnd);	/* quotient */
	    sr = SEXT32 (R[r1]) % SEXT16 (opnd);  }	/* remainder */
	if (opnd && (st < 0x8000) && (st >= -0x8000)) {	/* if quo fits */
	    R[r1] = sr & DMASK32;			/* store remainder */
	    R[r1p1] = st & DMASK32;  }			/* store quotient */
	else if (PSW & PSW_AFI)				/* div fault enabled? */
		cc = exception (AFIPSW, cc, 0);		/* exception */
	break;

case 0x1D:						/* DR - RR */
case 0x5D:						/* D - RXF */
	r1p1 = (r1 + 1) & 0xF;
	rslt = R[r1];					/* get dividend */
	rlo = R[r1p1];
	if (R[r1] & SIGN32) { DNEG (rslt, rlo); }	/* |divd| */
	dvr = ABS (opnd);				/* |divr| */
	if (rslt < dvr) {				/* will div work? */
	    uint32 quos = R[r1] ^ opnd;			/* expected sign */
	    for (i = t = 0; i < 32; i++) {		/* 32 iterations */
		rslt = ((rslt << 1) & DMASK32) | 	/* shift divd */
		    ((rlo >> 31) & 1);
		rlo = (rlo << 1) & DMASK32;
		t = (t << 1) & DMASK32;			/* shift quo */
		if (rslt >= dvr) {			/* subtract work? */
		    rslt = rslt - dvr;			/* divd -= divr */
		    t = t | 1;  }  }			/* set quo bit */
	    if (quos & SIGN32) t = NEG (t);		/* res -? neg quo */
	    if (R[r1] & SIGN32) rslt = NEG (rslt);	/* adj rem sign */
	    if (t && ((t ^ quos) & SIGN32)) {		/* res sign wrong? */
	        if (PSW & PSW_AFI)			/* if enabled, */
		    cc = exception (AFIPSW, cc, 0);	/* exception */
		break;  }
	    R[r1] = rslt;				/* store rem */
	    R[r1p1] = t;  }				/* store quo */
	else if (PSW & PSW_AFI)				/* div fault enabled? */
		cc = exception (AFIPSW, cc, 0);		/* exception */
	break;

/* Floating point instructions */

case 0x28:						/* LER - NO */
case 0x38:						/* LDR - NO */
case 0x68:						/* LE - RX */
case 0x78:						/* LD - RX */
	cc = f_l (op, r1, r2, ea);			/* load */
	if ((cc & CC_V) && (PSW & PSW_AFI)) 		/* V set? */
	    cc = exception (AFIPSW, cc, 1);
	break;

case 0x29:						/* CER - NO */
case 0x39:						/* CDR - NO */
case 0x69:						/* CE - RX */
case 0x79:						/* CD - RX */
	cc = f_c (op, r1, r2, ea);			/* compare */
	break;

case 0x2A:						/* AER - NO */
case 0x2B:						/* SER - NO */
case 0x3A:						/* ADR - NO */
case 0x3B:						/* SDR - NO */
case 0x6A:						/* AE - RX */
case 0x6B:						/* SE - RX */
case 0x7A:						/* AD - RX */
case 0x7B:						/* SD - RX */
	cc = f_as (op, r1, r2, ea);			/* add/sub */
	if ((cc & CC_V) && (PSW & PSW_AFI)) 		/* V set? */
	    cc = exception (AFIPSW, cc, 1);
	break;

case 0x2C:						/* MER - NO */
case 0x3C:						/* MDR - NO */
case 0x6C:						/* ME - RX */
case 0x7C:						/* MD - RX */
	cc = f_m (op, r1, r2, ea);			/* multiply */
	if ((cc & CC_V) && (PSW & PSW_AFI)) 		/* V set? */
	    cc = exception (AFIPSW, cc, 1);
	break;

case 0x2D:						/* DER - NO */
case 0x3D:						/* DDR - NO */
case 0x6D:						/* DE - RX */
case 0x7D:						/* DD - RX */
	cc = f_d (op, r1, r2, ea);			/* perform divide */
	if ((cc & CC_V) && (PSW & PSW_AFI)) 		/* V set? */
	    cc = exception (AFIPSW, cc, 1);
	break;

case 0x2E:						/* FXR - NO */
case 0x3E:						/* FXDR - NO */
	cc = f_fix32 (op, r1, r2);			/* cvt to integer */
	break;

case 0x2F:						/* FLR - NO */
case 0x3F:						/* FLDR - NO */
	cc = f_flt32 (op, r1, r2);			/* cvt to floating */
	break;

case 0x60:						/* STE - RX */
	t = ReadFReg (r1);				/* get sp reg */
	WriteF (ea, t, VW);				/* write */
	break;

case 0x70:						/* STD - RX */
	WriteF (ea, D[r1 >> 1].h, VW);			/* write hi */
	WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, VW);	/* write lo */
	break;

case 0x71:						/* STME - RX */
	for ( ; r1 <= 0xE; r1 = r1 + 2) {		/* loop thru reg */
	    t = ReadFReg (r1);				/* get sp reg */
	    WriteF (ea, t, VW);				/* write */
	    ea = (ea + 4) & VAMASK;  }			/* incr mem addr */
	break;

case 0x72:						/* LME - RX */
	for ( ; r1 <= 0xE; r1 = r1 + 2) {		/* loop thru reg */
	    t = ReadF (ea, VR);				/* get value */
	    WriteFReg (r1, t);				/* write reg */
	    ea = (ea + 4) & VAMASK;  }			/* incr mem addr */
	break;

case 0x7E:						/* STMD - RX */
	for ( ; r1 <= 0xE; r1 = r1 + 2) {		/* loop thru reg */
	    WriteF (ea, D[r1 >> 1].h, VW);		/* write register */
	    WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, VW);
	    ea = (ea + 8) & VAMASK;  }			/* incr mem addr */
	break;

case 0x7F:						/* LMD - RX */
	for ( ; r1 <= 0xE; r1 = r1 + 2) {		/* loop thru reg */
	    D[r1 >> 1].h = ReadF (ea, VR);		/* load register */
	    D[r1 >> 1].l = ReadF ((ea + 4) & VAMASK, VR);
	    ea = (ea + 8) & VAMASK;  }			/* incr mem addr */
	break;

/* Miscellaneous */
	
case 0xE1:						/* SVC - RX */
	PCQ_ENTRY;					/* effective branch */
	t = BUILD_PSW (cc);				/* save PSW */
	cc = newPSW (ReadF (SVNPS32, P));		/* get new PSW */
	R[13] = ea & 0xFFFFFF;				/* parameter */
	R[14] = t;					/* old PSW */
	R[15] = PC;					/* old PC */
	PC = ReadH (SVNPC + r1 + r1, P);		/* new PC */
	if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb,
	    ">>SVC: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
	    pcq[pcq_p], t, PC, PSW);
	break;

case 0xE2:						/* SINT - RI1 */
	dev = opnd & DEV_MAX;				/* get dev */
	cc = int_auto (dev, cc);			/* auto int */
	int_eval ();
	break;

case 0xE3:						/* SCP - RXH */
	opnd = opnd & DMASK16;				/* zero ext operand */
	if (opnd & CCW32_B1) t = ea + CCB32_B1C;	/* point to buf */
	else t = ea + CCB32_B0C;
	sr = ReadH (t & VAMASK, VR);			/* get count */
	sr = SEXT16 (sr);				/* sign extend */
	if (sr <= 0) {					/* <= 0? */
	    bufa = ReadF ((t + 2) & VAMASK, VR);	/* get buf end */
	    if (opnd & CCW32_WR)			/* write? */
		R[r1] = ReadB ((bufa + sr) & VAMASK, VR);  /* R1 gets mem */
	    else WriteB ((bufa + sr) & VAMASK, R[r1], VW); /* read, R1 to mem */
	    sr = sr + 1;				/* inc count */
	    CC_GL_32 (sr & DMASK32);			/* set cc's */
	    WriteH (t & VAMASK, sr, VW);		/* rewrite */
	    if ((sr > 0) && !(opnd & CCW32_FST))	/* buf switch? */
		WriteH (ea, opnd ^ CCW32_B1, VW);	/* flip CCW bit */
	    }						/* end if */
	else cc = CC_V;
	break;

case 0x18:						/* LPSWR - RR */
	PCQ_ENTRY;					/* effective branch */
	PC = R[(r2 + 1) & 0xF] & VAMASK;		/* new PC (old reg set) */
	if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb,
	    ">>LPSWR: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
	    pcq[pcq_p], BUILD_PSW (cc), PC, opnd);
	cc = newPSW (opnd);				/* new PSW */
	if (PSW & PSW_SQI) cc = testsysq (cc);		/* test for q */
	break;

case 0xC2:						/* LPSW - RXF */
	PCQ_ENTRY;					/* effective branch */
	PC = ReadF ((ea + 4) & VAMASK, VR) & VAMASK;	/* new PC */
	if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb,
	    ">>LPSW: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
	    pcq[pcq_p], BUILD_PSW (cc), PC, opnd);
	cc = newPSW (opnd);				/* new PSW */
	if (PSW & PSW_SQI) cc = testsysq (cc);		/* test for q */
	break;

case 0x95:						/* EPSR - NO */
	R[r1] = BUILD_PSW (cc);				/* save PSW */
	cc = newPSW (R[r2]);				/* load new PSW */
	if (PSW & PSW_SQI) cc = testsysq (cc);		/* test for q */
	break;	

case 0x64:						/* ATL - RX */
case 0x65:						/* ABL - RX */
	cc = addtoq (ea, R[r1], op & 1);		/* add to q */
	break;

case 0x66:						/* RTL - RX */
case 0x67:						/* RBL - RX */
	cc = remfmq (ea, r1, op & 1);			/* rem from q */
	break;

case 0x5E:						/* CRC12 - RXH */
	opnd = opnd & DMASK16;				/* zero ext opnd */
	t = (R[r1] & 0x3F) ^ opnd;
	for (i = 0; i < 6; i++) {
	    if (t & 1) t = (t >> 1) ^ 0x0F01;
	    else t = t >> 1;  }
	WriteH (ea, t, VW);
	break;

case 0x5F:						/* CRC16 - RXH */
	opnd = opnd & DMASK16;				/* zero ext opnd */
	t = (R[r1] & 0xFF) ^ opnd;
	for (i = 0; i < 8; i++) {
	    if (t & 1) t = (t >> 1) ^ 0xA001;
	    else t = t >> 1;  }
	WriteH (ea, t, VW);
	break;

case 0xE7:						/* TLATE - RXF */
	t = (opnd + ((R[r1] & DMASK8) << 1)) & VAMASK;	/* table entry */
	rslt = ReadH (t, VR);				/* get entry */
	if (rslt & SIGN16) R[r1] = rslt & DMASK8;	/* direct xlate? */
	else {	PCQ_ENTRY;				/* branch */
		PC = rslt << 1;  }
	break;

/* I/O instructions */

case 0xDE:						/* OC - RX */
	opnd = ReadB (ea, VR);				/* fetch operand */
case 0x9E:						/* OCR - RR */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {
	    dev_tab[dev] (dev, IO_ADR, 0);		/* select */
	    dev_tab[dev] (dev, IO_OC, opnd & DMASK8);	/* send command */
	    cc = 0;  }
	else cc = CC_V;
	int_eval ();					/* re-eval intr */
	break;

case 0xDA:						/* WD - RX */
	opnd = ReadB (ea, VR);				/* fetch operand */
case 0x9A:						/* WDR - RR */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {
	    dev_tab[dev] (dev, IO_ADR, 0);		/* select */
	    dev_tab[dev] (dev, IO_WD, opnd & DMASK8);	/* send data */
	    cc = 0;  }
	else cc = CC_V;
	int_eval ();					/* re-eval intr */
	break;

case 0xD8:						/* WH - RX */
	opnd = ReadH (ea, VR);				/* fetch operand */
case 0x98:						/* WHR - RR */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {
	    if (dev_tab[dev] (dev, IO_ADR, 0))		/* select; hw ok? */
		dev_tab[dev] (dev, IO_WH, opnd & DMASK16);	/* send data */
	    else {					/* byte only */
		dev_tab[dev] (dev, IO_WD, (opnd >> 8) & DMASK8); /* hi */
		dev_tab[dev] (dev, IO_WD, opnd & DMASK8);  } /* send lo byte */
	    cc = 0;  }
	else cc = CC_V;
	int_eval ();					/* re-eval intr */
	break;

case 0x9B:						/* RDR - RR */
case 0xDB:						/* RD - RX */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {				/* dev exist? */
	    dev_tab[dev] (dev, IO_ADR, 0);		/* select */
	    t = dev_tab[dev] (dev, IO_RD, 0);		/* get data */
	    cc = 0;  }
	else {						/* no */
	    t = 0;
	    cc = CC_V;  }
	if (OP_TYPE (op) != OP_RR) WriteB (ea, t, VW);	/* RX or RR? */
	else R[r2] = t & DMASK8;
	int_eval ();					/* re-eval intr */
	break;

case 0x99:						/* RHR - RR */
case 0xD9:						/* RH - RX */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {				/* dev exist? */
	    if (dev_tab[dev] (dev, IO_ADR, 0))		/* select, hw ok? */
		t = dev_tab[dev] (dev, IO_RH, 0);	/* get data */
	    else {					/* byte only */
		rslt = dev_tab[dev] (dev, IO_RD, 0);	/* get byte */
		t = dev_tab[dev] (dev, IO_RD, 0);	/* get byte */
		t = (rslt << 8) | t;  }			/* merge */
	    cc = 0;  }
	else {						/* no */
	    t = 0;
	    cc = CC_V;  }
	if (OP_TYPE (op) != OP_RR) WriteH (ea, t, VW);	/* RX or RR? */
	else R[r2] = t & DMASK16;
	int_eval ();					/* re-eval intr */
	break;

case 0x9D:						/* SSR - RR */
case 0xDD:						/* SS - RX */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {				/* dev exist? */
	    dev_tab[dev] (dev, IO_ADR, 0);		/* select */
	    t = dev_tab[dev] (dev, IO_SS, 0);  }	/* get status */
	else t = STA_EX;				/* no */
	if (OP_TYPE (op) != OP_RR) WriteB (ea, t, VW);	/* RX or RR? */
	else R[r2] = t & DMASK8;
	cc = t & 0xF;
	int_eval ();					/* re-eval intr */
	break;

/* Block I/O instructions
	
   On a real Interdata system, the block I/O instructions can't be
   interrupted or stopped.  To model this behavior, while allowing
   the instructions to go back through fetch for I/O processing and
   WRU testing, the simulator implements a 'block I/O in progress'
   flag and status block.  If a block I/O is in progress, normal
   interrupts and fetches are suppressed until the block I/O is done.
*/

case 0x96:						/* WBR - RR */
case 0xD6:						/* WB - RXF */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {				/* dev exist? */
	    if (OP_TYPE (op) != OP_RR)
		lim = ReadF ((ea + 4) & VAMASK, VR);
	    else lim = R[(r2 + 1) & 0xF];
	    if (opnd > lim) cc = 0;			/* start > end? */
	    else {					/* no, start I/O */
		dev_tab[dev] (dev, IO_ADR, 0);		/* select dev */
		blk_io.dfl = dev;			/* set status block */
		blk_io.cur = opnd;
		blk_io.end = lim;
		qevent = qevent | EV_BLK;  }  }		/* I/O in prog */
	else cc = CC_V;					/* nx dev */
	break;

case 0x97:						/* RBR - RR */
case 0xD7:						/* RB - RXF */
	dev = R[r1] & DEV_MAX;
	if (DEV_ACC (dev)) {				/* dev exist? */
	    if (OP_TYPE (op) != OP_RR)
		lim = ReadF ((ea + 4) & VAMASK, VR);
	    else lim = R[(r2 + 1) & 0xF];
	    if (opnd > lim) cc = 0;			/* start > end? */
	    else {					/* no, start I/O */
		dev_tab[dev] (dev, IO_ADR, 0);		/* select dev */
		blk_io.dfl = dev | BL_RD;		/* set status block */
		blk_io.cur = opnd;
		blk_io.end = lim;
		qevent = qevent | EV_BLK;  }  }		/* I/O in prog */
	else cc = CC_V;					/* nx dev */
	break;

case 0xD5:						/* AL - RX */
	dev = ReadB (AL_DEV, P);			/* get device */
	t = ReadB (AL_IOC, P);				/* get command */
	if (DEV_ACC (dev)) {				/* dev exist? */
	    if (AL_BUF > ea) cc = 0;			/* start > end? */
	    else {					/* no, start I/O */
		dev_tab[dev] (dev, IO_ADR, 0);		/* select dev */
		dev_tab[dev] (dev, IO_OC, t);		/* start dev */
		blk_io.dfl = dev | BL_RD | BL_LZ;	/* set status block */
		blk_io.cur = AL_BUF;
		blk_io.end = ea;
		qevent = qevent | EV_BLK;  }  }		/* I/O in prog */
	else cc = CC_V;					/* nx dev */
	break;  }					/* end switch */
	}						/* end while */

/* Simulation halted */

PSW = BUILD_PSW (cc);
PC = PC & VAMASK;
set_r_display (R);
pcq_r->qptr = pcq_p;					/* update pc q ptr */
return reason;
}

/* Load new PSW */

uint32 newPSW (uint32 val)
{
uint32 rs = PSW_GETREG (val);				/* register set */

R = &GREG[rs * 16];					/* set register set */
PSW = val & PSW_MASK;					/* store PSW */
int_eval ();						/* update intreq */
if (PSW & PSW_WAIT) qevent = qevent | EV_WAIT;		/* wait state? */
else qevent = qevent & ~EV_WAIT;
if (PSW & PSW_EXI) SET_ENB (v_DS);			/* enable/disable */
else CLR_ENB (v_DS);					/* console intr */
return PSW & CC_MASK;
}

/* Exception handler - 7/32 always uses register set 0 */

uint32 exception (uint32 loc, uint32 cc, uint32 flg)
{
int32 oldPSW = BUILD_PSW (cc);				/* save old PSW */
int32 oldPC = PC;					/* save old PC */

cc = newPSW (ReadF (loc, P));				/* new PSW */
PC = ReadF (loc + 4, P) & VAMASK;			/* new PC */
if (cpu_unit.flags & UNIT_832) {			/* 8/32? */
	R[14] = oldPSW;					/* PSW to new 14 */
	R[15] = oldPC;  }				/* PC to new 15 */
else {	GREG[14] = oldPSW;				/* 7/32, PSW to set 0 14 */
	GREG[15] = oldPC;  }				/* PC to set 0 15 */
if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb,
	">>Exc %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
	loc, oldPC, oldPSW, PC, PSW | cc | flg);
return cc | flg;					/* return CC */
}

/* Test for queue interrupts - system queue addresses are physical */

uint32 testsysq (uint32 cc)
{
int32 qb = ReadF (SQP, P);				/* get sys q addr */
int32 usd = ReadH (qb + Q32_USD, P);			/* get use count */

if (usd) {						/* entries? */
	cc = exception (SQTPSW, cc, 0);			/* take sysq exc */
	if (cpu_unit.flags & UNIT_832) R[13] = qb;	/* R13 = sys q addr */
	else GREG[13] = qb;  }
return cc;
}

/* Add to queue */

uint32 addtoq (uint32 ea, uint32 val, uint32 flg)
{
uint32 slt, usd, wra, t;

t = ReadF (ea, VR);					/* slots/used */
slt = (t >> 16) & DMASK16;				/* # slots */
usd = t & DMASK16;					/* # used */
if (usd >= slt) return CC_V;				/* list full? */
usd = (usd + 1) & DMASK16;				/* inc # used */
WriteH (ea + Q32_USD, usd, VW);				/* rewrite */
if (flg) {						/* ABL? */
	wra = ReadH ((ea + Q32_BOT) & VAMASK, VR);	/* get bottom */
	t = wra + 1;					/* adv bottom */
	if (t >= slt) t = 0;				/* wrap if necc */
	WriteH ((ea + Q32_BOT) & VAMASK, t, VW);  }	/* rewrite bottom */
else {	wra = ReadH ((ea + Q32_TOP) & VAMASK, VR);	/* ATL, get top */
	if (wra == 0) wra = (slt - 1) & DMASK16;	/* wrap if necc */
	else wra = wra - 1;				/* dec top */
	WriteH ((ea + Q32_TOP) & VAMASK, wra, VW);  }	/* rewrite top */
WriteF ((ea + Q32_BASE + (wra * Q32_SLNT)) & VAMASK, val, VW); /* write slot */
return 0;
}

/* Remove from queue */

uint32 remfmq (uint32 ea, uint32 r1, uint32 flg)
{
uint32 slt, usd, rda, t;

t = ReadF (ea, VR);					/* get slots/used */
slt = (t >> 16) & DMASK16;				/* # slots */
usd = t & DMASK16;					/* # used */
if (usd == 0) return CC_V;				/* empty? */
usd = usd - 1;						/* dec used */
WriteH (ea + Q32_USD, usd, VW);				/* rewrite */
if (flg) {						/* RBL? */
	rda = ReadH ((ea + Q32_BOT) & VAMASK, VR);	/* get bottom */
	if (rda == 0) rda = (slt - 1) & DMASK16;	/* wrap if necc */
	else rda = rda - 1;				/* dec bottom */
	WriteH ((ea + Q32_BOT) & VAMASK, rda, VW);  }	/* rewrite bottom */
else {	rda = ReadH ((ea + Q32_TOP) & VAMASK, VR);	/* RTL, get top */
	t = rda + 1;					/* adv top */
	if (t >= slt) t = 0;				/* wrap if necc */
	WriteH ((ea + Q32_TOP) & VAMASK, t, VW);  }	/* rewrite top */
R[r1] = ReadF ((ea + Q32_BASE + (rda * Q32_SLNT)) & VAMASK, VR); /* read slot */
if (usd) return CC_G;
else return 0;
}

/* Automatic interrupt processing */

uint32 int_auto (uint32 dev, uint32 cc)
{
uint32 addr, vec, by, ccw, ccwa, ccwb;
uint32 i, hw, tblad, tblen, bufe, st, t;
int32 bufc;
uint32 oldPSW = BUILD_PSW (cc);

vec = ReadH (INTSVT + dev + dev, P);			/* get vector */
newPSW (0x2800);					/* new PSW */
R[0] = oldPSW;						/* save old PSW */
R[1] = PC;						/* save PC */
R[2] = dev;						/* set dev # */
if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb,
	">>Int %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
	dev, PC, oldPSW, vec, 0x2800);
if (DEV_ACC (dev)) {					/* dev exist? */
	hw = dev_tab[dev] (dev, IO_ADR, 0);		/* select, get hw */
	R[3] = st = dev_tab[dev] (dev, IO_SS, 0);  }	/* sense status */
else {	hw = 0;
	R[3] = CC_V;  }
if ((vec & 1) == 0) {					/* immed int? */
	PC = vec;					/* new PC */
	return PSW & CC_MASK;  }			/* exit */
R[4] = ccwa = vec & ~1;					/* save CCW addr */
ccw = ReadH (ccwa, VR);					/* read CCW */
if ((ccw & CCW32_EXE) == 0) {				/* exec clr? */
	PC = ReadH (ccwa + CCB32_SUB, VR);		/* get subr */
	return 0;  }					/* CC = 0 */
if (!DEV_ACC (dev) || (st & CCW32_STA (ccw))) {		/* bad status? */
	PC = ReadH (ccwa + CCB32_SUB, VR);		/* get subr */
	return CC_L;  }					/* CC = L */
if (ccw & CCW32_FST) {					/* fast mode? */
	t = ReadH (ccwa + CCB32_B0C, VR);		/* get count */
	bufc = SEXT16 (t);				/* sign ext */
	if (bufc <= 0) {				/* still valid? */
	    bufe = ReadF (ccwa + CCB32_B0E, VR);	/* get end addr */
	    addr = (bufe + bufc) & VAMASK;
	    if (hw) {					/* halfword? */
		if (ccw & CCW32_WR) {			/* write? */
		    t = ReadH (addr, VR);		/* get hw */
		    dev_tab[dev] (dev, IO_WH, t);  }	/* send to dev */
		else {					/* read */
		    t = dev_tab[dev] (dev, IO_RH, 0);	/* get hw */
		    WriteH (addr, t, VW);  }		/* write to mem */
	        bufc = bufc + 2;  }			/* adv buf cnt */
	    else {					/* byte */
		if (ccw & CCW32_WR) {			/* write? */
		    t = ReadB (addr, VR);		/* get byte */
		    dev_tab[dev] (dev, IO_WD, t);  }	/* send to dev */
		else {					/* read */
		    t = dev_tab[dev] (dev, IO_RD, 0);	/* get byte */
		    WriteB (addr, t, VW);  }		/* write to mem */
		bufc = bufc + 1;  }			/* adv buf cnt */
	    WriteH (ccwa + CCB32_B0C, bufc, VW);	/* rewrite cnt */
	    if (bufc > 0) {
		PC = ReadH (ccwa + CCB32_SUB, VR);	/* get subr */
		return CC_G;  }				/* CC = G */
	    }						/* end if bufc <= 0 */
	}						/* end fast */
else {							/* slow mode */
	if (ccw & CCW32_B1) ccwb = ccwa + CCB32_B1C;	/* which buf? */
	else ccwb = ccwa + CCB32_B0C;
	t = ReadH (ccwb, VR);				/* get count */
	bufc = SEXT16 (t);				/* sign ext */
	if (bufc <= 0) {				/* still valid? */
	    bufe = ReadF (ccwb + 2, VR);		/* get end addr */
	    addr = (bufe + bufc) & VAMASK;
	    if (ccw & CCW32_WR) {			/* write? */
		by = ReadB (addr, VR);			/* byte fm mem */
		if (ccw & CCW32_TL) {			/* translate? */
		    tblad = ReadF (ccwa + CCB32_TAB, VR);/* get tbl addr */
		    tblen = (tblad + (by << 1)) & VAMASK; /* tbl entry addr */
		    t = ReadH (tblen, VR);		/* get tbl entry */
		    if ((t & SIGN16) == 0) {		/* special xlate? */
			PC = t << 1;			/* change PC */
			R[3] = by;			/* untrans char */
			return 0;  }			/* CC = 0 */
		    by = t & DMASK8;  }			/* replace */
		dev_tab[dev] (dev, IO_WD, by);  }	/* write to dev */
	    else {					/* read */
		by = dev_tab[dev] (dev, IO_RD, 0);	/* get from dev */
		if (ccw & CCW32_TL) {			/* translate? */
		    tblad = ReadF (ccwa + CCB32_TAB, VR);/* get tbl addr */
		    tblen = (tblad + (by << 1)) & VAMASK; /* tbl entry addr */
		    t = ReadH (tblen, VR);		/* get tbl entry */
		    if ((t & SIGN16) == 0) {		/* special xlate? */
			PC = t << 1;			/* change PC */
			R[3] = by;			/* untrans char */
			return 0;  }			/* CC = 0 */
		    WriteB (addr, t, VW);  }		/* wr trans */
		else WriteB (addr, by, VW);  }		/* wr orig */
	    t = ReadH (ccwa + CCB32_CHK, VR);		/* get check wd */
	    t = t ^ by;					/* start LRC */
	    if (ccw & CCW32_CRC) {			/* CRC? */
		for (i = 0; i < 8; i++) {
		    if (t & 1) t = (t >> 1) ^ 0xA001;
		    else t = t >> 1;  }  }
	    WriteH (ccwa + CCB32_CHK, t, VW);		/* rewrite chk wd */
	    bufc = bufc + 1;				/* adv buf cnt */
	    WriteH (ccwb, bufc, VW);			/* rewrite cnt */
	    if (bufc > 0) {				/* cnt pos? */
		ccw = ccw ^ CCW32_B1;			/* flip buf */
		WriteH (ccwa, ccw, VW);			/* rewrite */
		PC = ReadH (ccwa + CCB32_SUB, VR);	/* get subr */
		return CC_G;  }				/* CC = G */
	    }						/* end if bufc */
	}						/* end slow */
PC = R[1];						/* restore PC */
return newPSW (R[0]);					/* restore PSW, CC */
}

/* Display register device */

uint32 display (uint32 dev, uint32 op, uint32 dat)
{
int t;

switch (op) {
case IO_ADR:						/* select */
	if (!drmod) drpos = srpos = 0;			/* norm mode? clr */
	return BY;					/* byte only */
case IO_OC:						/* command */
	op = op & 0xC0;
	if (op == 0x40) {				/* x40 = inc */
	    drmod = 1;
	    drpos = srpos = 0;  }			/* init cntrs */
	else if (op == 0x80) drmod = 0;			/* x80 = norm */
	break;
case IO_WD:						/* write */
	if (drpos < 4) 
	    DR = (DR & ~(DMASK8 << (drpos * 8))) | (dat << (drpos * 8));
	else if (drpos == 4) DRX = dat;
	drpos = (drpos + 1) & 0x7;
	break;
case IO_RD:						/* read */
	t = (SR >> (srpos * 8)) & DMASK8;
	srpos = srpos ^ 1;
	return t;
case IO_SS:						/* status */
	return 0x80;  }
return 0;
}	

/* Relocation and protection */

uint32 Reloc (uint32 va, uint32 rel)
{
uint32 seg, off, mapr, lim;

seg = VA_GETSEG (va);					/* get seg num */
off = VA_GETOFF (va);					/* get offset */
mapr = mac_reg[seg];					/* get seg reg */
lim = GET_SRL (mapr);					/* get limit */
if (off >= lim) {					/* limit viol? */
	mac_sta = MACS_L;				/* set status */
	ABORT (MPRO);  }				/* abort */
if ((mapr & SR_PRS) == 0) {				/* not present? */
	mac_sta = MACS_NP;				/* set status */
	ABORT (MPRO);  }				/* abort */
if ((rel == VE) && (mapr & SR_EXP)) {			/* exec, prot? */
	mac_sta = MACS_EX;				/* set status */
	qevent = qevent | EV_MAC;  }			/* req intr */
if ((rel == VW) && (mapr & (SR_WPI | SR_WRP))) {	/* write, prot? */
	if (mapr & SR_WRP) {				/* write abort? */
	    mac_sta = MACS_WP;				/* set status */
	    ABORT (MPRO); }				/* abort */
	else {						/* write intr */
	    mac_sta = MACS_WI;				/* set status */
	    qevent = qevent | EV_MAC;  }  }		/* req intr */
return (off + (mapr & SRF_MASK)) & PAMASK32;		/* relocate */
}

uint32 RelocT (uint32 va, uint32 base, uint32 rel, uint32 *pa)
{
uint32 seg, off, mapr, lim;

seg = VA_GETSEG (va);					/* get seg num */
off = VA_GETOFF (va);					/* get offset */
mapr = ReadF ((base + (seg << 2)) & VAMASK, rel);	/* get seg reg */
lim = GET_SRL (mapr);					/* get limit */
if (off >= lim) return CC_C;				/* limit viol? */
if ((mapr & SR_PRS) == 0) return CC_V;			/* not present? */
*pa = off + (mapr & SRF_MASK);				/* translate */
if (mapr & (SR_WRP | SR_WPI)) return CC_G;		/* write prot? */
if (mapr & SR_EXP) return CC_L;				/* exec prot? */
return 0;						/* ok */
}

/* Memory interface routines

   ReadB	read byte (processor)
   ReadH	read halfword (processor)
   ReadF	read fullword (processor)
   WriteB	write byte (processor)
   WriteH	write halfword (processor)
   WriteF	write fullword (processor)
   IOReadB	read byte (IO)
   IOWriteB	write byte (IO)
*/

uint32 ReadB (uint32 loc, uint32 rel)
{
uint32 val;
uint32 sc = (3 - (loc & 3)) << 3;

if ((PSW & PSW_REL) == 0) {				/* reloc off? */
	if ((loc & ~03) == MAC_STA) {			/* MAC status? */
	    val = mac_sta;				/* read it */
	    qevent = qevent & ~EV_MAC;  }		/* clr MAC intr */
	else val = M[loc >> 2];  }			/* get mem word */
else if (rel == 0) val = M[loc >> 2];			/* phys ref? */
else {	uint32 pa = Reloc (loc, rel);			/* relocate */
	val = M[pa >> 2];  }
return (val >> sc) & DMASK8;
}

uint32 ReadH (uint32 loc, uint32 rel)
{
uint32 val;

if ((PSW & PSW_REL) == 0) {				/* reloc off? */
	if ((loc & ~03) == MAC_STA) {			/* MAC status? */
	    val = mac_sta;				/* read it */
	    qevent = qevent & ~EV_MAC;  }		/* clr MAC intr */
	else val = M[loc >> 2];  }			/* get mem word */
else if (rel == 0) val = M[loc >> 2];			/* phys ref? */
else {	uint32 pa = Reloc (loc, rel);			/* relocate */
	val = M[pa >> 2];  }
return (val >> ((loc & 2)? 0: 16)) & DMASK16;
}

uint32 ReadF (uint32 loc, uint32 rel)
{
uint32 val;

if ((PSW & PSW_REL) == 0) {				/* reloc off? */
	if ((loc & ~03) == MAC_STA) {			/* MAC status? */
	    val = mac_sta;				/* read it */
	    qevent = qevent & ~EV_MAC;  }		/* clr MAC intr */
	else val = M[loc >> 2];  }			/* get mem word */
else if (rel == 0) val = M[loc >> 2];			/* phys ref? */
else {	uint32 pa = Reloc (loc, rel);			/* relocate */
	val = M[pa >> 2];  }
return val;
}

void WriteB (uint32 loc, uint32 val, uint32 rel)
{
uint32 pa = loc;
uint32 sc = (3 - (loc & 3)) << 3;

val = val & DMASK8;
if ((PSW & PSW_REL) == 0) {				/* reloc off? */
	uint32 idx = (pa - MAC_BASE) >> 2;		/* check for MAC */
	if (idx <= MAC_LNT) {
	    if (idx < MAC_LNT) mac_reg[idx] =
		((mac_reg[idx] & ~(DMASK8 << sc)) | (val << sc)) & SR_MASK;
	    else {
		mac_sta = 0;
		qevent = qevent & ~EV_MAC;  }  }  }
else if (rel != 0) pa = Reloc (loc, rel);		/* !phys? relocate */
if (MEM_ADDR_OK (pa)) M[pa >> 2] = 
	(M[pa >> 2] & ~(DMASK8 << sc)) | (val << sc);
return;
}

void WriteH (uint32 loc, uint32 val, uint32 rel)
{
uint32 pa = loc;

val = val & DMASK16;
if ((PSW & PSW_REL) == 0) {				/* reloc off? */
	uint32 idx = (pa - MAC_BASE) >> 2;		/* check for MAC */
	if (idx <= MAC_LNT) {
	    if (idx < MAC_LNT) mac_reg[idx] = ((loc & 2)?
		((mac_reg[idx] & ~DMASK16) | val):
		((mac_reg[idx] & DMASK16) | (val << 16))) & SR_MASK;
	    else {
		mac_sta = 0;
		qevent = qevent & ~EV_MAC;  }  }  }
else if (rel != 0) pa = Reloc (loc, rel);		/* !phys? relocate */
if (MEM_ADDR_OK (pa)) M[pa >> 2] = (loc & 2)?
	((M[pa >> 2] & ~DMASK16) | val):
	((M[pa >> 2] & DMASK16) | (val << 16));
return;
}

void WriteF (uint32 loc, uint32 val, uint32 rel)
{
uint32 pa = loc;

val = val & DMASK32;
if (loc & 2) {
	WriteH (loc & VAMASK, (val >> 16) & DMASK16, rel);
	WriteH ((loc + 2) & VAMASK, val & DMASK16, rel);
	return;  }
if ((PSW & PSW_REL) == 0) {				/* reloc off? */
	uint32 idx = (pa - MAC_BASE) >> 2;		/* check for MAC */
	if (idx <= MAC_LNT) {
	    if (idx < MAC_LNT) mac_reg[idx] = val & SR_MASK;
	    else {
		mac_sta = 0;
		qevent = qevent & ~EV_MAC;  }  }  }
else if (rel != 0) pa = Reloc (loc, rel);		/* !phys? relocate */
if (MEM_ADDR_OK (pa)) M[pa >> 2] = val & DMASK32;
return;
}

uint32 IOReadB (uint32 loc)
{
uint32 sc = (3 - (loc & 3)) << 3;

return (M[loc >> 2] >> sc) & DMASK8;
}

void IOWriteB (uint32 loc, uint32 val)
{
uint32 sc = (3 - (loc & 3)) << 3;

val = val & DMASK8;
M[loc >> 2] = (M[loc >> 2] & ~(DMASK8 << sc)) | (val << sc);
return;
}

/* Reset routine */

t_stat cpu_reset (DEVICE *dptr)
{
qevent = 0;						/* no events */
mac_sta = 0;						/* clear MAC */
newPSW (0);						/* PSW = 0 */
set_r_display (R);
DR = 0;							/* clear display */
drmod = 0;
blk_io.dfl = blk_io.cur = blk_io.end = 0;		/* no block I/O */
sim_brk_types = sim_brk_dflt = SWMASK ('E');		/* init bkpts */
if (M == NULL) M = calloc (MAXMEMSIZE32 >> 1, sizeof (uint16));
if (M == NULL) return SCPE_MEM;
pcq_r = find_reg ("PCQ", NULL, dptr);			/* init PCQ */
if (pcq_r) pcq_r->qptr = 0;
else return SCPE_IERR;
return SCPE_OK;
}

/* Memory examine */

t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) {
	int32 cc = RelocT (addr, MAC_BASE, P, &addr);
	if (cc & (CC_C | CC_V)) return SCPE_NXM;  }
if (addr >= MEMSIZE) return SCPE_NXM;
if (vptr != NULL) *vptr = IOReadB (addr);
return SCPE_OK;
}

/* Memory deposit */

t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) {
	int32 cc = RelocT (addr, MAC_BASE, P, &addr);
	if (cc & (CC_C | CC_V)) return SCPE_NXM;  }
if (addr >= MEMSIZE) return SCPE_NXM;
IOWriteB (addr, val & 0xFF);
return SCPE_OK;
}

/* Change memory size */

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

if ((val <= 0) || (val > MAXMEMSIZE32) || ((val & 0xFFFF) != 0))
	return SCPE_ARG;
for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
	return SCPE_OK;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE32; i = i + 4) M[i >> 2] = 0;
return SCPE_OK;
}

/* Set current R pointers for SCP */

void set_r_display (uint32 *rbase)
{
extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr);
REG *rptr;
int32 i;

rptr = find_reg ("R0", NULL, &cpu_dev);
if (rptr == NULL) return;
for (i = 0; i < 16; i++, rptr++) rptr->loc = (void *) (rbase + i);
return;
}

/* Set console interrupt */

t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (PSW & PSW_EXI) SET_INT (v_DS);
return SCPE_OK;
}

/* Set history */

t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i, lnt;
t_stat r;

if (cptr == NULL) {
	for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
	hst_p = 0;
	return SCPE_OK;  }
lnt = (uint32) 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 = 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, void *desc)
{
uint32 op, k, di;
t_value sim_eval[6];
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
	UNIT *uptr, int32 sw);

if (hst_lnt == 0) return SCPE_NOFNC;			/* enabled? */
fprintf (st, "PC     r1       operand  ea     IR\n\n");
di = hst_p;						/* work forward */
for (k = 0; k < hst_lnt; k++) {				/* print specified */
	h = &hst[(di++) % hst_lnt];			/* entry pointer */
	if (h->pc & HIST_PC) {				/* instruction? */
	    fprintf (st, "%06X %08X %08X ", h->pc & VAMASK32, h->r1, h->opnd);
	    sim_eval[0] = op = (h->ir1 >> 8) & 0xFF;
	    sim_eval[1] = h->ir1 & 0xFF;
	    sim_eval[2] = (h->ir2 >> 8) & 0xFF;
	    sim_eval[3] = h->ir2 & 0xFF;
	    sim_eval[4] = (h->ir3 >> 8) & 0xFF;
	    sim_eval[5] = h->ir3 & 0xFF;
	    if (OP_TYPE (op) >= OP_RX) fprintf (st, "%06X ", h->ea);
	    else fprintf (st, "       ");
	    if ((fprint_sym (st, h->pc & VAMASK32, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
		fprintf (st, "(undefined) %04X", h->ir1);
	    fputc ('\n', st);				/* end line */
	    }						/* end if instruction */
	}						/* end for */
return SCPE_OK;
}
