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