This source file includes following definitions.
- setenv
- unsetenv
- xstrerror_l
- processIsTranslated
- strremove
- strtrimspace
- allowCores
- CleanDUMA
- dl_iterate_phdr_callback
- GetUCRTVersion
- dps8_sir_report_error
- main
- process_stdin_commands
- set_prompt
- find_cmd
- exit_cmd
- _cmd_name_compare
- fprint_help
- fprint_header
- fprint_reg_help_ex
- fprint_reg_help
- fprint_attach_help_ex
- fprint_set_help_ex
- fprint_set_help
- fprint_show_help_ex
- fprint_show_help
- fprint_brk_help_ex
- help_dev_help
- help_cmd_output
- help_cmd
- spawn_cmd
- echo_cmd
- do_cmd
- do_position
- do_cmd_label
- sim_sub_args
- sim_cmp_string
- assert_cmd
- send_cmd
- sim_show_send
- expect_cmd
- sim_show_expect
- goto_cmd
- return_cmd
- shift_cmd
- call_cmd
- on_cmd
- noop_cmd
- set_on
- set_verify
- set_message
- set_localopc
- set_quiet
- sim_set_environment
- set_cmd
- find_ctab
- find_c1tab
- set_dev_radix
- set_dev_enbdis
- set_unit_enbdis
- set_dev_debug
- show_cmd
- show_cmd_fi
- find_shtab
- show_device
- fprint_sep
- show_unit
- sprint_capac
- fprint_capac
- show_default_base_system_script
- printp
- strip_spaces
- printpq
- show_prom
- show_buildinfo
- show_version
- show_config
- show_log_names
- show_dev_logicals
- show_queue
- show_time
- show_break
- show_dev_radix
- show_dev_debug
- show_on
- show_mod_names
- show_dev_modifiers
- show_all_mods
- show_one_mod
- show_show_commands
- show_dev_show_commands
- brk_cmd
- ssh_break
- ssh_break_one
- reset_cmd
- reset_all
- reset_all_p
- attach_cmd
- scp_attach_unit
- attach_unit
- attach_err
- detach_cmd
- detach_all
- scp_detach_unit
- detach_unit
- sim_dname
- sim_uname
- run_cmd
- run_cmd_message
- sim_run_boot_prep
- fprint_stopped_gen
- fprint_stopped
- step_svc
- expect_svc
- int_handler
- exdep_cmd
- exdep_reg_loop
- exdep_addr_loop
- ex_reg
- get_rval
- dep_reg
- put_rval
- ex_addr
- get_aval
- dep_addr
- eval_cmd
- read_line
- read_line_p
- get_glyph_gen
- get_glyph
- get_glyph_nc
- get_glyph_quoted
- get_glyph_cmd
- sim_trim_endspc
- sim_isspace
- sim_islower
- sim_isalpha
- sim_isprint
- sim_isdigit
- sim_isgraph
- sim_isalnum
- get_uint
- get_range
- sim_decode_quoted_string
- sim_encode_quoted_string
- fprint_buffer_string
- find_dev
- find_unit
- sim_register_internal_device
- find_dev_from_unit
- qdisable
- find_reg_glob
- find_reg
- get_switches
- get_sim_sw
- get_sim_opt
- put_switches
- get_rsearch
- get_asearch
- test_search
- strtotv
- sprint_val
- fprint_val
- sim_fmt_secs
- sim_process_event
- sim_activate
- _sim_activate
- sim_activate_abs
- sim_activate_after
- _sim_activate_after
- sim_cancel
- sim_is_active
- sim_activate_time
- sim_gtime
- sim_qcount
- sim_brk_init
- sim_brk_fnd
- sim_brk_fnd_ex
- sim_brk_new
- sim_brk_set
- sim_brk_clr
- sim_brk_clrall
- sim_brk_show
- sim_brk_showall
- sim_brk_test
- sim_brk_getact
- sim_brk_clract
- sim_brk_setact
- sim_brk_npc
- sim_brk_clrspc
- sim_brk_message
- sim_set_expect
- sim_set_noexpect
- sim_exp_fnd
- sim_exp_clr_tab
- sim_exp_clr
- sim_exp_clrall
- sim_exp_set
- sim_exp_show_tab
- sim_exp_show
- sim_exp_showall
- sim_exp_check
- sim_send_input
- sim_send_clear
- sim_show_send_input
- sim_send_poll_data
- sim_error_text
- sim_string_to_stat
- get_dbg_verb
- sim_debug_prefix
- fprint_fields
- sim_debug_bits_hdr
- sim_debug_bits
- sim_printf
- sim_messagef
- _sim_debug
- sim_data_trace
- Fprintf
- appendText
- cleanHelp
- buildHelp
- helpPrompt
- displayMagicTopic
- displayFlatHelp
- matchHelpTopicName
- scp_vhelp
- scp_help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 #if !defined(__EXTENSIONS__)
43 # define __EXTENSIONS__
44 #endif
45
46 #if !defined(__STDC_WANT_LIB_EXT1__)
47 # define __STDC_WANT_LIB_EXT1__ 1
48 #endif
49
50 #if !defined(_GNU_SOURCE)
51 # define _GNU_SOURCE
52 #endif
53
54
55
56 #include "sim_defs.h"
57 #include "sim_disk.h"
58 #include "sim_tape.h"
59 #include "sim_sock.h"
60
61 #include <signal.h>
62 #include <ctype.h>
63 #include <time.h>
64 #include <math.h>
65 #include <stddef.h>
66 #if defined(_WIN32)
67 # if !defined(WIN32_LEAN_AND_MEAN)
68 # define WIN32_LEAN_AND_MEAN
69 # endif
70 # if defined(_MSC_VER)
71 # pragma warning(push, 3)
72 # endif
73 # include <direct.h>
74 # include <io.h>
75 # include <fcntl.h>
76 #else
77 # include <unistd.h>
78 # define HAVE_UNISTD 1
79 #endif
80 #include <sys/stat.h>
81 #include <sys/types.h>
82 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
83 # include <sys/resource.h>
84 #endif
85 #include <setjmp.h>
86 #include <stdint.h>
87 #include <limits.h>
88 #if defined(__APPLE__)
89 # include <xlocale.h>
90 #endif
91 #include <locale.h>
92
93 #include "linehistory.h"
94
95 #if defined(__APPLE__)
96 # include <sys/sysctl.h>
97 #endif
98
99 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) )
100 # include <sys/sysinfo.h>
101 # define LINUX_OS
102 #endif
103
104 #include <uv.h>
105
106 #if !defined(HAVE_UNISTD)
107 # undef USE_BACKTRACE
108 #endif
109
110 #if defined(USE_BACKTRACE)
111 # include <string.h>
112 # include <signal.h>
113 #endif
114
115 #if defined(__HAIKU__)
116 # include <OS.h>
117 #endif
118
119 #if !defined(__CYGWIN__)
120 # if !defined(__APPLE__)
121 # if !defined(_AIX)
122 # if !defined(__MINGW32__)
123 # if !defined(__MINGW64__)
124 # if !defined(CROSS_MINGW32)
125 # if !defined(CROSS_MINGW64)
126 # if !defined(_WIN32)
127 # if !defined(__HAIKU__)
128 # if !defined(__QNX__)
129 # include <link.h>
130 # endif
131 # endif
132 # endif
133 # endif
134 # endif
135 # endif
136 # endif
137 # endif
138 # endif
139 #endif
140
141 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
142 # include <windows.h>
143 #endif
144
145 #if defined(__CYGWIN__)
146 # include <windows.h>
147 # include <sys/utsname.h>
148 # include <sys/cygwin.h>
149 # include <cygwin/version.h>
150 #endif
151
152 #define DBG_CTR 0
153
154 #include "../dps8/dps8.h"
155 #include "../dps8/dps8_cpu.h"
156 #include "../dps8/ver.h"
157
158 #include "../dps8/dps8_iom.h"
159 #include "../dps8/dps8_fnp2.h"
160
161 #include "../decNumber/decContext.h"
162 #include "../decNumber/decNumberLocal.h"
163
164 #include "../dps8/dps8_math128.h"
165
166 #include "../dps8/dps8_sir.h"
167
168 #if !defined(__CYGWIN__)
169 # if !defined(__APPLE__)
170 # if !defined(_AIX)
171 # if !defined(__MINGW32__)
172 # if !defined(__MINGW64__)
173 # if !defined(CROSS_MINGW32)
174 # if !defined(CROSS_MINGW64)
175 # if !defined(_WIN32)
176 # if !defined(__HAIKU__)
177 # if !defined(__QNX__)
178 static unsigned int dl_iterate_phdr_callback_called = 0;
179 # endif
180 # endif
181 # endif
182 # endif
183 # endif
184 # endif
185 # endif
186 # endif
187 # endif
188 #endif
189
190 #if defined(MAX)
191 # undef MAX
192 #endif
193 #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
194
195 #if defined(FREE)
196 # undef FREE
197 #endif
198 #define FREE(p) do \
199 { \
200 free((p)); \
201 (p) = NULL; \
202 } while(0)
203
204
205
206 #define SCH_OR 0
207 #define SCH_AND 1
208 #define SCH_XOR 2
209 #define SCH_E 0
210 #define SCH_N 1
211 #define SCH_G 2
212 #define SCH_L 3
213 #define SCH_EE 4
214 #define SCH_NE 5
215 #define SCH_GE 6
216 #define SCH_LE 7
217
218 #define MAX_DO_NEST_LVL 20
219 #define SRBSIZ 1024
220 #define SIM_BRK_INILNT 4096
221 #define SIM_BRK_ALLTYP 0xFFFFFFFB
222
223 #define UPDATE_SIM_TIME \
224 if (1) { \
225 int32 _x; \
226 if (sim_clock_queue == QUEUE_LIST_END) \
227 _x = noqueue_time; \
228 else \
229 _x = sim_clock_queue->time; \
230 sim_time = sim_time + (_x - sim_interval); \
231 sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
232 if (sim_clock_queue == QUEUE_LIST_END) \
233 noqueue_time = sim_interval; \
234 else \
235 sim_clock_queue->time = sim_interval; \
236 } \
237 else \
238 (void)0
239
240 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
241
242 #define SZ_R(rp) \
243 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
244
245 #define SZ_LOAD(sz,v,mb,j) \
246 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
247 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
248 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
249 else v = *(((t_uint64 *) mb) + ((uint32) j));
250
251 #define SZ_STORE(sz,v,mb,j) \
252 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
253 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
254 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
255 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
256
257 #define GET_SWITCHES(cp) \
258 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
259
260 #define GET_RADIX(val,dft) \
261 if (sim_switches & SWMASK ('O')) val = 8; \
262 else if (sim_switches & SWMASK ('D')) val = 10; \
263 else if (sim_switches & SWMASK ('H')) val = 16; \
264 else val = dft;
265
266
267
268
269
270
271 t_bool sim_asynch_enabled = FALSE;
272 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
273 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
274 extern void (*sim_vm_init) (void);
275 extern void (*sim_vm_exit) (void);
276 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
277 void (*sim_vm_post) (t_bool from_scp) = NULL;
278 CTAB *sim_vm_cmd = NULL;
279 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
280 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
281 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
282 t_value (*sim_vm_pc_value) (void) = NULL;
283 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
284 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
285 unsigned int nprocs;
286
287
288
289
290
291 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
292 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
293 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
294 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
295 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
296 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
297 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
298 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
299 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
300 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
301 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
302 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
303 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
304 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
305 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
306 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
307 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
308 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
309 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
310 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
311 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
312 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
313 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
314 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
315 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
316 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
317 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
318 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
319 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
320 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
321 t_stat sim_save (FILE *sfile);
322 t_stat sim_rest (FILE *rfile);
323
324
325
326 t_stat sim_brk_init (void);
327 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
328 t_stat sim_brk_clr (t_addr loc, int32 sw);
329 t_stat sim_brk_clrall (int32 sw);
330 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
331 t_stat sim_brk_showall (FILE *st, uint32 sw);
332 CONST char *sim_brk_getact (char *buf, int32 size);
333 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
334 char *sim_brk_clract (void);
335
336 FILE *stdnul;
337
338
339
340 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
341 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
342 int32 test_search (t_value *val, SCHTAB *schptr);
343 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
344 int32 get_switches (const char *cptr);
345 CONST char *get_sim_sw (CONST char *cptr);
346 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
347 t_value get_rval (REG *rptr, uint32 idx);
348 void put_rval (REG *rptr, uint32 idx, t_value val);
349 void fprint_help (FILE *st);
350 void fprint_stopped (FILE *st, t_stat r);
351 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
352 void fprint_sep (FILE *st, int32 *tokens);
353 char *read_line (char *ptr, int32 size, FILE *stream);
354 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
355 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
356 char *sim_trim_endspc (char *cptr);
357
358
359
360 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
361 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
362 t_bool qdisable (DEVICE *dptr);
363 t_stat attach_err (UNIT *uptr, t_stat stat);
364 t_stat detach_all (int32 start_device, t_bool shutdown);
365 t_stat assign_device (DEVICE *dptr, const char *cptr);
366 t_stat deassign_device (DEVICE *dptr);
367 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
368 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
369 REG *lowr, REG *highr, uint32 lows, uint32 highs);
370 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
371 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
372 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
373 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
374 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
375 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
376 UNIT *uptr, int32 dfltinc);
377 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
378 t_stat step_svc (UNIT *ptr);
379 t_stat expect_svc (UNIT *ptr);
380 t_stat set_on (int32 flag, CONST char *cptr);
381 t_stat set_verify (int32 flag, CONST char *cptr);
382 t_stat set_message (int32 flag, CONST char *cptr);
383 t_stat set_quiet (int32 flag, CONST char *cptr);
384 t_stat set_localopc (int32 flag, CONST char *cptr);
385 t_stat set_asynch (int32 flag, CONST char *cptr);
386 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
387 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
388 void int_handler (int signal);
389 t_stat set_prompt (int32 flag, CONST char *cptr);
390 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
391 t_stat sim_set_environment (int32 flag, CONST char *cptr);
392 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
393
394
395
396 DEVICE *sim_dflt_dev = NULL;
397 UNIT *sim_clock_queue = QUEUE_LIST_END;
398 int32 sim_interval = 0;
399 int32 sim_switches = 0;
400 FILE *sim_ofile = NULL;
401 SCHTAB *sim_schrptr = NULL;
402 SCHTAB *sim_schaptr = NULL;
403 DEVICE *sim_dfdev = NULL;
404 UNIT *sim_dfunit = NULL;
405 DEVICE **sim_internal_devices = NULL;
406 uint32 sim_internal_device_count = 0;
407 int32 sim_opt_out = 0;
408 int32 sim_is_running = 0;
409 t_bool sim_processing_event = FALSE;
410 uint32 sim_brk_summ = 0;
411 uint32 sim_brk_types = 0;
412 BRKTYPTAB *sim_brk_type_desc = NULL;
413 uint32 sim_brk_dflt = 0;
414 uint32 sim_brk_match_type;
415 t_addr sim_brk_match_addr;
416 char *sim_brk_act[MAX_DO_NEST_LVL];
417 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
418 BRKTAB **sim_brk_tab = NULL;
419 int32 sim_brk_ent = 0;
420 int32 sim_brk_lnt = 0;
421 int32 sim_brk_ins = 0;
422 int32 sim_iglock = 0;
423 int32 sim_nolock = 0;
424 int32 sim_quiet = 0;
425 int32 sim_localopc = 1;
426 int32 sim_randompst = 0;
427 int32 sim_randstate = 0;
428 int32 sim_step = 0;
429 int nodist = 0;
430 #if defined(PERF_STRIP)
431 int32 sim_nostate = 1;
432 #else
433 int32 sim_nostate = 0;
434 #endif
435 static double sim_time;
436 static uint32 sim_rtime;
437 static int32 noqueue_time;
438 volatile int32 stop_cpu = 0;
439 t_value *sim_eval = NULL;
440 static t_value sim_last_val;
441 static t_addr sim_last_addr;
442 FILE *sim_log = NULL;
443 FILEREF *sim_log_ref = NULL;
444 FILE *sim_deb = NULL;
445 FILEREF *sim_deb_ref = NULL;
446 int32 sim_deb_switches = 0;
447 struct timespec sim_deb_basetime;
448 char *sim_prompt = NULL;
449 static FILE *sim_gotofile;
450 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];
451 static int32 sim_do_echo = 0;
452 static int32 sim_show_message = 1;
453 static int32 sim_on_inherit = 0;
454 static int32 sim_do_depth = 0;
455
456 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
457 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
458 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
459 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
460 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
461
462 t_stat sim_last_cmd_stat;
463
464 static SCHTAB sim_stabr;
465 static SCHTAB sim_staba;
466
467 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };
468 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) };
469
470
471
472 const char save_vercur[] = "V4.1";
473 const char save_ver40[] = "V4.0";
474 const char save_ver35[] = "V3.5";
475 const char save_ver32[] = "V3.2";
476 const char save_ver30[] = "V3.0";
477 const struct scp_error {
478 const char *code;
479 const char *message;
480 } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
481 {{"NXM", "Address space exceeded"},
482 {"UNATT", "Unit not attached"},
483 {"IOERR", "I/O error"},
484 {"CSUM", "Checksum error"},
485 {"FMT", "Format error"},
486 {"NOATT", "Unit not attachable"},
487 {"OPENERR", "File open error"},
488 {"MEM", "Memory exhausted"},
489 {"ARG", "Invalid argument"},
490 {"STEP", "Step expired"},
491 {"UNK", "Unknown command"},
492 {"RO", "Read only argument"},
493 {"INCOMP", "Command not completed"},
494 {"STOP", "Simulation stopped"},
495 {"EXIT", "Goodbye"},
496 {"TTIERR", "Console input I/O error"},
497 {"TTOERR", "Console output I/O error"},
498 {"EOF", "End of file"},
499 {"REL", "Relocation error"},
500 {"NOPARAM", "No settable parameters"},
501 {"ALATT", "Unit already attached"},
502 {"TIMER", "Hardware timer error"},
503 {"SIGERR", "Signal handler setup error"},
504 {"TTYERR", "Console terminal setup error"},
505 {"SUB", "Subscript out of range"},
506 {"NOFNC", "Command not allowed"},
507 {"UDIS", "Unit disabled"},
508 {"NORO", "Read only operation not allowed"},
509 {"INVSW", "Invalid switch"},
510 {"MISVAL", "Missing value"},
511 {"2FARG", "Too few arguments"},
512 {"2MARG", "Too many arguments"},
513 {"NXDEV", "Non-existent device"},
514 {"NXUN", "Non-existent unit"},
515 {"NXREG", "Non-existent register"},
516 {"NXPAR", "Non-existent parameter"},
517 {"NEST", "Nested DO command limit exceeded"},
518 {"IERR", "Internal error"},
519 {"MTRLNT", "Invalid magtape record length"},
520 {"LOST", "Console Telnet connection lost"},
521 {"TTMO", "Console Telnet connection timed out"},
522 {"STALL", "Console Telnet output stall"},
523 {"AFAIL", "Assertion failed"},
524 {"INVREM", "Invalid remote console command"},
525 {"NOTATT", "Not attached"},
526 {"EXPECT", "Expect matched"},
527 {"REMOTE", "Remote console command"},
528 };
529
530 const size_t size_map[] = { sizeof (int8),
531 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
532 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
533 };
534
535 const t_value width_mask[] = { 0,
536 0x1, 0x3, 0x7, 0xF,
537 0x1F, 0x3F, 0x7F, 0xFF,
538 0x1FF, 0x3FF, 0x7FF, 0xFFF,
539 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
540 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
541 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
542 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
543 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
544 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
545 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
546 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
547 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
548 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
549 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
550 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
551 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
552 };
553
554 static const char simh_help[] =
555
556 "1Commands\n"
557 #define HLP_RESET "*Commands Resetting Devices"
558
559 "2Resetting Devices\n"
560 " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\n"
561 " simulator to a predefined condition. If the switch \"`-p`\" is specified,\n"
562 " the device is reset to its initial power-on state:\n\n"
563 "++RESET resets all devices\n"
564 "++RESET -p power-cycle all devices\n"
565 "++RESET ALL resets all devices\n"
566 "++RESET <device> resets the specified <device>\n\n"
567 " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\n"
568 " interrupt requests, and returns the device to a quiescent state.\n\n"
569 " * It does **NOT** clear the main memory or affect associated I/O\n"
570 " connections.\n"
571 #define HLP_EXAMINE "*Commands Examining_and_Changing_State"
572 #define HLP_IEXAMINE "*Commands Examining_and_Changing_State"
573 #define HLP_DEPOSIT "*Commands Examining_and_Changing_State"
574 #define HLP_IDEPOSIT "*Commands Examining_and_Changing_State"
575
576 "2Examining and Changing State\n"
577 " There are four commands to examine and change state:\n\n"
578 " * `EXAMINE` (*abbreviated* `E`) examines state\n"
579 " * `DEPOSIT` (*abbreviated* `D`) changes state\n"
580 " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\n"
581 " and allows the user to interactively change it\n"
582 " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\n"
583 " interactively change state\n\n"
584 " All four commands take the form:\n\n"
585 "++command {modifiers} <object list>\n\n"
586 " The `DEPOSIT` command requires the deposit value at the end of the command.\n\n"
587 " There are four kinds of modifiers: **switches**, **device/unit name**,\n"
588 " **search specifier**, and for `EXAMINE`, **output file**.\n\n"
589 " * **Switches** have been described previously.\n"
590 " * A **device/unit name** identifies the device and unit whose address\n"
591 " space is to be examined or modified. If no device is specified, the CPU\n"
592 " main memory is selected. If a device but no unit is specified, unit `0`\n"
593 " of the specified device is selected automatically.\n"
594 " * The **search specifier** provides criteria for testing addresses or\n"
595 " registers to see if they should be processed. The search specifier\n"
596 " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\n"
597 " both, optionally separated by spaces:\n\n"
598 "++{ < logical op > < value > } < relational op > < value >\n\n"
599
600 " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\n"
601 " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\n"
602 " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\n"
603 " equal*), \">=\" (*greater than or equal*), \">\" (*greater\n"
604 " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\n"
605 " * * If any \"<`logical operator`>\" is specified without\n"
606 " a \"<`relational operator`>\", it is ignored.\n"
607 " * * If any \"<`relational operator`>\" is specified without\n"
608 " a \"<`logical operator`>\", no logical operation is performed.\n"
609 " * * All comparisons are unsigned.\n\n"
610 " * The **output file** modifier redirects the command output to a file\n"
611 " instead of the console. The **output file** modifier is specified with\n"
612 " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\n\n"
613 " **NOTE**: Modifiers may be specified in any order. If multiple\n"
614 " modifiers of the same type are specified, later modifiers override earlier\n"
615 " modifiers. If the **device/unit name** comes *after* the search specifier,\n"
616 " the search values will interpreted in the *radix of the CPU*, rather than\n"
617 " of the device/unit.\n\n"
618 " The \"<`object list`>\" argument consists of one or more of the following,\n"
619 " separated by commas:\n\n"
620
621 "++register the specified register\n"
622 "++register[sub1-sub2] the specified register array locations,\n"
623 "++++++++ starting at location sub1 up to and\n"
624 "++++++++ including location sub2\n"
625 "++register[sub1/length] the specified register array locations,\n"
626 "++++++++ starting at location sub1 up to but\n"
627 "++++++++ not including sub1+length\n"
628 "++register[ALL] all locations in the specified register\n"
629 "++++++++ array\n"
630 "++register1-register2 all the registers starting at register1\n"
631 "++++++++ up to and including register2\n"
632 "++address the specified location\n"
633 "++address1-address2 all locations starting at address1 up to\n"
634 "++++++++ and including address2\n"
635 "++address/length all location starting at address up to\n"
636 "++++++++ but not including address+length\n"
637 "++STATE all registers in the device\n"
638 "++ALL all locations in the unit\n"
639 "++$ the last value displayed by an EXAMINE\n"
640 "++++++++ command interpreted as an address\n"
641 "3Switches\n"
642 "4Formatting Control\n"
643 " Switches can be used to control the format of the displayed information:\n\n"
644
645 "5-a\n"
646 " display as ASCII\n"
647 "5-c\n"
648 " display as character string\n"
649 "5-m\n"
650 " display as instruction mnemonics\n"
651 "5-o\n"
652 " display as octal\n"
653 "5-d\n"
654 " display as decimal\n"
655 "5-h\n"
656 " display as hexadecimal\n\n"
657 "3Examples\n"
658 "++ex 1000-1100 examine 1000 to 1100\n"
659 "++de PC 1040 set PC to 1040\n"
660 "++ie 40-50 interactively examine 40:50\n"
661 "++ie >1000 40-50 interactively examine the subset\n"
662 "+++++++++ of locations 40:50 that are >1000\n"
663 "++ex rx0 50060 examine 50060, RX unit 0\n"
664 "++ex rx sbuf[3-6] examine SBUF[3] to SBUF[6] in RX\n"
665 "++de all 0 set main memory to 0\n"
666 "++de &77>0 0 set all addresses whose low order\n"
667 "+++++++++ bits are non-zero to 0\n"
668 "++ex -m @memdump.txt 0-7777 dump memory to file\n\n"
669 " * **NOTE**: To terminate an interactive command, simply type any bad value\n"
670 " (*e.g.* `XYZ`) when input is requested.\n"
671 #define HLP_EVALUATE "*Commands Evaluating_Instructions"
672
673 "2Evaluating Instructions\n"
674 " The `EVAL` command evaluates a symbolic expression and returns the\n"
675 " equivalent numeric value.\n\n"
676
677 "2Running A Simulated Program\n"
678 #define HLP_RUN "*Commands Running_A_Simulated_Program RUN"
679 "3RUN\n"
680 " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\n"
681 " argument, if given, in the PC (program counter), and starts execution.\n"
682 " If no argument is given execution starts at the current PC.\n"
683 #define HLP_GO "*Commands Running_A_Simulated_Program GO"
684 "3GO\n"
685 " The `GO` command does *not* reset devices, deposits its argument (if\n"
686 " given) in the PC, and starts execution. If no argument is given,\n"
687 " execution starts at the current PC (program counter).\n"
688 #define HLP_CONTINUE "*Commands Running_A_Simulated_Program Continuing_Execution"
689 "3Continuing Execution\n"
690 " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\n"
691 " (if execution was stopped, possibly due to hitting a breakpoint) at the\n"
692 " current program counter without resetting any devices.\n"
693 #define HLP_STEP "*Commands Running_A_Simulated_Program Step_Execution"
694 "3Step Execution\n"
695 " The `STEP` command (*abbreviated* `S`) resumes execution at the current\n"
696 " PC for the number of instructions given by its argument. If no argument\n"
697 " is supplied, one instruction is executed.\n"
698 "4Switches\n"
699 "5`-T`\n"
700 " If the `STEP` command is invoked with the \"`-T`\" switch, the step\n"
701 " command will cause execution to run for *microseconds* rather than\n"
702 " instructions.\n"
703 #define HLP_NEXT "*Commands Running_A_Simulated_Program NEXT"
704 "3NEXT\n"
705 " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\n"
706 " for one instruction, attempting to execute *through* subroutine calls.\n"
707 " If the next instruction to be executed is *not* a subroutine call, then\n"
708 " one instruction is executed.\n"
709 #define HLP_BOOT "*Commands Running_A_Simulated_Program Booting_the_system"
710 "3Booting the system\n"
711 " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\n"
712 " the device and unit given by its argument. If no unit is supplied,\n"
713 " unit `0` is bootstrapped. The specified unit must be `ATTACH`'ed.\n\n"
714 " When booting Multics, the boot device should always be `iom0`.\n"
715 " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\n"
716 " into memory and the system will transfer control to the boot record.\n\n"
717 " **Example**\n\n"
718 "++; Boot Multics using iom0\n"
719 "++boot iom0\n\n"
720
721 "2Stopping The Simulator\n"
722 " The simulator runs until the simulated hardware encounters an error, or\n"
723 " until the user forces a stop condition.\n"
724 "3Simulator Detected Stop Conditions\n"
725 " These simulator-detected conditions stop simulation:\n\n"
726 "++- HALT instruction. If a HALT instruction is decoded, simulation stops.\n\n"
727 "++- I/O error. If an I/O error occurs during simulation of an I/O\n"
728 "+++operation, and the device stop-on-I/O-error flag is set, simulation\n"
729 "+++usually stops.\n\n"
730 "++- Processor condition. Certain processor conditions can stop\n"
731 "+++the simulation.\n"
732 "3User Specified Stop Conditions\n"
733 " Typing the interrupt character stops simulation. The interrupt character\n"
734 " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\n"
735 " set to `005` (`^E`).\n\n"
736
737 #define HLP_BREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
738 #define HLP_NOBREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
739 "4Breakpoints\n"
740 " The simulator offers breakpoint capability for debugging. Users may define\n"
741 " breakpoints of different types, identified by letter (for example, `E`\n"
742 " for *execution*, `R` for *read*, `W` for *write*, etc).\n\n"
743 " Associated with each breakpoint is a count and, optionally, one or more\n"
744 " actions. Each time a breakpoint occurs, the associated count\n"
745 " is *decremented*. If the count is less than or equal to `0`, the breakpoint\n"
746 " occurs; otherwise, it is deferred. When the breakpoint occurs, any\n"
747 " optional actions are automatically executed.\n\n"
748 " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\n\n"
749 "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\n\n"
750 " If no type is specified, the default breakpoint type (`E`, *execution*) is\n"
751 " used. If no address range is specified, the current PC is used. As\n"
752 " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\n"
753 " range of addresses low-high, or a relative range of address/length.\n"
754
755 "5Displaying Breakpoints\n"
756 " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\n\n"
757 "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\n\n"
758 " Locations with breakpoints of the specified type are displayed.\n\n"
759 " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\n"
760 " commands which may be subsequently used to establish the same\n"
761 " breakpoint(s).\n\n"
762 "5Removing Breakpoints\n"
763 " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\n"
764 "5Examples\n"
765 " The following examples illustrate breakpoint usage:\n\n"
766 "++BREAK set E break at current PC\n"
767 "++BREAK -e 200 set E break at 200\n"
768 "++BREAK 2000/2[2] set E breaks at 2000,2001 with count = 2\n"
769 "++BREAK 100;EX AC;D MQ 0 set E break at 100 with actions EX AC and\n"
770 "+++++++++D MQ 0\n"
771 "++BREAK 100; delete action on break at 100\n\n"
772
773 "2Connecting and Disconnecting Devices\n"
774 " Units are simulated as files on the host file system. Before using any\n"
775 " simulated unit, the user must specify the file to be accessed by that unit.\n"
776 #define HLP_ATTACH "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
777 "3Attaching devices\n"
778 " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\n\n"
779 "++ATTACH <unit> <filename>\n\n"
780 " Some devices have more detailed or specific help available with:\n\n"
781 "++HELP <device> ATTACH\n\n"
782 "4Switches\n"
783 "5-n\n"
784 " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\n"
785 " file will be created when the filename specified does not exist, or an\n"
786 " existing file will have it's size truncated to zero, and an appropriate\n"
787 " message is printed.\n"
788 "5-e\n"
789 " If the file does not exist, and the \"`-e`\" switch *was not* specified,\n"
790 " a new file is created, and an appropriate message is printed. If\n"
791 " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\n"
792 " error message is printed.\n"
793 "5-r\n"
794 " If the \"`-r`\" switch is specified, or the file is write protected by\n"
795 " host operating system, `ATTACH` tries to open the file in read only mode.\n"
796 " If the file does not exist, or the unit does not support read only\n"
797 " operation, an error occurs. Input-only devices, such as card readers, or\n"
798 " storage devices with write locking switches, such as disks or tapes,\n"
799 " support read only operation - other devices do not. If a file is\n"
800 " attached read only, its contents can be examined but not modified.\n"
801 "5-q\n"
802 " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\n"
803 " or opening one read only (\"`-r`\"), the message announcing this fact\n"
804 " is suppressed.\n"
805 "5-f\n"
806 " For simulated magnetic tapes, the `ATTACH` command can specify the format\n"
807 " of the attached tape image file:\n\n"
808 "++ATTACH -f <tape_unit> <format> <filename>\n\n"
809 " * The currently supported magnetic tape image file formats are:\n\n"
810 " | | |\n"
811 " | ----------------:|:---------------------------------------------------- |\n"
812 " | \"**`SIMH`**\" | The **SIMH** / **DPS8M** native portable tape format |\n"
813 " | \"**`E11`**\" | The *D Bit* **Ersatz-11** simulator format |\n"
814 " | \"**`TPC`**\" | The **TPC** format (*used by _SIMH_ prior to V2.3*) |\n"
815 " | \"**`P7B`**\" | The **Paul Pierce** `7`-track tape archive format |\n\n"
816
817 " * The default tape format can also be specified with the `SET` command\n"
818 " prior to using the `ATTACH` command:\n\n"
819 "++SET <tape_unit> FORMAT=<format>\n"
820 "++ATTACH <tape_unit> <filename>\n\n"
821 " * The format of a currently attached tape image can be displayed with\n"
822 " the `SHOW FORMAT` command:\n\n"
823 "++SHOW <unit> FORMAT\n\n"
824 " **Examples**\n\n"
825 " The following example illustrates common `ATTACH` usage:\n"
826 "++; Associate the tape image file \"12.7MULTICS.tap\" with the tape0 unit\n"
827 "++; in read-only mode, where tape0 corresponds to the first tape device.\n"
828 "++ATTACH -r tape0 12.7MULTICS.tap\n\n"
829 "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\n"
830 "++; The disk0 unit corresponds to the first disk device.\n"
831 "++ATTACH disk0 root.dsk\n\n"
832
833 #define HLP_DETACH "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
834 "3Detaching devices\n"
835 " The `DETACH` (*abbreviation* `DET`) command breaks the association between\n"
836 " a unit and its backing file or device:\n\n"
837 "++DETACH ALL Detach all units\n"
838 "++DETACH <unit> Detach specified unit\n\n"
839 " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\n"
840 #define HLP_SET "*Commands SET"
841 "2SET\n"
842
843 #define HLP_SET_LOG "*Commands SET Logging"
844 "3Logging\n"
845 " Interactions with the simulator session can be recorded to a log file.\n\n"
846 "+SET LOG log_file Specify the log destination\n"
847 "++++++++ (STDOUT, DEBUG, or filename)\n"
848 "+SET NOLOG Disables any currently active logging\n"
849 "4Switches\n"
850 "5`-N`\n"
851 " By default, log output is written at the *end* of the specified log file.\n"
852 " A new log file can created if the \"`-N`\" switch is used on the command\n"
853 " line.\n\n"
854 "5`-B`\n"
855 " By default, log output is written in *text* mode. The log file can be\n"
856 " opened for *binary* mode writing if the \"`-B`\" switch is used on the\n"
857 " command line.\n"
858 #define HLP_SET_DEBUG "*Commands SET Debug_Messages"
859
860 "3Debug Messages\n"
861 "+SET DEBUG debug_file Specify the debug destination\n"
862 "++++++++ (STDOUT, STDERR, LOG, or filename)\n"
863 "+SET NODEBUG Disables any currently active debug output\n"
864 "4Switches\n"
865 " Debug message output contains a timestamp which indicates the number of\n"
866 " simulated instructions which have been executed prior to the debug event.\n\n"
867 " Debug message output can be enhanced to contain additional, potentially\n"
868 " useful information.\n\n\n"
869 " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\n"
870 "5-T\n"
871 " The \"`-T`\" switch causes debug output to contain a time of day displayed\n"
872 " as `hh:mm:ss.msec`.\n"
873 "5-A\n"
874 " The \"`-A`\" switch causes debug output to contain a time of day displayed\n"
875 " as `seconds.msec`.\n"
876 "5-R\n"
877 " The \"`-R`\" switch causes timing to be relative to the start of debugging.\n"
878 "5-P\n"
879 " The \"`-P`\" switch adds the output of the PC (program counter) to each\n"
880 " debug message.\n"
881 "5-N\n"
882 " The \"`-N`\" switch causes a new (empty) file to be written to.\n"
883 " (The default is to append to an existing debug log file).\n"
884 "5-D\n"
885 " The \"`-D`\" switch causes data blob output to also display the data\n"
886 " as **`RADIX-50`** characters.\n"
887 "5-E\n"
888 " The \"`-E`\" switch causes data blob output to also display the data\n"
889 " as \"**EBCDIC**\" characters.\n"
890
891 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
892 "3Environment Variables\n"
893 "+SET ENVIRONMENT NAME=val Set environment variable\n"
894 "+SET ENVIRONMENT NAME Clear environment variable\n"
895 #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
896 "3Command Status Trap Dispatching\n"
897 "+SET ON Enables error checking command execution\n"
898 "+SET NOON Disables error checking command execution\n"
899 "+SET ON INHERIT Enables inheritance of ON state and actions\n"
900 "+SET ON NOINHERIT Disables inheritance of ON state and actions\n"
901 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
902 "3Command Execution Display\n"
903 "+SET VERIFY Enables display of processed script commands\n"
904 "+SET VERBOSE Enables display of processed script commands\n"
905 "+SET NOVERIFY Disables display of processed script commands\n"
906 "+SET NOVERBOSE Disables display of processed script commands\n"
907 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
908 "3Command Error Status Display\n"
909 "+SET MESSAGE Re-enables display of script error messages\n"
910 "+SET NOMESSAGE Disables display of script error messages\n"
911 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
912 "3Command Output Display\n"
913 "+SET QUIET Disables suppression of some messages\n"
914 "+SET NOQUIET Re-enables suppression of some messages\n"
915 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
916 "3Local Operator Console\n"
917 "+SET LOCALOPC Enables local operator console\n"
918 "+SET NOLOCALOPC Disables local operator console\n"
919 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
920 "3Command Prompt\n"
921 "+SET PROMPT \"string\" Sets an alternate simulator prompt string\n"
922 "3Device and Unit Settings\n"
923 "+SET <dev> OCT|DEC|HEX Set device display radix\n"
924 "+SET <dev> ENABLED Enable device\n"
925 "+SET <dev> DISABLED Disable device\n"
926 "+SET <dev> DEBUG{=arg} Set device debug flags\n"
927 "+SET <dev> NODEBUG={arg} Clear device debug flags\n"
928 "+SET <dev> arg{,arg...} Set device parameters\n"
929 "+SET <unit> ENABLED Enable unit\n"
930 "+SET <unit> DISABLED Disable unit\n"
931 "+SET <unit> arg{,arg...} Set unit parameters\n"
932 "+HELP <dev> SET Displays any device specific SET commands\n"
933 " \n\n"
934 " See the Omnibus documentation for a complete SET command reference.\n"
935
936 #define HLP_SHOW "*Commands SHOW"
937 "2SHOW\n"
938 "+SH{OW} B{UILDINFO} Show build-time compilation information\n"
939 "+SH{OW} CL{OCKS} Show wall clock and timer information\n"
940 "+SH{OW} C{ONFIGURATION} Show simulator configuration\n"
941 "+SH{OW} D{EFAULT_BASE_SYSTEM} Show default base system script\n"
942 "+SH{OW} DEV{ICES} Show devices\n"
943 "+SH{OW} M{ODIFIERS} Show SET commands for all devices\n"
944 "+SH{OW} O{N} Show ON condition actions\n"
945 "+SH{OW} P{ROM} Show CPU ID PROM initialization data\n"
946 "+SH{OW} Q{UEUE} Show event queue\n"
947 "+SH{OW} S{HOW} Show SHOW commands for all devices\n"
948 "+SH{OW} T{IME} Show simulated timer\n"
949 "+SH{OW} VE{RSION} Show simulator version\n"
950 "+H{ELP} <dev> SHOW Show device-specific SHOW commands\n"
951 "+SH{OW} <dev> {arg,...} Show device parameters\n"
952 "+SH{OW} <dev> DEBUG Show device debug flags\n"
953 "+SH{OW} <dev> MODIFIERS Show device modifiers\n"
954 "+SH{OW} <dev> RADIX Show device display radix\n"
955 "+SH{OW} <dev> SHOW Show device SHOW commands\n"
956 "+SH{OW} <unit> {arg,...} Show unit parameters\n\n"
957 " See the Omnibus documentation for a complete SHOW command reference.\n\n"
958 #define HLP_SHOW_CONFIG "*Commands SHOW"
959 #define HLP_SHOW_DEVICES "*Commands SHOW"
960 #define HLP_SHOW_FEATURES "*Commands SHOW"
961 #define HLP_SHOW_QUEUE "*Commands SHOW"
962 #define HLP_SHOW_TIME "*Commands SHOW"
963 #define HLP_SHOW_MODIFIERS "*Commands SHOW"
964 #define HLP_SHOW_NAMES "*Commands SHOW"
965 #define HLP_SHOW_SHOW "*Commands SHOW"
966 #define HLP_SHOW_VERSION "*Commands SHOW"
967 #define HLP_SHOW_BUILDINFO "*Commands SHOW"
968 #define HLP_SHOW_PROM "*Commands SHOW"
969 #define HLP_SHOW_DBS "*Commands SHOW"
970 #define HLP_SHOW_DEFAULT "*Commands SHOW"
971 #define HLP_SHOW_CONSOLE "*Commands SHOW"
972 #define HLP_SHOW_REMOTE "*Commands SHOW"
973 #define HLP_SHOW_BREAK "*Commands SHOW"
974 #define HLP_SHOW_LOG "*Commands SHOW"
975 #define HLP_SHOW_DEBUG "*Commands SHOW"
976 #define HLP_SHOW_CLOCKS "*Commands SHOW"
977 #define HLP_SHOW_ON "*Commands SHOW"
978 #define HLP_SHOW_SEND "*Commands SHOW"
979 #define HLP_SHOW_EXPECT "*Commands SHOW"
980 #define HLP_HELP "*Commands HELP"
981
982 "2HELP\n"
983 "+H{ELP} Show this message\n"
984 "+H{ELP} <command> Show help for command\n"
985 "+H{ELP} <dev> Show help for device\n"
986 "+H{ELP} <dev> REGISTERS Show help for device register variables\n"
987 "+H{ELP} <dev> ATTACH Show help for device specific ATTACH command\n"
988 "+H{ELP} <dev> SET Show help for device specific SET commands\n"
989 "+H{ELP} <dev> SHOW Show help for device specific SHOW commands\n"
990 "+H{ELP} <dev> <command> Show help for device specific <command> command\n"
991
992 "2Altering The Simulated Configuration\n"
993 " The \"SET <device> DISABLED\" command removes a device from the configuration.\n"
994 " A `DISABLED` device is invisible to running programs. The device can still\n"
995 " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\n\n"
996 " The \"SET <device> ENABLED\" command restores a disabled device to a\n"
997 " configuration.\n\n"
998 " Most multi-unit devices allow units to be enabled or disabled:\n\n"
999 "++SET <unit> ENABLED\n"
1000 "++SET <unit> DISABLED\n\n"
1001 " When a unit is disabled, it will not be displayed by SHOW DEVICE.\n\n"
1002
1003 #define HLP_DO "*Commands Executing_Command_Files Processing_Command_Files"
1004 "2Executing Command Files\n"
1005 "3Processing Command Files\n"
1006 " The simulator can invoke another script file with the \"`DO`\" command:\n\n"
1007 "++DO <filename> {arguments...} execute commands in specified file\n\n"
1008 " The \"`DO`\" command allows command files to contain substitutable\n"
1009 " arguments. The string \"`%%n`\", where \"`n`\" is a number\n"
1010 " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\n"
1011 " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\n"
1012 " The string \"`%%0`\" is replaced with \"<`filename`>\".\n The\n"
1013 " sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\n"
1014 " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\n"
1015 " be enclosed in matching single or double quotation marks.\n\n"
1016 " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\n"
1017 " deep.\n\n"
1018 "4Switches\n"
1019 "5`-v`\n\n"
1020 " If the switch \"`-v`\" is specified, commands in the command file are\n"
1021 " echoed *before* they are executed.\n\n"
1022 "5`-e`\n\n"
1023 " If the switch \"`-e`\" is specified, command processing (including nested\n"
1024 " command invocations) will be aborted if any command error is encountered.\n"
1025 " (A simulation stop **never** aborts processing; use `ASSERT` to catch\n"
1026 " unexpected stops.) Without this switch, all errors except `ASSERT` failures\n"
1027 " will be ignored, and command processing will continue.\n\n"
1028 "5`-o`\n\n"
1029 " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\n"
1030 " the calling command file will be inherited by the command file being\n"
1031 " invoked.\n"
1032 "5`-q`\n\n"
1033 " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\n"
1034 " enabled for the called command file, otherwise the *quiet mode* setting\n"
1035 " is inherited from the calling context.\n"
1036
1037 #define HLP_GOTO "*Commands Executing_Command_Files GOTO"
1038 "3GOTO\n"
1039 " Commands in a command file execute in sequence until either an error\n"
1040 " trap occurs (when a command completes with an error status), or when an\n"
1041 " explicit request is made to start command execution elsewhere with\n"
1042 " the `GOTO` command:\n\n"
1043 "++GOTO <label>\n\n"
1044 " * Labels are lines in a command file which the first non-whitespace\n"
1045 " character is a \"`:`\".\n"
1046 " * The target of a `GOTO` is the first matching label in the current `DO`\n"
1047 " command file which is encountered.\n\n"
1048 " **Example**\n\n"
1049 " The following example illustrates usage of the `GOTO` command (by\n"
1050 " creating an infinite loop):\n\n"
1051 "++:Label\n"
1052 "++:: This is a loop.\n"
1053 "++GOTO Label\n\n"
1054 #define HLP_RETURN "*Commands Executing_Command_Files RETURN"
1055
1056 "3RETURN\n"
1057 " The `RETURN` command causes the current procedure call to be restored to\n"
1058 " the calling context, possibly returning a specific return status.\n"
1059 " If no return status is specified, the return status from the last command\n"
1060 " executed will be returned. The calling context may have `ON` traps defined\n"
1061 " which may redirect command flow in that context.\n\n"
1062 "++RETURN return from command file with last command status\n"
1063 "++RETURN {-Q} <status> return from command file with specific status\n\n"
1064 " * The status return can be any numeric value or one of the standard SCPE_\n"
1065 " condition names.\n\n"
1066 " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\n"
1067 " status to be returned, but normal error status message printing to be\n"
1068 " suppressed.\n\n"
1069 " **Condition Names**\n\n"
1070 " The available standard SCPE_ condition names and their meanings are:\n\n"
1071 " | Name | Meaning | Name | Meaning |\n"
1072 " | ------- | --------------------------------| ------- | ----------------------------------- |\n"
1073 " | NXM | Address space exceeded | UNATT | Unit not attached |\n"
1074 " | IOERR | I/O error | CSUM | Checksum error |\n"
1075 " | FMT | Format error | NOATT | Unit not attachable |\n"
1076 " | OPENERR | File open error | MEM | Memory exhausted |\n"
1077 " | ARG | Invalid argument | STEP | Step expired |\n"
1078 " | UNK | Unknown command | RO | Read only argument |\n"
1079 " | INCOMP | Command not completed | STOP | Simulation stopped |\n"
1080 " | EXIT | Goodbye | TTIERR | Console input I/O error |\n"
1081 " | TTOERR | Console output I/O error | EOF | End of file |\n"
1082 " | REL | Relocation error | NOPARAM | No settable parameters |\n"
1083 " | ALATT | Unit already attached | TIMER | Hardware timer error |\n"
1084 " | SIGERR | Signal handler setup error | TTYERR | Console terminal setup error |\n"
1085 " | NOFNC | Command not allowed | UDIS | Unit disabled |\n"
1086 " | NORO | Read only operation not allowed | INVSW | Invalid switch |\n"
1087 " | MISVAL | Missing value | 2FARG | Too few arguments |\n"
1088 " | 2MARG | Too many arguments | NXDEV | Non-existent device |\n"
1089 " | NXUN | Non-existent unit | NXREG | Non-existent register |\n"
1090 " | NXPAR | Non-existent parameter | NEST | Nested DO command limit exceeded |\n"
1091 " | IERR | Internal error | MTRLNT | Invalid magtape record length |\n"
1092 " | LOST | Console Telnet connection lost | TTMO | Console Telnet connection timed out |\n"
1093 " | STALL | Console Telnet output stall | AFAIL | Assertion failed |\n"
1094 " | INVREM | Invalid remote console command | | |\n"
1095 "\n\n"
1096 #define HLP_SHIFT "*Commands Executing_Command_Files Shift_Parameters"
1097 "3Shift Parameters\n"
1098 " Shift the command files positional parameters\n"
1099 #define HLP_CALL "*Commands Executing_Command_Files Call_a_subroutine"
1100 "3Call a subroutine\n"
1101 " Control can be transferred to a labeled subroutine using `CALL`.\n\n"
1102 " **Example**\n\n"
1103 "++CALL routine\n"
1104 "++BYE\n"
1105 "++\n"
1106 "++:routine\n"
1107 "++ECHO routine called\n"
1108 "++RETURN\n\n"
1109 #define HLP_ON "*Commands Executing_Command_Files ON"
1110 "3ON\n"
1111 " The `ON` command performs actions after a condition, or clears a condition.\n"
1112 "++ON <condition> <action> Perform action after condition\n"
1113 "++ON <condition> Clears action of specified condition\n"
1114 #define HLP_PROCEED "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1115 #define HLP_IGNORE "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1116
1117 "3PROCEED or IGNORE\n"
1118 " The `PROCEED` (or `IGNORE`) command does nothing. It is potentially\n"
1119 " useful as a placeholder for any `ON` action condition that should be\n"
1120 " explicitly ignored, allowing command file execution to continue without\n"
1121 " taking any specific action.\n"
1122 #define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1123
1124 "3Displaying Arbitrary Text\n"
1125 " The `ECHO` command is a useful way of annotating command files. `ECHO`\n"
1126 " prints out its arguments to the console (and to any applicable log file):\n\n"
1127 "++ECHO <string> Output string to console\n\n"
1128 " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\n"
1129 " This may be used to provide spacing for console messages or log file\n"
1130 " output.\n"
1131
1132 #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Assertions"
1133 "3Testing Assertions\n"
1134 " The `ASSERT` command tests a simulator state condition and halts command\n"
1135 " file execution if the condition is false:\n\n"
1136 "++ASSERT <Simulator State Expressions>\n\n"
1137 " * If the indicated expression evaluates to false, the command completes\n"
1138 " with an `AFAIL` condition. By default, when a command file encounters a\n"
1139 " command which returns the `AFAIL` condition, it will exit the running\n"
1140 " command file with the `AFAIL` status to the calling command file. This\n"
1141 " behavior can be changed with the `ON` command as well as switches to the\n"
1142 " invoking `DO` command.\n\n"
1143 " **Examples**\n\n"
1144 " The command file below might be used to bootstrap a hypothetical system\n"
1145 " that halts after the initial load from disk. The `ASSERT` command can then\n"
1146 " be used to confirm that the load completed successfully by examining the\n"
1147 " CPU's \"`A`\" register for the expected value:\n\n"
1148 "++; Example INI file\n"
1149 "++BOOT\n"
1150 "++; A register contains error code; 0 = good boot\n"
1151 "++ASSERT A=0\n"
1152 "++RUN\n\n"
1153
1154 " * In the above example, if the \"`A`\" register is *not* `0`,\n"
1155 " the \"`ASSERT A=0`\" command will be displayed to the user, and the\n"
1156 " command file will be aborted with an \"`Assertion failed`\" message.\n"
1157 " Otherwise, the command file will continue to bring up the system.\n\n"
1158 " * See the **`IF`** command documentation for more information and details\n"
1159 " regarding simulator state expressions.\n\n"
1160 #define HLP_IF "*Commands Executing_Command_Files Testing_Conditions"
1161 "3Testing Conditions\n"
1162 " The `IF` command tests a simulator state condition and executes additional\n"
1163 " commands if the condition is true:\n\n"
1164 "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\n\n"
1165 " **Examples**\n\n"
1166 " The command file below might be used to bootstrap a hypothetical system\n"
1167 " that halts after the initial load from disk. The `IF` command can then\n"
1168 " be used to confirm that the load completed successfully by examining the\n"
1169 " CPU's \"`A`\" register for an expected value:\n\n"
1170 "++; Example INI file\n"
1171 "++BOOT\n"
1172 "++; A register contains error code; 0 = good boot\n"
1173 "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\n"
1174 "++RUN\n\n"
1175
1176 " * In the above example, if the \"`A`\" register is *not* `0`, the\n"
1177 " message \"`Boot failed - Failure Code `\" will be displayed, the contents\n"
1178 " of the \"`A`\" register will be displayed, and the command file will be\n"
1179 " aborted with an \"`Assertion failed`\" message. Otherwise, the command\n"
1180 " file will continue to bring up the system.\n"
1181 "4Conditional Expressions\n"
1182 " The `IF` and `ASSERT` commands evaluate the following two different forms\n"
1183 " of conditional expressions.\n\n"
1184 "5Simulator State Expressions\n"
1185 " \n \n"
1186 " The values of simulator registers can be evaluated with:\n\n"
1187 "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
1188 " * If \"<`dev`>\" is not specified, `CPU` is assumed. \"<`reg`>\" is a\n"
1189 " register belonging to the indicated device.\n"
1190 " * The \"<`addr`>\" is an address in the address space of the indicated\n"
1191 " device.\n"
1192 " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\n"
1193 " the same as those used for \"search specifiers\" by the `EXAMINE` and\n"
1194 " `DEPOSIT` commands.\n"
1195 " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\n"
1196 " not in the radix for the device when referencing a register; when an\n"
1197 " address is referenced the device radix is used as the default.\n\n"
1198 " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\n"
1199 " register value is first altered as indicated. The result is then compared\n"
1200 " to the \"<`value`>\" via the \"<`conditional-op`>\".\n"
1201 " * * If the result is *true*, the command(s) are executed before proceeding\n"
1202 " to the next line in the command file.\n"
1203 " * * If the result is *false*, the next command in the command file is\n"
1204 " processed.\n\n"
1205 "5String Comparison Expressions\n"
1206 " \n \n"
1207 " String Values can be compared with:\n\n"
1208 "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\n\n"
1209 " * The \"`-i`\" switch, if present, causes a comparison to be case\n"
1210 " insensitive.\n"
1211 " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\n"
1212 " values which may have environment variables substituted as desired.\n"
1213 " * The \"<`compare-op`>\" may be one of:\n\n"
1214 " | | |\n"
1215 " | --------------:|:---------------------- |\n"
1216 " | \"**`==`**\" | equal |\n"
1217 " | \"**`EQU`**\" | equal |\n"
1218 " | \"**`!=`**\" | not equal |\n"
1219 " | \"**`NEQ`**\" | not equal |\n"
1220 " | \"**<**\" | less than |\n"
1221 " | \"**`LSS`**\" | less than |\n"
1222 " | \"**<=**\" | less than or equal |\n"
1223 " | \"**`LEQ`**\" | less than or equal |\n"
1224 " | \"**>**\" | greater than |\n"
1225 " | \"**`GTR`**\" | greater than |\n"
1226 " | \"**>=**\" | greater than or equal |\n"
1227 " | \"**`GEQ`**\" | greater than or equal |\n"
1228 " * **NOTE**: Comparisons are *generic*. This means that if\n"
1229 " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\n"
1230 " digits, then the strings are converted to numbers and a numeric\n"
1231 " comparison is performed. For example, the comparison\n"
1232 " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\n"
1233
1234 #define HLP_EXIT "*Commands Exiting_the_Simulator"
1235 "2Exiting the Simulator\n"
1236 " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\n"
1237 " returning control to the host operating system.\n"
1238
1239 #define HLP_SPAWN "*Commands Executing_System_Commands"
1240 "2Executing System Commands\n"
1241 " * The simulator can execute host operating system commands with\n"
1242 " the \"`!`\" (*spawn*) command.\n\n"
1243 " | | |\n"
1244 " |:----------------------- |:------------------------------------------- |\n"
1245 " | \"**`!`**\" | Spawn the hosts default command interpreter |\n"
1246 " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\n\n"
1247 " * **NOTE**: The *exit status* from the command which was executed is set\n"
1248 " as the *command completion status* for the \"`!`\" command. This may\n"
1249 " influence any enabled `ON` condition traps.\n" ;
1250
1251
1252 static CTAB cmd_table[] = {
1253 { "RESET", &reset_cmd, 0, HLP_RESET },
1254 { "EXAMINE", &exdep_cmd, EX_E, HLP_EXAMINE },
1255 { "IEXAMINE", &exdep_cmd, EX_E+EX_I, HLP_IEXAMINE },
1256 { "DEPOSIT", &exdep_cmd, EX_D, HLP_DEPOSIT },
1257 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, HLP_IDEPOSIT },
1258 { "EVALUATE", &eval_cmd, 0, HLP_EVALUATE },
1259 { "RUN", &run_cmd, RU_RUN, HLP_RUN, NULL, &run_cmd_message },
1260 { "GO", &run_cmd, RU_GO, HLP_GO, NULL, &run_cmd_message },
1261 { "STEP", &run_cmd, RU_STEP, HLP_STEP, NULL, &run_cmd_message },
1262 { "NEXT", &run_cmd, RU_NEXT, HLP_NEXT, NULL, &run_cmd_message },
1263 { "CONTINUE", &run_cmd, RU_CONT, HLP_CONTINUE, NULL, &run_cmd_message },
1264 { "BOOT", &run_cmd, RU_BOOT, HLP_BOOT, NULL, &run_cmd_message },
1265 { "BREAK", &brk_cmd, SSH_ST, HLP_BREAK },
1266 { "NOBREAK", &brk_cmd, SSH_CL, HLP_NOBREAK },
1267 { "ATTACH", &attach_cmd, 0, HLP_ATTACH },
1268 { "DETACH", &detach_cmd, 0, HLP_DETACH },
1269 { "EXIT", &exit_cmd, 0, HLP_EXIT },
1270 { "QUIT", &exit_cmd, 0, NULL },
1271 { "BYE", &exit_cmd, 0, NULL },
1272 { "SET", &set_cmd, 0, HLP_SET },
1273 { "SHOW", &show_cmd, 0, HLP_SHOW },
1274 { "DO", &do_cmd, 1, HLP_DO },
1275 { "GOTO", &goto_cmd, 1, HLP_GOTO },
1276 { "RETURN", &return_cmd, 0, HLP_RETURN },
1277 { "SHIFT", &shift_cmd, 0, HLP_SHIFT },
1278 { "CALL", &call_cmd, 0, HLP_CALL },
1279 { "ON", &on_cmd, 0, HLP_ON },
1280 { "IF", &assert_cmd, 0, HLP_IF },
1281 { "PROCEED", &noop_cmd, 0, HLP_PROCEED },
1282 { "IGNORE", &noop_cmd, 0, HLP_IGNORE },
1283 { "ECHO", &echo_cmd, 0, HLP_ECHO },
1284 { "ASSERT", &assert_cmd, 1, HLP_ASSERT },
1285 { "SEND", &send_cmd, 0 },
1286 { "EXPECT", &expect_cmd, 1 },
1287 { "NOEXPECT", &expect_cmd, 0 },
1288 { "!", &spawn_cmd, 0, HLP_SPAWN },
1289 { "HELP", &help_cmd, 0, HLP_HELP },
1290 { NULL, NULL, 0 }
1291 };
1292
1293 static CTAB set_glob_tab[] = {
1294 { "CONSOLE", &sim_set_console, 0 },
1295 { "REMOTE", &sim_set_remote_console, 0 },
1296 { "BREAK", &brk_cmd, SSH_ST },
1297 { "NOBREAK", &brk_cmd, SSH_CL },
1298 { "TELNET", &sim_set_telnet, 0 },
1299 { "NOTELNET", &sim_set_notelnet, 0 },
1300 { "LOG", &sim_set_logon, 0, HLP_SET_LOG },
1301 { "NOLOG", &sim_set_logoff, 0, HLP_SET_LOG },
1302 { "DEBUG", &sim_set_debon, 0, HLP_SET_DEBUG },
1303 { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
1304 { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
1305 { "ON", &set_on, 1, HLP_SET_ON },
1306 { "NOON", &set_on, 0, HLP_SET_ON },
1307 { "VERIFY", &set_verify, 1, HLP_SET_VERIFY },
1308 { "VERBOSE", &set_verify, 1, HLP_SET_VERIFY },
1309 { "NOVERIFY", &set_verify, 0, HLP_SET_VERIFY },
1310 { "NOVERBOSE", &set_verify, 0, HLP_SET_VERIFY },
1311 { "MESSAGE", &set_message, 1, HLP_SET_MESSAGE },
1312 { "NOMESSAGE", &set_message, 0, HLP_SET_MESSAGE },
1313 { "QUIET", &set_quiet, 1, HLP_SET_QUIET },
1314 { "NOQUIET", &set_quiet, 0, HLP_SET_QUIET },
1315 { "LOCALOPC", &set_localopc, 1, HLP_SET_LOCALOPC },
1316 { "NOLOCALOPC", &set_localopc, 0, HLP_SET_LOCALOPC },
1317 { "PROMPT", &set_prompt, 0, HLP_SET_PROMPT },
1318 { NULL, NULL, 0 }
1319 };
1320
1321 static C1TAB set_dev_tab[] = {
1322 { "OCTAL", &set_dev_radix, 8 },
1323 { "DECIMAL", &set_dev_radix, 10 },
1324 { "HEX", &set_dev_radix, 16 },
1325 { "ENABLED", &set_dev_enbdis, 1 },
1326 { "DISABLED", &set_dev_enbdis, 0 },
1327 { "DEBUG", &set_dev_debug, 1 },
1328 { "NODEBUG", &set_dev_debug, 0 },
1329 { NULL, NULL, 0 }
1330 };
1331
1332 static C1TAB set_unit_tab[] = {
1333 { "ENABLED", &set_unit_enbdis, 1 },
1334 { "DISABLED", &set_unit_enbdis, 0 },
1335 { NULL, NULL, 0 }
1336 };
1337
1338 static SHTAB show_glob_tab[] = {
1339 { "CONFIGURATION", &show_config, 0, HLP_SHOW_CONFIG },
1340 { "DEFAULT_BASE_SYSTEM_SCRIPT",
1341 &show_default_base_system_script, 0, HLP_SHOW_DBS },
1342 { "DEVICES", &show_config, 1, HLP_SHOW_DEVICES },
1343 { "FEATURES", &show_config, 2, HLP_SHOW_FEATURES },
1344 { "QUEUE", &show_queue, 0, HLP_SHOW_QUEUE },
1345 { "TIME", &show_time, 0, HLP_SHOW_TIME },
1346 { "MODIFIERS", &show_mod_names, 0, HLP_SHOW_MODIFIERS },
1347 { "NAMES", &show_log_names, 0, HLP_SHOW_NAMES },
1348 { "SHOW", &show_show_commands, 0, HLP_SHOW_SHOW },
1349 { "VERSION", &show_version, 1, HLP_SHOW_VERSION },
1350 { "BUILDINFO", &show_buildinfo, 1, HLP_SHOW_BUILDINFO },
1351 { "PROM", &show_prom, 0, HLP_SHOW_PROM },
1352 { "CONSOLE", &sim_show_console, 0, HLP_SHOW_CONSOLE },
1353 { "REMOTE", &sim_show_remote_console, 0, HLP_SHOW_REMOTE },
1354 { "BREAK", &show_break, 0, HLP_SHOW_BREAK },
1355 { "LOG", &sim_show_log, 0, HLP_SHOW_LOG },
1356 { "TELNET", &sim_show_telnet, 0 },
1357 { "DEBUG", &sim_show_debug, 0, HLP_SHOW_DEBUG },
1358 { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS },
1359 { "SEND", &sim_show_send, 0, HLP_SHOW_SEND },
1360 { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT },
1361 { "ON", &show_on, 0, HLP_SHOW_ON },
1362 { NULL, NULL, 0 }
1363 };
1364
1365 static SHTAB show_dev_tab[] = {
1366 { "RADIX", &show_dev_radix, 0 },
1367 { "DEBUG", &show_dev_debug, 0 },
1368 { "MODIFIERS", &show_dev_modifiers, 0 },
1369 { "NAMES", &show_dev_logicals, 0 },
1370 { "SHOW", &show_dev_show_commands, 0 },
1371 { NULL, NULL, 0 }
1372 };
1373
1374 static SHTAB show_unit_tab[] = {
1375 { NULL, NULL, 0 }
1376 };
1377
1378 #if defined(_WIN32)
1379 static
1380 int setenv(const char *envname, const char *envval, int overwrite)
1381 {
1382 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1383 int r;
1384
1385 (void)sprintf(envstr, "%s=%s", envname, envval);
1386 r = _putenv(envstr);
1387 FREE(envstr);
1388 return r;
1389 }
1390
1391 static
1392 int unsetenv(const char *envname)
1393 {
1394 setenv(envname, "", 1);
1395 return 0;
1396 }
1397 #endif
1398
1399 #if !defined(NO_LOCALE)
1400 # define XSTR_EMAXLEN 32767
1401
1402 const char
1403 *xstrerror_l(int errnum)
1404 {
1405 int saved = errno;
1406 const char *ret = NULL;
1407 static __thread char buf[XSTR_EMAXLEN];
1408
1409 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1410 defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1411 # if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1412 if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf;
1413 # else
1414 if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf;
1415 # endif
1416 # else
1417 # if defined(__NetBSD__)
1418 locale_t loc = LC_GLOBAL_LOCALE;
1419 # else
1420 locale_t loc = uselocale((locale_t)0);
1421 # endif
1422 locale_t copy = loc;
1423 if (copy == LC_GLOBAL_LOCALE)
1424 copy = duplocale(copy);
1425
1426 if (copy != (locale_t)0)
1427 {
1428 ret = strerror_l(errnum, copy);
1429 if (loc == LC_GLOBAL_LOCALE)
1430 {
1431 freelocale(copy);
1432 }
1433 }
1434 # endif
1435
1436 if (!ret)
1437 {
1438 (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1439 ret = buf;
1440 }
1441
1442 errno = saved;
1443 return ret;
1444 }
1445 #else
1446 # define xstrerror_l strerror
1447 #endif
1448
1449 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1450
1451
1452
1453 #if defined(__APPLE__)
1454 int processIsTranslated(void)
1455 {
1456 int ret = 0;
1457 size_t size = sizeof(ret);
1458 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
1459 if (errno == ENOENT)
1460 return 0;
1461 return -1; }
1462 return ret;
1463 }
1464 #endif
1465
1466
1467
1468 char *strremove(char *str, const char *sub)
1469 {
1470 char *p, *q, *r;
1471 if (*sub && (q = r = strstr(str, sub)) != NULL) {
1472 size_t len = strlen(sub);
1473 while ((r = strstr(p = r + len, sub)) != NULL) {
1474 while (p < r)
1475 *q++ = *p++;
1476 }
1477 while ((*q++ = *p++) != '\0')
1478 continue;
1479 }
1480 return str;
1481 }
1482
1483
1484
1485 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
1486 {
1487 while (*str_untrimmed != '\0') {
1488 if(!isspace((unsigned char)*str_untrimmed)) {
1489 *str_trimmed = (char)*str_untrimmed;
1490 str_trimmed++;
1491 }
1492 str_untrimmed++;
1493 }
1494 *str_trimmed = '\0';
1495 }
1496
1497 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1498 void allowCores(void)
1499 {
1500 int ret;
1501 struct rlimit limit;
1502 # if defined(RLIMIT_CORE)
1503 ret = getrlimit(RLIMIT_CORE, &limit);
1504 (void)ret;
1505 # if defined(TESTING)
1506 if (ret != 0)
1507 {
1508 sim_warn ("Failed to query core dump configuration.");
1509 return;
1510 }
1511 # endif
1512 limit.rlim_cur = limit.rlim_max;
1513 ret = setrlimit(RLIMIT_CORE, &limit);
1514 # if defined(TESTING)
1515 if (ret != 0)
1516 {
1517 sim_warn ("Failed to enable unlimited core dumps.");
1518 return;
1519 }
1520 # endif
1521 # else
1522 # if defined(TESTING)
1523 sim_warn ("Unable to query core dump configuration.");
1524 # endif
1525 # endif
1526 return;
1527 }
1528 #endif
1529
1530 #if defined(USE_DUMA)
1531 void CleanDUMA(void)
1532 {
1533 (void)fflush(stdout);
1534 DUMA_CHECKALL();
1535 (void)fflush(stderr);
1536 }
1537 # undef USE_DUMA
1538 # define USE_DUMA 1
1539 #endif
1540
1541 #if !defined(SIG_SETMASK)
1542 # undef USE_BACKTRACE
1543 #endif
1544
1545 #if defined(PERF_STRIP)
1546 # undef USE_BACKTRACE
1547 #endif
1548
1549 #if defined(USE_BACKTRACE)
1550 # include <backtrace.h>
1551 # include <backtrace-supported.h>
1552 # define BACKTRACE_SKIP 1
1553 # define BACKTRACE_MAIN "main"
1554 # undef USE_BACKTRACE
1555 # define USE_BACKTRACE 1
1556 #endif
1557
1558 #if defined(BACKTRACE_SUPPORTED)
1559 # if defined(BACKTRACE_SUPPORTS_THREADS)
1560 # if !(BACKTRACE_SUPPORTED)
1561 # undef USE_BACKTRACE
1562 # endif
1563 # else
1564 # undef USE_BACKTRACE
1565 # endif
1566 #else
1567 # undef USE_BACKTRACE
1568 #endif
1569
1570 #if defined(USE_BACKTRACE)
1571 # if defined(BACKTRACE_SUPPORTED)
1572 # include "backtrace_func.c"
1573 # endif
1574 #endif
1575
1576 #if !defined(__CYGWIN__)
1577 # if !defined(__APPLE__)
1578 # if !defined(_AIX)
1579 # if !defined(__MINGW32__)
1580 # if !defined(__MINGW64__)
1581 # if !defined(CROSS_MINGW32)
1582 # if !defined(CROSS_MINGW64)
1583 # if !defined(_WIN32)
1584 # if !defined(__HAIKU__)
1585 # if !defined(__QNX__)
1586 static int
1587 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
1588 {
1589 (void)size;
1590 (void)data;
1591
1592 if (strlen(info->dlpi_name) >= 2) {
1593 if (!dl_iterate_phdr_callback_called)
1594 (void)printf ("\r\n Loaded shared objects: ");
1595
1596 dl_iterate_phdr_callback_called++;
1597 (void)printf ("%s ", info->dlpi_name);
1598 }
1599
1600 return 0;
1601 }
1602 # endif
1603 # endif
1604 # endif
1605 # endif
1606 # endif
1607 # endif
1608 # endif
1609 # endif
1610 # endif
1611 #endif
1612
1613 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1614 # if defined(_UCRT)
1615 # define MINGW_CRT "UCRT"
1616 # else
1617 # define MINGW_CRT "MSVCRT"
1618 # endif
1619 #endif
1620
1621 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1622 struct UCRTVersion
1623 {
1624 uint16_t ProductVersion[4];
1625 };
1626
1627 int
1628 GetUCRTVersion (struct UCRTVersion *ucrtversion)
1629 {
1630 # ifdef _DEBUG
1631 static const wchar_t *DllName = L"ucrtbased.dll";
1632 # else
1633 static const wchar_t *DllName = L"ucrtbase.dll";
1634 # endif
1635
1636 HMODULE ucrt = GetModuleHandleW (DllName);
1637 if (!ucrt)
1638 return GetLastError ();
1639
1640 wchar_t path[MAX_PATH];
1641 if (!GetModuleFileNameW (ucrt, path, MAX_PATH))
1642 return GetLastError ();
1643
1644 DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1645 if (!versionInfoSize)
1646 return GetLastError ();
1647
1648 uint8_t versionInfo[versionInfoSize];
1649
1650 if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1651 return GetLastError ();
1652
1653 VS_FIXEDFILEINFO *fixedFileInfo;
1654 UINT fixedFileInfoSize;
1655 if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1656 return GetLastError ();
1657
1658 memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1659
1660 return 0;
1661 }
1662 #endif
1663
1664
1665
1666 #if !defined(PERF_STRIP)
1667 static int dps8_sir_report_error(void)
1668 {
1669 char message[SIR_MAXERROR] = {0};
1670 (void)sir_geterror(message);
1671 (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1672 return EXIT_FAILURE;
1673 }
1674
1675
1676
1677 int main (int argc, char *argv[])
1678 {
1679 char *cptr, *cptr2;
1680 char nbuf[PATH_MAX + 7];
1681 char cbuf[4*CBUFSIZE];
1682 char **targv = NULL;
1683 int32 i, sw;
1684 t_bool lookswitch;
1685 t_stat stat;
1686
1687 # if defined(_AIX)
1688 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1689 if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1690 (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1691 __func__, __FILE__, __LINE__);
1692 abort();
1693 }
1694
1695 if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1696 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1697 }
1698
1699 if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1700 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1701 }
1702
1703 if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1704 (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1705 }
1706
1707 # if !defined(__PASE__)
1708 if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1709 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1710 }
1711 # endif
1712
1713 if (execvp(argv[0], argv) == -1) {
1714 (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1715 __func__, __FILE__, __LINE__);
1716 abort();
1717 }
1718 }
1719 # endif
1720
1721 # if defined(USE_BACKTRACE)
1722 # if defined(BACKTRACE_SUPPORTED)
1723 # if defined(_INC_BACKTRACE_FUNC)
1724 bt_pid = (long)getpid();
1725 (void)bt_pid;
1726 # endif
1727 # endif
1728 # endif
1729
1730 # if defined(__MINGW32__)
1731 # undef IS_WINDOWS
1732 # define IS_WINDOWS 1
1733 # if !defined(NEED_CONSOLE_SETUP)
1734 # define NEED_CONSOLE_SETUP
1735 # endif
1736 # endif
1737
1738 # if defined(CROSS_MINGW32)
1739 # undef IS_WINDOWS
1740 # define IS_WINDOWS 1
1741 # if !defined(NEED_CONSOLE_SETUP)
1742 # define NEED_CONSOLE_SETUP
1743 # endif
1744 # endif
1745
1746 # if defined(__MINGW64__)
1747 # undef IS_WINDOWS
1748 # define IS_WINDOWS 1
1749 # if !defined(NEED_CONSOLE_SETUP)
1750 # define NEED_CONSOLE_SETUP
1751 # endif
1752 # endif
1753
1754 # if defined(CROSS_MINGW64)
1755 # undef IS_WINDOWS
1756 # define IS_WINDOWS 1
1757 # if !defined(NEED_CONSOLE_SETUP)
1758 # define NEED_CONSOLE_SETUP
1759 # endif
1760 # endif
1761
1762 # if defined(__CYGWIN__)
1763 # if defined(IS_WINDOWS)
1764 # undef IS_WINDOWS
1765 # endif
1766 # endif
1767
1768 # if defined(USE_DUMA)
1769 # if defined(DUMA_EXPLICIT_INIT)
1770 duma_init();
1771 (void)fflush(stderr);
1772 # endif
1773 # if defined(DUMA_MIN_ALIGNMENT)
1774 # if DUMA_MIN_ALIGNMENT > 0
1775 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1776 # endif
1777 # endif
1778 DUMA_SET_FILL(0x2E);
1779 (void)fflush(stderr);
1780 (void)atexit(CleanDUMA);
1781 # endif
1782
1783 # if defined(USE_BACKTRACE)
1784 # if defined(BACKTRACE_SUPPORTED)
1785 # include "backtrace_main.c"
1786 # endif
1787 # endif
1788
1789 # if !defined(NO_LOCALE)
1790 (void)setlocale(LC_ALL, "");
1791 # endif
1792
1793 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1794 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1795 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1796 # endif
1797 # endif
1798
1799 # if defined(NEED_CONSOLE_SETUP)
1800 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1801 if (handle != INVALID_HANDLE_VALUE)
1802 {
1803 DWORD mode = 0;
1804 if (GetConsoleMode(handle, &mode))
1805 {
1806 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1807 SetConsoleMode(handle, mode);
1808 }
1809 }
1810 puts ("\e[0m");
1811 # endif
1812
1813 # if defined(__HAIKU__)
1814 (void)disable_debugger(1);
1815 # endif
1816
1817
1818
1819 sirinit si;
1820 if (!sir_makeinit(&si))
1821 return dps8_sir_report_error();
1822
1823
1824 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1825
1826
1827 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1828
1829
1830 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1831
1832
1833 si.d_stderr.opts = SIRO_NOHOST;
1834
1835
1836 si.d_syslog.levels = SIRL_NONE;
1837
1838
1839 si.d_syslog.opts = SIRO_DEFAULT;
1840
1841
1842 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1843
1844
1845 if (!sir_init(&si))
1846 return dps8_sir_report_error();
1847
1848
1849 char thread_name[SIR_MAXPID] = {0};
1850 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1851 (void)_sir_setthreadname(thread_name);
1852
1853
1854
1855 # if defined(__clang_analyzer__)
1856 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\n");
1857 return 1;
1858 # endif
1859
1860 if (argc == 0) {
1861 (void)fprintf (stderr, "Error: main() called directly!\n");
1862 return 1;
1863 }
1864
1865
1866 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1867 allowCores();
1868 # endif
1869
1870 int testEndian = decContextTestEndian();
1871 if (testEndian != 0) {
1872 if (testEndian == 1) {
1873 (void)fprintf (stderr,
1874 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\n");
1875 return 1;
1876 }
1877 if (testEndian == -1) {
1878 (void)fprintf (stderr,
1879 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\n");
1880 return 1;
1881 }
1882 (void)fprintf (stderr,
1883 "Error: Unable to determine system byte order; aborting.\n");
1884 return 1;
1885 }
1886 # if defined(NEED_128)
1887 test_math128();
1888 # endif
1889
1890 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1891
1892 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1893
1894
1895
1896
1897 nprocs = (unsigned int)uv_available_parallelism();
1898 # else
1899 nprocs = (unsigned int)_sir_nprocs();
1900 # endif
1901
1902
1903 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1904 if (!targv)
1905 {
1906 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1907 __func__, __FILE__, __LINE__);
1908 # if defined(USE_BACKTRACE)
1909 # if defined(SIGUSR2)
1910 (void)raise(SIGUSR2);
1911
1912 # endif
1913 # endif
1914 abort();
1915 }
1916 for (i=0; i<argc; i++)
1917 targv[i] = argv[i];
1918 argv = targv;
1919
1920
1921 set_prompt (0, "sim>");
1922 *cbuf = 0;
1923 sim_switches = 0;
1924 lookswitch = TRUE;
1925 stdnul = fopen(NULL_DEVICE,"wb");
1926
1927
1928 for (i = 1; i < argc; i++) {
1929 if (argv[i] == NULL)
1930 continue;
1931
1932 # if defined(THREADZ) || defined(LOCKLESS)
1933
1934 int perftestflag = strcmp(argv[i], "--perftest");
1935 if (perftestflag == 0) {
1936 char * testName = NULL;
1937 if (i + 1 < argc)
1938 testName = argv[i + 1];
1939 perfTest (testName);
1940 return 0;
1941 }
1942 # endif
1943
1944
1945 int onlyvers = strcmp(argv[i], "--version");
1946 if (onlyvers == 0) {
1947 # if defined(VER_H_GIT_VERSION)
1948 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1949 # if VER_H_GIT_PATCH_INT < 1
1950 (void)fprintf (stdout, "%s simulator %s\n",
1951 sim_name, VER_H_GIT_VERSION);
1952 # else
1953 (void)fprintf (stdout, "%s simulator %s+%s\n",
1954 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1955 # endif
1956 # else
1957 (void)fprintf (stdout, "%s simulator %s\n",
1958 sim_name, VER_H_GIT_VERSION);
1959 # endif
1960 # else
1961 (void)fprintf (stdout, "%s simulator\n", sim_name);
1962 # endif
1963 FREE (targv);
1964 return 0;
1965 }
1966
1967
1968 int longhelp = strcmp(argv[i], "--help");
1969 int shorthelp = strcmp(argv[i], "-h");
1970 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
1971 if (longhelp == 0 || shorthelp == 0) {
1972 # if defined(VER_H_GIT_VERSION)
1973 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1974 # if VER_H_GIT_PATCH_INT < 1
1975 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1976 # else
1977 (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1978 # endif
1979 # else
1980 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1981 # endif
1982 # else
1983 (void)fprintf (stdout, "%s simulator", sim_name);
1984 # endif
1985 (void)fprintf (stdout, "\n");
1986 (void)fprintf (stdout, "\n USAGE: %s { [ SWITCHES ] ... } { < SCRIPT > }", argv[0]);
1987 (void)fprintf (stdout, "\n");
1988 (void)fprintf (stdout, "\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
1989 (void)fprintf (stdout, "\n");
1990 (void)fprintf (stdout, "\n Switches:");
1991 (void)fprintf (stdout, "\n -e, -E Aborts script processing immediately upon any error");
1992 (void)fprintf (stdout, "\n -h, -H, --help Prints only this informational help text and exit");
1993 (void)fprintf (stdout, "\n -k, -K Disables all support for exclusive file locking");
1994 (void)fprintf (stdout, "\n -l, -L Reports but ignores all exclusive file locking errors");
1995 (void)fprintf (stdout, "\n -o, -O Makes scripting ON conditions and actions inheritable");
1996 (void)fprintf (stdout, "\n -q, -Q Disables printing of non-fatal informational messages");
1997 (void)fprintf (stdout, "\n -r, -R Enables an unlinked ephemeral system state file");
1998 (void)fprintf (stdout, "\n -s, -S Enables a randomized persistent system state file");
1999 (void)fprintf (stdout, "\n -t, -T Disables fsync and creation/usage of system state file");
2000 (void)fprintf (stdout, "\n -v, -V Prints commands read from script file before execution");
2001 (void)fprintf (stdout, "\n --version Prints only the simulator identification text and exit");
2002 (void)fprintf (stdout, "\n");
2003 # if defined(USE_DUMA)
2004 nodist++;
2005 # endif
2006 if (!nodist) {
2007 (void)fprintf (stdout, "\n This software is made available under the terms of the ICU License.");
2008 (void)fprintf (stdout, "\n For complete license details, see the LICENSE file included with the");
2009 (void)fprintf (stdout, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\n");
2010 }
2011 else
2012 {
2013 (void)fprintf (stdout, "\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2014 }
2015 (void)fprintf (stdout, "\n");
2016 FREE(argv);
2017 return 0;
2018 }
2019
2020 if ((*argv[i] == '-') && lookswitch) {
2021 if ((sw = get_switches (argv[i])) < 0) {
2022 (void)fprintf (stderr, "Invalid switch \"%s\".\nTry \"%s -h\" for help.\n", argv[i], argv[0]);
2023 FREE(argv);
2024 return 1;
2025 }
2026 sim_switches = sim_switches | sw;
2027 }
2028
2029 else {
2030 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2031 (void)fprintf (stderr, "Argument string too long\n");
2032 FREE(argv);
2033 return 1;
2034 }
2035 if (*cbuf)
2036 strcat (cbuf, " ");
2037 (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s",
2038 strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
2039 lookswitch = FALSE;
2040 }
2041 }
2042 sim_nolock = sim_switches & SWMASK ('K');
2043 sim_iglock = sim_switches & SWMASK ('L');
2044 sim_randompst = sim_switches & SWMASK ('S');
2045 sim_quiet = sim_switches & SWMASK ('Q');
2046 sim_randstate = sim_switches & SWMASK ('R');
2047 if (sim_randompst) sim_randstate = 1;
2048 sim_nostate = sim_switches & SWMASK ('T');
2049 if (sim_nostate)
2050 {
2051 sim_randompst = 0;
2052 sim_randstate = 0;
2053 }
2054 sim_on_inherit = sim_switches & SWMASK ('O');
2055
2056 sim_init_sock ();
2057 if (sim_dflt_dev == NULL)
2058 sim_dflt_dev = sim_devices[0];
2059 if (sim_vm_init != NULL)
2060 (*sim_vm_init)();
2061 sim_finit ();
2062 for (i = 0; cmd_table[i].name; i++) {
2063 size_t alias_len = strlen (cmd_table[i].name);
2064 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2065 if (!cmd_name)
2066 {
2067 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2068 __func__, __FILE__, __LINE__);
2069 # if defined(USE_BACKTRACE)
2070 # if defined(SIGUSR2)
2071 (void)raise(SIGUSR2);
2072
2073 # endif
2074 # endif
2075 abort();
2076 }
2077
2078 strcpy (cmd_name, cmd_table[i].name);
2079 while (alias_len > 1) {
2080 cmd_name[alias_len] = '\0';
2081 --alias_len;
2082 if (getenv (cmd_name))
2083 unsetenv (cmd_name);
2084 }
2085 FREE (cmd_name);
2086 }
2087 stop_cpu = 0;
2088 sim_interval = 0;
2089 sim_time = sim_rtime = 0;
2090 noqueue_time = 0;
2091 sim_clock_queue = QUEUE_LIST_END;
2092 sim_is_running = 0;
2093 sim_log = NULL;
2094 if (sim_emax <= 0)
2095 sim_emax = 1;
2096 sim_timer_init ();
2097
2098 if ((stat = sim_ttinit ()) != SCPE_OK) {
2099 (void)fprintf (stderr, "Fatal terminal initialization error\n%s\n",
2100 sim_error_text (stat));
2101 FREE(argv);
2102 return 1;
2103 }
2104 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2105 (void)fprintf (stderr, "Unable to allocate examine buffer\n");
2106 FREE(argv);
2107 return 1;
2108 };
2109 if ((stat = reset_all_p (0)) != SCPE_OK) {
2110 (void)fprintf (stderr, "Fatal simulator initialization error\n%s\n",
2111 sim_error_text (stat));
2112 FREE(argv);
2113 return 1;
2114 }
2115 if ((stat = sim_brk_init ()) != SCPE_OK) {
2116 (void)fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",
2117 sim_error_text (stat));
2118 FREE(argv);
2119 return 1;
2120 }
2121 if (!sim_quiet) {
2122 (void)printf ("\n");
2123 show_version (stdout, NULL, NULL, 0, NULL);
2124 }
2125
2126 cptr = getenv("HOME");
2127 if (cptr == NULL) {
2128 cptr = getenv("HOMEPATH");
2129 cptr2 = getenv("HOMEDRIVE");
2130 }
2131 else
2132 cptr2 = NULL;
2133 (void)cptr2;
2134 if ( (*cbuf) && (strcmp(cbuf, "")) )
2135 stat = do_cmd (0, cbuf);
2136 else if (*argv[0]) {
2137 char *np;
2138 nbuf[0] = '"';
2139 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
2140 if (stat == SCPE_OPENERR) {
2141 np = strrchr (nbuf, '/');
2142 if (np == NULL)
2143 np = strrchr (nbuf, '\\');
2144 if (np != NULL) {
2145 *np = '"';
2146 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
2147 }
2148 }
2149 }
2150
2151 argv = uv_setup_args(argc, argv);
2152
2153 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2154
2155 if (sim_vm_exit != NULL)
2156 (*sim_vm_exit)();
2157
2158 detach_all (0, TRUE);
2159 sim_set_deboff (0, NULL);
2160 sim_set_logoff (0, NULL);
2161 sim_set_notelnet (0, NULL);
2162 sim_ttclose ();
2163 sim_cleanup_sock ();
2164 fclose (stdnul);
2165 FREE (targv);
2166 FREE (sim_prompt);
2167 FREE (sim_eval);
2168 FREE (sim_internal_devices);
2169 FREE (sim_brk_tab);
2170 FREE (sim_staba.comp);
2171 FREE (sim_staba.mask);
2172 FREE (sim_stabr.comp);
2173 FREE (sim_stabr.mask);
2174 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2175 }
2176 #endif
2177
2178 t_stat process_stdin_commands (t_stat stat, char *argv[])
2179 {
2180 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2181 CONST char *cptr;
2182 t_stat stat_nomessage;
2183 CTAB *cmdp = NULL;
2184
2185 stat = SCPE_BARE_STATUS(stat);
2186 while (stat != SCPE_EXIT) {
2187 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
2188 (void)printf ("%s%s\n", sim_prompt, cptr);
2189 else if (sim_vm_read != NULL) {
2190 (void)printf ("%s", sim_prompt);
2191 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2192 }
2193 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
2194 if (cptr == NULL) {
2195 if (sim_ttisatty()) continue;
2196 else break;
2197 }
2198 if (*cptr == 0)
2199 continue;
2200 sim_sub_args (cbuf, sizeof(cbuf), argv);
2201 if (sim_log)
2202 (void)fprintf (sim_log, "%s%s\n", sim_prompt, cptr);
2203 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2204 (void)fprintf (sim_deb, "%s%s\n", sim_prompt, cptr);
2205 cptr = get_glyph_cmd (cptr, gbuf);
2206 sim_switches = 0;
2207 if ((cmdp = find_cmd (gbuf)))
2208 stat = cmdp->action (cmdp->arg, cptr);
2209 else
2210 stat = SCPE_UNK;
2211 stat_nomessage = stat & SCPE_NOMESSAGE;
2212 stat_nomessage = stat_nomessage || (!sim_show_message);
2213 stat = SCPE_BARE_STATUS(stat);
2214 sim_last_cmd_stat = stat;
2215 if (!stat_nomessage) {
2216 if (cmdp && (cmdp->message))
2217 cmdp->message (NULL, stat);
2218 else
2219 if (stat >= SCPE_BASE)
2220 sim_printf ("%s\n", sim_error_text (stat));
2221 }
2222 if (sim_vm_post != NULL)
2223 (*sim_vm_post) (TRUE);
2224 }
2225 return stat;
2226 }
2227
2228
2229
2230 t_stat set_prompt (int32 flag, CONST char *cptr)
2231 {
2232 char gbuf[CBUFSIZE], *gptr;
2233
2234 if ((NULL == cptr) || (*cptr == '\0'))
2235 return SCPE_ARG;
2236
2237 cptr = get_glyph_nc (cptr, gbuf, '"');
2238 if (gbuf[0] == '\0') {
2239 gbuf[sizeof (gbuf)-1] = '\0';
2240 strncpy (gbuf, cptr, sizeof (gbuf)-1);
2241 gptr = strchr (gbuf, '"');
2242 if (NULL != gptr)
2243 *gptr = '\0';
2244 }
2245 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
2246 if (!sim_prompt)
2247 {
2248 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2249 __func__, __FILE__, __LINE__);
2250 #if defined(USE_BACKTRACE)
2251 # if defined(SIGUSR2)
2252 (void)raise(SIGUSR2);
2253
2254 # endif
2255 #endif
2256 abort();
2257 }
2258 (void)sprintf (sim_prompt, "%s ", gbuf);
2259 return SCPE_OK;
2260 }
2261
2262
2263
2264 CTAB *find_cmd (const char *gbuf)
2265 {
2266 CTAB *cmdp = NULL;
2267
2268 if (sim_vm_cmd)
2269 cmdp = find_ctab (sim_vm_cmd, gbuf);
2270 if (cmdp == NULL)
2271 cmdp = find_ctab (cmd_table, gbuf);
2272 return cmdp;
2273 }
2274
2275
2276
2277 t_stat exit_cmd (int32 flag, CONST char *cptr)
2278 {
2279 return SCPE_EXIT;
2280 }
2281
2282
2283
2284
2285 static int _cmd_name_compare (const void *pa, const void *pb)
2286 {
2287 CTAB * const *a = (CTAB * const *)pa;
2288 CTAB * const *b = (CTAB * const *)pb;
2289
2290 return strcmp((*a)->name, (*b)->name);
2291 }
2292
2293 void fprint_help (FILE *st)
2294 {
2295 CTAB *cmdp;
2296 CTAB **hlp_cmdp = NULL;
2297 size_t cmd_cnt = 0;
2298 size_t cmd_size = 0;
2299 size_t max_cmdname_size = 0;
2300 size_t i, line_offset;
2301
2302 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2303 if (cmdp->help) {
2304 if (cmd_cnt >= cmd_size) {
2305 cmd_size += 20;
2306 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2307 if (!hlp_cmdp)
2308 {
2309 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2310 __func__, __FILE__, __LINE__);
2311 #if defined(USE_BACKTRACE)
2312 # if defined(SIGUSR2)
2313 (void)raise(SIGUSR2);
2314
2315 # endif
2316 #endif
2317 abort();
2318 }
2319 }
2320 hlp_cmdp[cmd_cnt] = cmdp;
2321 ++cmd_cnt;
2322 if (strlen(cmdp->name) > max_cmdname_size)
2323 max_cmdname_size = strlen(cmdp->name);
2324 }
2325 }
2326 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2327 if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2328 if (cmd_cnt >= cmd_size) {
2329 cmd_size += 20;
2330 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2331 if (!hlp_cmdp)
2332 {
2333 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2334 __func__, __FILE__, __LINE__);
2335 #if defined(USE_BACKTRACE)
2336 # if defined(SIGUSR2)
2337 (void)raise(SIGUSR2);
2338
2339 # endif
2340 #endif
2341 abort();
2342 }
2343 }
2344 hlp_cmdp[cmd_cnt] = cmdp;
2345 ++cmd_cnt;
2346 if (strlen (cmdp->name) > max_cmdname_size)
2347 max_cmdname_size = strlen(cmdp->name);
2348 }
2349 }
2350 (void)fprintf (st, "HELP is available for the following commands:\n\n ");
2351 if (hlp_cmdp)
2352 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2353 line_offset = 4;
2354 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2355 fputs (hlp_cmdp[i]->name, st);
2356 line_offset += 5 + max_cmdname_size;
2357 if (line_offset + max_cmdname_size > 79) {
2358 line_offset = 4;
2359 (void)fprintf (st, "\n ");
2360 }
2361 else
2362 (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2363 }
2364 FREE (hlp_cmdp);
2365 (void)fprintf (st, "\n");
2366 return;
2367 }
2368
2369 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2370 {
2371 if (!*pdone)
2372 (void)fprintf (st, "%s", context);
2373 *pdone = TRUE;
2374 }
2375
2376 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2377 {
2378 REG *rptr, *trptr;
2379 t_bool found = FALSE;
2380 t_bool all_unique = TRUE;
2381 size_t max_namelen = 0;
2382 DEVICE *tdptr;
2383 CONST char *tptr;
2384 char *namebuf;
2385 char rangebuf[32];
2386
2387 if (dptr->registers)
2388 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2389 if (rptr->flags & REG_HIDDEN)
2390 continue;
2391 if (rptr->depth > 1)
2392 (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2393 else
2394 strcpy (rangebuf, "");
2395 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2396 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2397 found = TRUE;
2398 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2399 if ((trptr == NULL) || (tdptr != dptr))
2400 all_unique = FALSE;
2401 }
2402 if (!found) {
2403 if (!silent)
2404 (void)fprintf (st, "No register HELP available for the %s device\n",
2405 dptr->name);
2406 }
2407 else {
2408 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2409 if (!namebuf)
2410 {
2411 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2412 __func__, __FILE__, __LINE__);
2413 #if defined(USE_BACKTRACE)
2414 # if defined(SIGUSR2)
2415 (void)raise(SIGUSR2);
2416
2417 # endif
2418 #endif
2419 abort();
2420 }
2421 (void)fprintf (st, "\nThe %s device implements these registers:\n\n",
2422 dptr->name);
2423 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2424 if (rptr->flags & REG_HIDDEN)
2425 continue;
2426 if (rptr->depth <= 1)
2427 (void)sprintf (namebuf, "%*s",
2428 -((int)max_namelen),
2429 rptr->name);
2430 else {
2431 (void)sprintf (rangebuf, "[%d:%d]",
2432 0,
2433 rptr->depth-1);
2434 (void)sprintf (namebuf, "%s%*s",
2435 rptr->name,
2436 (int)(strlen(rptr->name))-((int)max_namelen),
2437 rangebuf);
2438 }
2439 if (all_unique) {
2440 (void)fprintf (st, " %s %4d %s\n",
2441 namebuf,
2442 rptr->width,
2443 rptr->desc ? rptr->desc : "");
2444 continue;
2445 }
2446 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2447 if ((trptr == NULL) || (tdptr != dptr))
2448 (void)fprintf (st, " %s %s %4d %s\n",
2449 dptr->name,
2450 namebuf,
2451 rptr->width,
2452 rptr->desc ? rptr->desc : "");
2453 else
2454 (void)fprintf (st, " %*s %s %4d %s\n",
2455 (int)strlen(dptr->name), "",
2456 namebuf,
2457 rptr->width,
2458 rptr->desc ? rptr->desc : "");
2459 }
2460 FREE (namebuf);
2461 }
2462 }
2463
2464 void fprint_reg_help (FILE *st, DEVICE *dptr)
2465 {
2466 fprint_reg_help_ex (st, dptr, TRUE);
2467 }
2468
2469 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2470 {
2471 if (dptr->attach_help) {
2472 (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2473 dptr->attach_help (st, dptr, NULL, 0, NULL);
2474 return;
2475 }
2476 if (DEV_TYPE(dptr) == DEV_DISK) {
2477 (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2478 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2479 return;
2480 }
2481 if (DEV_TYPE(dptr) == DEV_TAPE) {
2482 (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2483 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2484 return;
2485 }
2486 if (!silent) {
2487 (void)fprintf (st, "No ATTACH help is available for the %s device\n", dptr->name);
2488 if (dptr->help)
2489 dptr->help (st, dptr, NULL, 0, NULL);
2490 }
2491 }
2492
2493 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2494 {
2495 MTAB *mptr;
2496 DEBTAB *dep;
2497 t_bool found = FALSE;
2498 char buf[CBUFSIZE], header[CBUFSIZE];
2499 uint32 enabled_units = dptr->numunits;
2500 uint32 unit;
2501
2502 (void)sprintf (header, "\n%s device SET commands:\n\n", dptr->name);
2503 for (unit=0; unit < dptr->numunits; unit++)
2504 if (dptr->units[unit].flags & UNIT_DIS)
2505 --enabled_units;
2506 if (dptr->modifiers) {
2507 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2508 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2509 continue;
2510 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2511 continue;
2512 if (mptr->mstring) {
2513 fprint_header (st, &found, header);
2514 (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2515 mptr->mstring,
2516 (strchr(mptr->mstring, '=')) \
2517 ? "" : (MODMASK(mptr,MTAB_VALR) \
2518 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2519 ? "{=val}" : "")));
2520 if ((strlen (buf) < 30) || (NULL == mptr->help))
2521 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2522 else
2523 (void)fprintf (st, "%s\n%-30s\t%s\n", buf, "", mptr->help);
2524 }
2525 }
2526 }
2527 if (dptr->flags & DEV_DISABLE) {
2528 fprint_header (st, &found, header);
2529 (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2530 (void)fprintf (st, "%-30s\tEnables device %s\n", buf, sim_dname (dptr));
2531 (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2532 (void)fprintf (st, "%-30s\tDisables device %s\n", buf, sim_dname (dptr));
2533 }
2534 if (dptr->flags & DEV_DEBUG) {
2535 fprint_header (st, &found, header);
2536 (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2537 (void)fprintf (st, "%-30s\tEnables debugging for device %s\n", buf, sim_dname (dptr));
2538 (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2539 (void)fprintf (st, "%-30s\tDisables debugging for device %s\n", buf, sim_dname (dptr));
2540 if (dptr->debflags) {
2541 t_bool desc_available = FALSE;
2542 strcpy (buf, "");
2543 (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2544 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2545 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2546 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2547 }
2548 (void)fprintf (st, "\n");
2549 (void)fprintf (st, "%-30s\tEnables specific debugging for device %s\n", buf, sim_dname (dptr));
2550 (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2551 for (dep = dptr->debflags; dep->name != NULL; dep++)
2552 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2553 (void)fprintf (st, "\n");
2554 (void)fprintf (st, "%-30s\tDisables specific debugging for device %s\n", buf, sim_dname (dptr));
2555 if (desc_available) {
2556 (void)fprintf (st, "\n*%s device DEBUG settings:\n", sim_dname (dptr));
2557 for (dep = dptr->debflags; dep->name != NULL; dep++)
2558 (void)fprintf (st, "%4s%-12s%s\n", "", dep->name, dep->desc ? dep->desc : "");
2559 }
2560 }
2561 }
2562 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2563 if (dptr->units->flags & UNIT_DISABLE) {
2564 fprint_header (st, &found, header);
2565 (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2566 (void)fprintf (st, "%-30s\tEnables unit %sn\n", buf, sim_dname (dptr));
2567 (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2568 (void)fprintf (st, "%-30s\tDisables unit %sn\n", buf, sim_dname (dptr));
2569 }
2570 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2571 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2572 continue;
2573 if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2574 continue;
2575 if (mptr->mstring) {
2576 fprint_header (st, &found, header);
2577 (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2578 (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2579 (strchr(mptr->mstring, '=')) \
2580 ? "" : (MODMASK(mptr,MTAB_VALR) \
2581 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2582 ? "{=val}" : "")));
2583 (void)fprintf (st, "%-30s\t%s\n", buf,
2584 (strchr(mptr->mstring, '=')) \
2585 ? "" : (mptr->help ? mptr->help : ""));
2586 }
2587 }
2588 }
2589 if (!found && !silent)
2590 (void)fprintf (st, "No SET help is available for the %s device\n", dptr->name);
2591 }
2592
2593 void fprint_set_help (FILE *st, DEVICE *dptr)
2594 {
2595 fprint_set_help_ex (st, dptr, TRUE);
2596 }
2597
2598 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2599 {
2600 MTAB *mptr;
2601 t_bool found = FALSE;
2602 char buf[CBUFSIZE], header[CBUFSIZE];
2603 uint32 enabled_units = dptr->numunits;
2604 uint32 unit;
2605
2606 (void)sprintf (header, "\n%s device SHOW commands:\n\n", dptr->name);
2607 for (unit=0; unit < dptr->numunits; unit++)
2608 if (dptr->units[unit].flags & UNIT_DIS)
2609 --enabled_units;
2610 if (dptr->modifiers) {
2611 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2612 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2613 continue;
2614 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2615 continue;
2616 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2617 continue;
2618 fprint_header (st, &found, header);
2619 (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2620 mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2621 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2622 }
2623 }
2624 if (dptr->flags & DEV_DEBUG) {
2625 fprint_header (st, &found, header);
2626 (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2627 (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\n", buf, sim_dname (dptr));
2628 }
2629 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2630 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2631 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2632 continue;
2633 if ((!mptr->disp) || (!mptr->pstring))
2634 continue;
2635 fprint_header (st, &found, header);
2636 (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2637 (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2638 MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2639 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2640 }
2641 }
2642 if (!found && !silent)
2643 (void)fprintf (st, "No SHOW help is available for the %s device\n", dptr->name);
2644 }
2645
2646 void fprint_show_help (FILE *st, DEVICE *dptr)
2647 {
2648 fprint_show_help_ex (st, dptr, TRUE);
2649 }
2650
2651 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2652 {
2653 BRKTYPTAB *brkt = dptr->brk_types;
2654 char gbuf[CBUFSIZE];
2655
2656 if (sim_brk_types == 0) {
2657 if ((dptr != sim_dflt_dev) && (!silent)) {
2658 (void)fprintf (st, "Breakpoints are not supported in the %s simulator\n", sim_name);
2659 if (dptr->help)
2660 dptr->help (st, dptr, NULL, 0, NULL);
2661 }
2662 return;
2663 }
2664 if (brkt == NULL) {
2665 int i;
2666
2667 if (dptr == sim_dflt_dev) {
2668 if (sim_brk_types & ~sim_brk_dflt) {
2669 (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2670 for (i=0; i<26; i++) {
2671 if (sim_brk_types & (1<<i))
2672 (void)fprintf (st, " -%c\n", 'A'+i);
2673 }
2674 }
2675 (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2676 }
2677 return;
2678 }
2679 (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2680 while (brkt->btyp) {
2681 (void)fprintf (st, " %s %s\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2682 ++brkt;
2683 }
2684 (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2685 }
2686
2687 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2688 {
2689 char gbuf[CBUFSIZE];
2690 CTAB *cmdp;
2691
2692 if (*cptr) {
2693 (void)get_glyph (cptr, gbuf, 0);
2694 if ((cmdp = find_cmd (gbuf))) {
2695 if (cmdp->action == &exdep_cmd) {
2696 if (dptr->help)
2697 return dptr->help (st, dptr, uptr, flag, cptr);
2698 else
2699 (void)fprintf (st, "No HELP available for the %s %s command\n", cmdp->name, sim_dname(dptr));
2700 return SCPE_OK;
2701 }
2702 if (cmdp->action == &set_cmd) {
2703 fprint_set_help_ex (st, dptr, FALSE);
2704 return SCPE_OK;
2705 }
2706 if (cmdp->action == &show_cmd) {
2707 fprint_show_help_ex (st, dptr, FALSE);
2708 return SCPE_OK;
2709 }
2710 if (cmdp->action == &attach_cmd) {
2711 fprint_attach_help_ex (st, dptr, FALSE);
2712 return SCPE_OK;
2713 }
2714 if (cmdp->action == &brk_cmd) {
2715 fprint_brk_help_ex (st, dptr, FALSE);
2716 return SCPE_OK;
2717 }
2718 if (dptr->help)
2719 return dptr->help (st, dptr, uptr, flag, cptr);
2720 (void)fprintf (st, "No %s HELP is available for the %s device\n", cmdp->name, dptr->name);
2721 return SCPE_OK;
2722 }
2723 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2724 fprint_reg_help_ex (st, dptr, FALSE);
2725 return SCPE_OK;
2726 }
2727 if (dptr->help)
2728 return dptr->help (st, dptr, uptr, flag, cptr);
2729 (void)fprintf (st, "No %s HELP is available for the %s device\n", gbuf, dptr->name);
2730 return SCPE_OK;
2731 }
2732 if (dptr->help) {
2733 return dptr->help (st, dptr, uptr, flag, cptr);
2734 }
2735 if (dptr->description)
2736 (void)fprintf (st, "%s %s HELP\n", dptr->description (dptr), dptr->name);
2737 else
2738 (void)fprintf (st, "%s HELP\n", dptr->name);
2739 fprint_set_help_ex (st, dptr, TRUE);
2740 fprint_show_help_ex (st, dptr, TRUE);
2741 fprint_attach_help_ex (st, dptr, TRUE);
2742 fprint_reg_help_ex (st, dptr, TRUE);
2743 fprint_brk_help_ex (st, dptr, TRUE);
2744 return SCPE_OK;
2745 }
2746
2747 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2748 {
2749 switch (help[0]) {
2750 case '*':
2751 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2752 if (sim_log)
2753 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2754 break;
2755 default:
2756 fputs (help, stdout);
2757 if (sim_log)
2758 fputs (help, sim_log);
2759 break;
2760 }
2761 return SCPE_OK;
2762 }
2763
2764 t_stat help_cmd (int32 flag, CONST char *cptr)
2765 {
2766 char gbuf[CBUFSIZE];
2767 CTAB *cmdp;
2768
2769 GET_SWITCHES (cptr);
2770 if (sim_switches & SWMASK ('F'))
2771 flag = flag | SCP_HELP_FLAT;
2772 if (*cptr) {
2773 cptr = get_glyph (cptr, gbuf, 0);
2774 if ((cmdp = find_cmd (gbuf))) {
2775 if (*cptr) {
2776 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2777 DEVICE *dptr;
2778 UNIT *uptr;
2779 t_stat r;
2780 cptr = get_glyph (cptr, gbuf, 0);
2781 dptr = find_unit (gbuf, &uptr);
2782 if (dptr == NULL)
2783 dptr = find_dev (gbuf);
2784 if (dptr != NULL) {
2785 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2786 if (sim_log)
2787 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2788 return r;
2789 }
2790 if (cmdp->action == &set_cmd) {
2791
2792 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2793 (cmdp->help))
2794 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2795 }
2796 else {
2797 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2798 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2799 return SCPE_ARG;
2800 return help_cmd_output (flag, shptr->help, NULL);
2801 }
2802 return SCPE_ARG;
2803 }
2804 else
2805 return SCPE_2MARG;
2806 }
2807 if (cmdp->help) {
2808 if (strcmp (cmdp->name, "HELP") == 0) {
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843 }
2844 else {
2845 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2846 sim_dflt_dev && sim_dflt_dev->help) {
2847 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2848 if (sim_log)
2849 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2850 }
2851 }
2852 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2853 }
2854 else {
2855 CTAB *cmdpa;
2856 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2857 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2858 sim_printf ("%s is an alias for the %s command:\n%s",
2859 cmdp->name, cmdpa->name, cmdpa->help);
2860 break;
2861 }
2862 if (cmdpa->name == NULL)
2863 sim_printf ("No help available for the %s command\n", cmdp->name);
2864 }
2865 }
2866 else {
2867 DEVICE *dptr;
2868 UNIT *uptr;
2869 t_stat r;
2870 dptr = find_unit (gbuf, &uptr);
2871 if (dptr == NULL) {
2872 dptr = find_dev (gbuf);
2873 if (dptr == NULL)
2874 return SCPE_ARG;
2875 if (dptr->flags & DEV_DIS)
2876 sim_printf ("Device %s is currently disabled\n", dptr->name);
2877 }
2878 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2879 if (sim_log)
2880 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2881 return r;
2882 }
2883 }
2884 else {
2885 fprint_help (stdout);
2886 if (sim_log)
2887 fprint_help (sim_log);
2888 }
2889 return SCPE_OK;
2890 }
2891
2892
2893
2894 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2895 {
2896 t_stat status;
2897 if ((cptr == NULL) || (strlen (cptr) == 0))
2898 cptr = getenv("SHELL");
2899 if ((cptr == NULL) || (strlen (cptr) == 0))
2900 cptr = getenv("ComSpec");
2901 (void)fflush(stdout);
2902 if (sim_log)
2903 (void)fflush (sim_log);
2904 if (sim_deb)
2905 (void)fflush (sim_deb);
2906 status = system (cptr);
2907
2908 return status;
2909 }
2910
2911
2912
2913 t_stat echo_cmd (int32 flag, CONST char *cptr)
2914 {
2915 sim_printf ("%s\n", cptr);
2916 return SCPE_OK;
2917 }
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939 t_stat do_cmd (int32 flag, CONST char *fcptr)
2940 {
2941 return do_cmd_label (flag, fcptr, NULL);
2942 }
2943
2944 static char *do_position(void)
2945 {
2946 static char cbuf[4*CBUFSIZE];
2947
2948 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
2949 sim_do_label[sim_do_depth] ? "::" : "",
2950 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
2951 sim_goto_line[sim_do_depth]);
2952 return cbuf;
2953 }
2954
2955 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
2956 {
2957 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
2958 CONST char *cptr;
2959 FILE *fpin;
2960 CTAB *cmdp = NULL;
2961 int32 echo, nargs, errabort, i;
2962 int32 saved_sim_do_echo = sim_do_echo,
2963 saved_sim_show_message = sim_show_message,
2964 saved_sim_on_inherit = sim_on_inherit,
2965 saved_sim_quiet = sim_quiet;
2966 t_bool staying;
2967 t_stat stat, stat_nomessage;
2968
2969 stat = SCPE_OK;
2970 staying = TRUE;
2971 if (flag > 0)
2972 GET_SWITCHES (fcptr);
2973 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
2974 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
2975 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
2976 errabort = sim_switches & SWMASK ('E');
2977
2978 abuf[sizeof(abuf)-1] = '\0';
2979 strncpy (abuf, fcptr, sizeof(abuf)-1);
2980 c = abuf;
2981 do_arg[10] = NULL;
2982 for (nargs = 0; nargs < 10; ) {
2983 while (sim_isspace (*c))
2984 c++;
2985 if (*c == 0)
2986 do_arg [nargs++] = NULL;
2987 else {
2988 if (*c == '\'' || *c == '"')
2989 quote = *c++;
2990 else quote = 0;
2991 do_arg[nargs++] = c;
2992 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
2993 c++;
2994 if (*c)
2995 *c++ = 0;
2996 }
2997 }
2998
2999 if (do_arg [0] == NULL)
3000 return SCPE_2FARG;
3001 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
3002 strcat (strcpy (cbuf, do_arg[0]), ".ini");
3003 if ((fpin = fopen (cbuf, "r")) == NULL) {
3004 if (flag == 0)
3005 (void)fprintf (stderr, "Can't open file %s\n", do_arg[0]);
3006 return SCPE_OPENERR;
3007 }
3008 }
3009 if (flag >= 0) {
3010 ++sim_do_depth;
3011 if (sim_on_inherit) {
3012 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
3013 for (i=0; i<SCPE_MAX_ERR; i++) {
3014 if (sim_on_actions[sim_do_depth-1][i]) {
3015 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3016 if (NULL == sim_on_actions[sim_do_depth][i]) {
3017 while (--i >= 0) {
3018 FREE(sim_on_actions[sim_do_depth][i]);
3019 sim_on_actions[sim_do_depth][i] = NULL;
3020 }
3021 sim_on_check[sim_do_depth] = 0;
3022 sim_brk_clract ();
3023 --sim_do_depth;
3024 fclose(fpin);
3025 return SCPE_MEM;
3026 }
3027 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3028 }
3029 }
3030 }
3031 }
3032
3033 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
3034 sim_do_label[sim_do_depth] = label;
3035 sim_goto_line[sim_do_depth] = 0;
3036 if (label) {
3037 sim_gotofile = fpin;
3038 sim_do_echo = echo;
3039 stat = goto_cmd (0, label);
3040 if (stat != SCPE_OK) {
3041 strcpy(cbuf, "RETURN SCPE_ARG");
3042 cptr = get_glyph (cbuf, gbuf, 0);
3043 cmdp = find_cmd (gbuf);
3044 goto Cleanup_Return;
3045 }
3046 }
3047 if (errabort)
3048 set_on (1, NULL);
3049
3050 do {
3051 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
3052 if (!sim_do_ocptr[sim_do_depth]) {
3053 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
3054 sim_goto_line[sim_do_depth] += 1;
3055 }
3056 if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {
3057 sim_sub_args(cbuf, sizeof(cbuf), do_arg);
3058 }
3059 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
3060 if (cptr == NULL) {
3061 stat = SCPE_OK;
3062 break;
3063 }
3064 if (*cptr == 0)
3065 continue;
3066 if (echo)
3067 sim_printf("%s> %s\n", do_position(), cptr);
3068 if (*cptr == ':')
3069 continue;
3070 cptr = get_glyph_cmd (cptr, gbuf);
3071 sim_switches = 0;
3072 sim_gotofile = fpin;
3073 sim_do_echo = echo;
3074 if ((cmdp = find_cmd (gbuf))) {
3075 if (cmdp->action == &return_cmd)
3076 break;
3077 if (cmdp->action == &do_cmd) {
3078 if (sim_do_depth >= MAX_DO_NEST_LVL)
3079 stat = SCPE_NEST;
3080 else
3081 stat = do_cmd (sim_do_depth+1, cptr);
3082 }
3083 else
3084 stat = cmdp->action (cmdp->arg, cptr);
3085 }
3086 else stat = SCPE_UNK;
3087 echo = sim_do_echo;
3088 stat_nomessage = stat & SCPE_NOMESSAGE;
3089 stat_nomessage = stat_nomessage || (!sim_show_message);
3090 stat = SCPE_BARE_STATUS(stat);
3091 if (cmdp)
3092 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3093 ((cmdp->action != &return_cmd) &&
3094 (cmdp->action != &goto_cmd) &&
3095 (cmdp->action != &on_cmd) &&
3096 (cmdp->action != &echo_cmd)))
3097 sim_last_cmd_stat = stat;
3098 switch (stat) {
3099 case SCPE_AFAIL:
3100 staying = (sim_on_check[sim_do_depth] &&
3101 sim_on_actions[sim_do_depth][stat]);
3102 break;
3103 case SCPE_EXIT:
3104 staying = FALSE;
3105 break;
3106 case SCPE_OK:
3107 case SCPE_STEP:
3108 break;
3109 default:
3110 break;
3111 }
3112 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
3113 (stat != SCPE_STEP)) {
3114 if (!echo && !sim_quiet &&
3115 !stat_nomessage &&
3116 !(cmdp && cmdp->message)) {
3117 sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
3118 }
3119 }
3120 if (!stat_nomessage) {
3121 if (cmdp && cmdp->message)
3122 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3123 else
3124 if (stat >= SCPE_BASE)
3125 sim_printf ("%s\n", sim_error_text (stat));
3126 }
3127 if (stat == SCPE_EXPECT)
3128 stat = SCPE_OK;
3129 if (staying &&
3130 (sim_on_check[sim_do_depth]) &&
3131 (stat != SCPE_OK) &&
3132 (stat != SCPE_STEP)) {
3133 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3134 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3135 else
3136 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3137 }
3138 if (sim_vm_post != NULL)
3139 (*sim_vm_post) (TRUE);
3140 } while (staying);
3141 Cleanup_Return:
3142 if (fpin)
3143 fclose (fpin);
3144 sim_gotofile = NULL;
3145 if (flag >= 0) {
3146 sim_do_echo = saved_sim_do_echo;
3147 sim_show_message = saved_sim_show_message;
3148 sim_on_inherit = saved_sim_on_inherit;
3149 }
3150 sim_quiet = saved_sim_quiet;
3151 if ((flag >= 0) || (!sim_on_inherit)) {
3152 for (i=0; i<SCPE_MAX_ERR; i++) {
3153 FREE (sim_on_actions[sim_do_depth][i]);
3154 sim_on_actions[sim_do_depth][i] = NULL;
3155 }
3156 sim_on_check[sim_do_depth] = 0;
3157 }
3158 if (flag >= 0)
3159 --sim_do_depth;
3160 sim_brk_clract ();
3161 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
3162 sim_string_to_stat (cptr, &stat);
3163 sim_last_cmd_stat = stat;
3164 if (sim_switches & SWMASK ('Q'))
3165 stat |= SCPE_NOMESSAGE;
3166 return stat;
3167 }
3168 return stat | SCPE_NOMESSAGE;
3169 }
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
3214 {
3215 char gbuf[CBUFSIZE];
3216 char *ip = instr, *op, *oend, *tmpbuf;
3217 const char *ap;
3218 char rbuf[CBUFSIZE];
3219 int i;
3220 time_t now;
3221 struct tm *tmnow;
3222
3223 time(&now);
3224 tmnow = localtime(&now);
3225 tmpbuf = (char *)malloc(instr_size);
3226 if (!tmpbuf)
3227 {
3228 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3229 __func__, __FILE__, __LINE__);
3230 #if defined(USE_BACKTRACE)
3231 # if defined(SIGUSR2)
3232 (void)raise(SIGUSR2);
3233
3234 # endif
3235 #endif
3236 abort();
3237 }
3238 op = tmpbuf;
3239 oend = tmpbuf + instr_size - 2;
3240 while (sim_isspace (*ip))
3241 *op++ = *ip++;
3242 for (; *ip && (op < oend); ) {
3243 if ((ip [0] == '\\') &&
3244 ((ip [1] == '%') || (ip [1] == '\\'))) {
3245 ip++;
3246 *op++ = *ip++;
3247 }
3248 else
3249 if ((*ip == '%') &&
3250 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
3251 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
3252 ap = do_arg[ip[1] - '0'];
3253 for (i=0; i<ip[1] - '0'; ++i)
3254 if (do_arg[i] == NULL) {
3255 ap = NULL;
3256 break;
3257 }
3258 ip = ip + 2;
3259 }
3260 else if (ip[1] == '*') {
3261 (void)memset (rbuf, '\0', sizeof(rbuf));
3262 ap = rbuf;
3263 for (i=1; i<=9; ++i)
3264 if (do_arg[i] == NULL)
3265 break;
3266 else
3267 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3268 if (strchr(do_arg[i], ' ')) {
3269 char quote = '"';
3270 if (strchr(do_arg[i], quote))
3271 quote = '\'';
3272 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3273 (i != 1) ? " " : "", quote,
3274 do_arg[i], quote);
3275 }
3276 else
3277 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3278 (i != 1) ? " " : "", do_arg[i]);
3279 }
3280 else
3281 break;
3282 ip = ip + 2;
3283 }
3284 else {
3285 ap = NULL;
3286 (void)get_glyph_nc (ip+1, gbuf, '%');
3287 ap = getenv(gbuf);
3288 if (!ap) {
3289 (void)get_glyph (ip+1, gbuf, '%');
3290 ap = getenv(gbuf);
3291 }
3292 ip += 1 + strlen (gbuf);
3293 if (*ip == '%') ++ip;
3294 if (!ap) {
3295
3296 if (!strcmp ("DATE", gbuf)) {
3297 (void)sprintf (rbuf, "%4d-%02d-%02d",
3298 tmnow->tm_year + 1900,
3299 tmnow->tm_mon + 1,
3300 tmnow->tm_mday);
3301 ap = rbuf;
3302 }
3303 else if (!strcmp ("TIME", gbuf)) {
3304 (void)sprintf (rbuf, "%02d:%02d:%02d",
3305 tmnow->tm_hour,
3306 tmnow->tm_min,
3307 tmnow->tm_sec);
3308 ap = rbuf;
3309 }
3310 else if (!strcmp ("DATETIME", gbuf)) {
3311 (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3312 tmnow->tm_year + 1900,
3313 tmnow->tm_mon + 1,
3314 tmnow->tm_mday,
3315 tmnow->tm_hour,
3316 tmnow->tm_min,
3317 tmnow->tm_sec);
3318 ap = rbuf;
3319 }
3320
3321 if (!strcmp ("LDATE", gbuf)) {
3322 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3323 ap = rbuf;
3324 }
3325 else if (!strcmp ("LTIME", gbuf)) {
3326 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3327 ap = rbuf;
3328 }
3329 else if (!strcmp ("CTIME", gbuf)) {
3330 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3331 ap = rbuf;
3332 }
3333
3334 else if (!strcmp ("DATE_YYYY", gbuf)) {
3335 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3336 ap = rbuf;
3337 }
3338 else if (!strcmp ("DATE_YY", gbuf)) {
3339 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3340 ap = rbuf;
3341 }
3342 else if (!strcmp ("DATE_YC", gbuf)) {
3343 (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3344 ap = rbuf;
3345 }
3346 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3347 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3348 int year = tmnow->tm_year + 1900;
3349 int days = year - 2001;
3350 int leaps = days/4 - days/100 + days/400;
3351 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3352 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3353 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3354 96, 80, 92, 76, 88, 72, 84};
3355 int cal_year = years[selector];
3356
3357 if (!strcmp ("DATE_19XX_YY", gbuf))
3358 (void)sprintf (rbuf, "%d", cal_year);
3359 else
3360 (void)sprintf (rbuf, "%d", cal_year + 1900);
3361 ap = rbuf;
3362 }
3363 else if (!strcmp ("DATE_MM", gbuf)) {
3364 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3365 ap = rbuf;
3366 }
3367 else if (!strcmp ("DATE_MMM", gbuf)) {
3368 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3369 ap = rbuf;
3370 }
3371 else if (!strcmp ("DATE_DD", gbuf)) {
3372 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3373 ap = rbuf;
3374 }
3375 else if (!strcmp ("DATE_D", gbuf)) {
3376 (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3377 ap = rbuf;
3378 }
3379 else if ((!strcmp ("DATE_WW", gbuf)) ||
3380 (!strcmp ("DATE_WYYYY", gbuf))) {
3381 int iso_yr = tmnow->tm_year + 1900;
3382 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3383
3384 if (iso_wk == 0) {
3385 iso_yr = iso_yr - 1;
3386 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3387 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3388 }
3389 else
3390 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3391 ++iso_yr;
3392 iso_wk = 1;
3393 }
3394 if (!strcmp ("DATE_WW", gbuf))
3395 (void)sprintf (rbuf, "%02d", iso_wk);
3396 else
3397 (void)sprintf (rbuf, "%04d", iso_yr);
3398 ap = rbuf;
3399 }
3400 else if (!strcmp ("DATE_JJJ", gbuf)) {
3401 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3402 ap = rbuf;
3403 }
3404 else if (!strcmp ("TIME_HH", gbuf)) {
3405 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3406 ap = rbuf;
3407 }
3408 else if (!strcmp ("TIME_MM", gbuf)) {
3409 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3410 ap = rbuf;
3411 }
3412 else if (!strcmp ("TIME_SS", gbuf)) {
3413 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3414 ap = rbuf;
3415 }
3416 else if (!strcmp ("STATUS", gbuf)) {
3417 (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3418 ap = rbuf;
3419 }
3420 else if (!strcmp ("TSTATUS", gbuf)) {
3421 (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3422 ap = rbuf;
3423 }
3424 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3425 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3426 ap = rbuf;
3427 }
3428 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3429 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3430 ap = rbuf;
3431 }
3432 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3433 (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3434 ap = rbuf;
3435 }
3436 else if (!strcmp ("SIM_QUIET", gbuf)) {
3437 (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3438 ap = rbuf;
3439 }
3440 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3441 (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3442 ap = rbuf;
3443 }
3444 else if (!strcmp ("HOSTID", gbuf)) {
3445 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3446 (void)sprintf (rbuf, "%ld", (long)gethostid());
3447 #else
3448 (void)sprintf (rbuf, "00000000");
3449 #endif
3450 ap = rbuf;
3451 }
3452 else if (!strcmp ("UID", gbuf)) {
3453 #if defined(HAVE_UNISTD)
3454 (void)sprintf (rbuf, "%ld", (long)getuid());
3455 #else
3456 (void)sprintf (rbuf, "0");
3457 #endif
3458 ap = rbuf;
3459 }
3460 else if (!strcmp ("GID", gbuf)) {
3461 #if defined(HAVE_UNISTD)
3462 (void)sprintf (rbuf, "%ld", (long)getgid());
3463 #else
3464 (void)sprintf (rbuf, "0");
3465 #endif
3466 ap = rbuf;
3467 }
3468 else if (!strcmp ("EUID", gbuf)) {
3469 #if defined(HAVE_UNISTD)
3470 (void)sprintf (rbuf, "%ld", (long)geteuid());
3471 #else
3472 (void)sprintf (rbuf, "0");
3473 #endif
3474 ap = rbuf;
3475 }
3476 else if (!strcmp ("EGID", gbuf)) {
3477 #if defined(HAVE_UNISTD)
3478 (void)sprintf (rbuf, "%ld", (long)getegid());
3479 #else
3480 (void)sprintf (rbuf, "0");
3481 #endif
3482 ap = rbuf;
3483 }
3484 else if (!strcmp ("PID", gbuf)) {
3485 #if defined(HAVE_UNISTD)
3486 (void)sprintf (rbuf, "%ld", (long)getpid());
3487 #else
3488 (void)sprintf (rbuf, "0");
3489 #endif
3490 ap = rbuf;
3491 }
3492 else if (!strcmp ("PPID", gbuf)) {
3493 #if defined(HAVE_UNISTD)
3494 (void)sprintf (rbuf, "%ld", (long)getppid());
3495 #else
3496 (void)sprintf (rbuf, "0");
3497 #endif
3498 ap = rbuf;
3499 }
3500 else if (!strcmp ("PGID", gbuf)) {
3501 #if defined(HAVE_UNISTD)
3502 (void)sprintf (rbuf, "%ld", (long)getpgid(getpid()));
3503 #else
3504 (void)sprintf (rbuf, "0");
3505 #endif
3506 ap = rbuf;
3507 }
3508 else if (!strcmp ("SID", gbuf)) {
3509 #if defined(HAVE_UNISTD)
3510 (void)sprintf (rbuf, "%ld", (long)getsid(getpid()));
3511 #else
3512 (void)sprintf (rbuf, "0");
3513 #endif
3514 ap = rbuf;
3515 }
3516 else if (!strcmp ("ENDIAN", gbuf)) {
3517 #if ( defined(DECLITEND) && DECLITEND == 1 )
3518 (void)sprintf (rbuf, "LITTLE");
3519 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3520 (void)sprintf (rbuf, "BIG");
3521 #else
3522 (void)sprintf (rbuf, "UNKNOWN");
3523 #endif
3524 ap = rbuf;
3525 }
3526 else if (!strcmp("SIM_NAME", gbuf)) {
3527 (void)sprintf (rbuf, "%s", sim_name);
3528 ap = rbuf;
3529 }
3530 else if (!strcmp("SIM_VERSION", gbuf)) {
3531 #if defined(VER_H_GIT_VERSION)
3532 (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3533 #else
3534 (void)sprintf (rbuf, "UNKNOWN");
3535 #endif
3536 ap = rbuf;
3537 }
3538 else if (!strcmp("SIM_HASH", gbuf)) {
3539 #if defined(VER_H_GIT_HASH)
3540 (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3541 #else
3542 (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3543 #endif
3544 ap = rbuf;
3545 }
3546 else if (!strcmp("SIM_RELT", gbuf)) {
3547 #if defined(VER_H_GIT_RELT)
3548 (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3549 #else
3550 (void)sprintf (rbuf, "X");
3551 #endif
3552 ap = rbuf;
3553 }
3554 else if (!strcmp("SIM_DATE", gbuf)) {
3555 #if defined(VER_H_GIT_DATE)
3556 (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3557 #else
3558 (void)sprintf (rbuf, "UNKNOWN");
3559 #endif
3560 ap = rbuf;
3561 }
3562 else if ( (!strcmp("CPUS", gbuf)) \
3563 || (!strcmp("SIM_PROCESSORS", gbuf) ) ) {
3564 (void)sprintf(rbuf, "%u", nprocs);
3565 ap = rbuf;
3566 }
3567 }
3568 }
3569 if (ap) {
3570 while (*ap && (op < oend))
3571 *op++ = *ap++;
3572 }
3573 }
3574 else
3575 *op++ = *ip++;
3576 }
3577 *op = 0;
3578 strcpy (instr, tmpbuf);
3579 FREE (tmpbuf);
3580 return;
3581 }
3582
3583 static
3584 int sim_cmp_string (const char *s1, const char *s2)
3585 {
3586 long int v1, v2;
3587 char *ep1, *ep2;
3588
3589 v1 = strtol(s1+1, &ep1, 0);
3590 v2 = strtol(s2+1, &ep2, 0);
3591 if ((ep1 != s1 + strlen (s1) - 1) ||
3592 (ep2 != s2 + strlen (s2) - 1))
3593 return strcmp (s1, s2);
3594 if (v1 == v2)
3595 return 0;
3596 if (v1 < v2)
3597 return -1;
3598 return 1;
3599 }
3600
3601
3602
3603 t_stat assert_cmd (int32 flag, CONST char *cptr)
3604 {
3605 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3606 CONST char *tptr, *gptr;
3607 REG *rptr;
3608 uint32 idx = 0;
3609 t_value val;
3610 t_stat r;
3611 t_bool Not = FALSE;
3612 t_bool result;
3613 t_addr addr = 0;
3614 t_stat reason = SCPE_AFAIL;
3615
3616 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3617
3618 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3619 # pragma diagnostic push
3620 # pragma diag_suppress = integer_sign_change
3621 #endif
3622 sim_stabr.boolop = sim_staba.boolop = -1;
3623 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3624 # pragma diagnostic pop
3625 #endif
3626 if (*cptr == 0)
3627 return SCPE_2FARG;
3628 tptr = get_glyph (cptr, gbuf, 0);
3629 if (!strcmp (gbuf, "NOT")) {
3630 Not = TRUE;
3631 cptr = (CONST char *)tptr;
3632 }
3633 if (*cptr == '"') {
3634 char op[CBUFSIZE];
3635 static struct {
3636 const char *op;
3637 int aval;
3638 int bval;
3639 t_bool invert;
3640 } *optr, compare_ops[] =
3641 {
3642 { "==", 0, 0, FALSE },
3643 { "EQU", 0, 0, FALSE },
3644 { "!=", 0, 0, TRUE },
3645 { "NEQ", 0, 0, TRUE },
3646 { "<", -1, -1, FALSE },
3647 { "LSS", -1, -1, FALSE },
3648 { "<=", 0, -1, FALSE },
3649 { "LEQ", 0, -1, FALSE },
3650 { ">", 1, 1, FALSE },
3651 { "GTR", 1, 1, FALSE },
3652 { ">=", 0, 1, FALSE },
3653 { "GEQ", 0, 1, FALSE },
3654 { NULL }
3655 };
3656
3657 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3658
3659 if (!*tptr)
3660 return SCPE_2FARG;
3661 cptr += strlen (gbuf);
3662 while (sim_isspace (*cptr))
3663 ++cptr;
3664 (void)get_glyph (cptr, op, '"');
3665 for (optr = compare_ops; optr->op; optr++)
3666 if (0 == strcmp (op, optr->op))
3667 break;
3668 if (!optr->op)
3669 return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
3670 cptr += strlen (op);
3671 while (sim_isspace (*cptr))
3672 ++cptr;
3673 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3674
3675 if (*cptr) {
3676 if (flag)
3677 return SCPE_2MARG;
3678 }
3679 else {
3680 if (!flag)
3681 return SCPE_2FARG;
3682 }
3683 result = sim_cmp_string (gbuf, gbuf2);
3684 result = ((result == optr->aval) || (result == optr->bval));
3685 if (optr->invert)
3686 result = !result;
3687 }
3688 else {
3689 cptr = get_glyph (cptr, gbuf, 0);
3690 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3691 if (rptr) {
3692 if (*gptr == '[') {
3693 if (rptr->depth <= 1)
3694 return SCPE_ARG;
3695 idx = (uint32) strtotv (++gptr, &tptr, 10);
3696 if ((gptr == tptr) || (*tptr++ != ']'))
3697 return SCPE_ARG;
3698 gptr = tptr;
3699 }
3700 else idx = 0;
3701 if (idx >= rptr->depth)
3702 return SCPE_SUB;
3703 }
3704 else {
3705 if (sim_dfdev && sim_vm_parse_addr)
3706 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3707 else if (sim_dfdev)
3708 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3709 if (gbuf == gptr)
3710 return SCPE_NXREG;
3711 }
3712 if (*gptr != 0)
3713 (void)get_glyph (gptr, gbuf, 0);
3714 else {
3715 if (*cptr == 0)
3716 return SCPE_2FARG;
3717 cptr = get_glyph (cptr, gbuf, 0);
3718 }
3719 if (*cptr) {
3720 if (flag)
3721 return SCPE_2MARG;
3722 }
3723 else {
3724 if (!flag)
3725 return SCPE_2FARG;
3726 }
3727 if (rptr) {
3728 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3729 # pragma diagnostic push
3730 # pragma diag_suppress = integer_sign_change
3731 #endif
3732 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3733 (sim_stabr.boolop == -1))
3734 return SCPE_MISVAL;
3735 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3736 # pragma diagnostic pop
3737 #endif
3738 val = get_rval (rptr, idx);
3739 result = test_search (&val, &sim_stabr);
3740 }
3741 else {
3742 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3743 # pragma diagnostic push
3744 # pragma diag_suppress = integer_sign_change
3745 #endif
3746 if (sim_dfdev)
3747 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3748 (sim_staba.boolop == -1))
3749 return SCPE_MISVAL;
3750 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3751 # pragma diagnostic pop
3752 #endif
3753 if (sim_dfdev)
3754 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3755 if (reason != SCPE_OK)
3756 return reason;
3757 result = test_search (sim_eval, &sim_staba);
3758 }
3759 }
3760 if (Not ^ result) {
3761 if (!flag)
3762 sim_brk_setact (cptr);
3763 }
3764 else
3765 if (flag)
3766 return SCPE_AFAIL;
3767 return SCPE_OK;
3768 }
3769
3770
3771
3772 t_stat send_cmd (int32 flag, CONST char *cptr)
3773 {
3774 char gbuf[CBUFSIZE];
3775 CONST char *tptr;
3776 uint8 dbuf[CBUFSIZE];
3777 uint32 dsize = 0;
3778 uint32 delay = 0;
3779 uint32 after = 0;
3780 t_stat r;
3781 SEND *snd = NULL;
3782
3783 GET_SWITCHES (cptr);
3784 tptr = get_glyph (cptr, gbuf, ',');
3785 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3786 r = tmxr_locate_line_send (gbuf, &snd);
3787 if (r != SCPE_OK)
3788 return r;
3789 cptr = tptr;
3790 tptr = get_glyph (tptr, gbuf, ',');
3791 }
3792 else
3793 snd = sim_cons_get_send ();
3794
3795 while (*cptr) {
3796 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3797 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3798 if (r != SCPE_OK)
3799 return sim_messagef (SCPE_ARG, "Invalid Delay Value\n");
3800 cptr = tptr;
3801 tptr = get_glyph (cptr, gbuf, ',');
3802 continue;
3803 }
3804 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3805 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3806 if (r != SCPE_OK)
3807 return sim_messagef (SCPE_ARG, "Invalid After Value\n");
3808 cptr = tptr;
3809 tptr = get_glyph (cptr, gbuf, ',');
3810 continue;
3811 }
3812 if ((*cptr == '"') || (*cptr == '\''))
3813 break;
3814 return SCPE_ARG;
3815 }
3816 if (*cptr) {
3817 if ((*cptr != '"') && (*cptr != '\''))
3818 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
3819 cptr = get_glyph_quoted (cptr, gbuf, 0);
3820 if (*cptr != '\0')
3821 return SCPE_2MARG;
3822
3823 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3824 return sim_messagef (SCPE_ARG, "Invalid String\n");
3825 }
3826 if ((dsize == 0) && (delay == 0) && (after == 0))
3827 return SCPE_2FARG;
3828 return sim_send_input (snd, dbuf, dsize, after, delay);
3829 }
3830
3831 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3832 {
3833 char gbuf[CBUFSIZE];
3834 CONST char *tptr;
3835 t_stat r;
3836 SEND *snd = NULL;
3837
3838 tptr = get_glyph (cptr, gbuf, ',');
3839 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3840 r = tmxr_locate_line_send (gbuf, &snd);
3841 if (r != SCPE_OK)
3842 return r;
3843 cptr = tptr;
3844 }
3845 else
3846 snd = sim_cons_get_send ();
3847 if (*cptr)
3848 return SCPE_2MARG;
3849 return sim_show_send_input (st, snd);
3850 }
3851
3852 t_stat expect_cmd (int32 flag, CONST char *cptr)
3853 {
3854 char gbuf[CBUFSIZE];
3855 CONST char *tptr;
3856 EXPECT *exp = NULL;
3857
3858 GET_SWITCHES (cptr);
3859 tptr = get_glyph (cptr, gbuf, ',');
3860 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3861 cptr = tptr;
3862 } else {
3863 exp = sim_cons_get_expect ();
3864 }
3865
3866 if (flag) {
3867 return sim_set_expect (exp, cptr);
3868 } else {
3869 if (exp == NULL) {
3870 exp = sim_cons_get_expect();
3871 }
3872 return sim_set_noexpect (exp, cptr);
3873 }
3874 }
3875
3876 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3877 {
3878 char gbuf[CBUFSIZE];
3879 CONST char *tptr;
3880 EXPECT *exp = NULL;
3881 t_stat r;
3882
3883 tptr = get_glyph (cptr, gbuf, ',');
3884 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3885 r = tmxr_locate_line_expect (gbuf, &exp);
3886 if (r != SCPE_OK)
3887 return r;
3888 cptr = tptr;
3889 }
3890 else
3891 exp = sim_cons_get_expect ();
3892 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3893 return SCPE_ARG;
3894 tptr = get_glyph_quoted (cptr, gbuf, 0);
3895 if (*tptr != '\0')
3896 return SCPE_2MARG;
3897 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3898 return SCPE_ARG;
3899 return sim_exp_show (st, exp, gbuf);
3900 }
3901
3902
3903
3904 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3905 {
3906 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3907 const char *cptr;
3908 long fpos;
3909 int32 saved_do_echo = sim_do_echo;
3910 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3911
3912 if (NULL == sim_gotofile) return SCPE_UNK;
3913 (void)get_glyph (fcptr, gbuf1, 0);
3914 if ('\0' == gbuf1[0]) return SCPE_ARG;
3915 fpos = ftell(sim_gotofile);
3916 rewind(sim_gotofile);
3917 sim_goto_line[sim_do_depth] = 0;
3918 sim_do_echo = 0;
3919 while (1) {
3920 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
3921 if (cptr == NULL) break;
3922 sim_goto_line[sim_do_depth] += 1;
3923 if (*cptr == 0) continue;
3924 if (*cptr != ':') continue;
3925 ++cptr;
3926 while (sim_isspace (*cptr)) ++cptr;
3927 cptr = get_glyph (cptr, gbuf, 0);
3928 if (0 == strcmp(gbuf, gbuf1)) {
3929 sim_brk_clract ();
3930 sim_do_echo = saved_do_echo;
3931 if (sim_do_echo)
3932 sim_printf("%s> %s\n", do_position(), cbuf);
3933 return SCPE_OK;
3934 }
3935 }
3936 sim_do_echo = saved_do_echo;
3937 fseek(sim_gotofile, fpos, SEEK_SET);
3938 sim_goto_line[sim_do_depth] = saved_goto_line;
3939 return SCPE_ARG;
3940 }
3941
3942
3943
3944
3945
3946
3947
3948
3949 t_stat return_cmd (int32 flag, CONST char *fcptr)
3950 {
3951 return SCPE_UNK;
3952 }
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962 t_stat shift_cmd (int32 flag, CONST char *fcptr)
3963 {
3964 return SCPE_UNK;
3965 }
3966
3967
3968
3969
3970
3971
3972
3973
3974 t_stat call_cmd (int32 flag, CONST char *fcptr)
3975 {
3976 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
3977 const char *cptr;
3978
3979 if (NULL == sim_gotofile) return SCPE_UNK;
3980 cptr = get_glyph (fcptr, gbuf, 0);
3981 if ('\0' == gbuf[0]) return SCPE_ARG;
3982 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
3983 sim_switches |= SWMASK ('O');
3984 return do_cmd_label (flag, cbuf, gbuf);
3985 }
3986
3987
3988
3989 t_stat on_cmd (int32 flag, CONST char *cptr)
3990 {
3991 char gbuf[CBUFSIZE];
3992 t_stat cond;
3993
3994 cptr = get_glyph (cptr, gbuf, 0);
3995 if ('\0' == gbuf[0]) return SCPE_ARG;
3996 if (0 == strcmp("ERROR", gbuf))
3997 cond = 0;
3998 else
3999 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4000 return SCPE_ARG;
4001 if ((NULL == cptr) || ('\0' == *cptr)) {
4002 FREE(sim_on_actions[sim_do_depth][cond]);
4003 sim_on_actions[sim_do_depth][cond] = NULL; }
4004 else {
4005 sim_on_actions[sim_do_depth][cond] =
4006 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4007 if (!sim_on_actions[sim_do_depth][cond])
4008 {
4009 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4010 __func__, __FILE__, __LINE__);
4011 #if defined(USE_BACKTRACE)
4012 # if defined(SIGUSR2)
4013 (void)raise(SIGUSR2);
4014
4015 # endif
4016 #endif
4017 abort();
4018 }
4019 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4020 }
4021 return SCPE_OK;
4022 }
4023
4024
4025
4026 t_stat noop_cmd (int32 flag, CONST char *cptr)
4027 {
4028 if (cptr && (*cptr != 0))
4029 return SCPE_2MARG;
4030 return SCPE_OK;
4031 }
4032
4033
4034
4035 t_stat set_on (int32 flag, CONST char *cptr)
4036 {
4037 if ((flag) && (cptr) && (*cptr)) {
4038 char gbuf[CBUFSIZE];
4039
4040 cptr = get_glyph (cptr, gbuf, 0);
4041 if (((MATCH_CMD(gbuf,"INHERIT")) &&
4042 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
4043 (*cptr))
4044 return SCPE_2MARG;
4045 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
4046 sim_on_inherit = 1;
4047 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
4048 sim_on_inherit = 0;
4049 return SCPE_OK;
4050 }
4051 if (cptr && (*cptr != 0))
4052 return SCPE_2MARG;
4053 sim_on_check[sim_do_depth] = flag;
4054 if ((sim_do_depth != 0) &&
4055 (NULL == sim_on_actions[sim_do_depth][0])) {
4056 sim_on_actions[sim_do_depth][0] =
4057 (char *)malloc(1+strlen("RETURN"));
4058 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4059 }
4060 if ((sim_do_depth != 0) &&
4061 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
4062 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
4063 (char *)malloc(1+strlen("RETURN"));
4064 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4065 }
4066 return SCPE_OK;
4067 }
4068
4069
4070
4071 t_stat set_verify (int32 flag, CONST char *cptr)
4072 {
4073 if (cptr && (*cptr != 0))
4074 return SCPE_2MARG;
4075 if (flag == sim_do_echo)
4076 return SCPE_OK;
4077 sim_do_echo = flag;
4078 return SCPE_OK;
4079 }
4080
4081
4082
4083 t_stat set_message (int32 flag, CONST char *cptr)
4084 {
4085 if (cptr && (*cptr != 0))
4086 return SCPE_2MARG;
4087 if (flag == sim_show_message)
4088 return SCPE_OK;
4089 sim_show_message = flag;
4090 return SCPE_OK;
4091 }
4092
4093
4094
4095 t_stat set_localopc (int32 flag, CONST char *cptr)
4096 {
4097 if (cptr && (*cptr != 0))
4098 return SCPE_2MARG;
4099 if (flag == sim_localopc)
4100 return SCPE_OK;
4101 sim_localopc = flag;
4102 return SCPE_OK;
4103 }
4104
4105
4106 t_stat set_quiet (int32 flag, CONST char *cptr)
4107 {
4108 if (cptr && (*cptr != 0))
4109 return SCPE_2MARG;
4110 if (flag == sim_quiet)
4111 return SCPE_OK;
4112 sim_quiet = flag;
4113 return SCPE_OK;
4114 }
4115
4116
4117
4118 t_stat sim_set_environment (int32 flag, CONST char *cptr)
4119 {
4120 char varname[CBUFSIZE];
4121
4122 if ((NULL == cptr) || (*cptr == 0))
4123 return SCPE_2FARG;
4124 cptr = get_glyph (cptr, varname, '=');
4125 setenv(varname, cptr, 1);
4126 return SCPE_OK;
4127 }
4128
4129
4130
4131 t_stat set_cmd (int32 flag, CONST char *cptr)
4132 {
4133 uint32 lvl = 0;
4134 t_stat r;
4135 char gbuf[CBUFSIZE], *cvptr;
4136 CONST char *svptr;
4137 DEVICE *dptr;
4138 UNIT *uptr;
4139 MTAB *mptr;
4140 CTAB *gcmdp;
4141 C1TAB *ctbr = NULL, *glbr;
4142
4143 GET_SWITCHES (cptr);
4144 if ((NULL == cptr) || (*cptr == 0))
4145 return SCPE_2FARG;
4146 cptr = get_glyph (svptr = cptr, gbuf, 0);
4147
4148 if ((dptr = find_dev (gbuf))) {
4149 uptr = dptr->units;
4150 ctbr = set_dev_tab;
4151 lvl = MTAB_VDV;
4152 GET_SWITCHES (cptr);
4153 }
4154 else if ((dptr = find_unit (gbuf, &uptr))) {
4155 if (uptr == NULL)
4156 return SCPE_NXUN;
4157 ctbr = set_unit_tab;
4158 lvl = MTAB_VUN;
4159 GET_SWITCHES (cptr);
4160 }
4161 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
4162 GET_SWITCHES (cptr);
4163 return gcmdp->action (gcmdp->arg, cptr);
4164 }
4165 else {
4166 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4167 if ((cvptr = strchr (gbuf, '=')))
4168 *cvptr++ = 0;
4169 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4170 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4171 dptr = sim_dflt_dev;
4172 cptr = svptr;
4173 while (sim_isspace(*cptr))
4174 ++cptr;
4175 break;
4176 }
4177 }
4178 }
4179 if (!dptr)
4180 return SCPE_NXDEV;
4181 lvl = MTAB_VDV;
4182 uptr = dptr->units;
4183 }
4184 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4185 return SCPE_2FARG;
4186 GET_SWITCHES (cptr);
4187
4188 while (*cptr != 0) {
4189 cptr = get_glyph (svptr = cptr, gbuf, ',');
4190 if (0 == strcmp (gbuf, ";"))
4191 break;
4192 if ((cvptr = strchr (gbuf, '=')))
4193 *cvptr++ = 0;
4194 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4195 if ((mptr->mstring) &&
4196 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4197 if (mptr->mask & MTAB_XTD) {
4198 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4199 return SCPE_ARG;
4200 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4201 return SCPE_UDIS;
4202 if (mptr->valid) {
4203 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4204 svptr = get_glyph_quoted (svptr, gbuf, ',');
4205 if ((cvptr = strchr (gbuf, '='))) {
4206 *cvptr++ = 0;
4207 cptr = svptr;
4208 }
4209 }
4210 else {
4211 if (cvptr && MODMASK(mptr,MTAB_NC)) {
4212 (void)get_glyph_nc (svptr, gbuf, ',');
4213 if ((cvptr = strchr (gbuf, '=')))
4214 *cvptr++ = 0;
4215 }
4216 }
4217 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4218 if (r != SCPE_OK)
4219 return r;
4220 }
4221 else if (!mptr->desc)
4222 break;
4223 else if (cvptr)
4224 return SCPE_ARG;
4225 else *((int32 *) mptr->desc) = mptr->match;
4226 }
4227 else {
4228 if (cvptr)
4229 return SCPE_ARG;
4230 if (uptr->flags & UNIT_DIS)
4231 return SCPE_UDIS;
4232 if ((mptr->valid) &&
4233 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4234 return r;
4235 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4236 (mptr->match & mptr->mask);
4237 }
4238 break;
4239 }
4240 }
4241 if (!mptr || (mptr->mask == 0)) {
4242 if ((glbr = find_c1tab (ctbr, gbuf))) {
4243 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
4244 if (r != SCPE_OK)
4245 return r;
4246 }
4247 else if (!dptr->modifiers)
4248 return SCPE_NOPARAM;
4249 else return SCPE_NXPAR;
4250 }
4251 }
4252 return SCPE_OK;
4253 }
4254
4255
4256
4257 CTAB *find_ctab (CTAB *tab, const char *gbuf)
4258 {
4259 if (!tab)
4260 return NULL;
4261 for (; tab->name != NULL; tab++) {
4262 if (MATCH_CMD (gbuf, tab->name) == 0)
4263 return tab;
4264 }
4265 return NULL;
4266 }
4267
4268 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
4269 {
4270 if (!tab)
4271 return NULL;
4272 for (; tab->name != NULL; tab++) {
4273 if (MATCH_CMD (gbuf, tab->name) == 0)
4274 return tab;
4275 }
4276 return NULL;
4277 }
4278
4279
4280
4281 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4282 {
4283 if (cptr)
4284 return SCPE_ARG;
4285 dptr->dradix = flag & 037;
4286 return SCPE_OK;
4287 }
4288
4289
4290
4291 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4292 {
4293 UNIT *up;
4294 uint32 i;
4295
4296 if (cptr)
4297 return SCPE_ARG;
4298 if ((dptr->flags & DEV_DISABLE) == 0)
4299 return SCPE_NOFNC;
4300 if (flag) {
4301 if ((dptr->flags & DEV_DIS) == 0)
4302 return SCPE_OK;
4303 dptr->flags = dptr->flags & ~DEV_DIS;
4304 }
4305 else {
4306 if (dptr->flags & DEV_DIS)
4307 return SCPE_OK;
4308 for (i = 0; i < dptr->numunits; i++) {
4309 up = (dptr->units) + i;
4310 if ((up->flags & UNIT_ATT) || sim_is_active (up))
4311 return SCPE_NOFNC;
4312 }
4313 dptr->flags = dptr->flags | DEV_DIS;
4314 }
4315 if (dptr->reset)
4316 return dptr->reset (dptr);
4317 else return SCPE_OK;
4318 }
4319
4320
4321
4322 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4323 {
4324 if (cptr)
4325 return SCPE_ARG;
4326 if (!(uptr->flags & UNIT_DISABLE))
4327 return SCPE_NOFNC;
4328 if (flag)
4329 uptr->flags = uptr->flags & ~UNIT_DIS;
4330 else {
4331 if ((uptr->flags & UNIT_ATT) ||
4332 sim_is_active (uptr))
4333 return SCPE_NOFNC;
4334 uptr->flags = uptr->flags | UNIT_DIS;
4335 }
4336 return SCPE_OK;
4337 }
4338
4339
4340
4341 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4342 {
4343 char gbuf[CBUFSIZE];
4344 DEBTAB *dep;
4345
4346 if ((dptr->flags & DEV_DEBUG) == 0)
4347 return SCPE_NOFNC;
4348 if (cptr == NULL) {
4349 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4350 if (flag && dptr->debflags) {
4351 for (dep = dptr->debflags; dep->name != NULL; dep++)
4352 dptr->dctrl = dptr->dctrl | dep->mask;
4353 }
4354 return SCPE_OK;
4355 }
4356 if (dptr->debflags == NULL)
4357 return SCPE_ARG;
4358 while (*cptr) {
4359 cptr = get_glyph (cptr, gbuf, ';');
4360 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4361 if (strcmp (dep->name, gbuf) == 0) {
4362 if (flag)
4363 dptr->dctrl = dptr->dctrl | dep->mask;
4364 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4365 break;
4366 }
4367 }
4368 if (dep->mask == 0)
4369 return SCPE_ARG;
4370 }
4371 return SCPE_OK;
4372 }
4373
4374
4375
4376 t_stat show_cmd (int32 flag, CONST char *cptr)
4377 {
4378 t_stat r = SCPE_IERR;
4379
4380 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4381
4382 if (NULL == cptr)
4383 return r;
4384 if (sim_ofile) {
4385 r = show_cmd_fi (sim_ofile, flag, cptr);
4386 fclose (sim_ofile);
4387 }
4388 else {
4389 r = show_cmd_fi (stdout, flag, cptr);
4390 if (sim_log && (sim_log != stdout))
4391 show_cmd_fi (sim_log, flag, cptr);
4392 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4393 show_cmd_fi (sim_deb, flag, cptr);
4394 }
4395 return r;
4396 }
4397
4398 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4399 {
4400 uint32 lvl = 0xFFFFFFFF;
4401 char gbuf[CBUFSIZE], *cvptr;
4402 CONST char *svptr;
4403 DEVICE *dptr;
4404 UNIT *uptr;
4405 MTAB *mptr;
4406 SHTAB *shtb = NULL, *shptr;
4407
4408 GET_SWITCHES (cptr);
4409 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4410 return SCPE_2FARG;
4411 cptr = get_glyph (svptr = cptr, gbuf, 0);
4412
4413 if ((dptr = find_dev (gbuf))) {
4414 uptr = dptr->units;
4415 shtb = show_dev_tab;
4416 lvl = MTAB_VDV;
4417 GET_SWITCHES (cptr);
4418 }
4419 else if ((dptr = find_unit (gbuf, &uptr))) {
4420 if (uptr == NULL)
4421 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\n", gbuf);
4422 if (uptr->flags & UNIT_DIS)
4423 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", gbuf);
4424 shtb = show_unit_tab;
4425 lvl = MTAB_VUN;
4426 GET_SWITCHES (cptr);
4427 }
4428 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4429 GET_SWITCHES (cptr);
4430 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4431 }
4432 else {
4433 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4434 if ((cvptr = strchr (gbuf, '=')))
4435 *cvptr++ = 0;
4436 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4437 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4438 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4439 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4440 dptr = sim_dflt_dev;
4441 lvl = MTAB_VDV;
4442 cptr = svptr;
4443 while (sim_isspace(*cptr))
4444 ++cptr;
4445 break;
4446 }
4447 }
4448 }
4449 if (!dptr) {
4450 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4451 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4452 else
4453 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf);
4454 }
4455 }
4456
4457 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4458 return (lvl == MTAB_VDV)?
4459 show_device (ofile, dptr, 0):
4460 show_unit (ofile, dptr, uptr, -1);
4461 }
4462 GET_SWITCHES (cptr);
4463
4464 while (*cptr != 0) {
4465 cptr = get_glyph (cptr, gbuf, ',');
4466 if ((cvptr = strchr (gbuf, '=')))
4467 *cvptr++ = 0;
4468 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4469 if (((mptr->mask & MTAB_XTD)?
4470 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4471 ((mptr->disp && mptr->pstring &&
4472 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4473 )) {
4474 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4475 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\n", gbuf, cvptr);
4476 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4477 break;
4478 }
4479 }
4480 if (!mptr || (mptr->mask == 0)) {
4481 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4482 t_stat r;
4483
4484 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4485 if (r != SCPE_OK)
4486 return r;
4487 }
4488 else {
4489 if (!dptr->modifiers)
4490 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\n", dptr->name);
4491 else
4492 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\n", gbuf);
4493 }
4494 }
4495 }
4496 return SCPE_OK;
4497 }
4498
4499 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4500 {
4501 if (!tab)
4502 return NULL;
4503 for (; tab->name != NULL; tab++) {
4504 if (MATCH_CMD (gbuf, tab->name) == 0)
4505 return tab;
4506 }
4507 return NULL;
4508 }
4509
4510
4511
4512 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4513 {
4514 uint32 j, udbl, ucnt;
4515 UNIT *uptr;
4516 int32 toks = 0;
4517
4518 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4519 (void)fprintf (st, "%s", sim_dname (dptr));
4520 if ((flag == 2) && dptr->description) {
4521 (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4522 }
4523 else {
4524 if ((sim_switches & SWMASK ('D')) && dptr->description)
4525 (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4526 }
4527 if (qdisable (dptr)) {
4528 (void)fprintf (st, "\tdisabled\n");
4529 return SCPE_OK;
4530 }
4531 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4532 uptr = dptr->units + j;
4533 if (!(uptr->flags & UNIT_DIS))
4534 ucnt++;
4535 else if (uptr->flags & UNIT_DISABLE)
4536 udbl++;
4537 }
4538
4539 if (dptr->numunits == 0) {
4540
4541
4542 }
4543 else
4544 {
4545 if (ucnt == 0) {
4546 fprint_sep (st, &toks);
4547 (void)fprintf (st, "all units disabled\n");
4548 }
4549 else if ((ucnt + udbl) == 1) {
4550 fprint_sep (st, &toks);
4551 (void)fprintf (st, " 1 unit\n");
4552 }
4553 else if ((ucnt > 1) || (udbl > 0)) {
4554 fprint_sep (st, &toks);
4555 (void)fprintf (st, "%2.d units\n", ucnt + udbl);
4556 }
4557 else
4558 if ((flag != 2) || !dptr->description || toks)
4559 (void)fprintf (st, "\n");
4560 toks = 0;
4561 }
4562 if (flag)
4563 return SCPE_OK;
4564 for (j = 0; j < dptr->numunits; j++) {
4565 uptr = dptr->units + j;
4566 if ((uptr->flags & UNIT_DIS) == 0)
4567 show_unit (st, dptr, uptr, ucnt + udbl);
4568 }
4569 }
4570 return SCPE_OK;
4571 }
4572
4573 void fprint_sep (FILE *st, int32 *tokens)
4574 {
4575 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4576 *tokens += 1;
4577 }
4578
4579 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4580 {
4581 int32 u = (int32)(uptr - dptr->units);
4582 int32 toks = 0;
4583
4584 if (flag > 1)
4585 (void)fprintf (st, " %s%d \n", sim_dname (dptr), u);
4586 else if (flag < 0)
4587 (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4588 if (uptr->flags & UNIT_ATT) {
4589 fprint_sep (st, &toks);
4590 (void)fprintf (st, "status : attached to %s", uptr->filename);
4591 if (uptr->flags & UNIT_RO)
4592 (void)fprintf (st, ", read only");
4593 }
4594 else {
4595 if (uptr->flags & UNIT_ATTABLE) {
4596 fprint_sep (st, &toks);
4597 (void)fprintf (st, "status : not attached");
4598 }
4599 }
4600 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4601 fprint_sep (st, &toks);
4602 fprint_capac (st, dptr, uptr);
4603 }
4604 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4605 if (toks || (flag < 0) || (flag > 1))
4606 (void)fprintf (st, "\n");
4607 return SCPE_OK;
4608 }
4609
4610 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4611 {
4612 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4613 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4614 t_offset mval;
4615 t_offset psize = (t_offset)uptr->capac;
4616 char *scale, *width;
4617
4618 if (sim_switches & SWMASK ('B'))
4619 kval = 1024;
4620 mval = kval * kval;
4621 if (dptr->flags & DEV_SECTORS) {
4622 kval = kval / 512;
4623 mval = mval / 512;
4624 }
4625 if ((dptr->dwidth / dptr->aincr) > 8)
4626 width = "W";
4627 else
4628 width = "B";
4629 if ((psize < (kval * 10)) &&
4630 (0 != (psize % kval))) {
4631 scale = "";
4632 }
4633 else if ((psize < (mval * 10)) &&
4634 (0 != (psize % mval))){
4635 scale = "K";
4636 psize = psize / kval;
4637 }
4638 else {
4639 scale = "M";
4640 psize = psize / mval;
4641 }
4642 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4643 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4644 return capac_buf;
4645 }
4646
4647 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4648 {
4649 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4650 }
4651
4652
4653
4654 extern void print_default_base_system_script (void);
4655 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4656 {
4657 #if !defined(PERF_STRIP)
4658 print_default_base_system_script();
4659 #endif
4660 return 0;
4661 }
4662
4663 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4664 sim_printf (" %s ", label);
4665 sim_printf (" %2d %3o(8) '", length, offset);
4666 for (int l = 0; l < length; l ++)
4667 {
4668 unsigned int byte = PROM[offset + l];
4669 if (byte == 255)
4670 {
4671 byte = ' ';
4672 }
4673 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4674 }
4675 sim_printf ("'\r\n");
4676 }
4677
4678 static void strip_spaces(char* str) {
4679 int i, x;
4680 for (i=x=0; str[i]; ++i)
4681 {
4682 if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)])))
4683 {
4684 str[x++] = str[i];
4685 }
4686 }
4687 str[x] = '\0';
4688 i = -1;
4689 x = 0;
4690 while (str[x] != '\0')
4691 {
4692 if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4693 {
4694 i=x;
4695 }
4696 x++;
4697 }
4698 str[i+1] = '\0';
4699 }
4700
4701 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
4702 char sx[1024];
4703 sx[1023] = '\0';
4704 unsigned int lastbyte = 0;
4705 for (int l = 0; l < length; l ++)
4706 {
4707 unsigned int byte = PROM[offset + l];
4708 if (byte == 255)
4709 {
4710 byte = 20;
4711 }
4712 if ((lastbyte != 20) && (byte != 20))
4713 {
4714 (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4715 }
4716 lastbyte = byte;
4717 }
4718 strip_spaces(sx);
4719 (void)fprintf (st, "%s", sx);
4720 }
4721
4722 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4723 {
4724 unsigned char PROM[1024];
4725 setupPROM (0, PROM);
4726
4727 sim_printf (" PROM size: %llu bytes\r\n",
4728 (long long unsigned)sizeof(PROM));
4729 sim_printf (" PROM initialization data:\r\n\r\n");
4730
4731 sim_printf (" Field Description Length Offset Contents\r\n");
4732 sim_printf (" ========================= ======== ======== ==================================\r\n");
4733 sim_printf ("\r\n");
4734
4735
4736
4737 printp (PROM, "CPU Model ", 0, 11);
4738 printp (PROM, "CPU Serial ", 11, 11);
4739 printp (PROM, "Ship Date ", 22, 6);
4740 printp (PROM, "PROM Layout Version ", 60, 1);
4741 printp (PROM, "Release Git Commit Date ", 70, 10);
4742 printp (PROM, "Release Major ", 80, 3);
4743 printp (PROM, "Release Minor ", 83, 3);
4744 printp (PROM, "Release Patch ", 86, 3);
4745 printp (PROM, "Release Iteration ", 89, 3);
4746 printp (PROM, "Release Build Number ", 92, 8);
4747 printp (PROM, "Release Type ", 100, 1);
4748 printp (PROM, "Release Version Text ", 101, 29);
4749 printp (PROM, "Build Architecture ", 130, 20);
4750 printp (PROM, "Build Operating System ", 150, 20);
4751 printp (PROM, "Target Architecture ", 170, 20);
4752 printp (PROM, "Target Operating System ", 190, 20);
4753
4754 sim_printf("\r\n");
4755 return 0;
4756 }
4757
4758 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4759 {
4760 (void)fprintf (st, "\r Build Information:\n");
4761 #if defined(BUILDINFO_scp)
4762 (void)fprintf (st, "\r\n Compilation info: %s\n", BUILDINFO_scp );
4763 #else
4764 (void)fprintf (st, "\r\n Compilation info: Not available\n" );
4765 #endif
4766 #if !defined(__CYGWIN__)
4767 # if !defined(__APPLE__)
4768 # if !defined(_AIX)
4769 # if !defined(__MINGW32__)
4770 # if !defined(__MINGW64__)
4771 # if !defined(CROSS_MINGW32)
4772 # if !defined(CROSS_MINGW64)
4773 # if !defined(_WIN32)
4774 # if !defined(__HAIKU__)
4775 # if !defined(__QNX__)
4776 (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4777 if (dl_iterate_phdr_callback_called)
4778 (void)fprintf (st, "\n");
4779 dl_iterate_phdr_callback_called = 0;
4780 # endif
4781 # endif
4782 # endif
4783 # endif
4784 # endif
4785 # endif
4786 # endif
4787 # endif
4788 # endif
4789 #endif
4790 #if defined(UV_VERSION_MAJOR) && \
4791 defined(UV_VERSION_MINOR) && \
4792 defined(UV_VERSION_PATCH)
4793 # if defined(UV_VERSION_MAJOR)
4794 # if !defined(UV_VERSION_MINOR) && \
4795 !defined(UV_VERSION_PATCH) && \
4796 !defined(UV_VERSION_SUFFIX)
4797 (void)fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4798 # endif
4799 # if defined(UV_VERSION_MINOR)
4800 # if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4801 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4802 UV_VERSION_MINOR);
4803 # endif
4804 # if defined(UV_VERSION_PATCH)
4805 # if !defined(UV_VERSION_SUFFIX)
4806 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4807 UV_VERSION_MINOR, UV_VERSION_PATCH);
4808 # endif
4809 # if defined(UV_VERSION_SUFFIX)
4810 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4811 UV_VERSION_MINOR, UV_VERSION_PATCH);
4812 # if defined(UV_VERSION_IS_RELEASE)
4813 # if UV_VERSION_IS_RELEASE == 1
4814 # define UV_RELEASE_TYPE " (release)"
4815 # endif
4816 # if UV_VERSION_IS_RELEASE == 0
4817 # define UV_RELEASE_TYPE "-dev"
4818 # endif
4819 # if !defined(UV_RELEASE_TYPE)
4820 # define UV_RELEASE_TYPE ""
4821 # endif
4822 # if defined(UV_RELEASE_TYPE)
4823 (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4824 # endif
4825 # endif
4826 # endif
4827 # endif
4828 # endif
4829 unsigned int CurrentUvVersion = uv_version();
4830 if (CurrentUvVersion > 0)
4831 if (uv_version_string() != NULL)
4832 (void)fprintf (st, "; %s in use", uv_version_string());
4833 # endif
4834 #else
4835 (void)fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4836 #endif
4837
4838
4839
4840 (void)fprintf (st, "\r\n Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4841 SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4842 SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4843 sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4844 #if defined(DECNUMBERLOC)
4845 # if defined(DECVERSION)
4846 # if defined(DECVERSEXT)
4847 (void)fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4848 # else
4849 # if defined(DECNLAUTHOR)
4850 (void)fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4851 # else
4852 (void)fprintf (st, "\r\n Math library: %s", DECVERSION);
4853 # endif
4854 # endif
4855 # else
4856 (void)fprintf (st, "\r\n Math library: decNumber, unknown version");
4857 # endif
4858 #endif
4859 #if defined(LOCKLESS)
4860 (void)fprintf (st, "\r\n Atomic operations: ");
4861 # if defined(AIX_ATOMICS)
4862 (void)fprintf (st, "C11 and IBM AIX-style");
4863 # elif defined(BSD_ATOMICS)
4864 (void)fprintf (st, "C11 and FreeBSD-style");
4865 # elif defined(GNU_ATOMICS)
4866 (void)fprintf (st, "C11 and GNU-style");
4867 # elif defined(SYNC_ATOMICS)
4868 (void)fprintf (st, "C11 and GNU sync-style");
4869 # elif defined(ISO_ATOMICS)
4870 (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4871 # elif defined(NT_ATOMICS)
4872 (void)fprintf (st, "C11 and Windows NT interlocked operations");
4873 # endif
4874 #endif
4875 (void)fprintf (st, "\r\n File locking: ");
4876 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4877 (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4878 #endif
4879 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4880 (void)fprintf (st, "POSIX-style fcntl() locking");
4881 #endif
4882 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4883 (void)fprintf (st, "BSD-style flock() locking");
4884 #endif
4885 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4886 (void)fprintf (st, "No file locking available");
4887 #endif
4888 (void)fprintf (st, "\r\n Windows support: ");
4889 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4890 # if defined(__MINGW64_VERSION_STR)
4891 (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4892 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4893 (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4894 # else
4895 (void)fprintf (st, "Built with MinGW");
4896 # endif
4897
4898 # if defined(MINGW_CRT)
4899 (void)fprintf (st, "; %s", MINGW_CRT);
4900 # if !defined(_UCRT)
4901 # if defined(__MSVCRT_VERSION__)
4902 # if __MSVCRT_VERSION__ > 0x00
4903 (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4904 # endif
4905 # endif
4906 # else
4907
4908 struct UCRTVersion ucrtversion;
4909 int result = GetUCRTVersion (&ucrtversion);
4910
4911 if (result == 0)
4912 (void)fprintf (st, " %u.%u.%u.%u",
4913 ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4914 ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4915 # endif
4916 (void)fprintf (st, " in use");
4917 # endif
4918 #elif defined(__CYGWIN__)
4919 struct utsname utsname;
4920 (void)fprintf (st, "Built with Cygwin %d.%d.%d",
4921 CYGWIN_VERSION_DLL_MAJOR / 1000,
4922 CYGWIN_VERSION_DLL_MAJOR % 1000,
4923 CYGWIN_VERSION_DLL_MINOR);
4924 if (uname(&utsname) == 0)
4925 fprintf (st, "; %s in use", utsname.release);
4926 #else
4927 (void)fprintf (st, "Disabled");
4928 #endif
4929
4930 (void)fprintf (st, "\r\n");
4931 return 0;
4932 }
4933
4934 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4935 {
4936 const char *arch = "";
4937 char *whydirty = " ";
4938 int dirty = 0;
4939
4940 if (cptr && (*cptr != 0))
4941 return SCPE_2MARG;
4942 if (flag) {
4943 (void)fprintf (st, " %s Simulator:", sim_name);
4944 #if defined(USE_DUMA)
4945 # undef NO_SUPPORT_VERSION
4946 # define NO_SUPPORT_VERSION 1
4947 nodist++;
4948 #endif
4949 #if defined(NO_SUPPORT_VERSION) || \
4950 defined(WITH_SOCKET_DEV) || \
4951 defined(WITH_ABSI_DEV) || \
4952 defined(WITH_MGP_DEV) || \
4953 defined(TESTING) || \
4954 defined(ISOLTS) || \
4955 defined(USE_DUMA)
4956 # if !defined(NO_SUPPORT_VERSION)
4957 # define NO_SUPPORT_VERSION 1
4958 # endif
4959 #endif
4960 #if defined(NO_SUPPORT_VERSION)
4961 dirty++;
4962 #endif
4963 #if defined(GENERATED_MAKE_VER_H)
4964 # if defined(VER_H_GIT_VERSION)
4965
4966
4967 if (strstr(VER_H_GIT_VERSION, "*"))
4968 {
4969 dirty++;
4970 }
4971
4972
4973 if ((strstr(VER_H_GIT_VERSION, "X")) || \
4974 (strstr(VER_H_GIT_VERSION, "D")) || \
4975 (strstr(VER_H_GIT_VERSION, "A")) || \
4976 (strstr(VER_H_GIT_VERSION, "B")))
4977 {
4978 dirty++;
4979 }
4980
4981
4982 if (dirty)
4983 {
4984 if ((strstr(VER_H_GIT_VERSION, "X")))
4985 {
4986 whydirty = " ";
4987 }
4988 else if ((strstr(VER_H_GIT_VERSION, "D")))
4989 {
4990 whydirty = " DEV ";
4991 }
4992 else if ((strstr(VER_H_GIT_VERSION, "A")))
4993 {
4994 whydirty = " ALPHA ";
4995 }
4996 else if ((strstr(VER_H_GIT_VERSION, "B")))
4997 {
4998 whydirty = " BETA ";
4999 }
5000 }
5001
5002 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5003 # if defined(VER_H_GIT_HASH)
5004 # if VER_H_GIT_PATCH_INT < 1
5005 (void)fprintf (st, "\n Version: %s (%ld-bit)\n Commit: %s",
5006 VER_H_GIT_VERSION,
5007 (long)(CHAR_BIT*sizeof(void *)),
5008 VER_H_GIT_HASH);
5009 # else
5010 # define NO_SUPPORT_VERSION 1
5011 (void)fprintf (st, "\n Version: %s+%s (%ld-bit)\n Commit: %s",
5012 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5013 (long)(CHAR_BIT*sizeof(void *)),
5014 VER_H_GIT_HASH);
5015 # endif
5016 # else
5017 # if VER_H_GIT_PATCH_INT < 1
5018 (void)fprintf (st, "\n Version: %s (%ld-bit)",
5019 VER_H_GIT_VERSION,
5020 (long)(CHAR_BIT*sizeof(void *)));
5021 # else
5022 # define NO_SUPPORT_VERSION 1
5023 (void)fprintf (st, "\n Version: %s+%s (%ld-bit)",
5024 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5025 (long)(CHAR_BIT*sizeof(void *)));
5026 # endif
5027 # endif
5028 # else
5029 # if defined(VER_H_GIT_HASH)
5030 (void)fprintf (st, "\n Version: %s (%ld-bit)\n Commit: %s",
5031 VER_H_GIT_VERSION,
5032 (long)(CHAR_BIT*sizeof(void *)),
5033 VER_H_GIT_HASH);
5034 # else
5035 (void)fprintf (st, "\n Version: %s (%ld-bit)",
5036 VER_H_GIT_VERSION,
5037 (long)(CHAR_BIT*sizeof(void *)));
5038 # endif
5039 # endif
5040 # endif
5041 #endif
5042
5043
5044 #if defined(TESTING)
5045 (void)fprintf (st, "\n Options: ");
5046 # if !defined(HAVE_DPSOPT)
5047 # define HAVE_DPSOPT 1
5048 # endif
5049 (void)fprintf (st, "TESTING");
5050 #endif
5051
5052
5053 #if defined(ISOLTS)
5054 # if defined(HAVE_DPSOPT)
5055 (void)fprintf (st, ", ");
5056 # else
5057 (void)fprintf (st, "\n Options: ");
5058 # endif
5059 # if !defined(HAVE_DPSOPT)
5060 # define HAVE_DPSOPT 1
5061 # endif
5062 (void)fprintf (st, "ISOLTS");
5063 #endif
5064
5065
5066 #if defined(NO_UCACHE)
5067 # if defined(HAVE_DPSOPT)
5068 (void)fprintf (st, ", ");
5069 # else
5070 (void)fprintf (st, "\n Options: ");
5071 # endif
5072 # if !defined(HAVE_DPSOPT)
5073 # define HAVE_DPSOPT 1
5074 # endif
5075 (void)fprintf (st, "NO_UCACHE");
5076 #endif
5077
5078
5079 #if defined(NEED_128)
5080 # if defined(HAVE_DPSOPT)
5081 (void)fprintf (st, ", ");
5082 # else
5083 (void)fprintf (st, "\n Options: ");
5084 # endif
5085 # if !defined(HAVE_DPSOPT)
5086 # define HAVE_DPSOPT 1
5087 # endif
5088 (void)fprintf (st, "NEED_128");
5089 #endif
5090
5091
5092 #if defined(WAM)
5093 # if defined(HAVE_DPSOPT)
5094 (void)fprintf (st, ", ");
5095 # else
5096 (void)fprintf (st, "\n Options: ");
5097 # endif
5098 # if !defined(HAVE_DPSOPT)
5099 # define HAVE_DPSOPT 1
5100 # endif
5101 (void)fprintf (st, "WAM");
5102 #endif
5103
5104
5105 #if defined(ROUND_ROBIN)
5106 # if defined(HAVE_DPSOPT)
5107 (void)fprintf (st, ", ");
5108 # else
5109 (void)fprintf (st, "\n Options: ");
5110 # endif
5111 # if !defined(HAVE_DPSOPT)
5112 # define HAVE_DPSOPT 1
5113 # endif
5114 (void)fprintf (st, "ROUND_ROBIN");
5115 #endif
5116
5117
5118 #if !defined(LOCKLESS)
5119 # if defined(HAVE_DPSOPT)
5120 (void)fprintf (st, ", ");
5121 # else
5122 (void)fprintf (st, "\n Options: ");
5123 # endif
5124 # if !defined(HAVE_DPSOPT)
5125 # define HAVE_DPSOPT 1
5126 # endif
5127 (void)fprintf (st, "NO_LOCKLESS");
5128 #endif
5129
5130
5131 #if defined(WITH_ABSI_DEV)
5132 # if defined(HAVE_DPSOPT)
5133 (void)fprintf (st, ", ");
5134 # else
5135 (void)fprintf (st, "\n Options: ");
5136 # endif
5137 # if !defined(HAVE_DPSOPT)
5138 # define HAVE_DPSOPT 1
5139 # endif
5140 (void)fprintf (st, "ABSI");
5141 #endif
5142
5143
5144 #if defined(WITH_SOCKET_DEV)
5145 # if defined(HAVE_DPSOPT)
5146 (void)fprintf (st, ", ");
5147 # else
5148 (void)fprintf (st, "\n Options: ");
5149 # endif
5150 # if !defined(HAVE_DPSOPT)
5151 # define HAVE_DPSOPT 1
5152 # endif
5153 (void)fprintf (st, "SOCKET");
5154 #endif
5155
5156
5157 #if defined(WITH_MGP_DEV)
5158 # if defined(HAVE_DPSOPT)
5159 (void)fprintf (st, ", ");
5160 # else
5161 (void)fprintf (st, "\n Options: ");
5162 # endif
5163 # if !defined(HAVE_DPSOPT)
5164 # define HAVE_DPSOPT 1
5165 # endif
5166 (void)fprintf (st, "CHAOSNET");
5167 # if USE_SOCKET_DEV_APPROACH
5168 (void)fprintf (st, "-S");
5169 # endif
5170 #endif
5171
5172
5173 #if defined(USE_DUMA)
5174 # if defined(HAVE_DPSOPT)
5175 (void)fprintf (st, ", ");
5176 # else
5177 (void)fprintf (st, "\n Options: ");
5178 # endif
5179 # if !defined(HAVE_DPSOPT)
5180 # define HAVE_DPSOPT 1
5181 # endif
5182 (void)fprintf (st, "DUMA");
5183 #endif
5184
5185 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5186 # if defined(NO_SUPPORT_VERSION)
5187 (void)fprintf (st, "\n Modified: %s", VER_H_GIT_DATE);
5188 # else
5189 (void)fprintf (st, "\n Released: %s", VER_H_GIT_DATE);
5190 # endif
5191 #endif
5192 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5193 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5194 #endif
5195 #if defined(VER_CURRENT_TIME)
5196 (void)fprintf (st, "\n Compiled: %s", VER_CURRENT_TIME);
5197 #endif
5198 if (dirty)
5199 {
5200 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5201 }
5202 (void)fprintf (st, "\r\n\r\n Build Information:");
5203 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5204 char build_os_version_raw[255];
5205 char build_os_arch_raw[255];
5206 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5207 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5208 char *build_os_version = strdup(build_os_version_raw);
5209 if (!build_os_version)
5210 {
5211 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5212 __func__, __FILE__, __LINE__);
5213 # if defined(USE_BACKTRACE)
5214 # if defined(SIGUSR2)
5215 (void)raise(SIGUSR2);
5216
5217 # endif
5218 # endif
5219 abort();
5220 }
5221 char *build_os_arch = strdup(build_os_arch_raw);
5222 if (!build_os_arch)
5223 {
5224 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5225 __func__, __FILE__, __LINE__);
5226 # if defined(USE_BACKTRACE)
5227 # if defined(SIGUSR2)
5228 (void)raise(SIGUSR2);
5229
5230 # endif
5231 # endif
5232 abort();
5233 }
5234 unsigned char SPROM[1024];
5235 setupPROM (0, SPROM);
5236 (void)fprintf (st, "\n Target: ");
5237 printpq (SPROM, st, 190, 20);
5238 if (SPROM[170] != 20)
5239 {
5240 if (SPROM[170] != 255)
5241 {
5242 (void)fprintf (st, " on ");
5243 printpq (SPROM, st, 170, 20);
5244 }
5245 }
5246 strtrimspace(build_os_version, build_os_version_raw);
5247 strtrimspace(build_os_arch, build_os_arch_raw);
5248 (void)fprintf (st, "\n Build OS: %s %s", build_os_version, build_os_arch);
5249 FREE(build_os_version);
5250 FREE(build_os_arch);
5251 #endif
5252 #if defined(__VERSION__)
5253 char gnumver[2];
5254 char postver[1024];
5255 (void)sprintf(gnumver, "%.1s", __VERSION__);
5256 (void)sprintf(postver, "%.1023s", __VERSION__);
5257 strremove(postver, "(TM)");
5258 strremove(postver, "(R)");
5259 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5260 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5261 strremove(postver, " gcc 4.9 mode");
5262 strremove(postver, "4.2.1 Compatible ");
5263 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5264 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5265 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5266 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5267 strremove(postver, "(experimental) ");
5268 strremove(postver, ".module+el8.7.0+20823+214a699d");
5269 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5270 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5271 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5272 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5273 strremove(postver, "llvmorg-16.0.6-0-");
5274 strremove(postver, " Clang 15.0.0 (build 760095e)");
5275 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5276 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5277 strremove(postver, " Clang 15.0.0 (build 232543c)");
5278 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5279 strremove(postver, "CLANG: ");
5280 #endif
5281 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5282 # if !defined(__clang_version__)
5283 if (isdigit((unsigned char)gnumver[0])) {
5284 (void)fprintf (st, "\n Compiler: GCC %s", postver);
5285 } else {
5286 (void)fprintf (st, "\n Compiler: %s", postver);
5287 }
5288 # endif
5289 # if defined(__clang_analyzer__ )
5290 (void)fprintf (st, "\n Compiler: Clang C/C++ Static Analyzer");
5291 # elif defined(__clang_version__) && defined(__VERSION__)
5292 char clangllvmver[1024];
5293 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5294 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5295 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5296 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5297 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5298 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5299 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5300 strremove(clangllvmver, " ( )");
5301 strremove(clangllvmver, " ()");
5302 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5303 (void)fprintf (st, "\n Compiler: Clang %s", clangllvmver);
5304 } else {
5305 (void)fprintf (st, "\n Compiler: %s", postver);
5306 }
5307 # elif defined(__clang_version__)
5308 (void)fprintf (st, "\n Compiler: %s", postver);
5309 # endif
5310 #elif defined(__PGI) && !defined(__NVCOMPILER)
5311 (void)fprintf (st, "\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5312 # if defined(__PGIC__)
5313 (void)fprintf (st, "%d", __PGIC__);
5314 # if defined(__PGIC_MINOR__)
5315 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5316 # if defined(__PGIC_PATCHLEVEL__)
5317 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5318 # endif
5319 # endif
5320 # endif
5321 #elif defined(__NVCOMPILER)
5322 (void)fprintf (st, "\n Compiler: NVIDIA HPC SDK C Compiler ");
5323 # if defined(__NVCOMPILER_MAJOR__)
5324 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5325 # if defined(__NVCOMPILER_MINOR__)
5326 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5327 # if defined(__NVCOMPILER_PATCHLEVEL__)
5328 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5329 # endif
5330 # endif
5331 # endif
5332 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5333 (void)fprintf (st, "\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5334 _MSC_FULL_VER/10000000,
5335 (_MSC_FULL_VER/100000)%100,
5336 _MSC_FULL_VER%100000,
5337 _MSC_BUILD);
5338 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5339 # if defined(_AIX) && defined(__PASE__)
5340 (void)fprintf (st, "\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5341 # endif
5342 # if defined(_AIX) && !defined(__PASE__)
5343 (void)fprintf (st, "\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5344 # endif
5345 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5346 (void)fprintf (st, "\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5347 # endif
5348 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5349 # if defined(__PPC__) && defined(__APPLE__)
5350 (void)fprintf (st, "\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5351 # else
5352 (void)fprintf (st, "\n Compiler: IBM XL C/C++ V%s", __xlc__);
5353 # endif
5354 # endif
5355 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5356 # define VER_ENC(maj, min, rev) \
5357 (((maj) * 1000000) + ((min) * 1000) + (rev))
5358 # define VER_DEC_MAJ(ver) \
5359 ((ver) / 1000000)
5360 # define VER_DEC_MIN(ver) \
5361 (((ver) % 1000000) / 1000)
5362 # define VER_DEC_REV(ver) \
5363 ((ver) % 1000)
5364 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5365 # define COMP_VER VER_ENC( \
5366 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5367 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5368 (__SUNPRO_C & 0xf) * 10)
5369 # elif defined(__SUNPRO_C)
5370 # define COMP_VER VER_ENC( \
5371 (__SUNPRO_C >> 8) & 0xf, \
5372 (__SUNPRO_C >> 4) & 0xf, \
5373 (__SUNPRO_C) & 0xf)
5374 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5375 # define COMP_VER VER_ENC( \
5376 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5377 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5378 (__SUNPRO_CC & 0xf) * 10)
5379 # elif defined(__SUNPRO_CC)
5380 # define COMP_VER VER_ENC( \
5381 (__SUNPRO_CC >> 8) & 0xf, \
5382 (__SUNPRO_CC >> 4) & 0xf, \
5383 (__SUNPRO_CC) & 0xf)
5384 # endif
5385 # if !defined(COMP_VER)
5386 # define COMP_VER 0
5387 # endif
5388 (void)fprintf (st, "\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5389 VER_DEC_MAJ(COMP_VER),
5390 VER_DEC_MIN(COMP_VER),
5391 VER_DEC_REV(COMP_VER));
5392 #elif defined(__DMC__)
5393 (void)fprintf (st, "\n Compiler: Digital Mars C/C++");
5394 #elif defined(__PCC__)
5395 (void)fprintf (st, "\n Compiler: Portable C Compiler");
5396 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5397 (void)fprintf (st, "\n Compiler: Plan 9 Compiler Suite");
5398 #elif defined(__ACK__)
5399 (void)fprintf (st, "\n Compiler: Amsterdam Compiler Kit");
5400 #elif defined(__COMO__)
5401 (void)fprintf (st, "\n Compiler: Comeau C++");
5402 #elif defined(__COMPCERT__)
5403 (void)fprintf (st, "\n Compiler: CompCert C");
5404 #elif defined(__COVERITY__)
5405 (void)fprintf (st, "\n Compiler: Coverity C/C++ Static Analyzer");
5406 #elif defined(__LCC__)
5407 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5408 (void)fprintf (st, "\n Compiler: MCST Elbrus C Compiler");
5409 # if __LCC__ > 99
5410 (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5411 # if defined(__LCC_MINOR__)
5412 # if __LCC_MINOR__ > 0
5413 (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5414 # endif
5415 # endif
5416 # endif
5417 # if defined(__EDG__) && defined(__EDG_VERSION__)
5418 # if __EDG_VERSION__ > 99
5419 (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5420 (int)(((__EDG_VERSION__) % 100) % 10));
5421 # endif
5422 # endif
5423 # else
5424 (void)fprintf (st, "\n Compiler: Local/Little C Compiler (lcc)");
5425 # endif
5426 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5427 (void)fprintf (st, "\n Compiler: SGI MIPSpro");
5428 #elif defined(__OPEN64__)
5429 (void)fprintf (st, "\n Compiler: Open64 %s", __OPEN64__);
5430 #elif defined(__PGI) || defined(__PGIC__)
5431 (void)fprintf (st, "\n Compiler: Portland Group/PGI C/C++");
5432 #elif defined(__VBCC__)
5433 (void)fprintf (st, "\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5434 #elif defined(__WATCOMC__)
5435 (void)fprintf (st, "\n Compiler: Watcom C/C++ %d.%d",
5436 __WATCOMC__ / 100,
5437 __WATCOMC__ % 100);
5438 #elif defined(__xlC__)
5439 (void)fprintf (st, "\n Compiler: IBM XL C/C++");
5440 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5441 # if defined(__INTEL_COMPILER_UPDATE)
5442 # if defined(__INTEL_COMPILER_BUILD_DATE)
5443 (void)fprintf (st, "\n Compiler: Intel C++ Compiler %d.%d (%d)",
5444 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5445 __INTEL_COMPILER_BUILD_DATE);
5446 # else
5447 (void)fprintf (st, "\n Compiler: Intel C++ Compiler %d.%d",
5448 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5449 # endif
5450 # else
5451 (void)fprintf (st, "\n Compiler: Intel C++ Compiler %d",
5452 __INTEL_COMPILER);
5453 # endif
5454 #elif defined(SIM_COMPILER)
5455 # define S_xstr(a) S_str(a)
5456 # define S_str(a) #a
5457 (void)fprintf (st, "\n Compiler: %s", S_xstr(SIM_COMPILER));
5458 # undef S_str
5459 # undef S_xstr
5460 #else
5461 (void)fprintf (st, "\n Compiler: Unknown");
5462 #endif
5463
5464 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5465 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5466 # define SC_IS_PPC64 1
5467 #else
5468 # define SC_IS_PPC64 0
5469 #endif
5470
5471 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5472 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5473 defined(__PPC32)
5474 # define SC_IS_PPC32 1
5475 #else
5476 # define SC_IS_PPC32 0
5477 #endif
5478
5479 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5480 arch = " x86_64";
5481 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5482 arch = " x86";
5483 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5484 arch = " arm64";
5485 #elif defined(_M_ARM) || defined(__arm__)
5486 arch = " arm";
5487 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5488 arch = " ia64";
5489 #elif SC_IS_PPC64
5490 arch = " powerpc64";
5491 #elif SC_IS_PPC32
5492 arch = " powerpc";
5493 #elif defined(__s390x__)
5494 arch = " s390x";
5495 #elif defined(__s390__)
5496 arch = " s390";
5497 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5498 arch = " j2";
5499 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5500 arch = " sh4";
5501 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5502 arch = " sh2";
5503 #elif defined(__alpha__)
5504 arch = " alpha";
5505 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5506 arch = " hppa";
5507 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5508 arch = " ice9";
5509 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5510 arch = " mips64";
5511 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5512 arch = " mips";
5513 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5514 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5515 arch = " openrisc";
5516 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5517 arch = " sparc64";
5518 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5519 arch = " sparc";
5520 #elif defined(__riscv) || defined(__riscv__)
5521 arch = " riscv";
5522 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5523 arch = " e2k";
5524 #elif defined(__myriad2__)
5525 arch = " myriad2";
5526 #elif defined(__loongarch64) || defined(__loongarch__)
5527 arch = " loongarch";
5528 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5529 arch = " m68k";
5530 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5531 arch = " m88k";
5532 #elif defined(__VAX__) || defined(__vax__)
5533 arch = " vax";
5534 #elif defined(__NIOS2__) || defined(__nios2__)
5535 arch = " nios2";
5536 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5537 arch = " microblaze";
5538 #else
5539 arch = " ";
5540 #endif
5541 (void)fprintf (st, "%s", arch);
5542 #if defined(BUILD_BY_USER)
5543 (void)fprintf (st, "\n Built by: %s", BUILD_BY_USER);
5544 #else
5545 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5546 (void)fprintf (st, "\n Built by: %s", VER_H_PREP_USER);
5547 # endif
5548 #endif
5549 (void)fprintf (st, "\n\n Host System Information:");
5550 #if defined(_WIN32)
5551 if (1) {
5552 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5553 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5554 char osversion[PATH_MAX+1] = "";
5555 FILE *f;
5556
5557 if ((f = _popen ("ver", "r"))) {
5558 (void)memset (osversion, 0, sizeof(osversion));
5559 do {
5560 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5561 break;
5562 sim_trim_endspc (osversion);
5563 } while (osversion[0] == '\0');
5564 _pclose (f);
5565 }
5566 (void)fprintf (st, "\n Host OS: %s", osversion);
5567 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5568 }
5569 #else
5570 if (1) {
5571 char osversion[2*PATH_MAX+1] = "";
5572 FILE *f;
5573 # if !defined(_AIX)
5574 if ((f = popen \
5575 ("uname -mrs 2> /dev/null", "r"))) {
5576 # else
5577 if ((f = popen \
5578 ("sh -c 'echo \"$(command -p env uname -v \
5579 2> /dev/null).$(command -p env uname -r \
5580 2> /dev/null) $(command -p env uname -p \
5581 2> /dev/null)\"' 2> /dev/null", "r"))) {
5582 # endif
5583 (void)memset (osversion, 0, sizeof(osversion));
5584 do {
5585 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5586 break;
5587 }
5588 sim_trim_endspc (osversion);
5589 } while (osversion[0] == '\0');
5590 pclose (f);
5591 strremove(osversion, "0000000000000000 ");
5592 strremove(osversion, " 0000000000000000");
5593 strremove(osversion, "000000000000 ");
5594 strremove(osversion, " 000000000000");
5595 strremove(osversion, "IBM ");
5596 strremove(osversion, " (emulated by qemu)");
5597 strremove(osversion, " (emulated by QEMU)");
5598 }
5599 # if !defined(_AIX)
5600 (void)fprintf (st, "\n Host OS: %s", osversion);
5601 # else
5602 strremove(osversion, "AIX ");
5603 # if !defined(__PASE__)
5604 (void)fprintf (st, "\n Host OS: IBM AIX %s", osversion);
5605 # else
5606 (void)fprintf (st, "\n Host OS: IBM OS/400 (PASE) %s", osversion);
5607 # endif
5608 # endif
5609 } else {
5610 # if !defined(_AIX)
5611 (void)fprintf (st, "\n Host OS: Unknown");
5612 # else
5613 # if !defined(__PASE__)
5614 (void)fprintf (st, "\n Host OS: IBM AIX");
5615 # else
5616 (void)fprintf (st, "\n Host OS: IBM OS/400 (PASE)");
5617 # endif
5618 # endif
5619 }
5620 #endif
5621 #if defined(__APPLE__)
5622 int isRosetta = processIsTranslated();
5623 if (isRosetta == 1) {
5624 sim_printf ("\n\n ****** RUNNING UNDER APPLE ROSETTA 2, EXPECT REDUCED PERFORMANCE ******");
5625 }
5626 #endif
5627 if (nodist)
5628 {
5629 sim_printf ("\n\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\n");
5630 }
5631 else
5632 {
5633 (void)fprintf (st, "\n");
5634 (void)fprintf (st, "\n This software is made available under the terms of the ICU License.");
5635 (void)fprintf (st, "\n For complete license details, see the LICENSE file included with the");
5636 (void)fprintf (st, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5637 }
5638 (void)fprintf (st, "\n");
5639 }
5640 return SCPE_OK;
5641 }
5642
5643 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5644 {
5645 size_t i;
5646 DEVICE *dptr;
5647 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5648
5649 if (cptr && (*cptr != 0))
5650 return SCPE_2MARG;
5651 (void)fprintf (st, "%s simulator configuration%s\n\n", sim_name, only_enabled ? " (enabled devices)" : "");
5652 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5653 if (!only_enabled || !qdisable (dptr))
5654 show_device (st, dptr, flag);
5655 return SCPE_OK;
5656 }
5657
5658 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5659 {
5660 int32 i;
5661 DEVICE *dptr;
5662
5663 if (cptr && (*cptr != 0))
5664 return SCPE_2MARG;
5665 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5666 show_dev_logicals (st, dptr, NULL, 1, cptr);
5667 return SCPE_OK;
5668 }
5669
5670 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5671 {
5672 if (dptr->lname)
5673 (void)fprintf (st, "%s -> %s\n", dptr->lname, dptr->name);
5674 else if (!flag)
5675 fputs ("no logical name assigned\n", st);
5676 return SCPE_OK;
5677 }
5678
5679 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5680 {
5681 DEVICE *dptr;
5682 UNIT *uptr;
5683 int32 accum;
5684
5685 if (cptr && (*cptr != 0))
5686 return SCPE_2MARG;
5687 if (sim_clock_queue == QUEUE_LIST_END)
5688 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\n",
5689 sim_name, sim_time, sim_timer_inst_per_sec ());
5690 else {
5691 const char *tim;
5692
5693 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\n",
5694 sim_name, sim_time, sim_timer_inst_per_sec ());
5695 accum = 0;
5696 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5697 if (uptr == &sim_step_unit)
5698 (void)fprintf (st, " Step timer");
5699 else
5700 if (uptr == &sim_expect_unit)
5701 (void)fprintf (st, " Expect fired");
5702 else
5703 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5704 (void)fprintf (st, " %s", sim_dname (dptr));
5705 if (dptr->numunits > 1)
5706 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5707 }
5708 else
5709 (void)fprintf (st, " Unknown");
5710 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5711 (void)fprintf (st, " at %d%s%s%s%s\n", accum + uptr->time,
5712 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5713 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5714 accum = accum + uptr->time;
5715 }
5716 }
5717 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5718 return SCPE_OK;
5719 }
5720
5721 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5722 {
5723 if (cptr && (*cptr != 0))
5724 return SCPE_2MARG;
5725 (void)fprintf (st, "Time:\t%.0f\n", sim_gtime());
5726 return SCPE_OK;
5727 }
5728
5729 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5730 {
5731 t_stat r;
5732
5733 if (cptr && (*cptr != 0))
5734 r = ssh_break (st, cptr, 1);
5735 else
5736 r = sim_brk_showall (st, (uint32)sim_switches);
5737 return r;
5738 }
5739
5740 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5741 {
5742 (void)fprintf (st, "Radix=%d\n", dptr->dradix);
5743 return SCPE_OK;
5744 }
5745
5746 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5747 {
5748 int32 any = 0;
5749 DEBTAB *dep;
5750
5751 if (dptr->flags & DEV_DEBUG) {
5752 if (dptr->dctrl == 0)
5753 fputs ("Debugging disabled", st);
5754 else if (dptr->debflags == NULL)
5755 fputs ("Debugging enabled", st);
5756 else {
5757 uint32 dctrl = dptr->dctrl;
5758
5759 fputs ("Debug=", st);
5760 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5761 if ((dctrl & dep->mask) == dep->mask) {
5762 dctrl &= ~dep->mask;
5763 if (any)
5764 fputc (';', st);
5765 fputs (dep->name, st);
5766 any = 1;
5767 }
5768 }
5769 }
5770 fputc ('\n', st);
5771 return SCPE_OK;
5772 }
5773 else return SCPE_NOFNC;
5774 }
5775
5776
5777
5778 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5779 {
5780 int32 lvl, i;
5781
5782 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5783 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5784 if (lvl > 0)
5785 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5786 else
5787 (void)fprintf(st, "On Processing for input commands");
5788 (void)fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5789 for (i=1; i<SCPE_BASE; ++i) {
5790 if (sim_on_actions[lvl][i])
5791 (void)fprintf(st, " on %5d %s\n", i, sim_on_actions[lvl][i]); }
5792 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5793 if (sim_on_actions[lvl][i])
5794 (void)fprintf(st, " on %-5s %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5795 if (sim_on_actions[lvl][0])
5796 (void)fprintf(st, " on ERROR %s\n", sim_on_actions[lvl][0]);
5797 (void)fprintf(st, "\n");
5798 }
5799 if (sim_on_inherit)
5800 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\n");
5801 return SCPE_OK;
5802 }
5803
5804
5805
5806 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5807 {
5808 int32 i;
5809 DEVICE *dptr;
5810
5811 if (cptr && (*cptr != 0))
5812 return SCPE_2MARG;
5813 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5814 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5815 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5816 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5817 return SCPE_OK;
5818 }
5819
5820 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5821 {
5822 fprint_set_help (st, dptr);
5823 return SCPE_OK;
5824 }
5825
5826 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5827 {
5828 MTAB *mptr;
5829 t_stat r = SCPE_OK;
5830
5831 if (dptr->modifiers == NULL)
5832 return SCPE_OK;
5833 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5834 if (mptr->pstring &&
5835 ((mptr->mask & MTAB_XTD)?
5836 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5837 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5838 if (*toks > 0) {
5839 (void)fprintf (st, "\n");
5840 *toks = 0;
5841 }
5842 if (r == SCPE_OK)
5843 fprint_sep (st, toks);
5844 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5845 }
5846 }
5847 return SCPE_OK;
5848 }
5849
5850 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5851 CONST char *cptr, int32 flag)
5852 {
5853 t_stat r = SCPE_OK;
5854
5855 if (mptr->disp)
5856 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5857 else
5858 fputs (mptr->pstring, st);
5859 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5860 fputc ('\n', st);
5861 return r;
5862 }
5863
5864
5865
5866 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5867 {
5868 int32 i;
5869 DEVICE *dptr;
5870
5871 if (cptr && (*cptr != 0))
5872 return SCPE_2MARG;
5873 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5874 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5875 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5876 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5877 return SCPE_OK;
5878 }
5879
5880 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5881 {
5882 fprint_show_help (st, dptr);
5883 return SCPE_OK;
5884 }
5885
5886
5887
5888 t_stat brk_cmd (int32 flg, CONST char *cptr)
5889 {
5890 GET_SWITCHES (cptr);
5891 return ssh_break (NULL, cptr, flg);
5892 }
5893
5894 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
5895 {
5896 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5897 CONST char *tptr, *t1ptr;
5898 DEVICE *dptr = sim_dflt_dev;
5899 UNIT *uptr;
5900 t_stat r;
5901 t_addr lo, hi, max;
5902 int32 cnt;
5903
5904 if (sim_brk_types == 0)
5905 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5906 if (dptr == NULL)
5907 return SCPE_IERR;
5908 uptr = dptr->units;
5909 if (uptr == NULL)
5910 return SCPE_IERR;
5911 max = uptr->capac - 1;
5912 abuf[sizeof(abuf)-1] = '\0';
5913 strncpy (abuf, cptr, sizeof(abuf)-1);
5914 cptr = abuf;
5915 if ((aptr = strchr (abuf, ';'))) {
5916 if (flg != SSH_ST)
5917 return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", aptr);
5918 *aptr++ = 0;
5919 }
5920 if (*cptr == 0) {
5921 lo = (t_addr) get_rval (sim_PC, 0);
5922 return ssh_break_one (st, flg, lo, 0, aptr);
5923 }
5924 while (*cptr) {
5925 cptr = get_glyph (cptr, gbuf, ',');
5926 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5927 if (tptr == NULL)
5928 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\n", gbuf);
5929 if (*tptr == '[') {
5930 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5931 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5932 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\n", tptr + 1);
5933 tptr = t1ptr + 1;
5934 }
5935 else cnt = 0;
5936 if (*tptr != 0)
5937 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\n", tptr);
5938 if ((lo == 0) && (hi == max)) {
5939 if (flg == SSH_CL)
5940 sim_brk_clrall (sim_switches);
5941 else
5942 if (flg == SSH_SH)
5943 sim_brk_showall (st, (uint32)sim_switches);
5944 else
5945 return SCPE_ARG;
5946 }
5947 else {
5948 for ( ; lo <= hi; lo = lo + 1) {
5949 r = ssh_break_one (st, flg, lo, cnt, aptr);
5950 if (r != SCPE_OK)
5951 return r;
5952 }
5953 }
5954 }
5955 return SCPE_OK;
5956 }
5957
5958 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
5959 {
5960 if (!sim_brk_types)
5961 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5962 switch (flg) {
5963 case SSH_ST:
5964 return sim_brk_set (lo, sim_switches, cnt, aptr);
5965
5966 break;
5967
5968 case SSH_CL:
5969 return sim_brk_clr (lo, sim_switches);
5970
5971 break;
5972
5973 case SSH_SH:
5974 return sim_brk_show (st, lo, sim_switches);
5975
5976 break;
5977
5978 default:
5979 return SCPE_ARG;
5980 }
5981 }
5982
5983
5984
5985 static t_bool run_cmd_did_reset = FALSE;
5986
5987 t_stat reset_cmd (int32 flag, CONST char *cptr)
5988 {
5989 char gbuf[CBUFSIZE];
5990 DEVICE *dptr;
5991
5992 GET_SWITCHES (cptr);
5993 run_cmd_did_reset = FALSE;
5994 if (*cptr == 0)
5995 return (reset_all (0));
5996 cptr = get_glyph (cptr, gbuf, 0);
5997 if (*cptr != 0)
5998 return SCPE_2MARG;
5999 if (strcmp (gbuf, "ALL") == 0)
6000 return (reset_all (0));
6001 dptr = find_dev (gbuf);
6002 if (dptr == NULL)
6003 return SCPE_NXDEV;
6004 if (dptr->reset != NULL)
6005 return dptr->reset (dptr);
6006 else return SCPE_OK;
6007 }
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017 t_stat reset_all (uint32 start)
6018 {
6019 DEVICE *dptr;
6020 uint32 i;
6021 t_stat reason;
6022
6023 for (i = 0; i < start; i++) {
6024 if (sim_devices[i] == NULL)
6025 return SCPE_IERR;
6026 }
6027 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6028 if (dptr->reset != NULL) {
6029 reason = dptr->reset (dptr);
6030 if (reason != SCPE_OK)
6031 return reason;
6032 }
6033 }
6034 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6035 if (dptr->reset != NULL) {
6036 reason = dptr->reset (dptr);
6037 if (reason != SCPE_OK)
6038 return reason;
6039 }
6040 }
6041 return SCPE_OK;
6042 }
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052 t_stat reset_all_p (uint32 start)
6053 {
6054 t_stat r;
6055 int32 old_sw = sim_switches;
6056
6057 sim_switches = SWMASK ('P');
6058 r = reset_all (start);
6059 sim_switches = old_sw;
6060 return r;
6061 }
6062
6063
6064
6065 t_stat attach_cmd (int32 flag, CONST char *cptr)
6066 {
6067 char gbuf[4*CBUFSIZE];
6068 DEVICE *dptr;
6069 UNIT *uptr;
6070 t_stat r;
6071
6072 GET_SWITCHES (cptr);
6073 if ((NULL == cptr) || (*cptr == 0))
6074 return SCPE_2FARG;
6075 cptr = get_glyph (cptr, gbuf, 0);
6076 GET_SWITCHES (cptr);
6077 if ((NULL == cptr) || (*cptr == 0))
6078 return SCPE_2FARG;
6079 dptr = find_unit (gbuf, &uptr);
6080 if (dptr == NULL)
6081 return SCPE_NXDEV;
6082 if (uptr == NULL)
6083 return SCPE_NXUN;
6084 if (uptr->flags & UNIT_ATT) {
6085 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6086 !(dptr->flags & DEV_DONTAUTO)) {
6087 r = scp_detach_unit (dptr, uptr);
6088 if (r != SCPE_OK)
6089 return r; }
6090 else {
6091 if (!(uptr->dynflags & UNIT_ATTMULT))
6092 return SCPE_ALATT;
6093 }
6094 }
6095 gbuf[sizeof(gbuf)-1] = '\0';
6096 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6097 sim_trim_endspc (gbuf);
6098 return scp_attach_unit (dptr, uptr, gbuf);
6099 }
6100
6101
6102
6103 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6104 {
6105 if (dptr->attach != NULL)
6106 return dptr->attach (uptr, (CONST char *)cptr);
6107 return attach_unit (uptr, (CONST char *)cptr);
6108 }
6109
6110
6111
6112 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6113 {
6114 DEVICE *dptr;
6115
6116 if (uptr->flags & UNIT_DIS)
6117 return SCPE_UDIS;
6118 if (!(uptr->flags & UNIT_ATTABLE))
6119 return SCPE_NOATT;
6120 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6121 return SCPE_NOATT;
6122 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6123 if (uptr->filename == NULL)
6124 return SCPE_MEM;
6125 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6126 if ((sim_switches & SWMASK ('R')) ||
6127 ((uptr->flags & UNIT_RO) != 0)) {
6128 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6129 ((uptr->flags & UNIT_RO) == 0))
6130 return attach_err (uptr, SCPE_NORO);
6131 uptr->fileref = sim_fopen (cptr, "rb");
6132 if (uptr->fileref == NULL)
6133 return attach_err (uptr, SCPE_OPENERR);
6134 uptr->flags = uptr->flags | UNIT_RO;
6135 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6136 sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6137 }
6138 }
6139 else {
6140 if (sim_switches & SWMASK ('N')) {
6141 uptr->fileref = sim_fopen (cptr, "wb+");
6142 if (uptr->fileref == NULL)
6143 return attach_err (uptr, SCPE_OPENERR);
6144 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6145 sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6146 }
6147 }
6148 else {
6149 uptr->fileref = sim_fopen (cptr, "rb+");
6150 if (uptr->fileref == NULL) {
6151 #if defined(EWOULDBLOCK)
6152 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6153 #else
6154 if ((errno == EAGAIN))
6155 #endif
6156 return attach_err (uptr, SCPE_OPENERR);
6157
6158 #if defined(EPERM)
6159 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6160 #else
6161 if ((errno == EROFS) || (errno == EACCES)) {
6162 #endif
6163 if ((uptr->flags & UNIT_ROABLE) == 0)
6164 return attach_err (uptr, SCPE_NORO);
6165 uptr->fileref = sim_fopen (cptr, "rb");
6166 if (uptr->fileref == NULL)
6167 return attach_err (uptr, SCPE_OPENERR);
6168 uptr->flags = uptr->flags | UNIT_RO;
6169 if (!sim_quiet) {
6170 sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6171 }
6172 }
6173 else {
6174 if (sim_switches & SWMASK ('E'))
6175 return attach_err (uptr, SCPE_OPENERR);
6176 uptr->fileref = sim_fopen (cptr, "wb+");
6177 if (uptr->fileref == NULL)
6178 return attach_err (uptr, SCPE_OPENERR);
6179 if (!sim_quiet) {
6180 sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6181 }
6182 }
6183 }
6184 }
6185 }
6186 if (uptr->flags & UNIT_BUFABLE) {
6187 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6188 if (uptr->flags & UNIT_MUSTBUF)
6189 uptr->filebuf = calloc (cap, SZ_D (dptr));
6190 if (uptr->filebuf == NULL)
6191 return attach_err (uptr, SCPE_MEM);
6192 if (!sim_quiet) {
6193 sim_printf ("%s: buffering file in memory\n", sim_dname (dptr));
6194 }
6195 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6196 SZ_D (dptr), cap, uptr->fileref);
6197 uptr->flags = uptr->flags | UNIT_BUF;
6198 }
6199 uptr->flags = uptr->flags | UNIT_ATT;
6200 uptr->pos = 0;
6201 return SCPE_OK;
6202 }
6203
6204 t_stat attach_err (UNIT *uptr, t_stat stat)
6205 {
6206 FREE (uptr->filename);
6207 uptr->filename = NULL;
6208 return stat;
6209 }
6210
6211
6212
6213 t_stat detach_cmd (int32 flag, CONST char *cptr)
6214 {
6215 char gbuf[CBUFSIZE];
6216 DEVICE *dptr;
6217 UNIT *uptr;
6218
6219 GET_SWITCHES (cptr);
6220 if ((NULL == cptr) || (*cptr == 0))
6221 return SCPE_2FARG;
6222 cptr = get_glyph (cptr, gbuf, 0);
6223 if (*cptr != 0)
6224 return SCPE_2MARG;
6225 if (strcmp (gbuf, "ALL") == 0)
6226 return (detach_all (0, FALSE));
6227 dptr = find_unit (gbuf, &uptr);
6228 if (dptr == NULL)
6229 return SCPE_NXDEV;
6230 if (uptr == NULL)
6231 return SCPE_NXUN;
6232 return scp_detach_unit (dptr, uptr);
6233 }
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248 t_stat detach_all (int32 start, t_bool shutdown)
6249 {
6250 uint32 i, j;
6251 DEVICE *dptr;
6252 UNIT *uptr;
6253 t_stat r;
6254
6255 if ((start < 0) || (start > 1))
6256 return SCPE_IERR;
6257 if (shutdown)
6258 sim_switches = sim_switches | SIM_SW_SHUT;
6259 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6260 for (j = 0; j < dptr->numunits; j++) {
6261 uptr = (dptr->units) + j;
6262 if ((uptr->flags & UNIT_ATT) ||
6263 (shutdown && dptr->detach &&
6264 !(uptr->flags & UNIT_ATTABLE))) {
6265 r = scp_detach_unit (dptr, uptr);
6266
6267 if ((r != SCPE_OK) && !shutdown)
6268 return r;
6269 }
6270 }
6271 }
6272 return SCPE_OK;
6273 }
6274
6275
6276
6277 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6278 {
6279 if (dptr->detach != NULL)
6280 return dptr->detach (uptr);
6281 return detach_unit (uptr);
6282 }
6283
6284
6285
6286 t_stat detach_unit (UNIT *uptr)
6287 {
6288 DEVICE *dptr;
6289
6290 if (uptr == NULL)
6291 return SCPE_IERR;
6292 if (!(uptr->flags & UNIT_ATTABLE))
6293 return SCPE_NOATT;
6294 if (!(uptr->flags & UNIT_ATT)) {
6295 if (sim_switches & SIM_SW_REST)
6296 return SCPE_OK;
6297 else
6298 return SCPE_NOTATT;
6299 }
6300 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6301 return SCPE_OK;
6302 if (uptr->flags & UNIT_BUF) {
6303 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6304 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6305 if (!sim_quiet) {
6306 sim_printf ("%s: writing buffer to file\n", sim_dname (dptr));
6307 }
6308 rewind (uptr->fileref);
6309 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6310 if (ferror (uptr->fileref))
6311 sim_printf ("%s: I/O error - %s (Error %d)",
6312 sim_dname (dptr), xstrerror_l(errno), errno);
6313 }
6314 if (uptr->flags & UNIT_MUSTBUF) {
6315 FREE (uptr->filebuf);
6316 uptr->filebuf = NULL;
6317 }
6318 uptr->flags = uptr->flags & ~UNIT_BUF;
6319 }
6320 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6321 FREE (uptr->filename);
6322 uptr->filename = NULL;
6323 if (fclose (uptr->fileref) == EOF)
6324 return SCPE_IOERR;
6325 return SCPE_OK;
6326 }
6327
6328
6329
6330 const char *sim_dname (DEVICE *dptr)
6331 {
6332 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6333 }
6334
6335
6336
6337 const char *sim_uname (UNIT *uptr)
6338 {
6339 DEVICE *d = find_dev_from_unit(uptr);
6340 static char uname[CBUFSIZE];
6341
6342 if (!d)
6343 return "";
6344 if (d->numunits == 1)
6345 return sim_dname (d);
6346 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6347 return uname;
6348 }
6349
6350
6351
6352 t_stat run_cmd (int32 flag, CONST char *cptr)
6353 {
6354 char gbuf[CBUFSIZE] = "";
6355 CONST char *tptr;
6356 uint32 i, j;
6357 int32 sim_next = 0;
6358 int32 unitno;
6359 t_value pcv, orig_pcv;
6360 t_stat r;
6361 DEVICE *dptr;
6362 UNIT *uptr;
6363
6364 GET_SWITCHES (cptr);
6365 sim_step = 0;
6366 if ((flag == RU_RUN) || (flag == RU_GO)) {
6367 orig_pcv = get_rval (sim_PC, 0);
6368 if (*cptr != 0) {
6369 cptr = get_glyph (cptr, gbuf, 0);
6370 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6371 if (sim_dflt_dev && sim_vm_parse_addr)
6372 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6373 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6374 if ((tptr == gbuf) || (*tptr != 0) ||
6375 (pcv > width_mask[sim_PC->width]))
6376 return SCPE_ARG;
6377 put_rval (sim_PC, 0, pcv);
6378 }
6379 }
6380 if ((flag == RU_RUN) &&
6381 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6382 put_rval (sim_PC, 0, orig_pcv);
6383 return r;
6384 }
6385 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6386 int32 saved_switches = sim_switches;
6387
6388 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6389 cptr = get_glyph (cptr, gbuf, 0);
6390 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6391 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n",
6392 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6393 sim_switches = 0;
6394 GET_SWITCHES (cptr);
6395 if ((*cptr == '\'') || (*cptr == '"')) {
6396 r = expect_cmd (1, cptr);
6397 if (r != SCPE_OK)
6398 return r;
6399 }
6400 else {
6401 if (sim_switches == 0)
6402 sim_switches = sim_brk_dflt;
6403 sim_switches |= BRK_TYP_TEMP;
6404 sim_brk_types |= BRK_TYP_TEMP;
6405 r = ssh_break (NULL, cptr, SSH_ST);
6406 if (r != SCPE_OK)
6407 return sim_messagef (r, "Unable to establish breakpoint at: %s\n", cptr);
6408 }
6409 sim_switches = saved_switches;
6410 }
6411 }
6412
6413 else if ((flag == RU_STEP) ||
6414 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6415 static t_bool not_implemented_message = FALSE;
6416
6417 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6418 not_implemented_message = TRUE;
6419 flag = RU_STEP;
6420 }
6421 if (*cptr != 0) {
6422 cptr = get_glyph (cptr, gbuf, 0);
6423 if (*cptr != 0)
6424 return SCPE_2MARG;
6425 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6426 if ((r != SCPE_OK) || (sim_step <= 0))
6427 return SCPE_ARG;
6428 }
6429 else sim_step = 1;
6430 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6431 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6432 }
6433 else if (flag == RU_NEXT) {
6434 t_addr *addrs;
6435
6436 if (*cptr != 0) {
6437 cptr = get_glyph (cptr, gbuf, 0);
6438 if (*cptr != 0)
6439 return SCPE_2MARG;
6440 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6441 if ((r != SCPE_OK) || (sim_next <= 0))
6442 return SCPE_ARG;
6443 }
6444 else sim_next = 1;
6445 if (sim_vm_is_subroutine_call(&addrs)) {
6446 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6447 for (i=0; addrs[i]; i++)
6448 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6449 }
6450 else
6451 sim_step = 1;
6452 }
6453 else if (flag == RU_BOOT) {
6454 if (*cptr == 0)
6455 return SCPE_2FARG;
6456 cptr = get_glyph (cptr, gbuf, 0);
6457 if (*cptr != 0)
6458 return SCPE_2MARG;
6459 dptr = find_unit (gbuf, &uptr);
6460 if (dptr == NULL)
6461 return SCPE_NXDEV;
6462 if (uptr == NULL)
6463 return SCPE_NXUN;
6464 if (dptr->boot == NULL)
6465 return SCPE_NOFNC;
6466 if (uptr->flags & UNIT_DIS)
6467 return SCPE_UDIS;
6468 if ((uptr->flags & UNIT_ATTABLE) &&
6469 !(uptr->flags & UNIT_ATT))
6470 return SCPE_UNATT;
6471 unitno = (int32) (uptr - dptr->units);
6472 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6473 return r;
6474 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6475 return r;
6476 }
6477
6478 else
6479 if (flag != RU_CONT)
6480 return SCPE_IERR;
6481 else
6482 if (*cptr != 0)
6483 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\n");
6484
6485 if (sim_switches & SIM_SW_HIDE)
6486 return SCPE_OK;
6487
6488 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6489 for (j = 0; j < dptr->numunits; j++) {
6490 uptr = dptr->units + j;
6491 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6492 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6493 }
6494 }
6495 stop_cpu = 0;
6496 sim_is_running = 1;
6497 if (sim_ttrun () != SCPE_OK) {
6498 sim_is_running = 0;
6499 sim_ttcmd ();
6500 return SCPE_TTYERR;
6501 }
6502 if ((r = sim_check_console (30)) != SCPE_OK) {
6503 sim_is_running = 0;
6504 sim_ttcmd ();
6505 return r;
6506 }
6507 #if !defined(IS_WINDOWS)
6508 # if defined(SIGINT)
6509 if (signal (SIGINT, int_handler) == SIG_ERR) {
6510 sim_is_running = 0;
6511 sim_ttcmd ();
6512 return SCPE_SIGERR;
6513 }
6514 # endif
6515 #endif
6516 #if !defined(IS_WINDOWS)
6517 # if defined(SIGHUP)
6518 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6519 sim_is_running = 0;
6520 sim_ttcmd ();
6521 return SCPE_SIGERR;
6522 }
6523 # endif
6524 #endif
6525 #if !defined(IS_WINDOWS)
6526 # if defined(SIGTERM)
6527 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6528 sim_is_running = 0;
6529 sim_ttcmd ();
6530 return SCPE_SIGERR;
6531 }
6532 # endif
6533 #endif
6534 if (sim_step)
6535 sim_activate (&sim_step_unit, sim_step);
6536 (void)fflush(stdout);
6537 if (sim_log)
6538 (void)fflush (sim_log);
6539 sim_rtcn_init_all ();
6540 sim_start_timer_services ();
6541
6542 do {
6543 t_addr *addrs;
6544
6545 while (1) {
6546 r = sim_instr();
6547 if (r != SCPE_REMOTE)
6548 break;
6549 sim_remote_process_command ();
6550 }
6551 if ((flag != RU_NEXT) ||
6552 (--sim_next <=0))
6553 break;
6554 if (sim_step == 0) {
6555 t_addr val;
6556 BRKTAB *bp;
6557
6558 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6559 break;
6560 if (sim_vm_pc_value)
6561 val = (t_addr)(*sim_vm_pc_value)();
6562 else
6563 val = (t_addr)get_rval (sim_PC, 0);
6564 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6565 break;
6566 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6567 }
6568 else {
6569 if (r != SCPE_STEP)
6570 break;
6571 }
6572
6573 sim_step = 0;
6574 if (sim_vm_is_subroutine_call(&addrs)) {
6575 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6576 for (i=0; addrs[i]; i++)
6577 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6578 }
6579 else
6580 sim_step = 1;
6581 if (sim_step)
6582 sim_activate (&sim_step_unit, sim_step);
6583 } while (1);
6584
6585 sim_is_running = 0;
6586 sim_stop_timer_services ();
6587 sim_ttcmd ();
6588 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6589 signal (SIGINT, SIG_DFL);
6590 #if defined(SIGHUP)
6591 signal (SIGHUP, SIG_DFL);
6592 #endif
6593 signal (SIGTERM, SIG_DFL);
6594 if (sim_log)
6595 (void)fflush (sim_log);
6596 if (sim_deb)
6597 sim_debug_flush ();
6598 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6599 for (j = 0; j < dptr->numunits; j++) {
6600 uptr = dptr->units + j;
6601 if (uptr->flags & UNIT_ATT) {
6602 if (uptr->io_flush)
6603 uptr->io_flush (uptr);
6604 else {
6605 if (!(uptr->flags & UNIT_BUF) &&
6606 (uptr->fileref) &&
6607 !(uptr->dynflags & UNIT_NO_FIO) &&
6608 !(uptr->flags & UNIT_RO))
6609 (void)fflush (uptr->fileref);
6610 }
6611 }
6612 }
6613 }
6614 sim_cancel (&sim_step_unit);
6615 UPDATE_SIM_TIME;
6616 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6617 }
6618
6619
6620
6621 void
6622 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6623 {
6624 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6625 sim_printf("%s> %s\n", do_position(), unechoed_cmdline);
6626 #if defined(WIN_STDIO)
6627 (void)fflush(stderr);
6628 (void)fflush(stdout);
6629 #endif
6630 fprint_stopped (stdout, r);
6631 if (sim_log && (sim_log != stdout))
6632 fprint_stopped (sim_log, r);
6633 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6634 fprint_stopped (sim_deb, r);
6635 #if defined(WIN_STDIO)
6636 (void)fflush(stderr);
6637 (void)fflush(stdout);
6638 #endif
6639 }
6640
6641
6642
6643 t_stat sim_run_boot_prep (int32 flag)
6644 {
6645 UNIT *uptr;
6646 t_stat r;
6647
6648 sim_interval = 0;
6649 sim_time = sim_rtime = 0;
6650 noqueue_time = 0;
6651 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6652 sim_clock_queue = uptr->next;
6653 uptr->next = NULL;
6654 }
6655 r = reset_all (0);
6656 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6657 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6658 sim_printf ("Resetting all devices... This may not have been your intention.\n");
6659 sim_printf ("The GO and CONTINUE commands do not reset devices.\n");
6660 }
6661 run_cmd_did_reset = TRUE;
6662 }
6663 return r;
6664 }
6665
6666
6667
6668
6669
6670
6671
6672
6673 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6674 {
6675 int32 i;
6676 t_stat r = 0;
6677 t_addr k;
6678 t_value pcval;
6679
6680 fputc ('\n', st);
6681
6682 if (v >= SCPE_BASE)
6683 fputs (sim_error_text (v), st);
6684 else {
6685 fputs (sim_stop_messages [v], st);
6686
6687 if ((sim_vm_fprint_stopped != NULL) &&
6688 (!sim_vm_fprint_stopped (st, v)))
6689 return;
6690 }
6691
6692 (void)fprintf (st, ", %s: ", pc->name);
6693
6694 pcval = get_rval (pc, 0);
6695 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6696 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6697 else fprint_val (st, pcval, pc->radix, pc->width,
6698 pc->flags & REG_FMT);
6699 if ((dptr != NULL) && (dptr->examine != NULL)) {
6700 for (i = 0; i < sim_emax; i++)
6701 sim_eval[i] = 0;
6702 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6703 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6704 break;
6705 }
6706 if ((r == SCPE_OK) || (i > 0)) {
6707 (void)fprintf (st, " (");
6708 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6709 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6710 (void)fprintf (st, ")");
6711 }
6712 }
6713 (void)fprintf (st, "\n");
6714 return;
6715 }
6716
6717 void fprint_stopped (FILE *st, t_stat v)
6718 {
6719 #if defined(WIN_STDIO)
6720 (void)fflush(stderr);
6721 (void)fflush(stdout);
6722 #endif
6723 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6724 return;
6725 }
6726
6727
6728
6729
6730 t_stat step_svc (UNIT *uptr)
6731 {
6732 return SCPE_STEP;
6733 }
6734
6735
6736
6737
6738 t_stat expect_svc (UNIT *uptr)
6739 {
6740 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6741 }
6742
6743
6744
6745 void int_handler (int sig)
6746 {
6747 stop_cpu = 1;
6748 return;
6749 }
6750
6751
6752
6753 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6754 {
6755 char gbuf[CBUFSIZE];
6756 CONST char *gptr;
6757 CONST char *tptr = NULL;
6758 int32 opt;
6759 t_addr low, high;
6760 t_stat reason = SCPE_IERR;
6761 DEVICE *tdptr;
6762 REG *lowr, *highr;
6763 FILE *ofile;
6764
6765 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6766 if (flag == EX_E)
6767 opt = opt | CMD_OPT_OF;
6768 cptr = get_sim_opt (opt, cptr, &reason);
6769 if (NULL == cptr)
6770 return reason;
6771 if (*cptr == 0)
6772 return SCPE_2FARG;
6773 if (sim_dfunit == NULL)
6774 return SCPE_NXUN;
6775 cptr = get_glyph (cptr, gbuf, 0);
6776 if ((flag == EX_D) && (*cptr == 0))
6777
6778 return SCPE_2FARG;
6779 ofile = sim_ofile? sim_ofile: stdout;
6780
6781 for (gptr = gbuf, reason = SCPE_OK;
6782 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6783 tdptr = sim_dfdev;
6784 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6785 tptr = gptr + strlen ("STATE");
6786 if (*tptr && (*tptr++ != ','))
6787 return SCPE_ARG;
6788 if ((lowr = sim_dfdev->registers) == NULL)
6789 return SCPE_NXREG;
6790 for (highr = lowr; highr->name != NULL; highr++) ;
6791 sim_switches = sim_switches | SIM_SW_HIDE;
6792 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6793 lowr, --highr, 0, 0);
6794 continue;
6795 }
6796
6797
6798 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6799 (!(sim_opt_out & CMD_OPT_DFT) &&
6800 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6801 low = high = 0;
6802 if ((*tptr == '-') || (*tptr == ':')) {
6803 highr = find_reg (tptr + 1, &tptr, tdptr);
6804 if (highr == NULL)
6805 return SCPE_NXREG;
6806 }
6807 else {
6808 highr = lowr;
6809 if (*tptr == '[') {
6810 if (lowr->depth <= 1)
6811 return SCPE_ARG;
6812 tptr = get_range (NULL, tptr + 1, &low, &high,
6813 10, lowr->depth - 1, ']');
6814 if (tptr == NULL)
6815 return SCPE_ARG;
6816 }
6817 }
6818 if (*tptr && (*tptr++ != ','))
6819 return SCPE_ARG;
6820 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6821 lowr, highr, (uint32) low, (uint32) high);
6822 continue;
6823 }
6824
6825 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6826 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6827 sim_dfunit->capac - sim_dfdev->aincr), 0);
6828 if (tptr == NULL)
6829 return SCPE_ARG;
6830 if (*tptr && (*tptr++ != ','))
6831 return SCPE_ARG;
6832 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6833 sim_dfdev, sim_dfunit);
6834 }
6835 if (sim_ofile)
6836 fclose (sim_ofile);
6837 return reason;
6838 }
6839
6840
6841
6842
6843
6844
6845
6846 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6847 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6848 {
6849 t_stat reason;
6850 uint32 idx, val_start=lows;
6851 t_value val, last_val;
6852 REG *rptr;
6853
6854 if ((lowr == NULL) || (highr == NULL))
6855 return SCPE_IERR;
6856 if (lowr > highr)
6857 return SCPE_ARG;
6858 for (rptr = lowr; rptr <= highr; rptr++) {
6859 if ((sim_switches & SIM_SW_HIDE) &&
6860 (rptr->flags & REG_HIDDEN))
6861 continue;
6862 val = last_val = 0;
6863 for (idx = lows; idx <= highs; idx++) {
6864 if (idx >= rptr->depth)
6865 return SCPE_SUB;
6866 val = get_rval (rptr, idx);
6867 if (schptr && !test_search (&val, schptr))
6868 continue;
6869 if (flag == EX_E) {
6870 if ((idx > lows) && (val == last_val))
6871 continue;
6872 if (idx > val_start+1) {
6873 if (idx-1 == val_start+1) {
6874 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6875 if (reason != SCPE_OK)
6876 return reason;
6877 if (sim_log && (ofile == stdout))
6878 ex_reg (sim_log, val, flag, rptr, idx-1);
6879 }
6880 else {
6881 if (val_start+1 != idx-1) {
6882 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6883 if (sim_log && (ofile == stdout))
6884 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6885 }
6886 else {
6887 (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6888 if (sim_log && (ofile == stdout))
6889 (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6890 }
6891 }
6892 }
6893 sim_last_val = last_val = val;
6894 val_start = idx;
6895 reason = ex_reg (ofile, val, flag, rptr, idx);
6896 if (reason != SCPE_OK)
6897 return reason;
6898 if (sim_log && (ofile == stdout))
6899 ex_reg (sim_log, val, flag, rptr, idx);
6900 }
6901 if (flag != EX_E) {
6902 reason = dep_reg (flag, cptr, rptr, idx);
6903 if (reason != SCPE_OK)
6904 return reason;
6905 }
6906 }
6907 if ((flag == EX_E) && (val_start != highs)) {
6908 if (highs == val_start+1) {
6909 reason = ex_reg (ofile, val, flag, rptr, highs);
6910 if (reason != SCPE_OK)
6911 return reason;
6912 if (sim_log && (ofile == stdout))
6913 ex_reg (sim_log, val, flag, rptr, highs);
6914 }
6915 else {
6916 if (val_start+1 != highs) {
6917 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6918 if (sim_log && (ofile == stdout))
6919 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6920 }
6921 else {
6922 (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6923 if (sim_log && (ofile == stdout))
6924 (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6925 }
6926 }
6927 }
6928 }
6929 return SCPE_OK;
6930 }
6931
6932 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
6933 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6934 {
6935 t_addr i, mask;
6936 t_stat reason;
6937
6938 if (uptr->flags & UNIT_DIS)
6939 return SCPE_UDIS;
6940 mask = (t_addr) width_mask[dptr->awidth];
6941 if ((low > mask) || (high > mask) || (low > high))
6942 return SCPE_ARG;
6943 for (i = low; i <= high; ) {
6944 reason = get_aval (i, dptr, uptr);
6945 if (reason != SCPE_OK)
6946 return reason;
6947 if (schptr && !test_search (sim_eval, schptr))
6948 i = i + dptr->aincr;
6949 else {
6950 if (flag != EX_D) {
6951 reason = ex_addr (ofile, flag, i, dptr, uptr);
6952 if (reason > SCPE_OK)
6953 return reason;
6954 if (sim_log && (ofile == stdout))
6955 ex_addr (sim_log, flag, i, dptr, uptr);
6956 }
6957 else reason = 1 - dptr->aincr;
6958 if (flag != EX_E) {
6959 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
6960 if (reason > SCPE_OK)
6961 return reason;
6962 }
6963 i = i + (1 - reason);
6964 }
6965 }
6966 return SCPE_OK;
6967 }
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
6982 {
6983 int32 rdx;
6984
6985 if (rptr == NULL)
6986 return SCPE_IERR;
6987 if (rptr->depth > 1)
6988 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
6989 else
6990 (void)Fprintf (ofile, "%s:\t", rptr->name);
6991 if (!(flag & EX_E))
6992 return SCPE_OK;
6993 GET_RADIX (rdx, rptr->radix);
6994 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
6995 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
6996 else if (!(rptr->flags & REG_VMFLAGS) ||
6997 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
6998 NULL, sim_switches | SIM_SW_REG) > 0)) {
6999 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7000 if (rptr->fields) {
7001 (void)Fprintf (ofile, "\t");
7002 fprint_fields (ofile, val, val, rptr->fields);
7003 }
7004 }
7005 if (flag & EX_I)
7006 (void)Fprintf (ofile, "\t");
7007 else
7008 (void)Fprintf (ofile, "\n");
7009 return SCPE_OK;
7010 }
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021 t_value get_rval (REG *rptr, uint32 idx)
7022 {
7023 size_t sz;
7024 t_value val;
7025 uint32 *ptr;
7026
7027 sz = SZ_R (rptr);
7028 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7029 idx = idx + rptr->qptr;
7030 if (idx >= rptr->depth) idx = idx - rptr->depth;
7031 }
7032 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7033 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7034 if (sz <= sizeof (uint32))
7035 val = *ptr;
7036 else val = *((t_uint64 *) ptr);
7037 }
7038 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7039 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7040 if (sz <= sizeof (uint32))
7041 val = *ptr;
7042 else val = *((t_uint64 *) ptr);
7043 }
7044 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7045 (sz == sizeof (uint8)))
7046 val = *(((uint8 *) rptr->loc) + idx);
7047 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7048 (sz == sizeof (uint16)))
7049 val = *(((uint16 *) rptr->loc) + idx);
7050 else if (sz <= sizeof (uint32))
7051 val = *(((uint32 *) rptr->loc) + idx);
7052 else val = *(((t_uint64 *) rptr->loc) + idx);
7053 val = (val >> rptr->offset) & width_mask[rptr->width];
7054 return val;
7055 }
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7069 {
7070 t_stat r;
7071 t_value val, mask;
7072 int32 rdx;
7073 CONST char *tptr;
7074 char gbuf[CBUFSIZE];
7075
7076 if ((cptr == NULL) || (rptr == NULL))
7077 return SCPE_IERR;
7078 if (rptr->flags & REG_RO)
7079 return SCPE_RO;
7080 if (flag & EX_I) {
7081 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7082 if (sim_log)
7083 (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7084 if (cptr == NULL)
7085 return 1;
7086 if (*cptr == 0)
7087 return SCPE_OK;
7088 }
7089 mask = width_mask[rptr->width];
7090 GET_RADIX (rdx, rptr->radix);
7091 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7092 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7093 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7094 return SCPE_ARG;
7095 }
7096 else
7097 if (!(rptr->flags & REG_VMFLAGS) ||
7098 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7099 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7100 val = get_uint (cptr, rdx, mask, &r);
7101 if (r != SCPE_OK)
7102 return SCPE_ARG;
7103 }
7104 if ((rptr->flags & REG_NZ) && (val == 0))
7105 return SCPE_ARG;
7106 put_rval (rptr, idx, val);
7107 return SCPE_OK;
7108 }
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121 void put_rval (REG *rptr, uint32 idx, t_value val)
7122 {
7123 size_t sz;
7124 t_value mask;
7125 uint32 *ptr;
7126
7127 #define PUT_RVAL(sz,rp,id,v,m) \
7128 *(((sz *) rp->loc) + id) = \
7129 (sz)((*(((sz *) rp->loc) + id) & \
7130 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7131
7132 if (rptr == sim_PC)
7133 sim_brk_npc (0);
7134 sz = SZ_R (rptr);
7135 mask = width_mask[rptr->width];
7136 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7137 idx = idx + rptr->qptr;
7138 if (idx >= rptr->depth)
7139 idx = idx - rptr->depth;
7140 }
7141 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7142 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7143 if (sz <= sizeof (uint32))
7144 *ptr = (*ptr &
7145 ~(((uint32) mask) << rptr->offset)) |
7146 (((uint32) val) << rptr->offset);
7147 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7148 & ~(mask << rptr->offset)) | (val << rptr->offset);
7149 }
7150 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7151 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7152 if (sz <= sizeof (uint32))
7153 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7154 ~(((uint32) mask) << rptr->offset)) |
7155 (((uint32) val) << rptr->offset);
7156 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7157 & ~(mask << rptr->offset)) | (val << rptr->offset);
7158 }
7159 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7160 (sz == sizeof (uint8)))
7161 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7162 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7163 (sz == sizeof (uint16)))
7164 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7165 else if (sz <= sizeof (uint32))
7166 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7167 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7168 return;
7169 }
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7185 {
7186 t_stat reason;
7187 int32 rdx;
7188
7189 if (sim_vm_fprint_addr)
7190 sim_vm_fprint_addr (ofile, dptr, addr);
7191 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7192 (void)Fprintf (ofile, ":\t");
7193 if (!(flag & EX_E))
7194 return (1 - dptr->aincr);
7195
7196 GET_RADIX (rdx, dptr->dradix);
7197 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7198 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7199 reason = 1 - dptr->aincr;
7200 }
7201 if (flag & EX_I)
7202 (void)Fprintf (ofile, "\t");
7203 else
7204 (void)Fprintf (ofile, "\n");
7205 return reason;
7206 }
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7220 {
7221 int32 i;
7222 t_value mask;
7223 t_addr j, loc;
7224 size_t sz;
7225 t_stat reason = SCPE_OK;
7226
7227 if ((dptr == NULL) || (uptr == NULL))
7228 return SCPE_IERR;
7229 mask = width_mask[dptr->dwidth];
7230 for (i = 0; i < sim_emax; i++)
7231 sim_eval[i] = 0;
7232 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7233 if (dptr->examine != NULL) {
7234 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7235 if (reason != SCPE_OK)
7236 break;
7237 }
7238 else {
7239 if (!(uptr->flags & UNIT_ATT))
7240 return SCPE_UNATT;
7241 if (uptr->dynflags & UNIT_NO_FIO)
7242 return SCPE_NOFNC;
7243 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7244 reason = SCPE_NXM;
7245 break;
7246 }
7247 sz = SZ_D (dptr);
7248 loc = j / dptr->aincr;
7249 if (uptr->flags & UNIT_BUF) {
7250 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7251 }
7252 else {
7253 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7254 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7255 if ((feof (uptr->fileref)) &&
7256 !(uptr->flags & UNIT_FIX)) {
7257 reason = SCPE_EOF;
7258 break;
7259 }
7260 else if (ferror (uptr->fileref)) {
7261 clearerr (uptr->fileref);
7262 reason = SCPE_IOERR;
7263 break;
7264 }
7265 }
7266 }
7267 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7268 }
7269 if ((reason != SCPE_OK) && (i == 0))
7270 return reason;
7271 return SCPE_OK;
7272 }
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7289 UNIT *uptr, int32 dfltinc)
7290 {
7291 int32 i, count, rdx;
7292 t_addr j, loc;
7293 t_stat r, reason;
7294 t_value mask;
7295 size_t sz;
7296 char gbuf[CBUFSIZE];
7297
7298 if (dptr == NULL)
7299 return SCPE_IERR;
7300 if (flag & EX_I) {
7301 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7302 if (sim_log)
7303 (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7304 if (cptr == NULL)
7305 return 1;
7306 if (*cptr == 0)
7307 return dfltinc;
7308 }
7309 if (uptr->flags & UNIT_RO)
7310 return SCPE_RO;
7311 mask = width_mask[dptr->dwidth];
7312
7313 GET_RADIX (rdx, dptr->dradix);
7314 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7315 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7316 if (reason != SCPE_OK)
7317 return reason;
7318 reason = dfltinc;
7319 }
7320 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7321
7322 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7323 sim_eval[i] = sim_eval[i] & mask;
7324 if (dptr->deposit != NULL) {
7325 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7326 if (r != SCPE_OK)
7327 return r;
7328 }
7329 else {
7330 if (!(uptr->flags & UNIT_ATT))
7331 return SCPE_UNATT;
7332 if (uptr->dynflags & UNIT_NO_FIO)
7333 return SCPE_NOFNC;
7334 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7335 return SCPE_NXM;
7336 sz = SZ_D (dptr);
7337 loc = j / dptr->aincr;
7338 if (uptr->flags & UNIT_BUF) {
7339 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7340 if (loc >= uptr->hwmark)
7341 uptr->hwmark = (uint32) loc + 1;
7342 }
7343 else {
7344 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7345 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7346 if (ferror (uptr->fileref)) {
7347 clearerr (uptr->fileref);
7348 return SCPE_IOERR;
7349 }
7350 }
7351 }
7352 }
7353 return reason;
7354 }
7355
7356
7357
7358 t_stat eval_cmd (int32 flg, CONST char *cptr)
7359 {
7360 if (!sim_dflt_dev)
7361 return SCPE_ARG;
7362 DEVICE *dptr = sim_dflt_dev;
7363 int32 i, rdx, a, lim;
7364 t_stat r;
7365
7366 GET_SWITCHES (cptr);
7367 GET_RADIX (rdx, dptr->dradix);
7368 for (i = 0; i < sim_emax; i++)
7369 sim_eval[i] = 0;
7370 if (*cptr == 0)
7371 return SCPE_2FARG;
7372 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7373 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7374 if (r != SCPE_OK)
7375 return r;
7376 }
7377 lim = 1 - r;
7378 for (i = a = 0; a < lim; ) {
7379 sim_printf ("%d:\t", a);
7380 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7381 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7382 if (sim_log) {
7383 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7384 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7385 }
7386 sim_printf ("\n");
7387 if (r < 0)
7388 a = a + 1 - r;
7389 else a = a + dptr->aincr;
7390 i = a / dptr->aincr;
7391 }
7392 return SCPE_OK;
7393 }
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408 char *read_line (char *cptr, int32 size, FILE *stream)
7409 {
7410 return read_line_p (NULL, cptr, size, stream);
7411 }
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7426 {
7427 char *tptr;
7428
7429 if (prompt) {
7430 #if defined(HAVE_LINEHISTORY)
7431 char *tmpc = linenoise (prompt);
7432 if (tmpc == NULL)
7433 cptr = NULL;
7434 else {
7435 strncpy (cptr, tmpc, size-1);
7436 linenoiseHistoryAdd (tmpc);
7437 FREE (tmpc);
7438 }
7439 }
7440 #else
7441 (void)fflush (stdout);
7442 (void)printf ("%s", prompt);
7443 (void)fflush (stdout);
7444 cptr = fgets (cptr, size, stream);
7445 }
7446 #endif
7447 else cptr = fgets (cptr, size, stream);
7448
7449 if (cptr == NULL) {
7450 clearerr (stream);
7451 return NULL;
7452 }
7453 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7454 if ((*tptr == '\n') || (*tptr == '\r') ||
7455 (tptr == (cptr + size - 1))) {
7456 *tptr = 0;
7457 break;
7458 }
7459 }
7460 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7461 memmove (cptr, cptr + 3, strlen (cptr + 3));
7462 while (sim_isspace (*cptr))
7463 cptr++;
7464 if ((*cptr == ';') || (*cptr == '#')) {
7465 if (sim_do_echo)
7466 sim_printf("%s> %s\n", do_position(), cptr);
7467 *cptr = 0;
7468 }
7469
7470 return cptr;
7471 }
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7492 {
7493 t_bool quoting = FALSE;
7494 t_bool escaping = FALSE;
7495 char quote_char = 0;
7496
7497 while ((*iptr != 0) &&
7498 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7499 if (quote) {
7500 if (quoting) {
7501 if (!escaping) {
7502 if (*iptr == escape_char)
7503 escaping = TRUE;
7504 else
7505 if (*iptr == quote_char)
7506 quoting = FALSE;
7507 }
7508 else
7509 escaping = FALSE;
7510 }
7511 else {
7512 if ((*iptr == '"') || (*iptr == '\'')) {
7513 quoting = TRUE;
7514 quote_char = *iptr;
7515 }
7516 }
7517 }
7518 if (sim_islower (*iptr) && uc)
7519 *optr = (char)toupper (*iptr);
7520 else *optr = *iptr;
7521 iptr++; optr++;
7522 }
7523 if (mchar && (*iptr == mchar))
7524 iptr++;
7525 *optr = 0;
7526 while (sim_isspace (*iptr))
7527 iptr++;
7528 return iptr;
7529 }
7530
7531 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7532 {
7533 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7534 }
7535
7536 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7537 {
7538 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7539 }
7540
7541 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7542 {
7543 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7544 }
7545
7546 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7547 {
7548
7549 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7550 strcpy (optr, "!");
7551 return (CONST char *)(iptr + 1);
7552 }
7553 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7554 }
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564 char *sim_trim_endspc (char *cptr)
7565 {
7566 char *tptr;
7567
7568 tptr = cptr + strlen (cptr);
7569 while ((--tptr >= cptr) && sim_isspace (*tptr))
7570 *tptr = 0;
7571 return cptr;
7572 }
7573
7574 int sim_isspace (char c)
7575 {
7576 return (c & 0x80) ? 0 : isspace (c);
7577 }
7578
7579 int sim_islower (char c)
7580 {
7581 return (c & 0x80) ? 0 : islower (c);
7582 }
7583
7584 int sim_isalpha (char c)
7585 {
7586 return (c & 0x80) ? 0 : isalpha (c);
7587 }
7588
7589 int sim_isprint (char c)
7590 {
7591 return (c & 0x80) ? 0 : isprint (c);
7592 }
7593
7594 int sim_isdigit (char c)
7595 {
7596 return (c & 0x80) ? 0 : isdigit (c);
7597 }
7598
7599 int sim_isgraph (char c)
7600 {
7601 return (c & 0x80) ? 0 : isgraph (c);
7602 }
7603
7604 int sim_isalnum (char c)
7605 {
7606 return (c & 0x80) ? 0 : isalnum (c);
7607 }
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7621 {
7622 t_value val;
7623 CONST char *tptr;
7624
7625 *status = SCPE_OK;
7626 val = strtotv ((CONST char *)cptr, &tptr, radix);
7627 if ((cptr == tptr) || (val > max))
7628 *status = SCPE_ARG;
7629 else {
7630 while (sim_isspace (*tptr)) tptr++;
7631 if (*tptr != 0)
7632 *status = SCPE_ARG;
7633 }
7634 return val;
7635 }
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7653 uint32 rdx, t_addr max, char term)
7654 {
7655 CONST char *tptr;
7656
7657 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7658 tptr = cptr + strlen ("ALL");
7659 *lo = 0;
7660 *hi = max;
7661 }
7662 else {
7663 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7664 ((cptr[1] == '\0') ||
7665 (cptr[1] == '-') ||
7666 (cptr[1] == ':') ||
7667 (cptr[1] == '/'))) {
7668 tptr = cptr + strlen (".");
7669 *lo = *hi = sim_last_addr;
7670 }
7671 else {
7672 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7673 tptr = cptr + strlen ("$");
7674 *hi = *lo = (t_addr)sim_last_val;
7675 }
7676 else {
7677 if (dptr && sim_vm_parse_addr)
7678 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7679 else
7680 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7681 if (cptr == tptr)
7682 return NULL;
7683 }
7684 }
7685 if ((*tptr == '-') || (*tptr == ':')) {
7686 cptr = tptr + 1;
7687 if (dptr && sim_vm_parse_addr)
7688 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7689 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7690 if (cptr == tptr)
7691 return NULL;
7692 if (*lo > *hi)
7693 return NULL;
7694 }
7695 else if (*tptr == '/') {
7696 cptr = tptr + 1;
7697 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7698 if ((cptr == tptr) || (*hi == 0))
7699 return NULL;
7700 *hi = *lo + *hi - 1;
7701 }
7702 else *hi = *lo;
7703 }
7704 sim_last_addr = *hi;
7705 if (term && (*tptr++ != term))
7706 return NULL;
7707 return tptr;
7708 }
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7729 {
7730 char quote_char;
7731 uint8 *ostart = optr;
7732
7733 *osize = 0;
7734 if ((strlen(iptr) == 1) ||
7735 (iptr[0] != iptr[strlen(iptr)-1]) ||
7736 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7737 return SCPE_ARG;
7738 quote_char = *iptr++;
7739 while (iptr[1]) {
7740 if (*iptr != '\\') {
7741 if (*iptr == quote_char)
7742 return SCPE_ARG;
7743 *(optr++) = (uint8)(*(iptr++));
7744 continue;
7745 }
7746 ++iptr;
7747 switch (*iptr) {
7748 case 'r':
7749 *(optr++) = 13; ++iptr;
7750 break;
7751 case 'n':
7752 *(optr++) = 10; ++iptr;
7753 break;
7754 case 'f':
7755 *(optr++) = 12; ++iptr;
7756 break;
7757 case 't':
7758 *(optr++) = 9; ++iptr;
7759 break;
7760 case 'v':
7761 *(optr++) = 11; ++iptr;
7762 break;
7763 case 'b':
7764 *(optr++) = 8; ++iptr;
7765 break;
7766 case '\\':
7767 *(optr++) = 92; ++iptr;
7768 break;
7769 case 'e':
7770 *(optr++) = 27; ++iptr;
7771 break;
7772 case '\'':
7773 *(optr++) = 39; ++iptr;
7774 break;
7775 case '"':
7776 *(optr++) = 34; ++iptr;
7777 break;
7778 case '?':
7779 *(optr++) = 63; ++iptr;
7780 break;
7781 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7782 *optr = *(iptr++) - '0';
7783 if ((*iptr >= '0') && (*iptr <= '7'))
7784 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7785 if ((*iptr >= '0') && (*iptr <= '7'))
7786 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7787 ++optr;
7788 break;
7789 case 'x':
7790 if (1) {
7791 static const char *hex_digits = "0123456789ABCDEF";
7792 const char *c;
7793
7794 ++iptr;
7795 *optr = 0;
7796 c = strchr (hex_digits, toupper(*iptr));
7797 if (c) {
7798 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7799 ++iptr;
7800 }
7801 c = strchr (hex_digits, toupper(*iptr));
7802 if (c) {
7803 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7804 ++iptr;
7805 }
7806 ++optr;
7807 }
7808 break;
7809 default:
7810 return SCPE_ARG;
7811 }
7812 }
7813 *optr = '\0';
7814 *osize = (uint32)(optr-ostart);
7815 return SCPE_OK;
7816 }
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7832 {
7833 size_t i;
7834 t_bool double_quote_found = FALSE;
7835 t_bool single_quote_found = FALSE;
7836 char quote = '"';
7837 char *tptr, *optr;
7838
7839 optr = (char *)malloc (4*size + 3);
7840 if (optr == NULL)
7841 return NULL;
7842 tptr = optr;
7843 for (i=0; i<size; i++)
7844 switch ((char)iptr[i]) {
7845 case '"':
7846 double_quote_found = TRUE;
7847 break;
7848 case '\'':
7849 single_quote_found = TRUE;
7850 break;
7851 }
7852 if (double_quote_found && (!single_quote_found))
7853 quote = '\'';
7854 *tptr++ = quote;
7855 while (size--) {
7856 switch (*iptr) {
7857 case '\r':
7858 *tptr++ = '\\'; *tptr++ = 'r'; break;
7859 case '\n':
7860 *tptr++ = '\\'; *tptr++ = 'n'; break;
7861 case '\f':
7862 *tptr++ = '\\'; *tptr++ = 'f'; break;
7863 case '\t':
7864 *tptr++ = '\\'; *tptr++ = 't'; break;
7865 case '\v':
7866 *tptr++ = '\\'; *tptr++ = 'v'; break;
7867 case '\b':
7868 *tptr++ = '\\'; *tptr++ = 'b'; break;
7869 case '\\':
7870 *tptr++ = '\\'; *tptr++ = '\\'; break;
7871 case '"':
7872 case '\'':
7873 if (quote == *iptr)
7874 *tptr++ = '\\';
7875
7876 default:
7877 if (sim_isprint (*iptr))
7878 *tptr++ = *iptr;
7879 else {
7880 (void)sprintf (tptr, "\\%03o", *iptr);
7881 tptr += 4;
7882 }
7883 break;
7884 }
7885 ++iptr;
7886 }
7887 *tptr++ = quote;
7888 *tptr++ = '\0';
7889 return optr;
7890 }
7891
7892 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
7893 {
7894 char *string;
7895
7896 string = sim_encode_quoted_string (buf, size);
7897 (void)fprintf (st, "%s", string);
7898 FREE (string);
7899 }
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909 DEVICE *find_dev (const char *cptr)
7910 {
7911 int32 i;
7912 DEVICE *dptr;
7913
7914 if (cptr == NULL)
7915 return NULL;
7916 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7917 if ((strcmp (cptr, dptr->name) == 0) ||
7918 (dptr->lname &&
7919 (strcmp (cptr, dptr->lname) == 0)))
7920 return dptr;
7921 }
7922 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7923 if ((strcmp (cptr, dptr->name) == 0) ||
7924 (dptr->lname &&
7925 (strcmp (cptr, dptr->lname) == 0)))
7926 return dptr;
7927 }
7928 return NULL;
7929 }
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942 DEVICE *find_unit (const char *cptr, UNIT **uptr)
7943 {
7944 uint32 i, u;
7945 const char *nptr;
7946 const char *tptr;
7947 t_stat r;
7948 DEVICE *dptr;
7949
7950 if (uptr == NULL)
7951 return NULL;
7952 *uptr = NULL;
7953 if ((dptr = find_dev (cptr))) {
7954 if (qdisable (dptr))
7955 return NULL;
7956 *uptr = dptr->units;
7957 return dptr;
7958 }
7959
7960 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7961 if (qdisable (dptr))
7962 continue;
7963 if (dptr->numunits &&
7964 (((nptr = dptr->name) &&
7965 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
7966 ((nptr = dptr->lname) &&
7967 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
7968 tptr = cptr + strlen (nptr);
7969 if (sim_isdigit (*tptr)) {
7970 if (qdisable (dptr))
7971 return NULL;
7972 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
7973 if (r != SCPE_OK)
7974 *uptr = NULL;
7975 else
7976 *uptr = dptr->units + u;
7977 return dptr;
7978 }
7979 }
7980 for (u = 0; u < dptr->numunits; u++) {
7981 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
7982 *uptr = &dptr->units[u];
7983 return dptr;
7984 }
7985 }
7986 }
7987 return NULL;
7988 }
7989
7990
7991
7992
7993
7994
7995
7996 t_stat sim_register_internal_device (DEVICE *dptr)
7997 {
7998 uint32 i;
7999
8000 for (i = 0; (sim_devices[i] != NULL); i++)
8001 if (sim_devices[i] == dptr)
8002 return SCPE_OK;
8003 for (i = 0; i < sim_internal_device_count; i++)
8004 if (sim_internal_devices[i] == dptr)
8005 return SCPE_OK;
8006 ++sim_internal_device_count;
8007 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8008 if (!sim_internal_devices)
8009 {
8010 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8011 __func__, __FILE__, __LINE__);
8012 #if defined(USE_BACKTRACE)
8013 # if defined(SIGUSR2)
8014 (void)raise(SIGUSR2);
8015
8016 # endif
8017 #endif
8018 abort();
8019 }
8020 sim_internal_devices[sim_internal_device_count-1] = dptr;
8021 sim_internal_devices[sim_internal_device_count] = NULL;
8022 return SCPE_OK;
8023 }
8024
8025
8026
8027
8028
8029
8030
8031
8032
8033 DEVICE *find_dev_from_unit (UNIT *uptr)
8034 {
8035 DEVICE *dptr;
8036 uint32 i, j;
8037
8038 if (uptr == NULL)
8039 return NULL;
8040 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8041 for (j = 0; j < dptr->numunits; j++) {
8042 if (uptr == (dptr->units + j))
8043 return dptr;
8044 }
8045 }
8046 for (i = 0; i<sim_internal_device_count; i++) {
8047 dptr = sim_internal_devices[i];
8048 for (j = 0; j < dptr->numunits; j++) {
8049 if (uptr == (dptr->units + j))
8050 return dptr;
8051 }
8052 }
8053 return NULL;
8054 }
8055
8056
8057
8058 t_bool qdisable (DEVICE *dptr)
8059 {
8060 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8061 }
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8076 {
8077 int32 i;
8078 DEVICE *dptr;
8079 REG *rptr, *srptr = NULL;
8080
8081 *gdptr = NULL;
8082 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8083 if (dptr->flags & DEV_DIS)
8084 continue;
8085 if ((rptr = find_reg (cptr, optr, dptr))) {
8086 if (srptr)
8087 return NULL;
8088 srptr = rptr;
8089 *gdptr = dptr;
8090 }
8091 }
8092 return srptr;
8093 }
8094
8095
8096
8097
8098
8099
8100
8101
8102
8103
8104
8105
8106 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8107 {
8108 CONST char *tptr;
8109 REG *rptr;
8110 size_t slnt;
8111
8112 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8113 return NULL;
8114 tptr = cptr;
8115 do {
8116 tptr++;
8117 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8118 slnt = tptr - cptr;
8119 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8120 if ((slnt == strlen (rptr->name)) &&
8121 (strncmp (cptr, rptr->name, slnt) == 0)) {
8122 if (optr != NULL)
8123 *optr = tptr;
8124 return rptr;
8125 }
8126 }
8127 return NULL;
8128 }
8129
8130
8131
8132
8133
8134
8135
8136
8137
8138
8139 int32 get_switches (const char *cptr)
8140 {
8141 int32 sw;
8142
8143 if (*cptr != '-')
8144 return 0;
8145 sw = 0;
8146 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8147 if (sim_isalpha (*cptr) == 0)
8148 return -1;
8149 sw = sw | SWMASK (toupper (*cptr));
8150 }
8151 return sw;
8152 }
8153
8154
8155
8156
8157
8158
8159
8160
8161
8162
8163 CONST char *get_sim_sw (CONST char *cptr)
8164 {
8165 int32 lsw;
8166 char gbuf[CBUFSIZE];
8167
8168 while (*cptr == '-') {
8169 cptr = get_glyph (cptr, gbuf, 0);
8170 lsw = get_switches (gbuf);
8171 if (lsw <= 0)
8172 return NULL;
8173 sim_switches = sim_switches | lsw;
8174 }
8175 return cptr;
8176 }
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8189 {
8190 int32 t;
8191 char gbuf[CBUFSIZE];
8192 CONST char *svptr;
8193 DEVICE *tdptr;
8194 UNIT *tuptr;
8195
8196 sim_switches = 0;
8197 sim_ofile = NULL;
8198 sim_schrptr = NULL;
8199 sim_schaptr = NULL;
8200 sim_stabr.logic = sim_staba.logic = SCH_OR;
8201 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8202 sim_stabr.count = 1;
8203 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8204 if (!sim_stabr.mask)
8205 {
8206 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8207 __func__, __FILE__, __LINE__);
8208 #if defined(USE_BACKTRACE)
8209 # if defined(SIGUSR2)
8210 (void)raise(SIGUSR2);
8211
8212 # endif
8213 #endif
8214 abort();
8215 }
8216 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8217 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8218 if (!sim_stabr.comp)
8219 {
8220 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8221 __func__, __FILE__, __LINE__);
8222 #if defined(USE_BACKTRACE)
8223 # if defined(SIGUSR2)
8224 (void)raise(SIGUSR2);
8225
8226 # endif
8227 #endif
8228 abort();
8229 }
8230 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8231 sim_staba.count = sim_emax;
8232 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8233 if (!sim_staba.mask)
8234 {
8235 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8236 __func__, __FILE__, __LINE__);
8237 #if defined(USE_BACKTRACE)
8238 # if defined(SIGUSR2)
8239 (void)raise(SIGUSR2);
8240
8241 # endif
8242 #endif
8243 abort();
8244 }
8245 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8246 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8247 if (!sim_staba.comp)
8248 {
8249 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8250 __func__, __FILE__, __LINE__);
8251 #if defined(USE_BACKTRACE)
8252 # if defined(SIGUSR2)
8253 (void)raise(SIGUSR2);
8254
8255 # endif
8256 #endif
8257 abort();
8258 }
8259 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8260 if (! sim_dflt_dev)
8261 return NULL;
8262 sim_dfdev = sim_dflt_dev;
8263 sim_dfunit = sim_dfdev->units;
8264 sim_opt_out = 0;
8265 *st = SCPE_OK;
8266 while (*cptr) {
8267 svptr = cptr;
8268 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8269 if (sim_ofile) {
8270 fclose (sim_ofile);
8271 *st = SCPE_ARG;
8272 return NULL;
8273 }
8274 cptr = get_glyph (cptr + 1, gbuf, 0);
8275 sim_ofile = sim_fopen (gbuf, "a");
8276 if (sim_ofile == NULL) {
8277 *st = SCPE_OPENERR;
8278 return NULL;
8279 }
8280 sim_opt_out |= CMD_OPT_OF;
8281 continue;
8282 }
8283 cptr = get_glyph (cptr, gbuf, 0);
8284 if ((t = get_switches (gbuf)) != 0) {
8285 if (t < 0) {
8286 *st = SCPE_INVSW;
8287 return NULL;
8288 }
8289 sim_switches = sim_switches | t;
8290 }
8291 else if ((opt & CMD_OPT_SCH) &&
8292 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8293 sim_schrptr = &sim_stabr;
8294 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8295 sim_opt_out |= CMD_OPT_SCH;
8296 }
8297 else if ((opt & CMD_OPT_DFT) &&
8298 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8299 (tdptr = find_unit (gbuf, &tuptr)) &&
8300 (tuptr != NULL)) {
8301 sim_dfdev = tdptr;
8302 sim_dfunit = tuptr;
8303 sim_opt_out |= CMD_OPT_DFT;
8304 }
8305 else return svptr;
8306 }
8307 return cptr;
8308 }
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8321 {
8322 char *optr = buf;
8323 int32 bit;
8324
8325 (void)memset (buf, 0, bufsize);
8326 if ((sw == 0) || (bufsize < 3))
8327 return buf;
8328 --bufsize;
8329 *optr++ = '-';
8330 for (bit=0; bit <= ('Z'-'A'); bit++)
8331 if (sw & (1 << bit))
8332 if ((size_t)(optr - buf) < bufsize)
8333 *optr++ = 'A' + bit;
8334 return buf;
8335 }
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8349 {
8350 int32 c;
8351 size_t logop, cmpop;
8352 t_value logval, cmpval;
8353 const char *sptr;
8354 CONST char *tptr;
8355 const char logstr[] = "|&^", cmpstr[] = "=!><";
8356
8357 const size_t invalid_op = (size_t) -1;
8358
8359 logval = cmpval = 0;
8360 if (*cptr == 0)
8361 return NULL;
8362
8363 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8364 if ((sptr = strchr (logstr, c))) {
8365 logop = sptr - logstr;
8366 logval = strtotv (cptr, &tptr, radix);
8367 if (cptr == tptr)
8368 return NULL;
8369 cptr = tptr;
8370 }
8371 else if ((sptr = strchr (cmpstr, c))) {
8372 cmpop = sptr - cmpstr;
8373 if (*cptr == '=') {
8374 cmpop = cmpop + strlen (cmpstr);
8375 cptr++;
8376 }
8377 cmpval = strtotv (cptr, &tptr, radix);
8378 if (cptr == tptr)
8379 return NULL;
8380 cptr = tptr;
8381 }
8382 else return NULL;
8383 }
8384 if (schptr->count != 1) {
8385 FREE (schptr->mask);
8386 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8387 FREE (schptr->comp);
8388 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8389 }
8390 if (logop != invalid_op) {
8391 schptr->logic = logop;
8392 schptr->mask[0] = logval;
8393 }
8394 if (cmpop != invalid_op) {
8395 schptr->boolop = cmpop;
8396 schptr->comp[0] = cmpval;
8397 }
8398 schptr->count = 1;
8399 return schptr;
8400 }
8401
8402
8403
8404
8405
8406
8407
8408
8409
8410
8411
8412
8413 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8414 {
8415 int32 c;
8416 size_t logop, cmpop;
8417 t_value *logval, *cmpval;
8418 t_stat reason = SCPE_OK;
8419 CONST char *ocptr = cptr;
8420 const char *sptr;
8421 char gbuf[CBUFSIZE];
8422 const char logstr[] = "|&^", cmpstr[] = "=!><";
8423
8424 const size_t invalid_op = (size_t) -1;
8425
8426 if (*cptr == 0)
8427 return NULL;
8428 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8429 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8430
8431 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8432 if (NULL != (sptr = strchr (logstr, c))) {
8433 logop = sptr - logstr;
8434 cptr = get_glyph (cptr, gbuf, 0);
8435 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8436 if (reason > 0) {
8437 FREE (logval);
8438 FREE (cmpval);
8439 return get_rsearch (ocptr, radix, schptr);
8440 }
8441 }
8442 else if (NULL != (sptr = strchr (cmpstr, c))) {
8443 cmpop = sptr - cmpstr;
8444 if (*cptr == '=') {
8445 cmpop = cmpop + strlen (cmpstr);
8446 cptr++;
8447 }
8448 cptr = get_glyph (cptr, gbuf, 0);
8449 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8450 if (reason > 0) {
8451 FREE (logval);
8452 FREE (cmpval);
8453 return get_rsearch (ocptr, radix, schptr);
8454 }
8455 }
8456 else {
8457 FREE (logval);
8458 FREE (cmpval);
8459 return NULL;
8460 }
8461 }
8462 if (schptr->count != (uint32)(1 - reason)) {
8463 schptr->count = 1 - reason;
8464 FREE (schptr->mask);
8465 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8466 FREE (schptr->comp);
8467 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8468 }
8469 if (logop != invalid_op) {
8470 schptr->logic = logop;
8471 FREE (schptr->mask);
8472 schptr->mask = logval;
8473 }
8474 else {
8475 FREE (logval);
8476 }
8477 if (cmpop != invalid_op) {
8478 schptr->boolop = cmpop;
8479 FREE (schptr->comp);
8480 schptr->comp = cmpval;
8481 }
8482 else {
8483 FREE (cmpval);
8484 }
8485 return schptr;
8486 }
8487
8488
8489
8490
8491
8492
8493
8494
8495
8496
8497 int32 test_search (t_value *values, SCHTAB *schptr)
8498 {
8499 t_value *val = NULL;
8500 int32 i, updown;
8501 int32 ret = 0;
8502
8503 if (schptr == NULL)
8504 return ret;
8505
8506 val = (t_value *)malloc (schptr->count * sizeof (*values));
8507 if (!val)
8508 {
8509 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8510 __func__, __FILE__, __LINE__);
8511 #if defined(USE_BACKTRACE)
8512 # if defined(SIGUSR2)
8513 (void)raise(SIGUSR2);
8514
8515 # endif
8516 #endif
8517 abort();
8518 }
8519 for (i=0; i<(int32)schptr->count; i++) {
8520 val[i] = values[i];
8521 switch (schptr->logic) {
8522
8523 case SCH_OR:
8524 val[i] = val[i] | schptr->mask[i];
8525 break;
8526
8527 case SCH_AND:
8528 val[i] = val[i] & schptr->mask[i];
8529 break;
8530
8531 case SCH_XOR:
8532 val[i] = val[i] ^ schptr->mask[i];
8533 break;
8534 }
8535 }
8536
8537 ret = 1;
8538 if (1) {
8539 updown = -1;
8540 i=schptr->count-1;
8541 }
8542 else {
8543 updown = 1;
8544 i=0;
8545 }
8546 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8547 switch (schptr->boolop) {
8548
8549 case SCH_E: case SCH_EE:
8550 if (val[i] != schptr->comp[i])
8551 ret = 0;
8552 break;
8553
8554 case SCH_N: case SCH_NE:
8555 if (val[i] == schptr->comp[i])
8556 ret = 0;
8557 break;
8558
8559 case SCH_G:
8560 if (val[i] <= schptr->comp[i])
8561 ret = 0;
8562 break;
8563
8564 case SCH_GE:
8565 if (val[i] < schptr->comp[i])
8566 ret = 0;
8567 break;
8568
8569 case SCH_L:
8570 if (val[i] >= schptr->comp[i])
8571 ret = 0;
8572 break;
8573
8574 case SCH_LE:
8575 if (val[i] > schptr->comp[i])
8576 ret = 0;
8577 break;
8578 }
8579 }
8580 FREE (val);
8581 return ret;
8582 }
8583
8584
8585
8586
8587
8588
8589
8590
8591
8592
8593
8594
8595
8596
8597
8598 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8599 {
8600 int32 nodigit;
8601 t_value val;
8602 uint32 c, digit;
8603
8604 *endptr = inptr;
8605 if ((radix < 2) || (radix > 36))
8606 return 0;
8607 while (sim_isspace (*inptr))
8608 inptr++;
8609 val = 0;
8610 nodigit = 1;
8611 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8612 if (sim_islower (c))
8613 c = toupper (c);
8614 if (sim_isdigit (c))
8615 digit = c - (uint32) '0';
8616 else if (radix <= 10)
8617 break;
8618 else digit = c + 10 - (uint32) 'A';
8619 if (digit >= radix)
8620 return 0;
8621 val = (val * radix) + digit;
8622 nodigit = 0;
8623 }
8624 if (nodigit)
8625 return 0;
8626 *endptr = inptr;
8627 return val;
8628 }
8629
8630
8631
8632
8633
8634
8635
8636
8637
8638
8639
8640
8641
8642
8643
8644 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8645 size_t width, uint32 format)
8646 {
8647 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8648 t_value owtest, wtest;
8649 size_t d;
8650 size_t digit;
8651 size_t ndigits;
8652 size_t commas = 0;
8653 char dbuf[MAX_WIDTH + 1];
8654
8655 for (d = 0; d < MAX_WIDTH; d++)
8656 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8657 dbuf[MAX_WIDTH] = 0;
8658 d = MAX_WIDTH;
8659 do {
8660 d = d - 1;
8661 digit = val % radix;
8662 val = val / radix;
8663 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8664 } while ((d > 0) && (val != 0));
8665
8666 switch (format) {
8667 case PV_LEFT:
8668 break;
8669 case PV_RZRO:
8670 wtest = owtest = radix;
8671 ndigits = 1;
8672 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8673 owtest = wtest;
8674 wtest = wtest * radix;
8675 ndigits = ndigits + 1;
8676 }
8677 if ((MAX_WIDTH - (ndigits + commas)) < d)
8678 d = MAX_WIDTH - (ndigits + commas);
8679 break;
8680 }
8681 if (NULL == buffer)
8682 return ((t_stat) strlen(dbuf+d));
8683 *buffer = '\0';
8684 if (width < strlen(dbuf+d))
8685 return SCPE_IOERR;
8686 strcpy(buffer, dbuf+d);
8687 return SCPE_OK;
8688 }
8689
8690 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8691 uint32 width, uint32 format)
8692 {
8693 char dbuf[MAX_WIDTH + 1];
8694
8695 if (!stream)
8696 return sprint_val (NULL, val, radix, width, format);
8697 if (width > MAX_WIDTH)
8698 width = MAX_WIDTH;
8699 sprint_val (dbuf, val, radix, width, format);
8700 if (Fprintf (stream, "%s", dbuf) < 0)
8701 return SCPE_IOERR;
8702 return SCPE_OK;
8703 }
8704
8705 const char *sim_fmt_secs (double seconds)
8706 {
8707 static char buf[60];
8708 char frac[16] = "";
8709 const char *sign = "";
8710 double val = seconds;
8711 double days, hours, mins, secs, msecs, usecs;
8712
8713 if (val == 0.0)
8714 return "";
8715 if (val < 0.0) {
8716 sign = "-";
8717 val = -val;
8718 }
8719 days = floor (val / (24.0*60.0*60.0));
8720 val -= (days * 24.0*60.0*60.0);
8721 hours = floor (val / (60.0*60.0));
8722 val -= (hours * 60.0 * 60.0);
8723 mins = floor (val / 60.0);
8724 val -= (mins * 60.0);
8725 secs = floor (val);
8726 val -= secs;
8727 val *= 1000.0;
8728 msecs = floor (val);
8729 val -= msecs;
8730 val *= 1000.0;
8731 usecs = floor (val+0.5);
8732 if (usecs == 1000.0) {
8733 usecs = 0.0;
8734 msecs += 1;
8735 }
8736 if ((msecs > 0.0) || (usecs > 0.0)) {
8737 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8738 while (frac[strlen (frac) - 1] == '0')
8739 frac[strlen (frac) - 1] = '\0';
8740 if (strlen (frac) == 1)
8741 frac[0] = '\0';
8742 }
8743 if (days > 0)
8744 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8745 sign, days, (days != 1) ? "s" : "", hours, mins,
8746 secs, frac, (days == 1) ? "s" : "");
8747 else
8748 if (hours > 0)
8749 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8750 sign, hours, mins, secs, frac);
8751 else
8752 if (mins > 0)
8753 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8754 sign, mins, secs, frac);
8755 else
8756 if (secs > 0)
8757 (void)sprintf (buf, "%s%.0f%s second",
8758 sign, secs, frac);
8759 else
8760 if (msecs > 0) {
8761 if (usecs > 0)
8762 (void)sprintf (buf, "%s%.0f.%s msec",
8763 sign, msecs, frac+4);
8764 else
8765 (void)sprintf (buf, "%s%.0f msec",
8766 sign, msecs);
8767 }
8768 else
8769 (void)sprintf (buf, "%s%.0f usec",
8770 sign, usecs);
8771 if (0 != strncmp ("1 ", buf, 2))
8772 strcpy (&buf[strlen (buf)], "s");
8773 return buf;
8774 }
8775
8776
8777
8778
8779
8780
8781
8782
8783
8784
8785
8786
8787
8788
8789
8790
8791 t_stat sim_process_event (void)
8792 {
8793 UNIT *uptr;
8794 t_stat reason;
8795 #if defined(TESTING)
8796 cpu_state_t * cpup = _cpup;
8797 #endif
8798
8799 if (stop_cpu)
8800 {
8801 #if defined(WIN_STDIO)
8802 (void)fflush(stdout);
8803 (void)fflush(stderr);
8804 #endif
8805 return SCPE_STOP;
8806 }
8807 UPDATE_SIM_TIME;
8808
8809 if (sim_clock_queue == QUEUE_LIST_END) {
8810 sim_interval = noqueue_time = NOQUEUE_WAIT;
8811 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8812 "Queue Empty New Interval = %d\n",
8813 sim_interval);
8814 return SCPE_OK;
8815 }
8816 sim_processing_event = TRUE;
8817 do {
8818 uptr = sim_clock_queue;
8819 sim_clock_queue = uptr->next;
8820 uptr->next = NULL;
8821 sim_interval -= uptr->time;
8822 uptr->time = 0;
8823 if (sim_clock_queue != QUEUE_LIST_END)
8824 sim_interval = sim_clock_queue->time;
8825 else
8826 sim_interval = noqueue_time = NOQUEUE_WAIT;
8827 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8828 "Processing Event for %s\n", sim_uname (uptr));
8829 if (uptr->action != NULL)
8830 reason = uptr->action (uptr);
8831 else
8832 reason = SCPE_OK;
8833 } while ((reason == SCPE_OK) &&
8834 (sim_interval <= 0) &&
8835 (sim_clock_queue != QUEUE_LIST_END) &&
8836 (!stop_cpu));
8837
8838 if (sim_clock_queue == QUEUE_LIST_END) {
8839 sim_interval = noqueue_time = NOQUEUE_WAIT;
8840 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8841 "Processing Queue Complete New Interval = %d\n",
8842 sim_interval);
8843 }
8844 else
8845 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8846 "Processing Queue Complete New Interval = %d(%s)\n",
8847 sim_interval, sim_uname(sim_clock_queue));
8848
8849 if ((reason == SCPE_OK) && stop_cpu)
8850 {
8851 #if defined(WIN_STDIO)
8852 (void)fflush(stdout);
8853 (void)fflush(stderr);
8854 #endif
8855 reason = SCPE_STOP;
8856 }
8857 sim_processing_event = FALSE;
8858 return reason;
8859 }
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869
8870 t_stat sim_activate (UNIT *uptr, int32 event_time)
8871 {
8872 if (uptr->dynflags & UNIT_TMR_UNIT)
8873 return sim_timer_activate (uptr, event_time);
8874 return _sim_activate (uptr, event_time);
8875 }
8876
8877 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8878 {
8879 UNIT *cptr, *prvptr;
8880 int32 accum;
8881 #if defined(TESTING)
8882 cpu_state_t * cpup = _cpup;
8883 #endif
8884
8885 if (sim_is_active (uptr))
8886 return SCPE_OK;
8887 UPDATE_SIM_TIME;
8888
8889 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\n", sim_uname (uptr), event_time);
8890
8891 prvptr = NULL;
8892 accum = 0;
8893 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8894 if (event_time < (accum + cptr->time))
8895 break;
8896 accum = accum + cptr->time;
8897 prvptr = cptr;
8898 }
8899 if (prvptr == NULL) {
8900 cptr = uptr->next = sim_clock_queue;
8901 sim_clock_queue = uptr;
8902 }
8903 else {
8904 cptr = uptr->next = prvptr->next;
8905 prvptr->next = uptr;
8906 }
8907 uptr->time = event_time - accum;
8908 if (cptr != QUEUE_LIST_END)
8909 cptr->time = cptr->time - uptr->time;
8910 sim_interval = sim_clock_queue->time;
8911 return SCPE_OK;
8912 }
8913
8914
8915
8916
8917
8918
8919
8920
8921
8922
8923 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
8924 {
8925 sim_cancel (uptr);
8926 return _sim_activate (uptr, event_time);
8927 }
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
8939 {
8940 return _sim_activate_after (uptr, usec_delay);
8941 }
8942
8943 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
8944 {
8945 if (sim_is_active (uptr))
8946 return SCPE_OK;
8947 return sim_timer_activate_after (uptr, usec_delay);
8948 }
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959 t_stat sim_cancel (UNIT *uptr)
8960 {
8961 UNIT *cptr, *nptr;
8962 #if defined(TESTING)
8963 cpu_state_t * cpup = _cpup;
8964 #endif
8965
8966 if (sim_clock_queue == QUEUE_LIST_END)
8967 return SCPE_OK;
8968 if (!sim_is_active (uptr))
8969 return SCPE_OK;
8970 UPDATE_SIM_TIME;
8971 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr));
8972 nptr = QUEUE_LIST_END;
8973
8974 if (sim_clock_queue == uptr) {
8975 nptr = sim_clock_queue = uptr->next;
8976 uptr->next = NULL;
8977 }
8978 else {
8979 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8980 if (cptr->next == uptr) {
8981 nptr = cptr->next = uptr->next;
8982 uptr->next = NULL;
8983 break;
8984 }
8985 }
8986 }
8987 if (nptr != QUEUE_LIST_END)
8988 nptr->time += (uptr->next) ? 0 : uptr->time;
8989 if (!uptr->next)
8990 uptr->time = 0;
8991 if (sim_clock_queue != QUEUE_LIST_END)
8992 sim_interval = sim_clock_queue->time;
8993 else sim_interval = noqueue_time = NOQUEUE_WAIT;
8994 if (uptr->next) {
8995 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
8996 if (sim_deb)
8997 fclose(sim_deb);
8998 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
8999 __func__, __FILE__, __LINE__);
9000 abort ();
9001 }
9002 return SCPE_OK;
9003 }
9004
9005
9006
9007
9008
9009
9010
9011
9012
9013 t_bool sim_is_active (UNIT *uptr)
9014 {
9015 if (uptr->next == NULL)
9016 return FALSE;
9017 else
9018 return TRUE;
9019 }
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029 int32 sim_activate_time (UNIT *uptr)
9030 {
9031 UNIT *cptr;
9032 int32 accum = 0;
9033
9034 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9035 if (cptr == sim_clock_queue) {
9036 if (sim_interval > 0)
9037 accum = accum + sim_interval;
9038 }
9039 else
9040 accum = accum + cptr->time;
9041 if (cptr == uptr)
9042 return accum + 1;
9043 }
9044 return 0;
9045 }
9046
9047
9048
9049
9050
9051
9052
9053
9054 double sim_gtime (void)
9055 {
9056 return sim_time;
9057 }
9058
9059
9060
9061
9062
9063
9064
9065
9066 int32 sim_qcount (void)
9067 {
9068 int32 cnt;
9069 UNIT *uptr;
9070
9071 cnt = 0;
9072 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9073 cnt++;
9074 return cnt;
9075 }
9076
9077
9078
9079
9080
9081
9082
9083
9084
9085
9086
9087
9088
9089
9090
9091
9092
9093
9094
9095
9096
9097
9098
9099
9100
9101
9102
9103
9104
9105
9106
9107
9108
9109
9110
9111
9112 t_stat sim_brk_init (void)
9113 {
9114 int32 i;
9115
9116 for (i=0; i<sim_brk_lnt; i++) {
9117 BRKTAB *bp;
9118 if (sim_brk_tab)
9119 {
9120 bp = sim_brk_tab[i];
9121
9122 while (bp)
9123 {
9124 BRKTAB *bpt = bp->next;
9125
9126 FREE (bp->act);
9127 FREE (bp);
9128 bp = bpt;
9129 }
9130 }
9131 }
9132 if (sim_brk_tab != NULL)
9133 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9134 sim_brk_lnt = SIM_BRK_INILNT;
9135 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9136 if (sim_brk_tab == NULL)
9137 return SCPE_MEM;
9138 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9139 sim_brk_ent = sim_brk_ins = 0;
9140 sim_brk_clract ();
9141 sim_brk_npc (0);
9142 return SCPE_OK;
9143 }
9144
9145
9146
9147 BRKTAB *sim_brk_fnd (t_addr loc)
9148 {
9149 int32 lo, hi, p;
9150 BRKTAB *bp;
9151
9152 if (sim_brk_ent == 0) {
9153 sim_brk_ins = 0;
9154 return NULL;
9155 }
9156 lo = 0;
9157 hi = sim_brk_ent - 1;
9158 do {
9159 p = (lo + hi) >> 1;
9160 bp = sim_brk_tab[p];
9161 if (loc == bp->addr) {
9162 sim_brk_ins = p;
9163 return bp;
9164 }
9165 else if (loc < bp->addr)
9166 hi = p - 1;
9167 else lo = p + 1;
9168 } while (lo <= hi);
9169 if (loc < bp->addr)
9170 sim_brk_ins = p;
9171 else sim_brk_ins = p + 1;
9172 return NULL;
9173 }
9174
9175 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9176 {
9177 BRKTAB *bp = sim_brk_fnd (loc);
9178
9179 while (bp) {
9180 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9181 (bp->typ == btyp))
9182 return bp;
9183 bp = bp->next;
9184 }
9185 return bp;
9186 }
9187
9188
9189
9190 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9191 {
9192 int32 i, t;
9193 BRKTAB *bp, **newp;
9194
9195 if (sim_brk_ins < 0)
9196 return NULL;
9197 if (sim_brk_ent >= sim_brk_lnt) {
9198 t = sim_brk_lnt + SIM_BRK_INILNT;
9199 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9200 if (newp == NULL)
9201 return NULL;
9202 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9203 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9204 FREE (sim_brk_tab);
9205 sim_brk_tab = newp;
9206 sim_brk_lnt = t;
9207 }
9208 if ((sim_brk_ins == sim_brk_ent) ||
9209 ((sim_brk_ins != sim_brk_ent) &&
9210 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9211 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9212 sim_brk_tab[i] = sim_brk_tab[i - 1];
9213 sim_brk_tab[sim_brk_ins] = NULL;
9214 }
9215 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9216 if (!bp)
9217 {
9218 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9219 __func__, __FILE__, __LINE__);
9220 #if defined(USE_BACKTRACE)
9221 # if defined(SIGUSR2)
9222 (void)raise(SIGUSR2);
9223
9224 # endif
9225 #endif
9226 abort();
9227 }
9228 bp->next = sim_brk_tab[sim_brk_ins];
9229 sim_brk_tab[sim_brk_ins] = bp;
9230 if (bp->next == NULL)
9231 sim_brk_ent += 1;
9232 bp->addr = loc;
9233 bp->typ = btyp;
9234 bp->cnt = 0;
9235 bp->act = NULL;
9236 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9237 bp->time_fired[i] = -1.0;
9238 return bp;
9239 }
9240
9241
9242
9243 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9244 {
9245 BRKTAB *bp;
9246
9247 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9248 sw |= sim_brk_dflt;
9249 if (~sim_brk_types & sw) {
9250 char gbuf[CBUFSIZE];
9251
9252 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9253 }
9254 if ((sw & BRK_TYP_DYN_ALL) && act)
9255 return SCPE_ARG;
9256 bp = sim_brk_fnd (loc);
9257 if (!bp)
9258 bp = sim_brk_new (loc, sw);
9259 else {
9260 while (bp && (bp->typ != (uint32)sw))
9261 bp = bp->next;
9262 if (!bp)
9263 bp = sim_brk_new (loc, sw);
9264 }
9265 if (!bp)
9266 return SCPE_MEM;
9267 bp->cnt = ncnt;
9268 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9269 (bp->act != NULL) && (act != NULL)) {
9270 FREE (bp->act);
9271 bp->act = NULL;
9272 }
9273 if ((act != NULL) && (*act != 0)) {
9274 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9275 if (newp == NULL)
9276 return SCPE_MEM;
9277 strncpy (newp, act, CBUFSIZE);
9278 bp->act = newp;
9279 }
9280 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9281 return SCPE_OK;
9282 }
9283
9284
9285
9286 t_stat sim_brk_clr (t_addr loc, int32 sw)
9287 {
9288 BRKTAB *bpl = NULL;
9289 BRKTAB *bp = sim_brk_fnd (loc);
9290 int32 i;
9291
9292 if (!bp)
9293 return SCPE_OK;
9294 if (sw == 0)
9295 sw = SIM_BRK_ALLTYP;
9296
9297 #if !defined(__clang_analyzer__)
9298 while (bp) {
9299 if (bp->typ == (bp->typ & sw)) {
9300 FREE (bp->act);
9301 if (bp == sim_brk_tab[sim_brk_ins])
9302 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9303 else
9304 {
9305 if (bpl)
9306 bpl->next = bp->next;
9307 }
9308 FREE (bp);
9309 bp = bpl;
9310 }
9311 else {
9312 bpl = bp;
9313 bp = bp->next;
9314 }
9315 }
9316 #endif
9317 if (sim_brk_tab[sim_brk_ins] == NULL) {
9318 sim_brk_ent = sim_brk_ent - 1;
9319 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9320 sim_brk_tab[i] = sim_brk_tab[i+1];
9321 }
9322 sim_brk_summ = 0;
9323 for (i = 0; i < sim_brk_ent; i++) {
9324 bp = sim_brk_tab[i];
9325 while (bp) {
9326 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9327 bp = bp->next;
9328 }
9329 }
9330 return SCPE_OK;
9331 }
9332
9333
9334
9335 t_stat sim_brk_clrall (int32 sw)
9336 {
9337 int32 i;
9338
9339 if (sw == 0)
9340 sw = SIM_BRK_ALLTYP;
9341 for (i = 0; i < sim_brk_ent;) {
9342 t_addr loc = sim_brk_tab[i]->addr;
9343 sim_brk_clr (loc, sw);
9344 if ((i < sim_brk_ent) &&
9345 (loc == sim_brk_tab[i]->addr))
9346 ++i;
9347 }
9348 return SCPE_OK;
9349 }
9350
9351
9352
9353 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9354 {
9355 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9356 DEVICE *dptr;
9357 uint32 i, any;
9358
9359 if ((sw == 0) || (sw == SWMASK ('C'))) {
9360 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9361 if (!bp || (!(bp->typ & sw))) {
9362 return SCPE_OK; }
9363 dptr = sim_dflt_dev;
9364 if (dptr == NULL) {
9365 return SCPE_OK; }
9366 if (sw & SWMASK ('C')) {
9367 if (st != NULL) {
9368 (void)fprintf (st, "SET BREAK "); }
9369 } else {
9370 if (sim_vm_fprint_addr) {
9371 sim_vm_fprint_addr
9372 (st, dptr, loc);
9373 } else {
9374 fprint_val
9375 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9376 if (st != NULL) {
9377 (void)fprintf (st, ":\t"); }
9378 }
9379 for (i = any = 0; i < 26; i++) {
9380 if ((bp->typ >> i) & 1) {
9381 if ((sw & SWMASK ('C')) == 0) {
9382 if (any) {
9383 if (st != NULL) {
9384 (void)fprintf (st, ", "); } }
9385 if (st != NULL) {
9386 fputc (i + 'A', st); }
9387 }
9388 } else {
9389 if (st != NULL) {
9390 (void)fprintf (st, "-%c", i + 'A'); }
9391 any = 1;
9392 }
9393 }
9394 if (sw & SWMASK ('C')) {
9395 if (st != NULL) {
9396 (void)fprintf (st, " "); }
9397 if (sim_vm_fprint_addr) {
9398 if (st != NULL) {
9399 sim_vm_fprint_addr (st, dptr, loc); }
9400 } else {
9401 fprint_val
9402 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9403 }
9404 if (bp->cnt > 0) {
9405 if (st != NULL) {
9406 (void)fprintf (st, "[%d]", bp->cnt); } }
9407 if (bp->act != NULL) {
9408 if (st != NULL) {
9409 (void)fprintf (st, "; %s", bp->act); } }
9410 (void)fprintf (st, "\n");
9411 return SCPE_OK;
9412 }
9413
9414
9415
9416 t_stat sim_brk_showall (FILE *st, uint32 sw)
9417 {
9418 int32 bit, mask, types;
9419 BRKTAB **bpt;
9420
9421 if ((sw == 0) || (sw == SWMASK ('C')))
9422 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9423 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9424 if (sim_brk_types & (1 << bit))
9425 ++types;
9426 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9427 (void)fprintf (st, "Supported Breakpoint Types:");
9428 for (bit=0; bit <= ('Z'-'A'); bit++)
9429 if (sim_brk_types & (1 << bit))
9430 (void)fprintf (st, " -%c", 'A' + bit);
9431 (void)fprintf (st, "\n");
9432 }
9433 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9434 mask = (sw & sim_brk_types);
9435 (void)fprintf (st, "Displaying Breakpoint Types:");
9436 for (bit=0; bit <= ('Z'-'A'); bit++)
9437 if (mask & (1 << bit))
9438 (void)fprintf (st, " -%c", 'A' + bit);
9439 (void)fprintf (st, "\n");
9440 }
9441 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9442 BRKTAB *prev = NULL;
9443 BRKTAB *cur = *bpt;
9444 BRKTAB *next;
9445
9446 while (cur) {
9447 next = cur->next;
9448 cur->next = prev;
9449 prev = cur;
9450 cur = next;
9451 }
9452
9453 *bpt = prev;
9454
9455 cur = prev;
9456 while (cur) {
9457 if (cur->typ & sw)
9458 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9459 cur = cur->next;
9460 }
9461
9462 cur = prev;
9463 prev = NULL;
9464 while (cur) {
9465 next = cur->next;
9466 cur->next = prev;
9467 prev = cur;
9468 cur = next;
9469 }
9470
9471 *bpt = prev;
9472 }
9473 return SCPE_OK;
9474 }
9475
9476
9477
9478 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9479 {
9480 BRKTAB *bp;
9481 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9482
9483 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9484 btyp |= BRK_TYP_DYN_ALL;
9485
9486 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9487 double s_gtime = sim_gtime ();
9488
9489 if (bp->time_fired[spc] == s_gtime)
9490 return 0;
9491 bp->time_fired[spc] = s_gtime;
9492 if (--bp->cnt > 0)
9493 return 0;
9494 bp->cnt = 0;
9495 sim_brk_setact (bp->act);
9496 sim_brk_match_type = btyp & bp->typ;
9497 if (bp->typ & BRK_TYP_TEMP)
9498 sim_brk_clr (loc, bp->typ);
9499 sim_brk_match_addr = loc;
9500 return sim_brk_match_type;
9501 }
9502 return 0;
9503 }
9504
9505
9506
9507 CONST char *sim_brk_getact (char *buf, int32 size)
9508 {
9509 char *ep;
9510 size_t lnt;
9511
9512 if (sim_brk_act[sim_do_depth] == NULL)
9513 return NULL;
9514 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9515 sim_brk_act[sim_do_depth]++;
9516 if (*sim_brk_act[sim_do_depth] == 0) {
9517 return sim_brk_clract ();
9518 }
9519 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9520 lnt = ep - sim_brk_act[sim_do_depth];
9521 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9522 buf[lnt] = 0;
9523 sim_brk_act[sim_do_depth] += lnt + 1;
9524 }
9525 else {
9526 strncpy (buf, sim_brk_act[sim_do_depth], size);
9527 sim_brk_clract ();
9528 }
9529 return buf;
9530 }
9531
9532
9533
9534 char *sim_brk_clract (void)
9535 {
9536 FREE (sim_brk_act_buf[sim_do_depth]);
9537 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9538 }
9539
9540
9541
9542 void sim_brk_setact (const char *action)
9543 {
9544 if (action) {
9545 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9546 if (!sim_brk_act_buf[sim_do_depth])
9547 {
9548 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9549 __func__, __FILE__, __LINE__);
9550 #if defined(USE_BACKTRACE)
9551 # if defined(SIGUSR2)
9552 (void)raise(SIGUSR2);
9553
9554 # endif
9555 #endif
9556 abort();
9557 }
9558 strcpy (sim_brk_act_buf[sim_do_depth], action);
9559 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9560 }
9561 else
9562 sim_brk_clract ();
9563 }
9564
9565
9566
9567 void sim_brk_npc (uint32 cnt)
9568 {
9569 uint32 spc;
9570 BRKTAB **bpt, *bp;
9571
9572 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9573 cnt = SIM_BKPT_N_SPC;
9574 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9575 for (bp = *bpt; bp; bp = bp->next) {
9576 for (spc = 0; spc < cnt; spc++)
9577 bp->time_fired[spc] = -1.0;
9578 }
9579 }
9580 }
9581
9582
9583
9584 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9585 {
9586 BRKTAB **bpt, *bp;
9587
9588 if (spc < SIM_BKPT_N_SPC) {
9589 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9590 for (bp = *bpt; bp; bp = bp->next) {
9591 if (bp->typ & btyp)
9592 bp->time_fired[spc] = -1.0;
9593 }
9594 }
9595 }
9596 }
9597
9598 const char *sim_brk_message(void)
9599 {
9600 static char msg[256];
9601 char addr[65] = "";
9602 char buf[32];
9603
9604 msg[0] = '\0';
9605 if (sim_dflt_dev) {
9606 if (sim_vm_sprint_addr)
9607 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9608 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9609 }
9610 if (sim_brk_type_desc) {
9611 BRKTYPTAB *brk = sim_brk_type_desc;
9612
9613 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9614 if (brk->btyp == sim_brk_match_type) {
9615 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9616 break;
9617 }
9618 brk++;
9619 }
9620 }
9621 if (!msg[0])
9622 (void)sprintf (msg, "%s Breakpoint at: %s\n",
9623 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9624
9625 return msg;
9626 }
9627
9628
9629
9630
9631
9632
9633
9634
9635
9636
9637
9638
9639
9640
9641
9642
9643
9644
9645
9646
9647
9648
9649
9650
9651
9652
9653
9654
9655
9656
9657
9658
9659
9660
9661
9662
9663
9664 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9665 {
9666 char gbuf[CBUFSIZE];
9667 CONST char *tptr;
9668 CONST char *c1ptr;
9669 t_bool after_set = FALSE;
9670 uint32 after;
9671 int32 cnt = 0;
9672 t_stat r;
9673
9674 if (exp == NULL)
9675 return sim_messagef (SCPE_ARG, "Null exp!\n");
9676 after = exp->after;
9677
9678 if ((cptr == NULL) || (*cptr == 0))
9679 return SCPE_2FARG;
9680 if (*cptr == '[') {
9681 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9682 if ((cptr == c1ptr) || (*c1ptr != ']'))
9683 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n");
9684 cptr = c1ptr + 1;
9685 while (sim_isspace(*cptr))
9686 ++cptr;
9687 }
9688 tptr = get_glyph (cptr, gbuf, ',');
9689 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9690 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9691 if (r != SCPE_OK)
9692 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n");
9693 after_set = TRUE;
9694 cptr = tptr;
9695 }
9696 if ((*cptr != '"') && (*cptr != '\''))
9697 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9698 cptr = get_glyph_quoted (cptr, gbuf, 0);
9699
9700 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9701 }
9702
9703
9704
9705 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9706 {
9707 char gbuf[CBUFSIZE];
9708
9709 if (NULL == cptr || !*cptr)
9710 return sim_exp_clrall (exp);
9711 if ((*cptr != '"') && (*cptr != '\''))
9712 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9713 cptr = get_glyph_quoted (cptr, gbuf, 0);
9714 if (*cptr != '\0')
9715 return SCPE_2MARG;
9716 return sim_exp_clr (exp, gbuf);
9717 }
9718
9719
9720
9721 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9722 {
9723 size_t i;
9724
9725 if (NULL == exp->rules)
9726 return NULL;
9727 for (i=start_rule; i<exp->size; i++)
9728 if (!strcmp (exp->rules[i].match_pattern, match))
9729 return &exp->rules[i];
9730 return NULL;
9731 }
9732
9733
9734
9735 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9736 {
9737 size_t i;
9738
9739 if (NULL == ep)
9740 return SCPE_OK;
9741 FREE (ep->match);
9742 FREE (ep->match_pattern);
9743 FREE (ep->act);
9744 exp->size -= 1;
9745 #if !defined(__clang_analyzer__)
9746 for (i=ep-exp->rules; i<exp->size; i++)
9747 exp->rules[i] = exp->rules[i+1];
9748 if (exp->size == 0) {
9749 FREE (exp->rules);
9750 exp->rules = NULL;
9751 }
9752 #endif
9753 return SCPE_OK;
9754 }
9755
9756 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9757 {
9758 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9759
9760 while (ep) {
9761 sim_exp_clr_tab (exp, ep);
9762 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9763 }
9764 return SCPE_OK;
9765 }
9766
9767
9768
9769 t_stat sim_exp_clrall (EXPECT *exp)
9770 {
9771 int32 i;
9772
9773 for (i=0; i<exp->size; i++) {
9774 FREE (exp->rules[i].match);
9775 FREE (exp->rules[i].match_pattern);
9776 FREE (exp->rules[i].act);
9777 }
9778 FREE (exp->rules);
9779 exp->rules = NULL;
9780 exp->size = 0;
9781 FREE (exp->buf);
9782 exp->buf = NULL;
9783 exp->buf_size = 0;
9784 exp->buf_ins = 0;
9785 return SCPE_OK;
9786 }
9787
9788
9789
9790 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9791 {
9792 EXPTAB *ep;
9793 uint8 *match_buf;
9794 uint32 match_size;
9795 size_t i;
9796
9797
9798 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9799 if (!match_buf)
9800 return SCPE_MEM;
9801 if (switches & EXP_TYP_REGEX) {
9802 FREE (match_buf);
9803 return sim_messagef (SCPE_ARG, "RegEx support not available\n");
9804 }
9805 else {
9806 if (switches & EXP_TYP_REGEX_I) {
9807 FREE (match_buf);
9808 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\n");
9809 }
9810 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9811 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9812 FREE (match_buf);
9813 return sim_messagef (SCPE_ARG, "Invalid quoted string\n");
9814 }
9815 }
9816 FREE (match_buf);
9817 for (i=0; i<exp->size; i++) {
9818 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9819 (exp->rules[i].switches & EXP_TYP_PERSIST))
9820 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n");
9821 }
9822 if (after && exp->size)
9823 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n");
9824 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9825 if (!exp->rules)
9826 {
9827 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9828 __func__, __FILE__, __LINE__);
9829 #if defined(USE_BACKTRACE)
9830 # if defined(SIGUSR2)
9831 (void)raise(SIGUSR2);
9832
9833 # endif
9834 #endif
9835 abort();
9836 }
9837 ep = &exp->rules[exp->size];
9838 exp->size += 1;
9839 exp->after = after;
9840 (void)memset (ep, 0, sizeof(*ep));
9841 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9842 if (ep->match_pattern)
9843 strcpy (ep->match_pattern, match);
9844 ep->cnt = cnt;
9845 ep->switches = switches;
9846 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9847 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9848 sim_exp_clr_tab (exp, ep);
9849 FREE (match_buf);
9850 return SCPE_MEM;
9851 }
9852 if (switches & EXP_TYP_REGEX) {
9853 FREE (match_buf);
9854 match_buf = NULL;
9855 }
9856 else {
9857 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9858 sim_decode_quoted_string (match, match_buf, &match_size);
9859 ep->match = match_buf;
9860 ep->size = match_size;
9861 }
9862 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9863 if (!ep->match_pattern)
9864 {
9865 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9866 __func__, __FILE__, __LINE__);
9867 #if defined(USE_BACKTRACE)
9868 # if defined(SIGUSR2)
9869 (void)raise(SIGUSR2);
9870
9871 # endif
9872 #endif
9873 abort();
9874 }
9875 strcpy (ep->match_pattern, match);
9876 if (ep->act) {
9877 FREE (ep->act);
9878 ep->act = NULL;
9879 }
9880 if (act) while (sim_isspace(*act)) ++act;
9881 if ((act != NULL) && (*act != 0)) {
9882 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9883 if (newp == NULL)
9884 return SCPE_MEM;
9885 strcpy (newp, act);
9886 ep->act = newp;
9887 }
9888
9889 for (i=0; i<exp->size; i++) {
9890 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9891 if (compare_size >= exp->buf_size) {
9892 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
9893 exp->buf_size = compare_size + 1;
9894 }
9895 }
9896 return SCPE_OK;
9897 }
9898
9899
9900
9901 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
9902 {
9903 if (!ep)
9904 return SCPE_OK;
9905 (void)fprintf (st, "EXPECT");
9906 if (ep->switches & EXP_TYP_PERSIST)
9907 (void)fprintf (st, " -p");
9908 if (ep->switches & EXP_TYP_CLEARALL)
9909 (void)fprintf (st, " -c");
9910 if (ep->switches & EXP_TYP_REGEX)
9911 (void)fprintf (st, " -r");
9912 if (ep->switches & EXP_TYP_REGEX_I)
9913 (void)fprintf (st, " -i");
9914 (void)fprintf (st, " %s", ep->match_pattern);
9915 if (ep->cnt > 0)
9916 (void)fprintf (st, " [%d]", ep->cnt);
9917 if (ep->act)
9918 (void)fprintf (st, " %s", ep->act);
9919 (void)fprintf (st, "\n");
9920 return SCPE_OK;
9921 }
9922
9923 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
9924 {
9925 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9926
9927 if (exp->buf_size) {
9928 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9929
9930 (void)fprintf (st, "Match Buffer Size: %lld\n",
9931 (long long)exp->buf_size);
9932 (void)fprintf (st, "Buffer Insert Offset: %lld\n",
9933 (long long)exp->buf_ins);
9934 (void)fprintf (st, "Buffer Contents: %s\n",
9935 bstr);
9936 FREE (bstr);
9937 }
9938 if (exp->after)
9939 (void)fprintf (st, "Halt After: %lld instructions\n",
9940 (long long)exp->after);
9941 if (exp->dptr && exp->dbit)
9942 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
9943 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
9944 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9945 (void)fprintf (st, "Match Rules:\n");
9946 if (!*match)
9947 return sim_exp_showall (st, exp);
9948 if (!ep) {
9949 (void)fprintf (st, "No Rules match '%s'\n", match);
9950 return SCPE_ARG;
9951 }
9952 do {
9953 sim_exp_show_tab (st, exp, ep);
9954 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9955 } while (ep);
9956 return SCPE_OK;
9957 }
9958
9959
9960
9961 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
9962 {
9963 size_t i;
9964
9965 for (i=0; i < exp->size; i++)
9966 sim_exp_show_tab (st, exp, &exp->rules[i]);
9967 return SCPE_OK;
9968 }
9969
9970
9971
9972 t_stat sim_exp_check (EXPECT *exp, uint8 data)
9973 {
9974 size_t i;
9975 EXPTAB *ep = NULL;
9976 char *tstr = NULL;
9977 #if defined(TESTING)
9978 cpu_state_t * cpup = _cpup;
9979 #endif
9980
9981 if ((!exp) || (!exp->rules))
9982 return SCPE_OK;
9983
9984 exp->buf[exp->buf_ins++] = data;
9985 exp->buf[exp->buf_ins] = '\0';
9986
9987 for (i=0; i < exp->size; i++) {
9988 ep = &exp->rules[i];
9989 if (ep == NULL)
9990 break;
9991 if (ep->switches & EXP_TYP_REGEX) {
9992 }
9993 else {
9994 if (exp->buf_ins < ep->size) {
9995
9996
9997
9998
9999 if (exp->buf_ins > 0) {
10000 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10001 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10002 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10003
10004 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\n",
10005 (long long)exp->buf_ins, estr);
10006 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
10007 FREE (estr);
10008 FREE (mstr);
10009 }
10010 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10011 continue;
10012 }
10013 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10014 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10015 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10016
10017 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
10018 (long long)exp->buf_size-(ep->size-exp->buf_ins),
10019 (long long)ep->size-exp->buf_ins, estr);
10020 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
10021 FREE (estr);
10022 FREE (mstr);
10023 }
10024 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10025 continue;
10026 break;
10027 }
10028 else {
10029 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10030 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10031 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10032
10033 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
10034 (long long)exp->buf_ins-ep->size,
10035 (long long)ep->size, estr);
10036 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
10037 FREE (estr);
10038 FREE (mstr);
10039 }
10040 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10041 continue;
10042 break;
10043 }
10044 }
10045 }
10046 if (exp->buf_ins == exp->buf_size) {
10047 exp->buf_ins = 0;
10048 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\n");
10049 }
10050 if ((ep != NULL) && (i != exp->size)) {
10051 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\n");
10052 if (ep->cnt > 0) {
10053 ep->cnt -= 1;
10054 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\n",
10055 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10056 }
10057 else {
10058 uint32 after = exp->after;
10059 int32 switches = ep->switches;
10060 if (ep->act && *ep->act) {
10061 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\n", ep->act);
10062 }
10063 else {
10064 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\n");
10065 }
10066 sim_brk_setact (ep->act);
10067 if (ep->switches & EXP_TYP_CLEARALL)
10068 sim_exp_clrall (exp);
10069 else {
10070 if (!(ep->switches & EXP_TYP_PERSIST))
10071 sim_exp_clr_tab (exp, ep);
10072 }
10073 sim_activate (&sim_expect_unit,
10074 (switches & EXP_TYP_TIME) ?
10075 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10076 after);
10077 }
10078
10079 exp->buf_ins = 0;
10080 }
10081 if (tstr)
10082 FREE (tstr);
10083 return SCPE_OK;
10084 }
10085
10086
10087
10088 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10089 {
10090 if (snd->extoff != 0) {
10091 if (snd->insoff > snd->extoff)
10092 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10093 snd->insoff -= snd->extoff;
10094 snd->extoff = 0;
10095 }
10096 if (snd->insoff+size > snd->bufsize) {
10097 snd->bufsize = snd->insoff+size;
10098 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10099 if (!snd->buffer)
10100 {
10101 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10102 __func__, __FILE__, __LINE__);
10103 #if defined(USE_BACKTRACE)
10104 # if defined(SIGUSR2)
10105 (void)raise(SIGUSR2);
10106
10107 # endif
10108 #endif
10109 abort();
10110 }
10111 }
10112 memcpy(snd->buffer+snd->insoff, data, size);
10113 snd->insoff += size;
10114 if (delay)
10115 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10116 if (after)
10117 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10118 if (snd->after == 0)
10119 snd->after = snd->delay;
10120 snd->next_time = sim_gtime() + snd->after;
10121 return SCPE_OK;
10122 }
10123
10124
10125 t_stat sim_send_clear (SEND *snd)
10126 {
10127 snd->insoff = 0;
10128 snd->extoff = 0;
10129 return SCPE_OK;
10130 }
10131
10132
10133
10134 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10135 {
10136 if (snd->extoff < snd->insoff) {
10137 (void)fprintf (st, "%lld bytes of pending input Data:\n ",
10138 (long long)snd->insoff-snd->extoff);
10139 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10140 (void)fprintf (st, "\n");
10141 }
10142 else
10143 (void)fprintf (st, "No Pending Input Data\n");
10144 if ((snd->next_time - sim_gtime()) > 0) {
10145 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10146 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\n",
10147 (int)(snd->next_time - sim_gtime()),
10148 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10149 else
10150 (void)fprintf (st, "Minimum of %d instructions before sending first character\n",
10151 (int)(snd->next_time - sim_gtime()));
10152 }
10153 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10154 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\n",
10155 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10156 else
10157 (void)fprintf (st, "Minimum of %d instructions between characters\n",
10158 (int)snd->delay);
10159 if (snd->dptr && snd->dbit)
10160 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
10161 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10162 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10163 return SCPE_OK;
10164 }
10165
10166
10167
10168 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10169 {
10170 #if defined(TESTING)
10171 cpu_state_t * cpup = _cpup;
10172 #endif
10173 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10174 if (sim_gtime() < snd->next_time) {
10175 *stat = SCPE_OK;
10176 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\n");
10177 }
10178 else {
10179 char dstr[8] = "";
10180 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10181 snd->next_time = sim_gtime() + snd->delay;
10182 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10183 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10184 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\n", *stat & 0xFF, dstr);
10185 }
10186 return TRUE;
10187 }
10188 return FALSE;
10189 }
10190
10191
10192
10193 const char *sim_error_text (t_stat stat)
10194 {
10195 static char msgbuf[64];
10196
10197 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10198 if (stat == SCPE_OK)
10199 return "No Error";
10200 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10201 return scp_errors[stat-SCPE_BASE].message;
10202 (void)sprintf(msgbuf, "Error %d", stat);
10203 return msgbuf;
10204 }
10205
10206 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10207 {
10208 char gbuf[CBUFSIZE];
10209 size_t cond;
10210
10211 *stat = SCPE_ARG;
10212 cptr = get_glyph (cptr, gbuf, 0);
10213 if (0 == memcmp("SCPE_", gbuf, 5))
10214 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10215 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10216 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10217 cond += SCPE_BASE;
10218 break;
10219 }
10220 if (0 == strcmp(gbuf, "OK"))
10221 cond = SCPE_OK;
10222 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10223 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10224 if (0 == numeric_cond)
10225 return SCPE_ARG;
10226 cond = (t_stat) numeric_cond;
10227 }
10228 if (cond > SCPE_MAX_ERR)
10229 return SCPE_ARG;
10230 *stat = cond;
10231 return SCPE_OK;
10232 }
10233
10234
10235
10236 const char* debug_bstates = "01_^";
10237 char debug_line_prefix[256];
10238 int32 debug_unterm = 0;
10239
10240
10241
10242 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10243 {
10244 static const char *debtab_none = "DEBTAB_ISNULL";
10245 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10246 const char *some_match = NULL;
10247 int32 offset = 0;
10248
10249 if (dptr->debflags == 0)
10250 return debtab_none;
10251
10252 dbits &= dptr->dctrl;
10253
10254
10255
10256 while ((offset < 32) && dptr->debflags[offset].name) {
10257 if (dptr->debflags[offset].mask == dbits)
10258 return dptr->debflags[offset].name;
10259 if (dptr->debflags[offset].mask & dbits)
10260 some_match = dptr->debflags[offset].name;
10261 offset++;
10262 }
10263 return some_match ? some_match : debtab_nomatch;
10264 }
10265
10266
10267
10268 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10269 {
10270 const char* debug_type = get_dbg_verb (dbits, dptr);
10271 char tim_t[32] = "";
10272 char tim_a[32] = "";
10273 char pc_s[64] = "";
10274 struct timespec time_now;
10275
10276 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10277 clock_gettime(CLOCK_REALTIME, &time_now);
10278 if (sim_deb_switches & SWMASK ('R'))
10279 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10280 if (sim_deb_switches & SWMASK ('T')) {
10281 time_t tnow = (time_t)time_now.tv_sec;
10282 struct tm *now = gmtime(&tnow);
10283 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10284 (int)now->tm_hour,
10285 (int)now->tm_min,
10286 (int)now->tm_sec,
10287 (long)(time_now.tv_nsec / 1000000));
10288 }
10289 if (sim_deb_switches & SWMASK ('A')) {
10290 (void)sprintf(tim_t, "%d.%03ld ",
10291 (int)(time_now.tv_sec),
10292 (long)(time_now.tv_nsec / 1000000));
10293 }
10294 }
10295 if (sim_deb_switches & SWMASK ('P')) {
10296 t_value val;
10297
10298 if (sim_vm_pc_value)
10299 val = (*sim_vm_pc_value)();
10300 else
10301 val = get_rval (sim_PC, 0);
10302 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10303 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10304 }
10305 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10306 tim_t, tim_a, sim_gtime(), pc_s,
10307 "", dptr->name, debug_type);
10308 return debug_line_prefix;
10309 }
10310
10311 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10312 {
10313 int32 i, fields, offset;
10314 uint32 value, beforevalue, mask;
10315
10316 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10317 if (bitdefs[fields].offset == 0xffffffff)
10318 bitdefs[fields].offset = offset;
10319 offset += bitdefs[fields].width;
10320 }
10321 for (i = fields-1; i >= 0; i--) {
10322 if (bitdefs[i].name[0] == '\0')
10323 continue;
10324 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10325 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10326 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10327 }
10328 else {
10329 const char *delta = "";
10330 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10331 value = (uint32)((after >> bitdefs[i].offset) & mask);
10332 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10333 if (value < beforevalue)
10334 delta = "_";
10335 if (value > beforevalue)
10336 delta = "^";
10337 if (bitdefs[i].valuenames)
10338 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10339 else
10340 if (bitdefs[i].format) {
10341 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10342 (void)Fprintf(stream, bitdefs[i].format, value);
10343 (void)Fprintf(stream, " ");
10344 }
10345 else
10346 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10347 }
10348 }
10349 }
10350
10351
10352
10353
10354
10355 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10356 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10357 {
10358 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10359 if (!debug_unterm)
10360 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10361 if (header)
10362 (void)fprintf(sim_deb, "%s: ", header);
10363 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10364 if (terminate)
10365 (void)fprintf(sim_deb, "\r\n");
10366 debug_unterm = terminate ? 0 : 1;
10367 }
10368 }
10369 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10370 uint32 before, uint32 after, int terminate)
10371 {
10372 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10373 }
10374
10375
10376 void sim_printf (const char* fmt, ...)
10377 {
10378 char stackbuf[STACKBUFSIZE];
10379 int32 bufsize = sizeof(stackbuf);
10380 char *buf = stackbuf;
10381 int32 len;
10382 va_list arglist;
10383
10384 while (1) {
10385 va_start (arglist, fmt);
10386 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10387 va_end (arglist);
10388
10389
10390
10391 if ((len < 0) || (len >= bufsize-1)) {
10392 if (buf != stackbuf)
10393 FREE (buf);
10394 if (bufsize >= (INT_MAX / 2))
10395 return;
10396 bufsize = bufsize * 2;
10397 if (bufsize < len + 2)
10398 bufsize = len + 2;
10399 buf = (char *) malloc (bufsize);
10400 if (buf == NULL)
10401 return;
10402 buf[bufsize-1] = '\0';
10403 continue;
10404 }
10405 break;
10406 }
10407
10408 if (sim_is_running) {
10409 char *c, *remnant = buf;
10410 while ((c = strchr(remnant, '\n'))) {
10411 if ((c != buf) && (*(c - 1) != '\r'))
10412 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10413 else
10414 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10415 remnant = c + 1;
10416 }
10417 (void)printf("%s", remnant);
10418 }
10419 else
10420 (void)printf("%s", buf);
10421 if (sim_log && (sim_log != stdout))
10422 (void)fprintf (sim_log, "%s", buf);
10423 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10424 (void)fprintf (sim_deb, "%s", buf);
10425
10426 if (buf != stackbuf)
10427 FREE (buf);
10428 }
10429
10430
10431 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10432 {
10433 char stackbuf[STACKBUFSIZE];
10434 size_t bufsize = sizeof(stackbuf);
10435 char *buf = stackbuf;
10436 size_t len;
10437 va_list arglist;
10438 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10439
10440 while (1) {
10441 va_start (arglist, fmt);
10442 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10443 va_end (arglist);
10444
10445
10446
10447 if (len >= bufsize - 1) {
10448 if (buf != stackbuf)
10449 FREE (buf);
10450 bufsize = bufsize * 2;
10451 if (bufsize < len + 2)
10452 bufsize = len + 2;
10453 buf = (char *) malloc (bufsize);
10454 if (buf == NULL)
10455 return SCPE_MEM;
10456 buf[bufsize-1] = '\0';
10457 continue;
10458 }
10459 break;
10460 }
10461
10462 if (sim_do_ocptr[sim_do_depth]) {
10463 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10464 sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10465 else {
10466 if (sim_deb)
10467 (void)fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10468 }
10469 }
10470 if (sim_is_running && !inhibit_message) {
10471 char *c, *remnant = buf;
10472 while ((c = strchr(remnant, '\n'))) {
10473 if ((c != buf) && (*(c - 1) != '\r'))
10474 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10475 else
10476 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10477 remnant = c + 1;
10478 }
10479 (void)printf("%s", remnant);
10480 }
10481 else {
10482 if (!inhibit_message)
10483 (void)printf("%s", buf);
10484 }
10485 if (sim_log && (sim_log != stdout) && !inhibit_message)
10486 (void)fprintf (sim_log, "%s", buf);
10487 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10488 (void)fprintf (sim_deb, "%s", buf);
10489
10490 if (buf != stackbuf)
10491 FREE (buf);
10492 return stat | SCPE_NOMESSAGE;
10493 }
10494
10495
10496
10497
10498
10499
10500
10501
10502
10503 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10504 {
10505 DEVICE *dptr = (DEVICE *)vdptr;
10506 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10507 char stackbuf[STACKBUFSIZE];
10508 int32 bufsize = sizeof(stackbuf);
10509 char *buf = stackbuf;
10510 va_list arglist;
10511 int32 i, j, len;
10512 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10513
10514 buf[bufsize-1] = '\0';
10515 while (1) {
10516 va_start (arglist, fmt);
10517 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10518 va_end (arglist);
10519
10520
10521
10522 if ((len < 0) || (len >= bufsize-1)) {
10523 if (buf != stackbuf)
10524 FREE (buf);
10525 if (bufsize >= (INT_MAX / 2))
10526 return;
10527 bufsize = bufsize * 2;
10528 if (bufsize < len + 2)
10529 bufsize = len + 2;
10530 buf = (char *) malloc (bufsize);
10531 if (buf == NULL)
10532 return;
10533 buf[bufsize-1] = '\0';
10534 continue;
10535 }
10536 break;
10537 }
10538
10539
10540
10541 for (i = j = 0; i < len; ++i) {
10542 if ('\n' == buf[i]) {
10543 if (i >= j) {
10544 if ((i != j) || (i == 0)) {
10545 if (debug_unterm)
10546 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10547 else
10548 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10549 }
10550 debug_unterm = 0;
10551 }
10552 j = i + 1;
10553 }
10554 }
10555 if (i > j) {
10556 if (debug_unterm)
10557 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10558 else
10559 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10560 }
10561
10562
10563
10564 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10565 if (buf != stackbuf)
10566 FREE (buf);
10567 }
10568 return;
10569 }
10570
10571 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10572 {
10573 #if defined(TESTING)
10574 cpu_state_t * cpup = _cpup;
10575 #endif
10576 if (sim_deb && (dptr->dctrl & reason)) {
10577 sim_debug (reason, dptr, "%s %s %slen: %08X\n", sim_uname(uptr), txt, position, (unsigned int)len);
10578 if (data && len) {
10579 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10580 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10581 static char hex[] = "0123456789ABCDEF";
10582 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10583 static unsigned char ebcdic2ascii[] = {
10584 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10585 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10586 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10587 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10588 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10589 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10590 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10591 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10592 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10593 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10594 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10595 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10596 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10597 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10598 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10599 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10600 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10601 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10602 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10603 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10604 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10605 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10606 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10607 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10608 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10609 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10610 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10611 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10612 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10613 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10614 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10615 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10616 };
10617
10618 for (i=same=0; i<len; i += 16) {
10619 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10620 ++same;
10621 continue;
10622 }
10623 if (same > 0) {
10624 sim_debug (reason, dptr, "%04lx thru %04lx same as above\n",
10625 (unsigned long int)(i - (16*same)),
10626 (unsigned long int)(i - 1));
10627 same = 0;
10628 }
10629 group = (((len - i) > 16) ? 16 : (len - i));
10630 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10631 eidx = strlen(ebcdicbuf);
10632 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10633 ridx = strlen(rad50buf);
10634 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10635 soff = strlen(strbuf);
10636 for (sidx=oidx=0; sidx<group; ++sidx) {
10637 outbuf[oidx++] = ' ';
10638 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10639 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10640 if (sim_isprint (data[i+sidx]))
10641 strbuf[soff+sidx] = data[i+sidx];
10642 else
10643 strbuf[soff+sidx] = '.';
10644 if (ridx && ((sidx&1) == 0)) {
10645 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10646
10647 if (word >= 64000) {
10648 rad50buf[ridx++] = '|';
10649 rad50buf[ridx++] = '|';
10650 rad50buf[ridx++] = '|';
10651 }
10652 else {
10653 rad50buf[ridx++] = rad50[word/1600];
10654 rad50buf[ridx++] = rad50[(word/40)%40];
10655 rad50buf[ridx++] = rad50[word%40];
10656 }
10657 }
10658 if (eidx) {
10659 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10660 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10661 else
10662 ebcdicbuf[eidx++] = '.';
10663 }
10664 }
10665 outbuf[oidx] = '\0';
10666 strbuf[soff+sidx] = '\0';
10667 ebcdicbuf[eidx] = '\0';
10668 rad50buf[ridx] = '\0';
10669 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\n",
10670 (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10671 }
10672 if (same > 0) {
10673 sim_debug (reason, dptr, "%04lx thru %04lx same as above\n",
10674 (unsigned long int)(i-(16*same)),
10675 (unsigned long int)(len-1));
10676 }
10677 }
10678 }
10679 }
10680
10681 int Fprintf (FILE *f, const char* fmt, ...)
10682 {
10683 int ret = 0;
10684 va_list args;
10685
10686 va_start (args, fmt);
10687 ret = vfprintf (f, fmt, args);
10688 va_end (args);
10689 return ret;
10690 }
10691
10692
10693
10694
10695
10696
10697
10698
10699
10700
10701
10702
10703
10704
10705
10706
10707
10708
10709
10710 #define blankch(x) ((x) == ' ' || (x) == '\t')
10711
10712 typedef struct topic {
10713 size_t level;
10714 char *title;
10715 char *label;
10716 struct topic *parent;
10717 struct topic **children;
10718 uint32 kids;
10719 char *text;
10720 size_t len;
10721 uint32 flags;
10722 size_t kidwid;
10723 #define HLP_MAGIC_TOPIC 1
10724 } TOPIC;
10725
10726 static volatile struct {
10727 const char *error;
10728 const char *prox;
10729 size_t block;
10730 size_t line;
10731 } help_where = { "", NULL, 0, 0 };
10732 jmp_buf help_env;
10733
10734 #define FAIL(why,text,here) \
10735 { \
10736 help_where.error = #text; \
10737 help_where.prox = here; \
10738 longjmp ( help_env, (why) ); \
10739 \
10740 }
10741
10742
10743
10744
10745
10746
10747 static void appendText (TOPIC *topic, const char *text, size_t len)
10748 {
10749 char *newt;
10750
10751 if (!len)
10752 return;
10753
10754 newt = (char *)realloc (topic->text, topic->len + len +1);
10755 if (!newt) {
10756 #if !defined(SUNLINT)
10757 FAIL (SCPE_MEM, No memory, NULL);
10758 #endif
10759 }
10760 topic->text = newt;
10761 memcpy (newt + topic->len, text, len);
10762 topic->len +=len;
10763 newt[topic->len] = '\0';
10764 return;
10765 }
10766
10767
10768
10769 static void cleanHelp (TOPIC *topic)
10770 {
10771 TOPIC *child;
10772 size_t i;
10773
10774 FREE (topic->title);
10775 FREE (topic->text);
10776 FREE (topic->label);
10777 for (i = 0; i < topic->kids; i++) {
10778 child = topic->children[i];
10779 cleanHelp (child);
10780 FREE (child);
10781 }
10782 FREE (topic->children);
10783 return;
10784 }
10785
10786
10787
10788
10789 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10790 UNIT *uptr, const char *htext, va_list ap)
10791 {
10792 char *end;
10793 size_t n, ilvl;
10794 #define VSMAX 100
10795 char *vstrings[VSMAX];
10796 size_t vsnum = 0;
10797 char * astrings[VSMAX+1];
10798 size_t asnum = 0;
10799 char *const *hblock;
10800 const char *ep;
10801 t_bool excluded = FALSE;
10802
10803
10804
10805
10806
10807
10808
10809 (void)memset (vstrings, 0, sizeof (vstrings));
10810 (void)memset (astrings, 0, sizeof (astrings));
10811 astrings[asnum++] = (char *) htext;
10812
10813 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10814 help_where.block = hblock - astrings;
10815 help_where.line = 0;
10816 while (*htext) {
10817 const char *start;
10818
10819 help_where.line++;
10820 if (sim_isspace (*htext) || *htext == '+') {
10821 if (excluded) {
10822 while (*htext && *htext != '\n')
10823 htext++;
10824 if (*htext)
10825 ++htext;
10826 continue;
10827 }
10828 ilvl = 1;
10829 appendText (topic, " ", 4);
10830 if (*htext == '+') {
10831 while (*htext == '+') {
10832 ilvl++;
10833 appendText (topic, " ", 4);
10834 htext++;
10835 }
10836 }
10837 while (*htext && *htext != '\n' && sim_isspace (*htext))
10838 htext++;
10839 if (!*htext)
10840 break;
10841 start = htext;
10842 while (*htext) {
10843 if (*htext == '%') {
10844 appendText (topic, start, htext - start);
10845 switch (*++htext) {
10846 case 'U':
10847 if (dptr) {
10848 char buf[129];
10849 n = uptr? uptr - dptr->units: 0;
10850 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10851 appendText (topic, buf, strlen (buf));
10852 }
10853 break;
10854 case 'D':
10855 if (dptr != NULL)
10856 appendText (topic, dptr->name, strlen (dptr->name));
10857 break;
10858 case 'S':
10859 appendText (topic, sim_name, strlen (sim_name));
10860 break;
10861 case '%':
10862 appendText (topic, "%", 1);
10863 break;
10864 case '+':
10865 appendText (topic, "+", 1);
10866 break;
10867 default:
10868 if (sim_isdigit (*htext)) {
10869 n = 0;
10870 while (sim_isdigit (*htext))
10871 n += (n * 10) + (*htext++ - '0');
10872 if (( *htext != 'H' && *htext != 's') ||
10873 n == 0 || n >= VSMAX) {
10874 #if !defined(SUNLINT)
10875 FAIL (SCPE_ARG, Invalid escape, htext);
10876 #endif
10877 }
10878 while (n > vsnum)
10879 vstrings[vsnum++] = va_arg (ap, char *);
10880 start = vstrings[n-1];
10881 if (*htext == 'H') {
10882 if (asnum >= VSMAX) {
10883 #if !defined(SUNLINT)
10884 FAIL (SCPE_ARG, Too many blocks, htext);
10885 #endif
10886 }
10887 astrings[asnum++] = (char *)start;
10888 break;
10889 }
10890 ep = start;
10891 while (*ep) {
10892 if (*ep == '\n') {
10893 ep++;
10894 appendText (topic, start, ep - start);
10895 if (*ep) {
10896 size_t i;
10897 for (i = 0; i < ilvl; i++)
10898 appendText (topic, " ", 4);
10899 }
10900 start = ep;
10901 }
10902 else
10903 ep++;
10904 }
10905 appendText (topic, start, ep-start);
10906 break;
10907 }
10908 #if !defined(SUNLINT)
10909 FAIL (SCPE_ARG, Invalid escape, htext);
10910 #endif
10911 }
10912 start = ++htext;
10913 continue;
10914 }
10915 if (*htext == '\n') {
10916 htext++;
10917 appendText (topic, start, htext - start);
10918 break;
10919 }
10920 htext++;
10921 }
10922 continue;
10923 }
10924 if (sim_isdigit (*htext)) {
10925 TOPIC **children;
10926 TOPIC *newt;
10927 char nbuf[100];
10928
10929 n = 0;
10930 start = htext;
10931 while (sim_isdigit (*htext))
10932 n += (n * 10) + (*htext++ - '0');
10933 if ((htext == start) || !n) {
10934 #if !defined(SUNLINT)
10935 FAIL (SCPE_ARG, Invalid topic heading, htext);
10936 #endif
10937 }
10938 if (n <= topic->level) {
10939 while (n <= topic->level)
10940 topic = topic->parent;
10941 }
10942 else {
10943 if (n > topic->level + 1) {
10944 #if !defined(SUNLINT)
10945 FAIL (SCPE_ARG, Level not contiguous, htext);
10946 #endif
10947 }
10948 }
10949 while (*htext && (*htext != '\n') && sim_isspace (*htext))
10950 htext++;
10951 if (!*htext || (*htext == '\n')) {
10952 #if !defined(SUNLINT)
10953 FAIL (SCPE_ARG, Missing topic name, htext);
10954 #endif
10955 }
10956 start = htext;
10957 while (*htext && (*htext != '\n'))
10958 htext++;
10959 if (start == htext) {
10960 #if !defined(SUNLINT)
10961 FAIL (SCPE_ARG, Null topic name, htext);
10962 #endif
10963 }
10964 excluded = FALSE;
10965 if (*start == '?') {
10966 size_t n = 0;
10967 start++;
10968 while (sim_isdigit (*start))
10969 n += (n * 10) + (*start++ - '0');
10970 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
10971 #if !defined(SUNLINT)
10972 FAIL (SCPE_ARG, Invalid parameter number, start);
10973 #endif
10974 }
10975 while (n > vsnum)
10976 vstrings[vsnum++] = va_arg (ap, char *);
10977 end = vstrings[n-1];
10978 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
10979 excluded = TRUE;
10980 if (*htext)
10981 htext++;
10982 continue;
10983 }
10984 }
10985 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
10986 if (!newt) {
10987 #if !defined(SUNLINT)
10988 FAIL (SCPE_MEM, No memory, NULL);
10989 #endif
10990 }
10991 newt->title = (char *) malloc ((htext - start)+1);
10992 if (!newt->title) {
10993 FREE (newt);
10994 #if !defined(SUNLINT)
10995 FAIL (SCPE_MEM, No memory, NULL);
10996 #endif
10997 }
10998 memcpy (newt->title, start, htext - start);
10999 newt->title[htext - start] = '\0';
11000 if (*htext)
11001 htext++;
11002
11003 if (newt->title[0] == '$')
11004 newt->flags |= HLP_MAGIC_TOPIC;
11005
11006 children = (TOPIC **) realloc (topic->children,
11007 (topic->kids +1) * sizeof (TOPIC *));
11008 if (NULL == children) {
11009 FREE (newt->title);
11010 FREE (newt);
11011 #if !defined(SUNLINT)
11012 FAIL (SCPE_MEM, No memory, NULL);
11013 #endif
11014 }
11015 topic->children = children;
11016 topic->children[topic->kids++] = newt;
11017 newt->level = n;
11018 newt->parent = topic;
11019 n = strlen (newt->title);
11020 if (n > topic->kidwid)
11021 topic->kidwid = n;
11022 (void)sprintf (nbuf, ".%u", topic->kids);
11023 n = strlen (topic->label) + strlen (nbuf) + 1;
11024 newt->label = (char *) malloc (n);
11025 if (NULL == newt->label) {
11026 FREE (newt->title);
11027 topic->children[topic->kids -1] = NULL;
11028 FREE (newt);
11029 #if !defined(SUNLINT)
11030 FAIL (SCPE_MEM, No memory, NULL);
11031 #endif
11032 }
11033 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11034 topic = newt;
11035 continue;
11036 }
11037 if (*htext == ';') {
11038 while (*htext && *htext != '\n')
11039 htext++;
11040 continue;
11041 }
11042 #if !defined(SUNLINT)
11043 FAIL (SCPE_ARG, Unknown line type, htext);
11044 #endif
11045 }
11046 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11047 vsnum = 0;
11048 }
11049
11050 return topic;
11051 }
11052
11053
11054
11055
11056
11057 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
11058 {
11059 char *prefix;
11060 char *newp, *newt;
11061
11062 if (topic->level == 0) {
11063 prefix = (char *) calloc (2,1);
11064 if (!prefix) {
11065 #if !defined(SUNLINT)
11066 FAIL (SCPE_MEM, No memory, NULL);
11067 #endif
11068 }
11069 prefix[0] = '\n';
11070 }
11071 else
11072 prefix = helpPrompt (topic->parent, "", oneword);
11073
11074 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11075 strlen (pstring) +1);
11076 if (!newp) {
11077 FREE (prefix);
11078 #if !defined(SUNLINT)
11079 FAIL (SCPE_MEM, No memory, NULL);
11080 #endif
11081 }
11082 strcpy (newp, prefix);
11083 if (topic->children) {
11084 if (topic->level != 0)
11085 strcat (newp, " ");
11086 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11087 topic->title+1: topic->title;
11088 if (oneword) {
11089 char *np = newp + strlen (newp);
11090 while (*newt) {
11091 *np++ = blankch (*newt)? '_' : *newt;
11092 newt++;
11093 }
11094 *np = '\0';
11095 }
11096 else
11097 strcat (newp, newt);
11098 if (*pstring && *pstring != '?')
11099 strcat (newp, " ");
11100 }
11101 strcat (newp, pstring);
11102 FREE (prefix);
11103 return newp;
11104 }
11105
11106 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11107 {
11108 char tbuf[CBUFSIZE];
11109 size_t i, skiplines;
11110 #if defined(_WIN32)
11111 FILE *tmp;
11112 char *tmpnam;
11113
11114 do {
11115 int fd;
11116 tmpnam = _tempnam (NULL, "simh");
11117 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11118 if (fd != -1) {
11119 tmp = _fdopen (fd, "w+");
11120 break;
11121 }
11122 } while (1);
11123 #else
11124 FILE *tmp = tmpfile();
11125 #endif
11126
11127 if (!tmp) {
11128 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\n",
11129 xstrerror_l(errno), errno);
11130 return;
11131 }
11132
11133 if (topic->title)
11134 (void)fprintf (st, "%s\n", topic->title+1);
11135
11136 skiplines = 0;
11137 if (topic->title) {
11138 if (!strcmp (topic->title+1, "Registers")) {
11139 fprint_reg_help (tmp, dptr) ;
11140 skiplines = 1;
11141 }
11142 else
11143 if (!strcmp (topic->title+1, "Set commands")) {
11144 fprint_set_help (tmp, dptr);
11145 skiplines = 3;
11146 }
11147 else
11148 if (!strcmp (topic->title+1, "Show commands")) {
11149 fprint_show_help (tmp, dptr);
11150 skiplines = 3;
11151 }
11152 }
11153 rewind (tmp);
11154 if (errno) {
11155 (void)fprintf (st, "rewind: error %d\r\n", errno);
11156 }
11157
11158
11159
11160 for (i =0; i < skiplines; i++)
11161 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11162
11163 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11164 if (tbuf[0] != '\n')
11165 fputs (" ", st);
11166 fputs (tbuf, st);
11167 }
11168 fclose (tmp);
11169 #if defined(_WIN32)
11170 remove (tmpnam);
11171 FREE (tmpnam);
11172 #endif
11173 return;
11174 }
11175
11176
11177 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11178 UNIT *uptr, int32 flag,
11179 TOPIC *topic, va_list ap )
11180 {
11181 size_t i;
11182
11183 if (topic->flags & HLP_MAGIC_TOPIC) {
11184 (void)fprintf (st, "\n%s ", topic->label);
11185 displayMagicTopic (st, dptr, topic);
11186 }
11187 else
11188 (void)fprintf (st, "\n%s %s\n", topic->label, topic->title);
11189
11190
11191
11192
11193
11194
11195 if (topic->text)
11196 fputs (topic->text, st);
11197
11198 for (i = 0; i < topic->kids; i++)
11199 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11200
11201 return SCPE_OK;
11202 }
11203
11204 #define HLP_MATCH_AMBIGUOUS (~0u)
11205 #define HLP_MATCH_WILDCARD (~1U)
11206 #define HLP_MATCH_NONE 0
11207 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11208 {
11209 size_t i, match;
11210 char cbuf[CBUFSIZE], *cptr;
11211
11212 if (!strcmp (token, "*"))
11213 return HLP_MATCH_WILDCARD;
11214
11215 match = 0;
11216 for (i = 0; i < topic->kids; i++) {
11217 strcpy (cbuf,topic->children[i]->title +
11218 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11219 cptr = cbuf;
11220 while (*cptr) {
11221 if (blankch (*cptr)) {
11222 *cptr++ = '_';
11223 }
11224 else {
11225 *cptr = (char)toupper (*cptr);
11226 cptr++;
11227 }
11228 }
11229 if (!strcmp (cbuf, token))
11230 return i+1;
11231 if (!strncmp (cbuf, token, strlen (token))) {
11232 if (match)
11233 return HLP_MATCH_AMBIGUOUS;
11234 match = i+1;
11235 }
11236 }
11237 return match;
11238 }
11239
11240
11241
11242 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11243 UNIT *uptr, int32 flag,
11244 const char *help, const char *cptr, va_list ap)
11245 {
11246 TOPIC top;
11247 TOPIC *topic = ⊤
11248 int failed;
11249 size_t match;
11250 size_t i;
11251 const char *p;
11252 t_bool flat_help = FALSE;
11253 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11254
11255 static const char attach_help[] = { " ATTACH" };
11256 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\n" };
11257 static const char onecmd_help[] = { "%s help.\n" };
11258 static const char help_help[] = {
11259
11260 " To see more HELP information, type the listed subtopic name. To move\n"
11261 " up a level, just type <CR>. To review the current subtopic, type \"?\".\n"
11262 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\n\n"
11263 };
11264
11265 (void)memset (&top, 0, sizeof(top));
11266 top.parent = ⊤
11267 if ((failed = setjmp (help_env)) != 0) {
11268 (void)fprintf (stderr, "\nHELP was unable to process HELP for this device.\n"
11269 "Error in block %u line %u: %s\n"
11270 "%s%*.*s%s\n",
11271 (int)help_where.block, (int)help_where.line, help_where.error,
11272 help_where.prox ? "Near '" : "",
11273 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11274 help_where.prox ? help_where.prox : "",
11275 help_where.prox ? "'" : "");
11276 cleanHelp (&top);
11277 return failed;
11278 }
11279
11280
11281
11282
11283
11284 if (dptr) {
11285 p = dptr->name;
11286 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11287 }
11288 else
11289 p = sim_name;
11290 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11291 if (!top.title)
11292 {
11293 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11294 __func__, __FILE__, __LINE__);
11295 #if defined(USE_BACKTRACE)
11296 # if defined(SIGUSR2)
11297 (void)raise(SIGUSR2);
11298
11299 # endif
11300 #endif
11301 abort();
11302 }
11303 for (i = 0; p[i]; i++ )
11304 top.title[i] = (char)toupper (p[i]);
11305 top.title[i] = '\0';
11306 if (flag & SCP_HELP_ATTACH)
11307 strcpy (top.title+i, attach_help);
11308
11309 top.label = (char *) malloc (sizeof ("1"));
11310 if (!top.label)
11311 {
11312 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11313 __func__, __FILE__, __LINE__);
11314 #if defined(USE_BACKTRACE)
11315 # if defined(SIGUSR2)
11316 (void)raise(SIGUSR2);
11317
11318 # endif
11319 #endif
11320 abort();
11321 }
11322 strcpy (top.label, "1");
11323
11324 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11325
11326 if (flat_help) {
11327 flag |= SCP_HELP_FLAT;
11328 if (sim_ttisatty())
11329 (void)fprintf (st, "%s help.\nThis help is also available in hierarchical form.\n", top.title);
11330 else
11331 (void)fprintf (st, "%s help.\n", top.title);
11332 }
11333 else
11334 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11335
11336
11337
11338 (void) buildHelp (&top, dptr, uptr, help, ap);
11339
11340
11341
11342 while (cptr && *cptr) {
11343 cptr = get_glyph (cptr, gbuf, 0);
11344 if (!gbuf[0])
11345 break;
11346 if (!strcmp (gbuf, "HELP")) {
11347 (void)fprintf (st, "\n");
11348 fputs (help_help, st);
11349 break;
11350 }
11351 match = matchHelpTopicName (topic, gbuf);
11352 if (match == HLP_MATCH_WILDCARD) {
11353 if (dptr)
11354 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11355 cleanHelp (&top);
11356 return SCPE_OK;
11357 }
11358 if (match == HLP_MATCH_AMBIGUOUS) {
11359 (void)fprintf (st, "\n%s is ambiguous in %s\n", gbuf, topic->title);
11360 break;
11361 }
11362 if (match == HLP_MATCH_NONE) {
11363 (void)fprintf (st, "\n%s is not available in %s\n", gbuf, topic->title);
11364 break;
11365 }
11366 topic = topic->children[match-1];
11367 }
11368 cptr = NULL;
11369
11370 if (flat_help) {
11371 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11372 cleanHelp (&top);
11373 return SCPE_OK;
11374 }
11375
11376
11377
11378 while (TRUE) {
11379 char *pstring;
11380 const char *prompt[2] = {"? ", "Subtopic? "};
11381
11382
11383
11384 if (topic->flags & HLP_MAGIC_TOPIC) {
11385 fputc ('\n', st);
11386 displayMagicTopic (st, dptr, topic);
11387 }
11388 else
11389 (void)fprintf (st, "\n%s\n", topic->title);
11390
11391
11392
11393
11394
11395 if (topic->text)
11396 fputs (topic->text, st);
11397
11398 if (topic->kids) {
11399 size_t w = 0;
11400 char *p;
11401 char tbuf[CBUFSIZE];
11402
11403 (void)fprintf (st, "\n Additional information available:\n\n");
11404 for (i = 0; i < topic->kids; i++) {
11405 strcpy (tbuf, topic->children[i]->title +
11406 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11407 for (p = tbuf; *p; p++) {
11408 if (blankch (*p))
11409 *p = '_';
11410 }
11411 w += 4 + topic->kidwid;
11412 if (w > 80) {
11413 w = 4 + topic->kidwid;
11414 fputc ('\n', st);
11415 }
11416 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11417 }
11418 (void)fprintf (st, "\n\n");
11419 if (flag & SCP_HELP_ONECMD) {
11420 pstring = helpPrompt (topic, "", TRUE);
11421 (void)fprintf (st, "To view additional topics, type HELP %s topicname\n", pstring+1);
11422 FREE (pstring);
11423 break;
11424 }
11425 }
11426
11427 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11428 break;
11429
11430 reprompt:
11431 if (NULL == cptr || !*cptr) {
11432 if (topic->kids == 0)
11433 topic = topic->parent;
11434 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11435
11436 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11437 FREE (pstring);
11438 if ((cptr != NULL) &&
11439 ((0 == strcmp (cptr, "\x04")) ||
11440 (0 == strcmp (cptr, "\x1A"))))
11441 cptr = NULL;
11442 }
11443
11444 if (NULL == cptr)
11445 break;
11446
11447 cptr = get_glyph (cptr, gbuf, 0);
11448 if (!strcmp (gbuf, "*")) {
11449 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11450 gbuf[0] = '\0';
11451 }
11452 if (!gbuf[0]) {
11453 if (topic->level == 0)
11454 break;
11455 topic = topic->parent;
11456 continue;
11457 }
11458 if (!strcmp (gbuf, "?"))
11459 continue;
11460 if (!strcmp (gbuf, "HELP")) {
11461 fputs (help_help, st);
11462 goto reprompt;
11463 }
11464 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11465 break;
11466
11467
11468
11469 if (!topic->kids) {
11470 (void)fprintf (st, "No additional help at this level.\n");
11471 cptr = NULL;
11472 goto reprompt;
11473 }
11474 match = matchHelpTopicName (topic, gbuf);
11475 if (match == HLP_MATCH_AMBIGUOUS) {
11476 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\n", gbuf);
11477 cptr = NULL;
11478 goto reprompt;
11479 }
11480
11481 if (match == HLP_MATCH_NONE) {
11482 (void)fprintf (st, "Help for %s is not available\n", gbuf);
11483 cptr = NULL;
11484 goto reprompt;
11485 }
11486
11487
11488 topic = topic->children[match-1];
11489 }
11490
11491
11492
11493 cleanHelp (&top);
11494
11495 return SCPE_OK;
11496 }
11497
11498
11499
11500 t_stat scp_help (FILE *st, DEVICE *dptr,
11501 UNIT *uptr, int32 flag,
11502 const char *help, const char *cptr, ...)
11503 {
11504 t_stat r;
11505 va_list ap;
11506
11507 va_start (ap, cptr);
11508 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11509 va_end (ap);
11510
11511 return r;
11512 }
11513
11514 #if defined(_MSC_VER)
11515 # pragma warning(pop)
11516 #endif