f977fb24da1e5decdff2515b825c0ddf1281b365
1 /* pdp11_cpu.c: PDP-11 CPU simulator
3 Copyright (c) 1993-2008, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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
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
92 The register state for the PDP-11 is:
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
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
124 The PDP-11 has many instruction formats:
126 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ double operand
127 | opcode | source spec | dest spec | 010000:067777
128 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 110000:167777
130 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register + operand
131 | opcode | src reg| dest spec | 004000:004777
132 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 070000:077777
134 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ single operand
135 | opcode | dest spec | 000100:000177
136 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000300:000377
140 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ single register
141 | opcode |dest reg| 000200:000207
142 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000230:000237
144 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ no operand
145 | opcode | 000000:000007
146 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
148 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ branch
149 | opcode | branch displacement | 000400:003477
150 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 100000:103477
152 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ EMT/TRAP
153 | opcode | trap code | 104000:104777
154 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
156 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ cond code operator
157 | opcode | immediate | 000240:000277
158 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
160 An operand specifier consists of an addressing mode and a register.
161 The addressing modes are:
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]]
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:
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]]
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.
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.
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.
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
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.
211 4. Adding I/O devices. These modules must be modified:
213 pdp11_defs.h add device address and interrupt definitions
214 pdp11_sys.c add to sim_devices table entry
219 #include "pdp11_defs.h"
220 #include "pdp11_cpumod.h"
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)
239 #define HIST_MAX (1u << 18)
240 #define HIST_VLD 1 /* make PC odd */
241 #define HIST_ILNT 4 /* max inst length */
248 uint16 inst
[HIST_ILNT
];
253 extern FILE *sim_log
;
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 */
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
[];
312 /* Function declarations */
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
);
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
);
356 /* Trap data structures */
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
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
377 /* CPU data structures
379 cpu_dev CPU device descriptor
380 cpu_unit CPU unit descriptor
381 cpu_reg CPU register list
382 cpu_mod CPU modifier list
385 UNIT cpu_unit
= { UDATA (NULL
, UNIT_FIX
|UNIT_BINK
, INIMEMSIZE
) };
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
},
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
},
627 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
629 &cpu_ex
, &cpu_dep
, &cpu_reset
,
632 NULL
, &cpu_set_size
, NULL
635 t_stat
sim_instr (void)
638 volatile int32 trapea
; /* used by setjmp */
641 /* Restore register state
644 2. Active register file based on PSW<rs>
645 3. Active stack pointer based on PSW<cm>
646 4. Memory management control flags
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? */
658 put_PSW (PSW
, 0); /* set PSW, call calc_xs */
659 for (i
= 0; i
< 6; i
++) R
[i
] = REGFILE
[i
][rs
];
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 */
667 trap_req
= calc_ints (ipl
, trap_req
); /* upd int req */
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.
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.
684 All variables used in setjmp processing, or assumed to be valid
685 after setjmp, must be volatile or global.
688 abortval
= setjmp (save_env
); /* set abort hdlr */
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? */
696 setCPUERR (CPUE_RED
);
697 STACKFILE
[MD_KER
] = 4;
698 if (cm
== MD_KER
) SP
= 4;
702 /* Main instruction fetch/decode loop
704 Check for traps or interrupts. If trap, locate the vector and check
705 for stop condition. If interrupt, locate the vector.
708 while (reason
== 0) {
710 int32 IR
, srcspec
, srcreg
, dstspec
, dstreg
;
711 int32 src
, src2
, dst
, ea
;
712 int32 i
, t
, sign
, oldrs
, trapnum
;
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 */
724 } /* end if sim_interval */
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;
740 trapea
= get_vector (ipl
); /* get int vector */
741 trapnum
= TRAP_V_MAX
; /* defang stk trap */
743 if (trapea
== 0) { /* nothing to do? */
744 trap_req
= calc_ints (ipl
, 0); /* recalculate */
745 continue; /* back to fetch */
746 } /* end if trapea */
748 /* Process a trap or interrupt
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
759 wait_state
= 0; /* exit wait state */
761 PSW
= get_PSW (); /* assemble PSW */
763 if (CPUT (HAS_MMTR
)) { /* 45,70? */
764 if (update_MM
) MMR2
= trapea
; /* save vector */
765 MMR0
= MMR0
& ~MMR0_IC
; /* clear IC */
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
];
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
);
787 if ((cm
== MD_KER
) && (SP
< (STKLIM
+ STKL_Y
)) &&
788 (trapnum
!= TRAP_V_RED
) && (trapnum
!= TRAP_V_YEL
))
790 MMR0
= MMR0
| MMR0_IC
; /* back to instr */
791 continue; /* end if traps */
794 /* Fetch and decode next instruction */
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 */
806 if (sim_brk_summ
&& sim_brk_test (PC
, SWMASK ('E'))) { /* breakpoint? */
807 reason
= STOP_IBKPT
; /* stop simulation */
811 if (update_MM
) { /* if mm not frozen */
815 IR
= ReadE (PC
| isenable
); /* fetch instruction */
816 sim_interval
= sim_interval
- 1;
817 srcspec
= (IR
>> 6) & 077; /* src, dst specs */
819 srcreg
= (srcspec
<= 07); /* src, dst = rmode? */
820 dstreg
= (dstspec
<= 07);
821 if (hst_lnt
) { /* record history? */
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
;
835 if (hst_p
>= hst_lnt
) hst_p
= 0;
837 PC
= (PC
+ 2) & 0177777; /* incr PC, mod 65k */
838 switch ((IR
>> 12) & 017) { /* decode IR<15:12> */
840 /* Opcode 0: no operands, specials, branches, JSR, SOPs */
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 */
849 switch (IR
) { /* decode IR<2:0> */
851 if ((cm
== MD_KER
) &&
852 (!CPUT (CPUT_J
) || ((MAINT
& MAINT_HTRAP
) == 0)))
854 else if (CPUT (HAS_HALT4
)) { /* priv trap? */
856 setCPUERR (CPUE_HALT
);
858 else setTRAP (TRAP_ILL
); /* no, ill inst */
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
);
882 if (!CPUT (HAS_RTT
)) {
887 src
= ReadW (SP
| dsenable
);
888 src2
= ReadW (((SP
+ 2) & 0177777) | dsenable
);
889 STACKFILE
[cm
] = SP
= (SP
+ 4) & 0177777;
891 put_PSW (src2
, (cm
!= MD_KER
)); /* store PSW, prot */
893 for (i
= 0; i
< 6; i
++) {
894 REGFILE
[i
][oldrs
] = R
[i
];
895 R
[i
] = REGFILE
[i
][rs
];
899 isenable
= calc_is (cm
);
900 dsenable
= calc_ds (cm
);
901 trap_req
= calc_ints (ipl
, trap_req
);
903 if (CPUT (HAS_RTT
) && tbit
&& /* RTT impl? */
904 (IR
== 000002)) setTRAP (TRAP_TRC
); /* RTI immed trap */
907 if (CPUT (HAS_MFPT
)) /* implemented? */
908 R
[0] = cpu_tab
[cpu_model
].mfpt
; /* get type */
909 else setTRAP (TRAP_ILL
);
911 } /* end switch no ops */
912 break; /* end case no ops */
915 if (dstreg
) setTRAP (CPUT (HAS_JREG4
)? TRAP_PRV
: TRAP_ILL
);
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 */
925 case 002: /* RTS et al*/
926 if (IR
< 000210) { /* RTS */
927 dstspec
= dstspec
& 07;
929 R
[dstspec
] = ReadW (SP
| dsenable
);
930 if (dstspec
!= 6) SP
= (SP
+ 2) & 0177777;
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
);
942 else setTRAP (TRAP_ILL
);
945 if (IR
< 000260) { /* clear CC */
951 } /* end if clear CCs */
952 if (IR
& 010) N
= 1; /* set CC */
956 break; /* end case RTS et al */
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;
965 if (dstreg
) R
[dstspec
] = dst
;
966 else PWriteW (dst
, last_pa
);
967 break; /* end SWAB */
969 case 004: case 005: /* BR */
973 case 006: case 007: /* BR */
977 case 010: case 011: /* BNE */
978 if (Z
== 0) { BRANCH_F (IR
); }
981 case 012: case 013: /* BNE */
982 if (Z
== 0) { BRANCH_B (IR
); }
985 case 014: case 015: /* BEQ */
986 if (Z
) { BRANCH_F (IR
); }
989 case 016: case 017: /* BEQ */
990 if (Z
) { BRANCH_B (IR
); }
993 case 020: case 021: /* BGE */
994 if ((N
^ V
) == 0) { BRANCH_F (IR
); }
997 case 022: case 023: /* BGE */
998 if ((N
^ V
) == 0) { BRANCH_B (IR
); }
1001 case 024: case 025: /* BLT */
1002 if (N
^ V
) { BRANCH_F (IR
); }
1005 case 026: case 027: /* BLT */
1006 if (N
^ V
) { BRANCH_B (IR
); }
1009 case 030: case 031: /* BGT */
1010 if ((Z
| (N
^ V
)) == 0) { BRANCH_F (IR
); }
1013 case 032: case 033: /* BGT */
1014 if ((Z
| (N
^ V
)) == 0) { BRANCH_B (IR
); }
1017 case 034: case 035: /* BLE */
1018 if (Z
| (N
^ V
)) { BRANCH_F (IR
); }
1021 case 036: case 037: /* BLE */
1022 if (Z
| (N
^ V
)) { BRANCH_B (IR
); }
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
);
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
);
1040 JMP_PC (dst
& 0177777);
1042 break; /* end JSR */
1047 if (dstreg
) R
[dstspec
] = 0;
1048 else WriteW (0, GeteaW (dstspec
));
1052 dst
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1053 dst
= dst
^ 0177777;
1054 N
= GET_SIGN_W (dst
);
1058 if (dstreg
) R
[dstspec
] = dst
;
1059 else PWriteW (dst
, last_pa
);
1063 dst
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1064 dst
= (dst
+ 1) & 0177777;
1065 N
= GET_SIGN_W (dst
);
1067 V
= (dst
== 0100000);
1068 if (dstreg
) R
[dstspec
] = dst
;
1069 else PWriteW (dst
, last_pa
);
1073 dst
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1074 dst
= (dst
- 1) & 0177777;
1075 N
= GET_SIGN_W (dst
);
1077 V
= (dst
== 077777);
1078 if (dstreg
) R
[dstspec
] = dst
;
1079 else PWriteW (dst
, last_pa
);
1083 dst
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1084 dst
= (-dst
) & 0177777;
1085 N
= GET_SIGN_W (dst
);
1087 V
= (dst
== 0100000);
1089 if (dstreg
) R
[dstspec
] = dst
;
1090 else PWriteW (dst
, last_pa
);
1094 dst
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1095 dst
= (dst
+ C
) & 0177777;
1096 N
= GET_SIGN_W (dst
);
1098 V
= (C
&& (dst
== 0100000));
1100 if (dstreg
) R
[dstspec
] = dst
;
1101 else PWriteW (dst
, last_pa
);
1105 dst
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1106 dst
= (dst
- C
) & 0177777;
1107 N
= GET_SIGN_W (dst
);
1109 V
= (C
&& (dst
== 077777));
1110 C
= (C
&& (dst
== 0177777));
1111 if (dstreg
) R
[dstspec
] = dst
;
1112 else PWriteW (dst
, last_pa
);
1116 dst
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1117 N
= GET_SIGN_W (dst
);
1123 src
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1124 dst
= (src
>> 1) | (C
<< 15);
1125 N
= GET_SIGN_W (dst
);
1129 if (dstreg
) R
[dstspec
] = dst
;
1130 else PWriteW (dst
, last_pa
);
1134 src
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1135 dst
= ((src
<< 1) | C
) & 0177777;
1136 N
= GET_SIGN_W (dst
);
1138 C
= GET_SIGN_W (src
);
1140 if (dstreg
) R
[dstspec
] = dst
;
1141 else PWriteW (dst
, last_pa
);
1145 src
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1146 dst
= (src
>> 1) | (src
& 0100000);
1147 N
= GET_SIGN_W (dst
);
1151 if (dstreg
) R
[dstspec
] = dst
;
1152 else PWriteW (dst
, last_pa
);
1156 src
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1157 dst
= (src
<< 1) & 0177777;
1158 N
= GET_SIGN_W (dst
);
1160 C
= GET_SIGN_W (src
);
1162 if (dstreg
) R
[dstspec
] = dst
;
1163 else PWriteW (dst
, last_pa
);
1167 - MxPI must mask GeteaW returned address to force ispace
1168 - MxPI must set MMR1 for SP recovery in case of fault
1171 case 064: /* MARK */
1172 if (CPUT (HAS_MARK
)) {
1173 i
= (PC
+ dstspec
+ dstspec
) & 0177777;
1175 R
[5] = ReadW (i
| dsenable
);
1176 SP
= (i
+ 2) & 0177777;
1178 else setTRAP (TRAP_ILL
);
1181 case 065: /* MFPI */
1182 if (CPUT (HAS_MXPY
)) {
1184 if ((dstspec
== 6) && (cm
!= pm
)) dst
= STACKFILE
[pm
];
1185 else dst
= R
[dstspec
];
1188 i
= ((cm
== pm
) && (cm
== MD_USR
))? calc_ds (pm
): calc_is (pm
);
1189 dst
= ReadW ((GeteaW (dstspec
) & 0177777) | i
);
1191 N
= GET_SIGN_W (dst
);
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
);
1200 else setTRAP (TRAP_ILL
);
1203 case 066: /* MTPI */
1204 if (CPUT (HAS_MXPY
)) {
1205 dst
= ReadW (SP
| dsenable
);
1206 N
= GET_SIGN_W (dst
);
1209 SP
= (SP
+ 2) & 0177777;
1210 if (update_MM
) MMR1
= 026;
1212 if ((dstspec
== 6) && (cm
!= pm
)) STACKFILE
[pm
] = dst
;
1213 else R
[dstspec
] = dst
;
1215 else WriteW (dst
, (GeteaW (dstspec
) & 0177777) | calc_is (pm
));
1217 else setTRAP (TRAP_ILL
);
1221 if (CPUT (HAS_SXS
)) {
1222 dst
= N
? 0177777: 0;
1225 if (dstreg
) R
[dstspec
] = dst
;
1226 else WriteW (dst
, GeteaW (dstspec
));
1228 else setTRAP (TRAP_ILL
);
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 */
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;
1243 isenable
= calc_is (cm
);
1244 dsenable
= calc_ds (cm
);
1245 PC
= ReadW (010 | isenable
);
1247 else setTRAP (TRAP_ILL
);
1250 case 072: /* TSTSET */
1251 if (CPUT (HAS_TSWLK
) && !dstreg
) {
1252 dst
= ReadMW (GeteaW (dstspec
));
1253 N
= GET_SIGN_W (dst
);
1257 R
[0] = dst
; /* R[0] <- dst */
1258 PWriteW (R
[0] | 1, last_pa
); /* dst <- R[0] | 1 */
1260 else setTRAP (TRAP_ILL
);
1263 case 073: /* WRTLCK */
1264 if (CPUT (HAS_TSWLK
) && !dstreg
) {
1265 N
= GET_SIGN_W (R
[0]);
1268 WriteW (R
[0], GeteaW (dstspec
));
1270 else setTRAP (TRAP_ILL
);
1276 } /* end switch SOPs */
1277 break; /* end case 000 */
1279 /* Opcodes 01 - 06: double operand word instructions
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.
1286 Add: v = [sign (src) = sign (src2)] and [sign (src) != sign (result)]
1287 Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)]
1291 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1292 ea
= GeteaW (dstspec
);
1296 dst
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1297 if (!dstreg
) ea
= GeteaW (dstspec
);
1299 N
= GET_SIGN_W (dst
);
1302 if (dstreg
) R
[dstspec
] = dst
;
1303 else WriteW (dst
, ea
);
1307 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1308 src2
= ReadW (GeteaW (dstspec
));
1312 src
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1313 src2
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1315 dst
= (src
- src2
) & 0177777;
1316 N
= GET_SIGN_W (dst
);
1318 V
= GET_SIGN_W ((src
^ src2
) & (~src2
^ dst
));
1323 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1324 src2
= ReadW (GeteaW (dstspec
));
1328 src
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1329 src2
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1332 N
= GET_SIGN_W (dst
);
1338 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1339 src2
= ReadMW (GeteaW (dstspec
));
1343 src
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1344 src2
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1347 N
= GET_SIGN_W (dst
);
1350 if (dstreg
) R
[dstspec
] = dst
;
1351 else PWriteW (dst
, last_pa
);
1355 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1356 src2
= ReadMW (GeteaW (dstspec
));
1360 src
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1361 src2
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1364 N
= GET_SIGN_W (dst
);
1367 if (dstreg
) R
[dstspec
] = dst
;
1368 else PWriteW (dst
, last_pa
);
1372 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1373 src2
= ReadMW (GeteaW (dstspec
));
1377 src
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1378 src2
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1380 dst
= (src2
+ src
) & 0177777;
1381 N
= GET_SIGN_W (dst
);
1383 V
= GET_SIGN_W ((~src
^ src2
) & (src
^ dst
));
1385 if (dstreg
) R
[dstspec
] = dst
;
1386 else PWriteW (dst
, last_pa
);
1389 /* Opcode 07: EIS, FIS, CIS
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:
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.
1407 srcspec
= srcspec
& 07;
1408 switch ((IR
>> 9) & 07) { /* decode IR<11:9> */
1411 if (!CPUO (OPT_EIS
)) {
1415 src2
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1417 if (GET_SIGN_W (src2
)) src2
= src2
| ~077777;
1418 if (GET_SIGN_W (src
)) src
= src
| ~077777;
1420 R
[srcspec
] = (dst
>> 16) & 0177777;
1421 R
[srcspec
| 1] = dst
& 0177777;
1425 C
= ((dst
> 077777) || (dst
< -0100000));
1429 if (!CPUO (OPT_EIS
)) {
1433 src2
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1434 src
= (((uint32
) R
[srcspec
]) << 16) | R
[srcspec
| 1];
1436 N
= 0; /* J11,11/70 compat */
1437 Z
= V
= C
= 1; /* N = 0, Z = 1 */
1440 if ((src
== 020000000000) && (src2
== 0177777)) {
1441 V
= 1; /* J11,11/70 compat */
1442 N
= Z
= C
= 0; /* N = Z = 0 */
1445 if (GET_SIGN_W (src2
)) src2
= src2
| ~077777;
1446 if (GET_SIGN_W (R
[srcspec
])) src
= src
| ~017777777777;
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 */
1454 R
[srcspec
] = dst
& 0177777;
1455 R
[srcspec
| 1] = (src
- (src2
* dst
)) & 0177777;
1461 if (!CPUO (OPT_EIS
)) {
1465 src2
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1467 sign
= GET_SIGN_W (R
[srcspec
]);
1468 src
= sign
? R
[srcspec
] | ~077777: R
[srcspec
];
1469 if (src2
== 0) { /* [0] */
1473 else if (src2
<= 15) { /* [1,15] */
1475 i
= (src
>> (16 - src2
)) & 0177777;
1476 V
= (i
!= ((dst
& 0100000)? 0177777: 0));
1479 else if (src2
<= 31) { /* [16,31] */
1482 C
= (src
<< (src2
- 16)) & 1;
1484 else if (src2
== 32) { /* [32] = -32 */
1489 else { /* [33,63] = -31,-1 */
1490 dst
= (src
>> (64 - src2
)) | (-sign
<< (src2
- 32));
1492 C
= ((src
>> (63 - src2
)) & 1);
1494 dst
= R
[srcspec
] = dst
& 0177777;
1495 N
= GET_SIGN_W (dst
);
1500 if (!CPUO (OPT_EIS
)) {
1504 src2
= dstreg
? R
[dstspec
]: ReadW (GeteaW (dstspec
));
1506 sign
= GET_SIGN_W (R
[srcspec
]);
1507 src
= (((uint32
) R
[srcspec
]) << 16) | R
[srcspec
| 1];
1508 if (src2
== 0) { /* [0] */
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));
1518 else if (src2
== 32) { /* [32] = -32 */
1523 else { /* [33,63] = -31,-1 */
1524 dst
= (src
>> (64 - src2
)) | (-sign
<< (src2
- 32));
1526 C
= ((src
>> (63 - src2
)) & 1);
1528 i
= R
[srcspec
] = (dst
>> 16) & 0177777;
1529 dst
= R
[srcspec
| 1] = dst
& 0177777;
1531 Z
= GET_Z (dst
| i
);
1535 if (CPUT (HAS_SXS
)) {
1536 if (CPUT (IS_SDSD
) && !dstreg
) { /* R,not R */
1537 src2
= ReadMW (GeteaW (dstspec
));
1542 src2
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1545 N
= GET_SIGN_W (dst
);
1548 if (dstreg
) R
[dstspec
] = dst
;
1549 else PWriteW (dst
, last_pa
);
1551 else setTRAP (TRAP_ILL
);
1555 if (CPUO (OPT_FIS
)) fis11 (IR
);
1556 else setTRAP (TRAP_ILL
);
1560 if (CPUT (CPUT_60
) && (cm
== MD_KER
) && /* 11/60 MED? */
1562 ReadE (PC
| isenable
); /* read immediate */
1563 PC
= (PC
+ 2) & 0177777;
1565 else if (CPUO (OPT_CIS
)) /* CIS option? */
1566 reason
= cis11 (IR
);
1567 else setTRAP (TRAP_ILL
);
1571 if (CPUT (HAS_SXS
)) {
1572 R
[srcspec
] = (R
[srcspec
] - 1) & 0177777;
1574 JMP_PC ((PC
- dstspec
- dstspec
) & 0177777);
1577 else setTRAP (TRAP_ILL
);
1579 } /* end switch EIS */
1580 break; /* end case 007 */
1582 /* Opcode 10: branches, traps, SOPs */
1585 switch ((IR
>> 6) & 077) { /* decode IR<11:6> */
1587 case 000: case 001: /* BPL */
1588 if (N
== 0) { BRANCH_F (IR
); }
1591 case 002: case 003: /* BPL */
1592 if (N
== 0) { BRANCH_B (IR
); }
1595 case 004: case 005: /* BMI */
1596 if (N
) { BRANCH_F (IR
); }
1599 case 006: case 007: /* BMI */
1600 if (N
) { BRANCH_B (IR
); }
1603 case 010: case 011: /* BHI */
1604 if ((C
| Z
) == 0) { BRANCH_F (IR
); }
1607 case 012: case 013: /* BHI */
1608 if ((C
| Z
) == 0) { BRANCH_B (IR
); }
1611 case 014: case 015: /* BLOS */
1612 if (C
| Z
) { BRANCH_F (IR
); }
1615 case 016: case 017: /* BLOS */
1616 if (C
| Z
) { BRANCH_B (IR
); }
1619 case 020: case 021: /* BVC */
1620 if (V
== 0) { BRANCH_F (IR
); }
1623 case 022: case 023: /* BVC */
1624 if (V
== 0) { BRANCH_B (IR
); }
1627 case 024: case 025: /* BVS */
1628 if (V
) { BRANCH_F (IR
); }
1631 case 026: case 027: /* BVS */
1632 if (V
) { BRANCH_B (IR
); }
1635 case 030: case 031: /* BCC */
1636 if (C
== 0) { BRANCH_F (IR
); }
1639 case 032: case 033: /* BCC */
1640 if (C
== 0) { BRANCH_B (IR
); }
1643 case 034: case 035: /* BCS */
1644 if (C
) { BRANCH_F (IR
); }
1647 case 036: case 037: /* BCS */
1648 if (C
) { BRANCH_B (IR
); }
1651 case 040: case 041: case 042: case 043: /* EMT */
1655 case 044: case 045: case 046: case 047: /* TRAP */
1656 setTRAP (TRAP_TRAP
);
1659 case 050: /* CLRB */
1662 if (dstreg
) R
[dstspec
] = R
[dstspec
] & 0177400;
1663 else WriteB (0, GeteaB (dstspec
));
1666 case 051: /* COMB */
1667 dst
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1668 dst
= (dst
^ 0377) & 0377;
1669 N
= GET_SIGN_B (dst
);
1673 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1674 else PWriteB (dst
, last_pa
);
1677 case 052: /* INCB */
1678 dst
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1679 dst
= (dst
+ 1) & 0377;
1680 N
= GET_SIGN_B (dst
);
1683 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1684 else PWriteB (dst
, last_pa
);
1687 case 053: /* DECB */
1688 dst
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1689 dst
= (dst
- 1) & 0377;
1690 N
= GET_SIGN_B (dst
);
1693 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1694 else PWriteB (dst
, last_pa
);
1697 case 054: /* NEGB */
1698 dst
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1699 dst
= (-dst
) & 0377;
1700 N
= GET_SIGN_B (dst
);
1704 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1705 else PWriteB (dst
, last_pa
);
1708 case 055: /* ADCB */
1709 dst
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1710 dst
= (dst
+ C
) & 0377;
1711 N
= GET_SIGN_B (dst
);
1713 V
= (C
&& (dst
== 0200));
1715 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1716 else PWriteB (dst
, last_pa
);
1719 case 056: /* SBCB */
1720 dst
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1721 dst
= (dst
- C
) & 0377;
1722 N
= GET_SIGN_B (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
);
1730 case 057: /* TSTB */
1731 dst
= dstreg
? R
[dstspec
] & 0377: ReadB (GeteaB (dstspec
));
1732 N
= GET_SIGN_B (dst
);
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
);
1744 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1745 else PWriteB (dst
, last_pa
);
1748 case 061: /* ROLB */
1749 src
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1750 dst
= ((src
<< 1) | C
) & 0377;
1751 N
= GET_SIGN_B (dst
);
1753 C
= GET_SIGN_B (src
& 0377);
1755 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1756 else PWriteB (dst
, last_pa
);
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
);
1766 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1767 else PWriteB (dst
, last_pa
);
1770 case 063: /* ASLB */
1771 src
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1772 dst
= (src
<< 1) & 0377;
1773 N
= GET_SIGN_B (dst
);
1775 C
= GET_SIGN_B (src
& 0377);
1777 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1778 else PWriteB (dst
, last_pa
);
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
1786 case 064: /* MTPS */
1787 if (CPUT (HAS_MXPS
)) {
1788 dst
= dstreg
? R
[dstspec
]: ReadB (GeteaB (dstspec
));
1790 ipl
= (dst
>> PSW_V_IPL
) & 07;
1791 trap_req
= calc_ints (ipl
, trap_req
);
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;
1798 else setTRAP (TRAP_ILL
);
1801 case 065: /* MFPD */
1802 if (CPUT (HAS_MXPY
)) {
1804 if ((dstspec
== 6) && (cm
!= pm
)) dst
= STACKFILE
[pm
];
1805 else dst
= R
[dstspec
];
1807 else dst
= ReadW ((GeteaW (dstspec
) & 0177777) | calc_ds (pm
));
1808 N
= GET_SIGN_W (dst
);
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
);
1817 else setTRAP (TRAP_ILL
);
1820 case 066: /* MTPD */
1821 if (CPUT (HAS_MXPY
)) {
1822 dst
= ReadW (SP
| dsenable
);
1823 N
= GET_SIGN_W (dst
);
1826 SP
= (SP
+ 2) & 0177777;
1827 if (update_MM
) MMR1
= 026;
1829 if ((dstspec
== 6) && (cm
!= pm
)) STACKFILE
[pm
] = dst
;
1830 else R
[dstspec
] = dst
;
1832 else WriteW (dst
, (GeteaW (dstspec
) & 0177777) | calc_ds (pm
));
1834 else setTRAP (TRAP_ILL
);
1837 case 067: /* MFPS */
1838 if (CPUT (HAS_MXPS
)) {
1839 dst
= get_PSW () & 0377;
1840 N
= GET_SIGN_B (dst
);
1843 if (dstreg
) R
[dstspec
] = (dst
& 0200)? 0177400 | dst
: dst
;
1844 else WriteB (dst
, GeteaB (dstspec
));
1846 else setTRAP (TRAP_ILL
);
1852 } /* end switch SOPs */
1853 break; /* end case 010 */
1855 /* Opcodes 11 - 16: double operand byte instructions
1857 Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)]
1858 Sub: v = [sign (src) != sign (src2)] and [sign (src) = sign (result)]
1861 case 011: /* MOVB */
1862 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1863 ea
= GeteaB (dstspec
);
1864 dst
= R
[srcspec
] & 0377;
1867 dst
= srcreg
? R
[srcspec
] & 0377: ReadB (GeteaB (srcspec
));
1868 if (!dstreg
) ea
= GeteaB (dstspec
);
1870 N
= GET_SIGN_B (dst
);
1873 if (dstreg
) R
[dstspec
] = (dst
& 0200)? 0177400 | dst
: dst
;
1874 else WriteB (dst
, ea
);
1877 case 012: /* CMPB */
1878 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1879 src2
= ReadB (GeteaB (dstspec
));
1880 src
= R
[srcspec
] & 0377;
1883 src
= srcreg
? R
[srcspec
] & 0377: ReadB (GeteaB (srcspec
));
1884 src2
= dstreg
? R
[dstspec
] & 0377: ReadB (GeteaB (dstspec
));
1886 dst
= (src
- src2
) & 0377;
1887 N
= GET_SIGN_B (dst
);
1889 V
= GET_SIGN_B ((src
^ src2
) & (~src2
^ dst
));
1893 case 013: /* BITB */
1894 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1895 src2
= ReadB (GeteaB (dstspec
));
1896 src
= R
[srcspec
] & 0377;
1899 src
= srcreg
? R
[srcspec
] & 0377: ReadB (GeteaB (srcspec
));
1900 src2
= dstreg
? R
[dstspec
] & 0377: ReadB (GeteaB (dstspec
));
1902 dst
= (src2
& src
) & 0377;
1903 N
= GET_SIGN_B (dst
);
1908 case 014: /* BICB */
1909 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1910 src2
= ReadMB (GeteaB (dstspec
));
1914 src
= srcreg
? R
[srcspec
]: ReadB (GeteaB (srcspec
));
1915 src2
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1917 dst
= (src2
& ~src
) & 0377;
1918 N
= GET_SIGN_B (dst
);
1921 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1922 else PWriteB (dst
, last_pa
);
1925 case 015: /* BISB */
1926 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1927 src2
= ReadMB (GeteaB (dstspec
));
1931 src
= srcreg
? R
[srcspec
]: ReadB (GeteaB (srcspec
));
1932 src2
= dstreg
? R
[dstspec
]: ReadMB (GeteaB (dstspec
));
1934 dst
= (src2
| src
) & 0377;
1935 N
= GET_SIGN_B (dst
);
1938 if (dstreg
) R
[dstspec
] = (R
[dstspec
] & 0177400) | dst
;
1939 else PWriteB (dst
, last_pa
);
1943 if (CPUT (IS_SDSD
) && srcreg
&& !dstreg
) { /* R,not R */
1944 src2
= ReadMW (GeteaW (dstspec
));
1948 src
= srcreg
? R
[srcspec
]: ReadW (GeteaW (srcspec
));
1949 src2
= dstreg
? R
[dstspec
]: ReadMW (GeteaW (dstspec
));
1951 dst
= (src2
- src
) & 0177777;
1952 N
= GET_SIGN_W (dst
);
1954 V
= GET_SIGN_W ((src
^ src2
) & (~src
^ dst
));
1956 if (dstreg
) R
[dstspec
] = dst
;
1957 else PWriteW (dst
, last_pa
);
1960 /* Opcode 17: floating point */
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 */
1969 /* Simulation halted */
1972 for (i
= 0; i
< 6; i
++) REGFILE
[i
][rs
] = R
[i
];
1974 saved_PC
= PC
& 0177777;
1975 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
1976 set_r_display (rs
, cm
);
1980 /* Effective address calculations
1983 spec = specifier <5:0>
1985 ea = effective address
1986 <15:0> = virtual address
1987 <16> = instruction/data data space
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:
1996 Mode Index ref Indirect ref Direct ref
1998 17 na na instruction
2000 27 na na instruction
2002 37 na instruction (absolute) data
2004 47 na na instruction
2006 57 na instruction data
2007 60..67 instruction na data
2008 70..77 instruction data data
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.
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
2026 /* Effective address calculation for words */
2028 int32
GeteaW (int32 spec
)
2032 reg
= spec
& 07; /* register number */
2033 ds
= (reg
== 7)? isenable
: dsenable
; /* dspace if not PC */
2034 switch (spec
>> 3) { /* decode spec<5:3> */
2036 default: /* can't get here */
2038 return (R
[reg
] | ds
);
2041 R
[reg
] = ((adr
= R
[reg
]) + 2) & 0177777;
2042 if (update_MM
) MMR1
= calc_MMR1 (020 | reg
);
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
);
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
);
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
);
2067 adr
= ReadW (PC
| isenable
);
2068 PC
= (PC
+ 2) & 0177777;
2069 return (((R
[reg
] + adr
) & 0177777) | dsenable
);
2072 adr
= ReadW (PC
| isenable
);
2073 PC
= (PC
+ 2) & 0177777;
2074 adr
= ReadW (((R
[reg
] + adr
) & 0177777) | dsenable
);
2075 return (adr
| dsenable
);
2079 /* Effective address calculation for bytes */
2081 int32
GeteaB (int32 spec
)
2083 int32 adr
, reg
, ds
, delta
;
2085 reg
= spec
& 07; /* reg number */
2086 ds
= (reg
== 7)? isenable
: dsenable
; /* dspace if not PC */
2087 switch (spec
>> 3) { /* decode spec<5:3> */
2089 default: /* can't get here */
2091 return (R
[reg
] | ds
);
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
);
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
);
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
);
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
);
2122 adr
= ReadW (PC
| isenable
);
2123 PC
= (PC
+ 2) & 0177777;
2124 return (((R
[reg
] + adr
) & 0177777) | dsenable
);
2127 adr
= ReadW (PC
| isenable
);
2128 PC
= (PC
+ 2) & 0177777;
2129 adr
= ReadW (((R
[reg
] + adr
) & 0177777) | dsenable
);
2130 return (adr
| dsenable
);
2134 /* Read byte and word routines, read only and read-modify-write versions
2137 va = virtual address, <18:16> = mode, I/D space
2139 data = data read from memory or I/O space
2142 int32
ReadE (int32 va
)
2146 if ((va
& 1) && CPUT (HAS_ODD
)) { /* odd address? */
2147 setCPUERR (CPUE_ODD
);
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
);
2157 if (iopageR (&data
, pa
, READ
) != SCPE_OK
) { /* invalid I/O addr? */
2158 setCPUERR (CPUE_TMO
);
2164 int32
ReadW (int32 va
)
2168 if ((va
& 1) && CPUT (HAS_ODD
)) { /* odd address? */
2169 setCPUERR (CPUE_ODD
);
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
);
2178 if (iopageR (&data
, pa
, READ
) != SCPE_OK
) { /* invalid I/O addr? */
2179 setCPUERR (CPUE_TMO
);
2185 int32
ReadB (int32 va
)
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
);
2195 if (iopageR (&data
, pa
, READ
) != SCPE_OK
) { /* invalid I/O addr? */
2196 setCPUERR (CPUE_TMO
);
2199 return ((va
& 1)? data
>> 8: data
) & 0377;
2202 int32
ReadMW (int32 va
)
2206 if ((va
& 1) && CPUT (HAS_ODD
)) { /* odd address? */
2207 setCPUERR (CPUE_ODD
);
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
);
2216 if (iopageR (&data
, last_pa
, READ
) != SCPE_OK
) { /* invalid I/O addr? */
2217 setCPUERR (CPUE_TMO
);
2223 int32
ReadMB (int32 va
)
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
);
2234 if (iopageR (&data
, last_pa
, READ
) != SCPE_OK
) { /* invalid I/O addr? */
2235 setCPUERR (CPUE_TMO
);
2238 return ((va
& 1)? data
>> 8: data
) & 0377;
2241 /* Write byte and word routines
2244 data = data to be written
2245 va = virtual address, <18:16> = mode, I/D space, or
2246 pa = physical address
2250 void WriteW (int32 data
, int32 va
)
2254 if ((va
& 1) && CPUT (HAS_ODD
)) { /* odd address? */
2255 setCPUERR (CPUE_ODD
);
2258 pa
= relocW (va
); /* relocate */
2259 if (ADDR_IS_MEM (pa
)) { /* memory address? */
2263 if (pa
< IOPAGEBASE
) { /* not I/O address? */
2264 setCPUERR (CPUE_NXM
);
2267 if (iopageW (data
, pa
, WRITE
) != SCPE_OK
) { /* invalid I/O addr? */
2268 setCPUERR (CPUE_TMO
);
2274 void WriteB (int32 data
, int32 va
)
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
;
2284 if (pa
< IOPAGEBASE
) { /* not I/O address? */
2285 setCPUERR (CPUE_NXM
);
2288 if (iopageW (data
, pa
, WRITEB
) != SCPE_OK
) { /* invalid I/O addr? */
2289 setCPUERR (CPUE_TMO
);
2295 void PWriteW (int32 data
, int32 pa
)
2297 if (ADDR_IS_MEM (pa
)) { /* memory address? */
2301 if (pa
< IOPAGEBASE
) { /* not I/O address? */
2302 setCPUERR (CPUE_NXM
);
2305 if (iopageW (data
, pa
, WRITE
) != SCPE_OK
) { /* invalid I/O addr? */
2306 setCPUERR (CPUE_TMO
);
2312 void PWriteB (int32 data
, int32 pa
)
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
;
2319 if (pa
< IOPAGEBASE
) { /* not I/O address? */
2320 setCPUERR (CPUE_NXM
);
2323 if (iopageW (data
, pa
, WRITEB
) != SCPE_OK
) { /* invalid I/O addr? */
2324 setCPUERR (CPUE_TMO
);
2330 /* Relocate virtual address, read access
2333 va = virtual address, <18:16> = mode, I/D space
2335 pa = physical address
2336 On aborts, this routine aborts back to the top level simulator
2337 with an appropriate trap code.
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
2346 int32
relocR (int32 va
)
2348 int32 apridx
, apr
, pa
;
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) {
2360 if (pa
>= 0760000) pa
= 017000000 | pa
;
2364 pa
= va
& 0177777; /* mmgt off */
2365 if (pa
>= 0160000) pa
= 017600000 | pa
;
2370 /* Read relocation, access control field != read only or read/write
2372 ACF value 11/45,11/70 all others
2384 void relocR_test (int32 va
, int32 apridx
)
2388 err
= 0; /* init status */
2389 apr
= APRFILE
[apridx
]; /* get APR */
2390 switch (apr
& PDR_ACF
) { /* case on ACF */
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 */
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 */
2407 case 2: case 5: case 6: /* readable */
2408 return; /* continue */
2411 if (PLF_test (va
, apr
)) err
= err
| MMR0_PL
; /* pg lnt error? */
2412 reloc_abort (err
, apridx
);
2416 t_bool
PLF_test (int32 va
, int32 apr
)
2418 int32 dbn
= va
& VA_BN
; /* extr block num */
2419 int32 plf
= (apr
& PDR_PLF
) >> 2; /* extr page length */
2421 return ((apr
& PDR_ED
)? (dbn
< plf
): (dbn
> plf
)); /* pg lnt error? */
2424 void reloc_abort (int32 err
, int32 apridx
)
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 */
2434 /* Relocate virtual address, write access
2437 va = virtual address, <18:16> = mode, I/D space
2439 pa = physical address
2440 On aborts, this routine aborts back to the top level simulator
2441 with an appropriate trap code.
2444 - The 'normal' write code (110) is done in-line; all others
2446 - APRFILE[UNUSED] is all zeroes, forcing non-resident abort
2447 - Aborts must update MMR0<15:13,6:1> if updating is enabled
2450 int32
relocW (int32 va
)
2452 int32 apridx
, apr
, pa
;
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) {
2465 if (pa
>= 0760000) pa
= 017000000 | pa
;
2469 pa
= va
& 0177777; /* mmgt off */
2470 if (pa
>= 0160000) pa
= 017600000 | pa
;
2475 /* Write relocation, access control field != read/write
2477 ACF value 11/45,11/70 all others
2489 void relocW_test (int32 va
, int32 apridx
)
2493 err
= 0; /* init status */
2494 apr
= APRFILE
[apridx
]; /* get APR */
2495 switch (apr
& PDR_ACF
) { /* case on ACF */
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 */
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 */
2512 case 1: case 2: /* read only */
2513 err
= MMR0_RO
; /* MMR0 status */
2516 case 6: /* read/write */
2517 return; /* continue */
2519 if (PLF_test (va
, apr
)) err
= err
| MMR0_PL
; /* pg lnt error? */
2520 reloc_abort (err
, apridx
);
2524 /* Relocate virtual address, console access
2527 va = virtual address
2530 pa = physical address
2531 On aborts, this routine returns MAXMEMSIZE
2534 int32
relocC (int32 va
, int32 sw
)
2536 int32 mode
, dbn
, plf
, apridx
, apr
, pa
;
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) {
2554 if (pa
>= 0760000) pa
= 017000000 | pa
;
2558 pa
= va
& 0177777; /* mmgt off */
2559 if (pa
>= 0160000) pa
= 017600000 | pa
;
2564 /* Memory management registers
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
2572 t_stat
MMR012_rd (int32
*data
, int32 pa
, int32 access
)
2574 switch ((pa
>> 1) & 3) { /* decode pa<2:1> */
2580 *data
= MMR0
& cpu_tab
[cpu_model
].mm0
;
2590 } /* end switch pa */
2595 t_stat
MMR012_wr (int32 data
, int32 pa
, int32 access
)
2597 switch ((pa
>> 1) & 3) { /* decode pa<2:1> */
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
);
2609 default: /* MMR1, MMR2 */
2611 } /* end switch pa */
2614 t_stat
MMR3_rd (int32
*data
, int32 pa
, int32 access
) /* MMR3 */
2616 *data
= MMR3
& cpu_tab
[cpu_model
].mm3
;
2620 t_stat
MMR3_wr (int32 data
, int32 pa
, int32 access
) /* MMR3 */
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
);
2629 /* PARs and PDRs. These are grouped in I/O space as follows:
2631 17772200 - 17772276 supervisor block
2632 17772300 - 17772376 kernel block
2633 17777600 - 17777676 user block
2635 Within each block, the subblocks are I PDR's, D PDR's, I PAR's, D PAR's
2637 Thus, the algorithm for converting between I/O space addresses and
2638 APRFILE indices is as follows:
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>
2644 Note: the A,W bits are read only; they are cleared by any write to an APR
2647 t_stat
APR_rd (int32
*data
, int32 pa
, int32 access
)
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
;
2660 t_stat
APR_wr (int32 data
, int32 pa
, int32 access
)
2662 int32 left
, idx
, curr
;
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
);
2679 /* Explicit PSW read */
2681 t_stat
PSW_rd (int32
*data
, int32 pa
, int32 access
)
2683 if (access
== READC
) *data
= PSW
;
2684 else *data
= get_PSW ();
2688 /* Assemble PSW from pieces */
2690 int32
get_PSW (void)
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
);
2699 /* Explicit PSW write - T-bit may be protected */
2701 t_stat
PSW_wr (int32 data
, int32 pa
, int32 access
)
2703 int32 i
, curr
, oldrs
;
2705 if (access
== WRITEC
) { /* console access? */
2706 PSW
= data
& cpu_tab
[cpu_model
].psw
;
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
];
2723 SP
= STACKFILE
[cm
]; /* switch SP */
2724 isenable
= calc_is (cm
);
2725 dsenable
= calc_ds (cm
);
2729 /* Store pieces of new PSW - implements RTI/RTT protection */
2731 void put_PSW (int32 val
, t_bool prot
)
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);
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;
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;
2754 /* PIRQ write routine */
2756 void put_PIRQ (int32 val
)
2760 PIRQ
= val
& PIRQ_RW
;
2762 if (PIRQ
& PIRQ_PIR1
) {
2766 else CLR_INT (PIR1
);
2767 if (PIRQ
& PIRQ_PIR2
) {
2771 else CLR_INT (PIR2
);
2772 if (PIRQ
& PIRQ_PIR3
) {
2776 else CLR_INT (PIR3
);
2777 if (PIRQ
& PIRQ_PIR4
) {
2781 else CLR_INT (PIR4
);
2782 if (PIRQ
& PIRQ_PIR5
) {
2786 else CLR_INT (PIR5
);
2787 if (PIRQ
& PIRQ_PIR6
) {
2791 else CLR_INT (PIR6
);
2792 if (PIRQ
& PIRQ_PIR7
) {
2796 else CLR_INT (PIR7
);
2801 /* Stack trap routine */
2803 void set_stack_trap (int32 adr
)
2805 if (CPUT (HAS_STKLF
)) { /* fixed stack? */
2806 setTRAP (TRAP_YEL
); /* always yellow trap */
2807 setCPUERR (CPUE_YEL
);
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
);
2814 else { /* red zone abort */
2815 setCPUERR (CPUE_RED
);
2816 STACKFILE
[MD_KER
] = 4;
2821 return; /* no stack limit */
2826 t_stat
cpu_reset (DEVICE
*dptr
)
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
);
2847 /* Memory examine */
2849 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
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
;
2860 if (addr
< MEMSIZE
) {
2861 *vptr
= M
[addr
>> 1] & 0177777;
2864 if (addr
< IOPAGEBASE
) return SCPE_NXM
;
2865 stat
= iopageR (&iodata
, addr
, READC
);
2870 /* Memory deposit */
2872 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
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
;
2879 if (addr
< MEMSIZE
) {
2880 M
[addr
>> 1] = val
& 0177777;
2883 if (addr
< IOPAGEBASE
) return SCPE_NXM
;
2884 return iopageW ((int32
) val
, addr
, WRITEC
);
2887 /* Set R, SP register display addresses */
2889 void set_r_display (int32 rs
, int32 cm
)
2891 extern REG
*find_reg (char *cptr
, char **optr
, DEVICE
*dptr
);
2895 rptr
= find_reg ("R0", NULL
, &cpu_dev
);
2896 if (rptr
== NULL
) return;
2897 for (i
= 0; i
< 6; i
++, rptr
++) rptr
->loc
= (void *) ®FILE
[i
][rs
];
2898 rptr
->loc
= (void *) &STACKFILE
[cm
];
2904 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2910 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].pc
= 0;
2914 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
2915 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
2923 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
2924 if (hst
== NULL
) return SCPE_MEM
;
2932 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2934 int32 j
, k
, di
, lnt
, ir
;
2935 char *cptr
= (char *) desc
;
2936 t_value sim_eval
[HIST_ILNT
];
2939 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
2940 UNIT
*uptr
, int32 sw
);
2942 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
2944 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
2945 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
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? */
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 */
2973 /* Virtual address translation */
2975 t_stat
cpu_show_virt (FILE *of
, UNIT
*uptr
, int32 val
, void *desc
)
2978 char *cptr
= (char *) desc
;
2982 va
= (uint32
) get_uint (cptr
, 8, VAMASK
, &r
);
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
);
2991 fprintf (of
, "Invalid argument\n");