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