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