First Commit of my working state
[simh.git] / SDS / sds_cpu.c
CommitLineData
196ba1fc
PH
1/* sds_cpu.c: SDS 940 CPU simulator\r
2\r
3 Copyright (c) 2001-2007, 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 central processor\r
27 rtc real time clock\r
28\r
29 28-Apr-07 RMS Removed clock initialization\r
30 29-Dec-06 RMS Fixed breakpoint variable declarations\r
31 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
32 07-Nov-04 RMS Added instruction history\r
33 01-Mar-03 RMS Added SET/SHOW RTC FREQ support\r
34\r
35 The system state for the SDS 940 is:\r
36\r
37 A<0:23> A register\r
38 B<0:23> B register\r
39 X<0:23> X (index) register\r
40 OV overflow indicator\r
41 P<0:13> program counter\r
42 nml_mode compatible (1) vs 940 (0) mode\r
43 usr_mode user (1) vs monitor (0) mode\r
44 RL1<0:23> user map low\r
45 RL2<0:23> user map high\r
46 RL4<12:23> monitor map high\r
47 EM2<0:2> memory extension, block 2\r
48 EM3<0:2> memory extension, block 3\r
49 bpt breakpoint switches\r
50\r
51 The SDS 940 has three instruction format -- memory reference, register change,\r
52 and I/O. The memory reference format is:\r
53\r
54 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 23\r
55 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
56 | U| X| P| opcode |IN| address |\r
57 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
58\r
59 U force user mode addressing (monitor mode only)\r
60 X indexed\r
61 P opcode is a programmed operator\r
62 opcode opcode\r
63 IN indirect addressing\r
64 address virtual address\r
65\r
66 Virtual addresses are 14b. Depending on the operating mode (normal, user,\r
67 or monitor), virtual addresses are translated to 15b or 16b physical addresses.\r
68\r
69 normal virtual [000000:017777] are unmapped\r
70 EM2 and EM3 extend virtual [020000:037777] to 15b\r
71 user RL1 and RL2 map virtual [000000:037777] to 16b\r
72 monitor virtual [000000:017777] are unmapped\r
73 EM2 extends virtual [020000:027777] to 15b\r
74 RL4 maps virtual [030000:037777] to 16b\r
75\r
76 The register change format is:\r
77\r
78 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 23\r
79 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
80 | 0| m| 0| opcode | microcoded register change instruction |\r
81 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
82\r
83 The I/O format is:\r
84\r
85 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 23\r
86 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
87 | 0|CH| 0| opcode |mode | I/O function |\r
88 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
89\r
90 This routine is the instruction decode routine for the SDS 940.\r
91 It is called from the simulator control program to execute\r
92 instructions in simulated memory, starting at the simulated PC.\r
93 It runs until 'reason' is set non-zero.\r
94\r
95 General notes:\r
96\r
97 1. Reasons to stop. The simulator can be stopped by:\r
98\r
99 HALT instruction\r
100 breakpoint encountered\r
101 invalid instruction and stop_invins flag set\r
102 invalid I/O device and stop_invdev flag set\r
103 invalid I/O operation and stop_inviop flag set\r
104 I/O error in I/O simulator\r
105 indirect loop exceeding limit\r
106 EXU loop exceeding limit\r
107 mapping exception in interrupt or trap instruction\r
108\r
109 2. Interrupts. The interrupt structure consists of the following:\r
110\r
111 int_req interrupt requests (low bit reserved)\r
112 api_lvl active interrupt levels\r
113 int_reqhi highest interrupt request\r
114 api_lvlhi highest interrupt service (0 if none)\r
115 ion interrupt enable\r
116 ion_defer interrupt defer (one instruction)\r
117\r
118 3. Channels. The SDS 940 has a channel-based I/O structure. Each\r
119 channel is represented by a set of registers. Channels test the\r
120 I/O transfer requests from devices, which are kept in xfr_req.\r
121\r
122 4. Non-existent memory. On the SDS 940, reads to non-existent memory\r
123 return zero, and writes are ignored. In the simulator, the\r
124 largest possible memory is instantiated and initialized to zero.\r
125 Thus, only writes need be checked against actual memory size.\r
126\r
127 5. Adding I/O devices. These modules must be modified:\r
128\r
129 sds_defs.h add interrupt, transfer, and alert definitions\r
130 sds_io.c add alert dispatches aldisp\r
131 sds_sys.c add pointer to data structures to sim_devices\r
132*/\r
133\r
134#include "sds_defs.h"\r
135\r
136#define PCQ_SIZE 64 /* must be 2**n */\r
137#define PCQ_MASK (PCQ_SIZE - 1)\r
138#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = pc\r
139#define UNIT_V_MSIZE (UNIT_V_GENIE + 1) /* dummy mask */\r
140#define UNIT_MSIZE (1 << UNIT_V_MSIZE)\r
141\r
142#define HIST_XCT 1 /* instruction */\r
143#define HIST_INT 2 /* interrupt cycle */\r
144#define HIST_TRP 3 /* trap cycle */\r
145#define HIST_MIN 64\r
146#define HIST_MAX 65536\r
147#define HIST_NOEA 0x40000000\r
148\r
149typedef struct {\r
150 uint32 typ;\r
151 uint32 pc;\r
152 uint32 ir;\r
153 uint32 a;\r
154 uint32 b;\r
155 uint32 x;\r
156 uint32 ea;\r
157 } InstHistory;\r
158\r
159uint32 M[MAXMEMSIZE] = { 0 }; /* memory */\r
160uint32 A, B, X; /* registers */\r
161uint32 P; /* program counter */\r
162uint32 OV; /* overflow */\r
163uint32 xfr_req = 0; /* xfr req */\r
164uint32 ion = 0; /* int enable */\r
165uint32 ion_defer = 0; /* int defer */\r
166uint32 int_req = 0; /* int requests */\r
167uint32 int_reqhi = 0; /* highest int request */\r
168uint32 api_lvl = 0; /* api active */\r
169uint32 api_lvlhi = 0; /* highest api active */\r
170t_bool chan_req; /* chan request */\r
171uint32 nml_mode = 1; /* normal mode */\r
172uint32 usr_mode = 0; /* user mode */\r
173uint32 mon_usr_trap = 0; /* mon-user trap */\r
174uint32 EM2 = 2, EM3 = 3; /* extension registers */\r
175uint32 RL1, RL2, RL4; /* relocation maps */\r
176uint32 bpt; /* breakpoint switches */\r
177uint32 alert; /* alert dispatch */\r
178uint32 em2_dyn, em3_dyn; /* extensions, dynamic */\r
179uint32 usr_map[8]; /* user map, dynamic */\r
180uint32 mon_map[8]; /* mon map, dynamic */\r
181int32 ind_lim = 32; /* indirect limit */\r
182int32 exu_lim = 32; /* EXU limit */\r
183int32 cpu_genie = 0; /* Genie flag */\r
184int32 cpu_astop = 0; /* address stop */\r
185int32 stop_invins = 1; /* stop inv inst */\r
186int32 stop_invdev = 1; /* stop inv dev */\r
187int32 stop_inviop = 1; /* stop inv io op */\r
188uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r
189int32 pcq_p = 0; /* PC queue ptr */\r
190REG *pcq_r = NULL; /* PC queue reg ptr */\r
191int32 hst_p = 0; /* history pointer */\r
192int32 hst_lnt = 0; /* history length */\r
193InstHistory *hst = NULL; /* instruction history */\r
194int32 rtc_pie = 0; /* rtc pulse ie */\r
195int32 rtc_tps = 60; /* rtc ticks/sec */\r
196\r
197extern int32 sim_int_char;\r
198extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r
199\r
200t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
201t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
202t_stat cpu_reset (DEVICE *dptr);\r
203t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
204t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);\r
205t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r
206t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r
207t_stat Ea (uint32 wd, uint32 *va);\r
208t_stat EaSh (uint32 wd, uint32 *va);\r
209t_stat Read (uint32 va, uint32 *dat);\r
210t_stat Write (uint32 va, uint32 dat);\r
211void set_dyn_map (void);\r
212uint32 api_findreq (void);\r
213void api_dismiss (void);\r
214uint32 Add24 (uint32 s1, uint32 s2, uint32 cin);\r
215uint32 AddM24 (uint32 s1, uint32 s2);\r
216void Mul48 (uint32 mplc, uint32 mplr);\r
217void Div48 (uint32 dvdh, uint32 dvdl, uint32 dvr);\r
218void RotR48 (uint32 sc);\r
219void ShfR48 (uint32 sc, uint32 sgn);\r
220t_stat one_inst (uint32 inst, uint32 pc, uint32 mode);\r
221void inst_hist (uint32 inst, uint32 pc, uint32 typ);\r
222t_stat rtc_inst (uint32 inst);\r
223t_stat rtc_svc (UNIT *uptr);\r
224t_stat rtc_reset (DEVICE *dptr);\r
225t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);\r
226t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);\r
227\r
228extern t_bool io_init (void);\r
229extern t_stat op_wyim (uint32 inst, uint32 *dat);\r
230extern t_stat op_miwy (uint32 inst, uint32 dat);\r
231extern t_stat op_pin (uint32 *dat);\r
232extern t_stat op_pot (uint32 dat);\r
233extern t_stat op_eomd (uint32 inst);\r
234extern t_stat op_sks (uint32 inst, uint32 *skp);\r
235\r
236/* CPU data structures\r
237\r
238 cpu_dev CPU device descriptor\r
239 cpu_unit CPU unit descriptor\r
240 cpu_reg CPU register list\r
241 cpu_mod CPU modifiers list\r
242*/\r
243\r
244UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r
245\r
246REG cpu_reg[] = {\r
247 { ORDATA (P, P, 14) },\r
248 { ORDATA (A, A, 24) },\r
249 { ORDATA (B, B, 24) },\r
250 { ORDATA (X, X, 24) },\r
251 { FLDATA (OV, OV, 0) },\r
252 { ORDATA (EM2, EM2, 3) },\r
253 { ORDATA (EM3, EM3, 3) },\r
254 { ORDATA (RL1, RL1, 24) },\r
255 { ORDATA (RL2, RL2, 24) },\r
256 { ORDATA (RL4, RL4, 12) },\r
257 { FLDATA (NML, nml_mode, 0) },\r
258 { FLDATA (USR, usr_mode, 0) },\r
259 { FLDATA (MONUSR, mon_usr_trap, 0) },\r
260 { FLDATA (ION, ion, 0) },\r
261 { FLDATA (INTDEF, ion_defer, 0) },\r
262 { ORDATA (INTREQ, int_req, 32) },\r
263 { ORDATA (APILVL, api_lvl, 32) },\r
264 { DRDATA (INTRHI, int_reqhi, 5) },\r
265 { DRDATA (APILHI, api_lvlhi, 5), REG_RO },\r
266 { ORDATA (XFRREQ, xfr_req, 32) },\r
267 { FLDATA (BPT1, bpt, 3) },\r
268 { FLDATA (BPT2, bpt, 2) },\r
269 { FLDATA (BPT3, bpt, 1) },\r
270 { FLDATA (BPT4, bpt, 0) },\r
271 { ORDATA (ALERT, alert, 6) },\r
272 { FLDATA (STOP_INVINS, stop_invins, 0) },\r
273 { FLDATA (STOP_INVDEV, stop_invdev, 0) },\r
274 { FLDATA (STOP_INVIOP, stop_inviop, 0) },\r
275 { DRDATA (INDLIM, ind_lim, 8), REG_NZ+PV_LEFT },\r
276 { DRDATA (EXULIM, exu_lim, 8), REG_NZ+PV_LEFT },\r
277 { BRDATA (PCQ, pcq, 8, 14, PCQ_SIZE), REG_RO+REG_CIRC },\r
278 { ORDATA (PCQP, pcq_p, 6), REG_HRO },\r
279 { ORDATA (WRU, sim_int_char, 8) },\r
280 { NULL }\r
281 };\r
282\r
283MTAB cpu_mod[] = {\r
284 { UNIT_GENIE, 0, "standard peripherals", "SDS", &cpu_set_type },\r
285 { UNIT_GENIE, UNIT_GENIE, "Genie peripherals", "GENIE", &cpu_set_type },\r
286 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },\r
287 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },\r
288 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },\r
289 { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },\r
290 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",\r
291 &cpu_set_hist, &cpu_show_hist },\r
292 { 0 }\r
293 };\r
294\r
295DEVICE cpu_dev = {\r
296 "CPU", &cpu_unit, cpu_reg, cpu_mod,\r
297 1, 8, 16, 1, 8, 24,\r
298 &cpu_ex, &cpu_dep, &cpu_reset,\r
299 NULL, NULL, NULL,\r
300 NULL, 0\r
301 };\r
302\r
303/* Clock data structures\r
304\r
305 rtc_dev RTC device descriptor\r
306 rtc_unit RTC unit\r
307 rtc_reg RTC register list\r
308*/\r
309\r
310UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), 16000 };\r
311\r
312REG rtc_reg[] = {\r
313 { FLDATA (PIE, rtc_pie, 0) },\r
314 { DRDATA (TIME, rtc_unit.wait, 24), REG_NZ + PV_LEFT },\r
315 { DRDATA (TPS, rtc_tps, 8), PV_LEFT + REG_HRO },\r
316 { NULL }\r
317 };\r
318\r
319MTAB rtc_mod[] = {\r
320 { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",\r
321 &rtc_set_freq, NULL, NULL },\r
322 { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",\r
323 &rtc_set_freq, NULL, NULL },\r
324 { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,\r
325 NULL, &rtc_show_freq, NULL },\r
326 { 0 }\r
327 };\r
328\r
329DEVICE rtc_dev = {\r
330 "RTC", &rtc_unit, rtc_reg, rtc_mod,\r
331 1, 8, 8, 1, 8, 8,\r
332 NULL, NULL, &rtc_reset,\r
333 NULL, NULL, NULL\r
334 };\r
335\r
336/* Interrupt tables */\r
337\r
338static const uint32 api_mask[32] = {\r
339 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, 0xFFFFFFF0,\r
340 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, 0xFFFFFF00,\r
341 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, 0xFFFFF000,\r
342 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, 0xFFFF0000,\r
343 0xFFFE0000, 0xFFFC0000, 0xFFF80000, 0xFFF00000,\r
344 0xFFE00000, 0xFFC00000, 0xFF800000, 0xFF000000,\r
345 0xFE000000, 0xFC000000, 0xF8000000, 0xF0000000,\r
346 0xE0000000, 0xC0000000, 0x80000000, 0x00000000\r
347 };\r
348\r
349static const uint32 int_vec[32] = {\r
350 0, 0, 0, 0,\r
351 VEC_FORK, VEC_DRM, VEC_MUXCF,VEC_MUXCO,\r
352 VEC_MUXT, VEC_MUXR, VEC_HEOR, VEC_HZWC,\r
353 VEC_GEOR, VEC_GZWC, VEC_FEOR, VEC_FZWC,\r
354 VEC_EEOR, VEC_EZWC, VEC_DEOR, VEC_DZWC,\r
355 VEC_CEOR, VEC_CZWC, VEC_WEOR, VEC_YEOR,\r
356 VEC_WZWC, VEC_YZWC, VEC_RTCP, VEC_RTCS,\r
357 VEC_IPAR, VEC_CPAR, VEC_PWRF, VEC_PWRO\r
358 };\r
359\r
360t_stat sim_instr (void)\r
361{\r
362extern int32 sim_interval;\r
363uint32 inst, tinst, pa, save_P, save_mode;\r
364t_stat reason, tr;\r
365\r
366/* Restore register state */\r
367\r
368if (io_init ()) return SCPE_STOP; /* init IO; conflict? */\r
369reason = 0;\r
370xfr_req = xfr_req & ~1; /* <0> reserved */\r
371int_req = int_req & ~1; /* <0> reserved */\r
372api_lvl = api_lvl & ~1; /* <0> reserved */\r
373set_dyn_map (); /* set up mapping */\r
374int_reqhi = api_findreq (); /* recalc int req */\r
375chan_req = chan_testact (); /* recalc chan act */\r
376\r
377/* Main instruction fetch/decode loop */\r
378\r
379while (reason == 0) { /* loop until halted */\r
380\r
381 if (cpu_astop) { /* debug stop? */\r
382 cpu_astop = 0;\r
383 return SCPE_STOP;\r
384 }\r
385\r
386 if (sim_interval <= 0) { /* event queue? */\r
387 if (reason = sim_process_event ()) break; /* process */\r
388 int_reqhi = api_findreq (); /* recalc int req */\r
389 chan_req = chan_testact (); /* recalc chan act */\r
390 }\r
391\r
392 if (chan_req) { /* channel request? */\r
393 if (reason = chan_process ()) break; /* process */\r
394 int_reqhi = api_findreq (); /* recalc int req */\r
395 chan_req = chan_testact (); /* recalc chan act */\r
396 }\r
397\r
398 sim_interval = sim_interval - 1; /* count down */\r
399 if (ion && !ion_defer && int_reqhi) { /* int request? */\r
400 pa = int_vec[int_reqhi]; /* get vector */\r
401 if (pa == 0) { /* bad value? */\r
402 reason = STOP_ILLVEC;\r
403 break;\r
404 }\r
405 tinst = ReadP (pa); /* get inst */\r
406 save_mode = usr_mode; /* save mode */\r
407 usr_mode = 0; /* switch to mon */\r
408 if (hst_lnt) inst_hist (tinst, P, HIST_INT); /* record inst */\r
409 if (pa != VEC_RTCP) { /* normal intr? */\r
410 tr = one_inst (tinst, P, save_mode); /* exec intr inst */\r
411 if (tr) { /* stop code? */\r
412 usr_mode = save_mode; /* restore mode */\r
413 reason = (tr > 0)? tr: STOP_MMINT;\r
414 break;\r
415 }\r
416 api_lvl = api_lvl | (1u << int_reqhi); /* set level active */\r
417 api_lvlhi = int_reqhi; /* elevate api */\r
418 }\r
419 else { /* clock intr */\r
420 tr = rtc_inst (tinst); /* exec RTC inst */\r
421 usr_mode = save_mode; /* restore mode */\r
422 if (tr) { /* stop code? */\r
423 reason = (tr > 0)? tr: STOP_MMINT;\r
424 break;\r
425 }\r
426 int_req = int_req & ~INT_RTCP; /* clr clkp intr */\r
427 }\r
428 int_reqhi = api_findreq (); /* recalc int req */\r
429 }\r
430 else { /* normal instr */\r
431 if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */\r
432 reason = STOP_IBKPT; /* stop simulation */\r
433 break;\r
434 }\r
435 reason = Read (save_P = P, &inst); /* get instr */\r
436 P = (P + 1) & VA_MASK; /* incr PC */\r
437 if (reason == SCPE_OK) { /* fetch ok? */\r
438 ion_defer = 0; /* clear ion */\r
439 if (hst_lnt) inst_hist (inst, save_P, HIST_XCT);\r
440 reason = one_inst (inst, save_P, usr_mode); /* exec inst */\r
441 if (reason > 0) { /* stop code? */\r
442 if (reason != STOP_HALT) P = save_P;\r
443 if (reason == STOP_IONRDY) reason = 0;\r
444 }\r
445 } /* end if r == 0 */\r
446 if (reason < 0) { /* mm (fet or ex)? */\r
447 pa = -reason; /* get vector */\r
448 reason = 0; /* defang */\r
449 tinst = ReadP (pa); /* get inst */\r
450 if (I_GETOP (tinst) != BRM) { /* not BRM? */\r
451 reason = STOP_TRPINS; /* fatal err */\r
452 break;\r
453 }\r
454 save_mode = usr_mode; /* save mode */\r
455 usr_mode = 0; /* switch to mon */\r
456 mon_usr_trap = 0;\r
457 if (hst_lnt) inst_hist (tinst, save_P, HIST_TRP);\r
458 tr = one_inst (tinst, save_P, save_mode); /* trap inst */\r
459 if (tr) { /* stop code? */\r
460 usr_mode = save_mode; /* restore mode */\r
461 P = save_P; /* restore PC */\r
462 reason = (tr > 0)? tr: STOP_MMTRP;\r
463 break;\r
464 }\r
465 } /* end if reason */\r
466 } /* end else int */\r
467 } /* end while */\r
468\r
469/* Simulation halted */\r
470\r
471pcq_r->qptr = pcq_p; /* update pc q ptr */\r
472return reason;\r
473}\r
474\r
475/* Simulate one instruction */\r
476\r
477t_stat one_inst (uint32 inst, uint32 pc, uint32 mode)\r
478{\r
479uint32 op, shf_op, va, dat;\r
480uint32 old_A, old_B, old_X;\r
481int32 i, exu_cnt, sc;\r
482t_stat r;\r
483\r
484exu_cnt = 0; /* init EXU count */\r
485EXU_LOOP:\r
486op = I_GETOP (inst); /* get opcode */\r
487if (inst & I_POP) { /* POP? */\r
488 dat = (EM3 << 18) | (EM2 << 15) | I_IND | pc; /* data to save */\r
489 if (nml_mode) { /* normal mode? */\r
490 dat = (OV << 23) | dat; /* ov in <0> */\r
491 WriteP (0, dat);\r
492 }\r
493 else if (usr_mode) { /* user mode? */\r
494 if (inst & I_USR) { /* SYSPOP? */\r
495 dat = I_USR | (OV << 21) | dat; /* ov in <2> */\r
496 WriteP (0, dat);\r
497 usr_mode = 0; /* set mon mode */\r
498 }\r
499 else { /* normal POP */\r
500 dat = (OV << 23) | dat; /* ov in <0> */\r
501 if (r = Write (0, dat)) return r;\r
502 }\r
503 } \r
504 else { /* mon mode */\r
505 dat = (OV << 21) | dat; /* ov in <2> */\r
506 WriteP (0, dat); /* store return */\r
507 }\r
508 PCQ_ENTRY; /* save PC */\r
509 P = 0100 | op; /* new PC */\r
510 OV = 0; /* clear ovflo */\r
511 return SCPE_OK; /* end POP */\r
512 }\r
513\r
514switch (op) { /* case on opcode */\r
515\r
516/* Loads and stores */\r
517\r
518 case LDA:\r
519 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
520 if (r = Read (va, &A)) return r; /* get operand */\r
521 break;\r
522\r
523 case LDB:\r
524 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
525 if (r = Read (va, &B)) return r; /* get operand */\r
526 break;\r
527\r
528 case LDX:\r
529 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
530 if (r = Read (va, &X)) return r; /* get operand */\r
531 break;\r
532\r
533 case STA:\r
534 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
535 if (r = Write (va, A)) return r; /* write operand */\r
536 break;\r
537\r
538 case STB:\r
539 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
540 if (r = Write (va, B)) return r; /* write operand */\r
541 break;\r
542\r
543 case STX:\r
544 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
545 if (r = Write (va, X)) return r; /* write operand */\r
546 break;\r
547\r
548 case EAX:\r
549 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
550 if (nml_mode || usr_mode) /* normal or user? */\r
551 X = (X & ~VA_MASK) | (va & VA_MASK); /* only 14b */\r
552 else X = (X & ~XVA_MASK) | (va & XVA_MASK); /* mon, 15b */\r
553 break;\r
554\r
555 case XMA:\r
556 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
557 if (r = Read (va, &dat)) return r; /* get operand */\r
558 if (r = Write (va, A)) return r; /* write A */\r
559 A = dat; /* load A */\r
560 break;\r
561\r
562/* Arithmetic and logical */\r
563\r
564 case ADD:\r
565 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
566 if (r = Read (va, &dat)) return r; /* get operand */\r
567 A = Add24 (A, dat, 0); /* add */\r
568 break;\r
569\r
570 case ADC:\r
571 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
572 if (r = Read (va, &dat)) return r; /* get operand */\r
573 OV = 0; /* clear overflow */\r
574 A = Add24 (A, dat, X >> 23); /* add with carry */\r
575 break;\r
576\r
577 case SUB:\r
578 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
579 if (r = Read (va, &dat)) return r; /* get operand */\r
580 A = Add24 (A, dat ^ DMASK, 1); /* subtract */\r
581 break;\r
582\r
583 case SUC:\r
584 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
585 if (r = Read (va, &dat)) return r; /* get operand */\r
586 OV = 0; /* clear overflow */\r
587 A = Add24 (A, dat ^ DMASK, X >> 23); /* sub with carry */\r
588 break;\r
589\r
590 case ADM:\r
591 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
592 if (r = Read (va, &dat)) return r; /* get operand */\r
593 dat = AddM24 (dat, A); /* mem + A */\r
594 if (r = Write (va, dat)) return r; /* rewrite */\r
595 break;\r
596\r
597 case MIN:\r
598 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
599 if (r = Read (va, &dat)) return r; /* get operand */\r
600 dat = AddM24 (dat, 1); /* mem + 1 */\r
601 if (r = Write (va, dat)) return r; /* rewrite */\r
602 break;\r
603\r
604 case MUL:\r
605 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
606 if (r = Read (va, &dat)) return r; /* get operand */\r
607 Mul48 (A, dat); /* multiply */\r
608 break;\r
609\r
610 case DIV:\r
611 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
612 if (r = Read (va, &dat)) return r; /* get operand */\r
613 Div48 (A, B, dat); /* divide */\r
614 break;\r
615\r
616 case ETR:\r
617 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
618 if (r = Read (va, &dat)) return r; /* get operand */\r
619 A = A & dat; /* and */\r
620 break;\r
621\r
622 case MRG:\r
623 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
624 if (r = Read (va, &dat)) return r; /* get operand */\r
625 A = A | dat; /* or */\r
626 break;\r
627\r
628 case EOR:\r
629 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
630 if (r = Read (va, &dat)) return r; /* get operand */\r
631 A = A ^ dat; /* xor */\r
632 break;\r
633\r
634/* Skips */\r
635\r
636 case SKE:\r
637 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
638 if (r = Read (va, &dat)) return r; /* get operand */\r
639 if (A == dat) P = (P + 1) & VA_MASK; /* if A = op, skip */\r
640 break;\r
641\r
642 case SKG:\r
643 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
644 if (r = Read (va, &dat)) return r; /* get operand */\r
645 if (SXT (A) > SXT (dat)) P = (P + 1) & VA_MASK; /* if A > op, skip */\r
646 break;\r
647\r
648 case SKM:\r
649 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
650 if (r = Read (va, &dat)) return r; /* get operand */\r
651 if (((A ^ dat) & B) == 0) P = (P + 1) & VA_MASK; /* if A = op masked */\r
652 break;\r
653\r
654 case SKA:\r
655 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
656 if (r = Read (va, &dat)) return r; /* get operand */\r
657 if ((A & dat) == 0) P = (P + 1) & VA_MASK; /* if !(A & op), skip */\r
658 break;\r
659\r
660 case SKB:\r
661 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
662 if (r = Read (va, &dat)) return r; /* get operand */\r
663 if ((B & dat) == 0) P = (P + 1) & VA_MASK; /* if !(B & op), skip */\r
664 break;\r
665\r
666 case SKN:\r
667 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
668 if (r = Read (va, &dat)) return r; /* get operand */\r
669 if (dat & SIGN) P = (P + 1) & VA_MASK; /* if op < 0, skip */\r
670 break;\r
671\r
672 case SKR:\r
673 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
674 if (r = Read (va, &dat)) return r; /* get operand */\r
675 dat = AddM24 (dat, DMASK); /* decr operand */\r
676 if (r = Write (va, dat)) return r; /* rewrite operand */\r
677 if (dat & SIGN) P = (P + 1) & VA_MASK; /* if op < 0, skip */\r
678 break;\r
679\r
680 case SKD:\r
681 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
682 if (r = Read (va, &dat)) return r; /* get operand */\r
683 if (SXT_EXP (B) < SXT_EXP (dat)) { /* B < dat? */\r
684 X = (dat - B) & DMASK; /* X = dat - B */\r
685 P = (P + 1) & VA_MASK; /* skip */\r
686 }\r
687 else X = (B - dat) & DMASK; /* X = B - dat */\r
688 break;\r
689\r
690/* Control */\r
691\r
692 case NOP:\r
693 break;\r
694\r
695 case HLT:\r
696 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
697 return STOP_HALT; /* halt CPU */\r
698\r
699 case EXU:\r
700 exu_cnt = exu_cnt + 1; /* count chained EXU */\r
701 if (exu_cnt > exu_lim) return STOP_EXULIM; /* too many? */\r
702 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
703 if (r = Read (va, &dat)) return r; /* get operand */\r
704 inst = dat;\r
705 goto EXU_LOOP;\r
706 \r
707 case BRU:\r
708 if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */\r
709 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
710 if (r = Read (va, &dat)) return r; /* test dest access */\r
711 PCQ_ENTRY;\r
712 P = va & VA_MASK; /* branch */\r
713 break;\r
714\r
715 case BRX:\r
716 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
717 X = (X + 1) & DMASK; /* incr X */\r
718 if (X & I_IND) { /* bit 9 set? */\r
719 if (r = Read (va, &dat)) return r; /* test dest access */\r
720 PCQ_ENTRY;\r
721 P = va & VA_MASK; /* branch */\r
722 }\r
723 break;\r
724\r
725 case BRM:\r
726 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
727 dat = (EM3 << 18) | (EM2 << 15) | pc; /* form return word */\r
728 if (!nml_mode && !usr_mode) /* monitor mode? */\r
729 dat = dat | (mode << 23) | (OV << 21);\r
730 else dat = dat | (OV << 23); /* normal or user */\r
731 if (r = Write (va, dat)) return r; /* write ret word */\r
732 PCQ_ENTRY;\r
733 P = (va + 1) & VA_MASK; /* branch */\r
734 break;\r
735\r
736 case BRR:\r
737 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
738 if (r = Read (va, &dat)) return r; /* get operand */\r
739 PCQ_ENTRY;\r
740 P = (dat + 1) & VA_MASK; /* branch */\r
741 if (!nml_mode && !usr_mode) { /* monitor mode? */\r
742 OV = OV | ((dat >> 21) & 1); /* restore OV */\r
743 if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */\r
744 usr_mode = 1;\r
745 if (mon_usr_trap) return MM_MONUSR;\r
746 }\r
747 }\r
748 else OV = OV | ((dat >> 23) & 1); /* restore OV */\r
749 break;\r
750\r
751 case BRI:\r
752 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
753 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
754 if (r = Read (va, &dat)) return r; /* get operand */\r
755 api_dismiss (); /* dismiss hi api */\r
756 PCQ_ENTRY;\r
757 P = dat & VA_MASK; /* branch */\r
758 if (!nml_mode) { /* monitor mode? */\r
759 OV = (dat >> 21) & 1; /* restore OV */\r
760 if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */\r
761 usr_mode = 1;\r
762 if (mon_usr_trap) return MM_MONUSR;\r
763 }\r
764 }\r
765 else OV = (dat >> 23) & 1; /* restore OV */\r
766 break;\r
767\r
768/* Register change (microprogrammed) */\r
769\r
770 case RCH:\r
771 old_A = A; /* save orig reg */\r
772 old_B = B;\r
773 old_X = X;\r
774 if (inst & 000001211) { /* A change? */\r
775 if (inst & 01000) dat = (~old_A + 1) & DMASK; /* CNA */\r
776 else dat = 0;\r
777 if (inst & 00200) dat = dat | old_X;\r
778 if (inst & 00010) dat = dat | old_B;\r
779 if (inst & 00100) A = (A & ~EXPMASK) | (dat & EXPMASK);\r
780 else A = dat;\r
781 }\r
782 if (inst & 000000046) { /* B change? */\r
783 if (inst & 00040) dat = old_X;\r
784 else dat = 0;\r
785 if (inst & 00004) dat = dat | old_A;\r
786 if (inst & 00100) B = (B & ~EXPMASK) | (dat & EXPMASK);\r
787 else B = dat;\r
788 }\r
789 if (inst & 020000420) { /* X change? */\r
790 if (inst & 00400) dat = old_A;\r
791 else dat = 0;\r
792 if (inst & 00020) dat = dat | old_B;\r
793 if (inst & 00100) X = SXT_EXP (dat) & DMASK;\r
794 else X = dat;\r
795 }\r
796 break;\r
797\r
798/* Overflow instruction */\r
799\r
800 case OVF:\r
801 if ((inst & 0100) & OV) P = (P + 1) & VA_MASK;\r
802 if (inst & 0001) OV = 0;\r
803 if ((inst & 0010) && (((X >> 1) ^ X) & EXPS)) OV = 1;\r
804 break;\r
805\r
806/* Shifts */\r
807\r
808 case RSH:\r
809 if (r = EaSh (inst, &va)) return r; /* decode eff addr */\r
810 shf_op = I_GETSHFOP (va); /* get eff op */\r
811 sc = va & I_SHFMSK; /* get eff count */\r
812 switch (shf_op) { /* case on sub-op */\r
813 case 00: /* right arithmetic */\r
814 if (sc) ShfR48 (sc, (A & SIGN)? DMASK: 0);\r
815 break;\r
816 case 04: /* right cycle */\r
817 sc = sc % 48; /* mod 48 */\r
818 if (sc) RotR48 (sc);\r
819 break;\r
820 case 05: /* right logical */\r
821 if (sc) ShfR48 (sc, 0);\r
822 break;\r
823 default:\r
824 CRETINS; /* invalid inst */\r
825 break;\r
826 } /* end case shf op */\r
827 break;\r
828\r
829 case LSH:\r
830 if (r = EaSh (inst, &va)) return r; /* decode eff addr */\r
831 shf_op = I_GETSHFOP (va); /* get eff op */\r
832 sc = va & I_SHFMSK; /* get eff count */\r
833 switch (shf_op) { /* case on sub-op */\r
834 case 00: /* left arithmetic */\r
835 dat = A; /* save sign */\r
836 if (sc > 48) sc = 48;\r
837 for (i = 0; i < sc; i++) { /* loop */\r
838 A = ((A << 1) | (B >> 23)) & DMASK;\r
839 B = (B << 1) & DMASK;\r
840 if ((A ^ dat) & SIGN) OV = 1;\r
841 }\r
842 break;\r
843 case 02: /* normalize */\r
844 if (sc > 48) sc = 48;\r
845 for (i = 0; i < sc; i++) { /* until max count */\r
846 if ((A ^ (A << 1)) & SIGN) break;\r
847 A = ((A << 1) | (B >> 23)) & DMASK;\r
848 B = (B << 1) & DMASK;\r
849 }\r
850 X = (X - i) & DMASK;\r
851 break;\r
852 case 04: /* left cycle */\r
853 sc = sc % 48; /* mod 48 */\r
854 if (sc) RotR48 (48 - sc); /* rotate */\r
855 break;\r
856 case 06: /* cycle normalize */\r
857 if (sc > 48) sc = 48;\r
858 for (i = 0; i < sc; i++) { /* until max count */\r
859 if ((A ^ (A << 1)) & SIGN) break;\r
860 old_A = A; /* cyclic shift */\r
861 A = ((A << 1) | (B >> 23)) & DMASK;\r
862 B = ((B << 1) | (old_A >> 23)) & DMASK;\r
863 }\r
864 X = (X - i) & DMASK;\r
865 break;\r
866 default:\r
867 CRETINS; /* invalid inst */\r
868 break;\r
869 } /* end case shf op */\r
870 break;\r
871\r
872/* I/O instructions */\r
873\r
874 case MIW: case MIY:\r
875 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
876 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
877 if (r = Read (va, &dat)) return r; /* get operand */\r
878 if (r = op_miwy (inst, dat)) return r; /* process inst */\r
879 int_reqhi = api_findreq (); /* recalc int req */\r
880 chan_req = chan_testact (); /* recalc chan act */\r
881 break;\r
882\r
883 case WIM: case YIM:\r
884 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
885 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
886 if (r = op_wyim (inst, &dat)) return r; /* process inst */\r
887 if (r = Write (va, dat)) return r; /* write result */\r
888 int_reqhi = api_findreq (); /* recalc int req */\r
889 chan_req = chan_testact (); /* recalc chan act */\r
890 break;\r
891\r
892 case EOM: case EOD:\r
893 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
894 if (r = op_eomd (inst)) return r; /* process inst */\r
895 int_reqhi = api_findreq (); /* recalc int req */\r
896 chan_req = chan_testact (); /* recalc chan act */\r
897 ion_defer = 1;\r
898 break;\r
899\r
900 case POT:\r
901 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
902 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
903 if (r = Read (va, &dat)) return r; /* get operand */\r
904 if (r = op_pot (dat)) return r; /* process inst */\r
905 int_reqhi = api_findreq (); /* recalc int req */\r
906 chan_req = chan_testact (); /* recalc chan act */\r
907 break;\r
908\r
909 case PIN:\r
910 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
911 if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
912 if (r = op_pin (&dat)) return r; /* process inst */\r
913 if (r = Write (va, dat)) return r; /* write result */\r
914 int_reqhi = api_findreq (); /* recalc int req */\r
915 chan_req = chan_testact (); /* recalc chan act */\r
916 break;\r
917\r
918 case SKS:\r
919 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */\r
920 if (r = op_sks (inst, &dat)) return r; /* process inst */\r
921 if (dat) P = (P + 1) & VA_MASK;\r
922 break;\r
923\r
924 default:\r
925 if (!nml_mode && usr_mode) return MM_PRVINS; /* usr? priv viol */\r
926 CRETINS; /* invalid inst */\r
927 break;\r
928 }\r
929\r
930return SCPE_OK;\r
931}\r
932\r
933/* Effective address calculation */\r
934\r
935t_stat Ea (uint32 inst, uint32 *addr)\r
936{\r
937int32 i;\r
938uint32 wd = inst; /* homeable */\r
939uint32 va = wd & XVA_MASK; /* initial va */\r
940t_stat r;\r
941\r
942for (i = 0; i < ind_lim; i++) { /* count indirects */\r
943 if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK);\r
944 *addr = va;\r
945 if ((wd & I_IND) == 0) { /* end of ind chain? */\r
946 if (hst_lnt) hst[hst_p].ea = *addr; /* record */\r
947 return SCPE_OK;\r
948 }\r
949 if (r = Read (va, &wd)) return r; /* read ind; fails? */\r
950 va = (va & VA_USR) | (wd & XVA_MASK);\r
951 }\r
952return STOP_INDLIM; /* too many indirects */\r
953}\r
954\r
955/* Effective address calculation for shifts - direct indexing is 9b */\r
956\r
957t_stat EaSh (uint32 inst, uint32 *addr)\r
958{\r
959int32 i;\r
960uint32 wd = inst; /* homeable */\r
961uint32 va = wd & XVA_MASK; /* initial va */\r
962t_stat r;\r
963\r
964for (i = 0; i < ind_lim; i++) { /* count indirects */\r
965 if ((wd & I_IND) == 0) { /* end of ind chain? */\r
966 if (wd & I_IDX) *addr = (va & (VA_MASK & ~I_SHFMSK)) |\r
967 ((va + X) & I_SHFMSK); /* 9b indexing */\r
968 else *addr = va & VA_MASK;\r
969 if (hst_lnt) hst[hst_p].ea = *addr; /* record */\r
970 return SCPE_OK;\r
971 }\r
972 if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK);\r
973 if (r = Read (va, &wd)) return r; /* read ind; fails? */\r
974 va = (va & VA_USR) | (wd & XVA_MASK);\r
975 }\r
976return STOP_INDLIM; /* too many indirects */\r
977}\r
978\r
979/* Read word from virtual address */\r
980\r
981t_stat Read (uint32 va, uint32 *dat)\r
982{\r
983uint32 pgn, map, pa;\r
984\r
985if (nml_mode) { /* normal? */\r
986 va = va & VA_MASK; /* ignore user */\r
987 if (va < 020000) pa = va; /* first 8K: 1 for 1 */\r
988 else if (va < 030000) pa = va + em2_dyn; /* next 4K: ext EM2 */\r
989 else pa = va + em3_dyn; /* next 4K: ext EM3 */\r
990 }\r
991else if (usr_mode || (va & VA_USR)) { /* user mapping? */\r
992 pgn = VA_GETPN (va); /* get page no */\r
993 map = usr_map[pgn]; /* get map entry */\r
994 if (map == MAP_PROT) return MM_NOACC; /* prot? no access */\r
995 pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */\r
996 }\r
997else {\r
998 pgn = VA_GETPN (va); /* mon, get page no */\r
999 map = mon_map[pgn]; /* get map entry */\r
1000 if (map & MAP_PROT) return MM_NOACC; /* prot? no access */\r
1001 pa = map | (va & VA_POFF); /* map address */\r
1002 }\r
1003*dat = M[pa]; /* return word */\r
1004return SCPE_OK;\r
1005}\r
1006\r
1007/* Write word to virtual address */\r
1008\r
1009t_stat Write (uint32 va, uint32 dat)\r
1010{\r
1011uint32 pgn, map, pa;\r
1012\r
1013if (nml_mode) { /* normal? */\r
1014 va = va & VA_MASK; /* ignore user */\r
1015 if (va < 020000) pa = va; /* first 8K: 1 for 1 */\r
1016 else if (va < 030000) pa = va + em2_dyn; /* next 4K: ext EM2 */\r
1017 else pa = va + em3_dyn; /* next 4K: ext EM3 */\r
1018 }\r
1019else if (usr_mode || (va & VA_USR)) { /* user mapping? */\r
1020 pgn = VA_GETPN (va); /* get page no */\r
1021 map = usr_map[pgn]; /* get map entry */\r
1022 if (map & MAP_PROT) { /* protected page? */\r
1023 if (map == MAP_PROT) return MM_NOACC; /* zero? no access */\r
1024 else return MM_WRITE; /* else, write prot */\r
1025 }\r
1026 pa = map | (va & VA_POFF); /* map address */\r
1027 }\r
1028else {\r
1029 pgn = VA_GETPN (va); /* mon, get page no */\r
1030 map = mon_map[pgn]; /* get map entry */\r
1031 if (map & MAP_PROT) return MM_NOACC; /* prot? no access */\r
1032 pa = map | (va & VA_POFF); /* map address */\r
1033 }\r
1034if (MEM_ADDR_OK (pa)) M[pa] = dat;\r
1035return SCPE_OK;\r
1036}\r
1037\r
1038/* Relocate addr for console access */\r
1039\r
1040uint32 RelocC (int32 va, int32 sw)\r
1041{\r
1042uint32 nml = nml_mode, usr = usr_mode;\r
1043uint32 pa, pgn, map;\r
1044\r
1045if (sw & SWMASK ('N')) nml = 1; /* -n: normal */\r
1046else if (sw & SWMASK ('X')) nml = usr = 0; /* -x: mon */\r
1047else if (sw & SWMASK ('U')) nml = 0, usr = 1; /* -u: user */\r
1048else if (!(sw & SWMASK ('V'))) return va; /* -v: curr */\r
1049set_dyn_map ();\r
1050if (nml) { /* normal? */\r
1051 if (va < 020000) pa = va; /* first 8K: 1 for 1 */\r
1052 else if (va < 030000) pa = va + em2_dyn; /* next 4K: ext EM2 */\r
1053 else pa = va + em3_dyn; /* next 4K: ext EM3 */\r
1054 }\r
1055else {\r
1056 pgn = VA_GETPN (va); /* get page no */\r
1057 map = usr? usr_map[pgn]: mon_map[pgn]; /* get map entry */\r
1058 if (map == MAP_PROT) return MAXMEMSIZE + 1; /* no access page? */\r
1059 pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */\r
1060 }\r
1061return pa;\r
1062}\r
1063\r
1064/* Arithmetic routines */\r
1065\r
1066uint32 Add24 (uint32 s1, uint32 s2, uint32 cin)\r
1067{\r
1068uint32 t = s1 + s2 + cin; /* add with carry in */\r
1069if (t > DMASK) X = X | SIGN; /* carry to X<0> */\r
1070else X = X & ~SIGN;\r
1071if (((s1 ^ ~s2) & (s1 ^ t)) & SIGN) OV = 1; /* overflow */\r
1072return t & DMASK;\r
1073}\r
1074\r
1075uint32 AddM24 (uint32 s1, uint32 s2)\r
1076{\r
1077uint32 t = s1 + s2; /* add */\r
1078if (((s1 ^ ~s2) & (s1 ^ t)) & SIGN) OV = 1; /* overflow */\r
1079return t & DMASK;\r
1080}\r
1081\r
1082void Mul48 (uint32 s1, uint32 s2)\r
1083{\r
1084uint32 a = ABS (s1);\r
1085uint32 b = ABS (s2);\r
1086uint32 hi, md, lo, t, u;\r
1087\r
1088if ((a == 0) || (b == 0)) { /* ops zero? */\r
1089 A = B = 0;\r
1090 return;\r
1091 }\r
1092t = a >> 12; /* split op1 */\r
1093a = a & 07777;\r
1094u = b >> 12; /* split op2 */\r
1095b = b & 07777;\r
1096md = (a * u) + (b * t); /* cross product */\r
1097lo = (a * b) + ((md & 07777) << 12); /* low result */\r
1098hi = (t * u) + (md >> 12) + (lo >> 24); /* hi result */\r
1099A = ((hi << 1) & DMASK) | ((lo & DMASK) >> 23);\r
1100B = (lo << 1) & DMASK;\r
1101if ((s1 ^ s2) & SIGN) {\r
1102 B = ((B ^ DMASK) + 1) & DMASK;\r
1103 A = ((A ^ DMASK) + (B == 0)) & DMASK;\r
1104 }\r
1105else if (A & SIGN) OV = 1;\r
1106return;\r
1107}\r
1108\r
1109/* Divide - the SDS 940 uses a non-restoring divide. The algorithm\r
1110 runs even for overflow cases. Hence it must be emulated precisely\r
1111 to give the right answers for diagnostics. If the dividend is \r
1112 negative, AB are 2's complemented starting at B<22>, and B<23>\r
1113 is unchanged. */\r
1114\r
1115void Div48 (uint32 ar, uint32 br, uint32 m)\r
1116{\r
1117int32 i;\r
1118uint32 quo = 0; /* quotient */\r
1119uint32 dvdh = ar, dvdl = br; /* dividend */\r
1120uint32 dvr = ABS (m); /* make dvr pos */\r
1121\r
1122if (TSTS (dvdh)) { /* dvd < 0? */\r
1123 dvdl = (((dvdl ^ DMASK) + 2) & (DMASK & ~1)) | /* 23b negate */\r
1124 (dvdl & 1); /* low bit unch */\r
1125 dvdh = ((dvdh ^ DMASK) + (dvdl <= 1)) & DMASK;\r
1126 }\r
1127if ((dvdh > dvr) || /* divide fail? */\r
1128 ((dvdh == dvr) && dvdl) ||\r
1129 ((dvdh == dvr) && !TSTS (ar ^ m))) OV = 1;\r
1130dvdh = (dvdh - dvr) & DMASK; /* initial sub */\r
1131for (i = 0; i < 23; i++) { /* 23 iterations */\r
1132 quo = (quo << 1) | ((dvdh >> 23) ^ 1); /* quo bit = ~sign */\r
1133 dvdh = ((dvdh << 1) | (dvdl >> 23)) & DMASK; /* shift divd */\r
1134 dvdl = (dvdl << 1) & DMASK;\r
1135 if (quo & 1) /* test ~sign */\r
1136 dvdh = (dvdh - dvr) & DMASK; /* sign was +, sub */\r
1137 else dvdh = (dvdh + dvr) & DMASK; /* sign was -, add */\r
1138 }\r
1139quo = quo << 1; /* shift quo */\r
1140if (dvdh & SIGN) dvdh = (dvdh + dvr) & DMASK; /* last op -? restore */\r
1141else quo = quo | 1; /* +, set quo bit */\r
1142if (TSTS (ar ^ m)) A = NEG (quo); /* sign of quo */\r
1143else A = quo; /* A = quo */\r
1144if (TSTS (ar)) B = NEG (dvdh); /* sign of rem */\r
1145else B = dvdh; /* B = rem */\r
1146return;\r
1147}\r
1148\r
1149void RotR48 (uint32 sc)\r
1150{\r
1151uint32 t = A;\r
1152\r
1153if (sc >= 24) {\r
1154 sc = sc - 24;\r
1155 A = ((B >> sc) | (A << (24 - sc))) & DMASK;\r
1156 B = ((t >> sc) | (B << (24 - sc))) & DMASK;\r
1157 }\r
1158else {\r
1159 A = ((A >> sc) | (B << (24 - sc))) & DMASK;\r
1160 B = ((B >> sc) | (t << (24 - sc))) & DMASK;\r
1161 }\r
1162return;\r
1163}\r
1164\r
1165void ShfR48 (uint32 sc, uint32 sgn)\r
1166{\r
1167if (sc >= 48) A = B = sgn;\r
1168if (sc >= 24) {\r
1169 sc = sc - 24;\r
1170 B = ((A >> sc) | (sgn << (24 - sc))) & DMASK;\r
1171 A = sgn;\r
1172 }\r
1173else {\r
1174 B = ((B >> sc) | (A << (24 - sc)) & DMASK);\r
1175 A = ((A >> sc) | (sgn << (24 - sc))) & DMASK;\r
1176 }\r
1177return;\r
1178}\r
1179\r
1180/* POT routines for RL1, RL2, RL4 */\r
1181\r
1182t_stat pot_RL1 (uint32 num, uint32 *dat)\r
1183{\r
1184RL1 = *dat;\r
1185set_dyn_map ();\r
1186return SCPE_OK;\r
1187}\r
1188\r
1189t_stat pot_RL2 (uint32 num, uint32 *dat)\r
1190{\r
1191RL2 = *dat;\r
1192set_dyn_map ();\r
1193return SCPE_OK;\r
1194}\r
1195\r
1196t_stat pot_RL4 (uint32 num, uint32 *dat)\r
1197{\r
1198RL4 = (*dat) & 03737;\r
1199set_dyn_map ();\r
1200return SCPE_OK;\r
1201}\r
1202\r
1203/* Map EM2, EM3, RL1, RL2, RL4 to dynamic forms\r
1204\r
1205 EM2, EM3 - left shifted 12, base virtual address subtracted\r
1206 RL1, RL2 - page left shifted 11\r
1207 RL3 - filled in as 1 to 1 map\r
1208 RL4 - EM2 or page left shifted 11, PROT bit inserted\r
1209*/\r
1210\r
1211void set_dyn_map (void)\r
1212{\r
1213em2_dyn = ((EM2 & 07) << 12) - 020000;\r
1214em3_dyn = ((EM3 & 07) << 12) - 030000;\r
1215usr_map[0] = (RL1 >> 7) & (MAP_PROT | MAP_PAGE);\r
1216usr_map[1] = (RL1 >> 1) & (MAP_PROT | MAP_PAGE);\r
1217usr_map[2] = (RL1 << 5) & (MAP_PROT | MAP_PAGE);\r
1218usr_map[3] = (RL1 << 11) & (MAP_PROT | MAP_PAGE);\r
1219usr_map[4] = (RL2 >> 7) & (MAP_PROT | MAP_PAGE);\r
1220usr_map[5] = (RL2 >> 1) & (MAP_PROT | MAP_PAGE);\r
1221usr_map[6] = (RL2 << 5) & (MAP_PROT | MAP_PAGE);\r
1222usr_map[7] = (RL2 << 11) & (MAP_PROT | MAP_PAGE);\r
1223mon_map[0] = (0 << VA_V_PN);\r
1224mon_map[1] = (1 << VA_V_PN);\r
1225mon_map[2] = (2 << VA_V_PN);\r
1226mon_map[3] = (3 << VA_V_PN);\r
1227mon_map[4] = ((EM2 & 07) << 12);\r
1228mon_map[5] = ((EM2 & 07) << 12) + (1 << VA_V_PN);\r
1229mon_map[6] = (RL4 << 5) & MAP_PAGE;\r
1230mon_map[7] = (RL4 << 11) & MAP_PAGE;\r
1231if (mon_map[6] == 0) mon_map[6] = MAP_PROT;\r
1232if (mon_map[7] == 0) mon_map[7] = MAP_PROT;\r
1233return;\r
1234}\r
1235\r
1236/* Recalculate api requests */\r
1237\r
1238uint32 api_findreq (void)\r
1239{\r
1240uint32 i, t;\r
1241\r
1242t = (int_req & ~1) & api_mask[api_lvlhi]; /* unmasked int */\r
1243for (i = 31; t && (i > 0); i--) { /* find highest */\r
1244 if ((t >> i) & 1) return i;\r
1245 }\r
1246return 0; /* none */\r
1247}\r
1248\r
1249/* Dismiss highest priority interrupt */\r
1250\r
1251void api_dismiss (void)\r
1252{\r
1253uint32 i, t;\r
1254\r
1255t = 1u << api_lvlhi; /* highest active */\r
1256int_req = int_req & ~t; /* clear int req */\r
1257api_lvl = api_lvl & ~t; /* clear api level */\r
1258api_lvlhi = 0; /* assume all clear */\r
1259for (i = 31; api_lvl && (i > 0); i--) { /* find highest api */\r
1260 if ((api_lvl >> i) & 1) { /* bit set? */\r
1261 api_lvlhi = i; /* record level */\r
1262 break; /* done */\r
1263 }\r
1264 }\r
1265int_reqhi = api_findreq (); /* recalc intreq */\r
1266return;\r
1267}\r
1268\r
1269/* Reset routine */\r
1270\r
1271t_stat cpu_reset (DEVICE *dptr)\r
1272{\r
1273OV = 0;\r
1274EM2 = 2;\r
1275EM3 = 3;\r
1276RL1 = RL2 = RL4 = 0;\r
1277ion = ion_defer = 0;\r
1278nml_mode = 1;\r
1279usr_mode = 0;\r
1280mon_usr_trap = 0;\r
1281int_req = 0;\r
1282int_reqhi = 0;\r
1283api_lvl = 0;\r
1284api_lvlhi = 0;\r
1285alert = 0;\r
1286pcq_r = find_reg ("PCQ", NULL, dptr);\r
1287if (pcq_r) pcq_r->qptr = 0;\r
1288else return SCPE_IERR;\r
1289sim_brk_types = sim_brk_dflt = SWMASK ('E');\r
1290return SCPE_OK;\r
1291}\r
1292\r
1293/* Memory examine */\r
1294\r
1295t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
1296{\r
1297uint32 pa;\r
1298\r
1299pa = RelocC (addr, sw);\r
1300if (pa > MAXMEMSIZE) return SCPE_REL;\r
1301if (pa >= MEMSIZE) return SCPE_NXM;\r
1302if (vptr != NULL) *vptr = M[pa] & DMASK;\r
1303return SCPE_OK;\r
1304}\r
1305\r
1306/* Memory deposit */\r
1307\r
1308t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
1309{\r
1310uint32 pa;\r
1311\r
1312pa = RelocC (addr, sw);\r
1313if (pa > MAXMEMSIZE) return SCPE_REL;\r
1314if (pa >= MEMSIZE) return SCPE_NXM;\r
1315M[pa] = val & DMASK;\r
1316return SCPE_OK;\r
1317}\r
1318\r
1319/* Set memory size */\r
1320\r
1321t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1322{\r
1323int32 mc = 0;\r
1324uint32 i;\r
1325\r
1326if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 037777) != 0))\r
1327 return SCPE_ARG;\r
1328for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r
1329if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r
1330 return SCPE_OK;\r
1331MEMSIZE = val;\r
1332for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r
1333return SCPE_OK;\r
1334}\r
1335\r
1336/* Set system type (1 = Genie, 0 = standard) */\r
1337\r
1338t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1339{\r
1340extern t_stat drm_reset (DEVICE *dptr);\r
1341extern DEVICE drm_dev, mux_dev, muxl_dev;\r
1342extern UNIT drm_unit, mux_unit;\r
1343extern DIB mux_dib;\r
1344\r
1345if ((cpu_unit.flags & UNIT_GENIE) == (uint32) val) return SCPE_OK;\r
1346if ((drm_unit.flags & UNIT_ATT) || /* attached? */\r
1347 (mux_unit.flags & UNIT_ATT)) return SCPE_NOFNC; /* can't do it */\r
1348if (val) { /* Genie? */\r
1349 drm_dev.flags = drm_dev.flags & ~DEV_DIS; /* enb drum */\r
1350 mux_dev.flags = mux_dev.flags & ~DEV_DIS; /* enb mux */\r
1351 muxl_dev.flags = muxl_dev.flags & ~DEV_DIS;\r
1352 mux_dib.dev = DEV3_GMUX; /* Genie mux */\r
1353 }\r
1354else {\r
1355 drm_dev.flags = drm_dev.flags | DEV_DIS; /* dsb drum */\r
1356 mux_dib.dev = DEV3_SMUX; /* std mux */\r
1357 return drm_reset (&drm_dev);\r
1358 }\r
1359return SCPE_OK;\r
1360}\r
1361\r
1362/* The real time clock runs continuously; therefore, it only has\r
1363 a unit service routine and a reset routine. The service routine\r
1364 sets an interrupt that invokes the clock counter. The clock counter\r
1365 is a "one instruction interrupt", and only MIN/SKR are valid.\r
1366*/\r
1367\r
1368t_stat rtc_svc (UNIT *uptr)\r
1369{\r
1370if (rtc_pie) int_req = int_req | INT_RTCP; /* set pulse intr */\r
1371sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */\r
1372return SCPE_OK;\r
1373}\r
1374\r
1375/* Clock interrupt instruction */\r
1376\r
1377t_stat rtc_inst (uint32 inst)\r
1378{\r
1379uint32 op, dat, val, va;\r
1380t_stat r;\r
1381\r
1382op = I_GETOP (inst); /* get opcode */\r
1383if (op == MIN) val = 1; /* incr */\r
1384else if (op == SKR) val = DMASK; /* decr */\r
1385else return STOP_RTCINS; /* can't do it */\r
1386if (r = Ea (inst, &va)) return r; /* decode eff addr */\r
1387if (r = Read (va, &dat)) return r; /* get operand */\r
1388dat = AddM24 (dat, val); /* mem +/- 1 */\r
1389if (r = Write (va, dat)) return r; /* rewrite */\r
1390if (dat == 0) int_req = int_req | INT_RTCS; /* set clk sync int */\r
1391return SCPE_OK;\r
1392}\r
1393\r
1394/* Clock reset */\r
1395\r
1396t_stat rtc_reset (DEVICE *dptr)\r
1397{\r
1398rtc_pie = 0; /* disable pulse */\r
1399sim_activate (&rtc_unit, rtc_unit.wait); /* activate unit */\r
1400return SCPE_OK;\r
1401}\r
1402\r
1403/* Set frequency */\r
1404\r
1405t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1406{\r
1407if (cptr) return SCPE_ARG;\r
1408if ((val != 50) && (val != 60)) return SCPE_IERR;\r
1409rtc_tps = val;\r
1410return SCPE_OK;\r
1411}\r
1412\r
1413/* Show frequency */\r
1414\r
1415t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1416{\r
1417fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz");\r
1418return SCPE_OK;\r
1419}\r
1420\r
1421/* Record history */\r
1422\r
1423void inst_hist (uint32 ir, uint32 pc, uint32 tp)\r
1424{\r
1425hst_p = (hst_p + 1); /* next entry */\r
1426if (hst_p >= hst_lnt) hst_p = 0;\r
1427hst[hst_p].typ = tp | (OV << 4);\r
1428hst[hst_p].pc = pc;\r
1429hst[hst_p].ir = ir;\r
1430hst[hst_p].a = A;\r
1431hst[hst_p].b = B;\r
1432hst[hst_p].x = X;\r
1433hst[hst_p].ea = HIST_NOEA;\r
1434return;\r
1435}\r
1436\r
1437/* Set history */\r
1438\r
1439t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1440{\r
1441int32 i, lnt;\r
1442t_stat r;\r
1443\r
1444if (cptr == NULL) {\r
1445 for (i = 0; i < hst_lnt; i++) hst[i].typ = 0;\r
1446 hst_p = 0;\r
1447 return SCPE_OK;\r
1448 }\r
1449lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r
1450if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r
1451hst_p = 0;\r
1452if (hst_lnt) {\r
1453 free (hst);\r
1454 hst_lnt = 0;\r
1455 hst = NULL;\r
1456 }\r
1457if (lnt) {\r
1458 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));\r
1459 if (hst == NULL) return SCPE_MEM;\r
1460 hst_lnt = lnt;\r
1461 }\r
1462return SCPE_OK;\r
1463}\r
1464\r
1465/* Show history */\r
1466\r
1467t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1468{\r
1469int32 ov, k, di, lnt;\r
1470char *cptr = (char *) desc;\r
1471t_stat r;\r
1472t_value sim_eval;\r
1473InstHistory *h;\r
1474extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r
1475 UNIT *uptr, int32 sw);\r
1476static char *cyc[] = { " ", " ", "INT", "TRP" };\r
1477\r
1478if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r
1479if (cptr) {\r
1480 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);\r
1481 if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;\r
1482 }\r
1483else lnt = hst_lnt;\r
1484di = hst_p - lnt; /* work forward */\r
1485if (di < 0) di = di + hst_lnt;\r
1486fprintf (st, "CYC PC OV A B X EA IR\n\n");\r
1487for (k = 0; k < lnt; k++) { /* print specified */\r
1488 h = &hst[(++di) % hst_lnt]; /* entry pointer */\r
1489 if (h->typ) { /* instruction? */\r
1490 ov = (h->typ >> 4) & 1; /* overflow */\r
1491 fprintf (st, "%s %05o %o %08o %08o %08o ", cyc[h->typ & 3],\r
1492 h->pc, ov, h->a, h->b, h->x);\r
1493 if (h->ea & HIST_NOEA) fprintf (st, " ");\r
1494 else fprintf (st, "%05o ", h->ea);\r
1495 sim_eval = h->ir;\r
1496 if ((fprint_sym (st, h->pc, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)\r
1497 fprintf (st, "(undefined) %08o", h->ir);\r
1498 fputc ('\n', st); /* end line */\r
1499 } /* end else instruction */\r
1500 } /* end for */\r
1501return SCPE_OK;\r
1502}\r