First Commit of my working state
[simh.git] / scp.c
CommitLineData
196ba1fc
PH
1/* scp.c: simulator control program\r
2\r
3 Copyright (c) 1993-2008, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 31-Mar-08 RMS Fixed bug in local/global register search (found by Mark Pizzolato)\r
27 Fixed bug in restore of RO units (from Mark Pizzolato)\r
28 06-Feb-08 RMS Added SET/SHO/NO BR with default argument\r
29 18-Jul-07 RMS Modified match_ext for VMS ext;version support\r
30 28-Apr-07 RMS Modified sim_instr invocation to call sim_rtcn_init_all\r
31 Fixed bug in get_sim_opt\r
32 Fixed bug in restoration with changed memory size\r
33 08-Mar-07 JDB Fixed breakpoint actions in DO command file processing\r
34 30-Jan-07 RMS Fixed bugs in get_ipaddr\r
35 17-Oct-06 RMS Added idle support\r
36 04-Oct-06 JDB DO cmd failure now echoes cmd unless -q\r
37 14-Jul-06 RMS Added sim_activate_abs\r
38 02-Jun-06 JDB Fixed do_cmd to exit nested files on assertion failure\r
39 Added -E switch to do_cmd to exit on any error\r
40 14-Feb-06 RMS Upgraded save file format to V3.5\r
41 18-Jan-06 RMS Added fprint_stopped_gen\r
42 Added breakpoint spaces\r
43 Fixed unaligned register access (found by Doug Carman)\r
44 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r
45 30-Aug-05 RMS Revised to trim trailing spaces on file names\r
46 25-Aug-05 RMS Added variable default device support\r
47 23-Aug-05 RMS Added Linux line history support\r
48 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
49 01-May-05 RMS Revised syntax for SET DEBUG (from Dave Bryan)\r
50 22-Mar-05 JDB Modified DO command to allow ten-level nesting\r
51 18-Mar-05 RMS Moved DETACH tests into detach_unit (from Dave Bryan)\r
52 Revised interface to fprint_sym, fparse_sym\r
53 07-Feb-05 RMS Added ASSERT command (from Dave Bryan)\r
54 02-Feb-05 RMS Fixed bug in global register search\r
55 26-Dec-04 RMS Qualified SAVE examine, RESTORE deposit with SIM_SW_REST\r
56 10-Nov-04 JDB Fixed logging of errors from cmds in "do" file\r
57 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy\r
58 Renamed unit OFFLINE/ONLINE to DISABLED/ENABLED (from Dave Bryan)\r
59 Revised to flush output files after simulation stop (from Dave Bryan)\r
60 15-Oct-04 RMS Fixed HELP to suppress duplicate descriptions\r
61 27-Sep-04 RMS Fixed comma-separation options in set (from David Bryan)\r
62 09-Sep-04 RMS Added -p option for RESET\r
63 13-Aug-04 RMS Qualified RESTORE detach with SIM_SW_REST\r
64 17-Jul-04 RMS Added ECHO command (from Dave Bryan)\r
65 12-Jul-04 RMS Fixed problem ATTACHing to read only files\r
66 (found by John Dundas)\r
67 28-May-04 RMS Added SET/SHOW CONSOLE\r
68 14-Feb-04 RMS Updated SAVE/RESTORE (V3.2)\r
69 RMS Added debug print routines (from Dave Hittner)\r
70 RMS Added sim_vm_parse_addr and sim_vm_fprint_addr\r
71 RMS Added REG_VMAD support\r
72 RMS Split out libraries\r
73 RMS Moved logging function to SCP\r
74 RMS Exposed step counter interface(s)\r
75 RMS Fixed double logging of SHOW BREAK (found by Mark Pizzolato)\r
76 RMS Fixed implementation of REG_VMIO\r
77 RMS Added SET/SHOW DEBUG, SET/SHOW <device> DEBUG,\r
78 SHOW <device> MODIFIERS, SHOW <device> RADIX\r
79 RMS Changed sim_fsize to take uptr argument\r
80 29-Dec-03 RMS Added Telnet console output stall support\r
81 01-Nov-03 RMS Cleaned up implicit detach on attach/restore\r
82 Fixed bug in command line read while logging (found by Mark Pizzolato)\r
83 01-Sep-03 RMS Fixed end-of-file problem in dep, idep\r
84 Fixed error on trailing spaces in dep, idep\r
85 15-Jul-03 RMS Removed unnecessary test in reset_all\r
86 15-Jun-03 RMS Added register flag REG_VMIO\r
87 25-Apr-03 RMS Added extended address support (V3.0)\r
88 Fixed bug in SAVE (found by Peter Schorn)\r
89 Added u5, u6 fields\r
90 Added logical name support\r
91 03-Mar-03 RMS Added sim_fsize\r
92 27-Feb-03 RMS Fixed bug in multiword deposits to files\r
93 08-Feb-03 RMS Changed sim_os_sleep to void, match_ext to char*\r
94 Added multiple actions, .ini file support\r
95 Added multiple switch evaluations per line\r
96 07-Feb-03 RMS Added VMS support for ! (from Mark Pizzolato)\r
97 01-Feb-03 RMS Added breakpoint table extension, actions\r
98 14-Jan-03 RMS Added missing function prototypes\r
99 10-Jan-03 RMS Added attach/restore flag, dynamic memory size support,\r
100 case sensitive SET options\r
101 22-Dec-02 RMS Added ! (OS command) feature (from Mark Pizzolato)\r
102 17-Dec-02 RMS Added get_ipaddr\r
103 02-Dec-02 RMS Added EValuate command\r
104 16-Nov-02 RMS Fixed bug in register name match algorithm\r
105 13-Oct-02 RMS Fixed Borland compiler warnings (found by Hans Pufal)\r
106 05-Oct-02 RMS Fixed bugs in set_logon, ssh_break (found by David Hittner)\r
107 Added support for fixed buffer devices\r
108 Added support for Telnet console, removed VT support\r
109 Added help <command>\r
110 Added VMS file optimizations (from Robert Alan Byer)\r
111 Added quiet mode, DO with parameters, GUI interface,\r
112 extensible commands (from Brian Knittel)\r
113 Added device enable/disable commands\r
114 14-Jul-02 RMS Fixed exit bug in do, added -v switch (from Brian Knittel)\r
115 17-May-02 RMS Fixed bug in fxread/fxwrite error usage (found by\r
116 Norm Lastovic)\r
117 02-May-02 RMS Added VT emulation interface, changed {NO}LOG to SET {NO}LOG\r
118 22-Apr-02 RMS Fixed laptop sleep problem in clock calibration, added\r
119 magtape record length error (found by Jonathan Engdahl)\r
120 26-Feb-02 RMS Fixed initialization bugs in do_cmd, get_aval\r
121 (found by Brian Knittel)\r
122 10-Feb-02 RMS Fixed problem in clock calibration\r
123 06-Jan-02 RMS Moved device enable/disable to simulators\r
124 30-Dec-01 RMS Generalized timer packaged, added circular arrays\r
125 19-Dec-01 RMS Fixed DO command bug (found by John Dundas)\r
126 07-Dec-01 RMS Implemented breakpoint package\r
127 05-Dec-01 RMS Fixed bug in universal register logic\r
128 03-Dec-01 RMS Added read-only units, extended SET/SHOW, universal registers\r
129 24-Nov-01 RMS Added unit-based registers\r
130 16-Nov-01 RMS Added DO command\r
131 28-Oct-01 RMS Added relative range addressing\r
132 08-Oct-01 RMS Added SHOW VERSION\r
133 30-Sep-01 RMS Relaxed attach test in BOOT\r
134 27-Sep-01 RMS Added queue count routine, fixed typo in ex/mod\r
135 17-Sep-01 RMS Removed multiple console support\r
136 07-Sep-01 RMS Removed conditional externs on function prototypes\r
137 Added special modifier print\r
138 31-Aug-01 RMS Changed int64 to t_int64 for Windoze (V2.7)\r
139 18-Jul-01 RMS Minor changes for Macintosh port\r
140 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy)\r
141 27-May-01 RMS Added multiple console support\r
142 16-May-01 RMS Added logging\r
143 15-May-01 RMS Added features from Tim Litt\r
144 12-May-01 RMS Fixed missing return in disable_cmd\r
145 25-Mar-01 RMS Added ENABLE/DISABLE\r
146 14-Mar-01 RMS Revised LOAD/DUMP interface (again)\r
147 05-Mar-01 RMS Added clock calibration support\r
148 05-Feb-01 RMS Fixed bug, DETACH buffered unit with hwmark = 0\r
149 04-Feb-01 RMS Fixed bug, RESTORE not using device's attach routine\r
150 21-Jan-01 RMS Added relative time\r
151 22-Dec-00 RMS Fixed find_device for devices ending in numbers\r
152 08-Dec-00 RMS V2.5a changes\r
153 30-Oct-00 RMS Added output file option to examine\r
154 11-Jul-99 RMS V2.5 changes\r
155 13-Apr-99 RMS Fixed handling of 32b addresses\r
156 04-Oct-98 RMS V2.4 changes\r
157 20-Aug-98 RMS Added radix commands\r
158 05-Jun-98 RMS Fixed bug in ^D handling for UNIX\r
159 10-Apr-98 RMS Added switches to all commands\r
160 26-Oct-97 RMS Added search capability\r
161 25-Jan-97 RMS Revised data types\r
162 23-Jan-97 RMS Added bi-endian I/O\r
163 06-Sep-96 RMS Fixed bug in variable length IEXAMINE\r
164 16-Jun-96 RMS Changed interface to parse/print_sym\r
165 06-Apr-96 RMS Added error checking in reset all\r
166 07-Jan-96 RMS Added register buffers in save/restore\r
167 11-Dec-95 RMS Fixed ordering bug in save/restore\r
168 22-May-95 RMS Added symbolic input\r
169 13-Apr-95 RMS Added symbolic printouts\r
170*/\r
171\r
172/* Macros and data structures */\r
173\r
174#include "sim_defs.h"\r
175#include "sim_rev.h"\r
176#include <signal.h>\r
177#include <ctype.h>\r
178\r
179#ifdef HAVE_READLINE\r
180#include <sim_readline.h>\r
181#endif\r
182\r
183#define EX_D 0 /* deposit */\r
184#define EX_E 1 /* examine */\r
185#define EX_I 2 /* interactive */\r
186#define SCH_OR 0 /* search logicals */\r
187#define SCH_AND 1\r
188#define SCH_XOR 2\r
189#define SCH_E 0 /* search booleans */\r
190#define SCH_N 1\r
191#define SCH_G 2\r
192#define SCH_L 3\r
193#define SCH_EE 4\r
194#define SCH_NE 5\r
195#define SCH_GE 6\r
196#define SCH_LE 7\r
197#define SSH_ST 0 /* set */\r
198#define SSH_SH 1 /* show */\r
199#define SSH_CL 2 /* clear */\r
200\r
201#define DO_NEST_LVL 10 /* DO cmd nesting level */\r
202#define SRBSIZ 1024 /* save/restore buffer */\r
203#define SIM_BRK_INILNT 4096 /* bpt tbl length */\r
204#define SIM_BRK_ALLTYP 0xFFFFFFFF\r
205#define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \\r
206 sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \\r
207 x = sim_interval\r
208\r
209#define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])\r
210#define SZ_R(rp) \\r
211 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])\r
212#if defined (USE_INT64)\r
213#define SZ_LOAD(sz,v,mb,j) \\r
214 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \\r
215 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \\r
216 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \\r
217 else v = *(((t_uint64 *) mb) + ((uint32) j));\r
218#define SZ_STORE(sz,v,mb,j) \\r
219 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \\r
220 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \\r
221 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \\r
222 else *(((t_uint64 *) mb) + ((uint32) j)) = v;\r
223#else\r
224#define SZ_LOAD(sz,v,mb,j) \\r
225 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \\r
226 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \\r
227 else v = *(((uint32 *) mb) + ((uint32) j));\r
228#define SZ_STORE(sz,v,mb,j) \\r
229 if (sz == sizeof (uint8)) *(((uint8 *) mb) + ((uint32) j)) = (uint8) v; \\r
230 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \\r
231 else *(((uint32 *) mb) + ((uint32) j)) = v;\r
232#endif\r
233#define GET_SWITCHES(cp) \\r
234 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW\r
235#define GET_RADIX(val,dft) \\r
236 if (sim_switches & SWMASK ('O')) val = 8; \\r
237 else if (sim_switches & SWMASK ('D')) val = 10; \\r
238 else if (sim_switches & SWMASK ('H')) val = 16; \\r
239 else val = dft;\r
240\r
241/* VM interface */\r
242\r
243extern char sim_name[];\r
244extern DEVICE *sim_devices[];\r
245extern REG *sim_PC;\r
246extern const char *sim_stop_messages[];\r
247extern t_stat sim_instr (void);\r
248extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int32 flag);\r
249extern int32 sim_emax;\r
250extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r
251 UNIT *uptr, int32 sw);\r
252extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val,\r
253 int32 sw);\r
254\r
255/* The per-simulator init routine is a weak global that defaults to NULL\r
256 The other per-simulator pointers can be overrriden by the init routine */\r
257\r
258void (*sim_vm_init) (void);\r
259char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;\r
260void (*sim_vm_post) (t_bool from_scp) = NULL;\r
261CTAB *sim_vm_cmd = NULL;\r
262void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;\r
263t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr) = NULL;\r
264\r
265/* Prototypes */\r
266\r
267/* Set and show command processors */\r
268\r
269t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
270t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
271t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
272t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
273t_stat ssh_break (FILE *st, char *cptr, int32 flg);\r
274t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr);\r
275t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
276t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
277t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
278t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
279t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
280t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
281t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
282t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
283t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
284t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
285t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);\r
286t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);\r
287t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);\r
288t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg);\r
289t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, char *cptr, int32 flag);\r
290t_stat sim_check_console (int32 sec);\r
291t_stat sim_save (FILE *sfile);\r
292t_stat sim_rest (FILE *rfile);\r
293\r
294/* Breakpoint package */\r
295\r
296t_stat sim_brk_init (void);\r
297t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, char *act);\r
298t_stat sim_brk_clr (t_addr loc, int32 sw);\r
299t_stat sim_brk_clrall (int32 sw);\r
300t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);\r
301t_stat sim_brk_showall (FILE *st, int32 sw);\r
302char *sim_brk_getact (char *buf, int32 size);\r
303void sim_brk_clract (void);\r
304void sim_brk_npc (uint32 cnt);\r
305BRKTAB *sim_brk_new (t_addr loc);\r
306\r
307/* Commands support routines */\r
308\r
309SCHTAB *get_search (char *cptr, int32 radix, SCHTAB *schptr);\r
310int32 test_search (t_value val, SCHTAB *schptr);\r
311char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc);\r
312int32 get_switches (char *cptr);\r
313char *get_sim_sw (char *cptr);\r
314t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);\r
315t_value get_rval (REG *rptr, uint32 idx);\r
316void put_rval (REG *rptr, uint32 idx, t_value val);\r
317t_value strtotv (char *inptr, char **endptr, uint32 radix);\r
318void fprint_help (FILE *st);\r
319void fprint_stopped (FILE *st, t_stat r);\r
320void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);\r
321char *read_line (char *ptr, int32 size, FILE *stream);\r
322REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr);\r
323char *sim_trim_endspc (char *cptr);\r
324\r
325/* Forward references */\r
326\r
327t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, char *cptr);\r
328t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);\r
329t_bool qdisable (DEVICE *dptr);\r
330t_stat attach_err (UNIT *uptr, t_stat stat);\r
331t_stat detach_all (int32 start_device, t_bool shutdown);\r
332t_stat assign_device (DEVICE *dptr, char *cptr);\r
333t_stat deassign_device (DEVICE *dptr);\r
334t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, char *aptr);\r
335t_stat run_boot_prep (void);\r
336t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr,\r
337 REG *lowr, REG *highr, uint32 lows, uint32 highs);\r
338t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);\r
339t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx);\r
340t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr,\r
341 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);\r
342t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);\r
343t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr,\r
344 UNIT *uptr, int32 dfltinc);\r
345t_stat step_svc (UNIT *ptr);\r
346void sub_args (char *instr, char *tmpbuf, int32 maxstr, int32 nargs, char *do_arg[]);\r
347\r
348/* Global data */\r
349\r
350DEVICE *sim_dflt_dev = NULL;\r
351UNIT *sim_clock_queue = NULL;\r
352int32 sim_interval = 0;\r
353int32 sim_switches = 0;\r
354FILE *sim_ofile = NULL;\r
355SCHTAB *sim_schptr = FALSE;\r
356DEVICE *sim_dfdev = NULL;\r
357UNIT *sim_dfunit = NULL;\r
358int32 sim_opt_out = 0;\r
359int32 sim_is_running = 0;\r
360uint32 sim_brk_summ = 0;\r
361uint32 sim_brk_types = 0;\r
362uint32 sim_brk_dflt = 0;\r
363char *sim_brk_act = NULL;\r
364BRKTAB *sim_brk_tab = NULL;\r
365int32 sim_brk_ent = 0;\r
366int32 sim_brk_lnt = 0;\r
367int32 sim_brk_ins = 0;\r
368t_bool sim_brk_pend[SIM_BKPT_N_SPC] = { FALSE };\r
369t_addr sim_brk_ploc[SIM_BKPT_N_SPC] = { 0 };\r
370int32 sim_quiet = 0;\r
371int32 sim_step = 0;\r
372static double sim_time;\r
373static uint32 sim_rtime;\r
374static int32 noqueue_time;\r
375volatile int32 stop_cpu = 0;\r
376t_value *sim_eval = NULL;\r
377int32 sim_deb_close = 0; /* 1 = close debug */\r
378FILE *sim_log = NULL; /* log file */\r
379FILE *sim_deb = NULL; /* debug file */\r
380static SCHTAB sim_stab;\r
381\r
382static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };\r
383#if defined USE_INT64\r
384static const char *sim_si64 = "64b data";\r
385#else\r
386static const char *sim_si64 = "32b data";\r
387#endif\r
388#if defined USE_ADDR64\r
389static const char *sim_sa64 = "64b addresses";\r
390#else\r
391static const char *sim_sa64 = "32b addresses";\r
392#endif\r
393#if defined USE_NETWORK\r
394static const char *sim_snet = "Ethernet support";\r
395#else\r
396static const char *sim_snet = "no Ethernet";\r
397#endif\r
398\r
399/* Tables and strings */\r
400\r
401const char save_vercur[] = "V3.5";\r
402const char save_ver32[] = "V3.2";\r
403const char save_ver30[] = "V3.0";\r
404const char *scp_error_messages[] = {\r
405 "Address space exceeded",\r
406 "Unit not attached",\r
407 "I/O error",\r
408 "Checksum error",\r
409 "Format error",\r
410 "Unit not attachable",\r
411 "File open error",\r
412 "Memory exhausted",\r
413 "Invalid argument",\r
414 "Step expired",\r
415 "Unknown command",\r
416 "Read only argument",\r
417 "Command not completed",\r
418 "Simulation stopped",\r
419 "Goodbye",\r
420 "Console input I/O error",\r
421 "Console output I/O error",\r
422 "End of file",\r
423 "Relocation error",\r
424 "No settable parameters",\r
425 "Unit already attached",\r
426 "Hardware timer error",\r
427 "SIGINT handler setup error",\r
428 "Console terminal setup error",\r
429 "Subscript out of range",\r
430 "Command not allowed",\r
431 "Unit disabled",\r
432 "Read only operation not allowed",\r
433 "Invalid switch",\r
434 "Missing value",\r
435 "Too few arguments",\r
436 "Too many arguments",\r
437 "Non-existent device",\r
438 "Non-existent unit",\r
439 "Non-existent register",\r
440 "Non-existent parameter",\r
441 "Nested DO command limit exceeded",\r
442 "Internal error",\r
443 "Invalid magtape record length",\r
444 "Console Telnet connection lost",\r
445 "Console Telnet connection timed out",\r
446 "Console Telnet output stall",\r
447 "Assertion failed"\r
448 };\r
449\r
450const size_t size_map[] = { sizeof (int8),\r
451 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)\r
452#if defined (USE_INT64)\r
453 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)\r
454#endif\r
455};\r
456\r
457const t_value width_mask[] = { 0,\r
458 0x1, 0x3, 0x7, 0xF,\r
459 0x1F, 0x3F, 0x7F, 0xFF,\r
460 0x1FF, 0x3FF, 0x7FF, 0xFFF,\r
461 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,\r
462 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,\r
463 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,\r
464 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,\r
465 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF\r
466#if defined (USE_INT64)\r
467 , 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,\r
468 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,\r
469 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,\r
470 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,\r
471 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,\r
472 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,\r
473 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF,\r
474 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,\r
475 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF,\r
476 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF\r
477#endif\r
478 };\r
479\r
480static CTAB cmd_table[] = {\r
481 { "RESET", &reset_cmd, 0,\r
482 "r{eset} {ALL|<device>} reset simulator\n" },\r
483 { "EXAMINE", &exdep_cmd, EX_E,\r
484 "e{xamine} <list> examine memory or registers\n" },\r
485 { "IEXAMINE", &exdep_cmd, EX_E+EX_I,\r
486 "ie{xamine} <list> interactive examine memory or registers\n" },\r
487 { "DEPOSIT", &exdep_cmd, EX_D,\r
488 "d{eposit} <list> <val> deposit in memory or registers\n" },\r
489 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I,\r
490 "id{eposit} <list> interactive deposit in memory or registers\n" },\r
491 { "EVALUATE", &eval_cmd, 0,\r
492 "ev{aluate} <expr> evaluate symbolic expression\n" },\r
493 { "RUN", &run_cmd, RU_RUN,\r
494 "ru{n} {new PC} reset and start simulation\n" },\r
495 { "GO", &run_cmd, RU_GO,\r
496 "go {new PC} start simulation\n" }, \r
497 { "STEP", &run_cmd, RU_STEP,\r
498 "s{tep} {n} simulate n instructions\n" },\r
499 { "CONT", &run_cmd, RU_CONT,\r
500 "c{ont} continue simulation\n" },\r
501 { "BOOT", &run_cmd, RU_BOOT,\r
502 "b{oot} <unit> bootstrap unit\n" },\r
503 { "BREAK", &brk_cmd, SSH_ST,\r
504 "br{eak} <list> set breakpoints\n" },\r
505 { "NOBREAK", &brk_cmd, SSH_CL,\r
506 "nobr{eak} <list> clear breakpoints\n" },\r
507 { "ATTACH", &attach_cmd, 0,\r
508 "at{tach} <unit> <file> attach file to simulated unit\n" },\r
509 { "DETACH", &detach_cmd, 0,\r
510 "det{ach} <unit> detach file from simulated unit\n" },\r
511 { "ASSIGN", &assign_cmd, 0,\r
512 "as{sign} <device> <name> assign logical name for device\n" },\r
513 { "DEASSIGN", &deassign_cmd, 0,\r
514 "dea{ssign} <device> deassign logical name for device\n" },\r
515 { "SAVE", &save_cmd, 0,\r
516 "sa{ve} <file> save simulator to file\n" },\r
517 { "RESTORE", &restore_cmd, 0,\r
518 "rest{ore}|ge{t} <file> restore simulator from file\n" },\r
519 { "GET", &restore_cmd, 0, NULL },\r
520 { "LOAD", &load_cmd, 0,\r
521 "l{oad} <file> {<args>} load binary file\n" },\r
522 { "DUMP", &load_cmd, 1,\r
523 "du(mp) <file> {<args>} dump binary file\n" },\r
524 { "EXIT", &exit_cmd, 0,\r
525 "exi{t}|q{uit}|by{e} exit from simulation\n" },\r
526 { "QUIT", &exit_cmd, 0, NULL },\r
527 { "BYE", &exit_cmd, 0, NULL },\r
528 { "SET", &set_cmd, 0,\r
529 "set console arg{,arg...} set console options\n"\r
530 "set break <list> set breakpoints\n"\r
531 "set nobreak <list> clear breakpoints\n"\r
532 "set throttle x{M|K|%%} set simulation rate\n"\r
533 "set nothrottle set simulation rate to maximum\n"\r
534 "set <dev> OCT|DEC|HEX set device display radix\n"\r
535 "set <dev> ENABLED enable device\n"\r
536 "set <dev> DISABLED disable device\n"\r
537 "set <dev> DEBUG{=arg} set device debug flags\n"\r
538 "set <dev> NODEBUG={arg} clear device debug flags\n"\r
539 "set <dev> arg{,arg...} set device parameters\n"\r
540 "set <unit> ENABLED enable unit\n"\r
541 "set <unit> DISABLED disable unit\n"\r
542 "set <unit> arg{,arg...} set unit parameters\n"\r
543 },\r
544 { "SHOW", &show_cmd, 0,\r
545 "sh{ow} br{eak} <list> show breakpoints\n"\r
546 "sh{ow} con{figuration} show configuration\n"\r
547 "sh{ow} cons{ole} {arg} show console options\n"\r
548 "sh{ow} dev{ices} show devices\n" \r
549 "sh{ow} m{odifiers} show modifiers\n" \r
550 "sh{ow} n{ames} show logical names\n" \r
551 "sh{ow} q{ueue} show event queue\n" \r
552 "sh{ow} ti{me} show simulated time\n"\r
553 "sh{ow} th{rottle} show simulation rate\n" \r
554 "sh{ow} ve{rsion} show simulator version\n" \r
555 "sh{ow} <dev> RADIX show device display radix\n"\r
556 "sh{ow} <dev> DEBUG show device debug flags\n"\r
557 "sh{ow} <dev> MODIFIERS show device modifiers\n"\r
558 "sh{ow} <dev} NAMES show device logical name\n"\r
559 "sh{ow} <dev> {arg,...} show device parameters\n"\r
560 "sh{ow} <unit> {arg,...} show unit parameters\n" },\r
561 { "DO", &do_cmd, 1,\r
562 "do <file> {arg,arg...} process command file\n" },\r
563 { "ECHO", &echo_cmd, 0,\r
564 "echo <string> display <string>\n" },\r
565 { "ASSERT", &assert_cmd, 0,\r
566 "assert {<dev>} <cond> test simulator state against condition\n" },\r
567 { "HELP", &help_cmd, 0,\r
568 "h{elp} type this message\n"\r
569 "h{elp} <command> type help for command\n" },\r
570 { "!", &spawn_cmd, 0,\r
571 "! execute local command interpreter\n"\r
572 "! <command> execute local host command\n" },\r
573 { NULL, NULL, 0 }\r
574 };\r
575\r
576/* Main command loop */\r
577\r
578int main (int argc, char *argv[])\r
579{\r
580char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr;\r
581int32 i, sw;\r
582t_bool lookswitch;\r
583t_stat stat;\r
584CTAB *cmdp;\r
585\r
586#ifdef HAVE_READLINE\r
587 readline_read_history();\r
588#endif\r
589\r
590#if defined (__MWERKS__) && defined (macintosh)\r
591argc = ccommand (&argv);\r
592#endif\r
593\r
594*cbuf = 0; /* init arg buffer */\r
595sim_switches = 0; /* init switches */\r
596lookswitch = TRUE;\r
597for (i = 1; i < argc; i++) { /* loop thru args */\r
598 if (argv[i] == NULL) continue; /* paranoia */\r
599 if ((*argv[i] == '-') && lookswitch) { /* switch? */\r
600 if ((sw = get_switches (argv[i])) < 0) {\r
601 fprintf (stderr, "Invalid switch %s\n", argv[i]);\r
602 return 0;\r
603 }\r
604 sim_switches = sim_switches | sw;\r
605 }\r
606 else {\r
607 if ((strlen (argv[i]) + strlen (cbuf) + 1) >= CBUFSIZE) {\r
608 fprintf (stderr, "Argument string too long\n");\r
609 return 0;\r
610 }\r
611 if (*cbuf) strcat (cbuf, " "); /* concat args */\r
612 strcat (cbuf, argv[i]);\r
613 lookswitch = FALSE; /* no more switches */\r
614 }\r
615 } /* end for */\r
616sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */\r
617\r
618if (sim_vm_init != NULL) (*sim_vm_init)(); /* call once only */\r
619sim_finit (); /* init fio package */\r
620stop_cpu = 0;\r
621sim_interval = 0;\r
622sim_time = sim_rtime = 0;\r
623noqueue_time = 0;\r
624sim_clock_queue = NULL;\r
625sim_is_running = 0;\r
626sim_log = NULL;\r
627if (sim_emax <= 0) sim_emax = 1;\r
628sim_timer_init ();\r
629\r
630if ((stat = sim_ttinit ()) != SCPE_OK) {\r
631 fprintf (stderr, "Fatal terminal initialization error\n%s\n",\r
632 scp_error_messages[stat - SCPE_BASE]);\r
633 return 0;\r
634 }\r
635if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {\r
636 fprintf (stderr, "Unable to allocate examine buffer\n");\r
637 return 0;\r
638 };\r
639if ((stat = reset_all_p (0)) != SCPE_OK) {\r
640 fprintf (stderr, "Fatal simulator initialization error\n%s\n",\r
641 scp_error_messages[stat - SCPE_BASE]);\r
642 return 0;\r
643 }\r
644if ((stat = sim_brk_init ()) != SCPE_OK) {\r
645 fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",\r
646 scp_error_messages[stat - SCPE_BASE]);\r
647 return 0;\r
648 }\r
649if (!sim_quiet) {\r
650 printf ("\n");\r
651 show_version (stdout, NULL, NULL, 0, NULL);\r
652 }\r
653if (sim_dflt_dev == NULL) sim_dflt_dev = sim_devices[0]; /* if no default */\r
654\r
655if (*cbuf) /* cmd file arg? */\r
656 stat = do_cmd (0, cbuf); /* proc cmd file */\r
657else if (*argv[0]) { /* sim name arg? */\r
658 char nbuf[PATH_MAX + 7], *np; /* "path.ini" */\r
659 nbuf[0] = '"'; /* starting " */\r
660 strncpy (nbuf + 1, argv[0], PATH_MAX + 1); /* copy sim name */\r
661 if (np = match_ext (nbuf, "EXE")) *np = 0; /* remove .exe */\r
662 strcat (nbuf, ".ini\""); /* add .ini" */\r
663 stat = do_cmd (-1, nbuf); /* proc cmd file */\r
664 }\r
665\r
666while (stat != SCPE_EXIT) { /* in case exit */\r
667\r
668 if (cptr = sim_brk_getact (cbuf, CBUFSIZE)) /* pending action? */\r
669 printf ("sim> %s\n", cptr); /* echo */\r
670 else if (sim_vm_read != NULL) /* sim routine? */\r
671 cptr = (*sim_vm_read) (cbuf, CBUFSIZE, stdin);\r
672\r
673 else\r
674 #ifdef HAVE_READLINE\r
675 cptr = readline_read_line(cbuf,CBUFSIZE,"sim>");\r
676 #else\r
677 printf("sim>");\r
678 cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */\r
679 #endif\r
680 if (cptr == NULL){ /* ignore EOF */\r
681 printf("\r");\r
682 continue;\r
683 }\r
684 if (*cptr == 0) continue; /* ignore blank */\r
685\r
686 if (sim_log) fprintf (sim_log, "sim> %s\n", cptr); /* log cmd */\r
687 cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */\r
688 sim_switches = 0; /* init switches */\r
689 if (cmdp = find_cmd (gbuf)) /* lookup command */\r
690 stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */\r
691 else stat = SCPE_UNK;\r
692 if (stat >= SCPE_BASE) { /* error? */\r
693 printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);\r
694 if (sim_log) fprintf (sim_log, "%s\n",\r
695 scp_error_messages[stat - SCPE_BASE]);\r
696 }\r
697 if (sim_vm_post != NULL) (*sim_vm_post) (TRUE);\r
698 } /* end while */\r
699\r
700detach_all (0, TRUE); /* close files */\r
701sim_set_deboff (0, NULL); /* close debug */\r
702sim_set_logoff (0, NULL); /* close log */\r
703sim_set_notelnet (0, NULL); /* close Telnet */\r
704sim_ttclose (); /* close console */\r
705\r
706/* Write command history back to file */\r
707#ifdef HAVE_READLINE\r
708 readline_write_history();\r
709#endif\r
710\r
711return 0;\r
712}\r
713\r
714/* Find command routine */\r
715\r
716CTAB *find_cmd (char *gbuf)\r
717{\r
718CTAB *cmdp = NULL;\r
719\r
720if (sim_vm_cmd) cmdp = find_ctab (sim_vm_cmd, gbuf); /* try ext commands */\r
721if (cmdp == NULL) cmdp = find_ctab (cmd_table, gbuf); /* try regular cmds */\r
722return cmdp;\r
723}\r
724\r
725/* Exit command */\r
726\r
727t_stat exit_cmd (int32 flag, char *cptr)\r
728{\r
729return SCPE_EXIT;\r
730}\r
731\r
732/* Help command */\r
733\r
734void fprint_help (FILE *st)\r
735{\r
736CTAB *cmdp;\r
737\r
738for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {\r
739 if (cmdp->help) fprintf (st, cmdp->help);\r
740 }\r
741for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {\r
742 if (cmdp->help && (!sim_vm_cmd || !find_ctab (sim_vm_cmd, cmdp->name)))\r
743 fprintf (st, cmdp->help);\r
744 }\r
745return;\r
746}\r
747\r
748t_stat help_cmd (int32 flag, char *cptr)\r
749{\r
750char gbuf[CBUFSIZE];\r
751CTAB *cmdp;\r
752\r
753GET_SWITCHES (cptr);\r
754if (*cptr) {\r
755 cptr = get_glyph (cptr, gbuf, 0);\r
756 if (*cptr) return SCPE_2MARG;\r
757 if (cmdp = find_cmd (gbuf)) {\r
758 printf (cmdp->help);\r
759 if (sim_log) fprintf (sim_log, cmdp->help);\r
760 }\r
761 else return SCPE_ARG;\r
762 }\r
763else {\r
764 fprint_help (stdout);\r
765 if (sim_log) fprint_help (sim_log);\r
766 }\r
767return SCPE_OK;\r
768}\r
769\r
770/* Spawn command */\r
771\r
772t_stat spawn_cmd (int32 flag, char *cptr)\r
773{\r
774if ((cptr == NULL) || (strlen (cptr) == 0)) cptr = getenv("SHELL");\r
775if ((cptr == NULL) || (strlen (cptr) == 0)) cptr = getenv("ComSpec");\r
776#if defined (VMS)\r
777if ((cptr == NULL) || (strlen (cptr) == 0)) cptr = "SPAWN/INPUT=SYS$COMMAND:";\r
778#endif\r
779fflush(stdout); /* flush stdout */\r
780if (sim_log) fflush (sim_log); /* flush log if enabled */\r
781system (cptr);\r
782#if defined (VMS)\r
783printf ("\n");\r
784#endif\r
785\r
786return SCPE_OK;\r
787}\r
788\r
789/* Echo command */\r
790\r
791t_stat echo_cmd (int32 flag, char *cptr)\r
792{\r
793puts (cptr);\r
794if (sim_log) fprintf (sim_log, "%s\n", cptr);\r
795return SCPE_OK;\r
796}\r
797\r
798/* Do command\r
799\r
800 Syntax: DO {-E} {-V} <filename> {<arguments>...}\r
801\r
802 -E causes all command errors to be fatal; without it, only EXIT and ASSERT\r
803 failure will stop a command file.\r
804\r
805 -V causes commands to be echoed before execution.\r
806\r
807 Note that SCPE_STEP ("Step expired") is considered a note and not an error\r
808 and so does not abort command execution when using -E.\r
809 \r
810 Inputs:\r
811 flag = caller and nesting level indicator\r
812 fcptr = filename and optional arguments, space-separated\r
813 Outputs:\r
814 status = error status\r
815\r
816 The "flag" input value indicates the source of the call, as follows:\r
817\r
818 -1 = initialization file (no error if not found)\r
819 0 = command line file\r
820 1 = "DO" command\r
821 >1 = nested "DO" command\r
822*/\r
823\r
824#define SCPE_DOFAILED 0040000 /* fail in DO, not subproc */\r
825\r
826t_stat do_cmd (int32 flag, char *fcptr)\r
827{\r
828char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE], *c, quote, *do_arg[10];\r
829FILE *fpin;\r
830CTAB *cmdp;\r
831int32 echo, nargs, errabort;\r
832t_bool interactive, isdo, staying;\r
833t_stat stat;\r
834char *ocptr;\r
835\r
836stat = SCPE_OK;\r
837staying = TRUE;\r
838interactive = (flag > 0); /* issued interactively? */\r
839if (interactive) { GET_SWITCHES (fcptr); } /* get switches */\r
840echo = sim_switches & SWMASK ('V'); /* -v means echo */\r
841errabort = sim_switches & SWMASK ('E'); /* -e means abort on error */\r
842\r
843c = fcptr;\r
844for (nargs = 0; nargs < 10; ) { /* extract arguments */\r
845 while (isspace (*c)) c++; /* skip blanks */\r
846 if (*c == 0) break; /* all done */\r
847 if (*c == '\'' || *c == '"') quote = *c++; /* quoted string? */\r
848 else quote = 0;\r
849 do_arg[nargs++] = c; /* save start */\r
850 while (*c && (quote? (*c != quote): !isspace (*c))) c++;\r
851 if (*c) *c++ = 0; /* term at quote/spc */\r
852 } /* end for */\r
853if (nargs <= 0) return SCPE_2FARG; /* need at least 1 */\r
854if ((fpin = fopen (do_arg[0], "r")) == NULL) { /* file failed to open? */\r
855 if (flag == 0) /* cmd line file? */\r
856 fprintf (stderr, "Can't open file %s\n", do_arg[0]);\r
857 if (flag > 1)\r
858 return SCPE_OPENERR | SCPE_DOFAILED; /* return failure with flag */\r
859 else\r
860 return SCPE_OPENERR; /* return failure */\r
861 }\r
862if (flag < 1) flag = 1; /* start at level 1 */\r
863\r
864do {\r
865 ocptr = cptr = sim_brk_getact (cbuf, CBUFSIZE); /* get bkpt action */\r
866 if (!ocptr) /* no pending action? */\r
867 ocptr = cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */\r
868 sub_args (cbuf, gbuf, CBUFSIZE, nargs, do_arg); /* substitute args */\r
869 if (cptr == NULL) { /* EOF? */\r
870 stat = SCPE_OK; /* set good return */\r
871 break;\r
872 }\r
873 if (*cptr == 0) continue; /* ignore blank */\r
874 if (echo) printf("do> %s\n", cptr); /* echo if -v */\r
875 if (echo && sim_log) fprintf (sim_log, "do> %s\n", cptr);\r
876 cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */\r
877 sim_switches = 0; /* init switches */\r
878 isdo = FALSE;\r
879 if (cmdp = find_cmd (gbuf)) { /* lookup command */\r
880 isdo = (cmdp->action == &do_cmd);\r
881 if (isdo) { /* DO command? */\r
882 if (flag >= DO_NEST_LVL) stat = SCPE_NEST; /* nest too deep? */\r
883 else stat = do_cmd (flag + 1, cptr); /* exec DO cmd */\r
884 }\r
885 else stat = cmdp->action (cmdp->arg, cptr); /* exec other cmd */\r
886 }\r
887 else stat = SCPE_UNK; /* bad cmd given */\r
888 staying = (stat != SCPE_EXIT) && /* decide if staying */\r
889 (stat != SCPE_AFAIL) &&\r
890 (!errabort || (stat < SCPE_BASE) || (stat == SCPE_STEP));\r
891 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) && /* error from cmd? */\r
892 (stat != SCPE_STEP)) {\r
893 if (!echo && !sim_quiet && /* report if not echoing */\r
894 (!isdo || (stat & SCPE_DOFAILED))) { /* and not from DO return */\r
895 printf("%s> %s\n", do_arg[0], ocptr);\r
896 if (sim_log)\r
897 fprintf (sim_log, "%s> %s\n", do_arg[0], ocptr);\r
898 }\r
899 stat = stat & ~SCPE_DOFAILED; /* remove possible flag */\r
900 }\r
901 if ((staying || !interactive) && /* report error if staying */\r
902 (stat >= SCPE_BASE)) { /* or in cmdline file */\r
903 printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);\r
904 if (sim_log) fprintf (sim_log, "%s\n",\r
905 scp_error_messages[stat - SCPE_BASE]);\r
906 }\r
907 if (sim_vm_post != NULL) (*sim_vm_post) (TRUE);\r
908 } while (staying);\r
909\r
910fclose (fpin); /* close file */\r
911return stat;\r
912}\r
913\r
914/* Substitute_args - replace %n tokens in 'instr' with the do command's arguments\r
915\r
916 Calling sequence\r
917 instr = input string\r
918 tmpbuf = temp buffer\r
919 maxstr = min (len (instr), len (tmpbuf))\r
920 nargs = number of arguments\r
921 do_arg[10] = arguments\r
922*/\r
923\r
924void sub_args (char *instr, char *tmpbuf, int32 maxstr, int32 nargs, char *do_arg[])\r
925{\r
926char *ip, *op, *ap, *oend = tmpbuf + maxstr - 2;\r
927\r
928for (ip = instr, op = tmpbuf; *ip && (op < oend); ) {\r
929 if ((*ip == '\\') && (ip[1] == '%')) { /* \% = literal % */\r
930 ip++; /* skip \ */\r
931 if (*ip) *op++ = *ip++; /* copy next */\r
932 }\r
933 else if ((*ip == '%') && /* %n = sub */\r
934 ((ip[1] >= '1') && (ip[1] <= ('0'+ nargs - 1)))) {\r
935 ap = do_arg[ip[1] - '0'];\r
936 ip = ip + 2;\r
937 while (*ap && (op < oend)) *op++ = *ap++; /* copy the argument */\r
938 }\r
939 else *op++ = *ip++; /* literal character */\r
940 }\r
941*op = 0; /* term buffer */\r
942strcpy (instr, tmpbuf);\r
943return;\r
944}\r
945\r
946/* Assert command\r
947 \r
948 Syntax: ASSERT {<dev>} <reg>{<logical-op><value>}<conditional-op><value>\r
949\r
950 If <dev> is not specified, CPU is assumed. <value> is expressed in the radix\r
951 specified for <reg>. <logical-op> and <conditional-op> are the same as that\r
952 allowed for examine and deposit search specifications. */\r
953\r
954t_stat assert_cmd (int32 flag, char *cptr)\r
955{\r
956char gbuf[CBUFSIZE], *gptr, *aptr, *tptr;\r
957REG *rptr;\r
958uint32 idx;\r
959t_value val;\r
960t_stat r;\r
961\r
962aptr = cptr; /* save assertion */\r
963cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, cptr, &r); /* get sw, default */\r
964if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
965cptr = get_glyph (cptr, gbuf, 0); /* get register */\r
966rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */\r
967if (!rptr) return SCPE_NXREG; /* not there */\r
968if (*gptr == '[') { /* subscript? */\r
969 if (rptr->depth <= 1) return SCPE_ARG; /* array register? */\r
970 idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */\r
971 if ((gptr == tptr) || (*tptr++ != ']')) return SCPE_ARG;\r
972 gptr = tptr; /* update */\r
973 }\r
974else idx = 0; /* not array */\r
975if (idx >= rptr->depth) return SCPE_SUB; /* validate subscript */\r
976if (*gptr != 0) get_glyph (gptr, gbuf, 0); /* more? must be search */\r
977else {\r
978 if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
979 cptr = get_glyph (cptr, gbuf, 0); /* get search cond */\r
980 }\r
981if (*cptr != 0) return SCPE_2MARG; /* must be done */\r
982if (!get_search (gbuf, rptr->radix, &sim_stab)) /* parse condition */\r
983 return SCPE_MISVAL;\r
984val = get_rval (rptr, idx); /* get register value */\r
985if (test_search (val, &sim_stab)) return SCPE_OK; /* test condition */\r
986return SCPE_AFAIL; /* condition fails */\r
987}\r
988\r
989/* Set command */\r
990\r
991t_stat set_cmd (int32 flag, char *cptr)\r
992{\r
993int32 lvl;\r
994t_stat r;\r
995char gbuf[CBUFSIZE], *cvptr, *svptr;\r
996DEVICE *dptr;\r
997UNIT *uptr;\r
998MTAB *mptr;\r
999CTAB *gcmdp;\r
1000C1TAB *ctbr, *glbr;\r
1001\r
1002static CTAB set_glob_tab[] = {\r
1003 { "CONSOLE", &sim_set_console, 0 },\r
1004 { "BREAK", &brk_cmd, SSH_ST },\r
1005 { "TELNET", &sim_set_telnet, 0 }, /* deprecated */\r
1006 { "NOTELNET", &sim_set_notelnet, 0 }, /* deprecated */\r
1007 { "LOG", &sim_set_logon, 0 }, /* deprecated */\r
1008 { "NOLOG", &sim_set_logoff, 0 }, /* deprecated */\r
1009 { "DEBUG", &sim_set_debon, 0 }, /* deprecated */\r
1010 { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */\r
1011 { "THROTTLE", &sim_set_throt, 1 },\r
1012 { "NOTHROTTLE", &sim_set_throt, 0 },\r
1013 { NULL, NULL, 0 }\r
1014 };\r
1015\r
1016static C1TAB set_dev_tab[] = {\r
1017 { "OCTAL", &set_dev_radix, 8 },\r
1018 { "DECIMAL", &set_dev_radix, 10 },\r
1019 { "HEX", &set_dev_radix, 16 },\r
1020 { "ENABLED", &set_dev_enbdis, 1 },\r
1021 { "DISABLED", &set_dev_enbdis, 0 },\r
1022 { "DEBUG", &set_dev_debug, 1 },\r
1023 { "NODEBUG", &set_dev_debug, 0 },\r
1024 { NULL, NULL, 0 }\r
1025 };\r
1026\r
1027static C1TAB set_unit_tab[] = {\r
1028 { "ENABLED", &set_unit_enbdis, 1 },\r
1029 { "DISABLED", &set_unit_enbdis, 0 },\r
1030 { NULL, NULL, 0 }\r
1031 };\r
1032\r
1033GET_SWITCHES (cptr); /* get switches */\r
1034if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1035cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */\r
1036\r
1037if (dptr = find_dev (gbuf)) { /* device match? */\r
1038 uptr = dptr->units; /* first unit */\r
1039 ctbr = set_dev_tab; /* global table */\r
1040 lvl = MTAB_VDV; /* device match */\r
1041 }\r
1042else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */\r
1043 if (uptr == NULL) return SCPE_NXUN; /* invalid unit */\r
1044 ctbr = set_unit_tab; /* global table */\r
1045 lvl = MTAB_VUN; /* unit match */\r
1046 }\r
1047else if (gcmdp = find_ctab (set_glob_tab, gbuf)) /* global? */\r
1048 return gcmdp->action (gcmdp->arg, cptr); /* do the rest */\r
1049else return SCPE_NXDEV; /* no match */\r
1050if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1051\r
1052while (*cptr != 0) { /* do all mods */\r
1053 cptr = get_glyph (svptr = cptr, gbuf, ','); /* get modifier */\r
1054 if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */\r
1055 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {\r
1056 if ((mptr->mstring) && /* match string */\r
1057 (MATCH_CMD (gbuf, mptr->mstring) == 0)) { /* matches option? */\r
1058 if (mptr->mask & MTAB_XTD) { /* extended? */\r
1059 if ((lvl & mptr->mask) == 0) return SCPE_ARG;\r
1060 if ((lvl & MTAB_VUN) && (uptr->flags & UNIT_DIS))\r
1061 return SCPE_UDIS; /* unit disabled? */\r
1062 if (mptr->valid) { /* validation rtn? */\r
1063 if (cvptr && (mptr->mask & MTAB_NC))\r
1064 get_glyph_nc (svptr, gbuf, ',');\r
1065 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);\r
1066 if (r != SCPE_OK) return r;\r
1067 }\r
1068 else if (!mptr->desc) break; /* value desc? */\r
1069 else if (mptr->mask & MTAB_VAL) { /* take a value? */\r
1070 if (!cvptr) return SCPE_MISVAL; /* none? error */\r
1071 r = dep_reg (0, cvptr, (REG *) mptr->desc, 0);\r
1072 if (r != SCPE_OK) return r;\r
1073 }\r
1074 else if (cvptr) return SCPE_ARG; /* = value? */\r
1075 else *((int32 *) mptr->desc) = mptr->match;\r
1076 } /* end if xtd */\r
1077 else { /* old style */\r
1078 if (cvptr) return SCPE_ARG; /* = value? */\r
1079 if (uptr->flags & UNIT_DIS) /* disabled? */\r
1080 return SCPE_UDIS;\r
1081 if ((mptr->valid) && ((r = mptr->valid\r
1082 (uptr, mptr->match, cvptr, mptr->desc))\r
1083 != SCPE_OK)) return r; /* invalid? */\r
1084 uptr->flags = (uptr->flags & ~(mptr->mask)) |\r
1085 (mptr->match & mptr->mask); /* set new value */\r
1086 } /* end else xtd */\r
1087 break; /* terminate for */\r
1088 } /* end if match */\r
1089 } /* end for */\r
1090 if (!mptr || (mptr->mask == 0)) { /* no match? */\r
1091 if (glbr = find_c1tab (ctbr, gbuf)) { /* global match? */\r
1092 r = glbr->action (dptr, uptr, glbr->arg, cvptr); /* do global */\r
1093 if (r != SCPE_OK) return r;\r
1094 }\r
1095 else if (!dptr->modifiers) return SCPE_NOPARAM; /* no modifiers? */\r
1096 else return SCPE_NXPAR;\r
1097 } /* end if no mat */\r
1098 } /* end while */\r
1099return SCPE_OK; /* done all */\r
1100}\r
1101\r
1102/* Match CTAB/CTAB1 name */\r
1103\r
1104CTAB *find_ctab (CTAB *tab, char *gbuf)\r
1105{\r
1106for (; tab->name != NULL; tab++) {\r
1107 if (MATCH_CMD (gbuf, tab->name) == 0) return tab;\r
1108 }\r
1109return NULL;\r
1110}\r
1111\r
1112C1TAB *find_c1tab (C1TAB *tab, char *gbuf)\r
1113{\r
1114for (; tab->name != NULL; tab++) {\r
1115 if (MATCH_CMD (gbuf, tab->name) == 0) return tab;\r
1116 }\r
1117return NULL;\r
1118}\r
1119\r
1120/* Set device data radix routine */\r
1121\r
1122t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1123{\r
1124if (cptr) return SCPE_ARG;\r
1125dptr->dradix = flag & 037;\r
1126return SCPE_OK;\r
1127}\r
1128\r
1129/* Set device enabled/disabled routine */\r
1130\r
1131t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1132{\r
1133UNIT *up;\r
1134uint32 i;\r
1135\r
1136if (cptr) return SCPE_ARG;\r
1137if ((dptr->flags & DEV_DISABLE) == 0) return SCPE_NOFNC;/* allowed? */\r
1138if (flag) { /* enable? */\r
1139 if ((dptr->flags & DEV_DIS) == 0) /* already enb? ok */\r
1140 return SCPE_OK;\r
1141 dptr->flags = dptr->flags & ~DEV_DIS; /* no, enable */\r
1142 }\r
1143else {\r
1144 if (dptr->flags & DEV_DIS) return SCPE_OK; /* already dsb? ok */\r
1145 for (i = 0; i < dptr->numunits; i++) { /* check units */\r
1146 up = (dptr->units) + i; /* att or active? */\r
1147 if ((up->flags & UNIT_ATT) || sim_is_active (up))\r
1148 return SCPE_NOFNC; /* can't do it */\r
1149 }\r
1150 dptr->flags = dptr->flags | DEV_DIS; /* disable */\r
1151 }\r
1152if (dptr->reset) return dptr->reset (dptr); /* reset device */\r
1153else return SCPE_OK;\r
1154}\r
1155\r
1156/* Set unit enabled/disabled routine */\r
1157\r
1158t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1159{\r
1160if (cptr) return SCPE_ARG;\r
1161if (!(uptr->flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */\r
1162if (flag) uptr->flags = uptr->flags & ~UNIT_DIS; /* enb? enable */\r
1163else {\r
1164 if ((uptr->flags & UNIT_ATT) || /* dsb */\r
1165 sim_is_active (uptr)) return SCPE_NOFNC; /* more tests */\r
1166 uptr->flags = uptr->flags | UNIT_DIS; /* disable */\r
1167 }\r
1168return SCPE_OK;\r
1169}\r
1170\r
1171/* Set device debug enabled/disabled routine */\r
1172\r
1173t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1174{\r
1175char gbuf[CBUFSIZE];\r
1176DEBTAB *dep;\r
1177\r
1178if ((dptr->flags & DEV_DEBUG) == 0) return SCPE_NOFNC;\r
1179if (cptr == NULL) { /* no arguments? */\r
1180 dptr->dctrl = flag; /* disable/enable w/o table */\r
1181 if (flag && dptr->debflags) { /* enable with table? */\r
1182 for (dep = dptr->debflags; dep->name != NULL; dep++)\r
1183 dptr->dctrl = dptr->dctrl | dep->mask; /* set all */\r
1184 }\r
1185 return SCPE_OK;\r
1186 }\r
1187if (dptr->debflags == NULL) return SCPE_ARG; /* must have table */\r
1188while (*cptr) {\r
1189 cptr = get_glyph (cptr, gbuf, ';'); /* get debug flag */\r
1190 for (dep = dptr->debflags; dep->name != NULL; dep++) {\r
1191 if (strcmp (dep->name, gbuf) == 0) { /* match? */\r
1192 if (flag) dptr->dctrl = dptr->dctrl | dep->mask;\r
1193 else dptr->dctrl = dptr->dctrl & ~dep->mask;\r
1194 break;\r
1195 }\r
1196 } /* end for */\r
1197 if (dep->mask == 0) return SCPE_ARG; /* no match? */\r
1198 } /* end while */\r
1199return SCPE_OK;\r
1200}\r
1201\r
1202/* Show command */\r
1203\r
1204t_stat show_cmd (int32 flag, char *cptr)\r
1205{\r
1206t_stat r;\r
1207\r
1208cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r); /* get sw, ofile */\r
1209if (!cptr) return r; /* error? */\r
1210if (sim_ofile) { /* output file? */\r
1211 r = show_cmd_fi (sim_ofile, flag, cptr); /* do show */\r
1212 fclose (sim_ofile);\r
1213 }\r
1214else {\r
1215 r = show_cmd_fi (stdout, flag, cptr); /* no, stdout, log */\r
1216 if (sim_log) show_cmd_fi (sim_log, flag, cptr);\r
1217 }\r
1218return r;\r
1219}\r
1220\r
1221t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr)\r
1222{\r
1223int32 lvl;\r
1224char gbuf[CBUFSIZE], *cvptr;\r
1225DEVICE *dptr;\r
1226UNIT *uptr;\r
1227MTAB *mptr;\r
1228SHTAB *shtb, *shptr;\r
1229\r
1230static SHTAB show_glob_tab[] = {\r
1231 { "CONFIGURATION", &show_config, 0 },\r
1232 { "DEVICES", &show_config, 1 },\r
1233 { "QUEUE", &show_queue, 0 },\r
1234 { "TIME", &show_time, 0 },\r
1235 { "MODIFIERS", &show_mod_names, 0 },\r
1236 { "NAMES", &show_log_names, 0 },\r
1237 { "VERSION", &show_version, 1 },\r
1238 { "CONSOLE", &sim_show_console, 0 },\r
1239 { "BREAK", &show_break, 0 },\r
1240 { "LOG", &sim_show_log, 0 }, /* deprecated */\r
1241 { "TELNET", &sim_show_telnet, 0 }, /* deprecated */\r
1242 { "DEBUG", &sim_show_debug, 0 }, /* deprecated */\r
1243 { "THROTTLE", &sim_show_throt, 0 },\r
1244 { NULL, NULL, 0 }\r
1245 };\r
1246\r
1247static SHTAB show_dev_tab[] = {\r
1248 { "RADIX", &show_dev_radix, 0 },\r
1249 { "DEBUG", &show_dev_debug, 0 },\r
1250 { "MODIFIERS", &show_dev_modifiers, 0 },\r
1251 { "NAMES", &show_dev_logicals, 0 },\r
1252 { NULL, NULL, 0 }\r
1253 };\r
1254\r
1255static SHTAB show_unit_tab[] = {\r
1256 { NULL, NULL, 0 }\r
1257 };\r
1258\r
1259GET_SWITCHES (cptr); /* get switches */\r
1260if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1261cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
1262if (shptr = find_shtab (show_glob_tab, gbuf)) /* global? */\r
1263 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);\r
1264\r
1265if (dptr = find_dev (gbuf)) { /* device match? */\r
1266 uptr = dptr->units; /* first unit */\r
1267 shtb = show_dev_tab; /* global table */\r
1268 lvl = MTAB_VDV; /* device match */\r
1269 }\r
1270else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */\r
1271 if (uptr == NULL) return SCPE_NXUN; /* invalid unit */\r
1272 if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */\r
1273 shtb = show_unit_tab; /* global table */\r
1274 lvl = MTAB_VUN; /* unit match */\r
1275 }\r
1276else return SCPE_NXDEV; /* no match */\r
1277\r
1278if (*cptr == 0) { /* now eol? */\r
1279 return (lvl == MTAB_VDV)?\r
1280 show_device (ofile, dptr, 0):\r
1281 show_unit (ofile, dptr, uptr, -1);\r
1282 }\r
1283if (dptr->modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */\r
1284\r
1285while (*cptr != 0) { /* do all mods */\r
1286 cptr = get_glyph (cptr, gbuf, ','); /* get modifier */\r
1287 if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */\r
1288 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {\r
1289 if (((mptr->mask & MTAB_XTD)? /* right level? */\r
1290 (mptr->mask & lvl): (MTAB_VUN & lvl)) && \r
1291 ((mptr->disp && mptr->pstring && /* named disp? */\r
1292 (MATCH_CMD (gbuf, mptr->pstring) == 0)) ||\r
1293 ((mptr->mask & MTAB_VAL) && /* named value? */\r
1294 mptr->mstring &&\r
1295 (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {\r
1296 if (cvptr && !(mptr->mask & MTAB_SHP)) return SCPE_ARG;\r
1297 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);\r
1298 break;\r
1299 } /* end if */\r
1300 } /* end for */\r
1301 if (mptr->mask == 0) { /* no match? */\r
1302 if (shptr = find_shtab (shtb, gbuf)) /* global match? */\r
1303 shptr->action (ofile, dptr, uptr, shptr->arg, cptr);\r
1304 else return SCPE_ARG;\r
1305 } /* end if */\r
1306 } /* end while */\r
1307return SCPE_OK;\r
1308}\r
1309\r
1310SHTAB *find_shtab (SHTAB *tab, char *gbuf)\r
1311{\r
1312for (; tab->name != NULL; tab++) {\r
1313 if (MATCH_CMD (gbuf, tab->name) == 0) return tab;\r
1314 }\r
1315return NULL;\r
1316}\r
1317\r
1318/* Show device and unit */\r
1319\r
1320t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)\r
1321{\r
1322uint32 j, udbl, ucnt;\r
1323UNIT *uptr;\r
1324\r
1325fprintf (st, "%s", sim_dname (dptr)); /* print dev name */\r
1326if (qdisable (dptr)) { /* disabled? */\r
1327 fprintf (st, ", disabled\n");\r
1328 return SCPE_OK;\r
1329 }\r
1330for (j = ucnt = udbl = 0; j < dptr->numunits; j++) { /* count units */\r
1331 uptr = dptr->units + j;\r
1332 if (uptr->flags & UNIT_DISABLE) udbl++;\r
1333 if (!(uptr->flags & UNIT_DIS)) ucnt++;\r
1334 }\r
1335show_all_mods (st, dptr, dptr->units, MTAB_VDV); /* show dev mods */\r
1336if (dptr->numunits == 0) fprintf (st, "\n");\r
1337else {\r
1338 if (udbl && (ucnt == 0)) fprintf (st, ", all units disabled\n");\r
1339 else if (ucnt > 1) fprintf (st, ", %d units\n", ucnt);\r
1340 else if (flag) fprintf (st, "\n");\r
1341 }\r
1342if (flag) return SCPE_OK; /* dev only? */\r
1343for (j = 0; j < dptr->numunits; j++) { /* loop thru units */\r
1344 uptr = dptr->units + j;\r
1345 if ((uptr->flags & UNIT_DIS) == 0)\r
1346 show_unit (st, dptr, uptr, ucnt);\r
1347 }\r
1348return SCPE_OK;\r
1349}\r
1350\r
1351t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)\r
1352{\r
1353int32 u = uptr - dptr->units;\r
1354\r
1355if (flag > 1) fprintf (st, " %s%d", sim_dname (dptr), u);\r
1356else if (flag < 0) fprintf (st, "%s%d", sim_dname (dptr), u);\r
1357if (uptr->flags & UNIT_FIX) {\r
1358 fprintf (st, ", ");\r
1359 fprint_capac (st, dptr, uptr);\r
1360 }\r
1361if (uptr->flags & UNIT_ATT) {\r
1362 fprintf (st, ", attached to %s", uptr->filename);\r
1363 if (uptr->flags & UNIT_RO) fprintf (st, ", read only");\r
1364 }\r
1365else if (uptr->flags & UNIT_ATTABLE)\r
1366 fprintf (st, ", not attached");\r
1367show_all_mods (st, dptr, uptr, MTAB_VUN); /* show unit mods */ \r
1368fprintf (st, "\n");\r
1369return SCPE_OK;\r
1370}\r
1371\r
1372void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)\r
1373{\r
1374t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000;\r
1375t_addr mval = kval * kval;\r
1376t_addr psize = uptr->capac;\r
1377char scale, width;\r
1378\r
1379if ((dptr->dwidth / dptr->aincr) > 8) width = 'W';\r
1380else width = 'B';\r
1381if (uptr->capac < (kval * 10)) scale = 0;\r
1382else if (uptr->capac < (mval * 10)) {\r
1383 scale = 'K';\r
1384 psize = psize / kval;\r
1385 }\r
1386else {\r
1387 scale = 'M';\r
1388 psize = psize / mval;\r
1389 }\r
1390fprint_val (st, (t_value) psize, 10, T_ADDR_W, PV_LEFT);\r
1391if (scale) fputc (scale, st);\r
1392fputc (width, st);\r
1393return;\r
1394}\r
1395\r
1396/* Show <global name> processors */\r
1397\r
1398t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1399{\r
1400int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH, vdelt = SIM_DELTA;\r
1401\r
1402if (cptr && (*cptr != 0)) return SCPE_2MARG;\r
1403fprintf (st, "%s simulator V%d.%d-%d", sim_name, vmaj, vmin, vpat);\r
1404if (vdelt) fprintf (st, "(%d)", vdelt);\r
1405if (flag) fprintf (st, " [%s, %s, %s]", sim_si64, sim_sa64, sim_snet);\r
1406fprintf (st, "\n");\r
1407return SCPE_OK;\r
1408}\r
1409\r
1410t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr)\r
1411{\r
1412int32 i;\r
1413DEVICE *dptr;\r
1414\r
1415if (cptr && (*cptr != 0)) return SCPE_2MARG;\r
1416fprintf (st, "%s simulator configuration\n\n", sim_name);\r
1417for (i = 0; (dptr = sim_devices[i]) != NULL; i++)\r
1418 show_device (st, dptr, flag);\r
1419return SCPE_OK;\r
1420}\r
1421\r
1422t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr)\r
1423{\r
1424int32 i;\r
1425DEVICE *dptr;\r
1426\r
1427if (cptr && (*cptr != 0)) return SCPE_2MARG;\r
1428for (i = 0; (dptr = sim_devices[i]) != NULL; i++)\r
1429 show_dev_logicals (st, dptr, NULL, 1, cptr);\r
1430return SCPE_OK;\r
1431}\r
1432\r
1433t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1434{\r
1435if (dptr->lname) fprintf (st, "%s -> %s\n", dptr->lname, dptr->name);\r
1436else if (!flag) fputs ("no logical name assigned\n", st);\r
1437return SCPE_OK;\r
1438}\r
1439\r
1440t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr)\r
1441{\r
1442DEVICE *dptr;\r
1443UNIT *uptr;\r
1444int32 accum;\r
1445\r
1446if (cptr && (*cptr != 0)) return SCPE_2MARG;\r
1447if (sim_clock_queue == NULL) {\r
1448 fprintf (st, "%s event queue empty, time = %.0f\n",\r
1449 sim_name, sim_time);\r
1450 return SCPE_OK;\r
1451 }\r
1452fprintf (st, "%s event queue status, time = %.0f\n",\r
1453 sim_name, sim_time);\r
1454accum = 0;\r
1455for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) {\r
1456 if (uptr == &sim_step_unit) fprintf (st, " Step timer");\r
1457 else if ((dptr = find_dev_from_unit (uptr)) != NULL) {\r
1458 fprintf (st, " %s", sim_dname (dptr));\r
1459 if (dptr->numunits > 1) fprintf (st, " unit %d",\r
1460 (int32) (uptr - dptr->units));\r
1461 }\r
1462 else fprintf (st, " Unknown");\r
1463 fprintf (st, " at %d\n", accum + uptr->time);\r
1464 accum = accum + uptr->time;\r
1465 }\r
1466return SCPE_OK;\r
1467}\r
1468\r
1469t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1470{\r
1471if (cptr && (*cptr != 0)) return SCPE_2MARG;\r
1472fprintf (st, "Time:\t%.0f\n", sim_time);\r
1473return SCPE_OK;\r
1474}\r
1475\r
1476t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1477{\r
1478t_stat r;\r
1479\r
1480if (cptr && (*cptr != 0)) r = ssh_break (st, cptr, 1); /* more? */\r
1481else r = sim_brk_showall (st, sim_switches);\r
1482return r;\r
1483}\r
1484\r
1485t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1486{\r
1487fprintf (st, "Radix=%d\n", dptr->dradix);\r
1488return SCPE_OK;\r
1489}\r
1490\r
1491t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1492{\r
1493int32 any = 0;\r
1494DEBTAB *dep;\r
1495\r
1496if (dptr->flags & DEV_DEBUG) {\r
1497 if (dptr->dctrl == 0) fputs ("Debugging disabled", st);\r
1498 else if (dptr->debflags == NULL) fputs ("Debugging enabled", st);\r
1499 else {\r
1500 fputs ("Debug=", st);\r
1501 for (dep = dptr->debflags; dep->name != NULL; dep++) {\r
1502 if (dptr->dctrl & dep->mask) {\r
1503 if (any) fputc (';', st);\r
1504 fputs (dep->name, st);\r
1505 any = 1;\r
1506 }\r
1507 }\r
1508 }\r
1509 fputc ('\n', st);\r
1510 return SCPE_OK;\r
1511 }\r
1512else return SCPE_NOFNC;\r
1513}\r
1514\r
1515/* Show modifiers */\r
1516\r
1517t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr)\r
1518{\r
1519int32 i;\r
1520DEVICE *dptr;\r
1521\r
1522if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */\r
1523for (i = 0; (dptr = sim_devices[i]) != NULL; i++) \r
1524 show_dev_modifiers (st, dptr, NULL, flag, cptr);\r
1525return SCPE_OK;\r
1526}\r
1527\r
1528t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r
1529{\r
1530int any, enb;\r
1531MTAB *mptr;\r
1532DEBTAB *dep;\r
1533\r
1534any = enb = 0;\r
1535if (dptr->modifiers) {\r
1536 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {\r
1537 if (mptr->mstring) {\r
1538 if (strcmp (mptr->mstring, "ENABLED") == 0) enb = 1;\r
1539 if (any++) fprintf (st, ", %s", mptr->mstring);\r
1540 else fprintf (st, "%s\t%s", sim_dname (dptr), mptr->mstring);\r
1541 }\r
1542 }\r
1543 }\r
1544if (dptr->flags & DEV_DEBUG) {\r
1545 if (any++) fprintf (st, ", DEBUG, NODEBUG");\r
1546 else fprintf (st, "%s\tDEBUG, NODEBUG", sim_dname (dptr));\r
1547 }\r
1548if (!enb && (dptr->flags & DEV_DISABLE)) {\r
1549 if (any++) fprintf (st, ", ENABLED, DISABLED");\r
1550 else fprintf (st, "%s\tENABLED, DISABLED", sim_dname (dptr));\r
1551 }\r
1552if (any) fprintf (st, "\n");\r
1553if ((dptr->flags & DEV_DEBUG) && dptr->debflags) {\r
1554 fprintf (st, "%s\tDEBUG=", sim_dname (dptr));\r
1555 for (dep = dptr->debflags; dep->name != NULL; dep++)\r
1556 fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ","), dep->name);\r
1557 fprintf (st, "\n");\r
1558 }\r
1559return SCPE_OK;\r
1560}\r
1561\r
1562t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)\r
1563{\r
1564MTAB *mptr;\r
1565\r
1566if (dptr->modifiers == NULL) return SCPE_OK;\r
1567for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {\r
1568 if (mptr->pstring && ((mptr->mask & MTAB_XTD)?\r
1569 ((mptr->mask & flag) && !(mptr->mask & MTAB_NMO)): \r
1570 ((MTAB_VUN & flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {\r
1571 fputs (", ", st);\r
1572 show_one_mod (st, dptr, uptr, mptr, NULL, 0);\r
1573 }\r
1574 }\r
1575return SCPE_OK;\r
1576}\r
1577\r
1578t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,\r
1579 char *cptr, int32 flag)\r
1580{\r
1581t_value val;\r
1582\r
1583if (mptr->disp) mptr->disp (st, uptr, mptr->match, cptr? cptr: mptr->desc);\r
1584else if ((mptr->mask & MTAB_XTD) && (mptr->mask & MTAB_VAL)) {\r
1585 REG *rptr = (REG *) mptr->desc;\r
1586 fprintf (st, "%s=", mptr->pstring);\r
1587 val = get_rval (rptr, 0);\r
1588 fprint_val (st, val, rptr->radix, rptr->width,\r
1589 rptr->flags & REG_FMT);\r
1590 }\r
1591else fputs (mptr->pstring, st);\r
1592if (flag && !((mptr->mask & MTAB_XTD) &&\r
1593 (mptr->mask & MTAB_NMO))) fputc ('\n', st);\r
1594return SCPE_OK;\r
1595}\r
1596\r
1597/* Breakpoint commands */\r
1598\r
1599t_stat brk_cmd (int32 flg, char *cptr)\r
1600{\r
1601GET_SWITCHES (cptr); /* get switches */\r
1602return ssh_break (NULL, cptr, flg); /* call common code */\r
1603}\r
1604\r
1605t_stat ssh_break (FILE *st, char *cptr, int32 flg)\r
1606{\r
1607char gbuf[CBUFSIZE], *tptr, *t1ptr, *aptr;\r
1608DEVICE *dptr = sim_dflt_dev;\r
1609UNIT *uptr = dptr->units;\r
1610t_stat r;\r
1611t_addr lo, hi, max = uptr->capac - 1;\r
1612int32 cnt;\r
1613\r
1614if (sim_brk_types == 0) return SCPE_NOFNC;\r
1615if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR;\r
1616if (aptr = strchr (cptr, ';')) { /* ;action? */\r
1617 if (flg != SSH_ST) return SCPE_ARG; /* only on SET */\r
1618 *aptr++ = 0; /* separate strings */\r
1619 }\r
1620if (*cptr == 0) { /* no argument? */\r
1621 lo = (t_addr) get_rval (sim_PC, 0); /* use PC */\r
1622 return ssh_break_one (st, flg, lo, 0, aptr);\r
1623 }\r
1624while (*cptr) {\r
1625 cptr = get_glyph (cptr, gbuf, ',');\r
1626 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);\r
1627 if (tptr == NULL) return SCPE_ARG;\r
1628 if (*tptr == '[') {\r
1629 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);\r
1630 if ((tptr == t1ptr) || (*t1ptr != ']') ||\r
1631 (flg != SSH_ST)) return SCPE_ARG;\r
1632 tptr = t1ptr + 1;\r
1633 }\r
1634 else cnt = 0;\r
1635 if (*tptr != 0) return SCPE_ARG;\r
1636 if ((lo == 0) && (hi == max)) {\r
1637 if (flg == SSH_CL) sim_brk_clrall (sim_switches);\r
1638 else if (flg == SSH_SH) sim_brk_showall (st, sim_switches);\r
1639 else return SCPE_ARG;\r
1640 }\r
1641 else { \r
1642 for ( ; lo <= hi; lo = lo + 1) {\r
1643 r = ssh_break_one (st, flg, lo, cnt, aptr);\r
1644 if (r != SCPE_OK) return r;\r
1645 }\r
1646 }\r
1647 }\r
1648return SCPE_OK;\r
1649}\r
1650\r
1651t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, char *aptr)\r
1652{\r
1653switch (flg) {\r
1654\r
1655 case SSH_ST:\r
1656 return sim_brk_set (lo, sim_switches, cnt, aptr);\r
1657 break;\r
1658\r
1659 case SSH_CL:\r
1660 return sim_brk_clr (lo, sim_switches);\r
1661 break;\r
1662\r
1663 case SSH_SH:\r
1664 return sim_brk_show (st, lo, sim_switches);\r
1665 break;\r
1666\r
1667 default:\r
1668 return SCPE_ARG;\r
1669 }\r
1670}\r
1671\r
1672/* Reset command and routines\r
1673\r
1674 re[set] reset all devices\r
1675 re[set] all reset all devices\r
1676 re[set] device reset specific device\r
1677*/\r
1678\r
1679t_stat reset_cmd (int32 flag, char *cptr)\r
1680{\r
1681char gbuf[CBUFSIZE];\r
1682DEVICE *dptr;\r
1683\r
1684GET_SWITCHES (cptr); /* get switches */\r
1685if (*cptr == 0) return (reset_all (0)); /* reset(cr) */\r
1686cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
1687if (*cptr != 0) return SCPE_2MARG; /* now eol? */\r
1688if (strcmp (gbuf, "ALL") == 0) return (reset_all (0));\r
1689dptr = find_dev (gbuf); /* locate device */\r
1690if (dptr == NULL) return SCPE_NXDEV; /* found it? */\r
1691if (dptr->reset != NULL) return dptr->reset (dptr);\r
1692else return SCPE_OK;\r
1693}\r
1694\r
1695/* Reset devices start..end\r
1696\r
1697 Inputs:\r
1698 start = number of starting device\r
1699 Outputs:\r
1700 status = error status\r
1701*/\r
1702\r
1703t_stat reset_all (uint32 start)\r
1704{\r
1705DEVICE *dptr;\r
1706uint32 i;\r
1707t_stat reason;\r
1708\r
1709for (i = 0; i < start; i++) {\r
1710 if (sim_devices[i] == NULL) return SCPE_IERR;\r
1711 }\r
1712for (i = start; (dptr = sim_devices[i]) != NULL; i++) {\r
1713 if (dptr->reset != NULL) {\r
1714 reason = dptr->reset (dptr);\r
1715 if (reason != SCPE_OK) return reason;\r
1716 }\r
1717 }\r
1718return SCPE_OK;\r
1719}\r
1720\r
1721/* Reset to powerup state\r
1722\r
1723 Inputs:\r
1724 start = number of starting device\r
1725 Outputs:\r
1726 status = error status\r
1727*/\r
1728\r
1729t_stat reset_all_p (uint32 start)\r
1730{\r
1731t_stat r;\r
1732int32 old_sw = sim_switches;\r
1733\r
1734sim_switches = SWMASK ('P');\r
1735r = reset_all (start);\r
1736sim_switches = old_sw;\r
1737return r;\r
1738}\r
1739\r
1740/* Load and dump commands\r
1741\r
1742 lo[ad] filename {arg} load specified file\r
1743 du[mp] filename {arg} dump to specified file\r
1744*/\r
1745\r
1746t_stat load_cmd (int32 flag, char *cptr)\r
1747{\r
1748char gbuf[CBUFSIZE];\r
1749FILE *loadfile;\r
1750t_stat reason;\r
1751\r
1752GET_SWITCHES (cptr); /* get switches */\r
1753if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1754cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */\r
1755loadfile = sim_fopen (gbuf, flag? "wb": "rb"); /* open for wr/rd */\r
1756if (loadfile == NULL) return SCPE_OPENERR;\r
1757GET_SWITCHES (cptr); /* get switches */\r
1758reason = sim_load (loadfile, cptr, gbuf, flag); /* load or dump */\r
1759fclose (loadfile);\r
1760return reason;\r
1761}\r
1762\r
1763/* Attach command\r
1764\r
1765 at[tach] unit file attach specified unit to file\r
1766*/\r
1767\r
1768t_stat attach_cmd (int32 flag, char *cptr)\r
1769{\r
1770char gbuf[CBUFSIZE];\r
1771DEVICE *dptr;\r
1772UNIT *uptr;\r
1773t_stat r;\r
1774\r
1775GET_SWITCHES (cptr); /* get switches */\r
1776if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1777cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
1778GET_SWITCHES (cptr); /* get switches */\r
1779if (*cptr == 0) return SCPE_2FARG; /* now eol? */\r
1780dptr = find_unit (gbuf, &uptr); /* locate unit */\r
1781if (dptr == NULL) return SCPE_NXDEV; /* found dev? */\r
1782if (uptr == NULL) return SCPE_NXUN; /* valid unit? */\r
1783if (uptr->flags & UNIT_ATT) { /* already attached? */\r
1784 r = scp_detach_unit (dptr, uptr); /* detach it */\r
1785 if (r != SCPE_OK) return r; /* error? */\r
1786 }\r
1787sim_trim_endspc (cptr); /* trim trailing spc */\r
1788return scp_attach_unit (dptr, uptr, cptr); /* attach */\r
1789}\r
1790\r
1791/* Call device-specific or file-oriented attach unit routine */\r
1792\r
1793t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, char *cptr)\r
1794{\r
1795if (dptr->attach != NULL) /* device routine? */\r
1796 return dptr->attach (uptr, cptr); /* call it */\r
1797return attach_unit (uptr, cptr); /* no, std routine */\r
1798}\r
1799\r
1800/* Attach unit to file */\r
1801\r
1802t_stat attach_unit (UNIT *uptr, char *cptr)\r
1803{\r
1804DEVICE *dptr;\r
1805\r
1806if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */\r
1807if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */\r
1808if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT;\r
1809if (dptr->flags & DEV_RAWONLY) return SCPE_NOFNC; /* raw mode only? */\r
1810uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */\r
1811if (uptr->filename == NULL) return SCPE_MEM;\r
1812strncpy (uptr->filename, cptr, CBUFSIZE); /* save name */\r
1813if (sim_switches & SWMASK ('R')) { /* read only? */\r
1814 if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */\r
1815 return attach_err (uptr, SCPE_NORO); /* no, error */\r
1816 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */\r
1817 if (uptr->fileref == NULL) /* open fail? */\r
1818 return attach_err (uptr, SCPE_OPENERR); /* yes, error */\r
1819 uptr->flags = uptr->flags | UNIT_RO; /* set rd only */\r
1820 if (!sim_quiet) printf ("%s: unit is read only\n", sim_dname (dptr));\r
1821 }\r
1822else { /* normal */\r
1823 uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */\r
1824 if (uptr->fileref == NULL) { /* open fail? */\r
1825 if ((errno == EROFS) || (errno == EACCES)) { /* read only? */\r
1826 if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */\r
1827 return attach_err (uptr, SCPE_NORO); /* no error */\r
1828 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */\r
1829 if (uptr->fileref == NULL) /* open fail? */\r
1830 return attach_err (uptr, SCPE_OPENERR); /* yes, error */\r
1831 uptr->flags = uptr->flags | UNIT_RO; /* set rd only */\r
1832 if (!sim_quiet) printf ("%s: unit is read only\n", sim_dname (dptr));\r
1833 }\r
1834 else { /* doesn't exist */\r
1835 if (sim_switches & SWMASK ('E')) /* must exist? */\r
1836 return attach_err (uptr, SCPE_OPENERR); /* yes, error */\r
1837 uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */\r
1838 if (uptr->fileref == NULL) /* open fail? */\r
1839 return attach_err (uptr, SCPE_OPENERR); /* yes, error */\r
1840 if (!sim_quiet) printf ("%s: creating new file\n", sim_dname (dptr));\r
1841 }\r
1842 } /* end if null */\r
1843 } /* end else */\r
1844if (uptr->flags & UNIT_BUFABLE) { /* buffer? */\r
1845 uint32 cap = ((uint32) uptr->capac) / dptr->aincr; /* effective size */\r
1846 if (uptr->flags & UNIT_MUSTBUF) /* dyn alloc? */\r
1847 uptr->filebuf = calloc (cap, SZ_D (dptr)); /* allocate */\r
1848 if (uptr->filebuf == NULL) /* no buffer? */\r
1849 return attach_err (uptr, SCPE_MEM); /* error */\r
1850 if (!sim_quiet) printf ("%s: buffering file in memory\n", sim_dname (dptr));\r
1851 uptr->hwmark = sim_fread (uptr->filebuf, /* read file */\r
1852 SZ_D (dptr), cap, uptr->fileref);\r
1853 uptr->flags = uptr->flags | UNIT_BUF; /* set buffered */\r
1854 }\r
1855uptr->flags = uptr->flags | UNIT_ATT;\r
1856uptr->pos = 0;\r
1857return SCPE_OK;\r
1858}\r
1859\r
1860t_stat attach_err (UNIT *uptr, t_stat stat)\r
1861{\r
1862free (uptr->filename);\r
1863uptr->filename = NULL;\r
1864return stat;\r
1865}\r
1866\r
1867/* Detach command\r
1868\r
1869 det[ach] all detach all units\r
1870 det[ach] unit detach specified unit\r
1871*/\r
1872\r
1873t_stat detach_cmd (int32 flag, char *cptr)\r
1874{\r
1875char gbuf[CBUFSIZE];\r
1876DEVICE *dptr;\r
1877UNIT *uptr;\r
1878\r
1879GET_SWITCHES (cptr); /* get switches */\r
1880if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1881cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
1882if (*cptr != 0) return SCPE_2MARG; /* now eol? */\r
1883if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE));\r
1884dptr = find_unit (gbuf, &uptr); /* locate unit */\r
1885if (dptr == NULL) return SCPE_NXDEV; /* found dev? */\r
1886if (uptr == NULL) return SCPE_NXUN; /* valid unit? */\r
1887return scp_detach_unit (dptr, uptr); /* detach */\r
1888}\r
1889\r
1890/* Detach devices start..end\r
1891\r
1892 Inputs:\r
1893 start = number of starting device\r
1894 shutdown = TRUE if simulator shutting down\r
1895 Outputs:\r
1896 status = error status\r
1897\r
1898 Note that during shutdown, detach routines for non-attachable devices\r
1899 will be called. These routines can implement simulator shutdown.\r
1900*/\r
1901\r
1902t_stat detach_all (int32 start, t_bool shutdown)\r
1903{\r
1904uint32 i, j;\r
1905DEVICE *dptr;\r
1906UNIT *uptr;\r
1907t_stat r;\r
1908\r
1909if ((start < 0) || (start > 1)) return SCPE_IERR;\r
1910for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */\r
1911 for (j = 0; j < dptr->numunits; j++) { /* loop thru units */\r
1912 uptr = (dptr->units) + j;\r
1913 if ((uptr->flags & UNIT_ATT) || /* attached? */\r
1914 (shutdown && dptr->detach && /* shutdown, spec rtn, */\r
1915 !(uptr->flags & UNIT_ATTABLE))) { /* !attachable? */\r
1916 r = scp_detach_unit (dptr, uptr); /* detach unit */\r
1917 if (r != SCPE_OK) return r;\r
1918 }\r
1919 }\r
1920 }\r
1921return SCPE_OK;\r
1922}\r
1923\r
1924/* Call device-specific or file-oriented detach unit routine */\r
1925\r
1926t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)\r
1927{\r
1928if (dptr->detach != NULL) return dptr->detach (uptr); /* device routine? */\r
1929return detach_unit (uptr); /* no, standard */\r
1930}\r
1931\r
1932/* Detach unit from file */\r
1933\r
1934t_stat detach_unit (UNIT *uptr)\r
1935{\r
1936DEVICE *dptr;\r
1937\r
1938if (uptr == NULL) return SCPE_IERR;\r
1939if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOATT; /* attachable? */\r
1940if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r
1941if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK;\r
1942if (uptr->flags & UNIT_BUF) {\r
1943 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;\r
1944 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {\r
1945 if (!sim_quiet) printf ("%s: writing buffer to file\n", sim_dname (dptr));\r
1946 rewind (uptr->fileref);\r
1947 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);\r
1948 if (ferror (uptr->fileref)) perror ("I/O error");\r
1949 }\r
1950 if (uptr->flags & UNIT_MUSTBUF) { /* dyn alloc? */\r
1951 free (uptr->filebuf); /* free buf */\r
1952 uptr->filebuf = NULL;\r
1953 }\r
1954 uptr->flags = uptr->flags & ~UNIT_BUF;\r
1955 }\r
1956uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);\r
1957free (uptr->filename);\r
1958uptr->filename = NULL;\r
1959if (fclose (uptr->fileref) == EOF) return SCPE_IOERR;\r
1960return SCPE_OK;\r
1961}\r
1962\r
1963/* Assign command\r
1964\r
1965 as[sign] device name assign logical name to device\r
1966*/\r
1967\r
1968t_stat assign_cmd (int32 flag, char *cptr)\r
1969{\r
1970char gbuf[CBUFSIZE];\r
1971DEVICE *dptr;\r
1972\r
1973GET_SWITCHES (cptr); /* get switches */\r
1974if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
1975cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
1976GET_SWITCHES (cptr); /* get switches */\r
1977if (*cptr == 0) return SCPE_2FARG; /* now eol? */\r
1978dptr = find_dev (gbuf); /* locate device */\r
1979if (dptr == NULL) return SCPE_NXDEV; /* found dev? */\r
1980cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
1981if (*cptr != 0) return SCPE_2MARG; /* must be eol */\r
1982if (find_dev (gbuf)) return SCPE_ARG; /* name in use */\r
1983deassign_device (dptr); /* release current */\r
1984return assign_device (dptr, gbuf);\r
1985}\r
1986\r
1987t_stat assign_device (DEVICE *dptr, char *cptr)\r
1988{\r
1989dptr->lname = (char *) calloc (CBUFSIZE, sizeof (char));\r
1990if (dptr->lname == NULL) return SCPE_MEM;\r
1991strncpy (dptr->lname, cptr, CBUFSIZE);\r
1992return SCPE_OK;\r
1993}\r
1994\r
1995/* Deassign command\r
1996\r
1997 dea[ssign] device deassign logical name\r
1998*/\r
1999\r
2000t_stat deassign_cmd (int32 flag, char *cptr)\r
2001{\r
2002char gbuf[CBUFSIZE];\r
2003DEVICE *dptr;\r
2004\r
2005GET_SWITCHES (cptr); /* get switches */\r
2006if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
2007cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
2008if (*cptr != 0) return SCPE_2MARG; /* now eol? */\r
2009dptr = find_dev (gbuf); /* locate device */\r
2010if (dptr == NULL) return SCPE_NXDEV; /* found dev? */\r
2011return deassign_device (dptr);\r
2012}\r
2013\r
2014t_stat deassign_device (DEVICE *dptr)\r
2015{\r
2016if (dptr->lname) free (dptr->lname);\r
2017dptr->lname = NULL;\r
2018return SCPE_OK;\r
2019}\r
2020\r
2021/* Get device display name */\r
2022\r
2023char *sim_dname (DEVICE *dptr)\r
2024{\r
2025return (dptr->lname? dptr->lname: dptr->name);\r
2026}\r
2027\r
2028/* Save command\r
2029\r
2030 sa[ve] filename save state to specified file\r
2031*/\r
2032\r
2033t_stat save_cmd (int32 flag, char *cptr)\r
2034{\r
2035FILE *sfile;\r
2036t_stat r;\r
2037GET_SWITCHES (cptr); /* get switches */\r
2038if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
2039sim_trim_endspc (cptr);\r
2040if ((sfile = sim_fopen (cptr, "wb")) == NULL) return SCPE_OPENERR;\r
2041r = sim_save (sfile);\r
2042fclose (sfile);\r
2043return r;\r
2044}\r
2045\r
2046t_stat sim_save (FILE *sfile)\r
2047{\r
2048void *mbuf;\r
2049int32 l, t;\r
2050uint32 i, j;\r
2051t_addr k, high;\r
2052t_value val;\r
2053t_stat r;\r
2054t_bool zeroflg;\r
2055size_t sz;\r
2056DEVICE *dptr;\r
2057UNIT *uptr;\r
2058REG *rptr;\r
2059\r
2060#define WRITE_I(xx) sim_fwrite (&(xx), sizeof (xx), 1, sfile)\r
2061\r
2062fprintf (sfile, "%s\n%s\n%s\n%s\n%s\n%.0f\n",\r
2063 save_vercur, /* [V2.5] save format */\r
2064 sim_name, /* sim name */\r
2065 sim_si64, sim_sa64, sim_snet, /* [V3.5] options */\r
2066 sim_time); /* [V3.2] sim time */\r
2067WRITE_I (sim_rtime); /* [V2.6] sim rel time */\r
2068\r
2069for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */\r
2070 fputs (dptr->name, sfile); /* device name */\r
2071 fputc ('\n', sfile);\r
2072 if (dptr->lname) fputs (dptr->lname, sfile); /* [V3.0] logical name */\r
2073 fputc ('\n', sfile);\r
2074 WRITE_I (dptr->flags); /* [V2.10] flags */\r
2075 for (j = 0; j < dptr->numunits; j++) {\r
2076 uptr = dptr->units + j;\r
2077 t = sim_is_active (uptr);\r
2078 WRITE_I (j); /* unit number */\r
2079 WRITE_I (t); /* activation time */\r
2080 WRITE_I (uptr->u3); /* unit specific */\r
2081 WRITE_I (uptr->u4);\r
2082 WRITE_I (uptr->u5); /* [V3.0] more unit */\r
2083 WRITE_I (uptr->u6);\r
2084 WRITE_I (uptr->flags); /* [V2.10] flags */\r
2085 WRITE_I (uptr->capac); /* [V3.5] capacity */\r
2086 if (uptr->flags & UNIT_ATT) fputs (uptr->filename, sfile);\r
2087 fputc ('\n', sfile);\r
2088 if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) &&\r
2089 (dptr->examine != NULL) &&\r
2090 ((high = uptr->capac) != 0)) { /* memory-like unit? */\r
2091 WRITE_I (high); /* [V2.5] write size */\r
2092 sz = SZ_D (dptr);\r
2093 if ((mbuf = calloc (SRBSIZ, sz)) == NULL) {\r
2094 fclose (sfile);\r
2095 return SCPE_MEM;\r
2096 }\r
2097 for (k = 0; k < high; ) { /* loop thru mem */\r
2098 zeroflg = TRUE;\r
2099 for (l = 0; (l < SRBSIZ) && (k < high); l++,\r
2100 k = k + (dptr->aincr)) { /* check for 0 block */\r
2101 r = dptr->examine (&val, k, uptr, SIM_SW_REST);\r
2102 if (r != SCPE_OK) return r;\r
2103 if (val) zeroflg = FALSE;\r
2104 SZ_STORE (sz, val, mbuf, l);\r
2105 } /* end for l */\r
2106 if (zeroflg) { /* all zero's? */\r
2107 l = -l; /* invert block count */\r
2108 WRITE_I (l); /* write only count */\r
2109 }\r
2110 else {\r
2111 WRITE_I (l); /* block count */\r
2112 sim_fwrite (mbuf, sz, l, sfile);\r
2113 }\r
2114 } /* end for k */\r
2115 free (mbuf); /* dealloc buffer */\r
2116 } /* end if mem */\r
2117 else { /* no memory */\r
2118 high = 0; /* write 0 */\r
2119 WRITE_I (high);\r
2120 } /* end else mem */\r
2121 } /* end unit loop */\r
2122 t = -1; /* end units */\r
2123 WRITE_I (t); /* write marker */\r
2124 for (rptr = dptr->registers; (rptr != NULL) && /* loop thru regs */\r
2125 (rptr->name != NULL); rptr++) {\r
2126 fputs (rptr->name, sfile); /* name */\r
2127 fputc ('\n', sfile);\r
2128 WRITE_I (rptr->depth); /* [V2.10] depth */\r
2129 for (j = 0; j < rptr->depth; j++) { /* loop thru values */\r
2130 val = get_rval (rptr, j); /* get value */\r
2131 WRITE_I (val); /* store */\r
2132 }\r
2133 }\r
2134 fputc ('\n', sfile); /* end registers */\r
2135 }\r
2136fputc ('\n', sfile); /* end devices */\r
2137return (ferror (sfile))? SCPE_IOERR: SCPE_OK; /* error during save? */\r
2138}\r
2139\r
2140/* Restore command\r
2141\r
2142 re[store] filename restore state from specified file\r
2143*/\r
2144\r
2145t_stat restore_cmd (int32 flag, char *cptr)\r
2146{\r
2147FILE *rfile;\r
2148t_stat r;\r
2149\r
2150GET_SWITCHES (cptr); /* get switches */\r
2151if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
2152sim_trim_endspc (cptr);\r
2153if ((rfile = sim_fopen (cptr, "rb")) == NULL) return SCPE_OPENERR;\r
2154r = sim_rest (rfile);\r
2155fclose (rfile);\r
2156return r;\r
2157}\r
2158\r
2159t_stat sim_rest (FILE *rfile)\r
2160{\r
2161char buf[CBUFSIZE];\r
2162void *mbuf;\r
2163int32 j, blkcnt, limit, unitno, time, flg;\r
2164uint32 us, depth;\r
2165t_addr k, high, old_capac;\r
2166t_value val, mask;\r
2167t_stat r;\r
2168size_t sz;\r
2169t_bool v35, v32;\r
2170DEVICE *dptr;\r
2171UNIT *uptr;\r
2172REG *rptr;\r
2173\r
2174#define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \\r
2175 return SCPE_IOERR;\r
2176#define READ_I(xx) if (sim_fread (&xx, sizeof (xx), 1, rfile) == 0) \\r
2177 return SCPE_IOERR;\r
2178\r
2179READ_S (buf); /* [V2.5+] read version */\r
2180v35 = v32 = FALSE;\r
2181if (strcmp (buf, save_vercur) == 0) v35 = v32 = TRUE; /* version 3.5? */ \r
2182else if (strcmp (buf, save_ver32) == 0) v32 = TRUE; /* version 3.2? */\r
2183else if (strcmp (buf, save_ver30) != 0) { /* version 3.0? */\r
2184 printf ("Invalid file version: %s\n", buf);\r
2185 return SCPE_INCOMP;\r
2186 }\r
2187READ_S (buf); /* read sim name */\r
2188if (strcmp (buf, sim_name)) { /* name match? */\r
2189 printf ("Wrong system type: %s\n", buf);\r
2190 return SCPE_INCOMP;\r
2191 }\r
2192if (v35) { /* [V3.5+] options */\r
2193 READ_S (buf); /* integer size */\r
2194 if (strcmp (buf, sim_si64) != 0) {\r
2195 printf ("Incompatible integer size, save file = %s\n", buf);\r
2196 return SCPE_INCOMP;\r
2197 }\r
2198 READ_S (buf); /* address size */\r
2199 if (strcmp (buf, sim_sa64) != 0) {\r
2200 printf ("Incompatible address size, save file = %s\n", buf);\r
2201 return SCPE_INCOMP;\r
2202 }\r
2203 READ_S (buf); /* Ethernet */\r
2204 }\r
2205if (v32) { /* [V3.2+] time as string */\r
2206 READ_S (buf);\r
2207 sscanf (buf, "%lf", &sim_time);\r
2208 }\r
2209else READ_I (sim_time); /* sim time */\r
2210READ_I (sim_rtime); /* [V2.6+] sim rel time */\r
2211\r
2212for ( ;; ) { /* device loop */\r
2213 READ_S (buf); /* read device name */\r
2214 if (buf[0] == 0) break; /* last? */\r
2215 if ((dptr = find_dev (buf)) == NULL) { /* locate device */\r
2216 printf ("Invalid device name: %s\n", buf);\r
2217 return SCPE_INCOMP;\r
2218 }\r
2219 READ_S (buf); /* [V3.0+] logical name */\r
2220 deassign_device (dptr); /* delete old name */\r
2221 if ((buf[0] != 0) && \r
2222 ((r = assign_device (dptr, buf)) != SCPE_OK)) return r;\r
2223 READ_I (flg); /* [V2.10+] ctlr flags */\r
2224 if (!v32) flg = ((flg & DEV_UFMASK_31) << (DEV_V_UF - DEV_V_UF_31)) |\r
2225 (flg & ~DEV_UFMASK_31); /* [V3.2+] flags moved */\r
2226 dptr->flags = (dptr->flags & ~DEV_RFLAGS) | /* restore ctlr flags */\r
2227 (flg & DEV_RFLAGS);\r
2228 for ( ;; ) { /* unit loop */\r
2229 sim_switches = SIM_SW_REST; /* flag rstr, clr RO */\r
2230 READ_I (unitno); /* unit number */\r
2231 if (unitno < 0) break; /* end units? */\r
2232 if ((uint32) unitno >= dptr->numunits) { /* too big? */\r
2233 printf ("Invalid unit number: %s%d\n", sim_dname (dptr), unitno);\r
2234 return SCPE_INCOMP;\r
2235 }\r
2236 READ_I (time); /* event time */\r
2237 uptr = (dptr->units) + unitno;\r
2238 sim_cancel (uptr);\r
2239 if (time > 0) sim_activate (uptr, time - 1);\r
2240 READ_I (uptr->u3); /* device specific */\r
2241 READ_I (uptr->u4);\r
2242 READ_I (uptr->u5); /* [V3.0+] more dev spec */\r
2243 READ_I (uptr->u6);\r
2244 READ_I (flg); /* [V2.10+] unit flags */\r
2245 old_capac = uptr->capac; /* save current capacity */\r
2246 if (v35) { /* [V3.5+] capacity */\r
2247 READ_I (uptr->capac);\r
2248 }\r
2249 if (!v32) flg = ((flg & UNIT_UFMASK_31) << (UNIT_V_UF - UNIT_V_UF_31)) |\r
2250 (flg & ~UNIT_UFMASK_31); /* [V3.2+] flags moved */\r
2251 uptr->flags = (uptr->flags & ~UNIT_RFLAGS) |\r
2252 (flg & UNIT_RFLAGS); /* restore */\r
2253 READ_S (buf); /* attached file */\r
2254 if ((uptr->flags & UNIT_ATTABLE) && /* if attachable and */\r
2255 (!(dptr->flags & DEV_NET) || /* not net dev or */\r
2256 !(uptr->flags & UNIT_ATT) || /* not currently att */\r
2257 (buf[0] == 0))) { /* or will not be att */\r
2258 r = scp_detach_unit (dptr, uptr); /* detach old */\r
2259 if (r != SCPE_OK) return r;\r
2260 if (buf[0] != 0) { /* any file? */\r
2261 uptr->flags = uptr->flags & ~UNIT_DIS;\r
2262 if (flg & UNIT_RO) /* [V2.10+] saved flgs & RO? */\r
2263 sim_switches |= SWMASK ('R'); /* RO attach */\r
2264 r = scp_attach_unit (dptr, uptr, buf);\r
2265 if (r != SCPE_OK) return r;\r
2266 }\r
2267 }\r
2268 READ_I (high); /* memory capacity */\r
2269 if (high > 0) { /* [V2.5+] any memory? */\r
2270 if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) ||\r
2271 (dptr->deposit == NULL)) {\r
2272 printf ("Can't restore memory: %s%d\n", sim_dname (dptr), unitno);\r
2273 return SCPE_INCOMP;\r
2274 }\r
2275 if (high != old_capac) { /* size change? */\r
2276 uptr->capac = old_capac; /* temp restore old */\r
2277 if ((dptr->flags & DEV_DYNM) &&\r
2278 ((dptr->msize == NULL) ||\r
2279 (dptr->msize (uptr, (int32) high, NULL, NULL) != SCPE_OK))) {\r
2280 printf ("Can't change memory size: %s%d\n",\r
2281 sim_dname (dptr), unitno);\r
2282 return SCPE_INCOMP;\r
2283 }\r
2284 uptr->capac = high; /* new memory size */\r
2285 printf ("Memory size changed: %s%d = ", sim_dname (dptr), unitno);\r
2286 fprint_capac (stdout, dptr, uptr);\r
2287 printf ("\n");\r
2288 }\r
2289 sz = SZ_D (dptr); /* allocate buffer */\r
2290 if ((mbuf = calloc (SRBSIZ, sz)) == NULL)\r
2291 return SCPE_MEM;\r
2292 for (k = 0; k < high; ) { /* loop thru mem */\r
2293 READ_I (blkcnt); /* block count */\r
2294 if (blkcnt < 0) limit = -blkcnt; /* compressed? */\r
2295 else limit = sim_fread (mbuf, sz, blkcnt, rfile);\r
2296 if (limit <= 0) return SCPE_IOERR; /* invalid or err? */\r
2297 for (j = 0; j < limit; j++, k = k + (dptr->aincr)) {\r
2298 if (blkcnt < 0) val = 0; /* compressed? */\r
2299 else SZ_LOAD (sz, val, mbuf, j); /* saved value */\r
2300 r = dptr->deposit (val, k, uptr, SIM_SW_REST);\r
2301 if (r != SCPE_OK) return r;\r
2302 } /* end for j */\r
2303 } /* end for k */\r
2304 free (mbuf); /* dealloc buffer */\r
2305 } /* end if high */\r
2306 } /* end unit loop */\r
2307 for ( ;; ) { /* register loop */\r
2308 READ_S (buf); /* read reg name */\r
2309 if (buf[0] == 0) break; /* last? */\r
2310 READ_I (depth); /* [V2.10+] depth */\r
2311 if ((rptr = find_reg (buf, NULL, dptr)) == NULL) {\r
2312 printf ("Invalid register name: %s %s\n", sim_dname (dptr), buf);\r
2313 for (us = 0; us < depth; us++) { /* skip values */\r
2314 READ_I (val);\r
2315 }\r
2316 continue;\r
2317 }\r
2318 if (depth != rptr->depth) /* [V2.10+] mismatch? */\r
2319 printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n",\r
2320 sim_dname (dptr), buf, depth, rptr->depth);\r
2321 mask = width_mask[rptr->width]; /* get mask */\r
2322 for (us = 0; us < depth; us++) { /* loop thru values */\r
2323 READ_I (val); /* read value */\r
2324 if (val > mask) /* value ok? */\r
2325 printf ("Invalid register value: %s %s\n", sim_dname (dptr), buf);\r
2326 else if (us < rptr->depth) /* in range? */\r
2327 put_rval (rptr, us, val);\r
2328 }\r
2329 }\r
2330 } /* end device loop */\r
2331return SCPE_OK;\r
2332}\r
2333\r
2334/* Run, go, cont, step commands\r
2335\r
2336 ru[n] [new PC] reset and start simulation\r
2337 go [new PC] start simulation\r
2338 co[nt] start simulation\r
2339 s[tep] [step limit] start simulation for 'limit' instructions\r
2340 b[oot] device bootstrap from device and start simulation\r
2341*/\r
2342\r
2343t_stat run_cmd (int32 flag, char *cptr)\r
2344{\r
2345char *tptr, gbuf[CBUFSIZE];\r
2346uint32 i, j;\r
2347int32 unitno;\r
2348t_value pcv;\r
2349t_stat r;\r
2350DEVICE *dptr;\r
2351UNIT *uptr;\r
2352void int_handler (int signal);\r
2353\r
2354GET_SWITCHES (cptr); /* get switches */\r
2355sim_step = 0;\r
2356if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */\r
2357 if (*cptr != 0) { /* argument? */\r
2358 cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
2359 if (*cptr != 0) return SCPE_2MARG; /* should be end */\r
2360 if (sim_vm_parse_addr) /* address parser? */\r
2361 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);\r
2362 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */\r
2363 if ((tptr == gbuf) || (*tptr != 0) || /* error? */\r
2364 (pcv > width_mask[sim_PC->width])) return SCPE_ARG;\r
2365 put_rval (sim_PC, 0, pcv);\r
2366 }\r
2367 if ((flag == RU_RUN) && /* run? */\r
2368 ((r = run_boot_prep ()) != SCPE_OK)) return r; /* reset sim */\r
2369 }\r
2370\r
2371else if (flag == RU_STEP) { /* step */\r
2372 if (*cptr != 0) { /* argument? */\r
2373 cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
2374 if (*cptr != 0) return SCPE_2MARG; /* should be end */\r
2375 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);\r
2376 if ((r != SCPE_OK) || (sim_step <= 0)) /* error? */\r
2377 return SCPE_ARG;\r
2378 }\r
2379 else sim_step = 1;\r
2380 }\r
2381\r
2382else if (flag == RU_BOOT) { /* boot */\r
2383 if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
2384 cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r
2385 if (*cptr != 0) return SCPE_2MARG; /* should be end */\r
2386 dptr = find_unit (gbuf, &uptr); /* locate unit */\r
2387 if (dptr == NULL) return SCPE_NXDEV; /* found dev? */\r
2388 if (uptr == NULL) return SCPE_NXUN; /* valid unit? */\r
2389 if (dptr->boot == NULL) return SCPE_NOFNC; /* can it boot? */\r
2390 if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */\r
2391 if ((uptr->flags & UNIT_ATTABLE) && /* if attable, att? */\r
2392 !(uptr->flags & UNIT_ATT)) return SCPE_UNATT;\r
2393 unitno = (int32) (uptr - dptr->units); /* recover unit# */\r
2394 if ((r = run_boot_prep ()) != SCPE_OK) return r; /* reset sim */\r
2395 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK) /* boot device */\r
2396 return r;\r
2397 }\r
2398\r
2399else if (flag != RU_CONT) return SCPE_IERR; /* must be cont */\r
2400\r
2401for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* reposition all */\r
2402 for (j = 0; j < dptr->numunits; j++) { /* seq devices */\r
2403 uptr = dptr->units + j;\r
2404 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) ==\r
2405 (UNIT_ATT + UNIT_SEQ))\r
2406 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);\r
2407 }\r
2408 }\r
2409stop_cpu = 0;\r
2410if (signal (SIGINT, int_handler) == SIG_ERR) { /* set WRU */\r
2411 return SCPE_SIGERR;\r
2412 }\r
2413if (sim_ttrun () != SCPE_OK) { /* set console mode */\r
2414 sim_ttcmd ();\r
2415 return SCPE_TTYERR;\r
2416 }\r
2417if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? */\r
2418 sim_ttcmd ();\r
2419 return r;\r
2420 }\r
2421if (sim_step) sim_activate (&sim_step_unit, sim_step); /* set step timer */\r
2422sim_throt_sched (); /* set throttle */\r
2423sim_is_running = 1; /* flag running */\r
2424sim_brk_clract (); /* defang actions */\r
2425sim_rtcn_init_all (); /* re-init clocks */\r
2426r = sim_instr();\r
2427\r
2428sim_is_running = 0; /* flag idle */\r
2429sim_ttcmd (); /* restore console */\r
2430signal (SIGINT, SIG_DFL); /* cancel WRU */\r
2431sim_cancel (&sim_step_unit); /* cancel step timer */\r
2432sim_throt_cancel (); /* cancel throttle */\r
2433if (sim_clock_queue != NULL) { /* update sim time */\r
2434 UPDATE_SIM_TIME (sim_clock_queue->time);\r
2435 }\r
2436else {\r
2437 UPDATE_SIM_TIME (noqueue_time);\r
2438 }\r
2439if (sim_log) fflush (sim_log); /* flush console log */\r
2440if (sim_deb) fflush (sim_deb); /* flush debug log */\r
2441for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files */\r
2442 for (j = 0; j < dptr->numunits; j++) { /* if not buffered in mem */\r
2443 uptr = dptr->units + j;\r
2444 if ((uptr->flags & UNIT_ATT) && /* attached, */\r
2445 !(uptr->flags & UNIT_BUF) && /* not buffered, */\r
2446 (uptr->fileref) && /* real file, */\r
2447 !(uptr->flags & UNIT_RAW) && /* not raw, */\r
2448 !(uptr->flags & UNIT_RO)) /* not read only? */\r
2449 fflush (uptr->fileref);\r
2450 }\r
2451 }\r
2452#if defined (VMS)\r
2453printf ("\n");\r
2454#endif\r
2455fprint_stopped (stdout, r); /* print msg */\r
2456if (sim_log) fprint_stopped (sim_log, r); /* log if enabled */\r
2457return SCPE_OK;\r
2458}\r
2459\r
2460/* Common setup for RUN or BOOT */\r
2461\r
2462t_stat run_boot_prep (void)\r
2463{\r
2464sim_interval = 0; /* reset queue */\r
2465sim_time = sim_rtime = 0;\r
2466noqueue_time = 0;\r
2467sim_clock_queue = NULL;\r
2468return reset_all_p (0);\r
2469}\r
2470\r
2471/* Print stopped message */\r
2472\r
2473void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)\r
2474{\r
2475int32 i;\r
2476t_stat r = 0;\r
2477t_addr k;\r
2478t_value pcval;\r
2479\r
2480if (v >= SCPE_BASE) fprintf (st, "\n%s, %s: ",\r
2481 scp_error_messages[v - SCPE_BASE], pc->name);\r
2482else fprintf (st, "\n%s, %s: ", sim_stop_messages[v], pc->name);\r
2483pcval = get_rval (pc, 0);\r
2484if (sim_vm_fprint_addr) sim_vm_fprint_addr (st, dptr, (t_addr) pcval);\r
2485else fprint_val (st, pcval, pc->radix, pc->width,\r
2486 pc->flags & REG_FMT);\r
2487if ((dptr != NULL) && (dptr->examine != NULL)) {\r
2488 for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;\r
2489 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {\r
2490 if ((r = dptr->examine (&sim_eval[i], k, dptr->units,\r
2491 SWMASK ('V'))) != SCPE_OK) break;\r
2492 }\r
2493 if ((r == SCPE_OK) || (i > 0)) {\r
2494 fprintf (st, " (");\r
2495 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)\r
2496 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);\r
2497 fprintf (st, ")");\r
2498 }\r
2499 }\r
2500fprintf (st, "\n");\r
2501return;\r
2502}\r
2503\r
2504void fprint_stopped (FILE *st, t_stat v)\r
2505{\r
2506fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);\r
2507return;\r
2508}\r
2509\r
2510/* Unit service for step timeout, originally scheduled by STEP n command\r
2511 Return step timeout SCP code, will cause simulation to stop */\r
2512\r
2513t_stat step_svc (UNIT *uptr)\r
2514{\r
2515return SCPE_STEP;\r
2516}\r
2517\r
2518/* Cancel scheduled step service */\r
2519\r
2520t_stat sim_cancel_step (void)\r
2521{\r
2522return sim_cancel (&sim_step_unit);\r
2523}\r
2524\r
2525/* Signal handler for ^C signal - set stop simulation flag */\r
2526\r
2527void int_handler (int sig)\r
2528{\r
2529stop_cpu = 1;\r
2530return;\r
2531}\r
2532\r
2533/* Examine/deposit commands\r
2534\r
2535 ex[amine] [modifiers] list examine\r
2536 de[posit] [modifiers] list val deposit\r
2537 ie[xamine] [modifiers] list interactive examine\r
2538 id[eposit] [modifiers] list interactive deposit\r
2539\r
2540 modifiers\r
2541 @filename output file\r
2542 -letter(s) switches\r
2543 devname'n device name and unit number\r
2544 [{&|^}value]{=|==|!|!=|>|>=|<|<=} value search specification\r
2545\r
2546 list list of addresses and registers\r
2547 addr[:addr|-addr] address range\r
2548 ALL all addresses\r
2549 register[:register|-register] register range\r
2550 STATE all registers\r
2551*/\r
2552\r
2553t_stat exdep_cmd (int32 flag, char *cptr)\r
2554{\r
2555char gbuf[CBUFSIZE], *gptr, *tptr;\r
2556int32 opt;\r
2557t_addr low, high;\r
2558t_stat reason;\r
2559DEVICE *tdptr;\r
2560REG *lowr, *highr;\r
2561FILE *ofile;\r
2562\r
2563opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT; /* options for all */\r
2564if (flag == EX_E) opt = opt | CMD_OPT_OF; /* extra for EX */\r
2565cptr = get_sim_opt (opt, cptr, &reason); /* get cmd options */\r
2566if (!cptr) return reason; /* error? */\r
2567if (*cptr == 0) return SCPE_2FARG; /* must be more */\r
2568if (sim_dfunit == NULL) return SCPE_NXUN; /* got a unit? */\r
2569cptr = get_glyph (cptr, gbuf, 0); /* get list */\r
2570if ((flag == EX_D) && (*cptr == 0)) return SCPE_2FARG; /* deposit needs more */\r
2571ofile = sim_ofile? sim_ofile: stdout; /* no ofile? use stdout */\r
2572\r
2573for (gptr = gbuf, reason = SCPE_OK;\r
2574 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {\r
2575 tdptr = sim_dfdev; /* working dptr */\r
2576 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {\r
2577 tptr = gptr + strlen ("STATE");\r
2578 if (*tptr && (*tptr++ != ',')) return SCPE_ARG;\r
2579 if ((lowr = sim_dfdev->registers) == NULL) return SCPE_NXREG;\r
2580 for (highr = lowr; highr->name != NULL; highr++) ;\r
2581 sim_switches = sim_switches | SIM_SW_HIDE;\r
2582 reason = exdep_reg_loop (ofile, sim_schptr, flag, cptr,\r
2583 lowr, --highr, 0, 0);\r
2584 continue;\r
2585 }\r
2586\r
2587 if ((lowr = find_reg (gptr, &tptr, tdptr)) || /* local reg or */\r
2588 (!(sim_opt_out & CMD_OPT_DFT) && /* no dflt, global? */\r
2589 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {\r
2590 low = high = 0;\r
2591 if ((*tptr == '-') || (*tptr == ':')) {\r
2592 highr = find_reg (tptr + 1, &tptr, tdptr);\r
2593 if (highr == NULL) return SCPE_NXREG;\r
2594 }\r
2595 else {\r
2596 highr = lowr;\r
2597 if (*tptr == '[') {\r
2598 if (lowr->depth <= 1) return SCPE_ARG;\r
2599 tptr = get_range (NULL, tptr + 1, &low, &high,\r
2600 10, lowr->depth - 1, ']');\r
2601 if (tptr == NULL) return SCPE_ARG;\r
2602 }\r
2603 }\r
2604 if (*tptr && (*tptr++ != ',')) return SCPE_ARG;\r
2605 reason = exdep_reg_loop (ofile, sim_schptr, flag, cptr,\r
2606 lowr, highr, (uint32) low, (uint32) high);\r
2607 continue;\r
2608 }\r
2609\r
2610 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,\r
2611 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:\r
2612 sim_dfunit->capac - sim_dfdev->aincr), 0);\r
2613 if (tptr == NULL) return SCPE_ARG;\r
2614 if (*tptr && (*tptr++ != ',')) return SCPE_ARG;\r
2615 reason = exdep_addr_loop (ofile, sim_schptr, flag, cptr, low, high,\r
2616 sim_dfdev, sim_dfunit);\r
2617 } /* end for */\r
2618if (sim_ofile) fclose (sim_ofile); /* close output file */\r
2619return reason;\r
2620}\r
2621\r
2622/* Loop controllers for examine/deposit\r
2623\r
2624 exdep_reg_loop examine/deposit range of registers\r
2625 exdep_addr_loop examine/deposit range of addresses\r
2626*/\r
2627\r
2628t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, \r
2629 REG *lowr, REG *highr, uint32 lows, uint32 highs)\r
2630{\r
2631t_stat reason;\r
2632uint32 idx;\r
2633t_value val;\r
2634REG *rptr;\r
2635\r
2636if ((lowr == NULL) || (highr == NULL)) return SCPE_IERR;\r
2637if (lowr > highr) return SCPE_ARG;\r
2638for (rptr = lowr; rptr <= highr; rptr++) {\r
2639 if ((sim_switches & SIM_SW_HIDE) &&\r
2640 (rptr->flags & REG_HIDDEN)) continue;\r
2641 for (idx = lows; idx <= highs; idx++) {\r
2642 if (idx >= rptr->depth) return SCPE_SUB;\r
2643 val = get_rval (rptr, idx);\r
2644 if (schptr && !test_search (val, schptr)) continue;\r
2645 if (flag != EX_D) {\r
2646 reason = ex_reg (ofile, val, flag, rptr, idx);\r
2647 if (reason != SCPE_OK) return reason;\r
2648 if (sim_log && (ofile == stdout))\r
2649 ex_reg (sim_log, val, flag, rptr, idx);\r
2650 }\r
2651 if (flag != EX_E) {\r
2652 reason = dep_reg (flag, cptr, rptr, idx);\r
2653 if (reason != SCPE_OK) return reason;\r
2654 }\r
2655 }\r
2656 }\r
2657return SCPE_OK;\r
2658}\r
2659\r
2660t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr,\r
2661 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)\r
2662{\r
2663t_addr i, mask;\r
2664t_stat reason;\r
2665\r
2666if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */\r
2667mask = (t_addr) width_mask[dptr->awidth];\r
2668if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG;\r
2669for (i = low; i <= high; ) { /* all paths must incr!! */\r
2670 reason = get_aval (i, dptr, uptr); /* get data */\r
2671 if (reason != SCPE_OK) return reason; /* return if error */\r
2672 if (schptr && !test_search (sim_eval[0], schptr))\r
2673 i = i + dptr->aincr; /* sch fails, incr */\r
2674 else { /* no sch or success */\r
2675 if (flag != EX_D) { /* ex, ie, or id? */\r
2676 reason = ex_addr (ofile, flag, i, dptr, uptr);\r
2677 if (reason > SCPE_OK) return reason;\r
2678 if (sim_log && (ofile == stdout))\r
2679 ex_addr (sim_log, flag, i, dptr, uptr);\r
2680 }\r
2681 else reason = 1 - dptr->aincr; /* no, dflt incr */\r
2682 if (flag != EX_E) { /* ie, id, or d? */\r
2683 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);\r
2684 if (reason > SCPE_OK) return reason;\r
2685 }\r
2686 i = i + (1 - reason); /* incr */\r
2687 }\r
2688 }\r
2689return SCPE_OK;\r
2690}\r
2691\r
2692/* Examine register routine\r
2693\r
2694 Inputs:\r
2695 ofile = output stream\r
2696 val = current register value\r
2697 flag = type of ex/mod command (ex, iex, idep)\r
2698 rptr = pointer to register descriptor\r
2699 idx = index\r
2700 Outputs:\r
2701 return = error status\r
2702*/\r
2703\r
2704t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)\r
2705{\r
2706int32 rdx;\r
2707\r
2708if (rptr == NULL) return SCPE_IERR;\r
2709if (rptr->depth > 1) fprintf (ofile, "%s[%d]:\t", rptr->name, idx);\r
2710else fprintf (ofile, "%s:\t", rptr->name);\r
2711if (!(flag & EX_E)) return SCPE_OK;\r
2712GET_RADIX (rdx, rptr->radix);\r
2713if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr)\r
2714 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);\r
2715else if (!(rptr->flags & REG_VMIO) ||\r
2716 (fprint_sym (ofile, rdx, &val, NULL, sim_switches | SIM_SW_REG) > 0))\r
2717 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);\r
2718if (flag & EX_I) fprintf (ofile, "\t");\r
2719else fprintf (ofile, "\n");\r
2720return SCPE_OK;\r
2721}\r
2722\r
2723/* Get register value\r
2724\r
2725 Inputs:\r
2726 rptr = pointer to register descriptor\r
2727 idx = index\r
2728 Outputs:\r
2729 return = register value\r
2730*/\r
2731\r
2732t_value get_rval (REG *rptr, uint32 idx)\r
2733{\r
2734size_t sz;\r
2735t_value val;\r
2736UNIT *uptr;\r
2737\r
2738sz = SZ_R (rptr);\r
2739if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {\r
2740 idx = idx + rptr->qptr;\r
2741 if (idx >= rptr->depth) idx = idx - rptr->depth;\r
2742 }\r
2743if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {\r
2744 uptr = ((UNIT *) rptr->loc) + idx;\r
2745#if defined (USE_INT64)\r
2746 if (sz <= sizeof (uint32)) val = *((uint32 *) uptr);\r
2747 else val = *((t_uint64 *) uptr);\r
2748#else\r
2749 val = *((uint32 *) uptr);\r
2750#endif\r
2751 }\r
2752else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&\r
2753 (sz == sizeof (uint8)))\r
2754 val = *(((uint8 *) rptr->loc) + idx);\r
2755else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&\r
2756 (sz == sizeof (uint16)))\r
2757 val = *(((uint16 *) rptr->loc) + idx);\r
2758#if defined (USE_INT64)\r
2759else if (sz <= sizeof (uint32))\r
2760 val = *(((uint32 *) rptr->loc) + idx);\r
2761else val = *(((t_uint64 *) rptr->loc) + idx);\r
2762#else\r
2763else val = *(((uint32 *) rptr->loc) + idx);\r
2764#endif\r
2765val = (val >> rptr->offset) & width_mask[rptr->width];\r
2766return val;\r
2767}\r
2768\r
2769/* Deposit register routine\r
2770\r
2771 Inputs:\r
2772 flag = type of deposit (normal/interactive)\r
2773 cptr = pointer to input string\r
2774 rptr = pointer to register descriptor\r
2775 idx = index\r
2776 Outputs:\r
2777 return = error status\r
2778*/\r
2779\r
2780t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx)\r
2781{\r
2782t_stat r;\r
2783t_value val, mask;\r
2784int32 rdx;\r
2785char *tptr, gbuf[CBUFSIZE];\r
2786\r
2787if ((cptr == NULL) || (rptr == NULL)) return SCPE_IERR;\r
2788if (rptr->flags & REG_RO) return SCPE_RO;\r
2789if (flag & EX_I) {\r
2790 cptr = read_line (gbuf, CBUFSIZE, stdin);\r
2791 if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr);\r
2792 if (cptr == NULL) return 1; /* force exit */\r
2793 if (*cptr == 0) return SCPE_OK; /* success */\r
2794 }\r
2795mask = width_mask[rptr->width];\r
2796GET_RADIX (rdx, rptr->radix);\r
2797if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr) { /* address form? */\r
2798 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);\r
2799 if ((tptr == cptr) || (*tptr != 0) ||\r
2800 (val > mask)) return SCPE_ARG;\r
2801 }\r
2802else if (!(rptr->flags & REG_VMIO) || /* dont use sym? */\r
2803 (parse_sym (cptr, rdx, NULL, &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {\r
2804 val = get_uint (cptr, rdx, mask, &r);\r
2805 if (r != SCPE_OK) return SCPE_ARG;\r
2806 }\r
2807if ((rptr->flags & REG_NZ) && (val == 0)) return SCPE_ARG;\r
2808put_rval (rptr, idx, val);\r
2809return SCPE_OK;\r
2810}\r
2811\r
2812/* Put register value\r
2813\r
2814 Inputs:\r
2815 rptr = pointer to register descriptor\r
2816 idx = index\r
2817 val = new value\r
2818 mask = mask\r
2819 Outputs:\r
2820 none\r
2821*/\r
2822\r
2823void put_rval (REG *rptr, uint32 idx, t_value val)\r
2824{\r
2825size_t sz;\r
2826t_value mask;\r
2827UNIT *uptr;\r
2828\r
2829#define PUT_RVAL(sz,rp,id,v,m) \\r
2830 *(((sz *) rp->loc) + id) = \\r
2831 (*(((sz *) rp->loc) + id) & \\r
2832 ~((m) << (rp)->offset)) | ((v) << (rp)->offset)\r
2833\r
2834if (rptr == sim_PC) sim_brk_npc (0);\r
2835sz = SZ_R (rptr);\r
2836mask = width_mask[rptr->width];\r
2837if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {\r
2838 idx = idx + rptr->qptr;\r
2839 if (idx >= rptr->depth) idx = idx - rptr->depth;\r
2840 }\r
2841if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {\r
2842 uptr = ((UNIT *) rptr->loc) + idx;\r
2843#if defined (USE_INT64)\r
2844 if (sz <= sizeof (uint32))\r
2845 *((uint32 *) uptr) = (*((uint32 *) uptr) &\r
2846 ~(((uint32) mask) << rptr->offset)) | \r
2847 (((uint32) val) << rptr->offset);\r
2848 else *((t_uint64 *) uptr) = (*((t_uint64 *) uptr)\r
2849 & ~(mask << rptr->offset)) | (val << rptr->offset);\r
2850#else\r
2851 *((uint32 *) uptr) = (*((uint32 *) uptr) &\r
2852 ~(((uint32) mask) << rptr->offset)) | \r
2853 (((uint32) val) << rptr->offset);\r
2854#endif\r
2855 }\r
2856else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&\r
2857 (sz == sizeof (uint8)))\r
2858 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);\r
2859else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&\r
2860 (sz == sizeof (uint16)))\r
2861 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);\r
2862#if defined (USE_INT64)\r
2863else if (sz <= sizeof (uint32))\r
2864 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);\r
2865else PUT_RVAL (t_uint64, rptr, idx, val, mask);\r
2866#else\r
2867else PUT_RVAL (uint32, rptr, idx, val, mask);\r
2868#endif\r
2869return;\r
2870}\r
2871\r
2872/* Examine address routine\r
2873\r
2874 Inputs: (sim_eval is an implicit argument)\r
2875 ofile = output stream\r
2876 flag = type of ex/mod command (ex, iex, idep)\r
2877 addr = address to examine\r
2878 dptr = pointer to device\r
2879 uptr = pointer to unit\r
2880 Outputs:\r
2881 return = if > 0, error status\r
2882 if <= 0,-number of extra addr units retired\r
2883*/\r
2884\r
2885t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)\r
2886{\r
2887t_stat reason;\r
2888int32 rdx;\r
2889\r
2890if (sim_vm_fprint_addr) sim_vm_fprint_addr (ofile, dptr, addr);\r
2891else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);\r
2892fprintf (ofile, ":\t");\r
2893if (!(flag & EX_E)) return (1 - dptr->aincr);\r
2894\r
2895GET_RADIX (rdx, dptr->dradix);\r
2896if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {\r
2897 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);\r
2898 reason = 1 - dptr->aincr;\r
2899 }\r
2900if (flag & EX_I) fprintf (ofile, "\t");\r
2901else fprintf (ofile, "\n");\r
2902return reason;\r
2903}\r
2904\r
2905/* Get address routine\r
2906\r
2907 Inputs:\r
2908 flag = type of ex/mod command (ex, iex, idep)\r
2909 addr = address to examine\r
2910 dptr = pointer to device\r
2911 uptr = pointer to unit\r
2912 Outputs: (sim_eval is an implicit output)\r
2913 return = error status\r
2914*/\r
2915\r
2916t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)\r
2917{\r
2918int32 i;\r
2919t_value mask;\r
2920t_addr j, loc;\r
2921size_t sz;\r
2922t_stat reason = SCPE_OK;\r
2923\r
2924if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR;\r
2925mask = width_mask[dptr->dwidth];\r
2926for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;\r
2927for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {\r
2928 if (dptr->examine != NULL) {\r
2929 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);\r
2930 if (reason != SCPE_OK) break;\r
2931 }\r
2932 else {\r
2933 if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT;\r
2934 if (uptr->flags & UNIT_RAW) return SCPE_NOFNC;\r
2935 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {\r
2936 reason = SCPE_NXM;\r
2937 break;\r
2938 }\r
2939 sz = SZ_D (dptr);\r
2940 loc = j / dptr->aincr;\r
2941 if (uptr->flags & UNIT_BUF) {\r
2942 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);\r
2943 }\r
2944 else {\r
2945 sim_fseek (uptr->fileref, sz * loc, SEEK_SET);\r
2946 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);\r
2947 if ((feof (uptr->fileref)) &&\r
2948 !(uptr->flags & UNIT_FIX)) {\r
2949 reason = SCPE_EOF;\r
2950 break;\r
2951 }\r
2952 else if (ferror (uptr->fileref)) {\r
2953 clearerr (uptr->fileref);\r
2954 reason = SCPE_IOERR;\r
2955 break;\r
2956 }\r
2957 }\r
2958 }\r
2959 sim_eval[i] = sim_eval[i] & mask;\r
2960 }\r
2961if ((reason != SCPE_OK) && (i == 0)) return reason;\r
2962return SCPE_OK;\r
2963}\r
2964\r
2965/* Deposit address routine\r
2966\r
2967 Inputs:\r
2968 flag = type of deposit (normal/interactive)\r
2969 cptr = pointer to input string\r
2970 addr = address to examine\r
2971 dptr = pointer to device\r
2972 uptr = pointer to unit\r
2973 dfltinc = value to return on cr input\r
2974 Outputs:\r
2975 return = if > 0, error status\r
2976 if <= 0, -number of extra address units retired\r
2977*/\r
2978\r
2979t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr,\r
2980 UNIT *uptr, int32 dfltinc)\r
2981{\r
2982int32 i, count, rdx;\r
2983t_addr j, loc;\r
2984t_stat r, reason;\r
2985t_value mask;\r
2986size_t sz;\r
2987char gbuf[CBUFSIZE];\r
2988\r
2989if (dptr == NULL) return SCPE_IERR;\r
2990if (flag & EX_I) {\r
2991 cptr = read_line (gbuf, CBUFSIZE, stdin);\r
2992 if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr);\r
2993 if (cptr == NULL) return 1; /* force exit */\r
2994 if (*cptr == 0) return dfltinc; /* success */\r
2995 }\r
2996if (uptr->flags & UNIT_RO) return SCPE_RO; /* read only? */\r
2997mask = width_mask[dptr->dwidth];\r
2998\r
2999GET_RADIX (rdx, dptr->dradix);\r
3000if ((reason = parse_sym (cptr, addr, uptr, sim_eval, sim_switches)) > 0) {\r
3001 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);\r
3002 if (reason != SCPE_OK) return reason;\r
3003 }\r
3004count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;\r
3005\r
3006for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {\r
3007 sim_eval[i] = sim_eval[i] & mask;\r
3008 if (dptr->deposit != NULL) {\r
3009 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);\r
3010 if (r != SCPE_OK) return r;\r
3011 }\r
3012 else {\r
3013 if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT;\r
3014 if (uptr->flags & UNIT_RAW) return SCPE_NOFNC;\r
3015 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))\r
3016 return SCPE_NXM;\r
3017 sz = SZ_D (dptr);\r
3018 loc = j / dptr->aincr;\r
3019 if (uptr->flags & UNIT_BUF) {\r
3020 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);\r
3021 if (loc >= uptr->hwmark) uptr->hwmark = (uint32) loc + 1;\r
3022 }\r
3023 else {\r
3024 sim_fseek (uptr->fileref, sz * loc, SEEK_SET);\r
3025 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);\r
3026 if (ferror (uptr->fileref)) {\r
3027 clearerr (uptr->fileref);\r
3028 return SCPE_IOERR;\r
3029 }\r
3030 }\r
3031 }\r
3032 }\r
3033return reason;\r
3034}\r
3035\r
3036/* Evaluate command */\r
3037\r
3038t_stat eval_cmd (int32 flg, char *cptr)\r
3039{\r
3040DEVICE *dptr = sim_dflt_dev;\r
3041int32 i, rdx, a, lim;\r
3042t_stat r;\r
3043\r
3044GET_SWITCHES (cptr);\r
3045GET_RADIX (rdx, dptr->dradix);\r
3046for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;\r
3047if (*cptr == 0) return SCPE_2FARG;\r
3048if ((r = parse_sym (cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {\r
3049 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);\r
3050 if (r != SCPE_OK) return r;\r
3051 }\r
3052lim = 1 - r;\r
3053for (i = a = 0; a < lim; ) {\r
3054 printf ("%d:\t", a);\r
3055 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)\r
3056 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);\r
3057 printf ("\n");\r
3058 if (sim_log) {\r
3059 fprintf (sim_log, "%d\t", i);\r
3060 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)\r
3061 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);\r
3062 fprintf (sim_log, "\n");\r
3063 }\r
3064 if (r < 0) a = a + 1 - r;\r
3065 else a = a + dptr->aincr;\r
3066 i = a / dptr->aincr;\r
3067 }\r
3068return SCPE_OK;\r
3069}\r
3070\r
3071/* String processing routines\r
3072\r
3073 read_line read line\r
3074\r
3075 Inputs:\r
3076 cptr = pointer to buffer\r
3077 size = maximum size\r
3078 stream = pointer to input stream\r
3079 Outputs:\r
3080 optr = pointer to first non-blank character\r
3081 NULL if EOF\r
3082*/\r
3083\r
3084char *read_line (char *cptr, int32 size, FILE *stream)\r
3085{\r
3086char *tptr;\r
3087\r
3088cptr = fgets (cptr, size, stream); /* get cmd line */\r
3089if (cptr == NULL) {\r
3090 clearerr (stream); /* clear error */\r
3091 return NULL; /* ignore EOF */\r
3092 }\r
3093for (tptr = cptr; tptr < (cptr + size); tptr++) { /* remove cr or nl */\r
3094 if ((*tptr == '\n') || (*tptr == '\r') ||\r
3095 (tptr == (cptr + size - 1))) { /* str max length? */\r
3096 *tptr = 0; /* terminate */\r
3097 break;\r
3098 }\r
3099 }\r
3100while (isspace (*cptr)) cptr++; /* trim leading spc */\r
3101if (*cptr == ';') *cptr = 0; /* ignore comment */\r
3102\r
3103\r
3104return cptr;\r
3105}\r
3106\r
3107/* get_glyph get next glyph (force upper case)\r
3108 get_glyph_nc get next glyph (no conversion)\r
3109 get_glyph_gen get next glyph (general case)\r
3110\r
3111 Inputs:\r
3112 iptr = pointer to input string\r
3113 optr = pointer to output string\r
3114 mchar = optional end of glyph character\r
3115 flag = TRUE for convert to upper case (_gen only)\r
3116 Outputs\r
3117 result = pointer to next character in input string\r
3118*/\r
3119\r
3120char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc)\r
3121{\r
3122while ((isspace (*iptr) == 0) && (*iptr != 0) && (*iptr != mchar)) {\r
3123 if (islower (*iptr) && uc) *optr = toupper (*iptr);\r
3124 else *optr = *iptr;\r
3125 iptr++; optr++;\r
3126 }\r
3127*optr = 0;\r
3128if (mchar && (*iptr == mchar)) iptr++; /* skip terminator */\r
3129while (isspace (*iptr)) iptr++; /* absorb spaces */\r
3130return iptr;\r
3131}\r
3132\r
3133char *get_glyph (char *iptr, char *optr, char mchar)\r
3134{\r
3135return get_glyph_gen (iptr, optr, mchar, TRUE);\r
3136}\r
3137\r
3138char *get_glyph_nc (char *iptr, char *optr, char mchar)\r
3139{\r
3140return get_glyph_gen (iptr, optr, mchar, FALSE);\r
3141}\r
3142\r
3143/* Trim trailing spaces from a string\r
3144\r
3145 Inputs:\r
3146 cptr = pointer to string\r
3147 Outputs:\r
3148 cptr = pointer to string\r
3149*/\r
3150\r
3151char *sim_trim_endspc (char *cptr)\r
3152{\r
3153char *tptr;\r
3154\r
3155tptr = cptr + strlen (cptr);\r
3156while ((--tptr >= cptr) && isspace (*tptr)) *tptr = 0;\r
3157return cptr;\r
3158}\r
3159\r
3160/* get_yn yes/no question\r
3161\r
3162 Inputs:\r
3163 cptr = pointer to question\r
3164 deflt = default answer\r
3165 Outputs:\r
3166 result = true if yes, false if no\r
3167*/\r
3168\r
3169t_stat get_yn (char *ques, t_stat deflt)\r
3170{\r
3171char cbuf[CBUFSIZE], *cptr;\r
3172\r
3173printf ("%s ", ques);\r
3174cptr = read_line (cbuf, CBUFSIZE, stdin);\r
3175if ((cptr == NULL) || (*cptr == 0)) return deflt;\r
3176if ((*cptr == 'Y') || (*cptr == 'y')) return TRUE;\r
3177return FALSE;\r
3178}\r
3179\r
3180/* get_uint unsigned number\r
3181\r
3182 Inputs:\r
3183 cptr = pointer to input string\r
3184 radix = input radix\r
3185 max = maximum acceptable value\r
3186 *status = pointer to error status\r
3187 Outputs:\r
3188 val = value\r
3189*/\r
3190\r
3191t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status)\r
3192{\r
3193t_value val;\r
3194char *tptr;\r
3195\r
3196*status = SCPE_OK;\r
3197val = strtotv (cptr, &tptr, radix);\r
3198if ((cptr == tptr) || (val > max)) *status = SCPE_ARG;\r
3199else {\r
3200 while (isspace (*tptr)) tptr++;\r
3201 if (*tptr != 0) *status = SCPE_ARG;\r
3202 }\r
3203return val;\r
3204}\r
3205\r
3206/* get_range range specification\r
3207\r
3208 Inputs:\r
3209 dptr = pointer to device (NULL if none)\r
3210 cptr = pointer to input string\r
3211 *lo = pointer to low result\r
3212 *hi = pointer to high result\r
3213 aradix = radix\r
3214 max = default high value\r
3215 term = terminating character, 0 if none\r
3216 Outputs:\r
3217 tptr = input pointer after processing\r
3218 NULL if error\r
3219*/\r
3220\r
3221char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,\r
3222 uint32 rdx, t_addr max, char term)\r
3223{\r
3224char *tptr;\r
3225\r
3226if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) { /* ALL? */\r
3227 tptr = cptr + strlen ("ALL");\r
3228 *lo = 0;\r
3229 *hi = max;\r
3230 }\r
3231else {\r
3232 if (dptr && sim_vm_parse_addr) /* get low */\r
3233 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);\r
3234 else *lo = (t_addr) strtotv (cptr, &tptr, rdx);\r
3235 if (cptr == tptr) return NULL; /* error? */\r
3236 if ((*tptr == '-') || (*tptr == ':')) { /* range? */\r
3237 cptr = tptr + 1;\r
3238 if (dptr && sim_vm_parse_addr) /* get high */\r
3239 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);\r
3240 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);\r
3241 if (cptr == tptr) return NULL;\r
3242 if (*lo > *hi) return NULL;\r
3243 }\r
3244 else if (*tptr == '/') { /* relative? */\r
3245 cptr = tptr + 1;\r
3246 *hi = (t_addr) strtotv (cptr, &tptr, rdx); /* get high */\r
3247 if ((cptr == tptr) || (*hi == 0)) return NULL;\r
3248 *hi = *lo + *hi - 1;\r
3249 }\r
3250 else *hi = *lo;\r
3251 }\r
3252if (term && (*tptr++ != term)) return NULL;\r
3253return tptr;\r
3254}\r
3255\r
3256/* get_ipaddr IP address:port\r
3257\r
3258 Inputs:\r
3259 cptr = pointer to input string\r
3260 Outputs:\r
3261 ipa = pointer to IP address (may be NULL), 0 = none\r
3262 ipp = pointer to IP port (may be NULL), 0 = none\r
3263 result = status\r
3264*/\r
3265\r
3266t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp)\r
3267{\r
3268char gbuf[CBUFSIZE];\r
3269char *addrp, *portp, *octetp;\r
3270uint32 i, addr, port, octet;\r
3271t_stat r;\r
3272\r
3273if ((cptr == NULL) || (*cptr == 0))\r
3274 return SCPE_ARG;\r
3275strncpy (gbuf, cptr, CBUFSIZE);\r
3276addrp = gbuf; /* default addr */\r
3277if (portp = strchr (gbuf, ':')) *portp++ = 0; /* x:y? split */\r
3278else if (strchr (gbuf, '.')) portp = NULL; /* x.y...? */\r
3279else {\r
3280 portp = gbuf; /* port only */\r
3281 addrp = NULL; /* no addr */\r
3282 }\r
3283if (portp) { /* port string? */\r
3284 if (ipp == NULL) return SCPE_ARG; /* not wanted? */\r
3285 port = (int32) get_uint (portp, 10, 65535, &r);\r
3286 if ((r != SCPE_OK) || (port == 0)) return SCPE_ARG;\r
3287 }\r
3288else port = 0;\r
3289if (addrp) { /* addr string? */\r
3290 if (ipa == NULL) return SCPE_ARG; /* not wanted? */\r
3291 for (i = addr = 0; i < 4; i++) { /* four octets */\r
3292 octetp = strchr (addrp, '.'); /* find octet end */\r
3293 if (octetp != NULL) *octetp++ = 0; /* split string */\r
3294 else if (i < 3) return SCPE_ARG; /* except last */\r
3295 octet = (int32) get_uint (addrp, 10, 255, &r);\r
3296 if (r != SCPE_OK) return SCPE_ARG;\r
3297 addr = (addr << 8) | octet;\r
3298 addrp = octetp;\r
3299 }\r
3300 if (((addr & 0377) == 0) || ((addr & 0377) == 255))\r
3301 return SCPE_ARG;\r
3302 }\r
3303else addr = 0;\r
3304if (ipp) *ipp = port; /* return req values */\r
3305if (ipa) *ipa = addr;\r
3306return SCPE_OK; \r
3307}\r
3308\r
3309/* Find_device find device matching input string\r
3310\r
3311 Inputs:\r
3312 cptr = pointer to input string\r
3313 Outputs:\r
3314 result = pointer to device\r
3315*/\r
3316\r
3317DEVICE *find_dev (char *cptr)\r
3318{\r
3319int32 i;\r
3320DEVICE *dptr;\r
3321\r
3322for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {\r
3323 if ((strcmp (cptr, dptr->name) == 0) ||\r
3324 (dptr->lname &&\r
3325 (strcmp (cptr, dptr->lname) == 0))) return dptr;\r
3326 }\r
3327return NULL;\r
3328}\r
3329\r
3330/* Find_unit find unit matching input string\r
3331\r
3332 Inputs:\r
3333 cptr = pointer to input string\r
3334 uptr = pointer to unit pointer\r
3335 Outputs:\r
3336 result = pointer to device (null if no dev)\r
3337 *iptr = pointer to unit (null if nx unit)\r
3338*/\r
3339\r
3340DEVICE *find_unit (char *cptr, UNIT **uptr)\r
3341{\r
3342uint32 i, u;\r
3343char *nptr, *tptr;\r
3344t_stat r;\r
3345DEVICE *dptr;\r
3346\r
3347if (uptr == NULL) return NULL; /* arg error? */\r
3348if (dptr = find_dev (cptr)) { /* exact match? */\r
3349 if (qdisable (dptr)) return NULL; /* disabled? */\r
3350 *uptr = dptr->units; /* unit 0 */\r
3351 return dptr;\r
3352 }\r
3353\r
3354for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */\r
3355 if (dptr->numunits && /* any units? */\r
3356 (((nptr = dptr->name) &&\r
3357 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||\r
3358 ((nptr = dptr->lname) &&\r
3359 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {\r
3360 tptr = cptr + strlen (nptr);\r
3361 if (isdigit (*tptr)) {\r
3362 if (qdisable (dptr)) return NULL; /* disabled? */\r
3363 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);\r
3364 if (r != SCPE_OK) *uptr = NULL; /* error? */\r
3365 else *uptr = dptr->units + u;\r
3366 return dptr;\r
3367 }\r
3368 }\r
3369 }\r
3370return NULL;\r
3371}\r
3372\r
3373/* Find_dev_from_unit find device for unit\r
3374\r
3375 Inputs:\r
3376 uptr = pointer to unit\r
3377 Outputs:\r
3378 result = pointer to device\r
3379*/\r
3380\r
3381DEVICE *find_dev_from_unit (UNIT *uptr)\r
3382{\r
3383DEVICE *dptr;\r
3384uint32 i, j;\r
3385\r
3386if (uptr == NULL) return NULL;\r
3387for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {\r
3388 for (j = 0; j < dptr->numunits; j++) {\r
3389 if (uptr == (dptr->units + j)) return dptr;\r
3390 }\r
3391 }\r
3392return NULL;\r
3393}\r
3394\r
3395/* Test for disabled device */\r
3396\r
3397t_bool qdisable (DEVICE *dptr)\r
3398{\r
3399return (dptr->flags & DEV_DIS? TRUE: FALSE);\r
3400}\r
3401\r
3402/* find_reg_glob find globally unique register\r
3403\r
3404 Inputs:\r
3405 cptr = pointer to input string\r
3406 optr = pointer to output pointer (can be null)\r
3407 gdptr = pointer to global device\r
3408 Outputs:\r
3409 result = pointer to register, NULL if error\r
3410 *optr = pointer to next character in input string\r
3411 *gdptr = pointer to device where found\r
3412*/\r
3413\r
3414REG *find_reg_glob (char *cptr, char **optr, DEVICE **gdptr)\r
3415{\r
3416int32 i;\r
3417DEVICE *dptr;\r
3418REG *rptr, *srptr = NULL;\r
3419\r
3420for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */\r
3421 if (dptr->flags & DEV_DIS) continue; /* skip disabled */\r
3422 if (rptr = find_reg (cptr, optr, dptr)) { /* found? */\r
3423 if (srptr) return NULL; /* ambig? err */\r
3424 srptr = rptr; /* save reg */\r
3425 *gdptr = dptr; /* save unit */\r
3426 }\r
3427 }\r
3428return srptr;\r
3429}\r
3430\r
3431/* find_reg find register matching input string\r
3432\r
3433 Inputs:\r
3434 cptr = pointer to input string\r
3435 optr = pointer to output pointer (can be null)\r
3436 dptr = pointer to device\r
3437 Outputs:\r
3438 result = pointer to register, NULL if error\r
3439 *optr = pointer to next character in input string\r
3440*/\r
3441\r
3442REG *find_reg (char *cptr, char **optr, DEVICE *dptr)\r
3443{\r
3444char *tptr;\r
3445REG *rptr;\r
3446uint32 slnt;\r
3447\r
3448if ((cptr == NULL) || (dptr == NULL) ||\r
3449 (dptr->registers == NULL)) return NULL;\r
3450tptr = cptr;\r
3451do {\r
3452 tptr++;\r
3453 } while (isalnum (*tptr) || (*tptr == '*') || (*tptr == '_'));\r
3454slnt = tptr - cptr;\r
3455for (rptr = dptr->registers; rptr->name != NULL; rptr++) {\r
3456 if ((slnt == strlen (rptr->name)) &&\r
3457 (strncmp (cptr, rptr->name, slnt) == 0)) {\r
3458 if (optr != NULL) *optr = tptr;\r
3459 return rptr;\r
3460 }\r
3461 }\r
3462return NULL;\r
3463}\r
3464\r
3465/* get_switches get switches from input string\r
3466\r
3467 Inputs:\r
3468 cptr = pointer to input string\r
3469 Outputs:\r
3470 sw = switch bit mask\r
3471 0 if no switches, -1 if error\r
3472*/\r
3473\r
3474int32 get_switches (char *cptr)\r
3475{\r
3476int32 sw;\r
3477\r
3478if (*cptr != '-') return 0;\r
3479sw = 0;\r
3480for (cptr++; (isspace (*cptr) == 0) && (*cptr != 0); cptr++) {\r
3481 if (isalpha (*cptr) == 0) return -1;\r
3482 sw = sw | SWMASK (toupper (*cptr));\r
3483 }\r
3484return sw;\r
3485}\r
3486\r
3487/* get_sim_sw accumulate sim_switches\r
3488\r
3489 Inputs:\r
3490 cptr = pointer to input string\r
3491 Outputs:\r
3492 ptr = pointer to first non-string glyph\r
3493 NULL if error\r
3494*/\r
3495\r
3496char *get_sim_sw (char *cptr)\r
3497{\r
3498int32 lsw;\r
3499char gbuf[CBUFSIZE];\r
3500\r
3501while (*cptr == '-') { /* while switches */\r
3502 cptr = get_glyph (cptr, gbuf, 0); /* get switch glyph */\r
3503 lsw = get_switches (gbuf); /* parse */\r
3504 if (lsw <= 0) return NULL; /* invalid? */\r
3505 sim_switches = sim_switches | lsw; /* accumulate */\r
3506 }\r
3507return cptr;\r
3508}\r
3509\r
3510/* get_sim_opt get simulator command options\r
3511\r
3512 Inputs:\r
3513 opt = command options\r
3514 cptr = pointer to input string\r
3515 Outputs:\r
3516 ptr = pointer to next glypsh, NULL if error\r
3517 *stat = error status\r
3518*/\r
3519\r
3520char *get_sim_opt (int32 opt, char *cptr, t_stat *st)\r
3521{\r
3522int32 t;\r
3523char *svptr, gbuf[CBUFSIZE];\r
3524DEVICE *tdptr;\r
3525UNIT *tuptr;\r
3526\r
3527sim_switches = 0; /* no switches */\r
3528sim_ofile = NULL; /* no output file */\r
3529sim_schptr = NULL; /* no search */\r
3530sim_stab.logic = SCH_OR; /* default search params */\r
3531sim_stab.boolop = SCH_GE;\r
3532sim_stab.mask = 0;\r
3533sim_stab.comp = 0;\r
3534sim_dfdev = sim_dflt_dev;\r
3535sim_dfunit = sim_dfdev->units;\r
3536sim_opt_out = 0; /* no options yet */\r
3537*st = SCPE_OK;\r
3538while (*cptr) { /* loop through modifiers */\r
3539 svptr = cptr; /* save current position */\r
3540 if ((opt & CMD_OPT_OF) && (*cptr == '@')) { /* output file spec? */\r
3541 if (sim_ofile) { /* already got one? */\r
3542 fclose (sim_ofile); /* one per customer */\r
3543 *st = SCPE_ARG;\r
3544 return NULL;\r
3545 }\r
3546 cptr = get_glyph_nc (cptr + 1, gbuf, 0);\r
3547 sim_ofile = sim_fopen (gbuf, "a"); /* open for append */\r
3548 if (sim_ofile == NULL) { /* open failed? */\r
3549 *st = SCPE_OPENERR; \r
3550 return NULL;\r
3551 }\r
3552 sim_opt_out |= CMD_OPT_OF; /* got output file */\r
3553 continue;\r
3554 }\r
3555 cptr = get_glyph (cptr, gbuf, 0);\r
3556 if ((t = get_switches (gbuf)) != 0) { /* try for switches */\r
3557 if (t < 0) { /* err if bad switch */\r
3558 *st = SCPE_INVSW;\r
3559 return NULL;\r
3560 }\r
3561 sim_switches = sim_switches | t; /* or in new switches */\r
3562 }\r
3563 else if ((opt & CMD_OPT_SCH) && /* if allowed, */\r
3564 get_search (gbuf, sim_dfdev->dradix, &sim_stab)) { /* try for search */\r
3565 sim_schptr = &sim_stab; /* set search */\r
3566 sim_opt_out |= CMD_OPT_SCH; /* got search */\r
3567 }\r
3568 else if ((opt & CMD_OPT_DFT) && /* default allowed? */\r
3569 ((sim_opt_out & CMD_OPT_DFT) == 0) && /* none yet? */\r
3570 (tdptr = find_unit (gbuf, &tuptr)) && /* try for default */\r
3571 (tuptr != NULL)) {\r
3572 sim_dfdev = tdptr; /* set as default */\r
3573 sim_dfunit = tuptr;\r
3574 sim_opt_out |= CMD_OPT_DFT; /* got default */\r
3575 }\r
3576 else return svptr; /* not rec, break out */\r
3577 }\r
3578return cptr;\r
3579}\r
3580\r
3581/* Match file extension\r
3582\r
3583 Inputs:\r
3584 fnam = file name\r
3585 ext = extension, without period\r
3586 Outputs:\r
3587 cp = pointer to final '.' if match, NULL if not\r
3588*/\r
3589\r
3590char *match_ext (char *fnam, char *ext)\r
3591{\r
3592char *pptr, *fptr, *eptr;\r
3593\r
3594if ((fnam == NULL) || (ext == NULL)) /* bad arguments? */\r
3595 return NULL;\r
3596pptr = strrchr (fnam, '.'); /* find last . */\r
3597if (pptr) { /* any? */\r
3598 for (fptr = pptr + 1, eptr = ext; /* match characters */\r
3599#if defined (VMS) /* VMS: stop at ; or null */\r
3600 (*fptr != 0) && (*fptr != ';');\r
3601#else\r
3602 *fptr != 0; /* others: stop at null */\r
3603#endif\r
3604 fptr++, eptr++) {\r
3605 if (toupper (*fptr) != toupper (*eptr))\r
3606 return NULL;\r
3607 }\r
3608 if (*eptr != 0) return NULL; /* ext exhausted? */\r
3609 }\r
3610return pptr;\r
3611}\r
3612\r
3613/* Get search specification\r
3614\r
3615 Inputs:\r
3616 cptr = pointer to input string\r
3617 radix = radix for numbers\r
3618 schptr = pointer to search table\r
3619 Outputs:\r
3620 return = NULL if error\r
3621 schptr if valid search specification\r
3622*/\r
3623\r
3624SCHTAB *get_search (char *cptr, int32 radix, SCHTAB *schptr)\r
3625{\r
3626int32 c, logop, cmpop;\r
3627t_value logval, cmpval;\r
3628char *sptr, *tptr;\r
3629const char logstr[] = "|&^", cmpstr[] = "=!><";\r
3630\r
3631logval = cmpval = 0;\r
3632if (*cptr == 0) return NULL; /* check for clause */\r
3633for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */\r
3634 if (sptr = strchr (logstr, c)) { /* check for mask */\r
3635 logop = sptr - logstr;\r
3636 logval = strtotv (cptr, &tptr, radix);\r
3637 if (cptr == tptr) return NULL;\r
3638 cptr = tptr;\r
3639 }\r
3640 else if (sptr = strchr (cmpstr, c)) { /* check for boolop */\r
3641 cmpop = sptr - cmpstr;\r
3642 if (*cptr == '=') {\r
3643 cmpop = cmpop + strlen (cmpstr);\r
3644 cptr++;\r
3645 }\r
3646 cmpval = strtotv (cptr, &tptr, radix);\r
3647 if (cptr == tptr) return NULL;\r
3648 cptr = tptr;\r
3649 }\r
3650 else return NULL;\r
3651 } /* end for */\r
3652if (logop >= 0) {\r
3653 schptr->logic = logop;\r
3654 schptr->mask = logval;\r
3655 }\r
3656if (cmpop >= 0) {\r
3657 schptr->boolop = cmpop;\r
3658 schptr->comp = cmpval;\r
3659 }\r
3660return schptr;\r
3661}\r
3662\r
3663/* Test value against search specification\r
3664\r
3665 Inputs:\r
3666 val = value to test\r
3667 schptr = pointer to search table\r
3668 Outputs:\r
3669 return = 1 if value passes search criteria, 0 if not\r
3670*/\r
3671\r
3672int32 test_search (t_value val, SCHTAB *schptr)\r
3673{\r
3674if (schptr == NULL) return 0;\r
3675\r
3676switch (schptr->logic) { /* case on logical */\r
3677\r
3678 case SCH_OR:\r
3679 val = val | schptr->mask;\r
3680 break;\r
3681\r
3682 case SCH_AND:\r
3683 val = val & schptr->mask;\r
3684 break;\r
3685\r
3686 case SCH_XOR:\r
3687 val = val ^ schptr->mask;\r
3688 break;\r
3689 }\r
3690\r
3691switch (schptr->boolop) { /* case on comparison */\r
3692\r
3693 case SCH_E: case SCH_EE:\r
3694 return (val == schptr->comp);\r
3695\r
3696 case SCH_N: case SCH_NE:\r
3697 return (val != schptr->comp);\r
3698\r
3699 case SCH_G:\r
3700 return (val > schptr->comp);\r
3701\r
3702 case SCH_GE:\r
3703 return (val >= schptr->comp);\r
3704\r
3705 case SCH_L:\r
3706 return (val < schptr->comp);\r
3707\r
3708 case SCH_LE:\r
3709 return (val <= schptr->comp);\r
3710 }\r
3711\r
3712return 0;\r
3713}\r
3714\r
3715/* Radix independent input/output package\r
3716\r
3717 strtotv - general radix input routine\r
3718\r
3719 Inputs:\r
3720 inptr = string to convert\r
3721 endptr = pointer to first unconverted character\r
3722 radix = radix for input\r
3723 Outputs:\r
3724 value = converted value\r
3725\r
3726 On an error, the endptr will equal the inptr.\r
3727*/\r
3728\r
3729t_value strtotv (char *inptr, char **endptr, uint32 radix)\r
3730{\r
3731int32 nodigit;\r
3732t_value val;\r
3733uint32 c, digit;\r
3734\r
3735*endptr = inptr; /* assume fails */\r
3736if ((radix < 2) || (radix > 36)) return 0;\r
3737while (isspace (*inptr)) inptr++; /* bypass white space */\r
3738val = 0;\r
3739nodigit = 1;\r
3740for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */\r
3741 if (islower (c)) c = toupper (c);\r
3742 if (isdigit (c)) digit = c - (uint32) '0'; /* digit? */\r
3743 else if (radix <= 10) break; /* stop if not expected */\r
3744 else digit = c + 10 - (uint32) 'A'; /* convert letter */\r
3745 if (digit >= radix) return 0; /* valid in radix? */\r
3746 val = (val * radix) + digit; /* add to value */\r
3747 nodigit = 0;\r
3748 }\r
3749if (nodigit) return 0; /* no digits? */\r
3750*endptr = inptr; /* result pointer */\r
3751return val;\r
3752}\r
3753\r
3754/* fprint_val - general radix printing routine\r
3755\r
3756 Inputs:\r
3757 stream = stream designator\r
3758 val = value to print\r
3759 radix = radix to print\r
3760 width = width to print\r
3761 format = leading zeroes format\r
3762 Outputs:\r
3763 status = error status\r
3764*/\r
3765\r
3766t_stat fprint_val (FILE *stream, t_value val, uint32 radix,\r
3767 uint32 width, uint32 format)\r
3768{\r
3769#define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value)))\r
3770t_value owtest, wtest;\r
3771int32 d, digit, ndigits;\r
3772char dbuf[MAX_WIDTH + 1];\r
3773\r
3774for (d = 0; d < MAX_WIDTH; d++) dbuf[d] = (format == PV_RZRO)? '0': ' ';\r
3775dbuf[MAX_WIDTH] = 0;\r
3776d = MAX_WIDTH;\r
3777do {\r
3778 d = d - 1;\r
3779 digit = (int32) (val % radix);\r
3780 val = val / radix;\r
3781 dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10);\r
3782 } while ((d > 0) && (val != 0));\r
3783\r
3784if (format != PV_LEFT) {\r
3785 wtest = owtest = radix;\r
3786 ndigits = 1;\r
3787 while ((wtest < width_mask[width]) && (wtest >= owtest)) {\r
3788 owtest = wtest;\r
3789 wtest = wtest * radix;\r
3790 ndigits = ndigits + 1;\r
3791 }\r
3792 if ((MAX_WIDTH - ndigits) < d) d = MAX_WIDTH - ndigits;\r
3793 }\r
3794if (fputs (&dbuf[d], stream) == EOF) return SCPE_IOERR;\r
3795return SCPE_OK;\r
3796}\r
3797\r
3798/* Event queue package\r
3799\r
3800 sim_activate add entry to event queue\r
3801 sim_cancel remove entry from event queue\r
3802 sim_process_event process entries on event queue\r
3803 sim_is_active see if entry is on event queue\r
3804 sim_atime return absolute time for an entry\r
3805 sim_gtime return global time\r
3806 sim_qcount return event queue entry count\r
3807\r
3808 Asynchronous events are set up by queueing a unit data structure\r
3809 to the event queue with a timeout (in simulator units, relative\r
3810 to the current time). Each simulator 'times' these events by\r
3811 counting down interval counter sim_interval. When this reaches\r
3812 zero the simulator calls sim_process_event to process the event\r
3813 and to see if further events need to be processed, or sim_interval\r
3814 reset to count the next one.\r
3815\r
3816 The event queue is maintained in clock order; entry timeouts are\r
3817 RELATIVE to the time in the previous entry.\r
3818\r
3819 sim_process_event - process event\r
3820\r
3821 Inputs:\r
3822 none\r
3823 Outputs:\r
3824 reason = reason code returned by any event processor,\r
3825 or 0 (SCPE_OK) if no exceptions\r
3826*/\r
3827\r
3828t_stat sim_process_event (void)\r
3829{\r
3830UNIT *uptr;\r
3831t_stat reason;\r
3832\r
3833if (stop_cpu) return SCPE_STOP; /* stop CPU? */\r
3834if (sim_clock_queue == NULL) { /* queue empty? */\r
3835 UPDATE_SIM_TIME (noqueue_time); /* update sim time */\r
3836 sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */\r
3837 return SCPE_OK;\r
3838 }\r
3839UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */\r
3840do {\r
3841 uptr = sim_clock_queue; /* get first */\r
3842 sim_clock_queue = uptr->next; /* remove first */\r
3843 uptr->next = NULL; /* hygiene */\r
3844 uptr->time = 0;\r
3845 if (sim_clock_queue != NULL) sim_interval = sim_clock_queue->time;\r
3846 else sim_interval = noqueue_time = NOQUEUE_WAIT;\r
3847 if (uptr->action != NULL) reason = uptr->action (uptr);\r
3848 else reason = SCPE_OK;\r
3849 } while ((reason == SCPE_OK) && (sim_interval == 0));\r
3850\r
3851/* Empty queue forces sim_interval != 0 */\r
3852\r
3853return reason;\r
3854}\r
3855\r
3856/* sim_activate - activate (queue) event\r
3857\r
3858 Inputs:\r
3859 uptr = pointer to unit\r
3860 event_time = relative timeout\r
3861 Outputs:\r
3862 reason = result (SCPE_OK if ok)\r
3863*/\r
3864\r
3865t_stat sim_activate (UNIT *uptr, int32 event_time)\r
3866{\r
3867UNIT *cptr, *prvptr;\r
3868int32 accum;\r
3869\r
3870if (event_time < 0) return SCPE_IERR;\r
3871if (sim_is_active (uptr)) return SCPE_OK; /* already active? */\r
3872if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); }\r
3873else { UPDATE_SIM_TIME (sim_clock_queue->time); } /* update sim time */\r
3874\r
3875prvptr = NULL;\r
3876accum = 0;\r
3877for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {\r
3878 if (event_time < (accum + cptr->time)) break;\r
3879 accum = accum + cptr->time;\r
3880 prvptr = cptr;\r
3881 }\r
3882if (prvptr == NULL) { /* insert at head */\r
3883 cptr = uptr->next = sim_clock_queue;\r
3884 sim_clock_queue = uptr;\r
3885 }\r
3886else {\r
3887 cptr = uptr->next = prvptr->next; /* insert at prvptr */\r
3888 prvptr->next = uptr;\r
3889 }\r
3890uptr->time = event_time - accum;\r
3891if (cptr != NULL) cptr->time = cptr->time - uptr->time;\r
3892sim_interval = sim_clock_queue->time;\r
3893return SCPE_OK;\r
3894}\r
3895\r
3896/* sim_activate_abs - activate (queue) event even if event already scheduled\r
3897\r
3898 Inputs:\r
3899 uptr = pointer to unit\r
3900 event_time = relative timeout\r
3901 Outputs:\r
3902 reason = result (SCPE_OK if ok)\r
3903*/\r
3904\r
3905t_stat sim_activate_abs (UNIT *uptr, int32 event_time)\r
3906{\r
3907sim_cancel (uptr);\r
3908return sim_activate (uptr, event_time);\r
3909}\r
3910\r
3911/* sim_cancel - cancel (dequeue) event\r
3912\r
3913 Inputs:\r
3914 uptr = pointer to unit\r
3915 Outputs:\r
3916 reason = result (SCPE_OK if ok)\r
3917\r
3918*/\r
3919\r
3920t_stat sim_cancel (UNIT *uptr)\r
3921{\r
3922UNIT *cptr, *nptr;\r
3923\r
3924if (sim_clock_queue == NULL) return SCPE_OK;\r
3925UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */\r
3926nptr = NULL;\r
3927if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr->next;\r
3928else {\r
3929 for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {\r
3930 if (cptr->next == uptr) {\r
3931 nptr = cptr->next = uptr->next;\r
3932 break; /* end queue scan */\r
3933 }\r
3934 }\r
3935 }\r
3936if (nptr != NULL) nptr->time = nptr->time + uptr->time;\r
3937uptr->next = NULL; /* hygiene */\r
3938uptr->time = 0;\r
3939if (sim_clock_queue != NULL) sim_interval = sim_clock_queue->time;\r
3940else sim_interval = noqueue_time = NOQUEUE_WAIT;\r
3941return SCPE_OK;\r
3942}\r
3943\r
3944/* sim_is_active - test for entry in queue, return activation time\r
3945\r
3946 Inputs:\r
3947 uptr = pointer to unit\r
3948 Outputs:\r
3949 result = absolute activation time + 1, 0 if inactive\r
3950*/\r
3951\r
3952int32 sim_is_active (UNIT *uptr)\r
3953{\r
3954UNIT *cptr;\r
3955int32 accum;\r
3956\r
3957accum = 0;\r
3958for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {\r
3959 if (cptr == sim_clock_queue) {\r
3960 if (sim_interval > 0) accum = accum + sim_interval;\r
3961 }\r
3962 else accum = accum + cptr->time;\r
3963 if (cptr == uptr) return accum + 1;\r
3964 }\r
3965return 0;\r
3966}\r
3967\r
3968/* sim_gtime - return global time\r
3969 sim_grtime - return global time with rollover\r
3970\r
3971 Inputs: none\r
3972 Outputs:\r
3973 time = global time\r
3974*/\r
3975\r
3976double sim_gtime (void)\r
3977{\r
3978if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); }\r
3979else { UPDATE_SIM_TIME (sim_clock_queue->time); }\r
3980return sim_time;\r
3981}\r
3982\r
3983uint32 sim_grtime (void)\r
3984{\r
3985if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); }\r
3986else { UPDATE_SIM_TIME (sim_clock_queue->time); }\r
3987return sim_rtime;\r
3988}\r
3989\r
3990/* sim_qcount - return queue entry count\r
3991\r
3992 Inputs: none\r
3993 Outputs:\r
3994 count = number of entries on the queue\r
3995*/\r
3996\r
3997int32 sim_qcount (void)\r
3998{\r
3999int32 cnt;\r
4000UNIT *uptr;\r
4001\r
4002cnt = 0;\r
4003for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) cnt++;\r
4004return cnt;\r
4005}\r
4006\r
4007/* Breakpoint package. This module replaces the VM-implemented one\r
4008 instruction breakpoint capability.\r
4009\r
4010 Breakpoints are stored in table sim_brk_tab, which is ordered by address for\r
4011 efficient binary searching. A breakpoint consists of a four entry structure:\r
4012\r
4013 addr address of the breakpoint\r
4014 type types of breakpoints set on the address\r
4015 a bit mask representing letters A-Z\r
4016 cnt number of iterations before breakp is taken\r
4017 action pointer command string to be executed\r
4018 when break is taken\r
4019\r
4020 sim_brk_summ is a summary of the types of breakpoints that are currently set (it\r
4021 is the bitwise OR of all the type fields). A simulator need only check for\r
4022 a breakpoint of type X if bit SWMASK('X') is set in sim_brk_sum.\r
4023\r
4024 The package contains the following public routines:\r
4025\r
4026 sim_brk_init initialize\r
4027 sim_brk_set set breakpoint\r
4028 sim_brk_clr clear breakpoint\r
4029 sim_brk_clrall clear all breakpoints\r
4030 sim_brk_show show breakpoint\r
4031 sim_brk_showall show all breakpoints\r
4032 sim_brk_test test for breakpoint\r
4033 sim_brk_npc PC has been changed\r
4034 sim_brk_getact get next action\r
4035 sim_brk_clract clear pending actions\r
4036\r
4037 Initialize breakpoint system.\r
4038*/\r
4039\r
4040t_stat sim_brk_init (void)\r
4041{\r
4042sim_brk_lnt = SIM_BRK_INILNT;\r
4043sim_brk_tab = (BRKTAB *) calloc (sim_brk_lnt, sizeof (BRKTAB));\r
4044if (sim_brk_tab == NULL) return SCPE_MEM;\r
4045sim_brk_ent = sim_brk_ins = 0;\r
4046sim_brk_act = NULL;\r
4047sim_brk_npc (0);\r
4048return SCPE_OK;\r
4049}\r
4050\r
4051/* Search for a breakpoint in the sorted breakpoint table */\r
4052\r
4053BRKTAB *sim_brk_fnd (t_addr loc)\r
4054{\r
4055int32 lo, hi, p;\r
4056BRKTAB *bp;\r
4057\r
4058if (sim_brk_ent == 0) { /* table empty? */\r
4059 sim_brk_ins = 0; /* insrt at head */\r
4060 return NULL; /* sch fails */\r
4061 }\r
4062lo = 0; /* initial bounds */\r
4063hi = sim_brk_ent - 1;\r
4064do {\r
4065 p = (lo + hi) >> 1; /* probe */\r
4066 bp = sim_brk_tab + p; /* table addr */\r
4067 if (loc == bp->addr) return bp; /* match? */\r
4068 else if (loc < bp->addr) hi = p - 1; /* go down? p is upper */\r
4069 else lo = p + 1; /* go up? p is lower */\r
4070 } while (lo <= hi);\r
4071if (loc < bp->addr) sim_brk_ins = p; /* insrt before or */\r
4072else sim_brk_ins = p + 1; /* after last sch */\r
4073return NULL;\r
4074}\r
4075\r
4076/* Insert a breakpoint */\r
4077\r
4078BRKTAB *sim_brk_new (t_addr loc)\r
4079{\r
4080int32 i, t;\r
4081BRKTAB *bp, *newp;\r
4082\r
4083if (sim_brk_ins < 0) return NULL;\r
4084if (sim_brk_ent >= sim_brk_lnt) { /* out of space? */\r
4085 t = sim_brk_lnt + SIM_BRK_INILNT; /* new size */\r
4086 newp = (BRKTAB *) calloc (t, sizeof (BRKTAB)); /* new table */\r
4087 if (newp == NULL) return NULL; /* can't extend */\r
4088 for (i = 0; i < sim_brk_lnt; i++) /* copy table */\r
4089 *(newp + i) = *(sim_brk_tab + i);\r
4090 free (sim_brk_tab); /* free old table */\r
4091 sim_brk_tab = newp; /* new base, lnt */\r
4092 sim_brk_lnt = t;\r
4093 }\r
4094if (sim_brk_ins != sim_brk_ent) { /* move needed? */\r
4095 for (bp = sim_brk_tab + sim_brk_ent;\r
4096 bp > sim_brk_tab + sim_brk_ins; bp--)\r
4097 *bp = *(bp - 1);\r
4098 }\r
4099bp = sim_brk_tab + sim_brk_ins;\r
4100bp->addr = loc;\r
4101bp->typ = 0;\r
4102bp->cnt = 0;\r
4103bp->act = NULL;\r
4104sim_brk_ent = sim_brk_ent + 1;\r
4105return bp;\r
4106}\r
4107\r
4108/* Set a breakpoint of type sw */\r
4109\r
4110t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, char *act)\r
4111{\r
4112BRKTAB *bp;\r
4113\r
4114if (sw == 0) sw = sim_brk_dflt;\r
4115if ((sim_brk_types & sw) == 0) return SCPE_NOFNC;\r
4116bp = sim_brk_fnd (loc); /* present? */\r
4117if (!bp) bp = sim_brk_new (loc); /* no, allocate */\r
4118if (!bp) return SCPE_MEM; /* still no? mem err */\r
4119bp->typ = sw; /* set type */\r
4120bp->cnt = ncnt; /* set count */\r
4121if ((bp->act != NULL) && (act != NULL)) { /* replace old action? */\r
4122 free (bp->act); /* deallocate */\r
4123 bp->act = NULL; /* now no action */\r
4124 }\r
4125if ((act != NULL) && (*act != 0)) { /* new action? */\r
4126 char *newp = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc buf */\r
4127 if (newp == NULL) return SCPE_MEM; /* mem err? */\r
4128 strncpy (newp, act, CBUFSIZE); /* copy action */\r
4129 bp->act = newp; /* set pointer */\r
4130 }\r
4131sim_brk_summ = sim_brk_summ | sw;\r
4132return SCPE_OK;\r
4133}\r
4134\r
4135/* Clear a breakpoint */\r
4136\r
4137t_stat sim_brk_clr (t_addr loc, int32 sw)\r
4138{\r
4139BRKTAB *bp = sim_brk_fnd (loc);\r
4140\r
4141if (!bp) return SCPE_OK; /* not there? ok */\r
4142if (sw == 0) sw = SIM_BRK_ALLTYP;\r
4143bp->typ = bp->typ & ~sw;\r
4144if (bp->typ) return SCPE_OK; /* clear all types? */\r
4145if (bp->act != NULL) free (bp->act); /* deallocate action */\r
4146for ( ; bp < (sim_brk_tab + sim_brk_ent - 1); bp++) /* erase entry */\r
4147 *bp = *(bp + 1);\r
4148sim_brk_ent = sim_brk_ent - 1; /* decrement count */\r
4149sim_brk_summ = 0; /* recalc summary */\r
4150for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++)\r
4151 sim_brk_summ = sim_brk_summ | bp->typ;\r
4152return SCPE_OK;\r
4153}\r
4154\r
4155/* Clear all breakpoints */\r
4156\r
4157t_stat sim_brk_clrall (int32 sw)\r
4158{\r
4159BRKTAB *bp;\r
4160\r
4161if (sw == 0) sw = SIM_BRK_ALLTYP;\r
4162for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); ) {\r
4163 if (bp->typ & sw) sim_brk_clr (bp->addr, sw);\r
4164 else bp++;\r
4165 }\r
4166return SCPE_OK;\r
4167}\r
4168\r
4169/* Show a breakpoint */\r
4170\r
4171t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)\r
4172{\r
4173BRKTAB *bp = sim_brk_fnd (loc);\r
4174DEVICE *dptr;\r
4175int32 i, any;\r
4176\r
4177if (sw == 0) sw = SIM_BRK_ALLTYP;\r
4178if (!bp || (!(bp->typ & sw))) return SCPE_OK;\r
4179dptr = sim_dflt_dev;\r
4180if (dptr == NULL) return SCPE_OK;\r
4181if (sim_vm_fprint_addr) sim_vm_fprint_addr (st, dptr, loc);\r
4182else fprint_val (st, loc, dptr->aradix, dptr->awidth, PV_LEFT);\r
4183fprintf (st, ":\t");\r
4184for (i = any = 0; i < 26; i++) {\r
4185 if ((bp->typ >> i) & 1) {\r
4186 if (any) fprintf (st, ", ");\r
4187 fputc (i + 'A', st);\r
4188 any = 1;\r
4189 }\r
4190 }\r
4191if (bp->cnt > 0) fprintf (st, " [%d]", bp->cnt);\r
4192if (bp->act != NULL) fprintf (st, "; %s", bp->act);\r
4193fprintf (st, "\n");\r
4194return SCPE_OK;\r
4195}\r
4196\r
4197/* Show all breakpoints */\r
4198\r
4199t_stat sim_brk_showall (FILE *st, int32 sw)\r
4200{\r
4201BRKTAB *bp;\r
4202\r
4203if (sw == 0) sw = SIM_BRK_ALLTYP;\r
4204for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) {\r
4205 if (bp->typ & sw) sim_brk_show (st, bp->addr, sw);\r
4206 }\r
4207return SCPE_OK;\r
4208}\r
4209\r
4210/* Test for breakpoint */\r
4211\r
4212uint32 sim_brk_test (t_addr loc, uint32 btyp)\r
4213{\r
4214BRKTAB *bp;\r
4215uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);\r
4216\r
4217if ((bp = sim_brk_fnd (loc)) && (btyp & bp->typ)) { /* in table, type match? */\r
4218 if ((sim_brk_pend[spc] && (loc == sim_brk_ploc[spc])) || /* previous location? */\r
4219 (--bp->cnt > 0)) return 0; /* count > 0? */\r
4220 bp->cnt = 0; /* reset count */\r
4221 sim_brk_ploc[spc] = loc; /* save location */\r
4222 sim_brk_pend[spc] = TRUE; /* don't do twice */\r
4223 sim_brk_act = bp->act; /* set up actions */\r
4224 return (btyp & bp->typ);\r
4225 }\r
4226sim_brk_pend[spc] = FALSE;\r
4227return 0;\r
4228}\r
4229\r
4230/* Get next pending action, if any */\r
4231\r
4232char *sim_brk_getact (char *buf, int32 size)\r
4233{\r
4234char *ep;\r
4235size_t lnt;\r
4236\r
4237if (sim_brk_act == NULL) return NULL; /* any action? */\r
4238while (isspace (*sim_brk_act)) sim_brk_act++; /* skip spaces */\r
4239if (*sim_brk_act == 0) return (sim_brk_act = NULL); /* now empty? */\r
4240if (ep = strchr (sim_brk_act, ';')) { /* cmd delimiter? */\r
4241 lnt = ep - sim_brk_act; /* cmd length */\r
4242 memcpy (buf, sim_brk_act, lnt + 1); /* copy with ; */\r
4243 buf[lnt] = 0; /* erase ; */\r
4244 sim_brk_act = sim_brk_act + lnt + 1; /* adv ptr */\r
4245 }\r
4246else {\r
4247 strncpy (buf, sim_brk_act, size); /* copy action */\r
4248 sim_brk_act = NULL; /* no more */\r
4249 }\r
4250return buf;\r
4251}\r
4252\r
4253/* Clear pending actions */\r
4254\r
4255void sim_brk_clract (void)\r
4256{\r
4257sim_brk_act = NULL;\r
4258}\r
4259\r
4260/* New PC */\r
4261\r
4262void sim_brk_npc (uint32 cnt)\r
4263{\r
4264uint32 i;\r
4265\r
4266if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC)) cnt = SIM_BKPT_N_SPC;\r
4267for (i = 0; i < cnt; i++) {\r
4268 sim_brk_pend[i] = FALSE;\r
4269 sim_brk_ploc[i] = 0;\r
4270 }\r
4271return;\r
4272}\r
4273\r
4274/* Clear breakpoint space */\r
4275\r
4276void sim_brk_clrspc (uint32 spc)\r
4277{\r
4278if (spc < SIM_BKPT_N_SPC) {\r
4279 sim_brk_pend[spc] = FALSE;\r
4280 sim_brk_ploc[spc] = 0;\r
4281 }\r
4282return;\r
4283}\r
4284\r
4285/* Debug printout routines, from Dave Hittner */\r
4286\r
4287const char* debug_bstates = "01_^";\r
4288const char* debug_fmt = "DBG> %s %s: ";\r
4289int32 debug_unterm = 0;\r
4290\r
4291/* Finds debug phrase matching bitmask from from device DEBTAB table */\r
4292\r
4293static char* get_dbg_verb (uint32 dbits, DEVICE* dptr)\r
4294{\r
4295static char* debtab_none = "DEBTAB_ISNULL";\r
4296static char* debtab_nomatch = "DEBTAB_NOMATCH";\r
4297int32 offset = 0;\r
4298\r
4299if (dptr->debflags == 0) return debtab_none;\r
4300\r
4301/* Find matching words for bitmask */\r
4302\r
4303while (dptr->debflags[offset].name && (offset < 32)) {\r
4304 if (dptr->debflags[offset].mask & dbits)\r
4305 return dptr->debflags[offset].name;\r
4306 offset++;\r
4307 }\r
4308return debtab_nomatch;\r
4309}\r
4310\r
4311/* Prints standard debug prefix unless previous call unterminated */\r
4312\r
4313static void sim_debug_prefix (uint32 dbits, DEVICE* dptr)\r
4314{\r
4315if (!debug_unterm) {\r
4316 char* debug_type = get_dbg_verb (dbits, dptr);\r
4317 fprintf(sim_deb, debug_fmt, dptr->name, debug_type);\r
4318 }\r
4319}\r
4320\r
4321/* Prints state of a register: bit translation + state (0,1,_,^)\r
4322 indicating the state and transition of the bit. States:\r
4323 0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */\r
4324\r
4325void sim_debug_u16(uint32 dbits, DEVICE* dptr, const char* const* bitdefs,\r
4326 uint16 before, uint16 after, int terminate)\r
4327{\r
4328if (sim_deb && (dptr->dctrl & dbits)) {\r
4329 int32 i;\r
4330\r
4331 sim_debug_prefix(dbits, dptr); /* print prefix if required */\r
4332 for (i = 15; i >= 0; i--) { /* print xlation, transition */\r
4333 int off = ((after >> i) & 1) + (((before ^ after) >> i) & 1) * 2;\r
4334 fprintf(sim_deb, "%s%c ", bitdefs[i], debug_bstates[off]);\r
4335 }\r
4336 if (terminate) fprintf(sim_deb, "\r\n");\r
4337 debug_unterm = terminate ? 0 : 1; /* set unterm for next */\r
4338 }\r
4339}\r
4340\r
4341#if defined (_WIN32)\r
4342#define vsnprintf _vsnprintf\r
4343#endif\r
4344#if defined (__DECC) && defined (__VMS)\r
4345#define NO_vsnprintf\r
4346#endif\r
4347#if defined( NO_vsnprintf)\r
4348#define STACKBUFSIZE 16384\r
4349#else\r
4350#define STACKBUFSIZE 2048\r
4351#endif\r
4352\r
4353/* Inline debugging - will print debug message if debug file is\r
4354 set and the bitmask matches the current device debug options.\r
4355 Extra returns are added for un*x systems, since the output\r
4356 device is set into 'raw' mode when the cpu is booted,\r
4357 and the extra returns don't hurt any other systems. */\r
4358\r
4359void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...)\r
4360{\r
4361if (sim_deb && (dptr->dctrl & dbits)) {\r
4362\r
4363 char stackbuf[STACKBUFSIZE];\r
4364 int32 bufsize = sizeof(stackbuf);\r
4365 char *buf = stackbuf;\r
4366 va_list arglist;\r
4367 int32 i, j, len;\r
4368\r
4369 buf[bufsize-1] = '\0';\r
4370 sim_debug_prefix(dbits, dptr); /* print prefix if required */\r
4371\r
4372 while (1) { /* format passed string, args */\r
4373 va_start (arglist, fmt);\r
4374#if defined(NO_vsnprintf)\r
4375#if defined(HAS_vsprintf_void)\r
4376\r
4377/* Note, this could blow beyond the buffer, and we couldn't tell */\r
4378/* That is a limitation of the C runtime library available on this platform */\r
4379\r
4380 vsprintf (buf, fmt, arglist);\r
4381 for (len = 0; len < bufsize-1; len++)\r
4382 if (buf[len] == 0) break;\r
4383#else\r
4384 len = vsprintf (buf, fmt, arglist);\r
4385#endif /* HAS_vsprintf_void */\r
4386#else /* NO_vsnprintf */\r
4387#if defined(HAS_vsnprintf_void)\r
4388 vsnprintf (buf, bufsize-1, fmt, arglist);\r
4389 for (len = 0; len < bufsize-1; len++)\r
4390 if (buf[len] == 0) break;\r
4391#else\r
4392 len = vsnprintf (buf, bufsize-1, fmt, arglist);\r
4393#endif /* HAS_vsnprintf_void */\r
4394#endif /* NO_vsnprintf */\r
4395 va_end (arglist);\r
4396\r
4397/* If it didn't fit into the buffer, then grow it and try again */\r
4398\r
4399 if ((len < 0) || (len >= bufsize-1)) {\r
4400 if (buf != stackbuf) free (buf);\r
4401 bufsize = bufsize * 2;\r
4402 buf = (char *) malloc (bufsize);\r
4403 if (buf == NULL) return; /* out of memory */\r
4404 buf[bufsize-1] = '\0';\r
4405 continue;\r
4406 }\r
4407 break;\r
4408 }\r
4409\r
4410/* Output the formatted data expanding newlines where they exist */\r
4411\r
4412 for (i = j = 0; i < len; ++i) {\r
4413 if ('\n' == buf[i]) {\r
4414 if (i > j) fwrite (&buf[j], 1, i-j, sim_deb);\r
4415 j = i;\r
4416 fputc('\r', sim_deb);\r
4417 }\r
4418 }\r
4419 if (i > j) fwrite (&buf[j], 1, i-j, sim_deb);\r
4420\r
4421/* Set unterminated flag for next time */\r
4422\r
4423 debug_unterm = (len && (buf[len-1]=='\n')) ? 0 : 1;\r
4424 if (buf != stackbuf) free (buf);\r
4425 }\r
4426return;\r
4427}\r