First Commit of my working state
[simh.git] / Ibm1130 / ibm1130_cpu.c
CommitLineData
196ba1fc
PH
1/* ibm1130_cpu.c: IBM 1130 CPU simulator\r
2\r
3 Based on the SIMH package written by Robert M Supnik\r
4\r
5 * (C) Copyright 2002, Brian Knittel.\r
6 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r
7 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r
8 * usual yada-yada. Please keep this notice and the copyright in any distributions\r
9 * or modifications.\r
10 *\r
11 * This is not a supported product, but I welcome bug reports and fixes.\r
12 * Mail to simh@ibm1130.org\r
13\r
14 25-Jun-01 BLK Written\r
15 10-May-02 BLK Fixed bug in MDX instruction\r
16 27-Mar-02 BLK Made BOSC work even in short form\r
17 16-Aug-02 BLK Fixed bug in multiply instruction; didn't work with negative values\r
18 18-Mar-03 BLK Fixed bug in divide instruction; didn't work with negative values\r
19 23-Jul-03 BLK Prevented tti polling in CGI mode\r
20 24-Nov-03 BLK Fixed carry bit error in subtract and subtract double, found by Bob Flanders\r
21 20-Oct-04 BLK Changed "(unsigned int32)" to "(uint32)" to accomodate improved definitions of simh types\r
22 Also commented out my echo command as it's now a standard simh command\r
23 27-Nov-05 BLK Added Arithmetic Factor Register support per Carl Claunch (GUI only)\r
24 06-Dec-06 BLK Moved CGI stuff out of ibm1130_cpu.c\r
25\r
26>> To do: verify actual operands stored in ARF, need to get this from state diagrams in the schematic set\r
27 Also: determine how many bits are actually stored in the IAR in a real 1130, by forcing wraparound\r
28 and storing the IAR.\r
29\r
30 IBM 1800 support is just beginning. Mode set is done (SET CPU 1800 or SET CPU 1130).\r
31 Index registers are handled (1800 has real registers, 1130 uses core locations 1, 2 and 3 -- \r
32 but does the 1800 make its hardware index registers appear in the address space?)\r
33 Need to add: memory protect feature, more interrupt levels, GUI mods, IO device mods, timers, watchdog.\r
34 Memory protect was interesting -- they borrowed one of the two parity bits. XIO(0) on 1800 is used for\r
35 interval timers, console data switches, console sense/program select/CE switches, interrupt mask register,\r
36 programmed interrupt, console interrupt and operations monitor (watchdog)\r
37 very interesting stuff.\r
38\r
39 The register state for the IBM 1130 CPU is:\r
40\r
41 IAR instruction address register\r
42 ACC accumulator\r
43 EXT accumulator extension\r
44 Oflow overflow bit\r
45 Carry carry bit\r
46 CES console entry switches\r
47 ipl current interrupt level, -1 = non interrupt\r
48 iplpending bitmap of pending interrupts\r
49 wait_state current CPU state: running or waiting\r
50 DSW console run/stop switch device status word\r
51 RUNMODE processor step/run mode (may also imply IntRun)\r
52 BREAK breakpoint address\r
53 WRU simulator-break character\r
54 IntRun Int Run flag (causes level 5 interrupt after every instruction)\r
55 ILSW0..5 interrupt level status words\r
56 XR1, 2, 3 for IBM 1800 only, index registers 1, 2, and 3\r
57\r
58 The SAR (storage address register) and SBR (storage buffer register) are updated\r
59 but not saved in the CPU state; they matter only to the GUI.\r
60\r
61 Interrupt handling: interrupts occur when any device on any level has an\r
62 active interrupt. XIO commands can clear specific IRQ bits. When this\r
63 happens, we have to evaluate all devices on the same IRQ level for remaining\r
64 indicators. The flag int_req is set with a bit corresponding to the IRQ level\r
65 when any interrupt indicator is activated.\r
66\r
67 The 1130 console has a switch that controls several run modes: SS (single processor\r
68 step), SCLK (single clock step), SINST (single instruction step), INT_RUN\r
69 (IRQ 5 after each non interrupt-handler instruction) and RUN (normal operation).\r
70 This simulator does not implement SS and SCLK. The simulator GUI console handles\r
71 SINST, so we only have to worry about INT_RUN. The console command SET CPU IntRun sets\r
72 the tmode (trace mode) flag; this causes a level 5 interrupt after each\r
73 instruction.\r
74\r
75 The IBM 1130 instruction formats are\r
76\r
77 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ \r
78 | opcode | F| T | | general format\r
79 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
80\r
81 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
82 | opcode | 0| T | DISPLACEMENT | short instruction\r
83 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
84\r
85 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
86 | opcode | 1| T | I| MODIFIER | long instruction\r
87 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
88 | ADDRESS | \r
89 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
90\r
91 opcode in MSBits\r
92\r
93 F = format. 0 = short (1 word), 1 = long (2 word) instruction\r
94\r
95 T = Tag 00 = no index register (e.g. IAR relative)\r
96 01 = use index register 1 (e.g. core address 1 = M[1])\r
97 02 = use index register 2 (e.g. core address 2 = M[2])\r
98 03 = use index register 3 (e.g. core address 3 = M[3])\r
99\r
100 DISPLACEMENT = two's complement (must be sign-extended)\r
101\r
102 I = Indirect\r
103\r
104 Note that IAR = instruction address+1 when instruction is being decoded.\r
105\r
106 In normal addressing mode, effective address (EA) is computed as follows:\r
107\r
108 F = 0 T = 0 EA = IAR + DISPLACEMENT\r
109 0 1 IAR + DISPLACEMENT + M[1] \r
110 0 2 IAR + DISPLACEMENT + M[2]\r
111 0 3 IAR + DISPLACEMENT + M[3]\r
112\r
113 F = 1 T = 0 I = 0 EA = ADDRESS\r
114 1 1 0 ADDRESS + M[1]\r
115 1 2 0 ADDRESS + M[2]\r
116 1 3 0 ADDRESS + M[3]\r
117 1 0 1 M[ADDRESS]\r
118 1 1 1 M[ADDRESS + M[1]]\r
119 1 2 1 M[ADDRESS + M[2]]\r
120 1 3 1 M[ADDRESS + M[3]]\r
121\r
122 Loads or stores are then made to/from MEM[EA]. Some instructions have special\r
123 weird addressing modes. Simulator code precomputes standard addressing for\r
124 all instructions though it's not always used.\r
125\r
126 General notes:\r
127\r
128 Adding I/O devices requires modifications to three modules:\r
129\r
130 ibm1130_defs.h add interrupt request definitions\r
131 ibm1130_cpu.c add XIO command linkages\r
132 ibm1130_sys.c add to sim_devices array\r
133*/\r
134\r
135/* ------------------------------------------------------------------------\r
136 * Definitions\r
137 * ------------------------------------------------------------------------ */\r
138\r
139#include <stdarg.h>\r
140\r
141#include "ibm1130_defs.h"\r
142\r
143#define save_ibkpt (cpu_unit.u3) /* will be SAVEd */\r
144\r
145#define UPDATE_BY_TIMER\r
146#define ENABLE_BACKTRACE\r
147/* #define USE_MY_ECHO_CMD */ /* simh now has echo command built in */\r
148#define ENABLE_1800_SUPPORT /* define to enable support for 1800 CPU simulation mode */\r
149\r
150static void cgi_start(void);\r
151static void cgi_stop(t_stat reason);\r
152static int simh_status_to_stopcode (int status);\r
153\r
154/* hook pointers from scp.c */\r
155void (*sim_vm_init) (void) = &sim_init;\r
156extern char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream);\r
157extern void (*sim_vm_post) (t_bool from_scp);\r
158extern CTAB *sim_vm_cmd;\r
159\r
160/* space to store extra simulator-specific commands */\r
161#define MAX_EXTRA_COMMANDS 10\r
162CTAB x_cmds[MAX_EXTRA_COMMANDS];\r
163\r
164#ifdef _WIN32\r
165# define CRLF "\r\n"\r
166#else\r
167# define CRLF "\n"\r
168#endif\r
169\r
170/* ------------------------------------------------------------------------\r
171 * initializers for globals\r
172 * ------------------------------------------------------------------------ */\r
173\r
174#define SIGN_BIT(v) ((v) & 0x8000)\r
175#define DWSIGN_BIT(v) ((v) & 0x80000000)\r
176\r
177uint16 M[MAXMEMSIZE]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */\r
178uint16 ILSW[6] = {0,0,0,0,0,0}; /* interrupt level status words */\r
179uint16 XR[3] = {0,0,0}; /* IBM 1800 index registers */\r
180int32 IAR; /* instruction address register */\r
181int32 prev_IAR; /* instruction address register at start of current instruction */\r
182int32 SAR, SBR; /* storage address/buffer registers */\r
183int32 OP, TAG, CCC; /* instruction decoded pieces */\r
184int32 CES; /* console entry switches */\r
185int32 ACC, EXT; /* accumulator and extension */\r
186int32 ARF; /* arithmetic factor, a non-addressable internal CPU register */\r
187int32 RUNMODE; /* processor run/step mode */\r
188int32 ipl = -1; /* current interrupt level (-1 = not handling irq) */\r
189int32 iplpending = 0; /* interrupted IPL's */\r
190int32 tbit = 0; /* trace flag (causes level 5 IRQ after each instr) */\r
191int32 V = 0, C = 0; /* condition codes */\r
192int32 wait_state = 0; /* wait state (waiting for an IRQ) */\r
193int32 wait_lamp = TRUE; /* alternate indicator to light the wait lamp on the GUI */\r
194int32 int_req = 0; /* sum of interrupt request levels active */\r
195int32 int_lamps = 0; /* accumulated version of int_req - gives lamp persistence */\r
196int32 int_mask; /* current active interrupt mask (ipl sensitive) */\r
197int32 mem_mask; /* mask for memory address bits based on current memory size */\r
198int32 cpu_dsw = 0; /* CPU device status word */\r
199int32 ibkpt_addr = -1; /* breakpoint addr */\r
200int32 sim_gui = TRUE; /* enable gui */\r
201t_bool running = FALSE; /* TRUE if CPU is running */\r
202t_bool power = TRUE; /* TRUE if CPU power is on */\r
203t_bool cgi = FALSE; /* TRUE if we are running as a CGI program */\r
204t_bool cgiwritable = FALSE; /* TRUE if we can write the disk images back to the image file in CGI mode */\r
205t_bool is_1800 = FALSE; /* TRUE if we are simulating an IBM 1800 processor */\r
206t_stat reason; /* CPU execution loop control */\r
207\r
208static int32 int_masks[6] = {\r
209 0x00, 0x20, 0x30, 0x38, 0x3C, 0x3E /* IPL 0 is highest prio (sees no other interrupts) */\r
210};\r
211\r
212/* ------------------------------------------------------------------------\r
213 * Function declarations\r
214 * ------------------------------------------------------------------------ */\r
215\r
216t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
217t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
218t_stat cpu_reset (DEVICE *dptr);\r
219t_stat cpu_svc (UNIT *uptr);\r
220t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc);\r
221t_stat cpu_set_type (UNIT *uptr, int32 value, char *cptr, void *desc);\r
222void calc_ints (void);\r
223\r
224extern t_stat ts_wr (int32 data, int32 addr, int32 access);\r
225extern t_stat detach_cmd (int flags, char *cptr);\r
226extern UNIT cr_unit;\r
227extern int32 sim_switches;\r
228\r
229#ifdef ENABLE_BACKTRACE\r
230 static void archive_backtrace(char *inst);\r
231 static void reset_backtrace (void);\r
232 static void show_backtrace (int nshow);\r
233 static t_stat backtrace_cmd (int flag, char *cptr);\r
234#else\r
235 #define archive_backtrace(inst)\r
236 #define reset_backtrace()\r
237 #define show_backtrace(ntrace)\r
238#endif\r
239\r
240#ifdef GUI_SUPPORT\r
241# define ARFSET(v) ARF = (v) & 0xFFFF /* set Arithmetic Factor Register (used for display purposes only) */\r
242#else\r
243# define ARFSET(v) /* without GUI, no need for setting ARF */\r
244#endif\r
245\r
246static void init_console_window (void);\r
247static void destroy_console_window (void);\r
248static t_stat view_cmd (int flag, char *cptr);\r
249static t_stat cpu_attach (UNIT *uptr, char *cptr);\r
250static t_bool bsctest (int32 DSPLC, t_bool reset_V);\r
251static void exit_irq (void);\r
252static void trace_instruction (void);\r
253\r
254/* ------------------------------------------------------------------------\r
255 * CPU data structures:\r
256 * cpu_dev CPU device descriptor\r
257 * cpu_unit CPU unit descriptor\r
258 * cpu_reg CPU register list\r
259 * cpu_mod CPU modifier list\r
260 *\r
261 * The CPU is attachable; attaching a file to it write a log of instructions\r
262 * and registers\r
263 * ------------------------------------------------------------------------ */\r
264\r
265#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */\r
266#define UNIT_1800 (1 << (UNIT_V_UF + 0)) /* flag for 1800 mode */\r
267\r
268UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX | UNIT_BINK | UNIT_ATTABLE | UNIT_SEQ, INIMEMSIZE) };\r
269\r
270REG cpu_reg[] = {\r
271 { HRDATA (IAR, IAR, 32) },\r
272 { HRDATA (ACC, ACC, 32) },\r
273 { HRDATA (EXT, EXT, 32) },\r
274 { FLDATA (Oflow, V, 1) },\r
275 { FLDATA (Carry, C, 1) },\r
276 { HRDATA (CES, CES, 32) },\r
277 { HRDATA (ipl, ipl, 32), REG_RO },\r
278 { HRDATA (iplpending, iplpending, 32), REG_RO },\r
279 { HRDATA (wait_state, wait_state, 32)},\r
280 { HRDATA (DSW, cpu_dsw, 32), REG_RO },\r
281 { HRDATA (RUNMODE, RUNMODE, 32) },\r
282 { HRDATA (BREAK, ibkpt_addr, 32) },\r
283 { ORDATA (WRU, sim_int_char, 8) },\r
284 { FLDATA (IntRun, tbit, 1) },\r
285\r
286 { HRDATA (ILSW0, ILSW[0], 32), REG_RO },\r
287 { HRDATA (ILSW1, ILSW[1], 32), REG_RO },\r
288 { HRDATA (ILSW2, ILSW[2], 32), REG_RO },\r
289 { HRDATA (ILSW3, ILSW[3], 32), REG_RO },\r
290 { HRDATA (ILSW4, ILSW[4], 32), REG_RO },\r
291 { HRDATA (ILSW5, ILSW[5], 32), REG_RO },\r
292\r
293#ifdef ENABLE_1800_SUPPORT\r
294 { HRDATA (IS_1800, is_1800, 32), REG_RO|REG_HIDDEN}, /* is_1800 flag is part of state, but hidden */\r
295 { HRDATA (XR1, XR[0], 16), REG_RO|REG_HIDDEN}, /* index registers are unhidden if CPU set to 1800 mode */\r
296 { HRDATA (XR2, XR[1], 16), REG_RO|REG_HIDDEN},\r
297 { HRDATA (XR3, XR[2], 16), REG_RO|REG_HIDDEN},\r
298#endif\r
299\r
300 { HRDATA (ARF, ARF, 32) },\r
301 { NULL}\r
302};\r
303\r
304MTAB cpu_mod[] = {\r
305 { UNIT_MSIZE, 4096, NULL, "4KW", &cpu_set_size},\r
306 { UNIT_MSIZE, 8192, NULL, "8KW", &cpu_set_size},\r
307 { UNIT_MSIZE, 16384, NULL, "16KW", &cpu_set_size},\r
308 { UNIT_MSIZE, 32768, NULL, "32KW", &cpu_set_size},\r
309#ifdef ENABLE_1800_SUPPORT\r
310 { UNIT_1800, 0, "1130", "1130", &cpu_set_type},\r
311 { UNIT_1800, UNIT_1800, "1800", "1800", &cpu_set_type},\r
312#endif\r
313 { 0 } };\r
314\r
315DEVICE cpu_dev = {\r
316 "CPU", &cpu_unit, cpu_reg, cpu_mod,\r
317 1, 16, 16, 1, 16, 16,\r
318 &cpu_ex, &cpu_dep, &cpu_reset,\r
319 NULL, cpu_attach, NULL}; /* attaching to CPU creates cpu log file */\r
320\r
321/* ------------------------------------------------------------------------ \r
322 * Memory read/write -- save SAR and SBR on the way in and out\r
323 *\r
324 * (It can be helpful to set breakpoints on a = 1, 2, or 3 in these routines\r
325 * to detect attempts to read/set index registers using normal memory addessing.\r
326 * APL\1130 does this in some places, I think these are why it had to be modified\r
327 * to run on the 1800. Of course not all read/write to 1, 2 or implies an attempt\r
328 * to read/set and index register -- they could using the address in the normal way).\r
329 * ------------------------------------------------------------------------ */\r
330\r
331int32 ReadW (int32 a)\r
332{\r
333 SAR = a;\r
334 SBR = (int32) M[(a) & mem_mask];\r
335 return SBR;\r
336}\r
337\r
338void WriteW (int32 a, int32 d)\r
339{\r
340 SAR = a;\r
341 SBR = d;\r
342 M[a & mem_mask] = (int16) d;\r
343}\r
344\r
345/* ------------------------------------------------------------------------ \r
346 * read and write index registers. On the 1130, they're in core addresses 1, 2, 3.\r
347 * on the 1800, they're separate registers\r
348 * ------------------------------------------------------------------------ */\r
349\r
350static uint16 ReadIndex (int32 tag)\r
351{\r
352#ifdef ENABLE_1800_SUPPORT\r
353 if (is_1800)\r
354 return XR[tag-1]; /* 1800: fetch from register */\r
355#endif\r
356 \r
357 SAR = tag; /* 1130: ordinary read from memory (like ReadW) */\r
358 SBR = (int32) M[(tag) & mem_mask];\r
359 return SBR;\r
360}\r
361\r
362static void WriteIndex (int32 tag, int32 d)\r
363{\r
364#ifdef ENABLE_1800_SUPPORT\r
365 if (is_1800) {\r
366 XR[tag-1] = d; /* 1800: store in register */\r
367 return;\r
368 }\r
369#endif\r
370\r
371 SAR = tag; /* 1130: ordinary write to memory (same as WriteW) */\r
372 SBR = d;\r
373 M[tag & mem_mask] = (int16) d;\r
374}\r
375\r
376/* ------------------------------------------------------------------------ \r
377 * upcase - force a string to uppercase (ASCII)\r
378 * ------------------------------------------------------------------------ */\r
379\r
380char *upcase (char *str)\r
381{\r
382 char *s;\r
383\r
384 for (s = str; *s; s++) {\r
385 if (*s >= 'a' && *s <= 'z')\r
386 *s -= 32;\r
387 } \r
388\r
389 return str;\r
390}\r
391\r
392/* ------------------------------------------------------------------------ \r
393 * calc_ints - set appropriate bits in int_req if any interrupts are pending on given levels\r
394 *\r
395 * int_req:\r
396 * bit 5 4 3 2 1 0\r
397 * \ \ \ \ \ \\r
398 * \ \ \ \ \ interrupt level 5 pending (lowest priority)\r
399 * \ . . .\r
400 * interrupt level 0 pending (highest priority)\r
401 *\r
402 * int_mask is set according to current interrupt level (ipl)\r
403 *\r
404 * 0 0 0 0 0 0 ipl = 0 (currently servicing highest priority interrupt)\r
405 * 1 0 0 0 0 0 1\r
406 * 1 1 0 0 0 0 2\r
407 * 1 1 1 0 0 0 3\r
408 * 1 1 1 1 0 0 4\r
409 * 1 1 1 1 1 0 5 (currently servicing lowest priority interrupt)\r
410 * 1 1 1 1 1 1 -1 (not servicing an interrupt)\r
411 * ------------------------------------------------------------------------ */\r
412\r
413void calc_ints (void)\r
414{\r
415 register int i;\r
416 register int32 newbits = 0;\r
417\r
418 GUI_BEGIN_CRITICAL_SECTION /* using critical section here so we don't mislead the GUI thread */\r
419\r
420 for (i = 6; --i >= 0; ) {\r
421 newbits >>= 1;\r
422 if (ILSW[i])\r
423 newbits |= 0x20;\r
424 }\r
425\r
426 int_req = newbits;\r
427 int_lamps |= int_req;\r
428 int_mask = (ipl < 0) ? 0xFFFF : int_masks[ipl]; /* be sure this is set correctly */\r
429\r
430 GUI_END_CRITICAL_SECTION\r
431}\r
432\r
433/* ------------------------------------------------------------------------\r
434 * instruction processor\r
435 * ------------------------------------------------------------------------ */\r
436\r
437#define INCREMENT_IAR IAR = (IAR + 1) & mem_mask\r
438#define DECREMENT_IAR IAR = (IAR - 1) & mem_mask\r
439\r
440void bail (char *msg)\r
441{\r
442 printf("%s\n", msg);\r
443 exit(1);\r
444}\r
445\r
446static void weirdop (char *msg, int offset)\r
447{\r
448 printf("Weird opcode: %s at %04x\n", msg, IAR+offset);\r
449}\r
450\r
451static char *xio_devs[] = {\r
452 "0?", "console", "1142card", "1134papertape",\r
453 "dsk0", "1627plot", "1132print", "switches",\r
454 "1231omr", "2501card", "comm", "b?",\r
455 "sys7", "d?", "e?", "f?",\r
456 "10?", "dsk1", "dsk2", "dsk3",\r
457 "dsk4", "dsk5", "dsk6", "dsk7+",\r
458 "18?", "2250disp", "2741attachment", "1b",\r
459 "1c?", "1d?", "1e?", "1f?"\r
460};\r
461\r
462static char *xio_funcs[] = {\r
463 "0?", "write", "read", "sense_irq",\r
464 "control", "initw", "initr", "sense"\r
465};\r
466\r
467t_stat sim_instr (void)\r
468{\r
469 extern int32 sim_interval;\r
470 extern UNIT *sim_clock_queue;\r
471 int32 i, eaddr, INDIR, IR, F, DSPLC, word2, oldval, newval, src, src2, dst, abit, xbit;\r
472 int32 iocc_addr, iocc_op, iocc_dev, iocc_func, iocc_mod;\r
473 char msg[50];\r
474 int cwincount = 0, status;\r
475 static long ninstr = 0;\r
476 static char *intlabel[] = {"INT0","INT1","INT2","INT3","INT4","INT5"};\r
477\r
478 if (cgi) /* give CGI hook function a chance to do something */\r
479 cgi_start();\r
480\r
481 if (running) /* this is definitely not reentrant */\r
482 return -1;\r
483\r
484 if (! power) /* this matters only to the GUI */\r
485 return STOP_POWER_OFF;\r
486\r
487 running = TRUE;\r
488\r
489 mem_mask = MEMSIZE - 1; /* set other useful variables */\r
490 calc_ints();\r
491\r
492 /* Main instruction fetch/decode loop */\r
493\r
494 reason = 0;\r
495 wait_lamp = 0; /* release lock on wait lamp */\r
496\r
497#ifdef GUI_SUPPORT\r
498 update_gui(TRUE);\r
499 gui_run(TRUE);\r
500#endif\r
501\r
502 while (reason == 0) {\r
503 IAR &= mem_mask;\r
504\r
505#ifdef GUI_SUPPORT\r
506#ifndef UPDATE_BY_TIMER\r
507#if (UPDATE_INTERVAL > 0)\r
508 if (--cwincount <= 0) {\r
509 update_gui(FALSE); /* update console lamps only every so many instructions */\r
510 cwincount = UPDATE_INTERVAL + (rand() % MIN(UPDATE_INTERVAL, 32));\r
511 }\r
512#else\r
513 update_gui(FALSE);\r
514#endif /* ifdef UPDATE_INTERVAL */\r
515#endif /* ifndef UPDATE_BY_TIMER */\r
516#endif /* ifdef GUI_SUPPORT */\r
517\r
518 if (sim_interval <= 0) { /* any events timed out? */\r
519 if (sim_clock_queue != NULL) {\r
520 if ((status = sim_process_event()) != 0)\r
521 reason = simh_status_to_stopcode(status);\r
522\r
523 calc_ints();\r
524 continue;\r
525 }\r
526 }\r
527\r
528 if (int_req & int_mask) { /* any pending interrupts? */\r
529 for (i = 0; i <= 5; i++) /* find highest pending interrupt */\r
530 if ((int_req & int_mask) & (0x20 >> i))\r
531 break;\r
532\r
533 if (i >= 6) { /* nothing to do? */\r
534 calc_ints(); /* weird. recalculate */\r
535 continue; /* back to fetch */\r
536 }\r
537\r
538 GUI_BEGIN_CRITICAL_SECTION\r
539\r
540 if (ipl >= 0) /* save previous IPL in bit stack */\r
541 iplpending |= (0x20 >> ipl);\r
542\r
543 ipl = i; /* set new interrupt level */\r
544 int_mask = int_masks[i]; /* set appropriate mask */\r
545\r
546 GUI_END_CRITICAL_SECTION\r
547\r
548 wait_state = 0; /* exit wait state */\r
549 eaddr = ReadW(8+i); /* get IRQ vector */\r
550 archive_backtrace(intlabel[i]);\r
551 WriteW(eaddr, IAR); /* save IAR */\r
552 IAR = (eaddr+1) & mem_mask; /* go to next address */\r
553 continue; /* now continue processing */\r
554 } /* end if int_req */\r
555\r
556 if (wait_state) { /* waiting? */\r
557 sim_interval = 0; /* run the clock out */\r
558\r
559 if (sim_qcount() <= (cgi ? 0 : 1)) { /* one routine queued? we're waiting for keyboard only */\r
560 if (keyboard_is_busy()) { /* we are actually waiting for a keystroke */\r
561 if ((status = sim_process_event()) != SCPE_OK) /* get it with wait_state still set */\r
562 reason = simh_status_to_stopcode(status);\r
563 }\r
564 else { /* CPU is not expecting a keystroke (keyboard interrupt) */\r
565 if (wait_state == WAIT_OP)\r
566 reason = STOP_WAIT; /* end the simulation */\r
567 else\r
568 reason = STOP_INVALID_INSTR;\r
569 }\r
570 }\r
571\r
572 if (gdu_active()) /* but don't stop simulator if 2250 GDU is running */\r
573 reason = 0;\r
574\r
575 continue;\r
576 }\r
577\r
578 if (IAR == ibkpt_addr) { /* simulator breakpoint? */\r
579 save_ibkpt = ibkpt_addr; /* save bkpt */\r
580 ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */\r
581 sim_activate(&cpu_unit, 1); /* sched re-enable after next instruction */\r
582 reason = STOP_IBKPT; /* stop simulation */\r
583 cwincount = 0;\r
584 continue;\r
585 }\r
586\r
587 ninstr++;\r
588 if (cpu_unit.flags & UNIT_ATT)\r
589 trace_instruction(); /* log CPU details if logging is enabled */\r
590\r
591 prev_IAR = IAR; /* save IAR before incrementing it */\r
592\r
593 IR = ReadW(IAR); /* fetch 1st word of instruction */\r
594 INCREMENT_IAR;\r
595 sim_interval = sim_interval - 1; /* this constitutes one tick of the simulation clock */\r
596\r
597 OP = (IR >> 11) & 0x1F; /* opcode */\r
598 F = IR & 0x0400; /* format bit: 1 = long instr */\r
599 TAG = IR & 0x0300; /* tag bits: index reg x */\r
600 if (TAG)\r
601 TAG >>= 8;\r
602\r
603 /* here I compute the usual effective address on the assumption that the instruction will need it. Some don't. */\r
604\r
605 if (F) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */\r
606 INDIR = IR & 0x0080; /* indirect bit */\r
607 DSPLC = IR & 0x007F; /* displacement or modifier */\r
608 if (DSPLC & 0x0040)\r
609 DSPLC |= ~ 0x7F; /* sign extend */\r
610\r
611 word2 = ReadW(IAR); /* get reference address */\r
612 INCREMENT_IAR; /* bump the instruction address register */\r
613\r
614 eaddr = word2; /* assume standard addressing & compute effective address */\r
615 if (TAG) /* if indexed */\r
616 eaddr += ReadIndex(TAG); /* add index register value */\r
617 if (INDIR) /* if indirect addressing */\r
618 eaddr = ReadW(eaddr); /* pick up referenced address */\r
619 }\r
620 else { /* short instruction, use displacement */\r
621 INDIR = 0; /* never indirect */\r
622 DSPLC = IR & 0x00FF; /* get displacement */\r
623 if (DSPLC & 0x0080)\r
624 DSPLC |= ~ 0xFF;\r
625\r
626 if (TAG) /* if indexed */\r
627 eaddr = ReadIndex(TAG) + DSPLC; /* add index register value */\r
628 else\r
629 eaddr = IAR + DSPLC; /* otherwise relative to IAR after fetch */\r
630 }\r
631\r
632 switch (OP) { /* decode instruction */\r
633 case 0x01: /* --- XIO --- */\r
634 iocc_addr = ReadW(eaddr); /* get IOCC packet */\r
635 iocc_op = ReadW(eaddr|1); /* note 'or' not plus, address must be even for proper operation */\r
636\r
637 iocc_dev = (iocc_op >> 11) & 0x001F;\r
638 iocc_func = (iocc_op >> 8) & 0x0007;\r
639 iocc_mod = iocc_op & 0x00FF;\r
640\r
641 if (cpu_unit.flags & UNIT_ATT)\r
642 trace_io("* XIO %s %s mod %02x addr %04x", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr);\r
643\r
644/* fprintf(stderr, "* XIO %s %s mod %02x addr %04x\n", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); */\r
645\r
646 ACC = 0; /* ACC is destroyed, and default XIO_SENSE_DEV result is 0 */\r
647\r
648 switch (iocc_func) {\r
649 case XIO_UNUSED:\r
650 sprintf(msg, "Unknown op %x on device %02x", iocc_func, iocc_dev);\r
651 xio_error(msg);\r
652 break;\r
653 \r
654 case XIO_SENSE_IRQ: /* examine current Interrupt Level Status Word */\r
655 ACC = (ipl >= 0) ? ILSW[ipl] : 0;\r
656 break;\r
657 \r
658 default: /* perform device-specific operation */\r
659 switch (iocc_dev) {\r
660 case 0x01: /* console keyboard and printer */\r
661 xio_1131_console(iocc_addr, iocc_func, iocc_mod);\r
662 break;\r
663 case 0x02: /* 1142 card reader/punch */\r
664 xio_1142_card(iocc_addr, iocc_func, iocc_mod);\r
665 break;\r
666 case 0x03: /* 1134 paper tape reader/punch */\r
667 xio_1134_papertape(iocc_addr, iocc_func, iocc_mod);\r
668 break;\r
669 case 0x04: /* CPU disk storage */\r
670 xio_disk(iocc_addr, iocc_func, iocc_mod, 0);\r
671 break;\r
672 case 0x05: /* 1627 plotter */\r
673 xio_1627_plotter(iocc_addr, iocc_func, iocc_mod);\r
674 break;\r
675 case 0x06: /* 1132 Printer */\r
676 xio_1132_printer(iocc_addr, iocc_func, iocc_mod);\r
677 break;\r
678 case 0x07: /* console switches, stop key, run mode */\r
679 xio_1131_switches(iocc_addr, iocc_func, iocc_mod);\r
680 break;\r
681 case 0x08: /* 1231 optical mark reader */\r
682 xio_1231_optical(iocc_addr, iocc_func, iocc_mod);\r
683 break;\r
684 case 0x09: /* 2501 card reader */\r
685 xio_2501_card(iocc_addr, iocc_func, iocc_mod);\r
686 break;\r
687 case 0x0a: /* synchronous comm adapter */\r
688 xio_sca(iocc_addr, iocc_func, iocc_mod);\r
689 break;\r
690 case 0x0c: /* IBM System/7 interprocessor link */\r
691 xio_system7(iocc_addr, iocc_func, iocc_mod);\r
692 break;\r
693 case 0x11: /* 2310 Disk Storage, Drive 1, or 2311 Disk Storage Drive. Drive 1, Disk 1 */\r
694 xio_disk(iocc_addr, iocc_func, iocc_mod, 1);\r
695 break;\r
696 case 0x12: /* 2310 Disk Storage, Drive 2, or 2311 Disk Storage Drive. Drive 1, Disk 2 */\r
697 xio_disk(iocc_addr, iocc_func, iocc_mod, 2);\r
698 break;\r
699 case 0x13: /* 2310 Disk Storage, Drive 3, or 2311 Disk Storage Drive. Drive 1, Disk 3 */\r
700 xio_disk(iocc_addr, iocc_func, iocc_mod, 3);\r
701 break;\r
702 case 0x14: /* 2310 Disk Storage, Drive 4, or 2311 Disk Storage Drive. Drive 1, Disk 4 */\r
703 xio_disk(iocc_addr, iocc_func, iocc_mod, 4);\r
704 break;\r
705 case 0x15: /* 1403 Printer */\r
706 xio_1403_printer(iocc_addr, iocc_func, iocc_mod);\r
707 break;\r
708 case 0x16: /* 2311 Disk Storage Drive. Drive 1, Disk 5 */\r
709 xio_disk(iocc_addr, iocc_func, iocc_mod, -1);\r
710 break;\r
711 case 0x17: /* 2311 Disk Storage Drive, Drive 2, Disk 1 through 5 */\r
712 xio_disk(iocc_addr, iocc_func, iocc_mod, -1);\r
713 break;\r
714 case 0x19: /* 2250 Display Unit */\r
715 xio_2250_display(iocc_addr, iocc_func, iocc_mod);\r
716 break;\r
717 case 0x1a: /* 2741 Attachment (nonstandard serial interface used by APL\1130 */\r
718 xio_t2741_terminal(iocc_addr, iocc_func, iocc_mod);\r
719 break;\r
720 default:\r
721 sprintf(msg, "unknown device %02x", iocc_dev);\r
722 xio_error(msg);\r
723 break;\r
724 }\r
725 }\r
726\r
727 calc_ints(); /* after every XIO, reset int_mask just in case */\r
728 break;\r
729\r
730 case 0x02: /* --- SLA,SLT,SLC,SLCA,NOP - Shift Left family --- */\r
731 if (F) {\r
732 weirdop("Long Left Shift", -2);\r
733 DECREMENT_IAR;\r
734 }\r
735\r
736 CCC = ((TAG == 0) ? DSPLC : ReadIndex(TAG)) & 0x003F;\r
737 ARFSET(CCC);\r
738 if (CCC == 0)\r
739 break; /* shift of zero is a NOP */\r
740\r
741 switch (IR & 0x00C0) {\r
742 case 0x0040: /* SLCA */\r
743 if (TAG) {\r
744 while (CCC > 0 && (ACC & 0x8000) == 0) {\r
745 ACC <<= 1;\r
746 CCC--;\r
747 }\r
748 C = (CCC != 0);\r
749 WriteIndex(TAG, (ReadIndex(TAG) & 0xFF00) | CCC); /* put low 6 bits back into index register and zero bits 8 and 9 */\r
750 break;\r
751 }\r
752 /* if TAG == 0, fall through and treat like normal shift SLA */\r
753\r
754 case 0x0000: /* SLA */\r
755 while (CCC > 0) {\r
756 C = (ACC & 0x8000);\r
757 ACC = (ACC << 1) & 0xFFFF;\r
758 CCC--;\r
759 }\r
760 break;\r
761\r
762 case 0x00C0: /* SLC */\r
763 if (TAG) {\r
764 while (CCC > 0 && (ACC & 0x8000) == 0) {\r
765 abit = (EXT & 0x8000) >> 15;\r
766 ACC = ((ACC << 1) & 0xFFFF) | abit;\r
767 EXT = (EXT << 1);\r
768 CCC--;\r
769 }\r
770 C = (CCC != 0);\r
771 WriteIndex(TAG, ReadIndex(TAG) & 0xFF00 | CCC); /* put 6 bits back into low byte of index register */\r
772 break;\r
773 }\r
774 /* if TAG == 0, fall through and treat like normal shift SLT */\r
775\r
776 case 0x0080: /* SLT */\r
777 while (CCC > 0) {\r
778 C = (ACC & 0x8000);\r
779 abit = (EXT & 0x8000) >> 15;\r
780 ACC = ((ACC << 1) & 0xFFFF) | abit;\r
781 EXT = (EXT << 1) & 0xFFFF;\r
782 CCC--;\r
783 }\r
784 break;\r
785\r
786 default:\r
787 bail("SLA switch, can't happen");\r
788 break;\r
789 }\r
790 break;\r
791\r
792 case 0x03: /* --- SRA, SRT, RTE - Shift Right family --- */\r
793 if (F) {\r
794 weirdop("Long Right Shift", -2);\r
795 DECREMENT_IAR;\r
796 }\r
797\r
798 CCC = ((TAG == 0) ? DSPLC : ReadIndex(TAG)) & 0x3F;\r
799 ARFSET(CCC);\r
800 if (CCC == 0)\r
801 break; /* NOP */\r
802\r
803 switch (IR & 0x00C0) {\r
804 case 0x0000: /* SRA */\r
805 ACC = (CCC < 16) ? ((ACC & 0xFFFF) >> CCC) : 0;\r
806 CCC = 0;\r
807 break;\r
808\r
809 case 0x0040: /* invalid */\r
810 wait_state = WAIT_INVALID_OP;\r
811 break;\r
812\r
813 case 0x0080: /* SRT */\r
814 while (CCC > 0) {\r
815 xbit = (ACC & 0x0001) << 15;\r
816 abit = (ACC & 0x8000);\r
817 ACC = (ACC >> 1) & 0x7FFF | abit;\r
818 EXT = (EXT >> 1) & 0x7FFF | xbit;\r
819 CCC--;\r
820 }\r
821 break;\r
822\r
823 case 0x00C0: /* RTE */\r
824 while (CCC > 0) {\r
825 abit = (EXT & 0x0001) << 15;\r
826 xbit = (ACC & 0x0001) << 15;\r
827 ACC = (ACC >> 1) & 0x7FFF | abit;\r
828 EXT = (EXT >> 1) & 0x7FFF | xbit;\r
829 CCC--;\r
830 }\r
831 break;\r
832\r
833 default:\r
834 bail("SRA switch, can't happen");\r
835 break;\r
836 }\r
837 break;\r
838\r
839 case 0x04: /* --- LDS - Load Status --- */\r
840 if (F) { /* never fetches second word? */\r
841 weirdop("Long LDS", -2);\r
842 DECREMENT_IAR;\r
843 }\r
844\r
845 V = (DSPLC & 1);\r
846 C = (DSPLC & 2) >> 1;\r
847 break;\r
848\r
849 case 0x05: /* --- STS - Store Status --- */\r
850 newval = ReadW(eaddr) & 0xFF00;\r
851 if (C)\r
852 newval |= 2;\r
853 if (V)\r
854 newval |= 1;\r
855\r
856 WriteW(eaddr, newval);\r
857 C = V = 0; /* clear flags after storing */\r
858 break;\r
859\r
860 case 0x06: /* --- WAIT --- */\r
861 wait_state = WAIT_OP;\r
862 if (F) { /* what happens if we use long format? */\r
863 weirdop("Long WAIT", -2);\r
864 DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word? */\r
865 }\r
866 break;\r
867\r
868 case 0x08: /* --- BSI - Branch and store IAR --- */\r
869 if (F) {\r
870 if (bsctest(IR, F)) /* do standard BSC long format testing */\r
871 break; /* if any condition is true, do nothing */\r
872 }\r
873 WriteW(eaddr, IAR); /* do subroutine call */\r
874 archive_backtrace("BSI"); /* save info in back-trace buffer */\r
875 IAR = (eaddr + 1) & mem_mask;\r
876 break;\r
877\r
878 case 0x09: /* --- BSC - Branch and skip on Condition --- */\r
879 if (F) {\r
880 if (bsctest(IR, F)) /* long format; any indicator cancels branch */\r
881 break;\r
882\r
883 archive_backtrace((DSPLC & 0x40) ? "BOSC" : "BSC"); /* save info in back-trace buffer */\r
884 IAR = eaddr; /* no indicator means branch taken */\r
885 }\r
886 else { /* short format: skip if any indicator hits */\r
887 if (bsctest(IR, F)) {\r
888 archive_backtrace((DSPLC & 0x40) ? "BOSC" : "BSC"); /* save info in back-trace buffer */\r
889 INCREMENT_IAR;\r
890 }\r
891 }\r
892/* 27Mar02: moved this test out of the (F) condition; BOSC works even in the\r
893 * short form. The displacement field in this instruction is always the set of\r
894 * condition bits, and the interrupt clear bit doesn't collide. */\r
895\r
896 if (DSPLC & 0x40) { /* BOSC = exit from interrupt handler */\r
897 exit_irq();\r
898 cwincount = 0;\r
899 }\r
900 break;\r
901\r
902 case 0x0c: /* --- LDX - Load Index --- */\r
903 if (F)\r
904 eaddr = (INDIR) ? ReadW(word2) : word2;\r
905 else\r
906 eaddr = DSPLC;\r
907\r
908 if (TAG)\r
909 WriteIndex(TAG, eaddr);\r
910 else {\r
911 archive_backtrace("LDX"); /* save info in back-trace buffer */\r
912 IAR = eaddr; /* what happens in short form? can onlyjump to low addresses? */\r
913 }\r
914 break;\r
915\r
916 case 0x0d: /* --- STX - Store Index --- */\r
917 if (F) { /* compute EA without any indexing */\r
918 eaddr = (INDIR) ? ReadW(word2) : word2;\r
919 }\r
920 else {\r
921 eaddr = IAR + DSPLC;\r
922 }\r
923 WriteW(eaddr, TAG ? ReadIndex(TAG) : IAR);\r
924 break;\r
925\r
926 case 0x0e: /* --- MDX - Modify Index and Skip --- */\r
927 if (F) { /* long format: adjust memory location */\r
928 if (TAG) {\r
929 oldval = ReadIndex(TAG); /* add word2 to index */\r
930 newval = oldval + (INDIR ? ReadW(word2) : word2);\r
931 WriteIndex(TAG, newval);\r
932 }\r
933 else {\r
934 oldval = ReadW(word2);\r
935 DSPLC = IR & 0x00FF; /* use extended displacement (no INDIR bit, it's is part of displacement in this op) */\r
936 if (DSPLC & 0x0080)\r
937 DSPLC |= ~ 0xFF;\r
938 newval = oldval + DSPLC; /* add modifier to @word2 */\r
939 WriteW(word2, newval);\r
940 }\r
941 }\r
942 else { /* short format: adust IAR or index */\r
943 if (TAG) {\r
944 oldval = ReadIndex(TAG); /* add displacement to index */\r
945 newval = oldval + DSPLC;\r
946 WriteIndex(TAG, newval);\r
947 }\r
948 else {\r
949 oldval = IAR; /* add displacement to IAR */\r
950 newval = IAR + DSPLC;\r
951 archive_backtrace("MDX");\r
952 IAR = newval & mem_mask;\r
953 }\r
954 }\r
955\r
956 if ((F || TAG) && (((newval & 0xFFFF) == 0) || ((oldval & 0x8000) != (newval & 0x8000)))) {\r
957 archive_backtrace("SKP");\r
958 INCREMENT_IAR; /* skip if index sign change or zero */\r
959 }\r
960 break;\r
961\r
962 case 0x10: /* --- A - Add --- */\r
963 /* in adds and subtracts, carry is set or cleared, overflow is set only */\r
964 src = ReadW(eaddr);\r
965 ARFSET(src);\r
966 src2 = ACC;\r
967 ACC = (ACC + src) & 0xFFFF;\r
968\r
969 C = ACC < src;\r
970 if (! V)\r
971 V = SIGN_BIT((~src ^ src2) & (src ^ ACC));\r
972 break;\r
973\r
974 case 0x11: /* --- AD - Add Double --- */\r
975 src = ((ACC << 16) | (EXT & 0xFFFF));\r
976 ARFSET(EXT);\r
977 src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1);\r
978 dst = src + src2;\r
979 ACC = (dst >> 16) & 0xFFFF;\r
980 EXT = dst & 0xFFFF;\r
981\r
982 C = (uint32) dst < (uint32) src;\r
983 if (! V)\r
984 V = DWSIGN_BIT((~src ^ src2) & (src ^ dst));\r
985 break;\r
986\r
987 case 0x12: /* --- S - Subtract --- */\r
988 src = ACC;\r
989 ARFSET(src);\r
990 src2 = ReadW(eaddr);\r
991 ACC = (ACC-src2) & 0xFFFF;\r
992\r
993 C = src < src2;\r
994 if (! V)\r
995 V = SIGN_BIT((src ^ src2) & (src ^ ACC));\r
996 break;\r
997\r
998 case 0x13: /* --- SD - Subtract Double --- */\r
999 src = ((ACC << 16) | (EXT & 0xFFFF));\r
1000 ARFSET(EXT);\r
1001 src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1);\r
1002 dst = src - src2;\r
1003 ACC = (dst >> 16) & 0xFFFF;\r
1004 EXT = dst & 0xFFFF;\r
1005\r
1006 C = (uint32) src < (uint32) src2;\r
1007 if (! V)\r
1008 V = DWSIGN_BIT((src ^ src2) & (src ^ dst));\r
1009 break;\r
1010\r
1011 case 0x14: /* --- M - Multiply --- */\r
1012 if ((src = ACC & 0xFFFF) & 0x8000) /* sign extend the values */\r
1013 src |= ~0xFFFF;\r
1014 if ((src2 = ReadW(eaddr)) & 0x8000)\r
1015 src2 |= ~0xFFFF;\r
1016\r
1017 ARFSET(src2);\r
1018 dst = src * src2;\r
1019 ACC = (dst >> 16) & 0xFFFF; /* split the results */\r
1020 EXT = dst & 0xFFFF;\r
1021 break;\r
1022\r
1023 case 0x15: /* --- D - Divide --- */\r
1024 src = ((ACC << 16) | (EXT & 0xFFFF));\r
1025 if ((src2 = ReadW(eaddr)) & 0x8000)\r
1026 src2 |= ~0xFFFF; /* oops: sign extend was missing, fixed 18Mar03 */\r
1027\r
1028 ARFSET(src2);\r
1029\r
1030 if (src2 == 0)\r
1031 V = 1; /* divide by zero just sets overflow, ACC & EXT are undefined */\r
1032 else {\r
1033 ACC = (src / src2) & 0xFFFF;\r
1034 EXT = (src % src2) & 0xFFFF;\r
1035 }\r
1036 break;\r
1037\r
1038 case 0x18: /* --- LD - Load ACC --- */\r
1039 ACC = ReadW(eaddr);\r
1040 break;\r
1041\r
1042 case 0x19: /* --- LDD - Load Double --- */\r
1043 ACC = ReadW(eaddr);\r
1044 EXT = ReadW(eaddr|1); /* notice address is |1 not +1 */\r
1045 break;\r
1046\r
1047 case 0x1a: /* --- STO - Store ACC --- */\r
1048 WriteW(eaddr, ACC);\r
1049 break;\r
1050\r
1051 case 0x1b: /* --- STD - Store Double --- */\r
1052 WriteW(eaddr|1, EXT);\r
1053 WriteW(eaddr, ACC); /* order is important: if odd addr, only ACC is stored */\r
1054 break;\r
1055\r
1056 case 0x1c: /* --- AND - Logical AND --- */\r
1057 src = ReadW(eaddr); \r
1058 ARFSET(src);\r
1059 ACC &= src;\r
1060 break;\r
1061\r
1062 case 0x1d: /* --- OR - Logical OR --- */\r
1063 src = ReadW(eaddr); \r
1064 ARFSET(src);\r
1065 ACC |= src;\r
1066 break;\r
1067\r
1068 case 0x1e: /* --- EOR - Logical Excl OR --- */\r
1069 src = ReadW(eaddr); \r
1070 ARFSET(src);\r
1071 ACC ^= src;\r
1072 break;\r
1073\r
1074 case 0x16:\r
1075 case 0x17:\r
1076#ifdef ENABLE_1800_SUPPORT\r
1077 if (is_1800) {\r
1078 if (OP == 0x16) { /* --- CMP - Compare --- */\r
1079 src = ACC; /* like subtract but result isn't stored */\r
1080 src2 = ReadW(eaddr);\r
1081 dst = (ACC-src2) & 0xFFFF;\r
1082 C = src < src2;\r
1083\r
1084 if (dst & 0x8000) /* if ACC < operand, skip 1 instruction */\r
1085 IAR = IAR+1;\r
1086 else if ((dst & 0xFFFF) == 0) /* if ACC == operand, skip 2 instructions */\r
1087 IAR = IAR+2;\r
1088 }\r
1089 else { /* --- DCMP - Compare Double --- */\r
1090 src = ((ACC << 16) | (EXT & 0xFFFF));\r
1091 src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1);\r
1092 dst = src - src2;\r
1093 C = (uint32) src < (uint32) src2;\r
1094\r
1095 if (dst & 0x80000000) /* if ACC_EXT < operand, skip 1 instruction */\r
1096 IAR = IAR+1;\r
1097 else if (dst == 0) /* if ACC_EXT == operand, skip 2 instructions */\r
1098 IAR = IAR+2;\r
1099 }\r
1100\r
1101 break; /* these are legal instructions on the 1800 */\r
1102 }\r
1103#endif\r
1104 /* 1130: these are not legal instructions, fall through */\r
1105\r
1106 default:\r
1107/* all invalid instructions act like waits */\r
1108/* case 0x00: */\r
1109/* case 0x07: */\r
1110/* case 0x0a: */\r
1111/* case 0x0b: */\r
1112/* case 0x0e: */\r
1113/* case 0x0f: */\r
1114/* case 0x1f: */\r
1115 wait_state = WAIT_INVALID_OP;\r
1116 if (F)\r
1117 DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word? */\r
1118\r
1119 break;\r
1120 } /* end instruction decode switch */\r
1121\r
1122 if (RUNMODE != MODE_RUN && RUNMODE != MODE_INT_RUN)\r
1123 reason = STOP_WAIT;\r
1124\r
1125 if (tbit && (ipl < 0)) { /* if INT_RUN mode, set IRQ5 after this instr */\r
1126 GUI_BEGIN_CRITICAL_SECTION\r
1127 SETBIT(cpu_dsw, CPU_DSW_INT_RUN);\r
1128 SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);\r
1129 int_req |= INT_REQ_5;\r
1130 GUI_END_CRITICAL_SECTION\r
1131 }\r
1132 } /* end main loop */\r
1133\r
1134#ifdef GUI_SUPPORT\r
1135 gui_run(FALSE);\r
1136#endif\r
1137\r
1138 running = FALSE;\r
1139 int_lamps = 0; /* display only currently active interrupts while halted */\r
1140\r
1141 if (reason == STOP_WAIT || reason == STOP_INVALID_INSTR) {\r
1142 wait_state = 0; /* on resume, don't wait */\r
1143 wait_lamp = TRUE; /* but keep the lamp lit on the GUI */\r
1144\r
1145 CLRBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP); /* and on resume, reset program start bit */\r
1146 if ((cpu_dsw & CPU_DSW_PROGRAM_STOP) == 0)\r
1147 CLRBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);\r
1148 }\r
1149\r
1150 if (cgi) /* give CGI hook function a chance to do something */\r
1151 cgi_stop(reason);\r
1152\r
1153 return reason;\r
1154}\r
1155\r
1156/*\r
1157 * simh_status_to_stopcode - convert a SCPE_xxx value from sim_process_event into a STOP_xxx code\r
1158 */\r
1159 \r
1160static int simh_status_to_stopcode (int status)\r
1161{\r
1162 return (status == SCPE_BREAK) ? STOP_BREAK :\r
1163 (status == SCPE_STOP) ? STOP_IMMEDIATE :\r
1164 (status == SCPE_STEP) ? STOP_STEP : STOP_OTHER;\r
1165}\r
1166\r
1167/* ------------------------------------------------------------------------ \r
1168 * bsctest - perform standard set of condition tests. We return TRUE if any\r
1169 * of the condition bits specified in DSPLC test positive, FALSE if none are true.\r
1170 * If reset_V is TRUE, we reset the oVerflow flag after testing it.\r
1171 * ------------------------------------------------------------------------ */\r
1172\r
1173static t_bool bsctest (int32 DSPLC, t_bool reset_V)\r
1174{\r
1175 if (DSPLC & 0x01) { /* Overflow off (note inverted sense) */\r
1176 if (! V)\r
1177 return TRUE;\r
1178 else if (reset_V) /* reset after testing */\r
1179 V = 0;\r
1180 }\r
1181\r
1182 if (DSPLC & 0x02) { /* Carry off (note inverted sense) */\r
1183 if (! C)\r
1184 return TRUE;\r
1185 }\r
1186\r
1187 if (DSPLC & 0x04) /* Even */\r
1188 if ((ACC & 1) == 0)\r
1189 return TRUE;\r
1190\r
1191 if (DSPLC & 0x08) /* Positive */\r
1192 if ((ACC & 0x8000) == 0 && ACC != 0)\r
1193 return TRUE;\r
1194\r
1195 if (DSPLC & 0x10) /* Negative */\r
1196 if (ACC & 0x8000)\r
1197 return TRUE;\r
1198\r
1199 if (DSPLC & 0x20) /* Zero */\r
1200 if ((ACC & 0xFFFF) == 0)\r
1201 return TRUE;\r
1202\r
1203 return FALSE;\r
1204}\r
1205\r
1206/* ------------------------------------------------------------------------ \r
1207 * exit_irq - pop interrupt stack as part of return from subroutine (BOSC) \r
1208 * ------------------------------------------------------------------------ */\r
1209\r
1210static void exit_irq (void)\r
1211{\r
1212 int i, bit;\r
1213 \r
1214 GUI_BEGIN_CRITICAL_SECTION\r
1215\r
1216 if (ipl == 5 && tbit) { /* if we are exiting an INT_RUN interrupt, clear it for the next instruction */\r
1217 CLRBIT(cpu_dsw, CPU_DSW_INT_RUN);\r
1218 if ((cpu_dsw & CPU_DSW_PROGRAM_STOP) == 0)\r
1219 CLRBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);\r
1220 }\r
1221\r
1222 ipl = -1; /* default: return to main processor level */\r
1223 int_mask = 0xFFFF;\r
1224\r
1225 if (iplpending) { /* restore previous interrupt status */\r
1226 for (i = 0, bit = 0x20; i < 6; i++, bit >>= 1) {\r
1227 if (iplpending & bit) {\r
1228 iplpending &= ~bit;\r
1229 ipl = i;\r
1230 int_mask = int_masks[i];\r
1231 break;\r
1232 }\r
1233 }\r
1234 }\r
1235 GUI_END_CRITICAL_SECTION\r
1236\r
1237 calc_ints(); /* recompute pending interrupt mask */\r
1238} /* because we probably cleared some ILSW bits before this instruction */\r
1239\r
1240/* let a device halt the simulation */\r
1241\r
1242void break_simulation (t_stat stopreason)\r
1243{\r
1244 reason = stopreason;\r
1245}\r
1246\r
1247/* ------------------------------------------------------------------------ \r
1248 * SIMH required routines\r
1249 * ------------------------------------------------------------------------ */\r
1250\r
1251/* ------------------------------------------------------------------------ \r
1252 * Reset routine\r
1253 * ------------------------------------------------------------------------ */\r
1254\r
1255t_stat cpu_reset (DEVICE *dptr)\r
1256{\r
1257 wait_state = 0; /* cancel wait */\r
1258 wait_lamp = TRUE; /* but keep the wait lamp lit on the GUI */\r
1259\r
1260 if (cpu_unit.flags & UNIT_ATT) { /* record reset in CPU log */\r
1261 fseek(cpu_unit.fileref, 0, SEEK_END);\r
1262 fprintf(cpu_unit.fileref, "---RESET---" CRLF);\r
1263 }\r
1264\r
1265 GUI_BEGIN_CRITICAL_SECTION\r
1266\r
1267 CLRBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP|CPU_DSW_INT_RUN);\r
1268 CLRBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);\r
1269\r
1270 reset_backtrace();\r
1271\r
1272 ipl = -1;\r
1273 int_mask = 0xFFFF;\r
1274 int_req = 0; /* hmmm, it SHOULD reset the int req, right? */\r
1275 int_lamps = 0;\r
1276 iplpending = 0;\r
1277 memset(ILSW, 0, sizeof(ILSW));\r
1278\r
1279 cpu_dsw = 0; /* clear int req and prot stop bits */\r
1280 tbit = 0; /* cancel INT_RUN mode */\r
1281\r
1282 C = V = 0; /* clear processor flags */\r
1283 IAR = SAR = SBR = 0; /* clear IAR and other registers */\r
1284 ACC = EXT = OP = TAG = CCC = C = V = 0;\r
1285\r
1286 mem_mask = MEMSIZE - 1; /* wraparound mask */\r
1287\r
1288 GUI_END_CRITICAL_SECTION\r
1289\r
1290 return cpu_svc(&cpu_unit); /* reset breakpoint */\r
1291}\r
1292\r
1293/* ------------------------------------------------------------------------ \r
1294 * Memory examine\r
1295 * ------------------------------------------------------------------------ */\r
1296\r
1297t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
1298{\r
1299 if (vptr == NULL) return SCPE_ARG;\r
1300\r
1301 /* check this out -- save command hits it in weird way */\r
1302 /* I wish I remembered what I meant when I wrote that */\r
1303 if (addr < MEMSIZE) {\r
1304 *vptr = M[addr] & 0xFFFF;\r
1305 return SCPE_OK;\r
1306 }\r
1307 return SCPE_NXM;\r
1308}\r
1309\r
1310/* ------------------------------------------------------------------------ \r
1311 * Memory deposit\r
1312 * ------------------------------------------------------------------------ */\r
1313\r
1314t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
1315{\r
1316 if (addr < MEMSIZE) {\r
1317 M[addr] = (uint16) (val & 0xFFFF);\r
1318 return SCPE_OK;\r
1319 }\r
1320 return SCPE_NXM;\r
1321}\r
1322\r
1323/* ------------------------------------------------------------------------ \r
1324 * Breakpoint service\r
1325 * ------------------------------------------------------------------------ */\r
1326\r
1327t_stat cpu_svc (UNIT *uptr)\r
1328{\r
1329 if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt)\r
1330 ibkpt_addr = save_ibkpt;\r
1331\r
1332 save_ibkpt = -1;\r
1333 return SCPE_OK;\r
1334}\r
1335\r
1336/* ------------------------------------------------------------------------ \r
1337 * Memory allocation\r
1338 * ------------------------------------------------------------------------ */\r
1339\r
1340t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc)\r
1341{\r
1342 t_bool used;\r
1343 int32 i;\r
1344\r
1345 if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xFFF) != 0))\r
1346 return SCPE_ARG;\r
1347\r
1348 for (i = value, used = FALSE; i < (int32) MEMSIZE; i++) {\r
1349 if (M[i] != 0) {\r
1350 used = TRUE;\r
1351 break;\r
1352 }\r
1353 }\r
1354\r
1355 if (used && ! get_yn ("Really truncate memory [N]?", FALSE))\r
1356 return SCPE_OK;\r
1357\r
1358 for (i = MEMSIZE; i < value; i++) /* clear expanded area */\r
1359 M[i] = 0;\r
1360\r
1361 MEMSIZE = value;\r
1362 mem_mask = MEMSIZE - 1;\r
1363\r
1364 return SCPE_OK;\r
1365}\r
1366\r
1367/* processor type */\r
1368\r
1369t_stat cpu_set_type (UNIT *uptr, int32 value, char *cptr, void *desc)\r
1370{\r
1371 REG *r;\r
1372\r
1373 is_1800 = (value & UNIT_1800) != 0; /* set is_1800 mode flag */\r
1374\r
1375 for (r = cpu_reg; r->name != NULL; r++) { /* unhide or hide 1800-specific registers & state */\r
1376 if (strnicmp(r->name, "XR", 2) == 0) {\r
1377 if (value & UNIT_1800)\r
1378 CLRBIT(r->flags, REG_HIDDEN|REG_RO);\r
1379 else\r
1380 SETBIT(r->flags, REG_HIDDEN|REG_RO);\r
1381 }\r
1382 }\r
1383\r
1384 return SCPE_OK;\r
1385}\r
1386\r
1387/* ------------------------------------------------------------------------ \r
1388 * IO function for console switches\r
1389 * ------------------------------------------------------------------------ */\r
1390\r
1391void xio_1131_switches (int32 addr, int32 func, int32 modify)\r
1392{\r
1393 char msg[80];\r
1394\r
1395 switch (func) {\r
1396 case XIO_READ:\r
1397 WriteW(addr, CES);\r
1398 break;\r
1399\r
1400 case XIO_SENSE_DEV:\r
1401 ACC = cpu_dsw;\r
1402 break;\r
1403\r
1404 default:\r
1405 sprintf(msg, "Invalid console switch function %x", func);\r
1406 xio_error(msg);\r
1407 }\r
1408}\r
1409\r
1410/* ------------------------------------------------------------------------ \r
1411 * Illegal IO operation. Not yet sure what the actual CPU does in this case\r
1412 * ------------------------------------------------------------------------ */\r
1413\r
1414void xio_error (char *msg)\r
1415{\r
1416 printf("*** XIO error at %04x: %s\n", prev_IAR, msg);\r
1417 if (cgi) /* if this happens in CGI mode, probably best to halt */\r
1418 break_simulation(STOP_CRASH);\r
1419}\r
1420\r
1421/* ------------------------------------------------------------------------ \r
1422 * register_cmd - add a command to the extensible command table\r
1423 * ------------------------------------------------------------------------ */\r
1424\r
1425t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help)\r
1426{\r
1427 int i;\r
1428\r
1429 for (i = 0; i < MAX_EXTRA_COMMANDS; i++) { /* find end of command table */\r
1430 if (x_cmds[i].action == action)\r
1431 return SCPE_OK; /* command is already there, just return */\r
1432 if (x_cmds[i].name == NULL)\r
1433 break;\r
1434 }\r
1435\r
1436 if (i >= (MAX_EXTRA_COMMANDS-1)) { /* no more room (we need room for the NULL) */\r
1437 fprintf(stderr, "The command table is full - rebuild the simulator with more free slots\n");\r
1438 return SCPE_ARG;\r
1439 }\r
1440\r
1441 x_cmds[i].action = action; /* add new command */\r
1442 x_cmds[i].name = name;\r
1443 x_cmds[i].arg = arg;\r
1444 x_cmds[i].help = help;\r
1445\r
1446 i++;\r
1447 x_cmds[i].action = NULL; /* move the NULL terminator */\r
1448 x_cmds[i].name = NULL;\r
1449\r
1450 return SCPE_OK;\r
1451}\r
1452\r
1453#ifdef USE_MY_ECHO_CMD\r
1454/* ------------------------------------------------------------------------ \r
1455 * echo_cmd - just echo the command line\r
1456 * ------------------------------------------------------------------------ */\r
1457\r
1458static t_stat echo_cmd (int flag, char *cptr)\r
1459{\r
1460 printf("%s\n", cptr);\r
1461 return SCPE_OK;\r
1462}\r
1463#endif\r
1464\r
1465/* ------------------------------------------------------------------------ \r
1466 * sim_init - initialize simulator upon startup of scp, before reset\r
1467 * ------------------------------------------------------------------------ */\r
1468\r
1469void sim_init (void)\r
1470{\r
1471 sim_gui = ! (sim_switches & SWMASK('G')); /* -g means no GUI */\r
1472\r
1473 sim_vm_cmd = x_cmds; /* provide list of additional commands */\r
1474\r
1475#ifdef GUI_SUPPORT\r
1476 /* set hook routines for GUI command processing */\r
1477 if (sim_gui) {\r
1478 sim_vm_read = &read_cmdline;\r
1479 sim_vm_post = &update_gui;\r
1480 }\r
1481#endif\r
1482\r
1483#ifdef ENABLE_BACKTRACE\r
1484 /* add the BACKTRACE command */\r
1485 register_cmd("BACKTRACE", &backtrace_cmd, 0, "ba{cktrace} {n} list last n branches/skips/interrupts\n");\r
1486#endif\r
1487\r
1488 register_cmd("VIEW", &view_cmd, 0, "v{iew} filename view a text file with notepad\n");\r
1489\r
1490#ifdef USE_MY_ECHO_CMD\r
1491 register_cmd("ECHO", &echo_cmd, 0, "echo args... echo arguments passed to command\n");\r
1492#endif\r
1493}\r
1494\r
1495/* ------------------------------------------------------------------------ \r
1496 * archive_backtrace - record a jump, skip, branch or whatever\r
1497 * ------------------------------------------------------------------------ */\r
1498\r
1499#ifdef ENABLE_BACKTRACE\r
1500\r
1501#define MAXARCHIVE 16\r
1502\r
1503static struct tag_arch {\r
1504 int iar;\r
1505 char *inst;\r
1506} arch[MAXARCHIVE];\r
1507int narchived = 0, archind = 0;\r
1508\r
1509static void archive_backtrace (char *inst)\r
1510{\r
1511 static int prevind;\r
1512\r
1513 if (narchived < MAXARCHIVE)\r
1514 narchived++;\r
1515\r
1516 if (narchived > 0 && arch[prevind].iar == prev_IAR)\r
1517 return;\r
1518\r
1519 arch[archind].iar = prev_IAR;\r
1520 arch[archind].inst = inst;\r
1521\r
1522 prevind = archind;\r
1523 archind = (archind+1) % MAXARCHIVE;\r
1524}\r
1525\r
1526static void reset_backtrace (void)\r
1527{\r
1528 narchived = 0;\r
1529 archind = 0;\r
1530}\r
1531\r
1532void void_backtrace (int afrom, int ato)\r
1533{\r
1534 int i;\r
1535\r
1536 afrom &= mem_mask;\r
1537 ato &= mem_mask;\r
1538\r
1539 for (i = 0; i < narchived; i++)\r
1540 if (arch[i].iar >= afrom && arch[i].iar <= ato)\r
1541 arch[i].inst = "OVERWRITTEN";\r
1542}\r
1543\r
1544static void show_backtrace (int nshow)\r
1545{\r
1546 int n = narchived, i = archind;\r
1547\r
1548 if (n > nshow) n = nshow;\r
1549\r
1550 while (--n >= 0) {\r
1551 i = (i > 0) ? (i-1) : (MAXARCHIVE-1);\r
1552 printf("from %04x (%s) ", arch[i].iar, arch[i].inst);\r
1553 }\r
1554\r
1555 if (narchived)\r
1556 putchar('\n');\r
1557}\r
1558\r
1559static t_stat backtrace_cmd (int flag, char *cptr)\r
1560{\r
1561 int n;\r
1562\r
1563 if ((n = atoi(cptr)) <= 0)\r
1564 n = 6;\r
1565\r
1566 show_backtrace(n);\r
1567 return SCPE_OK;\r
1568}\r
1569#else\r
1570\r
1571/* stub this for the disk routine */\r
1572\r
1573void void_backtrace (int afrom, int ato)\r
1574{\r
1575}\r
1576\r
1577#endif\r
1578\r
1579/*************************************************************************************\r
1580 * CPU log routines -- attaching a file to the CPU creates a trace of instructions and register values\r
1581 *\r
1582 * Syntax is WEIRD:\r
1583 *\r
1584 * attach cpu logfile log instructions and registers to file "logfile"\r
1585 * attach -f cpu cpu.log log instructions, registers and floating point acc\r
1586 * attach -m cpu mapfile logfile read addresses from "mapfile", log instructions to "logfile"\r
1587 * attach -f -m cpu mapfile logfile same and log floating point stuff too\r
1588 *\r
1589 * mapfile if specified is a list of symbols and addresses of the form:\r
1590 * symbol hexval\r
1591 *\r
1592 * e.g.\r
1593 * FSIN 082E\r
1594 * FARC 09D4\r
1595 * FMPY 09A4\r
1596 * NORM 0976\r
1597 * XMDS 095A\r
1598 * START 021A\r
1599 *\r
1600 * These values are easily obtained from a load map created by\r
1601 * XEQ L\r
1602 *\r
1603 * The log output is of the form\r
1604 *\r
1605 * IAR ACC EXT (flt) XR1 XR2 XR3 CVI FAC OPERATION\r
1606 * --------------- ---- ---- -------- ---- ---- ---- --- ------------- -----------------------\r
1607 * 002a 002a 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 4c80 BSC I ,0028 \r
1608 * 081d PAUSE+000d 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7400 MDM L 00f0,0 (0) \r
1609 * 0820 PAUSE+0010 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7201 MDX 2 0001 \r
1610 * 0821 PAUSE+0011 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6a03 STX 2 0003 \r
1611 * 0822 PAUSE+0012 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6600 LDX L2 0231 \r
1612 * 0824 PAUSE+0014 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,0237 \r
1613 * 0237 START+001d 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4480 BSI I ,3fff \r
1614 * 082f FSIN +0001 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4356 BSI 3 0056 \r
1615 * 3fd5 ILS01+35dd 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,08de \r
1616 *\r
1617 * IAR - instruction address register value, optionally including symbol and offset\r
1618 * ACC - accumulator\r
1619 * EXT - extension\r
1620 * flt - ACC+EXT interpreted as the mantissa of a floating pt number (value 0.5 -> 1)\r
1621 * XR* - index registers\r
1622 * CVI - carry, overflow and interrupt indicators\r
1623 * FAC - floating point accumulator (exponent at 125+XR3, mantissa at 126+XR3 and 127+XR3)\r
1624 * OP - opcode value and crude disassembly\r
1625 *\r
1626 * flt and FAC are displayed only when the -f flag is specified in the attach command\r
1627 * The label and offset and displayed only when the -m flag is specified in the attach command\r
1628 *\r
1629 * The register values shown are the values BEFORE the instruction is executed.\r
1630 *************************************************************************************/\r
1631\r
1632t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw);\r
1633\r
1634typedef struct tag_symentry {\r
1635 struct tag_symentry *next;\r
1636 int addr;\r
1637 char sym[6];\r
1638} SYMENTRY, *PSYMENTRY;\r
1639\r
1640static PSYMENTRY syms = NULL;\r
1641static t_bool new_log, log_fac;\r
1642\r
1643static t_stat cpu_attach (UNIT *uptr, char *cptr)\r
1644{\r
1645 char mapfile[200], buf[200], sym[100];\r
1646 int addr;\r
1647 PSYMENTRY n, prv, s;\r
1648 FILE *fd;\r
1649\r
1650 remove(cptr); /* delete old log file, if present */\r
1651 new_log = TRUE;\r
1652 log_fac = sim_switches & SWMASK ('F'); /* display the FAC and the ACC/EXT as fixed point. */\r
1653\r
1654 for (s = syms; s != NULL; s = n) { /* free any old map entries */\r
1655 n = s->next;\r
1656 free(s);\r
1657 }\r
1658 syms = NULL;\r
1659 \r
1660 if (sim_switches & SWMASK('M')) { /* use a map file to display relative addresses */\r
1661 cptr = get_glyph(cptr, mapfile, 0);\r
1662 if (! *mapfile) {\r
1663 printf("/m must be followed by a filename\n");\r
1664 return SCPE_ARG;\r
1665 }\r
1666 if ((fd = fopen(mapfile, "r")) == NULL) {\r
1667 perror(mapfile);\r
1668 return SCPE_OPENERR;\r
1669 }\r
1670\r
1671 while (fgets(buf, sizeof(buf), fd) != NULL) { /* read symbols & addresses, link in descending address order */\r
1672 if (sscanf(buf, "%s %x", sym, &addr) != 2)\r
1673 continue;\r
1674 if (*buf == ';')\r
1675 continue;\r
1676\r
1677 for (prv = NULL, s = syms; s != NULL; prv = s, s = s->next) {\r
1678 if (s->addr < addr)\r
1679 break;\r
1680 }\r
1681\r
1682 if ((n = malloc(sizeof(SYMENTRY))) == NULL) {\r
1683 printf("out of memory reading map!\n");\r
1684 break;\r
1685 }\r
1686\r
1687 sym[5] = '\0';\r
1688 strcpy(n->sym, sym);\r
1689 upcase(n->sym);\r
1690 n->addr = addr;\r
1691\r
1692 if (prv == NULL) {\r
1693 n->next = syms;\r
1694 syms = n;\r
1695 }\r
1696 else {\r
1697 n->next = prv->next;\r
1698 prv ->next = n;\r
1699 }\r
1700 }\r
1701 fclose(fd);\r
1702 }\r
1703\r
1704 return attach_unit(uptr, quotefix(cptr)); /* fix quotes in filenames & attach */\r
1705}\r
1706\r
1707static void trace_instruction (void)\r
1708{\r
1709 t_value v[2];\r
1710 float fac;\r
1711 short exp;\r
1712 int addr;\r
1713 PSYMENTRY s;\r
1714 long mant, sign;\r
1715 char facstr[20], fltstr[20];\r
1716\r
1717 if ((cpu_unit.flags & UNIT_ATT) == 0)\r
1718 return;\r
1719\r
1720 if (new_log) {\r
1721 fseek(cpu_unit.fileref, 0, SEEK_END);\r
1722 new_log = FALSE;\r
1723\r
1724 fprintf(cpu_unit.fileref, " IAR%s ACC EXT %s XR1 XR2 XR3 CVI %sOPERATION" CRLF,\r
1725 syms ? " " : "", log_fac ? " (flt) " : "", log_fac ? " FAC " : "");\r
1726 fprintf(cpu_unit.fileref, "----%s ---- ---- %s---- ---- ---- --- %s-----------------------" CRLF,\r
1727 syms ? "-----------" : "", log_fac ? "-------- " : "", log_fac ? "------------- " : "");\r
1728 }\r
1729\r
1730 if (! log_fac) \r
1731 facstr[0] = fltstr[0] = '\0';\r
1732 else {\r
1733 mant = ((ACC & 0xFFFF) << 16) | (EXT & 0xFFFF);\r
1734 if (mant == 0x80000000) {\r
1735 sign = TRUE;\r
1736 fac = 1.f;\r
1737 }\r
1738 else {\r
1739 if ((sign = mant & 0x80000000) != 0)\r
1740 mant = -mant;\r
1741 fac = (float) mant * ((float) 1./ (float) (unsigned long) 0x80000000);\r
1742 }\r
1743 sprintf(fltstr, "%c%.5f ", sign ? '-' : ' ', fac);\r
1744\r
1745 if (BETWEEN(M[3], 0x300, MEMSIZE-128)) {\r
1746 exp = (short) ((M[M[3]+125] & 0xFF) - 128);\r
1747 mant = (M[M[3]+126] << 8) | ((M[M[3]+127] >> 8) & 0xFF);\r
1748 if ((sign = (mant & 0x00800000)) != 0)\r
1749 mant = (-mant) & 0x00FFFFFF;\r
1750\r
1751 fac = (float) mant * ((float) 1. / (float) 0x00800000);\r
1752\r
1753 if (exp > 30) {\r
1754 fac *= (float) (1 << 30);\r
1755 exp -= 30;\r
1756 while (exp > 0)\r
1757 fac *= 2;\r
1758 }\r
1759 else if (exp > 0)\r
1760 fac *= (float) (1 << exp);\r
1761 else if (exp < -30) {\r
1762 fac /= (float) (1 << 30);\r
1763 exp += 30;\r
1764 while (exp < 0)\r
1765 fac /= 2;\r
1766 }\r
1767 else if (exp < 0)\r
1768 fac /= (float) (1 << -exp);\r
1769\r
1770 sprintf(facstr, "%c%.5e ", sign ? '-' : ' ', fac);\r
1771 }\r
1772 else\r
1773 strcpy(facstr, " ");\r
1774 }\r
1775\r
1776 addr = IAR & 0xFFFF;\r
1777 fprintf(cpu_unit.fileref, "%04x ", addr);\r
1778\r
1779 if (syms) {\r
1780 for (s = syms; s != NULL; s = s->next)\r
1781 if (s->addr <= addr)\r
1782 break;\r
1783 \r
1784 if (s == NULL)\r
1785 fprintf(cpu_unit.fileref, " %04x ", addr);\r
1786 else\r
1787 fprintf(cpu_unit.fileref, "%-5s+%04x ", s->sym, addr - s->addr);\r
1788 }\r
1789\r
1790 fprintf(cpu_unit.fileref, "%04x %04x %s%04x %04x %04x %c%c%c %s",\r
1791 ACC & 0xFFFF, EXT & 0xFFFF, fltstr, M[1] & 0xFFFF, M[2] & 0xFFFF, M[3] & 0xFFFF,\r
1792 C ? 'C' : ' ', V ? 'V' : ' ', (ipl < 0) ? ' ' : (ipl+'0'), facstr);\r
1793\r
1794 v[0] = M[ IAR & mem_mask];\r
1795 v[1] = M[(IAR+1) & mem_mask];\r
1796 fprint_sym(cpu_unit.fileref, IAR & mem_mask, v, NULL, SWMASK('M')); /* disassemble instruction */\r
1797\r
1798 fputs(CRLF, cpu_unit.fileref);\r
1799}\r
1800\r
1801void trace_io (char *fmt, ...)\r
1802{\r
1803 va_list args;\r
1804\r
1805 if ((cpu_unit.flags & UNIT_ATT) == 0)\r
1806 return;\r
1807\r
1808 va_start(args, fmt); /* get pointer to argument list */\r
1809 vfprintf(cpu_unit.fileref, fmt, args); /* write errors to cpu log file */\r
1810 va_end(args);\r
1811\r
1812 fputs(CRLF, cpu_unit.fileref);\r
1813}\r
1814\r
1815void trace_both (char *fmt, ...)\r
1816{\r
1817 va_list args;\r
1818\r
1819 if (cpu_unit.flags & UNIT_ATT) {\r
1820 va_start(args, fmt); /* get pointer to argument list */\r
1821 vfprintf(cpu_unit.fileref, fmt, args);\r
1822 va_end(args);\r
1823 fputs(CRLF, cpu_unit.fileref);\r
1824 }\r
1825\r
1826 va_start(args, fmt); /* get pointer to argument list */\r
1827 vfprintf(stdout, fmt, args);\r
1828 va_end(args);\r
1829 putchar('\n');\r
1830}\r
1831\r
1832/* debugging */\r
1833\r
1834void debug_print (char *fmt, ...)\r
1835{\r
1836 va_list args;\r
1837\r
1838 va_start(args, fmt);\r
1839 vprintf(fmt, args);\r
1840 if (cpu_unit.flags & UNIT_ATT)\r
1841 vfprintf(cpu_unit.fileref, fmt, args);\r
1842 va_end(args);\r
1843\r
1844 if (strchr(fmt, '\n') == NULL) { /* be sure to emit a newline */\r
1845 putchar('\n');\r
1846 if (cpu_unit.flags & UNIT_ATT)\r
1847 putc('\n', cpu_unit.fileref);\r
1848 }\r
1849}\r
1850\r
1851#ifdef _WIN32\r
1852#include <windows.h>\r
1853#endif\r
1854\r
1855/* view_cmd - let user view and/or edit a file (e.g. a printer output file, script, or source deck) */\r
1856\r
1857static t_stat view_cmd (int flag, char *cptr)\r
1858{\r
1859#ifdef _WIN32\r
1860 char cmdline[256];\r
1861\r
1862 sprintf(cmdline, "notepad %s", cptr);\r
1863 WinExec(cmdline, SW_SHOWNORMAL);\r
1864#endif\r
1865 return SCPE_OK;\r
1866}\r
1867\r
1868/* web server version - hooks for CGI mode. These function pointer can be set by the CGI version's main() routine */\r
1869\r
1870void (*cgi_start_hook)(void) = NULL; /* these can be defined by a CGI wrapper to do things on start and stop of simulation */\r
1871void (*cgi_end_hook)(void) = NULL;\r
1872\r
1873static void cgi_start (void)\r
1874{\r
1875 if (cgi_start_hook != NULL)\r
1876 (*cgi_start_hook)();\r
1877}\r
1878\r
1879static void cgi_stop (t_stat reason)\r
1880{\r
1881 if (cgi_end_hook != NULL)\r
1882 (*cgi_end_hook)();\r
1883}\r