home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Boot_Images / 2.11_on_rl02 / pdpsim.tz / pdpsim / pdp11_cpu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-29  |  69.2 KB  |  2,284 lines

  1. /* pdp11_cpu.c: PDP-11 CPU simulator
  2.  
  3.    Copyright (c) 1993, 1994, 1996,
  4.    Robert M Supnik, Digital Equipment Corporation
  5.    Commercial use prohibited
  6.  
  7.    17-Jul-94    RMS    Corrected updating of MMR1 if MMR0 locked
  8.  
  9.    The register state for the PDP-11 is:
  10.  
  11.    REGFILE[0:5][0]    general register set
  12.    REGFILE[0:5][1]    alternate general register set
  13.    STACKFILE[4]        stack pointers for kernel, supervisor, unused, user
  14.    PC            program counter
  15.    PSW            processor status word
  16.     <15:14> = CM     current processor mode
  17.     <13:12> = PM     previous processor mode
  18.     <11> = RS         register set select
  19.     <7:5> = IPL         interrupt priority level
  20.     <4> = TBIT         trace trap enable
  21.     <3:0> = NZVC     condition codes
  22.    FR[0:5]        floating point accumulators
  23.    FPS            floating point status register
  24.    FEC            floating exception code
  25.    FEA            floating exception address
  26.    MMR0,1,2,3        memory management control registers
  27.    APRFILE[0:63]    memory management relocation registers for
  28.              kernel, supervisor, unused, user
  29.     <31:16> = PAR     processor address registers
  30.     <15:0> = PDR     processor data registers
  31.    PIRQ            processor interrupt request register
  32.    CPUERR        CPU error register
  33.    MEMERR        memory system error register
  34.    CCR            cache control register
  35.    MAINT        maintenance register
  36.    HITMISS        cache status register
  37.    SR            switch register
  38.    DR            display register
  39. */
  40.     
  41. /* The PDP-11 has many instruction formats:
  42.  
  43.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    double operand
  44.    |  opcode   |   source spec   |     dest spec   |    010000:067777
  45.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    110000:167777
  46.  
  47.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    register + operand
  48.    |        opcode      | src reg|     dest spec   |    004000:004777
  49.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    070000:077777
  50.  
  51.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    single operand
  52.    |           opcode            |     dest spec   |    000100:000177
  53.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    000300:000377
  54.                             005000:007777
  55.                             105000:107777
  56.  
  57.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    single register
  58.    |                opcode                |dest reg|    000200:000207
  59.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    000230:000237
  60.  
  61.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    no operand
  62.    |                     opcode                    |    000000:000007
  63.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  64.  
  65.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    branch
  66.    |       opcode          |  branch displacement  |    000400:003477
  67.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    100000:103477
  68.  
  69.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    EMT/TRAP
  70.    |       opcode          |       trap code       |    104000:104777
  71.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  72.  
  73.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    cond code operator
  74.    |                opcode             | immediate |    000240:000277
  75.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  76.  
  77.    An operand specifier consists of an addressing mode and a register.
  78.    The addressing modes are:
  79.  
  80.    0    register direct        R        op = R
  81.    1    register deferred    (R)        op = M[R]
  82.    2    autoincrement        (R)+        op = M[R]; R = R + length
  83.    3    autoincrement deferred    @(R)+        op = M[M[R]]; R = R + 2
  84.    4    autodecrement        -(R)        R = R - length; op = M[R]
  85.    5    autodecrement deferred    @-(R)        R = R - 2; op = M[M[R]]
  86.    6    displacement        d(R)        op = M[R + disp]
  87.    7    displacement deferred    @d(R)        op = M[M[R + disp]]
  88.  
  89.    There are eight general registers, R0-R7.  R6 is the stack pointer,
  90.    R7 the PC.  The combination of addressing modes with R7 yields:
  91.  
  92.    27    immediate        #n        op = M[PC]; PC = PC + 2
  93.    37    absolute        @#n        op = M[M[PC]]; PC = PC + 2
  94.    67    relative        d(PC)        op = M[PC + disp]
  95.    77    relative deferred    @d(PC)        op = M[M[PC + disp]]
  96. */
  97.  
  98. /* This routine is the instruction decode routine for the PDP-11.  It
  99.    is called from the simulator control program to execute instructions
  100.    in simulated memory, starting at the simulated PC.  It runs until an
  101.    enabled exception is encountered.
  102.  
  103.    General notes:
  104.  
  105.    1. Virtual address format.  PDP-11 memory management uses the 16b
  106.       virtual address, the type of reference (instruction or data), and
  107.       the current mode, to construct the 22b physical address.  To
  108.       package this conveniently, the simulator uses a 19b pseudo virtual
  109.       address, consisting of the 16b virtual address prefixed with the
  110.       current mode and ispace/dspace indicator.  These are precalculated
  111.       as isenable and dsenable for ispace and dspace, respectively, and
  112.       must be recalculated whenever MMR0, MMR3, or PSW<cm> changes.
  113.  
  114.    2. Traps and interrupts.  Variable trap_req bit-encodes all possible
  115.       traps.  In addition, an interrupt pending bit is encoded as the
  116.       lowest priority trap.  Traps are processed by trap_vec and trap_clear,
  117.       which provide the vector and subordinate traps to clear, respectively.
  118.  
  119.       Variable int_req bit encodes all possible interrupts.  It is masked
  120.       under the interrupt masks, int_mask[ipl].  If any interrupt request
  121.       is not masked, the interrupt bit is set in trap_req.  While most
  122.       interrupts are handled centrally, a device can supply an interrupt
  123.       acknowledge routine.
  124.  
  125.    3. PSW handling.  The PSW is kept as components, for easier access.
  126.       Because the PSW can be explicitly written as address 17777776,
  127.       all instructions must update PSW before executing their last write.
  128.  
  129.    4. Adding I/O devices.  This requires modifications to three modules:
  130.  
  131.     pdp11_defs.h        add interrupt request definitions
  132.     pdp11_cpu.c        add I/O page linkages
  133.     pdp11_sys.c        add to sim_devices
  134. */
  135.  
  136. /* Definitions */
  137.  
  138. #include "pdp11_defs.h"
  139. #include <setjmp.h>
  140.  
  141. #define calc_is(md) ((md) << VA_V_MODE)
  142. #define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0))
  143. #define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val))
  144. #define calc_ints(lv,rq,tr) (((rq) & int_mask[(lv)])? \
  145.     ((tr) | TRAP_INT) : ((tr) & ~TRAP_INT))
  146. #define GET_SIGN_W(v) ((v) >> 15)
  147. #define GET_SIGN_B(v) ((v) >> 7)
  148. #define GET_Z(v) ((v) == 0)
  149. #define JMP_PC(x) old_PC = PC; PC = (x)
  150. #define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777
  151. #define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777
  152. #define ILL_ADR_FLAG    0200000
  153. #define save_ibkpt    (cpu_unit.u3)            /* will be SAVEd */
  154. #define last_pa        (cpu_unit.u4)            /* and RESTOREd */
  155. #define UNIT_V_18B    (UNIT_V_UF)            /* force 18b addr */
  156. #define UNIT_18B    (1u << UNIT_V_18B)
  157.  
  158. /* Global state */
  159.  
  160. unsigned short M[MEMSIZE >> 1] = { 0 };            /* memory */
  161. int REGFILE[6][2] = { 0 };                /* R0-R5, two sets */
  162. int STACKFILE[4] = { 0 };                /* SP, four modes */
  163. int saved_PC = 0;                    /* program counter */
  164. int R[8] = { 0 };                    /* working registers */
  165. int PSW = 0;                        /* PSW */
  166.   int cm = 0;                        /*   current mode */
  167.   int pm = 0;                        /*   previous mode */
  168.   int rs = 0;                        /*   register set */
  169.   int ipl = 0;                        /*   int pri level */
  170.   int tbit = 0;                        /*   trace flag */
  171.   int N = 0, Z = 0, V = 0, C = 0;            /*   condition codes */
  172. int wait_state = 0;                    /* wait state */
  173. int trap_req = 0;                    /* trap requests */
  174. int int_req = 0;                    /* interrupt requests */
  175. int PIRQ = 0;                        /* programmed int req */
  176. int SR = 0;                        /* switch register */
  177. int DR = 0;                        /* display register */
  178. fpac_t FR[6] = { 0 };                    /* fp accumulators */
  179. int FPS = 0;                        /* fp status */
  180. int FEC = 0;                        /* fp exception code */
  181. int FEA = 0;                        /* fp exception addr */
  182. int APRFILE[64] = { 0 };                /* PARs/PDRs */
  183. int MMR0 = 0;                        /* MMR0 - status */
  184. int MMR1 = 0;                        /* MMR1 - R+/-R */
  185. int MMR2 = 0;                        /* MMR2 - saved PC */
  186. int MMR3 = 0;                        /* MMR3 - 22b status */
  187. int isenable = 0, dsenable = 0;                /* i, d space flags */
  188. int CPUERR = 0;                        /* CPU error reg */
  189. int MEMERR = 0;                        /* memory error reg */
  190. int CCR = 0;                        /* cache control reg */
  191. int HITMISS = 0;                    /* hit/miss reg */
  192. int MAINT = (0 << 9) + (0 << 8) + (4 << 4);        /* maint bit<9> = Q/U */
  193.                             /*  <8> = hwre FP */
  194.                             /*  <6:4> = sys type */
  195. int stop_trap = 1;                    /* stop on trap */
  196. int stop_vecabort = 1;                    /* stop on vec abort */
  197. int stop_spabort = 1;                    /* stop on SP abort */
  198. int wait_enable = 0;                    /* wait state enable */
  199. int ibkpt_addr = ILL_ADR_FLAG | VAMASK;            /* breakpoint addr */
  200. int old_PC = 0;                        /* previous PC */
  201. jmp_buf save_env;                    /* abort handler */
  202. int dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS };    /* dspace enables */
  203. int int_mask[8] = { INT_IPL0, INT_IPL1, INT_IPL2,    /* interrupt masks */
  204.     INT_IPL3, INT_IPL4, INT_IPL5, INT_IPL6, INT_IPL7 };
  205. extern int sim_int_char;
  206.  
  207. /* Function declarations */
  208.  
  209. int cpu_ex (int *vptr, int addr, UNIT *uptr, int sw);
  210. int cpu_dep (int val, int addr, UNIT *uptr, int sw);
  211. int cpu_reset (DEVICE *dptr);
  212. int cpu_svc (UNIT *uptr);
  213. int GeteaB (int spec);
  214. int GeteaW (int spec);
  215. int relocR (int addr);
  216. int relocW (int addr);
  217. int ReadW (int addr);
  218. int ReadB (int addr);
  219. int ReadMW (int addr);
  220. int ReadMB (int addr);
  221. void WriteW (int data, int addr);
  222. void WriteB (int data, int addr);
  223. void PWriteW (int data, int addr);
  224. void PWriteB (int data, int addr);
  225. int iopageR (int *data, int addr, int access);
  226. int iopageW (int data, int addr, int access);
  227.  
  228. int CPU_rd (int *data, int addr, int access);
  229. int CPU_wr (int data, int addr, int access);
  230. int APR_rd (int *data, int addr, int access);
  231. int APR_wr (int data, int addr, int access);
  232. int SR_MMR012_rd (int *data, int addr, int access);
  233. int SR_MMR012_wr (int data, int addr, int access);
  234. int MMR3_rd (int *data, int addr, int access);
  235. int MMR3_wr (int data, int addr, int access);
  236. extern int std_rd (int *data, int addr, int access);
  237. extern int std_wr (int data, int addr, int access);
  238. extern int lpt_rd (int *data, int addr, int access);
  239. extern int lpt_wr (int data, int addr, int access);
  240. extern int rk_rd (int *data, int addr, int access);
  241. extern int rk_wr (int data, int addr, int access);
  242. extern int rl_rd (int *data, int addr, int access);
  243. extern int rl_wr (int data, int addr, int access);
  244. extern int rx_rd (int *data, int addr, int access);
  245. extern int rx_wr (int data, int addr, int access);
  246. extern int rk_inta (void);
  247.  
  248. /* Auxiliary data structures */
  249.  
  250. struct iolink {                        /* I/O page linkage */
  251.     int    low;                    /* low I/O addr */
  252.     int    high;                    /* high I/O addr */
  253.     int    (*read)();                /* read routine */
  254.     int    (*write)();  };                /* write routine */
  255.  
  256. struct iolink iotable[] = {
  257.     { 017777740, 017777777, &CPU_rd, &CPU_wr },
  258.     { 017777546, 017777567, &std_rd, &std_wr },
  259.     { 017777514, 017777517, &lpt_rd, &lpt_wr },
  260.     { 017777400, 017777417, &rk_rd, &rk_wr },
  261.     { 017774400, 017774411, &rl_rd, &rl_wr },
  262.     { 017777170, 017777173, &rx_rd, &rx_wr },
  263.     { 017777600, 017777677, &APR_rd, &APR_wr },
  264.     { 017772200, 017772377, &APR_rd, &APR_wr },
  265.     { 017777570, 017777577, &SR_MMR012_rd, &SR_MMR012_wr },
  266.     { 017772516, 017772517, &MMR3_rd, &MMR3_wr },
  267.     { 0, 0, NULL }  };
  268.  
  269. int int_vec[32] = {                    /* int req to vector */
  270.     0, 0, 0, VEC_PIRQ, VEC_CLK, 0, 0, VEC_PIRQ,
  271.     VEC_RK, VEC_RL, VEC_RX, 0, 0, 0, 0, VEC_PIRQ,
  272.     VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, VEC_LPT, 0, 0, 0,
  273.     0, 0, 0, 0, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ  };
  274.  
  275. int (*int_ack[32])() = {                /* int ack routines */
  276.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  277.     &rk_inta, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  278.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  279.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL  };
  280.  
  281. int trap_vec[TRAP_V_MAX] = {                /* trap req to vector */
  282.     VEC_RED, VEC_ODD, VEC_MME, VEC_NXM,
  283.     VEC_PAR, VEC_PRV, VEC_ILL, VEC_BPT,
  284.     VEC_IOT, VEC_EMT, VEC_TRAP, VEC_TRC,
  285.     VEC_YEL, VEC_PWRFL, VEC_FPE };
  286.  
  287. int trap_clear[TRAP_V_MAX] = {                /* trap clears */
  288.     TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC,
  289.     TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC,
  290.     TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC,
  291.     TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC,
  292.     TRAP_PAR+TRAP_TRC, TRAP_PRV+TRAP_TRC,
  293.     TRAP_ILL+TRAP_TRC, TRAP_BPT+TRAP_TRC,
  294.     TRAP_IOT+TRAP_TRC, TRAP_EMT+TRAP_TRC,
  295.     TRAP_TRAP+TRAP_TRC, TRAP_TRC,
  296.     TRAP_YEL, TRAP_PWRFL, TRAP_FPE };
  297.  
  298. /* CPU data structures
  299.  
  300.    cpu_dev    CPU device descriptor
  301.    cpu_unit    CPU unit descriptor
  302.    cpu_reg    CPU register list
  303.    cpu_mod    CPU modifier list
  304. */
  305.  
  306. UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX, MEMSIZE) };
  307.  
  308. REG cpu_reg[] = {
  309.     { ORDATA (PC, saved_PC, 16) },
  310.     { ORDATA (R0, REGFILE[0][0], 16) },
  311.     { ORDATA (R1, REGFILE[1][0], 16) },
  312.     { ORDATA (R2, REGFILE[2][0], 16) },
  313.     { ORDATA (R3, REGFILE[3][0], 16) },
  314.     { ORDATA (R4, REGFILE[4][0], 16) },
  315.     { ORDATA (R5, REGFILE[5][0], 16) },
  316.     { ORDATA (R10, REGFILE[0][1], 16) },
  317.     { ORDATA (R11, REGFILE[1][1], 16) },
  318.     { ORDATA (R12, REGFILE[2][1], 16) },
  319.     { ORDATA (R13, REGFILE[3][1], 16) },
  320.     { ORDATA (R14, REGFILE[4][1], 16) },
  321.     { ORDATA (R15, REGFILE[5][1], 16) },
  322.     { ORDATA (KSP, STACKFILE[KERNEL], 16) },
  323.     { ORDATA (SSP, STACKFILE[SUPER], 16) },
  324.     { ORDATA (USP, STACKFILE[USER], 16) },
  325.     { ORDATA (PSW, PSW, 16) },
  326.     { GRDATA (CM, PSW, 8, 2, PSW_V_CM) },
  327.     { GRDATA (PM, PSW, 8, 2, PSW_V_PM) },
  328.     { FLDATA (RS, PSW, PSW_V_RS) },
  329.     { GRDATA (IPL, PSW, 8, 3, PSW_V_IPL) },
  330.     { FLDATA (T, PSW, PSW_V_TBIT) },
  331.     { FLDATA (N, PSW, PSW_V_N) },
  332.     { FLDATA (Z, PSW, PSW_V_Z) },
  333.     { FLDATA (V, PSW, PSW_V_V) },
  334.     { FLDATA (C, PSW, PSW_V_C) },
  335.     { ORDATA (SR, SR, 16) },
  336.     { ORDATA (DR, DR, 16) },
  337.     { ORDATA (MEMERR, MEMERR, 16) },
  338.     { ORDATA (CCR, CCR, 16) },
  339.     { ORDATA (MAINT, MAINT, 16) },
  340.     { ORDATA (HITMISS, HITMISS, 16) },
  341.     { ORDATA (CPUERR, CPUERR, 16) },
  342.     { ORDATA (INT, int_req, 32), REG_RO },
  343.     { ORDATA (TRAPS, trap_req, TRAP_V_MAX) },
  344.     { ORDATA (PIRQ, PIRQ, 16) },
  345.     { FLDATA (WAIT, wait_state, 0) },
  346.     { FLDATA (WAIT_ENABLE, wait_enable, 0) },
  347.     { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) },
  348.     { FLDATA (STOP_VECA, stop_vecabort, 0) },
  349.     { FLDATA (STOP_SPA, stop_spabort, 0) },
  350.     { ORDATA (FAC0H, FR[0].h, 32) },
  351.     { ORDATA (FAC0L, FR[0].l, 32) },
  352.     { ORDATA (FAC1H, FR[1].h, 32) },
  353.     { ORDATA (FAC1L, FR[1].l, 32) },
  354.     { ORDATA (FAC2H, FR[2].h, 32) },
  355.     { ORDATA (FAC2L, FR[2].l, 32) },
  356.     { ORDATA (FAC3H, FR[3].h, 32) },
  357.     { ORDATA (FAC3L, FR[3].l, 32) },
  358.     { ORDATA (FAC4H, FR[4].h, 32) },
  359.     { ORDATA (FAC4L, FR[4].l, 32) },
  360.     { ORDATA (FAC5H, FR[5].h, 32) },
  361.     { ORDATA (FAC5L, FR[5].l, 32) },
  362.     { ORDATA (FPS, FPS, 16) },
  363.     { ORDATA (FEA, FEA, 16) },
  364.     { ORDATA (FEC, FEC, 4) },
  365.     { ORDATA (MMR0, MMR0, 16) },
  366.     { ORDATA (MMR1, MMR1, 16) },
  367.     { ORDATA (MMR2, MMR2, 16) },
  368.     { ORDATA (MMR3, MMR3, 16) },
  369.     { GRDATA (KIPAR0, APRFILE[000], 8, 16, 16) },
  370.     { GRDATA (KIPDR0, APRFILE[000], 8, 16, 0) },
  371.     { GRDATA (KIPAR1, APRFILE[001], 8, 16, 16) },
  372.     { GRDATA (KIPDR1, APRFILE[001], 8, 16, 0) },
  373.     { GRDATA (KIPAR2, APRFILE[002], 8, 16, 16) },
  374.     { GRDATA (KIPDR2, APRFILE[002], 8, 16, 0) },
  375.     { GRDATA (KIPAR3, APRFILE[003], 8, 16, 16) },
  376.     { GRDATA (KIPDR3, APRFILE[003], 8, 16, 0) },
  377.     { GRDATA (KIPAR4, APRFILE[004], 8, 16, 16) },
  378.     { GRDATA (KIPDR4, APRFILE[004], 8, 16, 0) },
  379.     { GRDATA (KIPAR5, APRFILE[005], 8, 16, 16) },
  380.     { GRDATA (KIPDR5, APRFILE[005], 8, 16, 0) },
  381.     { GRDATA (KIPAR6, APRFILE[006], 8, 16, 16) },
  382.     { GRDATA (KIPDR6, APRFILE[006], 8, 16, 0) },
  383.     { GRDATA (KIPAR7, APRFILE[007], 8, 16, 16) },
  384.     { GRDATA (KIPDR7, APRFILE[007], 8, 16, 0) },
  385.     { GRDATA (KDPAR0, APRFILE[010], 8, 16, 16) },
  386.     { GRDATA (KDPDR0, APRFILE[010], 8, 16, 0) },
  387.     { GRDATA (KDPAR1, APRFILE[011], 8, 16, 16) },
  388.     { GRDATA (KDPDR1, APRFILE[011], 8, 16, 0) },
  389.     { GRDATA (KDPAR2, APRFILE[012], 8, 16, 16) },
  390.     { GRDATA (KDPDR2, APRFILE[012], 8, 16, 0) },
  391.     { GRDATA (KDPAR3, APRFILE[013], 8, 16, 16) },
  392.     { GRDATA (KDPDR3, APRFILE[013], 8, 16, 0) },
  393.     { GRDATA (KDPAR4, APRFILE[014], 8, 16, 16) },
  394.     { GRDATA (KDPDR4, APRFILE[014], 8, 16, 0) },
  395.     { GRDATA (KDPAR5, APRFILE[015], 8, 16, 16) },
  396.     { GRDATA (KDPDR5, APRFILE[015], 8, 16, 0) },
  397.     { GRDATA (KDPAR6, APRFILE[016], 8, 16, 16) },
  398.     { GRDATA (KDPDR6, APRFILE[016], 8, 16, 0) },
  399.     { GRDATA (KDPAR7, APRFILE[017], 8, 16, 16) },
  400.     { GRDATA (KDPDR7, APRFILE[017], 8, 16, 0) },
  401.     { GRDATA (SIPAR0, APRFILE[020], 8, 16, 16) },
  402.     { GRDATA (SIPDR0, APRFILE[020], 8, 16, 0) },
  403.     { GRDATA (SIPAR1, APRFILE[021], 8, 16, 16) },
  404.     { GRDATA (SIPDR1, APRFILE[021], 8, 16, 0) },
  405.     { GRDATA (SIPAR2, APRFILE[022], 8, 16, 16) },
  406.     { GRDATA (SIPDR2, APRFILE[022], 8, 16, 0) },
  407.     { GRDATA (SIPAR3, APRFILE[023], 8, 16, 16) },
  408.     { GRDATA (SIPDR3, APRFILE[023], 8, 16, 0) },
  409.     { GRDATA (SIPAR4, APRFILE[024], 8, 16, 16) },
  410.     { GRDATA (SIPDR4, APRFILE[024], 8, 16, 0) },
  411.     { GRDATA (SIPAR5, APRFILE[025], 8, 16, 16) },
  412.     { GRDATA (SIPDR5, APRFILE[025], 8, 16, 0) },
  413.     { GRDATA (SIPAR6, APRFILE[026], 8, 16, 16) },
  414.     { GRDATA (SIPDR6, APRFILE[026], 8, 16, 0) },
  415.     { GRDATA (SIPAR7, APRFILE[027], 8, 16, 16) },
  416.     { GRDATA (SIPDR7, APRFILE[027], 8, 16, 0) },
  417.     { GRDATA (SDPAR0, APRFILE[030], 8, 16, 16) },
  418.     { GRDATA (SDPDR0, APRFILE[030], 8, 16, 0) },
  419.     { GRDATA (SDPAR1, APRFILE[031], 8, 16, 16) },
  420.     { GRDATA (SDPDR1, APRFILE[031], 8, 16, 0) },
  421.     { GRDATA (SDPAR2, APRFILE[032], 8, 16, 16) },
  422.     { GRDATA (SDPDR2, APRFILE[032], 8, 16, 0) },
  423.     { GRDATA (SDPAR3, APRFILE[033], 8, 16, 16) },
  424.     { GRDATA (SDPDR3, APRFILE[033], 8, 16, 0) },
  425.     { GRDATA (SDPAR4, APRFILE[034], 8, 16, 16) },
  426.     { GRDATA (SDPDR4, APRFILE[034], 8, 16, 0) },
  427.     { GRDATA (SDPAR5, APRFILE[035], 8, 16, 16) },
  428.     { GRDATA (SDPDR5, APRFILE[035], 8, 16, 0) },
  429.     { GRDATA (SDPAR6, APRFILE[036], 8, 16, 16) },
  430.     { GRDATA (SDPDR6, APRFILE[036], 8, 16, 0) },
  431.     { GRDATA (SDPAR7, APRFILE[037], 8, 16, 16) },
  432.     { GRDATA (SDPDR7, APRFILE[037], 8, 16, 0) },
  433.     { GRDATA (UIPAR0, APRFILE[060], 8, 16, 16) },
  434.     { GRDATA (UIPDR0, APRFILE[060], 8, 16, 0) },
  435.     { GRDATA (UIPAR1, APRFILE[061], 8, 16, 16) },
  436.     { GRDATA (UIPDR1, APRFILE[061], 8, 16, 0) },
  437.     { GRDATA (UIPAR2, APRFILE[062], 8, 16, 16) },
  438.     { GRDATA (UIPDR2, APRFILE[062], 8, 16, 0) },
  439.     { GRDATA (UIPAR3, APRFILE[063], 8, 16, 16) },
  440.     { GRDATA (UIPDR3, APRFILE[063], 8, 16, 0) },
  441.     { GRDATA (UIPAR4, APRFILE[064], 8, 16, 16) },
  442.     { GRDATA (UIPDR4, APRFILE[064], 8, 16, 0) },
  443.     { GRDATA (UIPAR5, APRFILE[065], 8, 16, 16) },
  444.     { GRDATA (UIPDR5, APRFILE[065], 8, 16, 0) },
  445.     { GRDATA (UIPAR6, APRFILE[066], 8, 16, 16) },
  446.     { GRDATA (UIPDR6, APRFILE[066], 8, 16, 0) },
  447.     { GRDATA (UIPAR7, APRFILE[067], 8, 16, 16) },
  448.     { GRDATA (UIPDR7, APRFILE[067], 8, 16, 0) },
  449.     { GRDATA (UDPAR0, APRFILE[070], 8, 16, 16) },
  450.     { GRDATA (UDPDR0, APRFILE[070], 8, 16, 0) },
  451.     { GRDATA (UDPAR1, APRFILE[071], 8, 16, 16) },
  452.     { GRDATA (UDPDR1, APRFILE[071], 8, 16, 0) },
  453.     { GRDATA (UDPAR2, APRFILE[072], 8, 16, 16) },
  454.     { GRDATA (UDPDR2, APRFILE[072], 8, 16, 0) },
  455.     { GRDATA (UDPAR3, APRFILE[073], 8, 16, 16) },
  456.     { GRDATA (UDPDR3, APRFILE[073], 8, 16, 0) },
  457.     { GRDATA (UDPAR4, APRFILE[074], 8, 16, 16) },
  458.     { GRDATA (UDPDR4, APRFILE[074], 8, 16, 0) },
  459.     { GRDATA (UDPAR5, APRFILE[075], 8, 16, 16) },
  460.     { GRDATA (UDPDR5, APRFILE[075], 8, 16, 0) },
  461.     { GRDATA (UDPAR6, APRFILE[076], 8, 16, 16) },
  462.     { GRDATA (UDPDR6, APRFILE[076], 8, 16, 0) },
  463.     { GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) },
  464.     { GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) },
  465.     { FLDATA (18B_ADDR, cpu_unit.flags, UNIT_V_18B), REG_HRO },
  466.     { ORDATA (OLDPC, old_PC, 16), REG_RO },
  467.     { ORDATA (BREAK, ibkpt_addr, 17) },
  468.     { ORDATA (WRU, sim_int_char, 8) },
  469.     { NULL}  };
  470.  
  471. MTAB cpu_mod[] = {
  472.     { UNIT_18B, UNIT_18B, "18b addressing", "18B", NULL },
  473.     { UNIT_18B, 0, NULL, "22B", NULL },
  474.     { 0 }  };
  475.  
  476. DEVICE cpu_dev = {
  477.     "CPU", &cpu_unit, cpu_reg, cpu_mod,
  478.     1, 8, 22, 2, 8, 16,
  479.     &cpu_ex, &cpu_dep, &cpu_reset,
  480.     NULL, NULL, NULL };
  481.  
  482. int sim_instr (void)
  483. {
  484. extern int sim_interval;
  485. extern UNIT *sim_clock_queue;
  486. register int IR, srcspec, srcreg, dstspec, dstreg;
  487. register int src, src2, dst;
  488. register int i, t, sign, oldrs, trapnum;
  489. int reason, trapea, abortval;
  490. extern int sim_process_event (void);
  491. extern int sim_activate (UNIT *uptr, int interval);
  492. extern int reset_all (int start_device);
  493. void fp11 (int IR);
  494.  
  495. /* Restore register state
  496.  
  497.     1. PSW components
  498.     2. Active register file based on PSW<rs>
  499.     3. Active stack pointer based on PSW<cm>
  500.     4. Memory management control flags
  501.     5. Interrupt system
  502. */
  503.  
  504. cm = (PSW >> PSW_V_CM) & 03;                /* call calc_is,ds */
  505. pm = (PSW >> PSW_V_PM) & 03;
  506. rs = (PSW >> PSW_V_RS) & 01;
  507. ipl = (PSW >> PSW_V_IPL) & 07;                /* call calc_ints */
  508. tbit = (PSW >> PSW_V_TBIT) & 01;
  509. N = (PSW >> PSW_V_N) & 01;
  510. Z = (PSW >> PSW_V_Z) & 01;
  511. V = (PSW >> PSW_V_V) & 01;
  512. C = (PSW >> PSW_V_C) & 01;
  513.  
  514. for (i = 0; i < 6; i++) R[i] = REGFILE[i][rs];
  515. SP = STACKFILE[cm];
  516. PC = saved_PC;
  517.  
  518. isenable = calc_is (cm);
  519. dsenable = calc_ds (cm);
  520.  
  521. CPU_wr (PIRQ, 017777772, WRITE);            /* rewrite PIRQ */
  522. trap_req = calc_ints (ipl, int_req, trap_req);
  523. trapea = 0;
  524. reason = 0;
  525.  
  526. /* Abort handling
  527.  
  528.    If an abort occurs in memory management or memory access, the lower
  529.    level routine executes a longjmp to this area OUTSIDE the main
  530.    simulation loop.  The longjmp specifies a trap mask which is OR'd
  531.    into the trap_req register.  Simulation then resumes at the fetch
  532.    phase, and the trap is sprung.
  533.  
  534.    Aborts which occur within a trap sequence (trapea != 0) require
  535.    special handling.  If the abort occured on the stack pushes, and
  536.    the mode (encoded in trapea) is kernel, an "emergency" kernel
  537.    stack is created at 4, and a red zone stack trap taken.
  538. */
  539.  
  540. abortval = setjmp (save_env);                /* set abort hdlr */
  541. if (abortval != 0) {
  542.     trap_req = trap_req | abortval;            /* or in trap flag */
  543.     if ((trapea > 0) && (stop_vecabort)) reason = STOP_VECABORT;
  544.     if ((trapea < 0) && (stop_spabort)) reason = STOP_SPABORT;
  545.     if (trapea == ~KERNEL) {            /* kernel stk abort? */
  546.         setTRAP (TRAP_RED);
  547.         setCPUERR (CPUE_RED);
  548.         STACKFILE[KERNEL] = 4;
  549.         if (cm == KERNEL) SP = 4;  }  }
  550.  
  551. /* Main instruction fetch/decode loop
  552.  
  553.    Check for traps or interrupts.  If trap, locate the vector and check
  554.    for stop condition.  If interrupt, locate the vector.
  555. */ 
  556.  
  557. while (reason == 0)  {
  558. if (sim_interval <= 0) {                /* check clock queue */
  559.     reason = sim_process_event ();
  560.     trap_req = calc_ints (ipl, int_req, trap_req);
  561.     continue;  }
  562. if (trap_req) {                        /* check traps, ints */
  563.     trapea = 0;                    /* assume srch fails */
  564.     if (t = trap_req & TRAP_ALL) {            /* if a trap */
  565.         for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) {
  566.             if ((t >> trapnum) & 1) {
  567.                 trapea = trap_vec[trapnum];
  568.                 trap_req = trap_req & ~trap_clear[trapnum];
  569.                 if ((stop_trap >> trapnum) & 1)
  570.                     reason = trapnum + 1;
  571.                 break;  }  }  }
  572.     else if (t = int_req & int_mask[ipl]) {        /* if an interrupt */
  573.         for (i = 0; i < 32; i++) {
  574.             if ((t >> i) & 1) {
  575.                 int_req = int_req & ~(1u << i);
  576.                 if (int_ack[i]) trapea = int_ack[i]();
  577.                 else trapea = int_vec[i];
  578.                 trapnum = TRAP_V_MAX;
  579.                 break;  }  }  }
  580.     if (trapea == 0) {                /* nothing to do? */
  581.         trap_req = calc_ints (ipl, int_req, 0);    /* recalculate */
  582.         continue;  }                /* back to fetch */
  583.  
  584. /* Process a trap or interrupt
  585.  
  586.    1. Exit wait state
  587.    2. Save the current SP and PSW
  588.    3. Read the new PC, new PSW from trapea, kernel data space
  589.    4. Get the mode and stack selected by the new PSW
  590.    5. Push the old PC and PSW on the new stack
  591.    6. Update SP, PSW, and PC
  592.    7. If not stack overflow, check for stack overflow
  593. */
  594.  
  595.     wait_state = 0;                    /* exit wait state */
  596.     STACKFILE[cm] = SP;
  597.     PSW = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) |
  598.         (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
  599.         (N << PSW_V_N) | (Z << PSW_V_Z) |
  600.         (V << PSW_V_V) | (C << PSW_V_C);
  601.     oldrs = rs;
  602.     src = ReadW (trapea | calc_ds (KERNEL));
  603.     src2 = ReadW ((trapea + 2) | calc_ds (KERNEL));
  604.     t = (src2 >> PSW_V_CM) & 03;
  605.     trapea = ~t;                    /* flag pushes */
  606.     WriteW (PSW, ((STACKFILE[t] - 2) & 0177777) | calc_ds (t));
  607.     WriteW (PC, ((STACKFILE[t] - 4) & 0177777) | calc_ds (t));
  608.     trapea = 0;                    /* clear trap flag */
  609.     pm = cm;
  610.     cm = t;                        /* call calc_is,ds */
  611.     rs = (src2 >> PSW_V_RS) & 01;
  612.     ipl = (src2 >> PSW_V_IPL) & 07;            /* call calc_ints */
  613.     tbit = (src2 >> PSW_V_TBIT) & 01;
  614.     N = (src2 >> PSW_V_N) & 01;
  615.     Z = (src2 >> PSW_V_Z) & 01;
  616.     V = (src2 >> PSW_V_V) & 01;
  617.     C = (src2 >> PSW_V_C) & 01;
  618.     if (rs != oldrs) {                /* if rs chg, swap */
  619.         for (i = 0; i < 6; i++) {
  620.             REGFILE[i][oldrs] = R[i];
  621.             R[i] = REGFILE[i][rs];  }  }
  622.     SP = (STACKFILE[cm] - 4) & 0177777;        /* update SP, PC */
  623.     JMP_PC (src);
  624.     isenable = calc_is (cm);
  625.     dsenable = calc_ds (cm);
  626.     trap_req = calc_ints (ipl, int_req, trap_req);
  627.     if ((SP < STKLIM) && (cm == KERNEL) &&
  628.         (trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL)) {
  629.         setTRAP (TRAP_YEL);
  630.         setCPUERR (CPUE_YEL);  }
  631.     continue;  }                    /* end if traps */
  632.  
  633. /* Fetch and decode next instruction */
  634.  
  635. if (tbit) setTRAP (TRAP_TRC);
  636. if (wait_state) {                    /* wait state? */
  637.     if (sim_clock_queue != NULL) sim_interval = 0;    /* force check */
  638.     else reason = STOP_WAIT;
  639.     continue;  }
  640.  
  641. if (PC == ibkpt_addr) {                    /* breakpoint? */
  642.     save_ibkpt = ibkpt_addr;            /* save bkpt */
  643.     ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG;        /* disable */
  644.     sim_activate (&cpu_unit, 1);            /* sched re-enable */
  645.     reason = STOP_IBKPT;                /* stop simulation */
  646.     continue;  }
  647.  
  648. if (update_MM) {                    /* if mm not frozen */
  649.     MMR1 = 0;
  650.     MMR2 = PC;  }
  651. IR = ReadW (PC | isenable);                /* fetch instruction */
  652. PC = (PC + 2) & 0177777;                /* incr PC, mod 65k */
  653. sim_interval = sim_interval - 1;
  654. srcspec = (IR >> 6) & 077;                /* src, dst specs */
  655. dstspec = IR & 077;
  656. srcreg = (srcspec <= 07);                /* src, dst = rmode? */
  657. dstreg = (dstspec <= 07);
  658. switch ((IR >> 12) & 017) {                /* decode IR<15:12> */
  659.  
  660. /* Opcode 0: no operands, specials, branches, JSR, SOPs */
  661.  
  662. case 000:
  663.     switch ((IR >> 6) & 077) {            /* decode IR<11:6> */
  664.     case 000:                    /* no operand */
  665.         if (IR > 000010) {            /* 000010 - 000077 */
  666.             setTRAP (TRAP_ILL);        /* illegal */
  667.             break;  }
  668.         switch (IR) {                /* decode IR<2:0> */
  669.         case 0:                    /* HALT */
  670.                 if (cm == KERNEL) reason = STOP_HALT;
  671.             else {    setTRAP (TRAP_PRV);
  672.                 setCPUERR (CPUE_HALT);  }
  673.             break;
  674.         case 1:                    /* WAIT */
  675.             if (cm == KERNEL && wait_enable) wait_state = 1;
  676.             break;
  677.         case 3:                    /* BPT */
  678.             setTRAP (TRAP_BPT);
  679.             break;
  680.         case 4:                    /* IOT */
  681.             setTRAP (TRAP_IOT);
  682.             break;
  683.         case 5:                    /* RESET */
  684.             if (cm == KERNEL) {
  685.                 reset_all (1);
  686.                 PIRQ = 0;
  687.                 int_req = 0;
  688.                 MMR0 = MMR0 & ~(MMR0_MME | MMR0_FREEZE);
  689.                 MMR3 = 0;
  690.                 trap_req = trap_req & ~TRAP_INT;
  691.                 dsenable = calc_ds (cm);  }
  692.             break;
  693.  
  694. /* Opcode 0: specials, continued */
  695.  
  696.         case 2:                    /* RTI */
  697.         case 6:                    /* RTT */
  698.                 src = ReadW (SP | dsenable);
  699.                 src2 = ReadW (((SP + 2) & 0177777) | dsenable);
  700.             STACKFILE[cm] = SP = (SP + 4) & 0177777;
  701.             oldrs = rs;
  702.             if (cm == KERNEL) {
  703.                 cm = (src2 >> PSW_V_CM) & 03;
  704.                 pm = (src2 >> PSW_V_PM) & 03;
  705.                 rs = (src2 >> PSW_V_RS) & 01;
  706.                 ipl = (src2 >> PSW_V_IPL) & 07;  }
  707.             else {    cm = cm | ((src2 >> PSW_V_CM) & 03);
  708.                 pm = pm | ((src2 >> PSW_V_PM) & 03);
  709.                 rs = rs | ((src2 >> PSW_V_RS) & 01);  }
  710.             tbit = (src2 >> PSW_V_TBIT) & 01;
  711.             N = (src2 >> PSW_V_N) & 01;
  712.             Z = (src2 >> PSW_V_Z) & 01;
  713.             V = (src2 >> PSW_V_V) & 01;
  714.             C = (src2 >> PSW_V_C) & 01;
  715.             trap_req = calc_ints (ipl, int_req, trap_req);
  716.             isenable = calc_is (cm);
  717.             dsenable = calc_ds (cm);
  718.             if (rs != oldrs) {
  719.                 for (i = 0; i < 6; i++) {
  720.                         REGFILE[i][oldrs] = R[i];
  721.                         R[i] = REGFILE[i][rs];  }  }
  722.             SP = STACKFILE[cm];
  723.             JMP_PC (src);
  724.             if ((IR == 000002) && tbit) setTRAP (TRAP_TRC);
  725.             break;
  726.         case 7:                    /* MFPT */
  727.             R[0] = 5;            /* report J-11 */
  728.             break;    }            /* end switch no ops */
  729.         break;                    /* end case no ops */
  730.  
  731. /* Opcode 0: specials, continued */
  732.  
  733.     case 001:                    /* JMP */
  734.         if (dstreg) setTRAP (TRAP_ILL);
  735.         else {    JMP_PC (GeteaW (dstspec) & 0177777);  }
  736.         break;                    /* end JMP */
  737.     case 002:                    /* RTS et al*/
  738.         if (IR < 000210) {            /* RTS */
  739.             dstspec = dstspec & 07;
  740.             JMP_PC (R[dstspec]);
  741.             R[dstspec] = ReadW (SP | dsenable);
  742.             SP = (SP + 2) & 0177777;
  743.             break;  }             /* end if RTS */
  744.         if (IR < 000230) {
  745.             setTRAP (TRAP_ILL);
  746.             break;  }
  747.         if (IR < 000240) {            /* SPL */
  748.             if (cm == KERNEL) ipl = IR & 07;
  749.             trap_req = calc_ints (ipl, int_req, trap_req);
  750.             break;  }            /* end if SPL */
  751.         if (IR < 000260) {            /* clear CC */
  752.             if (IR & 010) N = 0;
  753.             if (IR & 004) Z = 0;
  754.             if (IR & 002) V = 0;
  755.             if (IR & 001) C = 0;
  756.             break;  }            /* end if clear CCs */
  757.         if (IR & 010) N = 1;            /* set CC */
  758.         if (IR & 004) Z = 1;
  759.         if (IR & 002) V = 1;
  760.         if (IR & 001) C = 1;
  761.         break;                    /* end case RTS et al */
  762.     case 003:                    /* SWAB */
  763.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  764.         dst = ((dst & 0377) << 8) | ((dst >> 8) & 0377);
  765.         N = GET_SIGN_B (dst & 0377);
  766.         Z = GET_Z (dst & 0377);
  767.         V = C = 0;
  768.         if (dstreg) R[dstspec] = dst;
  769.         else PWriteW (dst, last_pa);
  770.         break;                  /* end SWAB */
  771.  
  772. /* Opcode 0: branches, JSR */
  773.  
  774.     case 004: case 005:                /* BR */
  775.         BRANCH_F (IR);
  776.         break;
  777.     case 006: case 007:                /* BR */
  778.         BRANCH_B (IR);
  779.         break;
  780.     case 010: case 011:                /* BNE */
  781.         if (Z == 0) { BRANCH_F (IR); } 
  782.         break;
  783.     case 012: case 013:                /* BNE */
  784.         if (Z == 0) { BRANCH_B (IR); }
  785.         break;
  786.     case 014: case 015:                /* BEQ */
  787.         if (Z) { BRANCH_F (IR); } 
  788.         break;
  789.     case 016: case 017:                /* BEQ */
  790.         if (Z) { BRANCH_B (IR); }
  791.         break;
  792.     case 020: case 021:                /* BGE */
  793.         if ((N ^ V) == 0) { BRANCH_F (IR); } 
  794.         break;
  795.     case 022: case 023:                /* BGE */
  796.         if ((N ^ V) == 0) { BRANCH_B (IR); }
  797.         break;
  798.     case 024: case 025:                /* BLT */
  799.         if (N ^ V) { BRANCH_F (IR); }
  800.         break;
  801.     case 026: case 027:                /* BLT */
  802.         if (N ^ V) { BRANCH_B (IR); }
  803.         break;
  804.     case 030: case 031:                /* BGT */
  805.         if ((Z | (N ^ V)) == 0) { BRANCH_F (IR); } 
  806.         break;
  807.     case 032: case 033:                /* BGT */
  808.         if ((Z | (N ^ V)) == 0) { BRANCH_B (IR); }
  809.         break;
  810.     case 034: case 035:                /* BLE */
  811.         if (Z | (N ^ V)) { BRANCH_F (IR); } 
  812.         break;
  813.     case 036: case 037:                /* BLE */
  814.         if (Z | (N ^ V)) { BRANCH_B (IR); }
  815.         break;
  816.     case 040: case 041: case 042: case 043:        /* JSR */
  817.     case 044: case 045: case 046: case 047:
  818.         if (dstreg) setTRAP (TRAP_ILL);
  819.         else {    srcspec = srcspec & 07;
  820.             dst = GeteaW (dstspec);
  821.             SP = (SP - 2) & 0177777;
  822.             if (update_MM) MMR1 = calc_MMR1 (0366);
  823.             WriteW (R[srcspec], SP | dsenable);
  824.             if ((SP < STKLIM) && (cm == KERNEL)) {
  825.                 setTRAP (TRAP_YEL);
  826.                 setCPUERR (CPUE_YEL);  }
  827.             R[srcspec] = PC;
  828.             JMP_PC (dst & 0177777);  }
  829.         break;                    /* end JSR */
  830.  
  831. /* Opcode 0: SOPs */
  832.  
  833.     case 050:                    /* CLR */
  834.         N = V = C = 0;
  835.         Z = 1;
  836.         if (dstreg) R[dstspec] = 0;
  837.         else WriteW (0, GeteaW (dstspec));
  838.         break;
  839.     case 051:                    /* COM */
  840.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  841.         dst = dst ^ 0177777;
  842.         N = GET_SIGN_W (dst);
  843.         Z = GET_Z (dst);
  844.         V = 0;
  845.         C = 1;
  846.         if (dstreg) R[dstspec] = dst;
  847.         else PWriteW (dst, last_pa);
  848.         break;
  849.     case 052:                    /* INC */
  850.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  851.         dst = (dst + 1) & 0177777;
  852.         N = GET_SIGN_W (dst);
  853.         Z = GET_Z (dst);
  854.         V = (dst == 0100000);
  855.         if (dstreg) R[dstspec] = dst;
  856.         else PWriteW (dst, last_pa);
  857.         break;
  858.     case 053:                    /* DEC */
  859.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  860.         dst = (dst - 1) & 0177777;
  861.         N = GET_SIGN_W (dst);
  862.         Z = GET_Z (dst);
  863.         V = (dst == 077777);
  864.         if (dstreg) R[dstspec] = dst;
  865.         else PWriteW (dst, last_pa);
  866.         break;
  867.     case 054:                    /* NEG */
  868.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  869.         dst = (-dst) & 0177777;
  870.         N = GET_SIGN_W (dst);
  871.         Z = GET_Z (dst);
  872.         V = (dst == 0100000);
  873.         C = Z ^ 1;
  874.         if (dstreg) R[dstspec] = dst;
  875.         else PWriteW (dst, last_pa);
  876.         break;
  877.     case 055:                    /* ADC */
  878.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  879.         dst = (dst + C) & 0177777;
  880.         N = GET_SIGN_W (dst);
  881.         Z = GET_Z (dst);
  882.         V = (C && (dst == 0100000));
  883.         C = C & Z;
  884.         if (dstreg) R[dstspec] = dst;
  885.         else PWriteW (dst, last_pa);
  886.         break;
  887.  
  888. /* Opcode 0: SOPs, continued */
  889.  
  890.     case 056:                    /* SBC */
  891.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  892.         dst = (dst - C) & 0177777;
  893.         N = GET_SIGN_W (dst);
  894.         Z = GET_Z (dst);
  895.         V = (C && (dst == 077777));
  896.         C = (C && (dst == 0177777));
  897.         if (dstreg) R[dstspec] = dst;
  898.         else PWriteW (dst, last_pa);
  899.         break;
  900.     case 057:                    /* TST */
  901.         dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  902.         N = GET_SIGN_W (dst);
  903.         Z = GET_Z (dst);
  904.         V = C = 0;
  905.         break;
  906.     case 060:                    /* ROR */
  907.         src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  908.         dst = (src >> 1) | (C << 15);
  909.         N = GET_SIGN_W (dst);
  910.         Z = GET_Z (dst);
  911.         C = (src & 1);
  912.         V = N ^ C;
  913.         if (dstreg) R[dstspec] = dst;
  914.         else PWriteW (dst, last_pa);
  915.         break;
  916.     case 061:                    /* ROL */
  917.         src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  918.         dst = ((src << 1) | C) & 0177777;
  919.         N = GET_SIGN_W (dst);
  920.         Z = GET_Z (dst);
  921.         C = GET_SIGN_W (src);
  922.         V = N ^ C;
  923.         if (dstreg) R[dstspec] = dst;
  924.         else PWriteW (dst, last_pa);
  925.         break;
  926.     case 062:                    /* ASR */
  927.         src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  928.         dst = (src >> 1) | (src & 0100000);
  929.         N = GET_SIGN_W (dst);
  930.         Z = GET_Z (dst);
  931.         C = (src & 1);
  932.         V = N ^ C;
  933.         if (dstreg) R[dstspec] = dst;
  934.         else PWriteW (dst, last_pa);
  935.         break;
  936.     case 063:                    /* ASL */
  937.         src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  938.         dst = (src << 1) & 0177777;
  939.         N = GET_SIGN_W (dst);
  940.         Z = GET_Z (dst);
  941.         C = GET_SIGN_W (src);
  942.         V = N ^ C;
  943.         if (dstreg) R[dstspec] = dst;
  944.         else PWriteW (dst, last_pa);
  945.         break;
  946.  
  947. /* Opcode 0: SOPS, continued
  948.  
  949.    Notes:
  950.    - MxPI must mask GeteaW returned address to force ispace
  951.    - MxPI must set MMR1 for SP recovery in case of fault
  952. */
  953.  
  954.     case 064:                    /* MARK */
  955.         i = (PC + dstspec + dstspec) & 0177777;
  956.         JMP_PC (R[5]);
  957.         R[5] = ReadW (i | dsenable);
  958.         SP = (i + 2) & 0177777;
  959.         break;
  960.     case 065:                    /* MFPI */
  961.         if (dstreg) {
  962.             if ((dstspec == 6) && (cm != pm)) dst = STACKFILE[pm];
  963.             else dst = R[dstspec];  }
  964.         else dst = ReadW ((GeteaW (dstspec) & 0177777) | calc_is (pm));
  965.         N = GET_SIGN_W (dst);
  966.         Z = GET_Z (dst);
  967.         V = 0;
  968.         SP = (SP - 2) & 0177777;
  969.         if (update_MM) MMR1 = calc_MMR1 (0366);
  970.         WriteW (dst, SP | dsenable);
  971.         if ((cm == KERNEL) && (SP < STKLIM)) {
  972.             setTRAP (TRAP_YEL);
  973.             setCPUERR (CPUE_YEL);  }
  974.         break;
  975.     case 066:                    /* MTPI */
  976.         dst = ReadW (SP | dsenable);
  977.         N = GET_SIGN_W (dst);
  978.         Z = GET_Z (dst);
  979.         V = 0;
  980.         SP = (SP + 2) & 0177777;
  981.         if (update_MM) MMR1 = 026;
  982.         if (dstreg) {
  983.             if ((dstspec == 6) && (cm != pm)) STACKFILE[pm] = dst;
  984.             else R[dstspec] = dst;  }
  985.         else {    i = ((cm == pm) && (cm == USER))?
  986.                 calc_ds (pm): calc_is (pm);
  987.             WriteW (dst, (GeteaW (dstspec) & 0177777) | i);  }
  988.         break;
  989.     case 067:                    /* SXT */
  990.         dst = N? 0177777: 0;
  991.         Z = N ^ 1;
  992.         V = 0;
  993.         if (dstreg) R[dstspec] = dst;
  994.         else WriteW (dst, GeteaW (dstspec));
  995.         break;
  996.  
  997. /* Opcode 0: SOPs, continued */
  998.  
  999.     case 070:                    /* CSM */
  1000.         if (((MMR3 & MMR3_CSM) == 0) || (cm == KERNEL))
  1001.             setTRAP (TRAP_ILL);
  1002.         else {    dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1003.             PSW = (cm << PSW_V_CM) | (pm << PSW_V_PM) |
  1004.                 (rs << PSW_V_RS) | (ipl << PSW_V_IPL) | 
  1005.                 (tbit << PSW_V_TBIT);
  1006.             STACKFILE[cm] = SP;
  1007.             WriteW (PSW, ((SP - 2) & 0177777) | calc_ds (SUPER));
  1008.             WriteW (PC, ((SP - 4) & 0177777) | calc_ds (SUPER));
  1009.             WriteW (dst, ((SP - 6) & 0177777) | calc_ds (SUPER));
  1010.             SP = (SP - 6) & 0177777;
  1011.             pm = cm;
  1012.             cm = SUPER;
  1013.             tbit = 0;
  1014.             isenable = calc_is (cm);
  1015.             dsenable = calc_ds (cm);
  1016.             PC = ReadW (010 | isenable);  }
  1017.         break;
  1018.     case 072:                    /* TSTSET */
  1019.         if (dstreg) setTRAP (TRAP_ILL);
  1020.         else {    dst = ReadMW (GeteaW (dstspec));
  1021.             N = GET_SIGN_W (dst);
  1022.             Z = GET_Z (dst);
  1023.             V = 0;
  1024.             C = (dst & 1);
  1025.             PWriteW (R[0] | 1, last_pa);
  1026.             R[0] = dst;  }
  1027.         break;
  1028.     case 073:                    /* WRTLCK */
  1029.         if (dstreg) setTRAP (TRAP_ILL);
  1030.         else {    N = GET_SIGN_W (R[0]);
  1031.             Z = GET_Z (R[0]);
  1032.             V = 0;
  1033.             WriteW (R[0], GeteaW (dstspec));  }
  1034.         break;
  1035.     default:
  1036.         setTRAP (TRAP_ILL);
  1037.         break;  }                /* end switch SOPs */
  1038.     break;                        /* end case 000 */
  1039.  
  1040. /* Opcodes 01 - 06: double operand word instructions
  1041.  
  1042.    Add: v = [sign (src) = sign (src2)] and [sign (src) != sign (result)]
  1043.    Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)]
  1044. */
  1045.  
  1046. case 001:                        /* MOV */
  1047.     dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1048.     N = GET_SIGN_W (dst);
  1049.     Z = GET_Z (dst);
  1050.     V = 0;
  1051.     if (dstreg) R[dstspec] = dst;
  1052.     else WriteW (dst, GeteaW (dstspec));
  1053.     break;
  1054. case 002:                        /* CMP */
  1055.     src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1056.     src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1057.     dst = (src - src2) & 0177777;
  1058.     N = GET_SIGN_W (dst);
  1059.     Z = GET_Z (dst);
  1060.     V = GET_SIGN_W ((src ^ src2) & (~src2 ^ dst));
  1061.     C = (src < src2);
  1062.     break;
  1063. case 003:                        /* BIT */
  1064.     src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1065.     src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1066.     dst = src2 & src;
  1067.     N = GET_SIGN_W (dst);
  1068.     Z = GET_Z (dst);
  1069.     V = 0;
  1070.     break;
  1071. case 004:                        /* BIC */
  1072.     src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1073.     src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  1074.     dst = src2 & ~src;
  1075.     N = GET_SIGN_W (dst);
  1076.     Z = GET_Z (dst);
  1077.     V = 0;
  1078.     if (dstreg) R[dstspec] = dst;
  1079.     else PWriteW (dst, last_pa);
  1080.     break;
  1081. case 005:                        /* BIS */
  1082.     src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1083.     src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  1084.     dst = src2 | src;
  1085.     N = GET_SIGN_W (dst);
  1086.     Z = GET_Z (dst);
  1087.     V = 0;
  1088.     if (dstreg) R[dstspec] = dst;
  1089.     else PWriteW (dst, last_pa);
  1090.     break;
  1091. case 006:                        /* ADD */
  1092.     src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1093.     src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  1094.     dst = (src2 + src) & 0177777;
  1095.     N = GET_SIGN_W (dst);
  1096.     Z = GET_Z (dst);
  1097.     V = GET_SIGN_W ((~src ^ src2) & (src ^ dst));
  1098.     C = (dst < src);
  1099.     if (dstreg) R[dstspec] = dst;
  1100.     else PWriteW (dst, last_pa);
  1101.     break;
  1102.  
  1103. /* Opcode 07: EIS, FIS (not implemented), CIS (not implemented)
  1104.  
  1105.    Notes:
  1106.    - The code assumes that the host int length is at least 32 bits.
  1107.    - MUL carry: C is set if the (signed) result doesn't fit in 16 bits.
  1108.    - Divide has three error cases:
  1109.     1. Divide by zero.
  1110.     2. Divide largest negative number by -1.
  1111.     3. (Signed) quotient doesn't fit in 16 bits.
  1112.      Cases 1 and 2 must be tested in advance, to avoid C runtime errors.
  1113.    - ASHx left: overflow if the bits shifted out do not equal the sign
  1114.      of the result (convert shift out to 1/0, xor against sign).
  1115.    - ASHx right: if right shift sign extends, then the shift and
  1116.      conditional or of shifted -1 is redundant.  If right shift zero
  1117.      extends, then the shift and conditional or does sign extension.
  1118. */
  1119.  
  1120. case 007:
  1121.     srcspec = srcspec & 07;
  1122.     switch ((IR >> 9) & 07)  {            /* decode IR<11:9> */
  1123.     case 0:                        /* MUL */
  1124.         src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1125.         src = R[srcspec];
  1126.         if (GET_SIGN_W (src2)) src2 = src2 | ~077777;
  1127.         if (GET_SIGN_W (src)) src = src | ~077777;
  1128.         dst = src * src2;
  1129.         R[srcspec] = (dst >> 16) & 0177777;
  1130.         R[srcspec | 1] = dst & 0177777;
  1131.         N = (dst < 0);
  1132.         Z = GET_Z (dst);
  1133.         V = 0;
  1134.         C = ((dst > 077777) || (dst < -0100000));
  1135.         break;
  1136.     case 1:                        /* DIV */
  1137.         src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1138.         src = (R[srcspec] << 16) | R[srcspec | 1];
  1139.         if (src2 == 0) {
  1140.             V = C = 1;
  1141.             break;  }
  1142.         if ((src == 020000000000) && (src2 == 0177777)) {
  1143.             V = 1;
  1144.             C = 0;
  1145.             break;  }
  1146.         if (GET_SIGN_W (src2)) src2 = src2 | ~077777;
  1147.         if (GET_SIGN_W (R[srcspec])) src = src | ~017777777777;
  1148.         dst = src / src2;
  1149.         if ((dst >= 077777) || (dst < -0100000)) {
  1150.             V = 1;
  1151.             C = 0;
  1152.             break;  }
  1153.         R[srcspec] = dst & 0177777;
  1154.         R[srcspec | 1] = (src - (src2 * dst)) & 0177777;
  1155.         N = (dst < 0);
  1156.         Z = GET_Z (dst);
  1157.         V = C = 0;
  1158.         break;
  1159.  
  1160. /* Opcode 7: EIS, continued */
  1161.  
  1162.     case 2:                        /* ASH */
  1163.         src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1164.         src2 = src2 & 077;
  1165.         sign = GET_SIGN_W (R[srcspec]);
  1166.         src = sign? R[srcspec] | ~077777: R[srcspec];
  1167.         if (src2 == 0) {            /* [0] */
  1168.             dst = src;
  1169.             V = C = 0;  }
  1170.         else if (src2 <= 15) {            /* [1,15] */
  1171.             dst = src << src2;
  1172.             i = (src >> (16 - src2)) & 0177777;
  1173.             V = (i != ((dst & 0100000)? 0177777: 0));
  1174.             C = (i & 1);  }
  1175.         else if (src2 <= 31) {            /* [16,31] */
  1176.             dst = 0;
  1177.             V = (src != 0);
  1178.             C = (src << (src2 - 16)) & 1;  }
  1179.         else {                    /* [-32,-1] */
  1180.             dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
  1181.             V = 0;
  1182.             C = ((src >> (63 - src2)) & 1);  }
  1183.         dst = R[srcspec] = dst & 0177777;
  1184.         N = GET_SIGN_W (dst);
  1185.         Z = GET_Z (dst);
  1186.         break;
  1187.     case 3:                        /* ASHC */
  1188.         src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
  1189.         src2 = src2 & 077;
  1190.         sign = GET_SIGN_W (R[srcspec]);
  1191.         src = (R[srcspec] << 16) | R[srcspec | 1];
  1192.         if (src2 == 0) {             /* [0] */
  1193.             dst = src;
  1194.             V = C = 0;  }
  1195.         else if (src2 <= 31) {            /* [1,31] */
  1196.             dst = src << src2;
  1197.             i = (src >> (32 - src2)) | (-sign << src2);
  1198.             V = (i != ((dst & 020000000000)? -1: 0));
  1199.             C = (i & 1);  }
  1200.         else {                    /* [-32,-1] */
  1201.             dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
  1202.             V = 0;
  1203.             C = ((src >> (63 - src2)) & 1);  }
  1204.         i = R[srcspec] = (dst >> 16) & 0177777;
  1205.         dst = R[srcspec | 1] = dst & 0177777;
  1206.         N = GET_SIGN_W (i);
  1207.         Z = GET_Z (dst | i);
  1208.         break;
  1209.  
  1210. /* Opcode 7: EIS, continued */
  1211.  
  1212.     case 4:                        /* XOR */
  1213.         dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  1214.         dst = dst ^ R[srcspec];
  1215.         N = GET_SIGN_W (dst);
  1216.         Z = GET_Z (dst);
  1217.         V = 0;
  1218.         if (dstreg) R[dstspec] = dst;
  1219.         else PWriteW (dst, last_pa);
  1220.         break;
  1221.     case 5:                        /* FIS - not impl */
  1222.         setTRAP (TRAP_ILL);
  1223.         break;
  1224.     case 6:                        /* CIS - not impl */
  1225.         setTRAP (TRAP_ILL);
  1226.         break;
  1227.     case 7:                        /* SOB */
  1228.         R[srcspec] = (R[srcspec] - 1) & 0177777;
  1229.         if (R[srcspec]) {
  1230.             JMP_PC ((PC - dstspec - dstspec) & 0177777);  }
  1231.         break;  }                /* end switch EIS */
  1232.     break;                        /* end case 007 */
  1233.  
  1234. /* Opcode 10: branches, traps, SOPs */
  1235.  
  1236. case 010:
  1237.     switch ((IR >> 6) & 077) {            /* decode IR<11:6> */
  1238.     case 000: case 001:                /* BPL */
  1239.         if (N == 0) { BRANCH_F (IR); } 
  1240.         break;
  1241.     case 002: case 003:                /* BPL */
  1242.         if (N == 0) { BRANCH_B (IR); }
  1243.         break;
  1244.     case 004: case 005:                /* BMI */
  1245.         if (N) { BRANCH_F (IR); } 
  1246.         break;
  1247.     case 006: case 007:                /* BMI */
  1248.         if (N) { BRANCH_B (IR); }
  1249.         break;
  1250.     case 010: case 011:                /* BHI */
  1251.         if ((C | Z) == 0) { BRANCH_F (IR); } 
  1252.         break;
  1253.     case 012: case 013:                /* BHI */
  1254.         if ((C | Z) == 0) { BRANCH_B (IR); }
  1255.         break;
  1256.     case 014: case 015:                /* BLOS */
  1257.         if (C | Z) { BRANCH_F (IR); } 
  1258.         break;
  1259.     case 016: case 017:                /* BLOS */
  1260.         if (C | Z) { BRANCH_B (IR); }
  1261.         break;
  1262.     case 020: case 021:                /* BVC */
  1263.         if (V == 0) { BRANCH_F (IR); } 
  1264.         break;
  1265.     case 022: case 023:                /* BVC */
  1266.         if (V == 0) { BRANCH_B (IR); }
  1267.         break;
  1268.     case 024: case 025:                /* BVS */
  1269.         if (V) { BRANCH_F (IR); } 
  1270.         break;
  1271.     case 026: case 027:                /* BVS */
  1272.         if (V) { BRANCH_B (IR); }
  1273.         break;
  1274.     case 030: case 031:                /* BCC */
  1275.         if (C == 0) { BRANCH_F (IR); } 
  1276.         break;
  1277.     case 032: case 033:                /* BCC */
  1278.         if (C == 0) { BRANCH_B (IR); }
  1279.         break;
  1280.     case 034: case 035:                /* BCS */
  1281.         if (C) { BRANCH_F (IR); } 
  1282.         break;
  1283.     case 036: case 037:                /* BCS */
  1284.         if (C) { BRANCH_B (IR); }
  1285.         break;
  1286.     case 040: case 041: case 042: case 043:        /* EMT */
  1287.         setTRAP (TRAP_EMT);
  1288.         break;
  1289.     case 044: case 045: case 046: case 047:        /* TRAP */
  1290.         setTRAP (TRAP_TRAP);
  1291.         break;
  1292.  
  1293. /* Opcode 10, continued: SOPs */
  1294.  
  1295.     case 050:                    /* CLRB */
  1296.         N = V = C = 0;
  1297.         Z = 1;
  1298.         if (dstreg) R[dstspec] = R[dstspec] & 0177400;
  1299.         else WriteB (0, GeteaB (dstspec));
  1300.         break;
  1301.     case 051:                    /* COMB */
  1302.         dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1303.         dst = (dst ^ 0377) & 0377;
  1304.         N = GET_SIGN_B (dst);
  1305.         Z = GET_Z (dst);
  1306.         V = 0;
  1307.         C = 1;
  1308.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1309.         else PWriteB (dst, last_pa);
  1310.         break;
  1311.     case 052:                    /* INCB */
  1312.         dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1313.         dst = (dst + 1) & 0377;
  1314.         N = GET_SIGN_B (dst);
  1315.         Z = GET_Z (dst);
  1316.         V = (dst == 0200);
  1317.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1318.         else PWriteB (dst, last_pa);
  1319.         break;
  1320.     case 053:                    /* DECB */
  1321.         dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1322.         dst = (dst - 1) & 0377;
  1323.         N = GET_SIGN_B (dst);
  1324.         Z = GET_Z (dst);
  1325.         V = (dst == 0177);
  1326.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1327.         else PWriteB (dst, last_pa);
  1328.         break;
  1329.     case 054:                    /* NEGB */
  1330.         dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1331.         dst = (-dst) & 0377;
  1332.         N = GET_SIGN_B (dst);
  1333.         Z = GET_Z (dst);
  1334.         V = (dst == 0200);
  1335.         C = (Z ^ 1);
  1336.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1337.         else PWriteB (dst, last_pa);
  1338.         break;
  1339.     case 055:                    /* ADCB */
  1340.         dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1341.         dst = (dst + C) & 0377;
  1342.         N = GET_SIGN_B (dst);
  1343.         Z = GET_Z (dst);
  1344.         V = (C && (dst == 0200));
  1345.         C = C & Z;
  1346.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1347.         else PWriteB (dst, last_pa);
  1348.         break;
  1349.  
  1350. /* Opcode 10: SOPs, continued */
  1351.  
  1352.     case 056:                    /* SBCB */
  1353.         dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1354.         dst = (dst - C) & 0377;
  1355.         N = GET_SIGN_B (dst);
  1356.         Z = GET_Z (dst);
  1357.         V = (C && (dst == 0177));
  1358.         C = (C && (dst == 0377));
  1359.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1360.         else PWriteB (dst, last_pa);
  1361.         break;
  1362.     case 057:                    /* TSTB */
  1363.         dst = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec));
  1364.         N = GET_SIGN_B (dst);
  1365.         Z = GET_Z (dst);
  1366.         V = C = 0;
  1367.         break;
  1368.     case 060:                    /* RORB */
  1369.         src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1370.         dst = ((src & 0377) >> 1) | (C << 7);
  1371.         N = GET_SIGN_B (dst);
  1372.         Z = GET_Z (dst);
  1373.         C = (src & 1);
  1374.         V = N ^ C;
  1375.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1376.         else PWriteB (dst, last_pa);
  1377.         break;
  1378.     case 061:                    /* ROLB */
  1379.         src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1380.         dst = ((src << 1) | C) & 0377;
  1381.         N = GET_SIGN_B (dst);
  1382.         Z = GET_Z (dst);
  1383.         C = GET_SIGN_B (src & 0377);
  1384.         V = N ^ C;
  1385.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1386.         else PWriteB (dst, last_pa);
  1387.         break;
  1388.     case 062:                    /* ASRB */
  1389.         src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1390.         dst = ((src & 0377) >> 1) | (src & 0200);
  1391.         N = GET_SIGN_B (dst);
  1392.         Z = GET_Z (dst);
  1393.         C = (src & 1);
  1394.         V = N ^ C;
  1395.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1396.         else PWriteB (dst, last_pa);
  1397.         break;
  1398.     case 063:                    /* ASLB */
  1399.         src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1400.         dst = (src << 1) & 0377;
  1401.         N = GET_SIGN_B (dst);
  1402.         Z = GET_Z (dst);
  1403.         C = GET_SIGN_B (src & 0377);
  1404.         V = N ^ C;
  1405.         if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1406.         else PWriteB (dst, last_pa);
  1407.         break;
  1408.  
  1409. /* Opcode 10: SOPs, continued
  1410.  
  1411.    Notes:
  1412.    - MTPS cannot alter the T bit
  1413.    - MxPD must mask GeteaW returned address, dspace is from cm not pm
  1414.    - MxPD must set MMR1 for SP recovery in case of fault
  1415. */
  1416.  
  1417.     case 064:                    /* MTPS */
  1418.         dst = dstreg? R[dstspec]: ReadB (GeteaB (dstspec));
  1419.         if (cm == KERNEL) {
  1420.             ipl = (dst >> PSW_V_IPL) & 07;
  1421.             trap_req = calc_ints (ipl, int_req, trap_req);  }
  1422.         N = (dst >> PSW_V_N) & 01;
  1423.         Z = (dst >> PSW_V_Z) & 01;
  1424.         V = (dst >> PSW_V_V) & 01;
  1425.         C = (dst >> PSW_V_C) & 01;
  1426.         break;
  1427.     case 065:                    /* MFPD */
  1428.         if (dstreg) {
  1429.             if ((dstspec == 6) && (cm != pm)) dst = STACKFILE[pm];
  1430.             else dst = R[dstspec];  }
  1431.         else dst = ReadW ((GeteaW (dstspec) & 0177777) | calc_ds (pm));
  1432.         N = GET_SIGN_W (dst);
  1433.         Z = GET_Z (dst);
  1434.         V = 0;
  1435.         SP = (SP - 2) & 0177777;
  1436.         if (update_MM) MMR1 = calc_MMR1 (0366);
  1437.         WriteW (dst, SP | dsenable);
  1438.         if ((cm == KERNEL) && (SP < STKLIM)) {
  1439.             setTRAP (TRAP_YEL);
  1440.             setCPUERR (CPUE_YEL);  }
  1441.         break;
  1442.     case 066:                    /* MTPD */
  1443.         dst = ReadW (SP | dsenable);
  1444.         N = GET_SIGN_W (dst);
  1445.         Z = GET_Z (dst);
  1446.         V = 0;
  1447.         SP = (SP + 2) & 0177777;
  1448.         if (update_MM) MMR1 = 026;
  1449.         if (dstreg) {
  1450.             if ((dstspec == 6) && (cm != pm)) STACKFILE[pm] = dst;
  1451.             else R[dstspec] = dst;  }
  1452.         else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_ds (pm));
  1453.         break;
  1454.     case 067:                    /* MFPS */
  1455.         dst = (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
  1456.             (N << PSW_V_N) | (Z << PSW_V_Z) |
  1457.             (V << PSW_V_V) | (C << PSW_V_C);
  1458.         N = GET_SIGN_B (dst);
  1459.         Z = GET_Z (dst);
  1460.         V = 0;
  1461.         if (dstreg) R[dstspec] = (dst & 0200)? 0177400 | dst: dst;
  1462.         else WriteB (dst, GeteaB (dstspec));
  1463.         break;
  1464.     default:
  1465.         setTRAP (TRAP_ILL);
  1466.         break; }                /* end switch SOPs */
  1467.     break;                        /* end case 010 */
  1468.  
  1469. /* Opcodes 11 - 16: double operand byte instructions
  1470.  
  1471.    Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)]
  1472.    Sub: v = [sign (src) != sign (src2)] and [sign (src) = sign (result)]
  1473. */
  1474.  
  1475. case 011:                        /* MOVB */
  1476.     dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec));
  1477.     N = GET_SIGN_B (dst);
  1478.     Z = GET_Z (dst);
  1479.     V = 0;
  1480.     if (dstreg) R[dstspec] = (dst & 0200)? 0177400 | dst: dst;
  1481.     else WriteB (dst, GeteaB (dstspec));
  1482.     break;
  1483. case 012:                        /* CMPB */
  1484.     src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec));
  1485.     src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec));
  1486.     dst = (src - src2) & 0377;
  1487.     N = GET_SIGN_B (dst);
  1488.     Z = GET_Z (dst);
  1489.     V = GET_SIGN_B ((src ^ src2) & (~src2 ^ dst));
  1490.     C = (src < src2);
  1491.     break;
  1492. case 013:                        /* BITB */
  1493.     src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec));
  1494.     src2 = dstreg? R[dstspec]: ReadB (GeteaB (dstspec));
  1495.     dst = (src2 & src) & 0377;
  1496.     N = GET_SIGN_B (dst);
  1497.     Z = GET_Z (dst);
  1498.     V = 0;
  1499.     break;
  1500. case 014:                        /* BICB */
  1501.     src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec));
  1502.     src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1503.     dst = (src2 & ~src) & 0377;
  1504.     N = GET_SIGN_B (dst);
  1505.     Z = GET_Z (dst);
  1506.     V = 0;
  1507.     if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1508.     else PWriteB (dst, last_pa);
  1509.     break;
  1510. case 015:                        /* BISB */
  1511.     src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec));
  1512.     src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
  1513.     dst = (src2 | src) & 0377;
  1514.     N = GET_SIGN_B (dst);
  1515.     Z = GET_Z (dst);
  1516.     V = 0;
  1517.     if (dstreg) R[dstspec] = (R[dstspec] & 0177400) | dst;
  1518.     else PWriteB (dst, last_pa);
  1519.     break;
  1520. case 016:                        /* SUB */
  1521.     src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
  1522.     src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
  1523.     dst = (src2 - src) & 0177777;
  1524.     N = GET_SIGN_W (dst);
  1525.     Z = GET_Z (dst);
  1526.     V = GET_SIGN_W ((src ^ src2) & (~src ^ dst));
  1527.     C = (src2 < src);
  1528.     if (dstreg) R[dstspec] = dst;
  1529.     else PWriteW (dst, last_pa);
  1530.     break;
  1531.  
  1532. /* Opcode 17: floating point */
  1533.  
  1534. case 017:
  1535.     fp11 (IR);                    /* floating point */
  1536.     break;                        /* end case 017 */
  1537.     }                        /* end switch op */
  1538. }                            /* end main loop */
  1539.  
  1540. /* Simulation halted */
  1541.  
  1542. PSW = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) |
  1543.     (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
  1544.     (N << PSW_V_N) | (Z << PSW_V_Z) | (V << PSW_V_V) | (C << PSW_V_C);
  1545. for (i = 0; i < 6; i++) REGFILE[i][rs] = R[i];
  1546. STACKFILE[cm] = SP;
  1547. saved_PC = PC & 0177777;
  1548. return reason;
  1549. }                            /* end sim_instr */
  1550.  
  1551. /* Effective address calculations
  1552.  
  1553.    Inputs:
  1554.     spec    =    specifier <5:0>
  1555.    Outputs:
  1556.     ea    =    effective address
  1557.             <15:0> =  virtual address
  1558.             <16> =    instruction/data data space
  1559.             <18:17> = mode
  1560.  
  1561.    Data space calculation: the PDP-11 features both instruction and data
  1562.    spaces.  Instruction space contains the instruction and any sequential
  1563.    add ons (eg, immediates, absolute addresses).  Data space contains all
  1564.    data operands and indirect addresses.  If data space is enabled, then
  1565.    memory references are directed according to these rules:
  1566.  
  1567.     Mode    Index ref    Indirect ref        Direct ref
  1568.     10..16    na        na            data
  1569.     17    na        na            instruction
  1570.     20..26    na        na            data
  1571.     27    na        na            instruction
  1572.     30..36    na        data            data
  1573.     37    na        instruction (absolute)    data
  1574.     40..46    na        na            data
  1575.     47    na        na            instruction
  1576.     50..56    na        data            data
  1577.     57    na        instruction        data
  1578.     60..67    instruction    na            data
  1579.     70..77    instruction    data            data
  1580.  
  1581.    According to the PDP-11 Architecture Handbook, MMR1 records all
  1582.    autoincrement and autodecrement operations, including those which
  1583.    explicitly reference the PC.  For the J-11, this is only true for
  1584.    autodecrement operands, autodecrement deferred operands, and
  1585.    autoincrement destination operands that involve a write to memory.
  1586.    The simulator follows the Handbook, for simplicity.
  1587.  
  1588.    Notes:
  1589.  
  1590.    - dsenable will direct a reference to data space if data space is enabled
  1591.    - ds will direct a reference to data space if data space is enabled AND if
  1592.     the specifier register is not PC; this is used for 17, 27, 37, 47, 57
  1593.    - Modes 2x, 3x, 4x, and 5x must update MMR1 if updating enabled
  1594.    - Modes 46 and 56 must check for stack overflow if kernel mode
  1595. */
  1596.  
  1597. /* Effective address calculation for words */
  1598.  
  1599. int GeteaW (int spec)
  1600. {
  1601. int adr, reg, ds;
  1602.  
  1603. reg = spec & 07;                    /* register number */
  1604. ds = (reg == 7)? isenable: dsenable;            /* dspace if not PC */
  1605. switch (spec >> 3) {                    /* decode spec<5:3> */
  1606. default:                        /* can't get here */
  1607. case 1:                            /* (R) */
  1608.     return (R[reg] | ds);
  1609. case 2:                            /* (R)+ */
  1610.     R[reg] = ((adr = R[reg]) + 2) & 0177777;
  1611.     if (update_MM) MMR1 = calc_MMR1 (020 | reg);
  1612.     return (adr | ds);
  1613. case 3:                            /* @(R)+ */
  1614.     R[reg] = ((adr = R[reg]) + 2) & 0177777;
  1615.     if (update_MM) MMR1 = calc_MMR1 (020 | reg);
  1616.     adr = ReadW (adr | ds);
  1617.     return (adr | dsenable);
  1618. case 4:                            /* -(R) */
  1619.     adr = R[reg] = (R[reg] - 2) & 0177777;
  1620.     if (update_MM) MMR1 = calc_MMR1 (0360 | reg);
  1621.     if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
  1622.         setTRAP (TRAP_YEL);
  1623.         setCPUERR (CPUE_YEL);  }
  1624.     return (adr | ds);
  1625. case 5:                            /* @-(R) */
  1626.     adr = R[reg] = (R[reg] - 2) & 0177777;
  1627.     if (update_MM) MMR1 = calc_MMR1 (0360 | reg);
  1628.     if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
  1629.         setTRAP (TRAP_YEL);
  1630.         setCPUERR (CPUE_YEL);  }
  1631.     adr = ReadW (adr | ds);
  1632.     return (adr | dsenable);
  1633. case 6:                            /* d(r) */
  1634.     adr = ReadW (PC | isenable);
  1635.     PC = (PC + 2) & 0177777;
  1636.     return (((R[reg] + adr) & 0177777) | dsenable);
  1637. case 7:                            /* @d(R) */
  1638.     adr = ReadW (PC | isenable);
  1639.     PC = (PC + 2) & 0177777;
  1640.     adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
  1641.     return (adr | dsenable);
  1642.     }                        /* end switch */
  1643. }                            /* end GeteaW */
  1644.  
  1645. /* Effective address calculation for bytes */
  1646.  
  1647. int GeteaB (int spec)
  1648. {
  1649. int adr, reg, ds, delta;
  1650.  
  1651. reg = spec & 07;                    /* reg number */
  1652. ds = (reg == 7)? isenable: dsenable;            /* dspace if not PC */
  1653. switch (spec >> 3) {                    /* decode spec<5:3> */
  1654. default:                        /* can't get here */
  1655. case 1:                            /* (R) */
  1656.     return (R[reg] | ds);
  1657. case 2:                            /* (R)+ */
  1658.     delta = 1 + (reg >= 6);                /* 2 if R6, PC */
  1659.     R[reg] = ((adr = R[reg]) + delta) & 0177777;
  1660.     if (update_MM) MMR1 = calc_MMR1 ((delta << 3) | reg);
  1661.     return (adr | ds);
  1662. case 3:                            /* @(R)+ */
  1663.     adr = R[reg];
  1664.     R[reg] = ((adr = R[reg]) + 2) & 0177777;
  1665.     if (update_MM) MMR1 = calc_MMR1 (020 | reg);
  1666.     adr = ReadW (adr | ds);
  1667.     return (adr | dsenable);
  1668. case 4:                            /* -(R) */
  1669.     delta = 1 + (reg >= 6);                /* 2 if R6, PC */
  1670.     adr = R[reg] = (R[reg] - delta) & 0177777;
  1671.     if (update_MM) MMR1 = calc_MMR1 ((((-delta) & 037) << 3) | reg);
  1672.     if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
  1673.         setTRAP (TRAP_YEL);
  1674.         setCPUERR (CPUE_YEL);  }
  1675.     return (adr | ds);
  1676. case 5:                            /* @-(R) */
  1677.     adr = R[reg] = (R[reg] - 2) & 0177777;
  1678.     if (update_MM) MMR1 = calc_MMR1 (0360 | reg);
  1679.     if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
  1680.         setTRAP (TRAP_YEL);
  1681.         setCPUERR (CPUE_YEL);  }
  1682.     adr = ReadW (adr | ds);
  1683.     return (adr | dsenable);
  1684. case 6:                            /* d(r) */
  1685.     adr = ReadW (PC | isenable);
  1686.     PC = (PC + 2) & 0177777;
  1687.     return (((R[reg] + adr) & 0177777) | dsenable);
  1688. case 7:                            /* @d(R) */
  1689.     adr = ReadW (PC | isenable);
  1690.     PC = (PC + 2) & 0177777;
  1691.     adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
  1692.     return (adr | dsenable);
  1693.     }                        /* end switch */
  1694. }                            /* end GeteaB */
  1695.  
  1696. /* Read byte and word routines, read only and read-modify-write versions
  1697.  
  1698.    Inputs:
  1699.     va    =    virtual address, <18:16> = mode, I/D space
  1700.    Outputs:
  1701.     data    =    data read from memory or I/O space
  1702. */
  1703.  
  1704. int ReadW (int va)
  1705. {
  1706. int pa, data;
  1707.  
  1708. if (va & 1) {                        /* odd address? */
  1709.     setCPUERR (CPUE_ODD);
  1710.     ABORT (TRAP_ODD);  }
  1711. pa = relocR (va);                    /* relocate */
  1712. if (pa < MEMSIZE) return (M[pa >> 1]);            /* memory address? */
  1713. if (pa < IOPAGEBASE) {                    /* I/O address? */
  1714.     setCPUERR (CPUE_NXM);
  1715.     ABORT (TRAP_NXM);  }
  1716. if (iopageR (&data, pa, READ) != SCPE_OK) {        /* invalid I/O addr? */
  1717.     setCPUERR (CPUE_TMO);
  1718.     ABORT (TRAP_NXM);  }
  1719. return data;
  1720. }
  1721.  
  1722. int ReadB (int va)
  1723. {
  1724. int pa, data;
  1725.  
  1726. pa = relocR (va);                    /* relocate */
  1727. if (pa < MEMSIZE) return (va & 1? M[pa >> 1] >> 8: M[pa >> 1]) & 0377;
  1728. if (pa < IOPAGEBASE) {                    /* I/O address? */
  1729.     setCPUERR (CPUE_NXM);
  1730.     ABORT (TRAP_NXM);  }
  1731. if (iopageR (&data, pa, READ) != SCPE_OK) {        /* invalid I/O addr? */
  1732.     setCPUERR (CPUE_TMO);
  1733.     ABORT (TRAP_NXM);  }
  1734. return ((va & 1)? data >> 8: data) & 0377;
  1735. }
  1736.  
  1737. int ReadMW (int va)
  1738. {
  1739. int data;
  1740.  
  1741. if (va & 1) {                        /* odd address? */
  1742.     setCPUERR (CPUE_ODD);
  1743.     ABORT (TRAP_ODD);  }
  1744. last_pa = relocW (va);                    /* reloc, wrt chk */
  1745. if (last_pa < MEMSIZE) return (M[last_pa >> 1]);    /* memory address? */
  1746. if (last_pa < IOPAGEBASE) {                /* I/O address? */
  1747.     setCPUERR (CPUE_NXM);
  1748.     ABORT (TRAP_NXM);  }
  1749. if (iopageR (&data, last_pa, READ) != SCPE_OK) {    /* invalid I/O addr? */
  1750.     setCPUERR (CPUE_TMO);
  1751.     ABORT (TRAP_NXM);  }
  1752. return data;
  1753. }
  1754.  
  1755. int ReadMB (int va)
  1756. {
  1757. int data;
  1758.  
  1759. last_pa = relocW (va);                    /* reloc, wrt chk */
  1760. if (last_pa < MEMSIZE)
  1761.     return (va & 1? M[last_pa >> 1] >> 8: M[last_pa >> 1]) & 0377;
  1762. if (last_pa < IOPAGEBASE) {                /* I/O address? */
  1763.     setCPUERR (CPUE_NXM);
  1764.     ABORT (TRAP_NXM);  }
  1765. if (iopageR (&data, last_pa, READ) != SCPE_OK) {    /* invalid I/O addr? */
  1766.     setCPUERR (CPUE_TMO);
  1767.     ABORT (TRAP_NXM);  }
  1768. return ((va & 1)? data >> 8: data) & 0377;
  1769. }
  1770.  
  1771. /* Write byte and word routines
  1772.  
  1773.    Inputs:
  1774.     data    =    data to be written
  1775.     va    =    virtual address, <18:16> = mode, I/D space, or
  1776.     pa    =    physical address
  1777.    Outputs: none
  1778. */
  1779.  
  1780. void WriteW (int data, int va)
  1781. {
  1782. int pa;
  1783.  
  1784. if (va & 1) {                        /* odd address? */
  1785.     setCPUERR (CPUE_ODD);
  1786.     ABORT (TRAP_ODD);  }
  1787. pa = relocW (va);                    /* relocate */
  1788. if (pa < MEMSIZE) {                    /* memory address? */
  1789.     M[pa >> 1] = data;
  1790.     return;  }
  1791. if (pa < IOPAGEBASE) {                    /* I/O address? */
  1792.     setCPUERR (CPUE_NXM);
  1793.     ABORT (TRAP_NXM);  }
  1794. if (iopageW (data, pa, WRITE) != SCPE_OK) {        /* invalid I/O addr? */
  1795.     setCPUERR (CPUE_TMO);
  1796.     ABORT (TRAP_NXM);  }
  1797. return;
  1798. }
  1799.  
  1800. void WriteB (int data, int va)
  1801. {
  1802. int pa;
  1803.  
  1804. pa = relocW (va);                    /* relocate */
  1805. if (pa < MEMSIZE) {                    /* memory address? */
  1806.     if (va & 1) M[pa >> 1] = (M[pa >> 1] & 0377) | (data << 8);
  1807.     else M[pa >> 1] = (M[pa >> 1] & ~0377) | data;
  1808.     return;  }             
  1809. if (pa < IOPAGEBASE) {                    /* I/O address? */
  1810.     setCPUERR (CPUE_NXM);
  1811.     ABORT (TRAP_NXM);  }
  1812. if (iopageW (data, pa, WRITEB) != SCPE_OK) {        /* invalid I/O addr? */
  1813.     setCPUERR (CPUE_TMO);
  1814.     ABORT (TRAP_NXM);  }
  1815. return;
  1816. }
  1817.  
  1818. void PWriteW (int data, int pa)
  1819. {
  1820. if (pa < MEMSIZE) {                    /* memory address? */
  1821.     M[pa >> 1] = data;
  1822.     return;  }
  1823. if (pa < IOPAGEBASE) {                    /* I/O address? */
  1824.     setCPUERR (CPUE_NXM);
  1825.     ABORT (TRAP_NXM);  }
  1826. if (iopageW (data, pa, WRITE) != SCPE_OK) {        /* invalid I/O addr? */
  1827.     setCPUERR (CPUE_TMO);
  1828.     ABORT (TRAP_NXM);  }
  1829. return;
  1830. }
  1831.  
  1832. void PWriteB (int data, int pa)
  1833. {
  1834. if (pa < MEMSIZE) {                    /* memory address? */
  1835.     if (pa & 1) M[pa >> 1] = (M[pa >> 1] & 0377) | (data << 8);
  1836.     else M[pa >> 1] = (M[pa >> 1] & ~0377) | data;
  1837.     return;  }             
  1838. if (pa < IOPAGEBASE) {                    /* I/O address? */
  1839.     setCPUERR (CPUE_NXM);
  1840.     ABORT (TRAP_NXM);  }
  1841. if (iopageW (data, pa, WRITEB) != SCPE_OK) {        /* invalid I/O addr? */
  1842.     setCPUERR (CPUE_TMO);
  1843.     ABORT (TRAP_NXM);  }
  1844. return;
  1845. }
  1846.  
  1847. /* Relocate virtual address, read access
  1848.  
  1849.    Inputs:
  1850.     va    =    virtual address, <18:16> = mode, I/D space
  1851.    Outputs:
  1852.     pa    =    physical address
  1853.    On aborts, this routine aborts back to the top level simulator
  1854.    with an appropriate trap code.
  1855.  
  1856.    Notes:
  1857.    - APRFILE[UNUSED] is all zeroes, forcing non-resident abort
  1858.    - Aborts must update MMR0<15:13,6:1> if updating is enabled
  1859. */
  1860.  
  1861. int relocR (int va)
  1862. {
  1863. int dbn, plf, apridx, apr, pa;
  1864.  
  1865. if (MMR0 & MMR0_MME) {                    /* if mmgt */
  1866.     apridx = (va >> VA_V_APF) & 077;        /* index into APR */
  1867.     apr = APRFILE[apridx];                /* with va<18:13> */
  1868.     dbn = va & VA_BN;                /* extr block num */
  1869.     plf = (apr & PDR_PLF) >> 2;            /* extr page length */
  1870.     if ((apr & PDR_NR) == 0) {            /* if non-resident */
  1871.         if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE);
  1872.         MMR0 = MMR0 | MMR0_NR;
  1873.         ABORT (TRAP_MME);  }            /* abort ref */
  1874.     if ((apr & PDR_ED)? dbn < plf: dbn > plf) {    /* if pg lnt error */
  1875.         if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE);
  1876.         MMR0 = MMR0 | MMR0_PL;
  1877.         ABORT (TRAP_MME);  }            /* abort ref */
  1878.     pa = (va & VA_DF) + ((apr >> 10) & 017777700);
  1879.     if ((MMR3 & MMR3_M22E) == 0) {
  1880.         pa = pa & 0777777;
  1881.         if (pa >= 0760000) pa = 017000000 | pa;  }  }
  1882. else {    pa = va & 0177777;                /* mmgt off */
  1883.     if (pa >= 0160000) pa = 017600000 | pa;  }
  1884. return pa;
  1885. }                            /* end relocR */
  1886.  
  1887. /* Relocate virtual address, write access
  1888.  
  1889.    Inputs:
  1890.     va    =    virtual address, <18:16> = mode, I/D space
  1891.    Outputs:
  1892.     pa    =    physical address
  1893.    On aborts, this routine aborts back to the top level simulator
  1894.    with an appropriate trap code.
  1895.  
  1896.    Notes:
  1897.    - APRFILE[UNUSED] is all zeroes, forcing non-resident abort
  1898.    - Aborts must update MMR0<15:13,6:1> if updating is enabled
  1899. */
  1900.  
  1901. int relocW (int va)
  1902. {
  1903. int dbn, plf, apridx, apr, pa;
  1904.  
  1905. if (MMR0 & MMR0_MME) {                    /* if mmgt */
  1906.     apridx = (va >> VA_V_APF) & 077;        /* index into APR */
  1907.     apr = APRFILE[apridx];                /* with va<18:13> */
  1908.     dbn = va & VA_BN;                /* extr block num */
  1909.     plf = (apr & PDR_PLF) >> 2;            /* extr page length */
  1910.     if ((apr & PDR_NR) == 0) {            /* if non-resident */
  1911.         if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE);
  1912.         MMR0 = MMR0 | MMR0_NR;
  1913.         ABORT (TRAP_MME);  }            /* abort ref */
  1914.     if ((apr & PDR_ED)? dbn < plf: dbn > plf) {    /* if pg lnt error */
  1915.         if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE);
  1916.         MMR0 = MMR0 | MMR0_PL;
  1917.         ABORT (TRAP_MME);  }            /* abort ref */
  1918.     if ((apr & PDR_RW) == 0) {            /* if rd only error */
  1919.         if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE);
  1920.         MMR0 = MMR0 | MMR0_RO;
  1921.         ABORT (TRAP_MME);  }            /* abort ref */
  1922.     APRFILE[apridx] = apr | PDR_W;            /* set W */
  1923.     pa = (va & VA_DF) + ((apr >> 10) & 017777700);
  1924.     if ((MMR3 & MMR3_M22E) == 0) {
  1925.         pa = pa & 0777777;
  1926.         if (pa >= 0760000) pa = 017000000 | pa;  }  }
  1927. else {    pa = va & 0177777;                /* mmgt off */
  1928.     if (pa >= 0160000) pa = 017600000 | pa;  }
  1929. return pa;
  1930. }                            /* end relocW */
  1931.  
  1932. /* Relocate virtual address, console access
  1933.  
  1934.    Inputs:
  1935.     va    =    virtual address
  1936.     sw    =    switches
  1937.    Outputs:
  1938.     pa    =    physical address
  1939.    On aborts, this routine returns -1
  1940. */
  1941.  
  1942. int relocC (int va, int sw)
  1943. {
  1944. int mode, dbn, plf, apridx, apr, pa;
  1945.  
  1946. if (MMR0 & MMR0_MME) {                    /* if mmgt */
  1947.     if (sw & SWMASK ('K')) mode = KERNEL;
  1948.     else if (sw & SWMASK ('S')) mode = SUPER;
  1949.     else if (sw & SWMASK ('U')) mode = USER;
  1950.     else if (sw & SWMASK ('P')) mode = (PSW >> PSW_V_PM) & 03;
  1951.     else mode = (PSW >> PSW_V_CM) & 03;
  1952.     va = va | ((sw & SWMASK ('D'))? calc_ds (mode): calc_is (mode));
  1953.     apridx = (va >> VA_V_APF) & 077;        /* index into APR */
  1954.     apr = APRFILE[apridx];                /* with va<18:13> */
  1955.     dbn = va & VA_BN;                /* extr block num */
  1956.     plf = (apr & PDR_PLF) >> 2;            /* extr page length */
  1957.     if ((apr & PDR_NR) == 0) return -1;
  1958.     if ((apr & PDR_ED)? dbn < plf: dbn > plf) return -1;
  1959.     pa = (va & VA_DF) + ((apr >> 10) & 017777700);
  1960.     if ((MMR3 & MMR3_M22E) == 0) {
  1961.         pa = pa & 0777777;
  1962.         if (pa >= 0760000) pa = 017000000 | pa;  }  }
  1963. else {    pa = va & 0177777;                /* mmgt off */
  1964.     if (pa >= 0160000) pa = 017600000 | pa;  }
  1965. return pa;
  1966. }                            /* end relocC */
  1967.  
  1968. /* I/O page lookup and linkage routines
  1969.  
  1970.    Inputs:
  1971.     *data    =    pointer to data to read, if READ
  1972.     data    =    data to store, if WRITE or WRITEB
  1973.     pa    =    address
  1974.     access    =    READ, WRITE, or WRITEB
  1975.    Outputs:
  1976.     status    =    SCPE_OK or SCPE_NXM
  1977. */
  1978.  
  1979. int iopageR (int *data, int pa, int access)
  1980. {
  1981. int stat;
  1982. struct iolink *p;
  1983.  
  1984. for (p = &iotable[0]; p -> low != 0; p++ ) {
  1985.     if ((pa >= p -> low) && (pa <= p -> high))  {
  1986.         stat = p -> read (data, pa, access);
  1987.         trap_req = calc_ints (ipl, int_req, trap_req);
  1988.         return stat;  }  }
  1989. return SCPE_NXM;
  1990. }
  1991.  
  1992. int iopageW (int data, int pa, int access)
  1993. {
  1994. int stat;
  1995. struct iolink *p;
  1996.  
  1997. for (p = &iotable[0]; p -> low != 0; p++ ) {
  1998.     if ((pa >= p -> low) && (pa <= p -> high))  {
  1999.         stat = p -> write (data, pa, access);
  2000.         trap_req = calc_ints (ipl, int_req, trap_req);
  2001.         return stat;  }  }
  2002. return SCPE_NXM;
  2003. }
  2004.  
  2005. /* I/O page routines for CPU registers
  2006.  
  2007.    Switch register and memory management registers
  2008.  
  2009.    SR     17777570    read only
  2010.    MMR0 17777572    read/write, certain bits unimplemented or read only
  2011.    MMR1 17777574    read only
  2012.    MMR2 17777576    read only
  2013.    MMR3 17777516    read/write, certain bits unimplemented
  2014. */
  2015.  
  2016. int SR_MMR012_rd (int *data, int pa, int access)
  2017. {
  2018. switch ((pa >> 1) & 3) {                /* decode pa<2:1> */
  2019. case 0:                            /* SR */
  2020.     *data = SR;
  2021.     return SCPE_OK;
  2022. case 1:                            /* MMR0 */
  2023.     *data = MMR0 & MMR0_IMP;
  2024.     return SCPE_OK;
  2025. case 2:                            /* MMR1 */
  2026.     *data = MMR1;
  2027.     return SCPE_OK;
  2028. case 3:                            /* MMR2 */
  2029.     *data = MMR2;
  2030.     return SCPE_OK;  }                /* end switch pa */
  2031. }                            /* end SR_MMR012_rd */
  2032.  
  2033. int SR_MMR012_wr (int data, int pa, int access)
  2034. {
  2035. switch ((pa >> 1) & 3) {                /* decode pa<2:1> */
  2036. case 0:                            /* DR */
  2037.     DR = data;
  2038.     return SCPE_OK;
  2039. case 1:                            /* MMR0 */
  2040.     if (access == WRITEB) data = (pa & 1)?
  2041.         (MMR0 & 0377) | (data << 8): (MMR0 & ~0377) | data;
  2042.     MMR0 = (MMR0 & ~MMR0_RW) | (data & MMR0_RW);
  2043.     return SCPE_OK;
  2044. default:                        /* MMR1, MMR2 */
  2045.     return SCPE_OK;  }                /* end switch pa */
  2046. }                            /* end SR_MMR012_wr */
  2047.  
  2048. int MMR3_rd (int *data, int pa, int access)        /* MMR3 */
  2049. {
  2050. *data = MMR3 & MMR3_IMP;
  2051. return SCPE_OK;
  2052. }
  2053.  
  2054. int MMR3_wr (int data, int pa, int access)        /* MMR3 */
  2055. {
  2056. if (pa & 1) return SCPE_OK;
  2057. MMR3 = data & MMR3_RW;
  2058. if (cpu_unit.flags & UNIT_18B)
  2059.     MMR3 = MMR3 & ~(MMR3_BME + MMR3_M22E);        /* for UNIX V6 */
  2060. dsenable = calc_ds (cm);
  2061. return SCPE_OK;
  2062. }
  2063.  
  2064. /* PARs and PDRs.  These are grouped in I/O space as follows:
  2065.  
  2066.     17772200 - 17772276    supervisor block
  2067.     17772300 - 17772376    kernel block
  2068.     17777600 - 17777676    user block
  2069.  
  2070.    Within each block, the subblocks are I PDR's, D PDR's, I PAR's, D PAR's
  2071.  
  2072.    Thus, the algorithm for converting between I/O space addresses and
  2073.    APRFILE indices is as follows:
  2074.  
  2075.     idx<3:0> =    dspace'page    =    pa<4:1>
  2076.     par    =    PDR vs PAR    =    pa<5>
  2077.     idx<5:4> =    ker/sup/user    =    pa<8>'~pa<6>
  2078.  
  2079.    Note that the W bit is read only; it is cleared by any write to an APR
  2080. */
  2081.  
  2082. int APR_rd (int *data, int pa, int access)
  2083. {
  2084. int left, idx;
  2085.  
  2086. idx = (pa >> 1) & 017;                    /* dspace'page */
  2087. left = (pa >> 5) & 1;                    /* PDR vs PAR */
  2088. if ((pa & 0100) == 0) idx = idx | 020;            /* 1 for super, user */
  2089. if (pa & 0400) idx = idx | 040;                /* 1 for user only */
  2090. *data = left? (APRFILE[idx] >> 16) & 0177777: APRFILE[idx] & PDR_IMP;
  2091. return SCPE_OK;
  2092. }
  2093.  
  2094. int APR_wr (int data, int pa, int access)
  2095. {
  2096. int left, idx, curr;
  2097.  
  2098. idx = (pa >> 1) & 017;                    /* dspace'page */
  2099. left = (pa >> 5) & 1;                    /* PDR vs PAR */
  2100. if ((pa & 0100) == 0) idx = idx | 020;            /* 1 for super, user */
  2101. if (pa & 0400) idx = idx | 040;                /* 1 for user only */
  2102. curr = left? (APRFILE[idx] >> 16) & 0177777: APRFILE[idx] & PDR_IMP;
  2103. if (access == WRITEB) data = (pa & 1)?
  2104.     (curr & 0377) | (data << 8): (curr & ~0377) | data;
  2105. if (left) APRFILE[idx] =
  2106.     ((APRFILE[idx] & 0177777) | (data << 16)) & ~PDR_W;
  2107. else APRFILE[idx] =
  2108.     ((APRFILE[idx] & ~PDR_RW) | (data & PDR_RW)) & ~PDR_W;
  2109. return SCPE_OK;
  2110. }
  2111.  
  2112. /* CPU control registers
  2113.  
  2114.    MEMERR    17777744    read only, clear on write
  2115.    CCR        17777746    read/write
  2116.    MAINT    17777750    read only
  2117.    HITMISS    17777752    read only
  2118.    CPUERR    17777766    read only, clear on write
  2119.    PIRQ        17777772    read/write, with side effects
  2120.    PSW        17777776    read/write, with side effects
  2121. */
  2122.  
  2123. int CPU_rd (int *data, int pa, int access)
  2124. {
  2125. switch ((pa >> 1) & 017) {                /* decode pa<4:1> */
  2126. case 2:                         /* MEMERR */
  2127.     *data = MEMERR;
  2128.     MEMERR = 0;
  2129.     return SCPE_OK;
  2130. case 3:                            /* CCR */
  2131.     *data = CCR;
  2132.     return SCPE_OK;
  2133. case 4:                            /* MAINT */
  2134.     *data = MAINT;
  2135.     return SCPE_OK;
  2136. case 5:                            /* Hit/miss */
  2137.     *data = HITMISS;
  2138.     return SCPE_OK;
  2139. case 013:                        /* CPUERR */
  2140.     *data = CPUERR & CPUE_IMP;
  2141.     CPUERR = 0;
  2142.     return SCPE_OK;
  2143. case 015:                        /* PIRQ */
  2144.     *data = PIRQ;
  2145.     return SCPE_OK;
  2146. case 017:                        /* PSW */
  2147.     if (access == READC) *data = PSW;
  2148.     else *data = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) |
  2149.         (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
  2150.         (N << PSW_V_N) | (Z << PSW_V_Z) |
  2151.         (V << PSW_V_V) | (C << PSW_V_C);
  2152.     return SCPE_OK;  }                /* end switch PA */
  2153. return SCPE_NXM;                    /* unimplemented */
  2154. }
  2155.  
  2156. /* CPU control registers, continued */
  2157.  
  2158. int CPU_wr (int data, int pa, int access)
  2159. {
  2160. int i, pl, curr, oldrs;
  2161.  
  2162. switch ((pa >> 1) & 017) {                /* decode pa<4:1> */
  2163. case 2:                         /* MEMERR */
  2164.     MEMERR = 0;
  2165.     return SCPE_OK;
  2166. case 3:                            /* CCR */
  2167.     if (access == WRITEB) data = (pa & 1)?
  2168.         (CCR & 0377) | (data << 8): (CCR & ~0377) | data;
  2169.     CCR = data;
  2170.     return SCPE_OK;
  2171. case 4:                            /* MAINT */
  2172.     return SCPE_OK;
  2173. case 5:                            /* Hit/miss */
  2174.     return SCPE_OK;
  2175. case 013:                        /* CPUERR */
  2176.     CPUERR = 0;
  2177.     return SCPE_OK;
  2178. case 015:                        /* PIRQ */
  2179.     if (access == WRITEB) {
  2180.         if (pa & 1) data = data << 8;
  2181.         else return SCPE_OK;  }
  2182.     int_req = int_req & ~(INT_PIR7 + INT_PIR6 + INT_PIR5 + INT_PIR4 +
  2183.         INT_PIR3 + INT_PIR2 + INT_PIR1);
  2184.     PIRQ = data & PIRQ_RW;
  2185.     pl = 0;
  2186.     if (PIRQ & PIRQ_PIR1) { int_req = int_req | INT_PIR1; pl = 0042;  }
  2187.     if (PIRQ & PIRQ_PIR2) { int_req = int_req | INT_PIR2; pl = 0104;  }
  2188.     if (PIRQ & PIRQ_PIR3) { int_req = int_req | INT_PIR3; pl = 0146;  }
  2189.     if (PIRQ & PIRQ_PIR4) { int_req = int_req | INT_PIR4; pl = 0210;  }
  2190.     if (PIRQ & PIRQ_PIR5) { int_req = int_req | INT_PIR5; pl = 0252;  }
  2191.     if (PIRQ & PIRQ_PIR6) { int_req = int_req | INT_PIR6; pl = 0314;  }
  2192.     if (PIRQ & PIRQ_PIR7) { int_req = int_req | INT_PIR7; pl = 0356;  }
  2193.     PIRQ = PIRQ | pl;
  2194.     return SCPE_OK;
  2195.  
  2196. /* CPU control registers, continued
  2197.  
  2198.    Note: Explicit writes to the PSW do not modify the T bit
  2199. */
  2200.  
  2201. case 017:                        /* PSW */
  2202.     if (access == WRITEC) {                /* console access? */
  2203.         PSW = data & PSW_RW;
  2204.         return SCPE_OK;  }
  2205.     curr = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) |
  2206.         (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
  2207.         (N << PSW_V_N) | (Z << PSW_V_Z) |
  2208.         (V << PSW_V_V) | (C << PSW_V_C);
  2209.     STACKFILE[cm] = SP;
  2210.     if (access == WRITEB) data = (pa & 1)?
  2211.         (curr & 0377) | (data << 8): (curr & ~0377) | data;
  2212.     curr = (curr & ~PSW_RW) | (data & PSW_RW);
  2213.     oldrs = rs;
  2214.     cm = (curr >> PSW_V_CM) & 03;            /* call calc_is,ds */
  2215.     pm = (curr >> PSW_V_PM) & 03;
  2216.     rs = (curr >> PSW_V_RS) & 01;
  2217.     ipl = (curr >> PSW_V_IPL) & 07;
  2218.     N = (curr >> PSW_V_N) & 01;
  2219.     Z = (curr >> PSW_V_Z) & 01;
  2220.     V = (curr >> PSW_V_V) & 01;
  2221.     C = (curr >> PSW_V_C) & 01;
  2222.     if (rs != oldrs) {
  2223.         for (i = 0; i < 6; i++) {
  2224.             REGFILE[i][oldrs] = R[i];
  2225.             R[i] = REGFILE[i][rs];  }  }
  2226.     SP = STACKFILE[cm];
  2227.     isenable = calc_is (cm);
  2228.     dsenable = calc_ds (cm);
  2229.     return SCPE_OK;  }                /* end switch pa */
  2230. return SCPE_NXM;                    /* unimplemented */
  2231. }
  2232.  
  2233. /* Reset routine */
  2234.  
  2235. int cpu_reset (DEVICE *dptr)
  2236. {
  2237. PIRQ = MMR0 = MMR1 = MMR2 = MMR3 = 0;
  2238. DR = CPUERR = MEMERR = CCR = HITMISS = 0;
  2239. PSW = 000340;
  2240. trap_req = 0;
  2241. wait_state = 0;
  2242. return cpu_svc (&cpu_unit);
  2243. }
  2244.  
  2245. /* Memory examine */
  2246.  
  2247. int cpu_ex (int *vptr, int addr, UNIT *uptr, int sw)
  2248. {
  2249. if (vptr == NULL) return SCPE_ARG;
  2250. if (sw & SWMASK ('V')) {                /* -v */
  2251.     if (addr >= VASIZE) return SCPE_NXM;
  2252.     addr = relocC (addr, sw);            /* relocate */
  2253.     if (addr < 0) return SCPE_REL;  }
  2254. if (addr < MEMSIZE) {
  2255.     *vptr = M[addr >> 1] & 0177777;
  2256.     return SCPE_OK;  }
  2257. if (addr < IOPAGEBASE) return SCPE_NXM;
  2258. return iopageR (vptr, addr, READC);
  2259. }
  2260.  
  2261. /* Memory deposit */
  2262.  
  2263. int cpu_dep (int val, int addr, UNIT *uptr, int sw)
  2264. {
  2265. if (sw & SWMASK ('V')) {                /* -v */
  2266.     if (addr >= VASIZE) return SCPE_NXM;
  2267.     addr = relocC (addr, sw);            /* relocate */
  2268.     if (addr < 0) return SCPE_REL;  }
  2269. if (addr < MEMSIZE) {
  2270.     M[addr >> 1] = val & 0177777;
  2271.     return SCPE_OK;  }
  2272. if (addr < IOPAGEBASE) return SCPE_NXM;
  2273. return iopageW (val, addr, WRITEC);
  2274. }
  2275.  
  2276. /* Breakpoint service */
  2277.  
  2278. int cpu_svc (UNIT *uptr)
  2279. {
  2280. if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
  2281. save_ibkpt = -1;
  2282. return SCPE_OK;
  2283. }
  2284.