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