1 /* pdp11_cpu.c: PDP-11 CPU simulator
2 
3    Copyright (c) 1993-2012, Robert M Supnik
4 
5    Permission is hereby granted, free of charge, to any person obtaining a
6    copy of this software and associated documentation files (the "Software"),
7    to deal in the Software without restriction, including without limitation
8    the rights to use, copy, modify, merge, publish, distribute, sublicense,
9    and/or sell copies of the Software, and to permit persons to whom the
10    Software is furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18    ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22    Except as contained in this notice, the name of Robert M Supnik shall not be
23    used in advertising or otherwise to promote the sale, use or other dealings
24    in this Software without prior written authorization from Robert M Supnik.
25 
26    cpu          PDP-11 CPU
27 
28    29-Apr-12    RMS     Fixed compiler warning (Mark Pizzolato)
29    19-Mar-12    RMS     Fixed declaration of sim_switches (Mark Pizzolato)
30    29-Dec-08    RMS     Fixed failure to clear cpu_bme on RESET (Walter Mueller)
31    22-Apr-08    RMS     Fixed MMR0 treatment in RESET (Walter Mueller)
32    02-Feb-08    RMS     Fixed DMA memory address limit test (John Dundas)
33    28-Apr-07    RMS     Removed clock initialization
34    27-Oct-06    RMS     Added idle support
35    18-Oct-06    RMS     Fixed bug in ASH -32 C value
36    24-May-06    RMS     Added instruction history
37    03-May-06    RMS     Fixed XOR operand fetch order for 11/70-style systems
38    22-Sep-05    RMS     Fixed declarations (Sterling Garwood)
39    16-Aug-05    RMS     Fixed C++ declaration and cast problems
40    19-May-05    RMS     Replaced WAIT clock queue check with API call
41    19-Jan-05    RMS     Fixed bug(s) in RESET for 11/70 (Tim Chapman)
42    22-Dec-04    RMS     Fixed WAIT to work in all modes (John Dundas)
43    02-Oct-04    RMS     Added model emulation
44    25-Jan-04    RMS     Removed local debug logging support
45    29-Dec-03    RMS     Formalized 18b Qbus support
46    21-Dec-03    RMS     Added autoconfiguration controls
47    05-Jun-03    RMS     Fixed bugs in memory size table
48    12-Mar-03    RMS     Added logical name support
49    01-Feb-03    RMS     Changed R display to follow PSW<rs>, added SP display
50    19-Jan-03    RMS     Changed mode definitions for Apple Dev Kit conflict
51    05-Jan-03    RMS     Added memory size restore support
52    17-Oct-02    RMS     Fixed bug in examine/deposit (Hans Pufal)
53    08-Oct-02    RMS     Revised to build dib_tab dynamically
54                         Added SHOW IOSPACE
55    09-Sep-02    RMS     Added KW11P support
56    14-Jul-02    RMS     Fixed bug in MMR0 error status load
57    03-Jun-02    RMS     Fixed relocation add overflow, added PS<15:12> = 1111
58                         special case logic to MFPI and removed it from MTPI
59                         (John Dundas)
60    29-Apr-02    RMS     More fixes to DIV and ASH/ASHC (John Dundas)
61    28-Apr-02    RMS     Fixed bugs in illegal instruction 000010 and in
62                         write-only memory pages (Wolfgang Helbig)
63    21-Apr-02    RMS     Fixed bugs in DIV by zero, DIV overflow, TSTSET, RTS,
64                         ASHC -32, and red zone trap (John Dundas)
65    04-Mar-02    RMS     Changed double operand evaluation order for M+
66    23-Feb-02    RMS     Fixed bug in MAINT, CPUERR, MEMERR read
67    28-Jan-02    RMS     Revised for multiple timers; fixed calc_MMR1 macros
68    06-Jan-02    RMS     Revised enable/disable support
69    30-Dec-01    RMS     Added old PC queue
70    25-Dec-01    RMS     Cleaned up sim_inst declarations
71    11-Dec-01    RMS     Moved interrupt debug code
72    07-Dec-01    RMS     Revised to use new breakpoint package
73    08-Nov-01    RMS     Moved I/O to external module
74    26-Oct-01    RMS     Revised to use symbolic definitions for IO page
75    15-Oct-01    RMS     Added debug logging
76    08-Oct-01    RMS     Fixed bug in revised interrupt logic
77    07-Sep-01    RMS     Revised device disable and interrupt mechanisms
78    26-Aug-01    RMS     Added DZ11 support
79    10-Aug-01    RMS     Removed register from declarations
80    17-Jul-01    RMS     Fixed warning from VC++ 6.0
81    01-Jun-01    RMS     Added DZ11 interrupts
82    23-Apr-01    RMS     Added RK611 support
83    05-Apr-01    RMS     Added TS11/TSV05 support
84    05-Mar-01    RMS     Added clock calibration support
85    11-Feb-01    RMS     Added DECtape support
86    25-Jan-01    RMS     Fixed 4M memory definition (Eric Smith)
87    14-Apr-99    RMS     Changed t_addr to unsigned
88    18-Aug-98    RMS     Added CIS support
89    09-May-98    RMS     Fixed bug in DIV overflow test
90    19-Jan-97    RMS     Added RP/RM support
91    06-Apr-96    RMS     Added dynamic memory sizing
92    29-Feb-96    RMS     Added TM11 support
93    17-Jul-94    RMS     Corrected updating of MMR1 if MMR0 locked
94 
95    The register state for the PDP-11 is:
96 
97    REGFILE[0:5][0]      general register set
98    REGFILE[0:5][1]      alternate general register set
99    STACKFILE[4]         stack pointers for kernel, supervisor, unused, user
100    PC                   program counter
101    PSW                  processor status word
102     <15:14> = CM         current processor mode
103     <13:12> = PM         previous processor mode
104     <11> = RS            register set select
105     <8> = FPD            first part done (CIS)
106     <7:5> = IPL          interrupt priority level
107     <4> = TBIT           trace trap enable
108     <3:0> = NZVC         condition codes
109    FR[0:5]              floating point accumulators
110    FPS                  floating point status register
111    FEC                  floating exception code
112    FEA                  floating exception address
113    MMR0,1,2,3           memory management control registers
114    APRFILE[0:63]        memory management relocation registers for
115                          kernel, supervisor, unused, user
116     <31:16> = PAR        processor address registers
117     <15:0> = PDR         processor data registers
118    PIRQ                 processor interrupt request register
119    CPUERR               CPU error register
120    MEMERR               memory system error register
121    CCR                  cache control register
122    MAINT                maintenance register
123    HITMISS              cache status register
124    SR                   switch register
125    DR                   display register
126 
127    The PDP-11 has many instruction formats:
128 
129    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    double operand
130    |  opcode   |   source spec   |     dest spec   |    010000:067777
131    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    110000:167777
132 
133    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    register + operand
134    |        opcode      | src reg|     dest spec   |    004000:004777
135    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    070000:077777
136 
137    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    single operand
138    |           opcode            |     dest spec   |    000100:000177
139    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    000300:000377
140                                                         005000:007777
141                                                         105000:107777
142 
143    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    single register
144    |                opcode                |dest reg|    000200:000207
145    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    000230:000237
146 
147    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    no operand
148    |                     opcode                    |    000000:000007
149    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
150 
151    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    branch
152    |       opcode          |  branch displacement  |    000400:003477
153    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    100000:103477
154 
155    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    EMT/TRAP
156    |       opcode          |       trap code       |    104000:104777
157    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
158 
159    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    cond code operator
160    |                opcode             | immediate |    000240:000277
161    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
162 
163    An operand specifier consists of an addressing mode and a register.
164    The addressing modes are:
165 
166    0    register direct         R               op = R
167    1    register deferred       (R)             op = M[R]
168    2    autoincrement           (R)+            op = M[R]; R = R + length
169    3    autoincrement deferred  @(R)+           op = M[M[R]]; R = R + 2
170    4    autodecrement           -(R)            R = R - length; op = M[R]
171    5    autodecrement deferred  @-(R)           R = R - 2; op = M[M[R]]
172    6    displacement            d(R)            op = M[R + disp]
173    7    displacement deferred   @d(R)           op = M[M[R + disp]]
174 
175    There are eight general registers, R0-R7.  R6 is the stack pointer,
176    R7 the PC.  The combination of addressing modes with R7 yields:
177 
178    27   immediate               #n              op = M[PC]; PC = PC + 2
179    37   absolute                @#n             op = M[M[PC]]; PC = PC + 2
180    67   relative                d(PC)           op = M[PC + disp]
181    77   relative deferred       @d(PC)          op = M[M[PC + disp]]
182 
183    This routine is the instruction decode routine for the PDP-11.  It
184    is called from the simulator control program to execute instructions
185    in simulated memory, starting at the simulated PC.  It runs until an
186    enabled exception is encountered.
187 
188    General notes:
189 
190    1. Virtual address format.  PDP-11 memory management uses the 16b
191       virtual address, the type of reference (instruction or data), and
192       the current mode, to construct the 22b physical address.  To
193       package this conveniently, the simulator uses a 19b pseudo virtual
194       address, consisting of the 16b virtual address prefixed with the
195       current mode and ispace/dspace indicator.  These are precalculated
196       as isenable and dsenable for ispace and dspace, respectively, and
197       must be recalculated whenever MMR0, MMR3, or PSW<cm> changes.
198 
199    2. Traps and interrupts.  Variable trap_req bit-encodes all possible
200       traps.  In addition, an interrupt pending bit is encoded as the
201       lowest priority trap.  Traps are processed by trap_vec and trap_clear,
202       which provide the vector and subordinate traps to clear, respectively.
203 
204       Array int_req[0:7] bit encodes all possible interrupts.  It is masked
205       under the interrupt priority level, ipl.  If any interrupt request
206       is not masked, the interrupt bit is set in trap_req.  While most
207       interrupts are handled centrally, a device can supply an interrupt
208       acknowledge routine.
209 
210    3. PSW handling.  The PSW is kept as components, for easier access.
211       Because the PSW can be explicitly written as address 17777776,
212       all instructions must update PSW before executing their last write.
213 
214    4. Adding I/O devices.  These modules must be modified:
215 
216         pdp11_defs.h    add device address and interrupt definitions
217         pdp11_sys.c     add to sim_devices table entry
218 */
219 
220 /* Definitions */
221 
222 #include "pdp11_defs.h"
223 #include "pdp11_cpumod.h"
224 
225 #define PCQ_SIZE        64                              /* must be 2**n */
226 #define PCQ_MASK        (PCQ_SIZE - 1)
227 #define PCQ_ENTRY       pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
228 #define calc_is(md)     ((md) << VA_V_MODE)
229 #define calc_ds(md)     (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0))
230 #define calc_MMR1(val)  ((MMR1)? (((val) << 8) | MMR1): (val))
231 #define GET_SIGN_W(v)   (((v) >> 15) & 1)
232 #define GET_SIGN_B(v)   (((v) >> 7) & 1)
233 #define GET_Z(v)        ((v) == 0)
234 #define JMP_PC(x)       PCQ_ENTRY; PC = (x)
235 #define BRANCH_F(x)     PCQ_ENTRY; PC = (PC + (((x) + (x)) & 0377)) & 0177777
236 #define BRANCH_B(x)     PCQ_ENTRY; PC = (PC + (((x) + (x)) | 0177400)) & 0177777
237 #define last_pa         (cpu_unit.u4)                   /* auto save/rest */
238 #define UNIT_V_MSIZE    (UNIT_V_UF + 0)                 /* dummy */
239 #define UNIT_MSIZE      (1u << UNIT_V_MSIZE)
240 
241 #define HIST_MIN        64
242 #define HIST_MAX        (1u << 18)
243 #define HIST_VLD        1                               /* make PC odd */
244 #define HIST_ILNT       4                               /* max inst length */
245 
246 typedef struct {
247     uint16              pc;
248     uint16              psw;
249     uint16              src;
250     uint16              dst;
251     uint16              inst[HIST_ILNT];
252     } InstHistory;
253 
254 /* Global state */
255 
256 extern FILE *sim_log;
257 
258 uint16 *M = NULL;                                       /* memory */
259 int32 REGFILE[6][2] = { 0 };                            /* R0-R5, two sets */
260 int32 STACKFILE[4] = { 0 };                             /* SP, four modes */
261 int32 saved_PC = 0;                                     /* program counter */
262 int32 R[8] = { 0 };                                     /* working registers */
263 int32 PSW = 0;                                          /* PSW */
264   int32 cm = 0;                                         /*   current mode */
265   int32 pm = 0;                                         /*   previous mode */
266   int32 rs = 0;                                         /*   register set */
267   int32 fpd = 0;                                        /*   first part done */
268   int32 ipl = 0;                                        /*   int pri level */
269   int32 tbit = 0;                                       /*   trace flag */
270   int32 N = 0, Z = 0, V = 0, C = 0;                     /*   condition codes */
271 int32 wait_state = 0;                                   /* wait state */
272 int32 trap_req = 0;                                     /* trap requests */
273 int32 int_req[IPL_HLVL] = { 0 };                        /* interrupt requests */
274 int32 PIRQ = 0;                                         /* programmed int req */
275 int32 STKLIM = 0;                                       /* stack limit */
276 fpac_t FR[6] = { 0 };                                   /* fp accumulators */
277 int32 FPS = 0;                                          /* fp status */
278 int32 FEC = 0;                                          /* fp exception code */
279 int32 FEA = 0;                                          /* fp exception addr */
280 int32 APRFILE[64] = { 0 };                              /* PARs/PDRs */
281 int32 MMR0 = 0;                                         /* MMR0 - status */
282 int32 MMR1 = 0;                                         /* MMR1 - R+/-R */
283 int32 MMR2 = 0;                                         /* MMR2 - saved PC */
284 int32 MMR3 = 0;                                         /* MMR3 - 22b status */
285 int32 cpu_bme = 0;                                      /* bus map enable */
286 int32 cpu_astop = 0;                                    /* address stop */
287 int32 isenable = 0, dsenable = 0;                       /* i, d space flags */
288 int32 stop_trap = 1;                                    /* stop on trap */
289 int32 stop_vecabort = 1;                                /* stop on vec abort */
290 int32 stop_spabort = 1;                                 /* stop on SP abort */
291 int32 wait_enable = 0;                                  /* wait state enable */
292 int32 autcon_enb = 1;                                   /* autoconfig enable */
293 uint32 cpu_model = MOD_1173;                            /* CPU model */
294 uint32 cpu_type = 1u << MOD_1173;                       /* model as bit mask */
295 uint32 cpu_opt = SOP_1173;                              /* CPU options */
296 uint16 pcq[PCQ_SIZE] = { 0 };                           /* PC queue */
297 int32 pcq_p = 0;                                        /* PC queue ptr */
298 REG *pcq_r = NULL;                                      /* PC queue reg ptr */
299 jmp_buf save_env;                                       /* abort handler */
300 int32 hst_p = 0;                                        /* history pointer */
301 int32 hst_lnt = 0;                                      /* history length */
302 InstHistory *hst = NULL;                                /* instruction history */
303 int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS };  /* dspace enables */
304 t_addr cpu_memsize = INIMEMSIZE;                        /* last mem addr */
305 
306 extern int32 CPUERR, MAINT;
307 extern int32 sim_interval;
308 extern int32 sim_int_char;
309 extern int32 sim_switches;
310 extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
311 extern t_bool sim_idle_enab;
312 extern DEVICE *sim_devices[];
313 extern CPUTAB cpu_tab[];
314 
315 /* Function declarations */
316 
317 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
318 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
319 t_stat cpu_reset (DEVICE *dptr);
320 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
321 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
322 t_stat cpu_show_virt (FILE *st, UNIT *uptr, int32 val, void *desc);
323 int32 GeteaB (int32 spec);
324 int32 GeteaW (int32 spec);
325 int32 relocR (int32 addr);
326 int32 relocW (int32 addr);
327 void relocR_test (int32 va, int32 apridx);
328 void relocW_test (int32 va, int32 apridx);
329 t_bool PLF_test (int32 va, int32 apr);
330 void reloc_abort (int32 err, int32 apridx);
331 int32 ReadE (int32 addr);
332 int32 ReadW (int32 addr);
333 int32 ReadB (int32 addr);
334 int32 ReadMW (int32 addr);
335 int32 ReadMB (int32 addr);
336 void WriteW (int32 data, int32 addr);
337 void WriteB (int32 data, int32 addr);
338 void PWriteW (int32 data, int32 addr);
339 void PWriteB (int32 data, int32 addr);
340 void set_r_display (int32 rs, int32 cm);
341 t_stat CPU_wr (int32 data, int32 addr, int32 access);
342 void set_stack_trap (int32 adr);
343 int32 get_PSW (void);
344 void put_PSW (int32 val, t_bool prot);
345 void put_PIRQ (int32 val);
346 
347 extern void fp11 (int32 IR);
348 extern t_stat cis11 (int32 IR);
349 extern t_stat fis11 (int32 IR);
350 extern t_stat build_dib_tab (void);
351 extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc);
352 extern t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc);
353 extern t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc);
354 extern t_stat iopageR (int32 *data, uint32 addr, int32 access);
355 extern t_stat iopageW (int32 data, uint32 addr, int32 access);
356 extern int32 calc_ints (int32 nipl, int32 trq);
357 extern int32 get_vector (int32 nipl);
358 
359 /* Trap data structures */
360 
361 int32 trap_vec[TRAP_V_MAX] = {                          /* trap req to vector */
362     VEC_RED, VEC_ODD, VEC_MME, VEC_NXM,
363     VEC_PAR, VEC_PRV, VEC_ILL, VEC_BPT,
364     VEC_IOT, VEC_EMT, VEC_TRAP, VEC_TRC,
365     VEC_YEL, VEC_PWRFL, VEC_FPE
366     };
367 
368 int32 trap_clear[TRAP_V_MAX] = {                        /* trap clears */
369     TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_ODD+TRAP_NXM,
370     TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC,
371     TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC,
372     TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC,
373     TRAP_PAR+TRAP_TRC, TRAP_PRV+TRAP_TRC,
374     TRAP_ILL+TRAP_TRC, TRAP_BPT+TRAP_TRC,
375     TRAP_IOT+TRAP_TRC, TRAP_EMT+TRAP_TRC,
376     TRAP_TRAP+TRAP_TRC, TRAP_TRC,
377     TRAP_YEL, TRAP_PWRFL, TRAP_FPE
378     };
379 
380 /* CPU data structures
381 
382    cpu_dev      CPU device descriptor
383    cpu_unit     CPU unit descriptor
384    cpu_reg      CPU register list
385    cpu_mod      CPU modifier list
386 */
387 
388 UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK, INIMEMSIZE) };
389 
390 REG cpu_reg[] = {
391     { ORDATA (PC, saved_PC, 16) },
392     { ORDATA (R0, REGFILE[0][0], 16) },
393     { ORDATA (R1, REGFILE[1][0], 16) },
394     { ORDATA (R2, REGFILE[2][0], 16) },
395     { ORDATA (R3, REGFILE[3][0], 16) },
396     { ORDATA (R4, REGFILE[4][0], 16) },
397     { ORDATA (R5, REGFILE[5][0], 16) },
398     { ORDATA (SP, STACKFILE[MD_KER], 16) },
399     { ORDATA (R00, REGFILE[0][0], 16) },
400     { ORDATA (R01, REGFILE[1][0], 16) },
401     { ORDATA (R02, REGFILE[2][0], 16) },
402     { ORDATA (R03, REGFILE[3][0], 16) },
403     { ORDATA (R04, REGFILE[4][0], 16) },
404     { ORDATA (R05, REGFILE[5][0], 16) },
405     { ORDATA (R10, REGFILE[0][1], 16) },
406     { ORDATA (R11, REGFILE[1][1], 16) },
407     { ORDATA (R12, REGFILE[2][1], 16) },
408     { ORDATA (R13, REGFILE[3][1], 16) },
409     { ORDATA (R14, REGFILE[4][1], 16) },
410     { ORDATA (R15, REGFILE[5][1], 16) },
411     { ORDATA (KSP, STACKFILE[MD_KER], 16) },
412     { ORDATA (SSP, STACKFILE[MD_SUP], 16) },
413     { ORDATA (USP, STACKFILE[MD_USR], 16) },
414     { ORDATA (PSW, PSW, 16) },
415     { GRDATA (CM, PSW, 8, 2, PSW_V_CM) },
416     { GRDATA (PM, PSW, 8, 2, PSW_V_PM) },
417     { FLDATA (RS, PSW, PSW_V_RS) },
418     { FLDATA (FPD, PSW, PSW_V_FPD) },
419     { GRDATA (IPL, PSW, 8, 3, PSW_V_IPL) },
420     { FLDATA (T, PSW, PSW_V_TBIT) },
421     { FLDATA (N, PSW, PSW_V_N) },
422     { FLDATA (Z, PSW, PSW_V_Z) },
423     { FLDATA (V, PSW, PSW_V_V) },
424     { FLDATA (C, PSW, PSW_V_C) },
425     { ORDATA (PIRQ, PIRQ, 16) },
426     { ORDATA (STKLIM, STKLIM, 16) },
427     { ORDATA (FAC0H, FR[0].h, 32) },
428     { ORDATA (FAC0L, FR[0].l, 32) },
429     { ORDATA (FAC1H, FR[1].h, 32) },
430     { ORDATA (FAC1L, FR[1].l, 32) },
431     { ORDATA (FAC2H, FR[2].h, 32) },
432     { ORDATA (FAC2L, FR[2].l, 32) },
433     { ORDATA (FAC3H, FR[3].h, 32) },
434     { ORDATA (FAC3L, FR[3].l, 32) },
435     { ORDATA (FAC4H, FR[4].h, 32) },
436     { ORDATA (FAC4L, FR[4].l, 32) },
437     { ORDATA (FAC5H, FR[5].h, 32) },
438     { ORDATA (FAC5L, FR[5].l, 32) },
439     { ORDATA (FPS, FPS, 16) },
440     { ORDATA (FEA, FEA, 16) },
441     { ORDATA (FEC, FEC, 4) },
442     { ORDATA (MMR0, MMR0, 16) },
443     { ORDATA (MMR1, MMR1, 16) },
444     { ORDATA (MMR2, MMR2, 16) },
445     { ORDATA (MMR3, MMR3, 16) },
446     { GRDATA (KIPAR0, APRFILE[000], 8, 16, 16) },
447     { GRDATA (KIPDR0, APRFILE[000], 8, 16, 0) },
448     { GRDATA (KIPAR1, APRFILE[001], 8, 16, 16) },
449     { GRDATA (KIPDR1, APRFILE[001], 8, 16, 0) },
450     { GRDATA (KIPAR2, APRFILE[002], 8, 16, 16) },
451     { GRDATA (KIPDR2, APRFILE[002], 8, 16, 0) },
452     { GRDATA (KIPAR3, APRFILE[003], 8, 16, 16) },
453     { GRDATA (KIPDR3, APRFILE[003], 8, 16, 0) },
454     { GRDATA (KIPAR4, APRFILE[004], 8, 16, 16) },
455     { GRDATA (KIPDR4, APRFILE[004], 8, 16, 0) },
456     { GRDATA (KIPAR5, APRFILE[005], 8, 16, 16) },
457     { GRDATA (KIPDR5, APRFILE[005], 8, 16, 0) },
458     { GRDATA (KIPAR6, APRFILE[006], 8, 16, 16) },
459     { GRDATA (KIPDR6, APRFILE[006], 8, 16, 0) },
460     { GRDATA (KIPAR7, APRFILE[007], 8, 16, 16) },
461     { GRDATA (KIPDR7, APRFILE[007], 8, 16, 0) },
462     { GRDATA (KDPAR0, APRFILE[010], 8, 16, 16) },
463     { GRDATA (KDPDR0, APRFILE[010], 8, 16, 0) },
464     { GRDATA (KDPAR1, APRFILE[011], 8, 16, 16) },
465     { GRDATA (KDPDR1, APRFILE[011], 8, 16, 0) },
466     { GRDATA (KDPAR2, APRFILE[012], 8, 16, 16) },
467     { GRDATA (KDPDR2, APRFILE[012], 8, 16, 0) },
468     { GRDATA (KDPAR3, APRFILE[013], 8, 16, 16) },
469     { GRDATA (KDPDR3, APRFILE[013], 8, 16, 0) },
470     { GRDATA (KDPAR4, APRFILE[014], 8, 16, 16) },
471     { GRDATA (KDPDR4, APRFILE[014], 8, 16, 0) },
472     { GRDATA (KDPAR5, APRFILE[015], 8, 16, 16) },
473     { GRDATA (KDPDR5, APRFILE[015], 8, 16, 0) },
474     { GRDATA (KDPAR6, APRFILE[016], 8, 16, 16) },
475     { GRDATA (KDPDR6, APRFILE[016], 8, 16, 0) },
476     { GRDATA (KDPAR7, APRFILE[017], 8, 16, 16) },
477     { GRDATA (KDPDR7, APRFILE[017], 8, 16, 0) },
478     { GRDATA (SIPAR0, APRFILE[020], 8, 16, 16) },
479     { GRDATA (SIPDR0, APRFILE[020], 8, 16, 0) },
480     { GRDATA (SIPAR1, APRFILE[021], 8, 16, 16) },
481     { GRDATA (SIPDR1, APRFILE[021], 8, 16, 0) },
482     { GRDATA (SIPAR2, APRFILE[022], 8, 16, 16) },
483     { GRDATA (SIPDR2, APRFILE[022], 8, 16, 0) },
484     { GRDATA (SIPAR3, APRFILE[023], 8, 16, 16) },
485     { GRDATA (SIPDR3, APRFILE[023], 8, 16, 0) },
486     { GRDATA (SIPAR4, APRFILE[024], 8, 16, 16) },
487     { GRDATA (SIPDR4, APRFILE[024], 8, 16, 0) },
488     { GRDATA (SIPAR5, APRFILE[025], 8, 16, 16) },
489     { GRDATA (SIPDR5, APRFILE[025], 8, 16, 0) },
490     { GRDATA (SIPAR6, APRFILE[026], 8, 16, 16) },
491     { GRDATA (SIPDR6, APRFILE[026], 8, 16, 0) },
492     { GRDATA (SIPAR7, APRFILE[027], 8, 16, 16) },
493     { GRDATA (SIPDR7, APRFILE[027], 8, 16, 0) },
494     { GRDATA (SDPAR0, APRFILE[030], 8, 16, 16) },
495     { GRDATA (SDPDR0, APRFILE[030], 8, 16, 0) },
496     { GRDATA (SDPAR1, APRFILE[031], 8, 16, 16) },
497     { GRDATA (SDPDR1, APRFILE[031], 8, 16, 0) },
498     { GRDATA (SDPAR2, APRFILE[032], 8, 16, 16) },
499     { GRDATA (SDPDR2, APRFILE[032], 8, 16, 0) },
500     { GRDATA (SDPAR3, APRFILE[033], 8, 16, 16) },
501     { GRDATA (SDPDR3, APRFILE[033], 8, 16, 0) },
502     { GRDATA (SDPAR4, APRFILE[034], 8, 16, 16) },
503     { GRDATA (SDPDR4, APRFILE[034], 8, 16, 0) },
504     { GRDATA (SDPAR5, APRFILE[035], 8, 16, 16) },
505     { GRDATA (SDPDR5, APRFILE[035], 8, 16, 0) },
506     { GRDATA (SDPAR6, APRFILE[036], 8, 16, 16) },
507     { GRDATA (SDPDR6, APRFILE[036], 8, 16, 0) },
508     { GRDATA (SDPAR7, APRFILE[037], 8, 16, 16) },
509     { GRDATA (SDPDR7, APRFILE[037], 8, 16, 0) },
510     { GRDATA (UIPAR0, APRFILE[060], 8, 16, 16) },
511     { GRDATA (UIPDR0, APRFILE[060], 8, 16, 0) },
512     { GRDATA (UIPAR1, APRFILE[061], 8, 16, 16) },
513     { GRDATA (UIPDR1, APRFILE[061], 8, 16, 0) },
514     { GRDATA (UIPAR2, APRFILE[062], 8, 16, 16) },
515     { GRDATA (UIPDR2, APRFILE[062], 8, 16, 0) },
516     { GRDATA (UIPAR3, APRFILE[063], 8, 16, 16) },
517     { GRDATA (UIPDR3, APRFILE[063], 8, 16, 0) },
518     { GRDATA (UIPAR4, APRFILE[064], 8, 16, 16) },
519     { GRDATA (UIPDR4, APRFILE[064], 8, 16, 0) },
520     { GRDATA (UIPAR5, APRFILE[065], 8, 16, 16) },
521     { GRDATA (UIPDR5, APRFILE[065], 8, 16, 0) },
522     { GRDATA (UIPAR6, APRFILE[066], 8, 16, 16) },
523     { GRDATA (UIPDR6, APRFILE[066], 8, 16, 0) },
524     { GRDATA (UIPAR7, APRFILE[067], 8, 16, 16) },
525     { GRDATA (UIPDR7, APRFILE[067], 8, 16, 0) },
526     { GRDATA (UDPAR0, APRFILE[070], 8, 16, 16) },
527     { GRDATA (UDPDR0, APRFILE[070], 8, 16, 0) },
528     { GRDATA (UDPAR1, APRFILE[071], 8, 16, 16) },
529     { GRDATA (UDPDR1, APRFILE[071], 8, 16, 0) },
530     { GRDATA (UDPAR2, APRFILE[072], 8, 16, 16) },
531     { GRDATA (UDPDR2, APRFILE[072], 8, 16, 0) },
532     { GRDATA (UDPAR3, APRFILE[073], 8, 16, 16) },
533     { GRDATA (UDPDR3, APRFILE[073], 8, 16, 0) },
534     { GRDATA (UDPAR4, APRFILE[074], 8, 16, 16) },
535     { GRDATA (UDPDR4, APRFILE[074], 8, 16, 0) },
536     { GRDATA (UDPAR5, APRFILE[075], 8, 16, 16) },
537     { GRDATA (UDPDR5, APRFILE[075], 8, 16, 0) },
538     { GRDATA (UDPAR6, APRFILE[076], 8, 16, 16) },
539     { GRDATA (UDPDR6, APRFILE[076], 8, 16, 0) },
540     { GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) },
541     { GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) },
542     { BRDATA (IREQ, int_req, 8, 32, IPL_HLVL), REG_RO },
543     { ORDATA (TRAPS, trap_req, TRAP_V_MAX) },
544     { FLDATA (WAIT, wait_state, 0) },
545     { FLDATA (WAIT_ENABLE, wait_enable, 0), REG_HIDDEN },
546     { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) },
547     { FLDATA (STOP_VECA, stop_vecabort, 0) },
548     { FLDATA (STOP_SPA, stop_spabort, 0) },
549     { FLDATA (AUTOCON, autcon_enb, 0), REG_HRO },
550     { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC },
551     { ORDATA (PCQP, pcq_p, 6), REG_HRO },
552     { ORDATA (WRU, sim_int_char, 8) },
553     { ORDATA (MODEL, cpu_model, 16), REG_HRO },
554     { ORDATA (OPTIONS, cpu_opt, 32), REG_HRO },
555     { NULL}
556     };
557 
558 MTAB cpu_mod[] = {
559     { MTAB_XTD|MTAB_VDV, 0, "TYPE", NULL,
560       NULL, &cpu_show_model },
561     { MTAB_XTD|MTAB_VDV, MOD_1103, NULL, "11/03", &cpu_set_model },
562     { MTAB_XTD|MTAB_VDV, MOD_1104, NULL, "11/04", &cpu_set_model },
563     { MTAB_XTD|MTAB_VDV, MOD_1105, NULL, "11/05", &cpu_set_model },
564     { MTAB_XTD|MTAB_VDV, MOD_1120, NULL, "11/20", &cpu_set_model },
565     { MTAB_XTD|MTAB_VDV, MOD_1123, NULL, "11/23", &cpu_set_model },
566     { MTAB_XTD|MTAB_VDV, MOD_1123P, NULL, "11/23+", &cpu_set_model },
567     { MTAB_XTD|MTAB_VDV, MOD_1124, NULL, "11/24", &cpu_set_model },
568     { MTAB_XTD|MTAB_VDV, MOD_1134, NULL, "11/34", &cpu_set_model },
569     { MTAB_XTD|MTAB_VDV, MOD_1140, NULL, "11/40", &cpu_set_model },
570     { MTAB_XTD|MTAB_VDV, MOD_1144, NULL, "11/44", &cpu_set_model },
571     { MTAB_XTD|MTAB_VDV, MOD_1145, NULL, "11/45", &cpu_set_model },
572     { MTAB_XTD|MTAB_VDV, MOD_1153, NULL, "11/53", &cpu_set_model },
573     { MTAB_XTD|MTAB_VDV, MOD_1160, NULL, "11/60", &cpu_set_model },
574     { MTAB_XTD|MTAB_VDV, MOD_1170, NULL, "11/70", &cpu_set_model },
575     { MTAB_XTD|MTAB_VDV, MOD_1173, NULL, "11/73", &cpu_set_model },
576     { MTAB_XTD|MTAB_VDV, MOD_1173B, NULL, "11/73B", &cpu_set_model },
577     { MTAB_XTD|MTAB_VDV, MOD_1183, NULL, "11/83", &cpu_set_model },
578     { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "11/84", &cpu_set_model },
579     { MTAB_XTD|MTAB_VDV, MOD_1193, NULL, "11/93", &cpu_set_model },
580     { MTAB_XTD|MTAB_VDV, MOD_1194, NULL, "11/94", &cpu_set_model },
581     { MTAB_XTD|MTAB_VDV, MOD_1173, NULL, "Q22", &cpu_set_model },
582     { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "URH11", &cpu_set_model },
583     { MTAB_XTD|MTAB_VDV, MOD_1170, NULL, "URH70", &cpu_set_model },
584     { MTAB_XTD|MTAB_VDV, MOD_1145, NULL, "U18", &cpu_set_model },
585     { MTAB_XTD|MTAB_VDV, OPT_EIS, NULL, "EIS", &cpu_set_opt },
586     { MTAB_XTD|MTAB_VDV, OPT_EIS, NULL, "NOEIS", &cpu_clr_opt },
587     { MTAB_XTD|MTAB_VDV, OPT_FIS, NULL, "FIS", &cpu_set_opt },
588     { MTAB_XTD|MTAB_VDV, OPT_FIS, NULL, "NOFIS", &cpu_clr_opt },
589     { MTAB_XTD|MTAB_VDV, OPT_FPP, NULL, "FPP", &cpu_set_opt },
590     { MTAB_XTD|MTAB_VDV, OPT_FPP, NULL, "NOFPP", &cpu_clr_opt },
591     { MTAB_XTD|MTAB_VDV, OPT_CIS, NULL, "CIS", &cpu_set_opt },
592     { MTAB_XTD|MTAB_VDV, OPT_CIS, NULL, "NOCIS", &cpu_clr_opt },
593     { MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "MMU", &cpu_set_opt },
594     { MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "NOMMU", &cpu_clr_opt },
595     { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
596     { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
597     { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size},
598     { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size},
599     { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size},
600     { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size},
601     { UNIT_MSIZE, 98304, NULL, "96K", &cpu_set_size},
602     { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size},
603     { UNIT_MSIZE, 196608, NULL, "192K", &cpu_set_size},
604     { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size},
605     { UNIT_MSIZE, 393216, NULL, "384K", &cpu_set_size},
606     { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size},
607     { UNIT_MSIZE, 786432, NULL, "768K", &cpu_set_size},
608     { UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size},
609     { UNIT_MSIZE, 2097152, NULL, "2048K", &cpu_set_size},
610     { UNIT_MSIZE, 3145728, NULL, "3072K", &cpu_set_size},
611     { UNIT_MSIZE, 4186112, NULL, "4096K", &cpu_set_size},
612     { UNIT_MSIZE, 1048576, NULL, "1M", &cpu_set_size},
613     { UNIT_MSIZE, 2097152, NULL, "2M", &cpu_set_size},
614     { UNIT_MSIZE, 3145728, NULL, "3M", &cpu_set_size},
615     { UNIT_MSIZE, 4186112, NULL, "4M", &cpu_set_size},
616     { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
617       NULL, &show_iospace },
618     { MTAB_XTD|MTAB_VDV, 1, "AUTOCONFIG", "AUTOCONFIG",
619       &set_autocon, &show_autocon },
620     { MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG",
621       &set_autocon, NULL },
622     { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
623       &cpu_set_hist, &cpu_show_hist },
624     { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL,
625       NULL, &cpu_show_virt },
626     { 0 }
627     };
628 
629 DEVICE cpu_dev = {
630     "CPU", &cpu_unit, cpu_reg, cpu_mod,
631     1, 8, 22, 2, 8, 16,
632     &cpu_ex, &cpu_dep, &cpu_reset,
633     NULL, NULL, NULL,
634     NULL, DEV_DYNM, 0,
635     NULL, &cpu_set_size, NULL
636     };
637 
sim_instr(void)638 t_stat sim_instr (void)
639 {
640 int abortval, i;
641 volatile int32 trapea;                                  /* used by setjmp */
642 t_stat reason;
643 
644 /* Restore register state
645 
646         1. PSW components
647         2. Active register file based on PSW<rs>
648         3. Active stack pointer based on PSW<cm>
649         4. Memory management control flags
650         5. Interrupt system
651 */
652 
653 reason = build_dib_tab ();                              /* build, chk dib_tab */
654 if (reason != SCPE_OK)
655     return reason;
656 if (MEMSIZE < cpu_tab[cpu_model].maxm)                  /* mem size < max? */
657     cpu_memsize = MEMSIZE;                              /* then okay */
658 else cpu_memsize = cpu_tab[cpu_model].maxm - IOPAGESIZE;/* max - io page */
659 cpu_type = 1u << cpu_model;                             /* reset type mask */
660 cpu_bme = (MMR3 & MMR3_BME) && (cpu_opt & OPT_UBM);     /* map enabled? */
661 PC = saved_PC;
662 put_PSW (PSW, 0);                                       /* set PSW, call calc_xs */
663 for (i = 0; i < 6; i++)
664     R[i] = REGFILE[i][rs];
665 SP = STACKFILE[cm];
666 isenable = calc_is (cm);
667 dsenable = calc_ds (cm);
668 put_PIRQ (PIRQ);                                        /* rewrite PIRQ */
669 STKLIM = STKLIM & STKLIM_RW;                            /* clean up STKLIM */
670 MMR0 = MMR0 | MMR0_IC;                                  /* usually on */
671 
672 trap_req = calc_ints (ipl, trap_req);                   /* upd int req */
673 trapea = 0;
674 reason = 0;
675 
676 /* Abort handling
677 
678    If an abort occurs in memory management or memory access, the lower
679    level routine executes a longjmp to this area OUTSIDE the main
680    simulation loop.  The longjmp specifies a trap mask which is OR'd
681    into the trap_req register.  Simulation then resumes at the fetch
682    phase, and the trap is sprung.
683 
684    Aborts which occur within a trap sequence (trapea != 0) require
685    special handling.  If the abort occured on the stack pushes, and
686    the mode (encoded in trapea) is kernel, an "emergency" kernel
687    stack is created at 4, and a red zone stack trap taken.
688 
689    All variables used in setjmp processing, or assumed to be valid
690    after setjmp, must be volatile or global.
691 */
692 
693 abortval = setjmp (save_env);                           /* set abort hdlr */
694 if (abortval != 0) {
695     trap_req = trap_req | abortval;                     /* or in trap flag */
696     if ((trapea > 0) && stop_vecabort)
697         reason = STOP_VECABORT;
698     if ((trapea < 0) &&                                 /* stack push abort? */
699         (CPUT (STOP_STKA) || stop_spabort)) reason = STOP_SPABORT;
700     if (trapea == ~MD_KER) {                            /* kernel stk abort? */
701         setTRAP (TRAP_RED);
702         setCPUERR (CPUE_RED);
703         STACKFILE[MD_KER] = 4;
704         if (cm == MD_KER)
705             SP = 4;
706         }
707     }
708 
709 /* Main instruction fetch/decode loop
710 
711    Check for traps or interrupts.  If trap, locate the vector and check
712    for stop condition.  If interrupt, locate the vector.
713 */
714 
715 while (reason == 0)  {
716 
717     int32 IR, srcspec, srcreg, dstspec, dstreg;
718     int32 src, src2, dst, ea;
719     int32 i, t, sign, oldrs, trapnum;
720 
721     if (cpu_astop) {
722         cpu_astop = 0;
723         reason = SCPE_STOP;
724         break;
725 		}
726 
727     if (sim_interval <= 0) {                            /* intv cnt expired? */
728         reason = sim_process_event ();                  /* process events */
729         trap_req = calc_ints (ipl, trap_req);           /* recalc int req */
730         continue;
731         }                                               /* end if sim_interval */
732 
733     if (trap_req) {                                     /* check traps, ints */
734         trapea = 0;                                     /* assume srch fails */
735         if ((t = trap_req & TRAP_ALL)) {                /* if a trap */
736             for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) {
737                 if ((t >> trapnum) & 1) {               /* trap set? */
738                     trapea = trap_vec[trapnum];         /* get vec, clr */
739                     trap_req = trap_req & ~trap_clear[trapnum];
740                     if ((stop_trap >> trapnum) & 1)     /* stop on trap? */
741                         reason = trapnum + 1;
742                     break;
743                     }                                   /* end if t & 1 */
744                 }                                       /* end for */
745             }                                           /* end if t */
746         else {
747             trapea = get_vector (ipl);                  /* get int vector */
748             trapnum = TRAP_V_MAX;                       /* defang stk trap */
749             }                                           /* end else t */
750         if (trapea == 0) {                              /* nothing to do? */
751             trap_req = calc_ints (ipl, 0);              /* recalculate */
752             continue;                                   /* back to fetch */
753             }                                           /* end if trapea */
754 
755 /* Process a trap or interrupt
756 
757    1. Exit wait state
758    2. Save the current SP and PSW
759    3. Read the new PC, new PSW from trapea, kernel data space
760    4. Get the mode and stack selected by the new PSW
761    5. Push the old PC and PSW on the new stack
762    6. Update SP, PSW, and PC
763    7. If not stack overflow, check for stack overflow
764 */
765 
766         wait_state = 0;                                 /* exit wait state */
767         STACKFILE[cm] = SP;
768         PSW = get_PSW ();                               /* assemble PSW */
769         oldrs = rs;
770         if (CPUT (HAS_MMTR)) {                          /* 45,70? */
771             if (update_MM)                              /* save vector */
772                 MMR2 = trapea;
773             MMR0 = MMR0 & ~MMR0_IC;                     /* clear IC */
774             }
775         src = ReadW (trapea | calc_ds (MD_KER));        /* new PC */
776         src2 = ReadW ((trapea + 2) | calc_ds (MD_KER)); /* new PSW */
777         t = (src2 >> PSW_V_CM) & 03;                    /* new cm */
778         trapea = ~t;                                    /* flag pushes */
779         WriteW (PSW, ((STACKFILE[t] - 2) & 0177777) | calc_ds (t));
780         WriteW (PC, ((STACKFILE[t] - 4) & 0177777) | calc_ds (t));
781         trapea = 0;                                     /* clear trap flag */
782         src2 = (src2 & ~PSW_PM) | (cm << PSW_V_PM);     /* insert prv mode */
783         put_PSW (src2, 0);                              /* call calc_is,ds */
784         if (rs != oldrs) {                              /* if rs chg, swap */
785             for (i = 0; i < 6; i++) {
786                 REGFILE[i][oldrs] = R[i];
787                 R[i] = REGFILE[i][rs];
788                 }
789             }
790         SP = (STACKFILE[cm] - 4) & 0177777;             /* update SP, PC */
791         isenable = calc_is (cm);
792         dsenable = calc_ds (cm);
793         trap_req = calc_ints (ipl, trap_req);
794         JMP_PC (src);
795         if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)) &&
796             (trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL))
797             set_stack_trap (SP);
798         MMR0 = MMR0 | MMR0_IC;                          /* back to instr */
799         continue;                                       /* end if traps */
800         }
801 
802 /* Fetch and decode next instruction */
803 
804     if (tbit)
805         setTRAP (TRAP_TRC);
806     if (wait_state) {                                   /* wait state? */
807         if (sim_idle_enab)                              /* idle enabled? */
808             sim_idle (TMR_CLK, TRUE);
809         else if (wait_enable)                           /* old style idle? */
810             sim_interval = 0;                           /* force check */
811         else sim_interval = sim_interval - 1;           /* count cycle */
812         continue;
813         }
814 
815     if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
816         reason = STOP_IBKPT;                            /* stop simulation */
817         continue;
818 		}
819 
820     if (update_MM) {                                    /* if mm not frozen */
821         MMR1 = 0;
822         MMR2 = PC;
823         }
824     IR = ReadE (PC | isenable);                         /* fetch instruction */
825     sim_interval = sim_interval - 1;
826     srcspec = (IR >> 6) & 077;                          /* src, dst specs */
827     dstspec = IR & 077;
828     srcreg = (srcspec <= 07);                           /* src, dst = rmode? */
829     dstreg = (dstspec <= 07);
830     if (hst_lnt) {                                      /* record history? */
831         t_value val;
832         uint32 i;
833         hst[hst_p].pc = PC | HIST_VLD;
834         hst[hst_p].psw = get_PSW ();
835         hst[hst_p].src = R[srcspec & 07];
836         hst[hst_p].dst = R[dstspec & 07];
837         hst[hst_p].inst[0] = IR;
838         for (i = 1; i < HIST_ILNT; i++) {
839             if (cpu_ex (&val, (PC + (i << 1)) & 0177777, &cpu_unit, SWMASK ('V')))
840                 hst[hst_p].inst[i] = 0;
841             else hst[hst_p].inst[i] = (uint16) val;
842             }
843         hst_p = (hst_p + 1);
844         if (hst_p >= hst_lnt)
845             hst_p = 0;
846         }
847     PC = (PC + 2) & 0177777;                            /* incr PC, mod 65k */
848     switch ((IR >> 12) & 017) {                         /* decode IR<15:12> */
849 
850 /* Opcode 0: no operands, specials, branches, JSR, SOPs */
851 
852     case 000:
853         switch ((IR >> 6) & 077) {                      /* decode IR<11:6> */
854         case 000:                                       /* no operand */
855             if (IR >= 000010) {                         /* 000010 - 000077 */
856                 setTRAP (TRAP_ILL);                     /* illegal */
857                 break;
858                 }
859             switch (IR) {                               /* decode IR<2:0> */
860             case 0:                                     /* HALT */
861                 if ((cm == MD_KER) &&
862                     (!CPUT (CPUT_J) || ((MAINT & MAINT_HTRAP) == 0)))
863                     reason = STOP_HALT;
864                 else if (CPUT (HAS_HALT4)) {            /* priv trap? */
865                     setTRAP (TRAP_PRV);
866                     setCPUERR (CPUE_HALT);
867                     }
868                 else setTRAP (TRAP_ILL);                /* no, ill inst */
869                 break;
870             case 1:                                     /* WAIT */
871                 wait_state = 1;
872                 break;
873             case 3:                                     /* BPT */
874                 setTRAP (TRAP_BPT);
875                 break;
876             case 4:                                     /* IOT */
877                 setTRAP (TRAP_IOT);
878                 break;
879             case 5:                                     /* RESET */
880                 if (cm == MD_KER) {
881                     reset_all (2);                      /* skip CPU, sys reg */
882                     PIRQ = 0;                           /* clear PIRQ */
883                     STKLIM = 0;                         /* clear STKLIM */
884                     MMR0 = 0;                           /* clear MMR0 */
885                     MMR3 = 0;                           /* clear MMR3 */
886                     cpu_bme = 0;                        /* (also clear bme) */
887                     for (i = 0; i < IPL_HLVL; i++)
888                         int_req[i] = 0;
889                     trap_req = trap_req & ~TRAP_INT;
890                     dsenable = calc_ds (cm);
891                     }
892                 break;
893             case 6:                                     /* RTT */
894                 if (!CPUT (HAS_RTT)) {
895                     setTRAP (TRAP_ILL);
896                     break;
897                     }
898             case 2:                                     /* RTI */
899                 src = ReadW (SP | dsenable);
900                 src2 = ReadW (((SP + 2) & 0177777) | dsenable);
901                 STACKFILE[cm] = SP = (SP + 4) & 0177777;
902                 oldrs = rs;
903                 put_PSW (src2, (cm != MD_KER));         /* store PSW, prot */
904                 if (rs != oldrs) {
905                     for (i = 0; i < 6; i++) {
906                         REGFILE[i][oldrs] = R[i];
907                         R[i] = REGFILE[i][rs];
908                         }
909                     }
910                 SP = STACKFILE[cm];
911                 isenable = calc_is (cm);
912                 dsenable = calc_ds (cm);
913                 trap_req = calc_ints (ipl, trap_req);
914                 JMP_PC (src);
915                 if (CPUT (HAS_RTT) && tbit &&           /* RTT impl? */
916                     (IR == 000002)) setTRAP (TRAP_TRC); /* RTI immed trap */
917                 break;
918             case 7:                                     /* MFPT */
919                 if (CPUT (HAS_MFPT))                    /* implemented? */
920                     R[0] = cpu_tab[cpu_model].mfpt;     /* get type */
921                 else setTRAP (TRAP_ILL);
922                 break;
923                 }                                       /* end switch no ops */
924             break;                                      /* end case no ops */
925 
926         case 001:                                       /* JMP */
927             if (dstreg)
928                 setTRAP (CPUT (HAS_JREG4)? TRAP_PRV: TRAP_ILL);
929             else {
930                 dst = GeteaW (dstspec) & 0177777;       /* get eff addr */
931                 if (CPUT (CPUT_05|CPUT_20) &&           /* 11/05, 11/20 */
932                     ((dstspec & 070) == 020))           /* JMP (R)+? */
933                     dst = R[dstspec & 07];              /* use post incr */
934                 JMP_PC (dst);
935                 }
936             break;                                      /* end JMP */
937 
938         case 002:                                       /* RTS et al*/
939             if (IR < 000210) {                          /* RTS */
940                 dstspec = dstspec & 07;
941                 JMP_PC (R[dstspec]);
942                 R[dstspec] = ReadW (SP | dsenable);
943                 if (dstspec != 6)
944                     SP = (SP + 2) & 0177777;
945                 break;
946                 }                                       /* end if RTS */
947             if (IR < 000230) {
948                 setTRAP (TRAP_ILL);
949                 break;
950                 }
951             if (IR < 000240) {                          /* SPL */
952                 if (CPUT (HAS_SPL)) {
953                     if (cm == MD_KER)
954                         ipl = IR & 07;
955                     trap_req = calc_ints (ipl, trap_req);
956                     }
957                 else setTRAP (TRAP_ILL);
958                 break;
959                 }                                       /* end if SPL */
960             if (IR < 000260) {                          /* clear CC */
961                 if (IR & 010)
962                     N = 0;
963                 if (IR & 004)
964                     Z = 0;
965                 if (IR & 002)
966                     V = 0;
967                 if (IR & 001)
968                     C = 0;
969                 break;
970                 }                                       /* end if clear CCs */
971             if (IR & 010)                               /* set CC */
972                 N = 1;
973             if (IR & 004)
974                 Z = 1;
975             if (IR & 002)
976                 V = 1;
977             if (IR & 001)
978                 C = 1;
979             break;                                      /* end case RTS et al */
980 
981         case 003:                                       /* SWAB */
982             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
983             dst = ((dst & 0377) << 8) | ((dst >> 8) & 0377);
984             N = GET_SIGN_B (dst & 0377);
985             Z = GET_Z (dst & 0377);
986             if (!CPUT (CPUT_20))
987                 V = 0;
988             C = 0;
989             if (dstreg)
990                 R[dstspec] = dst;
991             else PWriteW (dst, last_pa);
992             break;                                      /* end SWAB */
993 
994         case 004: case 005:                             /* BR */
995             BRANCH_F (IR);
996             break;
997 
998         case 006: case 007:                             /* BR */
999             BRANCH_B (IR);
1000             break;
1001 
1002         case 010: case 011:                             /* BNE */
1003             if (Z == 0) {
1004                 BRANCH_F (IR);
1005                 }
1006             break;
1007 
1008         case 012: case 013:                             /* BNE */
1009             if (Z == 0) {
1010                 BRANCH_B (IR);
1011                 }
1012             break;
1013 
1014         case 014: case 015:                             /* BEQ */
1015             if (Z) {
1016                 BRANCH_F (IR);
1017                 }
1018             break;
1019 
1020         case 016: case 017:                             /* BEQ */
1021             if (Z) {
1022                 BRANCH_B (IR);
1023                 }
1024             break;
1025 
1026         case 020: case 021:                             /* BGE */
1027             if ((N ^ V) == 0) {
1028                 BRANCH_F (IR);
1029                 }
1030             break;
1031 
1032         case 022: case 023:                             /* BGE */
1033             if ((N ^ V) == 0) {
1034                 BRANCH_B (IR);
1035                 }
1036             break;
1037 
1038         case 024: case 025:                             /* BLT */
1039             if (N ^ V) {
1040                 BRANCH_F (IR);
1041                 }
1042             break;
1043 
1044         case 026: case 027:                             /* BLT */
1045             if (N ^ V) {
1046                 BRANCH_B (IR);
1047                 }
1048             break;
1049 
1050         case 030: case 031:                             /* BGT */
1051             if ((Z | (N ^ V)) == 0) {
1052                 BRANCH_F (IR);
1053                 }
1054             break;
1055 
1056         case 032: case 033:                             /* BGT */
1057             if ((Z | (N ^ V)) == 0) { BRANCH_B (IR); }
1058             break;
1059 
1060         case 034: case 035:                             /* BLE */
1061             if (Z | (N ^ V)) {
1062                 BRANCH_F (IR);
1063                 }
1064             break;
1065 
1066         case 036: case 037:                             /* BLE */
1067             if (Z | (N ^ V)) {
1068                 BRANCH_B (IR);
1069                 }
1070             break;
1071 
1072         case 040: case 041: case 042: case 043:         /* JSR */
1073         case 044: case 045: case 046: case 047:
1074             if (dstreg)
1075                 setTRAP (CPUT (HAS_JREG4)? TRAP_PRV: TRAP_ILL);
1076             else {
1077                 srcspec = srcspec & 07;
1078                 dst = GeteaW (dstspec);
1079                 if (CPUT (CPUT_05|CPUT_20) &&           /* 11/05, 11/20 */
1080                     ((dstspec & 070) == 020))           /* JSR (R)+? */
1081                     dst = R[dstspec & 07];              /* use post incr */
1082                 SP = (SP - 2) & 0177777;
1083                 if (update_MM)
1084                     MMR1 = calc_MMR1 (0366);
1085                 WriteW (R[srcspec], SP | dsenable);
1086                 if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)))
1087                     set_stack_trap (SP);
1088                 R[srcspec] = PC;
1089                 JMP_PC (dst & 0177777);
1090                 }
1091             break;                                      /* end JSR */
1092 
1093         case 050:                                       /* CLR */
1094             N = V = C = 0;
1095             Z = 1;
1096             if (dstreg)
1097                 R[dstspec] = 0;
1098             else WriteW (0, GeteaW (dstspec));
1099             break;
1100 
1101         case 051:                                       /* COM */
1102             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1103             dst = dst ^ 0177777;
1104             N = GET_SIGN_W (dst);
1105             Z = GET_Z (dst);
1106             V = 0;
1107             C = 1;
1108             if (dstreg)
1109                 R[dstspec] = dst;
1110             else PWriteW (dst, last_pa);
1111             break;
1112 
1113         case 052:                                       /* INC */
1114             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1115             dst = (dst + 1) & 0177777;
1116             N = GET_SIGN_W (dst);
1117             Z = GET_Z (dst);
1118             V = (dst == 0100000);
1119             if (dstreg)
1120                 R[dstspec] = dst;
1121             else PWriteW (dst, last_pa);
1122             break;
1123 
1124         case 053:                                       /* DEC */
1125             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1126             dst = (dst - 1) & 0177777;
1127             N = GET_SIGN_W (dst);
1128             Z = GET_Z (dst);
1129             V = (dst == 077777);
1130             if (dstreg)
1131                 R[dstspec] = dst;
1132             else PWriteW (dst, last_pa);
1133             break;
1134 
1135         case 054:                                       /* NEG */
1136             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1137             dst = (-dst) & 0177777;
1138             N = GET_SIGN_W (dst);
1139             Z = GET_Z (dst);
1140             V = (dst == 0100000);
1141             C = Z ^ 1;
1142             if (dstreg)
1143                 R[dstspec] = dst;
1144             else PWriteW (dst, last_pa);
1145             break;
1146 
1147         case 055:                                       /* ADC */
1148             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1149             dst = (dst + C) & 0177777;
1150             N = GET_SIGN_W (dst);
1151             Z = GET_Z (dst);
1152             V = (C && (dst == 0100000));
1153             C = C & Z;
1154             if (dstreg)
1155                 R[dstspec] = dst;
1156             else PWriteW (dst, last_pa);
1157             break;
1158 
1159         case 056:                                       /* SBC */
1160             dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1161             dst = (dst - C) & 0177777;
1162             N = GET_SIGN_W (dst);
1163             Z = GET_Z (dst);
1164             V = (C && (dst == 077777));
1165             C = (C && (dst == 0177777));
1166             if (dstreg)
1167                 R[dstspec] = dst;
1168             else PWriteW (dst, last_pa);
1169             break;
1170 
1171         case 057:                                       /* TST */
1172             dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1173             N = GET_SIGN_W (dst);
1174             Z = GET_Z (dst);
1175             V = C = 0;
1176             break;
1177 
1178         case 060:                                       /* ROR */
1179             src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1180             dst = (src >> 1) | (C << 15);
1181             N = GET_SIGN_W (dst);
1182             Z = GET_Z (dst);
1183             C = (src & 1);
1184             V = N ^ C;
1185             if (dstreg)
1186                 R[dstspec] = dst;
1187             else PWriteW (dst, last_pa);
1188             break;
1189 
1190         case 061:                                       /* ROL */
1191             src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1192             dst = ((src << 1) | C) & 0177777;
1193             N = GET_SIGN_W (dst);
1194             Z = GET_Z (dst);
1195             C = GET_SIGN_W (src);
1196             V = N ^ C;
1197             if (dstreg)
1198                 R[dstspec] = dst;
1199             else PWriteW (dst, last_pa);
1200             break;
1201 
1202         case 062:                                       /* ASR */
1203             src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1204             dst = (src >> 1) | (src & 0100000);
1205             N = GET_SIGN_W (dst);
1206             Z = GET_Z (dst);
1207             C = (src & 1);
1208             V = N ^ C;
1209             if (dstreg)
1210                 R[dstspec] = dst;
1211             else PWriteW (dst, last_pa);
1212             break;
1213 
1214         case 063:                                       /* ASL */
1215             src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1216             dst = (src << 1) & 0177777;
1217             N = GET_SIGN_W (dst);
1218             Z = GET_Z (dst);
1219             C = GET_SIGN_W (src);
1220             V = N ^ C;
1221             if (dstreg)
1222                 R[dstspec] = dst;
1223             else PWriteW (dst, last_pa);
1224             break;
1225 
1226 /* Notes:
1227    - MxPI must mask GeteaW returned address to force ispace
1228    - MxPI must set MMR1 for SP recovery in case of fault
1229 */
1230 
1231         case 064:                                       /* MARK */
1232             if (CPUT (HAS_MARK)) {
1233                 i = (PC + dstspec + dstspec) & 0177777;
1234                 JMP_PC (R[5]);
1235                 R[5] = ReadW (i | dsenable);
1236                 SP = (i + 2) & 0177777;
1237                 }
1238             else setTRAP (TRAP_ILL);
1239             break;
1240 
1241         case 065:                                       /* MFPI */
1242             if (CPUT (HAS_MXPY)) {
1243                 if (dstreg) {
1244                     if ((dstspec == 6) && (cm != pm))
1245                         dst = STACKFILE[pm];
1246                     else dst = R[dstspec];
1247                     }
1248                 else {
1249                     i = ((cm == pm) && (cm == MD_USR))? calc_ds (pm): calc_is (pm);
1250                     dst = ReadW ((GeteaW (dstspec) & 0177777) | i);
1251                     }
1252                 N = GET_SIGN_W (dst);
1253                 Z = GET_Z (dst);
1254                 V = 0;
1255                 SP = (SP - 2) & 0177777;
1256                 if (update_MM)
1257                     MMR1 = calc_MMR1 (0366);
1258                 WriteW (dst, SP | dsenable);
1259                 if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)))
1260                     set_stack_trap (SP);
1261                 }
1262             else setTRAP (TRAP_ILL);
1263             break;
1264 
1265         case 066:                                       /* MTPI */
1266             if (CPUT (HAS_MXPY)) {
1267                 dst = ReadW (SP | dsenable);
1268                 N = GET_SIGN_W (dst);
1269                 Z = GET_Z (dst);
1270                 V = 0;
1271                 SP = (SP + 2) & 0177777;
1272                 if (update_MM) MMR1 = 026;
1273                 if (dstreg) {
1274                     if ((dstspec == 6) && (cm != pm))
1275                         STACKFILE[pm] = dst;
1276                     else R[dstspec] = dst;
1277                     }
1278                 else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_is (pm));
1279                 }
1280             else setTRAP (TRAP_ILL);
1281             break;
1282 
1283         case 067:                                       /* SXT */
1284             if (CPUT (HAS_SXS)) {
1285                 dst = N? 0177777: 0;
1286                 Z = N ^ 1;
1287                 V = 0;
1288                 if (dstreg)
1289                     R[dstspec] = dst;
1290                 else WriteW (dst, GeteaW (dstspec));
1291                 }
1292             else setTRAP (TRAP_ILL);
1293             break;
1294 
1295         case 070:                                       /* CSM */
1296             if ((CPUT (HAS_CSM) && (MMR3 & MMR3_CSM)) || (cm != MD_KER)) {
1297                 dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1298                 PSW = get_PSW () & ~PSW_CC;             /* PSW, cc = 0 */
1299                 STACKFILE[cm] = SP;
1300                 WriteW (PSW, ((SP - 2) & 0177777) | calc_ds (MD_SUP));
1301                 WriteW (PC, ((SP - 4) & 0177777) | calc_ds (MD_SUP));
1302                 WriteW (dst, ((SP - 6) & 0177777) | calc_ds (MD_SUP));
1303                 SP = (SP - 6) & 0177777;
1304                 pm = cm;
1305                 cm = MD_SUP;
1306                 tbit = 0;
1307                 isenable = calc_is (cm);
1308                 dsenable = calc_ds (cm);
1309                 PC = ReadW (010 | isenable);
1310                 }
1311             else setTRAP (TRAP_ILL);
1312             break;
1313 
1314         case 072:                                       /* TSTSET */
1315             if (CPUT (HAS_TSWLK) && !dstreg) {
1316                 dst = ReadMW (GeteaW (dstspec));
1317                 N = GET_SIGN_W (dst);
1318                 Z = GET_Z (dst);
1319                 V = 0;
1320                 C = (dst & 1);
1321                 R[0] = dst;                             /* R[0] <- dst */
1322                 PWriteW (R[0] | 1, last_pa);            /* dst <- R[0] | 1 */
1323                 }
1324             else setTRAP (TRAP_ILL);
1325             break;
1326 
1327         case 073:                                       /* WRTLCK */
1328             if (CPUT (HAS_TSWLK) && !dstreg) {
1329                 N = GET_SIGN_W (R[0]);
1330                 Z = GET_Z (R[0]);
1331                 V = 0;
1332                 WriteW (R[0], GeteaW (dstspec));
1333                 }
1334             else setTRAP (TRAP_ILL);
1335             break;
1336 
1337         default:
1338             setTRAP (TRAP_ILL);
1339             break;
1340             }                                           /* end switch SOPs */
1341         break;                                          /* end case 000 */
1342 
1343 /* Opcodes 01 - 06: double operand word instructions
1344 
1345    J-11 (and F-11) optimize away register source operand decoding.
1346    As a result, dop R,+/-(R) use the modified version of R as source.
1347    Most (but not all) other PDP-11's fetch the source operand before
1348    any destination operand decoding.
1349 
1350    Add: v = [sign (src) = sign (src2)] and [sign (src) != sign (result)]
1351    Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)]
1352 */
1353 
1354     case 001:                                           /* MOV */
1355         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1356             ea = GeteaW (dstspec);
1357             dst = R[srcspec];
1358             }
1359         else {
1360             dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
1361             if (!dstreg) ea = GeteaW (dstspec);
1362             }
1363         N = GET_SIGN_W (dst);
1364         Z = GET_Z (dst);
1365         V = 0;
1366         if (dstreg)
1367             R[dstspec] = dst;
1368         else WriteW (dst, ea);
1369         break;
1370 
1371     case 002:                                           /* CMP */
1372         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1373             src2 = ReadW (GeteaW (dstspec));
1374             src = R[srcspec];
1375             }
1376         else {
1377             src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
1378             src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1379             }
1380         dst = (src - src2) & 0177777;
1381         N = GET_SIGN_W (dst);
1382         Z = GET_Z (dst);
1383         V = GET_SIGN_W ((src ^ src2) & (~src2 ^ dst));
1384         C = (src < src2);
1385         break;
1386 
1387     case 003:                                           /* BIT */
1388         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1389             src2 = ReadW (GeteaW (dstspec));
1390             src = R[srcspec];
1391             }
1392         else {
1393             src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
1394             src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1395             }
1396         dst = src2 & src;
1397         N = GET_SIGN_W (dst);
1398         Z = GET_Z (dst);
1399         V = 0;
1400         break;
1401 
1402     case 004:                                           /* BIC */
1403         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1404             src2 = ReadMW (GeteaW (dstspec));
1405             src = R[srcspec];
1406             }
1407         else {
1408             src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
1409             src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1410             }
1411         dst = src2 & ~src;
1412         N = GET_SIGN_W (dst);
1413         Z = GET_Z (dst);
1414         V = 0;
1415         if (dstreg)
1416             R[dstspec] = dst;
1417         else PWriteW (dst, last_pa);
1418         break;
1419 
1420     case 005:                                           /* BIS */
1421         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1422             src2 = ReadMW (GeteaW (dstspec));
1423             src = R[srcspec];
1424             }
1425         else {
1426             src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
1427             src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1428             }
1429         dst = src2 | src;
1430         N = GET_SIGN_W (dst);
1431         Z = GET_Z (dst);
1432         V = 0;
1433         if (dstreg)
1434             R[dstspec] = dst;
1435         else PWriteW (dst, last_pa);
1436         break;
1437 
1438     case 006:                                           /* ADD */
1439         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1440             src2 = ReadMW (GeteaW (dstspec));
1441             src = R[srcspec];
1442             }
1443         else {
1444             src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
1445             src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1446             }
1447         dst = (src2 + src) & 0177777;
1448         N = GET_SIGN_W (dst);
1449         Z = GET_Z (dst);
1450         V = GET_SIGN_W ((~src ^ src2) & (src ^ dst));
1451         C = (dst < src);
1452         if (dstreg)
1453             R[dstspec] = dst;
1454         else PWriteW (dst, last_pa);
1455         break;
1456 
1457 /* Opcode 07: EIS, FIS, CIS
1458 
1459    Notes:
1460    - The code assumes that the host int length is at least 32 bits.
1461    - MUL carry: C is set if the (signed) result doesn't fit in 16 bits.
1462    - Divide has three error cases:
1463         1. Divide by zero.
1464         2. Divide largest negative number by -1.
1465         3. (Signed) quotient doesn't fit in 16 bits.
1466      Cases 1 and 2 must be tested in advance, to avoid C runtime errors.
1467    - ASHx left: overflow if the bits shifted out do not equal the sign
1468      of the result (convert shift out to 1/0, xor against sign).
1469    - ASHx right: if right shift sign extends, then the shift and
1470      conditional or of shifted -1 is redundant.  If right shift zero
1471      extends, then the shift and conditional or does sign extension.
1472 */
1473 
1474     case 007:
1475         srcspec = srcspec & 07;
1476         switch ((IR >> 9) & 07)  {                      /* decode IR<11:9> */
1477 
1478         case 0:                                         /* MUL */
1479             if (!CPUO (OPT_EIS)) {
1480                 setTRAP (TRAP_ILL);
1481                 break;
1482                 }
1483             src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1484             src = R[srcspec];
1485             if (GET_SIGN_W (src2))
1486                 src2 = src2 | ~077777;
1487             if (GET_SIGN_W (src))
1488                 src = src | ~077777;
1489             dst = src * src2;
1490             R[srcspec] = (dst >> 16) & 0177777;
1491             R[srcspec | 1] = dst & 0177777;
1492             N = (dst < 0);
1493             Z = GET_Z (dst);
1494             V = 0;
1495             C = ((dst > 077777) || (dst < -0100000));
1496             break;
1497 
1498         case 1:                                         /* DIV */
1499             if (!CPUO (OPT_EIS)) {
1500                 setTRAP (TRAP_ILL);
1501                 break;
1502                 }
1503             src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1504             src = (((uint32) R[srcspec]) << 16) | R[srcspec | 1];
1505             if (src2 == 0) {
1506                 N = 0;                                  /* J11,11/70 compat */
1507                 Z = V = C = 1;                          /* N = 0, Z = 1 */
1508                 break;
1509                 }
1510             if ((src == 020000000000) && (src2 == 0177777)) {
1511                 V = 1;                                  /* J11,11/70 compat */
1512                 N = Z = C = 0;                          /* N = Z = 0 */
1513                 break;
1514                 }
1515             if (GET_SIGN_W (src2))
1516                 src2 = src2 | ~077777;
1517             if (GET_SIGN_W (R[srcspec]))
1518                 src = src | ~017777777777;
1519             dst = src / src2;
1520             N = (dst < 0);                              /* N set on 32b result */
1521             if ((dst > 077777) || (dst < -0100000)) {
1522                 V = 1;                                  /* J11,11/70 compat */
1523                 Z = C = 0;                              /* Z = C = 0 */
1524                 break;
1525                 }
1526             R[srcspec] = dst & 0177777;
1527             R[srcspec | 1] = (src - (src2 * dst)) & 0177777;
1528             Z = GET_Z (dst);
1529             V = C = 0;
1530             break;
1531 
1532         case 2:                                         /* ASH */
1533             if (!CPUO (OPT_EIS)) {
1534                 setTRAP (TRAP_ILL);
1535                 break;
1536                 }
1537             src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1538             src2 = src2 & 077;
1539             sign = GET_SIGN_W (R[srcspec]);
1540             src = sign? R[srcspec] | ~077777: R[srcspec];
1541             if (src2 == 0) {                            /* [0] */
1542                 dst = src;
1543                 V = C = 0;
1544                 }
1545             else if (src2 <= 15) {                      /* [1,15] */
1546                 dst = src << src2;
1547                 i = (src >> (16 - src2)) & 0177777;
1548                 V = (i != ((dst & 0100000)? 0177777: 0));
1549                 C = (i & 1);
1550                 }
1551             else if (src2 <= 31) {                      /* [16,31] */
1552                 dst = 0;
1553                 V = (src != 0);
1554                 C = (src << (src2 - 16)) & 1;
1555                 }
1556             else if (src2 == 32) {                      /* [32] = -32 */
1557                 dst = -sign;
1558                 V = 0;
1559                 C = sign;
1560                 }
1561             else {                                      /* [33,63] = -31,-1 */
1562                 dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
1563                 V = 0;
1564                 C = ((src >> (63 - src2)) & 1);
1565                 }
1566             dst = R[srcspec] = dst & 0177777;
1567             N = GET_SIGN_W (dst);
1568             Z = GET_Z (dst);
1569             break;
1570 
1571         case 3:                                         /* ASHC */
1572             if (!CPUO (OPT_EIS)) {
1573                 setTRAP (TRAP_ILL);
1574                 break;
1575                 }
1576             src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
1577             src2 = src2 & 077;
1578             sign = GET_SIGN_W (R[srcspec]);
1579             src = (((uint32) R[srcspec]) << 16) | R[srcspec | 1];
1580             if (src2 == 0) {                            /* [0] */
1581                 dst = src;
1582                 V = C = 0;
1583                 }
1584             else if (src2 <= 31) {                      /* [1,31] */
1585                 dst = ((uint32) src) << src2;
1586                 i = (src >> (32 - src2)) | (-sign << src2);
1587                 V = (i != ((dst & 020000000000)? -1: 0));
1588                 C = (i & 1);
1589                 }
1590             else if (src2 == 32) {                      /* [32] = -32 */
1591                 dst = -sign;
1592                 V = 0;
1593                 C = sign;
1594                 }
1595             else {                                      /* [33,63] = -31,-1 */
1596                 dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
1597                 V = 0;
1598                 C = ((src >> (63 - src2)) & 1);
1599                 }
1600             i = R[srcspec] = (dst >> 16) & 0177777;
1601             dst = R[srcspec | 1] = dst & 0177777;
1602             N = GET_SIGN_W (i);
1603             Z = GET_Z (dst | i);
1604             break;
1605 
1606         case 4:                                         /* XOR */
1607             if (CPUT (HAS_SXS)) {
1608                 if (CPUT (IS_SDSD) && !dstreg) {        /* R,not R */
1609                     src2 = ReadMW (GeteaW (dstspec));
1610                     src = R[srcspec];
1611                     }
1612                 else {
1613                     src = R[srcspec];
1614                     src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
1615                     }
1616                 dst = src ^ src2;
1617                 N = GET_SIGN_W (dst);
1618                 Z = GET_Z (dst);
1619                 V = 0;
1620                 if (dstreg)
1621                     R[dstspec] = dst;
1622                 else PWriteW (dst, last_pa);
1623                 }
1624             else setTRAP (TRAP_ILL);
1625             break;
1626 
1627         case 5:                                         /* FIS */
1628             if (CPUO (OPT_FIS))
1629                 fis11 (IR);
1630             else setTRAP (TRAP_ILL);
1631             break;
1632 
1633         case 6:                                         /* CIS */
1634             if (CPUT (CPUT_60) && (cm == MD_KER) &&     /* 11/60 MED? */
1635                 (IR == 076600)) {
1636                 ReadE (PC | isenable);                  /* read immediate */
1637                 PC = (PC + 2) & 0177777;
1638                 }
1639             else if (CPUO (OPT_CIS))                    /* CIS option? */
1640                 reason = cis11 (IR);
1641             else setTRAP (TRAP_ILL);
1642             break;
1643 
1644         case 7:                                         /* SOB */
1645             if (CPUT (HAS_SXS)) {
1646                 R[srcspec] = (R[srcspec] - 1) & 0177777;
1647                 if (R[srcspec]) {
1648                     JMP_PC ((PC - dstspec - dstspec) & 0177777);
1649                     }
1650                 }
1651             else setTRAP (TRAP_ILL);
1652             break;
1653             }                                           /* end switch EIS */
1654         break;                                          /* end case 007 */
1655 
1656 /* Opcode 10: branches, traps, SOPs */
1657 
1658     case 010:
1659         switch ((IR >> 6) & 077) {                      /* decode IR<11:6> */
1660 
1661         case 000: case 001:                             /* BPL */
1662             if (N == 0) {
1663                 BRANCH_F (IR);
1664                 }
1665             break;
1666 
1667         case 002: case 003:                             /* BPL */
1668             if (N == 0) {
1669                 BRANCH_B (IR);
1670                 }
1671             break;
1672 
1673         case 004: case 005:                             /* BMI */
1674             if (N) {
1675                 BRANCH_F (IR);
1676                 }
1677             break;
1678 
1679         case 006: case 007:                             /* BMI */
1680             if (N) {
1681                 BRANCH_B (IR);
1682                 }
1683             break;
1684 
1685         case 010: case 011:                             /* BHI */
1686             if ((C | Z) == 0) {
1687                 BRANCH_F (IR);
1688                 }
1689             break;
1690 
1691         case 012: case 013:                             /* BHI */
1692             if ((C | Z) == 0) {
1693                 BRANCH_B (IR);
1694                 }
1695             break;
1696 
1697         case 014: case 015:                             /* BLOS */
1698             if (C | Z) {
1699                 BRANCH_F (IR);
1700                 }
1701             break;
1702 
1703         case 016: case 017:                             /* BLOS */
1704             if (C | Z) {
1705                 BRANCH_B (IR);
1706                 }
1707             break;
1708 
1709         case 020: case 021:                             /* BVC */
1710             if (V == 0) {
1711                 BRANCH_F (IR);
1712                 }
1713             break;
1714 
1715         case 022: case 023:                             /* BVC */
1716             if (V == 0) {
1717                 BRANCH_B (IR);
1718                 }
1719             break;
1720 
1721         case 024: case 025:                             /* BVS */
1722             if (V) {
1723                 BRANCH_F (IR);
1724                 }
1725             break;
1726 
1727         case 026: case 027:                             /* BVS */
1728             if (V) {
1729                 BRANCH_B (IR);
1730                 }
1731             break;
1732 
1733         case 030: case 031:                             /* BCC */
1734             if (C == 0) {
1735                 BRANCH_F (IR);
1736                 }
1737             break;
1738 
1739         case 032: case 033:                             /* BCC */
1740             if (C == 0) {
1741                 BRANCH_B (IR);
1742                 }
1743             break;
1744 
1745         case 034: case 035:                             /* BCS */
1746             if (C) {
1747                 BRANCH_F (IR);
1748                 }
1749             break;
1750 
1751         case 036: case 037:                             /* BCS */
1752             if (C) {
1753                 BRANCH_B (IR);
1754                 }
1755             break;
1756 
1757         case 040: case 041: case 042: case 043:         /* EMT */
1758             setTRAP (TRAP_EMT);
1759             break;
1760 
1761         case 044: case 045: case 046: case 047:         /* TRAP */
1762             setTRAP (TRAP_TRAP);
1763             break;
1764 
1765         case 050:                                       /* CLRB */
1766             N = V = C = 0;
1767             Z = 1;
1768             if (dstreg)
1769                 R[dstspec] = R[dstspec] & 0177400;
1770             else WriteB (0, GeteaB (dstspec));
1771             break;
1772 
1773         case 051:                                       /* COMB */
1774             dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1775             dst = (dst ^ 0377) & 0377;
1776             N = GET_SIGN_B (dst);
1777             Z = GET_Z (dst);
1778             V = 0;
1779             C = 1;
1780             if (dstreg)
1781                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1782             else PWriteB (dst, last_pa);
1783             break;
1784 
1785         case 052:                                       /* INCB */
1786             dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1787             dst = (dst + 1) & 0377;
1788             N = GET_SIGN_B (dst);
1789             Z = GET_Z (dst);
1790             V = (dst == 0200);
1791             if (dstreg)
1792                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1793             else PWriteB (dst, last_pa);
1794             break;
1795 
1796         case 053:                                       /* DECB */
1797             dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1798             dst = (dst - 1) & 0377;
1799             N = GET_SIGN_B (dst);
1800             Z = GET_Z (dst);
1801             V = (dst == 0177);
1802             if (dstreg)
1803                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1804             else PWriteB (dst, last_pa);
1805             break;
1806 
1807         case 054:                                       /* NEGB */
1808             dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1809             dst = (-dst) & 0377;
1810             N = GET_SIGN_B (dst);
1811             Z = GET_Z (dst);
1812             V = (dst == 0200);
1813             C = (Z ^ 1);
1814             if (dstreg)
1815                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1816             else PWriteB (dst, last_pa);
1817             break;
1818 
1819         case 055:                                       /* ADCB */
1820             dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1821             dst = (dst + C) & 0377;
1822             N = GET_SIGN_B (dst);
1823             Z = GET_Z (dst);
1824             V = (C && (dst == 0200));
1825             C = C & Z;
1826             if (dstreg)
1827                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1828             else PWriteB (dst, last_pa);
1829             break;
1830 
1831         case 056:                                       /* SBCB */
1832             dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1833             dst = (dst - C) & 0377;
1834             N = GET_SIGN_B (dst);
1835             Z = GET_Z (dst);
1836             V = (C && (dst == 0177));
1837             C = (C && (dst == 0377));
1838             if (dstreg)
1839                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1840             else PWriteB (dst, last_pa);
1841             break;
1842 
1843         case 057:                                       /* TSTB */
1844             dst = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec));
1845             N = GET_SIGN_B (dst);
1846             Z = GET_Z (dst);
1847             V = C = 0;
1848             break;
1849 
1850         case 060:                                       /* RORB */
1851             src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1852             dst = ((src & 0377) >> 1) | (C << 7);
1853             N = GET_SIGN_B (dst);
1854             Z = GET_Z (dst);
1855             C = (src & 1);
1856             V = N ^ C;
1857             if (dstreg)
1858                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1859             else PWriteB (dst, last_pa);
1860             break;
1861 
1862         case 061:                                       /* ROLB */
1863             src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1864             dst = ((src << 1) | C) & 0377;
1865             N = GET_SIGN_B (dst);
1866             Z = GET_Z (dst);
1867             C = GET_SIGN_B (src & 0377);
1868             V = N ^ C;
1869             if (dstreg)
1870                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1871             else PWriteB (dst, last_pa);
1872             break;
1873 
1874         case 062:                                       /* ASRB */
1875             src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1876             dst = ((src & 0377) >> 1) | (src & 0200);
1877             N = GET_SIGN_B (dst);
1878             Z = GET_Z (dst);
1879             C = (src & 1);
1880             V = N ^ C;
1881             if (dstreg)
1882                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1883             else PWriteB (dst, last_pa);
1884             break;
1885 
1886         case 063:                                       /* ASLB */
1887             src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
1888             dst = (src << 1) & 0377;
1889             N = GET_SIGN_B (dst);
1890             Z = GET_Z (dst);
1891             C = GET_SIGN_B (src & 0377);
1892             V = N ^ C;
1893             if (dstreg)
1894                 R[dstspec] = (R[dstspec] & 0177400) | dst;
1895             else PWriteB (dst, last_pa);
1896             break;
1897 /* Notes:
1898    - MTPS cannot alter the T bit
1899    - MxPD must mask GeteaW returned address, dspace is from cm not pm
1900    - MxPD must set MMR1 for SP recovery in case of fault
1901 */
1902 
1903         case 064:                                       /* MTPS */
1904             if (CPUT (HAS_MXPS)) {
1905                 dst = dstreg? R[dstspec]: ReadB (GeteaB (dstspec));
1906                 if (cm == MD_KER) {
1907                     ipl = (dst >> PSW_V_IPL) & 07;
1908                     trap_req = calc_ints (ipl, trap_req);
1909                     }
1910                 N = (dst >> PSW_V_N) & 01;
1911                 Z = (dst >> PSW_V_Z) & 01;
1912                 V = (dst >> PSW_V_V) & 01;
1913                 C = (dst >> PSW_V_C) & 01;
1914                 }
1915             else setTRAP (TRAP_ILL);
1916             break;
1917 
1918         case 065:                                       /* MFPD */
1919             if (CPUT (HAS_MXPY)) {
1920                 if (dstreg) {
1921                     if ((dstspec == 6) && (cm != pm))
1922                         dst = STACKFILE[pm];
1923                     else dst = R[dstspec];
1924                     }
1925                 else dst = ReadW ((GeteaW (dstspec) & 0177777) | calc_ds (pm));
1926                 N = GET_SIGN_W (dst);
1927                 Z = GET_Z (dst);
1928                 V = 0;
1929                 SP = (SP - 2) & 0177777;
1930                 if (update_MM)
1931                     MMR1 = calc_MMR1 (0366);
1932                 WriteW (dst, SP | dsenable);
1933                 if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)))
1934                     set_stack_trap (SP);
1935                 }
1936             else setTRAP (TRAP_ILL);
1937             break;
1938 
1939         case 066:                                       /* MTPD */
1940             if (CPUT (HAS_MXPY)) {
1941                 dst = ReadW (SP | dsenable);
1942                 N = GET_SIGN_W (dst);
1943                 Z = GET_Z (dst);
1944                 V = 0;
1945                 SP = (SP + 2) & 0177777;
1946                 if (update_MM)
1947                     MMR1 = 026;
1948                 if (dstreg) {
1949                     if ((dstspec == 6) && (cm != pm))
1950                         STACKFILE[pm] = dst;
1951                     else R[dstspec] = dst;
1952                     }
1953                 else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_ds (pm));
1954                 }
1955             else setTRAP (TRAP_ILL);
1956             break;
1957 
1958         case 067:                                       /* MFPS */
1959             if (CPUT (HAS_MXPS)) {
1960                 dst = get_PSW () & 0377;
1961                 N = GET_SIGN_B (dst);
1962                 Z = GET_Z (dst);
1963                 V = 0;
1964                 if (dstreg)
1965                     R[dstspec] = (dst & 0200)? 0177400 | dst: dst;
1966                 else WriteB (dst, GeteaB (dstspec));
1967                 }
1968             else setTRAP (TRAP_ILL);
1969             break;
1970 
1971         default:
1972             setTRAP (TRAP_ILL);
1973             break;
1974             }                                           /* end switch SOPs */
1975         break;                                          /* end case 010 */
1976 
1977 /* Opcodes 11 - 16: double operand byte instructions
1978 
1979    Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)]
1980    Sub: v = [sign (src) != sign (src2)] and [sign (src) = sign (result)]
1981 */
1982 
1983     case 011:                                           /* MOVB */
1984         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
1985             ea = GeteaB (dstspec);
1986             dst = R[srcspec] & 0377;
1987             }
1988         else {
1989             dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec));
1990             if (!dstreg) ea = GeteaB (dstspec);
1991             }
1992         N = GET_SIGN_B (dst);
1993         Z = GET_Z (dst);
1994         V = 0;
1995         if (dstreg)
1996             R[dstspec] = (dst & 0200)? 0177400 | dst: dst;
1997         else WriteB (dst, ea);
1998         break;
1999 
2000     case 012:                                           /* CMPB */
2001         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
2002             src2 = ReadB (GeteaB (dstspec));
2003             src = R[srcspec] & 0377;
2004             }
2005         else {
2006             src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec));
2007             src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec));
2008             }
2009         dst = (src - src2) & 0377;
2010         N = GET_SIGN_B (dst);
2011         Z = GET_Z (dst);
2012         V = GET_SIGN_B ((src ^ src2) & (~src2 ^ dst));
2013         C = (src < src2);
2014         break;
2015 
2016     case 013:                                           /* BITB */
2017         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
2018             src2 = ReadB (GeteaB (dstspec));
2019             src = R[srcspec] & 0377;
2020             }
2021         else {
2022             src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec));
2023             src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec));
2024             }
2025         dst = (src2 & src) & 0377;
2026         N = GET_SIGN_B (dst);
2027         Z = GET_Z (dst);
2028         V = 0;
2029         break;
2030 
2031     case 014:                                           /* BICB */
2032         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
2033             src2 = ReadMB (GeteaB (dstspec));
2034             src = R[srcspec];
2035             }
2036         else {
2037             src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec));
2038             src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
2039             }
2040         dst = (src2 & ~src) & 0377;
2041         N = GET_SIGN_B (dst);
2042         Z = GET_Z (dst);
2043         V = 0;
2044         if (dstreg)
2045             R[dstspec] = (R[dstspec] & 0177400) | dst;
2046         else PWriteB (dst, last_pa);
2047         break;
2048 
2049     case 015:                                           /* BISB */
2050         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
2051             src2 = ReadMB (GeteaB (dstspec));
2052             src = R[srcspec];
2053             }
2054         else {
2055             src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec));
2056             src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec));
2057             }
2058         dst = (src2 | src) & 0377;
2059         N = GET_SIGN_B (dst);
2060         Z = GET_Z (dst);
2061         V = 0;
2062         if (dstreg)
2063             R[dstspec] = (R[dstspec] & 0177400) | dst;
2064         else PWriteB (dst, last_pa);
2065         break;
2066 
2067     case 016:                                           /* SUB */
2068         if (CPUT (IS_SDSD) && srcreg && !dstreg) {      /* R,not R */
2069             src2 = ReadMW (GeteaW (dstspec));
2070             src = R[srcspec];
2071             }
2072         else {
2073             src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec));
2074             src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
2075             }
2076         dst = (src2 - src) & 0177777;
2077         N = GET_SIGN_W (dst);
2078         Z = GET_Z (dst);
2079         V = GET_SIGN_W ((src ^ src2) & (~src ^ dst));
2080         C = (src2 < src);
2081         if (dstreg)
2082             R[dstspec] = dst;
2083         else PWriteW (dst, last_pa);
2084         break;
2085 
2086 /* Opcode 17: floating point */
2087 
2088     case 017:
2089         if (CPUO (OPT_FPP))
2090             fp11 (IR);                  /* call fpp */
2091         else setTRAP (TRAP_ILL);
2092         break;                                          /* end case 017 */
2093         }                                               /* end switch op */
2094     }                                                   /* end main loop */
2095 
2096 /* Simulation halted */
2097 
2098 PSW = get_PSW ();
2099 for (i = 0; i < 6; i++)
2100     REGFILE[i][rs] = R[i];
2101 STACKFILE[cm] = SP;
2102 saved_PC = PC & 0177777;
2103 pcq_r->qptr = pcq_p;                                    /* update pc q ptr */
2104 set_r_display (rs, cm);
2105 return reason;
2106 }
2107 
2108 /* Effective address calculations
2109 
2110    Inputs:
2111         spec    =       specifier <5:0>
2112    Outputs:
2113         ea      =       effective address
2114                         <15:0> =  virtual address
2115                         <16> =    instruction/data data space
2116                         <18:17> = mode
2117 
2118    Data space calculation: the PDP-11 features both instruction and data
2119    spaces.  Instruction space contains the instruction and any sequential
2120    add ons (eg, immediates, absolute addresses).  Data space contains all
2121    data operands and indirect addresses.  If data space is enabled, then
2122    memory references are directed according to these rules:
2123 
2124         Mode    Index ref       Indirect ref            Direct ref
2125         10..16  na              na                      data
2126         17      na              na                      instruction
2127         20..26  na              na                      data
2128         27      na              na                      instruction
2129         30..36  na              data                    data
2130         37      na              instruction (absolute)  data
2131         40..46  na              na                      data
2132         47      na              na                      instruction
2133         50..56  na              data                    data
2134         57      na              instruction             data
2135         60..67  instruction     na                      data
2136         70..77  instruction     data                    data
2137 
2138    According to the PDP-11 Architecture Handbook, MMR1 records all
2139    autoincrement and autodecrement operations, including those which
2140    explicitly reference the PC.  For the J-11, this is only true for
2141    autodecrement operands, autodecrement deferred operands, and
2142    autoincrement destination operands that involve a write to memory.
2143    The simulator follows the Handbook, for simplicity.
2144 
2145    Notes:
2146 
2147    - dsenable will direct a reference to data space if data space is enabled
2148    - ds will direct a reference to data space if data space is enabled AND if
2149         the specifier register is not PC; this is used for 17, 27, 37, 47, 57
2150    - Modes 2x, 3x, 4x, and 5x must update MMR1 if updating enabled
2151    - Modes 46 and 56 must check for stack overflow if kernel mode
2152 */
2153 
2154 /* Effective address calculation for words */
2155 
GeteaW(int32 spec)2156 int32 GeteaW (int32 spec)
2157 {
2158 int32 adr, reg, ds;
2159 
2160 reg = spec & 07;                                        /* register number */
2161 ds = (reg == 7)? isenable: dsenable;                    /* dspace if not PC */
2162 switch (spec >> 3) {                                    /* decode spec<5:3> */
2163 
2164     default:                                            /* can't get here */
2165     case 1:                                             /* (R) */
2166         return (R[reg] | ds);
2167 
2168     case 2:                                             /* (R)+ */
2169         R[reg] = ((adr = R[reg]) + 2) & 0177777;
2170         if (update_MM)
2171             MMR1 = calc_MMR1 (020 | reg);
2172         return (adr | ds);
2173 
2174     case 3:                                             /* @(R)+ */
2175         R[reg] = ((adr = R[reg]) + 2) & 0177777;
2176         if (update_MM)
2177             MMR1 = calc_MMR1 (020 | reg);
2178         adr = ReadW (adr | ds);
2179         return (adr | dsenable);
2180 
2181     case 4:                                             /* -(R) */
2182         adr = R[reg] = (R[reg] - 2) & 0177777;
2183         if (update_MM)
2184             MMR1 = calc_MMR1 (0360 | reg);
2185         if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
2186             set_stack_trap (adr);
2187         return (adr | ds);
2188 
2189     case 5:                                             /* @-(R) */
2190         adr = R[reg] = (R[reg] - 2) & 0177777;
2191         if (update_MM)
2192             MMR1 = calc_MMR1 (0360 | reg);
2193         if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
2194             set_stack_trap (adr);
2195         adr = ReadW (adr | ds);
2196         return (adr | dsenable);
2197 
2198     case 6:                                             /* d(r) */
2199         adr = ReadW (PC | isenable);
2200         PC = (PC + 2) & 0177777;
2201         return (((R[reg] + adr) & 0177777) | dsenable);
2202 
2203     case 7:                                             /* @d(R) */
2204         adr = ReadW (PC | isenable);
2205         PC = (PC + 2) & 0177777;
2206         adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
2207         return (adr | dsenable);
2208         }                                               /* end switch */
2209 }
2210 
2211 /* Effective address calculation for bytes */
2212 
GeteaB(int32 spec)2213 int32 GeteaB (int32 spec)
2214 {
2215 int32 adr, reg, ds, delta;
2216 
2217 reg = spec & 07;                                        /* reg number */
2218 ds = (reg == 7)? isenable: dsenable;                    /* dspace if not PC */
2219 switch (spec >> 3) {                                    /* decode spec<5:3> */
2220 
2221     default:                                            /* can't get here */
2222     case 1:                                             /* (R) */
2223         return (R[reg] | ds);
2224 
2225     case 2:                                                     /* (R)+ */
2226         delta = 1 + (reg >= 6);                         /* 2 if R6, PC */
2227         R[reg] = ((adr = R[reg]) + delta) & 0177777;
2228         if (update_MM)
2229             MMR1 = calc_MMR1 ((delta << 3) | reg);
2230         return (adr | ds);
2231 
2232     case 3:                                             /* @(R)+ */
2233         R[reg] = ((adr = R[reg]) + 2) & 0177777;
2234         if (update_MM)
2235             MMR1 = calc_MMR1 (020 | reg);
2236         adr = ReadW (adr | ds);
2237         return (adr | dsenable);
2238 
2239     case 4:                                             /* -(R) */
2240         delta = 1 + (reg >= 6);                         /* 2 if R6, PC */
2241         adr = R[reg] = (R[reg] - delta) & 0177777;
2242         if (update_MM)
2243             MMR1 = calc_MMR1 ((((-delta) & 037) << 3) | reg);
2244         if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
2245             set_stack_trap (adr);
2246         return (adr | ds);
2247 
2248     case 5:                                             /* @-(R) */
2249         adr = R[reg] = (R[reg] - 2) & 0177777;
2250         if (update_MM)
2251             MMR1 = calc_MMR1 (0360 | reg);
2252         if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
2253             set_stack_trap (adr);
2254         adr = ReadW (adr | ds);
2255         return (adr | dsenable);
2256 
2257     case 6:                                             /* d(r) */
2258         adr = ReadW (PC | isenable);
2259         PC = (PC + 2) & 0177777;
2260         return (((R[reg] + adr) & 0177777) | dsenable);
2261 
2262     case 7:                                             /* @d(R) */
2263         adr = ReadW (PC | isenable);
2264         PC = (PC + 2) & 0177777;
2265         adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
2266         return (adr | dsenable);
2267         }                                               /* end switch */
2268 }
2269 
2270 /* Read byte and word routines, read only and read-modify-write versions
2271 
2272    Inputs:
2273         va      =       virtual address, <18:16> = mode, I/D space
2274    Outputs:
2275         data    =       data read from memory or I/O space
2276 */
2277 
ReadE(int32 va)2278 int32 ReadE (int32 va)
2279 {
2280 int32 pa, data;
2281 
2282 if ((va & 1) && CPUT (HAS_ODD)) {                       /* odd address? */
2283     setCPUERR (CPUE_ODD);
2284     ABORT (TRAP_ODD);
2285     }
2286 pa = relocR (va);                                       /* relocate */
2287 if (ADDR_IS_MEM (pa))                                   /* memory address? */
2288     return (M[pa >> 1]);
2289 if ((pa < IOPAGEBASE) ||                                /* not I/O address */
2290     (CPUT (CPUT_J) && (pa >= IOBA_CPU))) {              /* or J11 int reg? */
2291         setCPUERR (CPUE_NXM);
2292         ABORT (TRAP_NXM);
2293         }
2294 if (iopageR (&data, pa, READ) != SCPE_OK) {             /* invalid I/O addr? */
2295     setCPUERR (CPUE_TMO);
2296     ABORT (TRAP_NXM);
2297     }
2298 return data;
2299 }
2300 
ReadW(int32 va)2301 int32 ReadW (int32 va)
2302 {
2303 int32 pa, data;
2304 
2305 if ((va & 1) && CPUT (HAS_ODD)) {                       /* odd address? */
2306     setCPUERR (CPUE_ODD);
2307     ABORT (TRAP_ODD);
2308     }
2309 pa = relocR (va);                                       /* relocate */
2310 if (ADDR_IS_MEM (pa))                                   /* memory address? */
2311     return (M[pa >> 1]);
2312 if (pa < IOPAGEBASE) {                                  /* not I/O address? */
2313     setCPUERR (CPUE_NXM);
2314     ABORT (TRAP_NXM);
2315     }
2316 if (iopageR (&data, pa, READ) != SCPE_OK) {             /* invalid I/O addr? */
2317     setCPUERR (CPUE_TMO);
2318     ABORT (TRAP_NXM);
2319     }
2320 return data;
2321 }
2322 
ReadB(int32 va)2323 int32 ReadB (int32 va)
2324 {
2325 int32 pa, data;
2326 
2327 pa = relocR (va);                                       /* relocate */
2328 if (ADDR_IS_MEM (pa))
2329     return (va & 1? M[pa >> 1] >> 8: M[pa >> 1]) & 0377;
2330 if (pa < IOPAGEBASE) {                                  /* not I/O address? */
2331     setCPUERR (CPUE_NXM);
2332     ABORT (TRAP_NXM);
2333     }
2334 if (iopageR (&data, pa, READ) != SCPE_OK) {             /* invalid I/O addr? */
2335     setCPUERR (CPUE_TMO);
2336     ABORT (TRAP_NXM);
2337     }
2338 return ((va & 1)? data >> 8: data) & 0377;
2339 }
2340 
ReadMW(int32 va)2341 int32 ReadMW (int32 va)
2342 {
2343 int32 data;
2344 
2345 if ((va & 1) && CPUT (HAS_ODD)) {                       /* odd address? */
2346     setCPUERR (CPUE_ODD);
2347     ABORT (TRAP_ODD);
2348     }
2349 last_pa = relocW (va);                                  /* reloc, wrt chk */
2350 if (ADDR_IS_MEM (last_pa))                              /* memory address? */
2351     return (M[last_pa >> 1]);
2352 if (last_pa < IOPAGEBASE) {                             /* not I/O address? */
2353     setCPUERR (CPUE_NXM);
2354     ABORT (TRAP_NXM);
2355     }
2356 if (iopageR (&data, last_pa, READ) != SCPE_OK) {        /* invalid I/O addr? */
2357     setCPUERR (CPUE_TMO);
2358     ABORT (TRAP_NXM);
2359     }
2360 return data;
2361 }
2362 
ReadMB(int32 va)2363 int32 ReadMB (int32 va)
2364 {
2365 int32 data;
2366 
2367 last_pa = relocW (va);                                  /* reloc, wrt chk */
2368 if (ADDR_IS_MEM (last_pa))
2369     return (va & 1? M[last_pa >> 1] >> 8: M[last_pa >> 1]) & 0377;
2370 if (last_pa < IOPAGEBASE) {                             /* not I/O address? */
2371     setCPUERR (CPUE_NXM);
2372     ABORT (TRAP_NXM);
2373     }
2374 if (iopageR (&data, last_pa, READ) != SCPE_OK) {        /* invalid I/O addr? */
2375     setCPUERR (CPUE_TMO);
2376     ABORT (TRAP_NXM);
2377     }
2378 return ((va & 1)? data >> 8: data) & 0377;
2379 }
2380 
2381 /* Write byte and word routines
2382 
2383    Inputs:
2384         data    =       data to be written
2385         va      =       virtual address, <18:16> = mode, I/D space, or
2386         pa      =       physical address
2387    Outputs: none
2388 */
2389 
WriteW(int32 data,int32 va)2390 void WriteW (int32 data, int32 va)
2391 {
2392 int32 pa;
2393 
2394 if ((va & 1) && CPUT (HAS_ODD)) {                       /* odd address? */
2395     setCPUERR (CPUE_ODD);
2396     ABORT (TRAP_ODD);
2397     }
2398 pa = relocW (va);                                       /* relocate */
2399 if (ADDR_IS_MEM (pa)) {                                 /* memory address? */
2400     M[pa >> 1] = data;
2401     return;
2402     }
2403 if (pa < IOPAGEBASE) {                                  /* not I/O address? */
2404     setCPUERR (CPUE_NXM);
2405     ABORT (TRAP_NXM);
2406     }
2407 if (iopageW (data, pa, WRITE) != SCPE_OK) {             /* invalid I/O addr? */
2408     setCPUERR (CPUE_TMO);
2409     ABORT (TRAP_NXM);
2410     }
2411 return;
2412 }
2413 
WriteB(int32 data,int32 va)2414 void WriteB (int32 data, int32 va)
2415 {
2416 int32 pa;
2417 
2418 pa = relocW (va);                                       /* relocate */
2419 if (ADDR_IS_MEM (pa)) {                                 /* memory address? */
2420     if (va & 1)
2421         M[pa >> 1] = (M[pa >> 1] & 0377) | (data << 8);
2422     else M[pa >> 1] = (M[pa >> 1] & ~0377) | data;
2423     return;
2424     }
2425 if (pa < IOPAGEBASE) {                                  /* not I/O address? */
2426     setCPUERR (CPUE_NXM);
2427     ABORT (TRAP_NXM);
2428     }
2429 if (iopageW (data, pa, WRITEB) != SCPE_OK) {            /* invalid I/O addr? */
2430     setCPUERR (CPUE_TMO);
2431     ABORT (TRAP_NXM);
2432     }
2433 return;
2434 }
2435 
PWriteW(int32 data,int32 pa)2436 void PWriteW (int32 data, int32 pa)
2437 {
2438 if (ADDR_IS_MEM (pa)) {                                 /* memory address? */
2439     M[pa >> 1] = data;
2440     return;
2441     }
2442 if (pa < IOPAGEBASE) {                                  /* not I/O address? */
2443     setCPUERR (CPUE_NXM);
2444     ABORT (TRAP_NXM);
2445     }
2446 if (iopageW (data, pa, WRITE) != SCPE_OK) {             /* invalid I/O addr? */
2447     setCPUERR (CPUE_TMO);
2448     ABORT (TRAP_NXM);
2449     }
2450 return;
2451 }
2452 
PWriteB(int32 data,int32 pa)2453 void PWriteB (int32 data, int32 pa)
2454 {
2455 if (ADDR_IS_MEM (pa)) {                                 /* memory address? */
2456     if (pa & 1)
2457         M[pa >> 1] = (M[pa >> 1] & 0377) | (data << 8);
2458     else M[pa >> 1] = (M[pa >> 1] & ~0377) | data;
2459     return;
2460     }
2461 if (pa < IOPAGEBASE) {                                  /* not I/O address? */
2462     setCPUERR (CPUE_NXM);
2463     ABORT (TRAP_NXM);
2464     }
2465 if (iopageW (data, pa, WRITEB) != SCPE_OK) {            /* invalid I/O addr? */
2466     setCPUERR (CPUE_TMO);
2467     ABORT (TRAP_NXM);
2468     }
2469 return;
2470 }
2471 
2472 /* Relocate virtual address, read access
2473 
2474    Inputs:
2475         va      =       virtual address, <18:16> = mode, I/D space
2476    Outputs:
2477         pa      =       physical address
2478    On aborts, this routine aborts back to the top level simulator
2479    with an appropriate trap code.
2480 
2481    Notes:
2482    - The 'normal' read codes (010, 110) are done in-line; all
2483      others in a subroutine
2484    - APRFILE[UNUSED] is all zeroes, forcing non-resident abort
2485    - Aborts must update MMR0<15:13,6:1> if updating is enabled
2486 */
2487 
relocR(int32 va)2488 int32 relocR (int32 va)
2489 {
2490 int32 apridx, apr, pa;
2491 
2492 if (MMR0 & MMR0_MME) {                                  /* if mmgt */
2493     apridx = (va >> VA_V_APF) & 077;                    /* index into APR */
2494     apr = APRFILE[apridx];                              /* with va<18:13> */
2495     if ((apr & PDR_PRD) != 2)                           /* not 2, 6? */
2496          relocR_test (va, apridx);                      /* long test */
2497     if (PLF_test (va, apr))                             /* pg lnt error? */
2498         reloc_abort (MMR0_PL, apridx);
2499     pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK;
2500     if ((MMR3 & MMR3_M22E) == 0) {
2501         pa = pa & 0777777;
2502         if (pa >= 0760000)
2503             pa = 017000000 | pa;
2504         }
2505     }
2506 else {
2507     pa = va & 0177777;                                  /* mmgt off */
2508     if (pa >= 0160000)
2509         pa = 017600000 | pa;
2510     }
2511 return pa;
2512 }
2513 
2514 /* Read relocation, access control field != read only or read/write
2515 
2516    ACF value            11/45,11/70             all others
2517 
2518    0                    abort NR                abort NR
2519    1                    trap                    -
2520    2                    ok                      ok
2521    3                    abort NR                -
2522    4                    trap                    abort NR
2523    5                    ok                      -
2524    6                    ok                      ok
2525    7                    abort NR                -
2526 */
2527 
relocR_test(int32 va,int32 apridx)2528 void relocR_test (int32 va, int32 apridx)
2529 {
2530 int32 apr, err;
2531 
2532 err = 0;                                                /* init status */
2533 apr = APRFILE[apridx];                                  /* get APR */
2534 switch (apr & PDR_ACF) {                                /* case on ACF */
2535 
2536     case 1: case 4:                                     /* trap read */
2537         if (CPUT (HAS_MMTR)) {                          /* traps implemented? */
2538             APRFILE[apridx] = APRFILE[apridx] | PDR_A;  /* set A */
2539             if (MMR0 & MMR0_TENB) {                     /* traps enabled? */
2540                 if (update_MM)                          /* update MMR0 */
2541                     MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE);
2542                 MMR0 = MMR0 | MMR0_TRAP;                /* set trap flag */
2543                 setTRAP (TRAP_MME);                     /* set trap */
2544                 }
2545             return;                                     /* continue op */
2546             }                                           /* not impl, abort NR */
2547     case 0: case 3: case 7:                             /* non-resident */
2548         err = MMR0_NR;                                  /* set MMR0 */
2549         break;                                          /* go test PLF, abort */
2550 
2551     case 2: case 5: case 6:                             /* readable */
2552         return;                                         /* continue */
2553         }                                               /* end switch */
2554 
2555 if (PLF_test (va, apr))                                 /* pg lnt error? */
2556     err = err | MMR0_PL;
2557 reloc_abort (err, apridx);
2558 return;
2559 }
2560 
PLF_test(int32 va,int32 apr)2561 t_bool PLF_test (int32 va, int32 apr)
2562 {
2563 int32 dbn = va & VA_BN;                                 /* extr block num */
2564 int32 plf = (apr & PDR_PLF) >> 2;                       /* extr page length */
2565 
2566 return ((apr & PDR_ED)? (dbn < plf): (dbn > plf));      /* pg lnt error? */
2567 }
2568 
reloc_abort(int32 err,int32 apridx)2569 void reloc_abort (int32 err, int32 apridx)
2570 {
2571 if (update_MM) MMR0 =                                   /* update MMR0 */
2572     (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE);
2573 APRFILE[apridx] = APRFILE[apridx] | PDR_A;              /* set A */
2574 MMR0 = MMR0 | err;                                      /* set aborts */
2575 ABORT (TRAP_MME);                                       /* abort ref */
2576 return;
2577 }
2578 
2579 /* Relocate virtual address, write access
2580 
2581    Inputs:
2582         va      =       virtual address, <18:16> = mode, I/D space
2583    Outputs:
2584         pa      =       physical address
2585    On aborts, this routine aborts back to the top level simulator
2586    with an appropriate trap code.
2587 
2588    Notes:
2589    - The 'normal' write code (110) is done in-line; all others
2590      in a subroutine
2591    - APRFILE[UNUSED] is all zeroes, forcing non-resident abort
2592    - Aborts must update MMR0<15:13,6:1> if updating is enabled
2593 */
2594 
relocW(int32 va)2595 int32 relocW (int32 va)
2596 {
2597 int32 apridx, apr, pa;
2598 
2599 if (MMR0 & MMR0_MME) {                                  /* if mmgt */
2600     apridx = (va >> VA_V_APF) & 077;                    /* index into APR */
2601     apr = APRFILE[apridx];                              /* with va<18:13> */
2602     if ((apr & PDR_ACF) != 6)                           /* not writeable? */
2603         relocW_test (va, apridx);                       /* long test */
2604     if (PLF_test (va, apr))                             /* pg lnt error? */
2605         reloc_abort (MMR0_PL, apridx);
2606     APRFILE[apridx] = apr | PDR_W;                      /* set W */
2607     pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK;
2608     if ((MMR3 & MMR3_M22E) == 0) {
2609         pa = pa & 0777777;
2610         if (pa >= 0760000)
2611             pa = 017000000 | pa;
2612         }
2613     }
2614 else {
2615     pa = va & 0177777;                                  /* mmgt off */
2616     if (pa >= 0160000)
2617         pa = 017600000 | pa;
2618     }
2619 return pa;
2620 }
2621 
2622 /* Write relocation, access control field != read/write
2623 
2624    ACF value            11/45,11/70             all others
2625 
2626    0                    abort NR                abort NR
2627    1                    abort RO                -
2628    2                    abort RO                abort RO
2629    3                    abort NR                -
2630    4                    trap                    abort NR
2631    5                    trap                    -
2632    6                    ok                      ok
2633    7                    abort NR                -
2634 */
2635 
relocW_test(int32 va,int32 apridx)2636 void relocW_test (int32 va, int32 apridx)
2637 {
2638 int32 apr, err;
2639 
2640 err = 0;                                                /* init status */
2641 apr = APRFILE[apridx];                                  /* get APR */
2642 switch (apr & PDR_ACF) {                                /* case on ACF */
2643 
2644     case 4: case 5:                                     /* trap write */
2645         if (CPUT (HAS_MMTR)) {                          /* traps implemented? */
2646             APRFILE[apridx] = APRFILE[apridx] | PDR_A;  /* set A */
2647             if (MMR0 & MMR0_TENB) {                     /* traps enabled? */
2648                 if (update_MM)                          /* update MMR0 */
2649                     MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE);
2650                 MMR0 = MMR0 | MMR0_TRAP;                /* set trap flag */
2651                 setTRAP (TRAP_MME);                     /* set trap */
2652                 }
2653             return;                                     /* continue op */
2654             }                                           /* not impl, abort NR */
2655     case 0: case 3: case 7:                             /* non-resident */
2656         err = MMR0_NR;                                  /* MMR0 status */
2657         break;                                          /* go test PLF, abort */
2658 
2659     case 1: case 2:                                     /* read only */
2660         err = MMR0_RO;                                  /* MMR0 status */
2661         break;
2662 
2663     case 6:                                             /* read/write */
2664         return;                                         /* continue */
2665         }                                               /* end switch */
2666 if (PLF_test (va, apr))                                 /* pg lnt error? */
2667     err = err | MMR0_PL;
2668 reloc_abort (err, apridx);
2669 return;
2670 }
2671 
2672 /* Relocate virtual address, console access
2673 
2674    Inputs:
2675         va      =       virtual address
2676         sw      =       switches
2677    Outputs:
2678         pa      =       physical address
2679    On aborts, this routine returns MAXMEMSIZE
2680 */
2681 
relocC(int32 va,int32 sw)2682 int32 relocC (int32 va, int32 sw)
2683 {
2684 int32 mode, dbn, plf, apridx, apr, pa;
2685 
2686 if (MMR0 & MMR0_MME) {                                  /* if mmgt */
2687     if (sw & SWMASK ('K'))
2688         mode = MD_KER;
2689     else if (sw & SWMASK ('S'))
2690         mode = MD_SUP;
2691     else if (sw & SWMASK ('U'))
2692         mode = MD_USR;
2693     else if (sw & SWMASK ('P'))
2694         mode = (PSW >> PSW_V_PM) & 03;
2695     else mode = (PSW >> PSW_V_CM) & 03;
2696     va = va | ((sw & SWMASK ('D'))? calc_ds (mode): calc_is (mode));
2697     apridx = (va >> VA_V_APF) & 077;                    /* index into APR */
2698     apr = APRFILE[apridx];                              /* with va<18:13> */
2699     dbn = va & VA_BN;                                   /* extr block num */
2700     plf = (apr & PDR_PLF) >> 2;                         /* extr page length */
2701     if ((apr & PDR_PRD) == 0)                           /* not readable? */
2702         return MAXMEMSIZE;
2703     if ((apr & PDR_ED)? dbn < plf: dbn > plf)
2704         return MAXMEMSIZE;
2705     pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK;
2706     if ((MMR3 & MMR3_M22E) == 0) {
2707         pa = pa & 0777777;
2708         if (pa >= 0760000)
2709             pa = 017000000 | pa;
2710         }
2711     }
2712 else {
2713     pa = va & 0177777;                                  /* mmgt off */
2714     if (pa >= 0160000)
2715         pa = 017600000 | pa;
2716     }
2717 return pa;
2718 }
2719 
2720 /* Memory management registers
2721 
2722    MMR0 17777572        read/write, certain bits unimplemented or read only
2723    MMR1 17777574        read only
2724    MMR2 17777576        read only
2725    MMR3 17777516        read/write, certain bits unimplemented
2726 */
2727 
MMR012_rd(int32 * data,int32 pa,int32 access)2728 t_stat MMR012_rd (int32 *data, int32 pa, int32 access)
2729 {
2730 switch ((pa >> 1) & 3) {                                /* decode pa<2:1> */
2731 
2732     case 0:                                             /* SR */
2733         return SCPE_NXM;
2734 
2735     case 1:                                             /* MMR0 */
2736         *data = MMR0 & cpu_tab[cpu_model].mm0;
2737         break;
2738 
2739     case 2:                                             /* MMR1 */
2740         *data = MMR1;
2741         break;
2742 
2743     case 3:                                             /* MMR2 */
2744         *data = MMR2;
2745         break;
2746         }                                               /* end switch pa */
2747 
2748 return SCPE_OK;
2749 }
2750 
MMR012_wr(int32 data,int32 pa,int32 access)2751 t_stat MMR012_wr (int32 data, int32 pa, int32 access)
2752 {
2753 switch ((pa >> 1) & 3) {                                /* decode pa<2:1> */
2754 
2755     case 0:                                             /* DR */
2756         return SCPE_NXM;
2757 
2758     case 1:                                             /* MMR0 */
2759         if (access == WRITEB)
2760             data = (pa & 1)? (MMR0 & 0377) | (data << 8): (MMR0 & ~0377) | data;
2761         data = data & cpu_tab[cpu_model].mm0;
2762         MMR0 = (MMR0 & ~MMR0_WR) | (data & MMR0_WR);
2763         return SCPE_OK;
2764 
2765     default:                                            /* MMR1, MMR2 */
2766         return SCPE_OK;
2767         }                                               /* end switch pa */
2768 }
2769 
MMR3_rd(int32 * data,int32 pa,int32 access)2770 t_stat MMR3_rd (int32 *data, int32 pa, int32 access)    /* MMR3 */
2771 {
2772 *data = MMR3 & cpu_tab[cpu_model].mm3;
2773 return SCPE_OK;
2774 }
2775 
MMR3_wr(int32 data,int32 pa,int32 access)2776 t_stat MMR3_wr (int32 data, int32 pa, int32 access)     /* MMR3 */
2777 {
2778 if (pa & 1)
2779     return SCPE_OK;
2780 MMR3 = data & cpu_tab[cpu_model].mm3;
2781 cpu_bme = (MMR3 & MMR3_BME) && (cpu_opt & OPT_UBM);
2782 dsenable = calc_ds (cm);
2783 return SCPE_OK;
2784 }
2785 
2786 /* PARs and PDRs.  These are grouped in I/O space as follows:
2787 
2788         17772200 - 17772276     supervisor block
2789         17772300 - 17772376     kernel block
2790         17777600 - 17777676     user block
2791 
2792    Within each block, the subblocks are I PDR's, D PDR's, I PAR's, D PAR's
2793 
2794    Thus, the algorithm for converting between I/O space addresses and
2795    APRFILE indices is as follows:
2796 
2797         idx<3:0> =      dspace'page     =       pa<4:1>
2798         par     =       PDR vs PAR      =       pa<5>
2799         idx<5:4> =      ker/sup/user    =       pa<8>'~pa<6>
2800 
2801    Note: the A,W bits are read only; they are cleared by any write to an APR
2802 */
2803 
APR_rd(int32 * data,int32 pa,int32 access)2804 t_stat APR_rd (int32 *data, int32 pa, int32 access)
2805 {
2806 t_stat left, idx;
2807 
2808 idx = (pa >> 1) & 017;                                  /* dspace'page */
2809 left = (pa >> 5) & 1;                                   /* PDR vs PAR */
2810 if ((pa & 0100) == 0)                                   /* 1 for super, user */
2811     idx = idx | 020;
2812 if (pa & 0400)                                          /* 1 for user only */
2813     idx = idx | 040;
2814 if (left)
2815     *data = (APRFILE[idx] >> 16) & cpu_tab[cpu_model].par;
2816 else *data = APRFILE[idx] & cpu_tab[cpu_model].pdr;
2817 return SCPE_OK;
2818 }
2819 
APR_wr(int32 data,int32 pa,int32 access)2820 t_stat APR_wr (int32 data, int32 pa, int32 access)
2821 {
2822 int32 left, idx, curr;
2823 
2824 idx = (pa >> 1) & 017;                                  /* dspace'page */
2825 left = (pa >> 5) & 1;                                   /* PDR vs PAR */
2826 if ((pa & 0100) == 0)                                   /* 1 for super, user */
2827     idx = idx | 020;
2828 if (pa & 0400)                                          /* 1 for user only */
2829     idx = idx | 040;
2830 if (left)
2831     curr = (APRFILE[idx] >> 16) & cpu_tab[cpu_model].par;
2832 else curr = APRFILE[idx] & cpu_tab[cpu_model].pdr;
2833 if (access == WRITEB)
2834     data = (pa & 1)? (curr & 0377) | (data << 8): (curr & ~0377) | data;
2835 if (left)
2836     APRFILE[idx] = ((APRFILE[idx] & 0177777) |
2837         (((uint32) (data & cpu_tab[cpu_model].par)) << 16)) & ~(PDR_A|PDR_W);
2838 else APRFILE[idx] = ((APRFILE[idx] & ~0177777) |
2839     (data & cpu_tab[cpu_model].pdr)) & ~(PDR_A|PDR_W);
2840 return SCPE_OK;
2841 }
2842 
2843 /* Explicit PSW read */
2844 
PSW_rd(int32 * data,int32 pa,int32 access)2845 t_stat PSW_rd (int32 *data, int32 pa, int32 access)
2846 {
2847 if (access == READC)
2848     *data = PSW;
2849 else *data = get_PSW ();
2850 return SCPE_OK;
2851 }
2852 
2853 /* Assemble PSW from pieces */
2854 
get_PSW(void)2855 int32 get_PSW (void)
2856 {
2857 return (cm << PSW_V_CM) | (pm << PSW_V_PM) |
2858     (rs << PSW_V_RS) | (fpd << PSW_V_FPD) |
2859     (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
2860     (N << PSW_V_N) | (Z << PSW_V_Z) |
2861     (V << PSW_V_V) | (C << PSW_V_C);
2862 }
2863 
2864 /* Explicit PSW write - T-bit may be protected */
2865 
PSW_wr(int32 data,int32 pa,int32 access)2866 t_stat PSW_wr (int32 data, int32 pa, int32 access)
2867 {
2868 int32 i, curr, oldrs;
2869 
2870 if (access == WRITEC) {                                 /* console access? */
2871     PSW = data & cpu_tab[cpu_model].psw;
2872     return SCPE_OK;
2873     }
2874 curr = get_PSW ();                                      /* get current */
2875 oldrs = rs;                                             /* save reg set */
2876 STACKFILE[cm] = SP;                                     /* save curr SP */
2877 if (access == WRITEB) data = (pa & 1)?
2878     (curr & 0377) | (data << 8): (curr & ~0377) | data;
2879 if (!CPUT (HAS_EXPT))                                   /* expl T writes? */
2880     data = (data & ~PSW_TBIT) | (curr & PSW_TBIT);      /* no, use old T */
2881 put_PSW (data, 0);                                      /* call calc_is,ds */
2882 if (rs != oldrs) {                                      /* switch reg set */
2883     for (i = 0; i < 6; i++) {
2884         REGFILE[i][oldrs] = R[i];
2885         R[i] = REGFILE[i][rs];
2886         }
2887     }
2888 SP = STACKFILE[cm];                                     /* switch SP */
2889 isenable = calc_is (cm);
2890 dsenable = calc_ds (cm);
2891 return SCPE_OK;
2892 }
2893 
2894 /* Store pieces of new PSW - implements RTI/RTT protection */
2895 
put_PSW(int32 val,t_bool prot)2896 void put_PSW (int32 val, t_bool prot)
2897 {
2898 val = val & cpu_tab[cpu_model].psw;                     /* mask off invalid bits */
2899 if (prot) {                                             /* protected? */
2900     cm = cm | ((val >> PSW_V_CM) & 03);                 /* or to cm,pm,rs */
2901     pm = pm | ((val >> PSW_V_PM) & 03);                 /* can't change ipl */
2902     rs = rs | ((val >> PSW_V_RS) & 01);
2903     }
2904 else {
2905     cm = (val >> PSW_V_CM) & 03;                        /* write cm,pm,rs,ipl */
2906     pm = (val >> PSW_V_PM) & 03;
2907     rs = (val >> PSW_V_RS) & 01;
2908     ipl = (val >> PSW_V_IPL) & 07;
2909     }
2910 fpd = (val >> PSW_V_FPD) & 01;                          /* always writeable */
2911 tbit = (val >> PSW_V_TBIT) & 01;
2912 N = (val >> PSW_V_N) & 01;
2913 Z = (val >> PSW_V_Z) & 01;
2914 V = (val >> PSW_V_V) & 01;
2915 C = (val >> PSW_V_C) & 01;
2916 return;
2917 }
2918 
2919 /* PIRQ write routine */
2920 
put_PIRQ(int32 val)2921 void put_PIRQ (int32 val)
2922 {
2923 int32 pl;
2924 
2925 PIRQ = val & PIRQ_RW;
2926 pl = 0;
2927 if (PIRQ & PIRQ_PIR1) {
2928     SET_INT (PIR1);
2929     pl = 0042;
2930     }
2931 else CLR_INT (PIR1);
2932 if (PIRQ & PIRQ_PIR2) {
2933     SET_INT (PIR2);
2934     pl = 0104;
2935     }
2936 else CLR_INT (PIR2);
2937 if (PIRQ & PIRQ_PIR3) {
2938     SET_INT (PIR3);
2939     pl = 0146;
2940     }
2941 else CLR_INT (PIR3);
2942 if (PIRQ & PIRQ_PIR4) {
2943     SET_INT (PIR4);
2944     pl = 0210;
2945     }
2946 else CLR_INT (PIR4);
2947 if (PIRQ & PIRQ_PIR5) {
2948     SET_INT (PIR5);
2949     pl = 0252;
2950     }
2951 else CLR_INT (PIR5);
2952 if (PIRQ & PIRQ_PIR6) {
2953     SET_INT (PIR6);
2954     pl = 0314;
2955     }
2956 else CLR_INT (PIR6);
2957 if (PIRQ & PIRQ_PIR7) {
2958     SET_INT (PIR7);
2959     pl = 0356;
2960     }
2961 else CLR_INT (PIR7);
2962 PIRQ = PIRQ | pl;
2963 return;
2964 }
2965 
2966 /* Stack trap routine */
2967 
set_stack_trap(int32 adr)2968 void set_stack_trap (int32 adr)
2969 {
2970 if (CPUT (HAS_STKLF)) {                                 /* fixed stack? */
2971     setTRAP (TRAP_YEL);                                 /* always yellow trap */
2972     setCPUERR (CPUE_YEL);
2973     }
2974 else if (CPUT (HAS_STKLR)) {                            /* register limit? */
2975     if (adr >= (STKLIM + STKL_R)) {                     /* yellow zone? */
2976         setTRAP (TRAP_YEL);                             /* still yellow trap */
2977         setCPUERR (CPUE_YEL);
2978         }
2979     else {                                              /* red zone abort */
2980         setCPUERR (CPUE_RED);
2981         STACKFILE[MD_KER] = 4;
2982         SP = 4;
2983         ABORT (TRAP_RED);
2984         }
2985     }
2986 return;                                                 /* no stack limit */
2987 }
2988 
2989 /* Reset routine */
2990 
cpu_reset(DEVICE * dptr)2991 t_stat cpu_reset (DEVICE *dptr)
2992 {
2993 PIRQ = 0;
2994 STKLIM = 0;
2995 PSW = 000340;
2996 MMR0 = 0;
2997 MMR1 = 0;
2998 MMR2 = 0;
2999 MMR3 = 0;
3000 trap_req = 0;
3001 wait_state = 0;
3002 if (M == NULL)
3003     M = (uint16 *) calloc (MEMSIZE >> 1, sizeof (uint16));
3004 if (M == NULL)
3005     return SCPE_MEM;
3006 pcq_r = find_reg ("PCQ", NULL, dptr);
3007 if (pcq_r)
3008     pcq_r->qptr = 0;
3009 else return SCPE_IERR;
3010 sim_brk_types = sim_brk_dflt = SWMASK ('E');
3011 set_r_display (0, MD_KER);
3012 return SCPE_OK;
3013 }
3014 
3015 /* Memory examine */
3016 
cpu_ex(t_value * vptr,t_addr addr,UNIT * uptr,int32 sw)3017 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
3018 {
3019 int32 iodata;
3020 t_stat stat;
3021 
3022 if (vptr == NULL)
3023     return SCPE_ARG;
3024 if (sw & SWMASK ('V')) {                                /* -v */
3025     if (addr >= VASIZE)
3026         return SCPE_NXM;
3027     addr = relocC (addr, sw);                           /* relocate */
3028     if (addr >= MAXMEMSIZE)
3029         return SCPE_REL;
3030     }
3031 if (addr < MEMSIZE) {
3032     *vptr = M[addr >> 1] & 0177777;
3033     return SCPE_OK;
3034     }
3035 if (addr < IOPAGEBASE)
3036     return SCPE_NXM;
3037 stat = iopageR (&iodata, addr, READC);
3038 *vptr = iodata;
3039 return stat;
3040 }
3041 
3042 /* Memory deposit */
3043 
cpu_dep(t_value val,t_addr addr,UNIT * uptr,int32 sw)3044 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
3045 {
3046 if (sw & SWMASK ('V')) {                                /* -v */
3047     if (addr >= VASIZE)
3048         return SCPE_NXM;
3049     addr = relocC (addr, sw);                           /* relocate */
3050     if (addr >= MAXMEMSIZE)
3051         return SCPE_REL;
3052     }
3053 if (addr < MEMSIZE) {
3054     M[addr >> 1] = val & 0177777;
3055     return SCPE_OK;
3056     }
3057 if (addr < IOPAGEBASE)
3058     return SCPE_NXM;
3059 return iopageW ((int32) val, addr, WRITEC);
3060 }
3061 
3062 /* Set R, SP register display addresses */
3063 
set_r_display(int32 rs,int32 cm)3064 void set_r_display (int32 rs, int32 cm)
3065 {
3066 extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr);
3067 REG *rptr;
3068 int32 i;
3069 
3070 rptr = find_reg ("R0", NULL, &cpu_dev);
3071 if (rptr == NULL)
3072     return;
3073 for (i = 0; i < 6; i++, rptr++)
3074     rptr->loc = (void *) &REGFILE[i][rs];
3075 rptr->loc = (void *) &STACKFILE[cm];
3076 return;
3077 }
3078 
3079 /* Set history */
3080 
cpu_set_hist(UNIT * uptr,int32 val,char * cptr,void * desc)3081 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
3082 {
3083 int32 i, lnt;
3084 t_stat r;
3085 
3086 if (cptr == NULL) {
3087     for (i = 0; i < hst_lnt; i++)
3088         hst[i].pc = 0;
3089     hst_p = 0;
3090     return SCPE_OK;
3091     }
3092 lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
3093 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
3094     return SCPE_ARG;
3095 hst_p = 0;
3096 if (hst_lnt) {
3097     free (hst);
3098     hst_lnt = 0;
3099     hst = NULL;
3100     }
3101 if (lnt) {
3102     hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
3103     if (hst == NULL)
3104         return SCPE_MEM;
3105     hst_lnt = lnt;
3106     }
3107 return SCPE_OK;
3108 }
3109 
3110 /* Show history */
3111 
cpu_show_hist(FILE * st,UNIT * uptr,int32 val,void * desc)3112 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
3113 {
3114 int32 j, k, di, lnt, ir;
3115 char *cptr = (char *) desc;
3116 t_value sim_eval[HIST_ILNT];
3117 t_stat r;
3118 InstHistory *h;
3119 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
3120     UNIT *uptr, int32 sw);
3121 
3122 if (hst_lnt == 0)                                       /* enabled? */
3123     return SCPE_NOFNC;
3124 if (cptr) {
3125     lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
3126     if ((r != SCPE_OK) || (lnt == 0))
3127         return SCPE_ARG;
3128     }
3129 else lnt = hst_lnt;
3130 di = hst_p - lnt;                                       /* work forward */
3131 if (di < 0)
3132     di = di + hst_lnt;
3133 fprintf (st, "PC     PSW     src    dst     IR\n\n");
3134 for (k = 0; k < lnt; k++) {                             /* print specified */
3135     h = &hst[(di++) % hst_lnt];                         /* entry pointer */
3136     if (h->pc & HIST_VLD) {                             /* instruction? */
3137         ir = h->inst[0];
3138         fprintf (st, "%06o %06o|", h->pc & ~HIST_VLD, h->psw);
3139         if (((ir & 0070000) != 0) ||                    /* dops, eis, fpp */
3140             ((ir & 0177000) == 0004000))                /* jsr */
3141             fprintf (st, "%06o %06o  ", h->src, h->dst);
3142         else if ((ir >= 0000100) &&                     /* not no opnd */
3143             (((ir & 0007700) <  0000300) ||             /* not branch */
3144              ((ir & 0007700) >= 0004000)))
3145             fprintf (st, "       %06o  ", h->dst);
3146         else fprintf (st, "               ");
3147         for (j = 0; j < HIST_ILNT; j++)
3148             sim_eval[j] = h->inst[j];
3149         if ((fprint_sym (st, h->pc & ~HIST_VLD, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
3150             fprintf (st, "(undefined) %06o", h->inst[0]);
3151         fputc ('\n', st);                               /* end line */
3152         }                                               /* end else instruction */
3153     }                                                   /* end for */
3154 return SCPE_OK;
3155 }
3156 
3157 /* Virtual address translation */
3158 
cpu_show_virt(FILE * of,UNIT * uptr,int32 val,void * desc)3159 t_stat cpu_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc)
3160 {
3161 t_stat r;
3162 char *cptr = (char *) desc;
3163 uint32 va, pa;
3164 
3165 if (cptr) {
3166     va = (uint32) get_uint (cptr, 8, VAMASK, &r);
3167     if (r == SCPE_OK) {
3168         pa = relocC (va, sim_switches);                 /* relocate */
3169         if (pa < MAXMEMSIZE)
3170             fprintf (of, "Virtual %-o = physical %-o\n", va, pa);
3171         else fprintf (of, "Virtual %-o is not valid\n", va);
3172         return SCPE_OK;
3173         }
3174     }
3175 fprintf (of, "Invalid argument\n");
3176 return SCPE_OK;
3177 }
3178