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, ®_rd, ®_wr }, /* Decode almost everything */
315 { 017777700, 017777775, ®_rd, ®_wr },
316
317 { 017777776, 017777777, &CPU_rd, &CPU_wr },
318
319 { 014000000, 017777777, ®_rd, ®_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