This source file includes following definitions.
- setenv
- unsetenv
- xstrerror_l
- 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_hints.h"
59 #include "sim_tape.h"
60 #include "sim_sock.h"
61 #include "sim_os_mem.h"
62
63 #include <signal.h>
64 #include <ctype.h>
65 #include <time.h>
66 #include <math.h>
67 #include <stddef.h>
68 #if defined(_WIN32)
69 # if !defined(WIN32_LEAN_AND_MEAN)
70 # define WIN32_LEAN_AND_MEAN
71 # endif
72 # if defined(_MSC_VER)
73 # pragma warning(push, 3)
74 # endif
75 # include <direct.h>
76 # include <io.h>
77 # include <fcntl.h>
78 #else
79 # include <unistd.h>
80 # define HAVE_UNISTD 1
81 #endif
82 #include <sys/stat.h>
83 #include <sys/types.h>
84 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
85 # include <sys/resource.h>
86 #endif
87 #include <setjmp.h>
88 #include <stdint.h>
89 #include <limits.h>
90 #if defined(__APPLE__)
91 # include <xlocale.h>
92 #endif
93 #include <locale.h>
94
95 #include "linehistory.h"
96
97 #if defined(__APPLE__)
98 # include <sys/sysctl.h>
99 #endif
100
101 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) )
102 # include <sys/sysinfo.h>
103 # define LINUX_OS
104 #endif
105
106 #include <uv.h>
107
108 #if !defined(HAVE_UNISTD)
109 # undef USE_BACKTRACE
110 #endif
111
112 #if defined(USE_BACKTRACE)
113 # include <string.h>
114 # include <signal.h>
115 #endif
116
117 #if defined(__HAIKU__)
118 # include <OS.h>
119 #endif
120
121 #if !defined(__CYGWIN__)
122 # if !defined(__APPLE__)
123 # if !defined(_AIX)
124 # if !defined(__MINGW32__)
125 # if !defined(__MINGW64__)
126 # if !defined(CROSS_MINGW32)
127 # if !defined(CROSS_MINGW64)
128 # if !defined(_WIN32)
129 # if !defined(__HAIKU__)
130 # if !defined(__QNX__)
131 # include <link.h>
132 # endif
133 # endif
134 # endif
135 # endif
136 # endif
137 # endif
138 # endif
139 # endif
140 # endif
141 #endif
142
143 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
144 # include <windows.h>
145 #endif
146
147 #if defined(__CYGWIN__)
148 # include <windows.h>
149 # include <sys/utsname.h>
150 # include <sys/cygwin.h>
151 # include <cygwin/version.h>
152 #endif
153
154 #define DBG_CTR 0
155
156 #include "../dps8/dps8.h"
157 #include "../dps8/dps8_cpu.h"
158 #include "../dps8/dps8_rt.h"
159 #include "../dps8/dps8_priv.h"
160 #include "../dps8/dps8_topo.h"
161 #include "../dps8/ver.h"
162
163 #include "../dps8/dps8_iom.h"
164 #include "../dps8/dps8_fnp2.h"
165
166 #include "../decNumber/decContext.h"
167 #include "../decNumber/decNumberLocal.h"
168
169 #include "../dps8/dps8_math128.h"
170
171 #include "../dps8/dps8_sir.h"
172
173 #if !defined(__CYGWIN__)
174 # if !defined(__APPLE__)
175 # if !defined(_AIX)
176 # if !defined(__MINGW32__)
177 # if !defined(__MINGW64__)
178 # if !defined(CROSS_MINGW32)
179 # if !defined(CROSS_MINGW64)
180 # if !defined(_WIN32)
181 # if !defined(__HAIKU__)
182 # if !defined(__QNX__)
183 static unsigned int dl_iterate_phdr_callback_called = 0;
184 # endif
185 # endif
186 # endif
187 # endif
188 # endif
189 # endif
190 # endif
191 # endif
192 # endif
193 #endif
194
195 #if defined(MAX)
196 # undef MAX
197 #endif
198 #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
199
200 #if defined(FREE)
201 # undef FREE
202 #endif
203 #define FREE(p) do \
204 { \
205 free((p)); \
206 (p) = NULL; \
207 } while(0)
208
209
210
211 #define SCH_OR 0
212 #define SCH_AND 1
213 #define SCH_XOR 2
214 #define SCH_E 0
215 #define SCH_N 1
216 #define SCH_G 2
217 #define SCH_L 3
218 #define SCH_EE 4
219 #define SCH_NE 5
220 #define SCH_GE 6
221 #define SCH_LE 7
222
223 #define MAX_DO_NEST_LVL 20
224 #define SRBSIZ 1024
225 #define SIM_BRK_INILNT 4096
226 #define SIM_BRK_ALLTYP 0xFFFFFFFB
227
228 #define UPDATE_SIM_TIME \
229 if (1) { \
230 int32 _x; \
231 if (sim_clock_queue == QUEUE_LIST_END) \
232 _x = noqueue_time; \
233 else \
234 _x = sim_clock_queue->time; \
235 sim_time = sim_time + (_x - sim_interval); \
236 sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
237 if (sim_clock_queue == QUEUE_LIST_END) \
238 noqueue_time = sim_interval; \
239 else \
240 sim_clock_queue->time = sim_interval; \
241 } \
242 else \
243 (void)0
244
245 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
246
247 #define SZ_R(rp) \
248 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
249
250 #define SZ_LOAD(sz,v,mb,j) \
251 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
252 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
253 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
254 else v = *(((t_uint64 *) mb) + ((uint32) j));
255
256 #define SZ_STORE(sz,v,mb,j) \
257 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
258 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
259 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
260 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
261
262 #define GET_SWITCHES(cp) \
263 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
264
265 #define GET_RADIX(val,dft) \
266 if (sim_switches & SWMASK ('O')) val = 8; \
267 else if (sim_switches & SWMASK ('D')) val = 10; \
268 else if (sim_switches & SWMASK ('H')) val = 16; \
269 else val = dft;
270
271
272
273
274
275
276 t_bool sim_asynch_enabled = FALSE;
277 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
278 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
279 extern void (*sim_vm_init) (void);
280 extern void (*sim_vm_exit) (void);
281 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
282 void (*sim_vm_post) (t_bool from_scp) = NULL;
283 CTAB *sim_vm_cmd = NULL;
284 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
285 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
286 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
287 t_value (*sim_vm_pc_value) (void) = NULL;
288 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
289 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
290 unsigned int nprocs;
291 unsigned int ncores;
292 bool mlock_failure = false;
293 char* sim_appfilename;
294
295
296
297
298
299 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
300 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
301 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
302 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
303 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
304 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
305 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
306 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
307 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
308 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
309 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
310 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
311 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
312 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
313 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
314 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
315 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
316 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
317 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
318 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
319 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
320 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
321 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
322 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
323 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
324 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
325 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
326 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
327 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
328 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
329 t_stat sim_save (FILE *sfile);
330 t_stat sim_rest (FILE *rfile);
331
332
333
334 t_stat sim_brk_init (void);
335 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
336 t_stat sim_brk_clr (t_addr loc, int32 sw);
337 t_stat sim_brk_clrall (int32 sw);
338 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
339 t_stat sim_brk_showall (FILE *st, uint32 sw);
340 CONST char *sim_brk_getact (char *buf, int32 size);
341 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
342 char *sim_brk_clract (void);
343
344 FILE *stdnul;
345
346
347
348 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
349 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
350 int32 test_search (t_value *val, SCHTAB *schptr);
351 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
352 int32 get_switches (const char *cptr);
353 CONST char *get_sim_sw (CONST char *cptr);
354 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
355 t_value get_rval (REG *rptr, uint32 idx);
356 void put_rval (REG *rptr, uint32 idx, t_value val);
357 void fprint_help (FILE *st);
358 void fprint_stopped (FILE *st, t_stat r);
359 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
360 void fprint_sep (FILE *st, int32 *tokens);
361 char *read_line (char *ptr, int32 size, FILE *stream);
362 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
363 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
364 char *sim_trim_endspc (char *cptr);
365
366
367
368 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
369 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
370 t_bool qdisable (DEVICE *dptr);
371 t_stat attach_err (UNIT *uptr, t_stat stat);
372 t_stat detach_all (int32 start_device, t_bool shutdown);
373 t_stat assign_device (DEVICE *dptr, const char *cptr);
374 t_stat deassign_device (DEVICE *dptr);
375 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
376 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
377 REG *lowr, REG *highr, uint32 lows, uint32 highs);
378 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
379 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
380 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
381 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
382 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
383 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
384 UNIT *uptr, int32 dfltinc);
385 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
386 t_stat step_svc (UNIT *ptr);
387 t_stat expect_svc (UNIT *ptr);
388 t_stat set_on (int32 flag, CONST char *cptr);
389 t_stat set_verify (int32 flag, CONST char *cptr);
390 t_stat set_message (int32 flag, CONST char *cptr);
391 t_stat set_quiet (int32 flag, CONST char *cptr);
392 t_stat set_localopc (int32 flag, CONST char *cptr);
393 t_stat set_asynch (int32 flag, CONST char *cptr);
394 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
395 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
396 void int_handler (int signal);
397 t_stat set_prompt (int32 flag, CONST char *cptr);
398 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
399 t_stat sim_set_environment (int32 flag, CONST char *cptr);
400 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
401
402
403
404 DEVICE *sim_dflt_dev = NULL;
405 UNIT *sim_clock_queue = QUEUE_LIST_END;
406 int32 sim_interval = 0;
407 int32 sim_switches = 0;
408 FILE *sim_ofile = NULL;
409 SCHTAB *sim_schrptr = NULL;
410 SCHTAB *sim_schaptr = NULL;
411 DEVICE *sim_dfdev = NULL;
412 UNIT *sim_dfunit = NULL;
413 DEVICE **sim_internal_devices = NULL;
414 uint32 sim_internal_device_count = 0;
415 int32 sim_opt_out = 0;
416 int32 sim_is_running = 0;
417 t_bool sim_processing_event = FALSE;
418 uint32 sim_brk_summ = 0;
419 uint32 sim_brk_types = 0;
420 BRKTYPTAB *sim_brk_type_desc = NULL;
421 uint32 sim_brk_dflt = 0;
422 uint32 sim_brk_match_type;
423 t_addr sim_brk_match_addr;
424 char *sim_brk_act[MAX_DO_NEST_LVL];
425 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
426 BRKTAB **sim_brk_tab = NULL;
427 int32 sim_brk_ent = 0;
428 int32 sim_brk_lnt = 0;
429 int32 sim_brk_ins = 0;
430 int32 sim_iglock = 0;
431 int32 sim_nolock = 0;
432 int32 sim_quiet = 0;
433 int32 sim_localopc = 1;
434 int32 sim_randompst = 0;
435 int32 sim_randstate = 0;
436 int32 sim_step = 0;
437 int nodist = 0;
438 #if defined(PERF_STRIP)
439 int32 sim_nostate = 1;
440 #else
441 int32 sim_nostate = 0;
442 #endif
443 static double sim_time;
444 static uint32 sim_rtime;
445 static int32 noqueue_time;
446 volatile int32 stop_cpu = 0;
447 t_value *sim_eval = NULL;
448 static t_value sim_last_val;
449 static t_addr sim_last_addr;
450 FILE *sim_log = NULL;
451 FILEREF *sim_log_ref = NULL;
452 FILE *sim_deb = NULL;
453 FILEREF *sim_deb_ref = NULL;
454 int32 sim_deb_switches = 0;
455 struct timespec sim_deb_basetime;
456 char *sim_prompt = NULL;
457 static FILE *sim_gotofile;
458 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];
459 static int32 sim_do_echo = 0;
460 static int32 sim_show_message = 1;
461 static int32 sim_on_inherit = 0;
462 #if !defined(PERF_STRIP)
463 static int32 sim_realtime = 0;
464 #endif
465 static int32 sim_do_depth = 0;
466 uint64_t sim_free_memory = 0;
467
468 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
469 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
470 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
471 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
472 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
473
474 t_stat sim_last_cmd_stat;
475
476 static SCHTAB sim_stabr;
477 static SCHTAB sim_staba;
478
479 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };
480 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) };
481
482 pthread_t main_thread_id;
483
484
485
486 const char save_vercur[] = "V4.1";
487 const char save_ver40[] = "V4.0";
488 const char save_ver35[] = "V3.5";
489 const char save_ver32[] = "V3.2";
490 const char save_ver30[] = "V3.0";
491 const struct scp_error {
492 const char *code;
493 const char *message;
494 } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
495 {{"NXM", "Address space exceeded"},
496 {"UNATT", "Unit not attached"},
497 {"IOERR", "I/O error"},
498 {"CSUM", "Checksum error"},
499 {"FMT", "Format error"},
500 {"NOATT", "Unit not attachable"},
501 {"OPENERR", "File open error"},
502 {"MEM", "Memory exhausted"},
503 {"ARG", "Invalid argument"},
504 {"STEP", "Step expired"},
505 {"UNK", "Unknown command"},
506 {"RO", "Read only argument"},
507 {"INCOMP", "Command not completed"},
508 {"STOP", "Simulation stopped"},
509 {"EXIT", "Goodbye"},
510 {"TTIERR", "Console input I/O error"},
511 {"TTOERR", "Console output I/O error"},
512 {"EOF", "End of file"},
513 {"REL", "Relocation error"},
514 {"NOPARAM", "No settable parameters"},
515 {"ALATT", "Unit already attached"},
516 {"TIMER", "Hardware timer error"},
517 {"SIGERR", "Signal handler setup error"},
518 {"TTYERR", "Console terminal setup error"},
519 {"SUB", "Subscript out of range"},
520 {"NOFNC", "Command not allowed"},
521 {"UDIS", "Unit disabled"},
522 {"NORO", "Read only operation not allowed"},
523 {"INVSW", "Invalid switch"},
524 {"MISVAL", "Missing value"},
525 {"2FARG", "Too few arguments"},
526 {"2MARG", "Too many arguments"},
527 {"NXDEV", "Non-existent device"},
528 {"NXUN", "Non-existent unit"},
529 {"NXREG", "Non-existent register"},
530 {"NXPAR", "Non-existent parameter"},
531 {"NEST", "Nested DO command limit exceeded"},
532 {"IERR", "Internal error"},
533 {"MTRLNT", "Invalid magtape record length"},
534 {"LOST", "Console Telnet connection lost"},
535 {"TTMO", "Console Telnet connection timed out"},
536 {"STALL", "Console Telnet output stall"},
537 {"AFAIL", "Assertion failed"},
538 {"INVREM", "Invalid remote console command"},
539 {"NOTATT", "Not attached"},
540 {"EXPECT", "Expect matched"},
541 {"REMOTE", "Remote console command"},
542 };
543
544 const size_t size_map[] = { sizeof (int8),
545 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
546 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
547 };
548
549 const t_value width_mask[] = { 0,
550 0x1, 0x3, 0x7, 0xF,
551 0x1F, 0x3F, 0x7F, 0xFF,
552 0x1FF, 0x3FF, 0x7FF, 0xFFF,
553 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
554 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
555 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
556 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
557 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
558 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
559 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
560 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
561 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
562 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
563 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
564 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
565 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
566 };
567
568 static const char simh_help[] =
569
570 "1Commands\n"
571 #define HLP_RESET "*Commands Resetting Devices"
572
573 "2Resetting Devices\n"
574 " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\r\n"
575 " simulator to a predefined condition. If the switch \"`-p`\" is specified,\r\n"
576 " the device is reset to its initial power-on state:\r\n\r\n"
577 "++RESET resets all devices\r\n"
578 "++RESET -p power-cycle all devices\r\n"
579 "++RESET ALL resets all devices\r\n"
580 "++RESET <device> resets the specified <device>\r\n\r\n"
581 " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\r\n"
582 " interrupt requests, and returns the device to a quiescent state.\r\n\r\n"
583 " * It does **NOT** clear the main memory or affect associated I/O\r\n"
584 " connections.\r\n"
585 #define HLP_EXAMINE "*Commands Examining_and_Changing_State"
586 #define HLP_IEXAMINE "*Commands Examining_and_Changing_State"
587 #define HLP_DEPOSIT "*Commands Examining_and_Changing_State"
588 #define HLP_IDEPOSIT "*Commands Examining_and_Changing_State"
589
590 "2Examining and Changing State\n"
591 " There are four commands to examine and change state:\r\n\r\n"
592 " * `EXAMINE` (*abbreviated* `E`) examines state\r\n"
593 " * `DEPOSIT` (*abbreviated* `D`) changes state\r\n"
594 " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\r\n"
595 " and allows the user to interactively change it\r\n"
596 " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\r\n"
597 " interactively change state\r\n\r\n"
598 " All four commands take the form:\r\n\r\n"
599 "++command {modifiers} <object list>\r\n\r\n"
600 " The `DEPOSIT` command requires the deposit value at the end of the command.\r\n\r\n"
601 " There are four kinds of modifiers: **switches**, **device/unit name**,\r\n"
602 " **search specifier**, and for `EXAMINE`, **output file**.\r\n\r\n"
603 " * **Switches** have been described previously.\r\n"
604 " * A **device/unit name** identifies the device and unit whose address\r\n"
605 " space is to be examined or modified. If no device is specified, the CPU\r\n"
606 " main memory is selected. If a device but no unit is specified, unit `0`\r\n"
607 " of the specified device is selected automatically.\r\n"
608 " * The **search specifier** provides criteria for testing addresses or\r\n"
609 " registers to see if they should be processed. The search specifier\r\n"
610 " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\r\n"
611 " both, optionally separated by spaces:\r\n\r\n"
612 "++{ < logical op > < value > } < relational op > < value >\r\n\r\n"
613
614 " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\r\n"
615 " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\r\n"
616 " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\r\n"
617 " equal*), \">=\" (*greater than or equal*), \">\" (*greater\r\n"
618 " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\r\n"
619 " * * If any \"<`logical operator`>\" is specified without\r\n"
620 " a \"<`relational operator`>\", it is ignored.\r\n"
621 " * * If any \"<`relational operator`>\" is specified without\r\n"
622 " a \"<`logical operator`>\", no logical operation is performed.\r\n"
623 " * * All comparisons are unsigned.\r\n\r\n"
624 " * The **output file** modifier redirects the command output to a file\r\n"
625 " instead of the console. The **output file** modifier is specified with\r\n"
626 " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\r\n\r\n"
627 " **NOTE**: Modifiers may be specified in any order. If multiple\r\n"
628 " modifiers of the same type are specified, later modifiers override earlier\r\n"
629 " modifiers. If the **device/unit name** comes *after* the search specifier,\r\n"
630 " the search values will interpreted in the *radix of the CPU*, rather than\r\n"
631 " of the device/unit.\r\n\r\n"
632 " The \"<`object list`>\" argument consists of one or more of the following,\r\n"
633 " separated by commas:\r\n\r\n"
634
635 "++register the specified register\r\n"
636 "++register[sub1-sub2] the specified register array locations,\r\n"
637 "++++++++ starting at location sub1 up to and\r\n"
638 "++++++++ including location sub2\r\n"
639 "++register[sub1/length] the specified register array locations,\r\n"
640 "++++++++ starting at location sub1 up to but\r\n"
641 "++++++++ not including sub1+length\r\n"
642 "++register[ALL] all locations in the specified register\r\n"
643 "++++++++ array\r\n"
644 "++register1-register2 all the registers starting at register1\r\n"
645 "++++++++ up to and including register2\r\n"
646 "++address the specified location\r\n"
647 "++address1-address2 all locations starting at address1 up to\r\n"
648 "++++++++ and including address2\r\n"
649 "++address/length all location starting at address up to\r\n"
650 "++++++++ but not including address+length\r\n"
651 "++STATE all registers in the device\r\n"
652 "++ALL all locations in the unit\r\n"
653 "++$ the last value displayed by an EXAMINE\r\n"
654 "++++++++ command interpreted as an address\r\n"
655 "3Switches\n"
656 "4Formatting Control\n"
657 " Switches can be used to control the format of the displayed information:\r\n\r\n"
658
659 "5`-a`\n"
660 " display as ASCII\r\n"
661 "5`-c`\n"
662 " display as character string\r\n"
663 "5`-m`\n"
664 " display as instruction mnemonics\r\n"
665 "5`-o`\n"
666 " display as octal\r\n"
667 "5`-d`\n"
668 " display as decimal\r\n"
669 "5`-h`\n"
670 " display as hexadecimal\r\n\r\n"
671 "3Examples\n"
672 "++ex 1000-1100 examine 1000 to 1100\r\n"
673 "++de PC 1040 set PC to 1040\r\n"
674 "++ie 40-50 interactively examine 40:50\r\n"
675 "++ie >1000 40-50 interactively examine the subset\r\n"
676 "+++++++++ of locations 40:50 that are >1000\r\n"
677 "++ex rx0 50060 examine 50060, RX unit 0\r\n"
678 "++ex rx sbuf[3-6] examine SBUF[3] to SBUF[6] in RX\r\n"
679 "++de all 0 set main memory to 0\r\n"
680 "++de &77>0 0 set all addresses whose low order\r\n"
681 "+++++++++ bits are non-zero to 0\r\n"
682 "++ex -m @memdump.txt 0-7777 dump memory to file\r\n\r\n"
683 " * **NOTE**: To terminate an interactive command, simply type any bad value\r\n"
684 " (*e.g.* `XYZ`) when input is requested.\r\n"
685 #define HLP_EVALUATE "*Commands Evaluating_Instructions"
686
687 "2Evaluating Instructions\n"
688 " The `EVAL` command evaluates a symbolic expression and returns the\r\n"
689 " equivalent numeric value.\r\n\r\n"
690
691 "2Running A Simulated Program\n"
692 #define HLP_RUN "*Commands Running_A_Simulated_Program RUN"
693 "3RUN\n"
694 " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\r\n"
695 " argument, if given, in the PC (program counter), and starts execution.\r\n"
696 " If no argument is given execution starts at the current PC.\r\n"
697 #define HLP_GO "*Commands Running_A_Simulated_Program GO"
698 "3GO\n"
699 " The `GO` command does *not* reset devices, deposits its argument (if\r\n"
700 " given) in the PC, and starts execution. If no argument is given,\r\n"
701 " execution starts at the current PC (program counter).\r\n"
702 #define HLP_CONTINUE "*Commands Running_A_Simulated_Program Continuing_Execution"
703 "3Continuing Execution\n"
704 " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\r\n"
705 " (if execution was stopped, possibly due to hitting a breakpoint) at the\r\n"
706 " current program counter without resetting any devices.\r\n"
707 #define HLP_STEP "*Commands Running_A_Simulated_Program Step_Execution"
708 "3Step Execution\n"
709 " The `STEP` command (*abbreviated* `S`) resumes execution at the current\r\n"
710 " PC for the number of instructions given by its argument. If no argument\r\n"
711 " is supplied, one instruction is executed.\r\n"
712 "4Switches\n"
713 "5`-T`\n"
714 " If the `STEP` command is invoked with the \"`-T`\" switch, the step\r\n"
715 " command will cause execution to run for *microseconds* rather than\r\n"
716 " instructions.\r\n"
717 #define HLP_NEXT "*Commands Running_A_Simulated_Program NEXT"
718 "3NEXT\n"
719 " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\r\n"
720 " for one instruction, attempting to execute *through* subroutine calls.\r\n"
721 " If the next instruction to be executed is *not* a subroutine call, then\r\n"
722 " one instruction is executed.\r\n"
723 #define HLP_BOOT "*Commands Running_A_Simulated_Program Booting_the_system"
724 "3Booting the system\n"
725 " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\r\n"
726 " the device and unit given by its argument. If no unit is supplied,\r\n"
727 " unit `0` is bootstrapped. The specified unit must be `ATTACH`'ed.\r\n\r\n"
728 " When booting Multics, the boot device should always be `iom0`.\r\n"
729 " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\r\n"
730 " into memory and the system will transfer control to the boot record.\r\n\r\n"
731 " **Example**\r\n\r\n"
732 "++; Boot Multics using iom0\r\n"
733 "++boot iom0\r\n\r\n"
734
735 "2Stopping The Simulator\n"
736 " The simulator runs until the simulated hardware encounters an error, or\r\n"
737 " until the user forces a stop condition.\r\n"
738 "3Simulator Detected Stop Conditions\n"
739 " These simulator-detected conditions stop simulation:\r\n\r\n"
740 "++- HALT instruction. If a HALT instruction is decoded, simulation stops.\r\n\r\n"
741 "++- I/O error. If an I/O error occurs during simulation of an I/O\r\n"
742 "+++operation, and the device stop-on-I/O-error flag is set, simulation\r\n"
743 "+++usually stops.\r\n\r\n"
744 "++- Processor condition. Certain processor conditions can stop\r\n"
745 "+++the simulation.\r\n"
746 "3User Specified Stop Conditions\n"
747 " Typing the interrupt character stops simulation. The interrupt character\r\n"
748 " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\r\n"
749 " set to `005` (`^E`).\r\n\r\n"
750
751 #define HLP_BREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
752 #define HLP_NOBREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
753 "4Breakpoints\n"
754 " The simulator offers breakpoint capability for debugging. Users may define\r\n"
755 " breakpoints of different types, identified by letter (for example, `E`\r\n"
756 " for *execution*, `R` for *read*, `W` for *write*, etc).\r\n\r\n"
757 " Associated with each breakpoint is a count and, optionally, one or more\r\n"
758 " actions. Each time a breakpoint occurs, the associated count\r\n"
759 " is *decremented*. If the count is less than or equal to `0`, the breakpoint\r\n"
760 " occurs; otherwise, it is deferred. When the breakpoint occurs, any\r\n"
761 " optional actions are automatically executed.\r\n\r\n"
762 " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\r\n\r\n"
763 "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\r\n\r\n"
764 " If no type is specified, the default breakpoint type (`E`, *execution*) is\r\n"
765 " used. If no address range is specified, the current PC is used. As\r\n"
766 " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\r\n"
767 " range of addresses low-high, or a relative range of address/length.\r\n"
768
769 "5Displaying Breakpoints\n"
770 " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\r\n\r\n"
771 "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\r\n\r\n"
772 " Locations with breakpoints of the specified type are displayed.\r\n\r\n"
773 " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\r\n"
774 " commands which may be subsequently used to establish the same\r\n"
775 " breakpoint(s).\r\n\r\n"
776 "5Removing Breakpoints\n"
777 " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\r\n"
778 "5Examples\n"
779 " The following examples illustrate breakpoint usage:\r\n\r\n"
780 "++BREAK set E break at current PC\r\n"
781 "++BREAK -e 200 set E break at 200\r\n"
782 "++BREAK 2000/2[2] set E breaks at 2000,2001 with count = 2\r\n"
783 "++BREAK 100;EX AC;D MQ 0 set E break at 100 with actions EX AC and\r\n"
784 "+++++++++D MQ 0\r\n"
785 "++BREAK 100; delete action on break at 100\r\n\r\n"
786
787 "2Connecting and Disconnecting Devices\n"
788 " Units are simulated as files on the host file system. Before using any\r\n"
789 " simulated unit, the user must specify the file to be accessed by that unit.\r\n"
790 #define HLP_ATTACH "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
791 "3Attaching devices\n"
792 " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\r\n\r\n"
793 "++ATTACH <unit> <filename>\r\n\r\n"
794 " Some devices have more detailed or specific help available with:\r\n\r\n"
795 "++HELP <device> ATTACH\r\n\r\n"
796 "4Switches\n"
797 "5`-n`\n"
798 " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\r\n"
799 " file will be created when the filename specified does not exist, or an\r\n"
800 " existing file will have it's size truncated to zero, and an appropriate\r\n"
801 " message is printed.\r\n"
802 "5`-e`\n"
803 " If the file does not exist, and the \"`-e`\" switch *was not* specified,\r\n"
804 " a new file is created, and an appropriate message is printed. If\r\n"
805 " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\r\n"
806 " error message is printed.\r\n"
807 "5`-r`\n"
808 " If the \"`-r`\" switch is specified, or the file is write protected by\r\n"
809 " host operating system, `ATTACH` tries to open the file in read only mode.\r\n"
810 " If the file does not exist, or the unit does not support read only\r\n"
811 " operation, an error occurs. Input-only devices, such as card readers, or\r\n"
812 " storage devices with write locking switches, such as disks or tapes,\r\n"
813 " support read only operation - other devices do not. If a file is\r\n"
814 " attached read only, its contents can be examined but not modified.\r\n"
815 "5`-q`\n"
816 " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\r\n"
817 " or opening one read only (\"`-r`\"), the message announcing this fact\r\n"
818 " is suppressed.\r\n"
819 "5`-f`\n"
820 " For simulated magnetic tapes, the `ATTACH` command can specify the format\r\n"
821 " of the attached tape image file:\r\n\r\n"
822 "++ATTACH -f <tape_unit> <format> <filename>\r\n\r\n"
823 " * The currently supported magnetic tape image file formats are:\r\n\r\n"
824 " | | |\r\n"
825 " | ----------------:|:---------------------------------------------------- |\r\n"
826 " | \"**`SIMH`**\" | The **SIMH** / **DPS8M** native portable tape format |\r\n"
827 " | \"**`E11`**\" | The *D Bit* **Ersatz-11** simulator format |\r\n"
828 " | \"**`TPC`**\" | The **TPC** format (*used by _SIMH_ prior to V2.3*) |\r\n"
829 " | \"**`P7B`**\" | The **Paul Pierce** `7`-track tape archive format |\r\n\r\n"
830
831 " * The default tape format can also be specified with the `SET` command\r\n"
832 " prior to using the `ATTACH` command:\r\n\r\n"
833 "++SET <tape_unit> FORMAT=<format>\r\n"
834 "++ATTACH <tape_unit> <filename>\r\n\r\n"
835 " * The format of a currently attached tape image can be displayed with\r\n"
836 " the `SHOW FORMAT` command:\r\n\r\n"
837 "++SHOW <unit> FORMAT\r\n\r\n"
838 " **Examples**\r\n\r\n"
839 " The following example illustrates common `ATTACH` usage:\r\n"
840 "++; Associate the tape image file \"12.8MULTICS.tap\" with the tape0 unit\r\n"
841 "++; in read-only mode, where tape0 corresponds to the first tape device.\r\n"
842 "++ATTACH -r tape0 12.8MULTICS.tap\r\n\r\n"
843 "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\r\n"
844 "++; The disk0 unit corresponds to the first disk device.\r\n"
845 "++ATTACH disk0 root.dsk\r\n\r\n"
846
847 #define HLP_DETACH "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
848 "3Detaching devices\n"
849 " The `DETACH` (*abbreviation* `DET`) command breaks the association between\r\n"
850 " a unit and its backing file or device:\r\n\r\n"
851 "++DETACH ALL Detach all units\r\n"
852 "++DETACH <unit> Detach specified unit\r\n\r\n"
853 " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\r\n"
854 #define HLP_SET "*Commands SET"
855 "2SET\n"
856
857 #define HLP_SET_LOG "*Commands SET Logging"
858 "3Logging\n"
859 " Interactions with the simulator session can be recorded to a log file.\r\n\r\n"
860 "+SET LOG log_file Specify the log destination\r\n"
861 "++++++++ (STDOUT, DEBUG, or filename)\r\n"
862 "+SET NOLOG Disables any currently active logging\r\n"
863 "4Switches\n"
864 "5`-N`\n"
865 " By default, log output is written at the *end* of the specified log file.\r\n"
866 " A new log file can created if the \"`-N`\" switch is used on the command\r\n"
867 " line.\r\n\r\n"
868 "5`-B`\n"
869 " By default, log output is written in *text* mode. The log file can be\r\n"
870 " opened for *binary* mode writing if the \"`-B`\" switch is used on the\r\n"
871 " command line.\r\n"
872 #define HLP_SET_DEBUG "*Commands SET Debug_Messages"
873
874 "3Debug Messages\n"
875 "+SET DEBUG debug_file Specify the debug destination\r\n"
876 "++++++++ (STDOUT, STDERR, LOG, or filename)\r\n"
877 "+SET NODEBUG Disables any currently active debug output\r\n"
878 "4Switches\n"
879 " Debug message output contains a timestamp which indicates the number of\r\n"
880 " simulated instructions which have been executed prior to the debug event.\r\n\r\n"
881 " Debug message output can be enhanced to contain additional, potentially\r\n"
882 " useful information.\r\n\r\n\r\n"
883 " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\r\n"
884 "5`-T`\n"
885 " The \"`-T`\" switch causes debug output to contain a time of day displayed\r\n"
886 " as `hh:mm:ss.msec`.\r\n"
887 "5`-A`\n"
888 " The \"`-A`\" switch causes debug output to contain a time of day displayed\r\n"
889 " as `seconds.msec`.\r\n"
890 "5`-R`\n"
891 " The \"`-R`\" switch causes timing to be relative to the start of debugging.\r\n"
892 "5`-P`\n"
893 " The \"`-P`\" switch adds the output of the PC (program counter) to each\r\n"
894 " debug message.\r\n"
895 "5`-N`\n"
896 " The \"`-N`\" switch causes a new (empty) file to be written to.\r\n"
897 " (The default is to append to an existing debug log file).\r\n"
898 "5`-D`\n"
899 " The \"`-D`\" switch causes data blob output to also display the data\r\n"
900 " as **`RADIX-50`** characters.\r\n"
901 "5`-E`\n"
902 " The \"`-E`\" switch causes data blob output to also display the data\r\n"
903 " as \"**EBCDIC**\" characters.\r\n"
904
905 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
906 "3Environment Variables\n"
907 "+SET ENVIRONMENT NAME=val Set environment variable\r\n"
908 "+SET ENVIRONMENT NAME Clear environment variable\r\n"
909 #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
910 "3Command Status Trap Dispatching\n"
911 "+SET ON Enables error checking command execution\r\n"
912 "+SET NOON Disables error checking command execution\r\n"
913 "+SET ON INHERIT Enables inheritance of ON state and actions\r\n"
914 "+SET ON NOINHERIT Disables inheritance of ON state and actions\r\n"
915 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
916 "3Command Execution Display\n"
917 "+SET VERIFY Enables display of processed script commands\r\n"
918 "+SET VERBOSE Enables display of processed script commands\r\n"
919 "+SET NOVERIFY Disables display of processed script commands\r\n"
920 "+SET NOVERBOSE Disables display of processed script commands\r\n"
921 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
922 "3Command Error Status Display\n"
923 "+SET MESSAGE Re-enables display of script error messages\r\n"
924 "+SET NOMESSAGE Disables display of script error messages\r\n"
925 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
926 "3Command Output Display\n"
927 "+SET QUIET Disables suppression of some messages\r\n"
928 "+SET NOQUIET Re-enables suppression of some messages\r\n"
929 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
930 "3Local Operator Console\n"
931 "+SET LOCALOPC Enables local operator console\r\n"
932 "+SET NOLOCALOPC Disables local operator console\r\n"
933 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
934 "3Command Prompt\n"
935 "+SET PROMPT \"string\" Sets an alternate simulator prompt string\r\n"
936 "3Device and Unit Settings\n"
937 "+SET <dev> OCT|DEC|HEX Set device display radix\r\n"
938 "+SET <dev> ENABLED Enable device\r\n"
939 "+SET <dev> DISABLED Disable device\r\n"
940 "+SET <dev> DEBUG{=arg} Set device debug flags\r\n"
941 "+SET <dev> NODEBUG={arg} Clear device debug flags\r\n"
942 "+SET <dev> arg{,arg...} Set device parameters\r\n"
943 "+SET <unit> ENABLED Enable unit\r\n"
944 "+SET <unit> DISABLED Disable unit\r\n"
945 "+SET <unit> arg{,arg...} Set unit parameters\r\n"
946 "+HELP <dev> SET Displays any device specific SET commands\r\n"
947 " \r\n\r\n"
948 " See the Omnibus documentation for a complete SET command reference.\r\n"
949
950 #define HLP_SHOW "*Commands SHOW"
951 "2SHOW\n"
952 "+SH{OW} B{UILDINFO} Show build-time compilation information\r\n"
953 "+SH{OW} CL{OCKS} Show wall clock and timer information\r\n"
954 "+SH{OW} C{ONFIGURATION} Show simulator configuration\r\n"
955 "+SH{OW} D{EFAULT_BASE_SYSTEM} Show default base system script\r\n"
956 "+SH{OW} DEV{ICES} Show devices\r\n"
957 "+SH{OW} H{INTS} Show configuration hints\r\n"
958 "+SH{OW} M{ODIFIERS} Show SET commands for all devices\r\n"
959 "+SH{OW} O{N} Show ON condition actions\r\n"
960 "+SH{OW} P{ROM} Show CPU ID PROM initialization data\r\n"
961 "+SH{OW} Q{UEUE} Show event queue\r\n"
962 "+SH{OW} S{HOW} Show SHOW commands for all devices\r\n"
963 "+SH{OW} T{IME} Show simulated timer\r\n"
964 "+SH{OW} VE{RSION} Show simulator version\r\n"
965 "+H{ELP} <dev> SHOW Show device-specific SHOW commands\r\n"
966 "+SH{OW} <dev> {arg,...} Show device parameters\r\n"
967 "+SH{OW} <dev> DEBUG Show device debug flags\r\n"
968 "+SH{OW} <dev> MODIFIERS Show device modifiers\r\n"
969 "+SH{OW} <dev> RADIX Show device display radix\r\n"
970 "+SH{OW} <dev> SHOW Show device SHOW commands\r\n"
971 "+SH{OW} <unit> {arg,...} Show unit parameters\r\n\r\n"
972 " See the Omnibus documentation for a complete SHOW command reference.\r\n\r\n"
973 #define HLP_SHOW_CONFIG "*Commands SHOW"
974 #define HLP_SHOW_DEVICES "*Commands SHOW"
975 #define HLP_SHOW_FEATURES "*Commands SHOW"
976 #define HLP_SHOW_QUEUE "*Commands SHOW"
977 #define HLP_SHOW_TIME "*Commands SHOW"
978 #define HLP_SHOW_MODIFIERS "*Commands SHOW"
979 #define HLP_SHOW_NAMES "*Commands SHOW"
980 #define HLP_SHOW_SHOW "*Commands SHOW"
981 #define HLP_SHOW_VERSION "*Commands SHOW"
982 #define HLP_SHOW_BUILDINFO "*Commands SHOW"
983 #define HLP_SHOW_PROM "*Commands SHOW"
984 #define HLP_SHOW_HINTS "*Commands SHOW"
985 #define HLP_SHOW_DBS "*Commands SHOW"
986 #define HLP_SHOW_DEFAULT "*Commands SHOW"
987 #define HLP_SHOW_CONSOLE "*Commands SHOW"
988 #define HLP_SHOW_REMOTE "*Commands SHOW"
989 #define HLP_SHOW_BREAK "*Commands SHOW"
990 #define HLP_SHOW_LOG "*Commands SHOW"
991 #define HLP_SHOW_DEBUG "*Commands SHOW"
992 #define HLP_SHOW_CLOCKS "*Commands SHOW"
993 #define HLP_SHOW_ON "*Commands SHOW"
994 #define HLP_SHOW_SEND "*Commands SHOW"
995 #define HLP_SHOW_EXPECT "*Commands SHOW"
996 #define HLP_HELP "*Commands HELP"
997
998 "2HELP\n"
999 "+H{ELP} Show this message\r\n"
1000 "+H{ELP} <command> Show help for command\r\n"
1001 "+H{ELP} <dev> Show help for device\r\n"
1002 "+H{ELP} <dev> REGISTERS Show help for device register variables\r\n"
1003 "+H{ELP} <dev> ATTACH Show help for device specific ATTACH command\r\n"
1004 "+H{ELP} <dev> SET Show help for device specific SET commands\r\n"
1005 "+H{ELP} <dev> SHOW Show help for device specific SHOW commands\r\n"
1006 "+H{ELP} <dev> <command> Show help for device specific <command> command\r\n"
1007
1008 "2Altering The Simulated Configuration\n"
1009 " The \"SET <device> DISABLED\" command removes a device from the configuration.\r\n"
1010 " A `DISABLED` device is invisible to running programs. The device can still\r\n"
1011 " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\r\n\r\n"
1012 " The \"SET <device> ENABLED\" command restores a disabled device to a\r\n"
1013 " configuration.\r\n\r\n"
1014 " Most multi-unit devices allow units to be enabled or disabled:\r\n\r\n"
1015 "++SET <unit> ENABLED\r\n"
1016 "++SET <unit> DISABLED\r\n\r\n"
1017 " When a unit is disabled, it will not be displayed by SHOW DEVICE.\r\n\r\n"
1018
1019 #define HLP_DO "*Commands Executing_Command_Files Processing_Command_Files"
1020 "2Executing Command Files\n"
1021 "3Processing Command Files\n"
1022 " The simulator can invoke another script file with the \"`DO`\" command:\r\n\r\n"
1023 "++DO <filename> {arguments...} execute commands in specified file\r\n\r\n"
1024 " The \"`DO`\" command allows command files to contain substitutable\r\n"
1025 " arguments. The string \"`%%n`\", where \"`n`\" is a number\r\n"
1026 " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\r\n"
1027 " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\r\n"
1028 " The string \"`%%0`\" is replaced with \"<`filename`>\"\r\n"
1029 " The sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\r\n"
1030 " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\r\n"
1031 " be enclosed in matching single or double quotation marks.\r\n\r\n"
1032 " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\r\n"
1033 " deep.\r\n\r\n"
1034 "4Switches\n"
1035 "5`-v`\n\n"
1036 " If the switch \"`-v`\" is specified, commands in the command file are\r\n"
1037 " echoed *before* they are executed.\r\n\r\n"
1038 "5`-e`\n\n"
1039 " If the switch \"`-e`\" is specified, command processing (including nested\r\n"
1040 " command invocations) will be aborted if any command error is encountered.\r\n"
1041 " (A simulation stop **never** aborts processing; use `ASSERT` to catch\r\n"
1042 " unexpected stops.) Without this switch, all errors except `ASSERT` failures\r\n"
1043 " will be ignored, and command processing will continue.\r\n\r\n"
1044 "5`-o`\n\n"
1045 " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\r\n"
1046 " the calling command file will be inherited by the command file being\r\n"
1047 " invoked.\r\n"
1048 "5`-q`\n\n"
1049 " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\r\n"
1050 " enabled for the called command file, otherwise the *quiet mode* setting\r\n"
1051 " is inherited from the calling context.\r\n"
1052
1053 #define HLP_GOTO "*Commands Executing_Command_Files GOTO"
1054 "3GOTO\n"
1055 " Commands in a command file execute in sequence until either an error\r\n"
1056 " trap occurs (when a command completes with an error status), or when an\r\n"
1057 " explicit request is made to start command execution elsewhere with\r\n"
1058 " the `GOTO` command:\r\n\r\n"
1059 "++GOTO <label>\r\n\r\n"
1060 " * Labels are lines in a command file which the first non-whitespace\r\n"
1061 " character is a \"`:`\".\r\n"
1062 " * The target of a `GOTO` is the first matching label in the current `DO`\r\n"
1063 " command file which is encountered.\r\n\r\n"
1064 " **Example**\r\n\r\n"
1065 " The following example illustrates usage of the `GOTO` command (by\r\n"
1066 " creating an infinite loop):\r\n\r\n"
1067 "++:Label\r\n"
1068 "++:: This is a loop.\r\n"
1069 "++GOTO Label\r\n\r\n"
1070 #define HLP_RETURN "*Commands Executing_Command_Files RETURN"
1071
1072 "3RETURN\n"
1073 " The `RETURN` command causes the current procedure call to be restored to\r\n"
1074 " the calling context, possibly returning a specific return status.\r\n"
1075 " If no return status is specified, the return status from the last command\r\n"
1076 " executed will be returned. The calling context may have `ON` traps defined\r\n"
1077 " which may redirect command flow in that context.\r\n\r\n"
1078 "++RETURN return from command file with last command status\r\n"
1079 "++RETURN {-Q} <status> return from command file with specific status\r\n\r\n"
1080 " * The status return can be any numeric value or one of the standard SCPE_\r\n"
1081 " condition names.\r\n\r\n"
1082 " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\r\n"
1083 " status to be returned, but normal error status message printing to be\r\n"
1084 " suppressed.\r\n\r\n"
1085 " **Condition Names**\r\n\r\n"
1086 " The available standard SCPE_ condition names and their meanings are:\r\n\r\n"
1087 " | Name | Meaning | Name | Meaning |\r\n"
1088 " | ------- | --------------------------------| ------- | ----------------------------------- |\r\n"
1089 " | NXM | Address space exceeded | UNATT | Unit not attached |\r\n"
1090 " | IOERR | I/O error | CSUM | Checksum error |\r\n"
1091 " | FMT | Format error | NOATT | Unit not attachable |\r\n"
1092 " | OPENERR | File open error | MEM | Memory exhausted |\r\n"
1093 " | ARG | Invalid argument | STEP | Step expired |\r\n"
1094 " | UNK | Unknown command | RO | Read only argument |\r\n"
1095 " | INCOMP | Command not completed | STOP | Simulation stopped |\r\n"
1096 " | EXIT | Goodbye | TTIERR | Console input I/O error |\r\n"
1097 " | TTOERR | Console output I/O error | EOF | End of file |\r\n"
1098 " | REL | Relocation error | NOPARAM | No settable parameters |\r\n"
1099 " | ALATT | Unit already attached | TIMER | Hardware timer error |\r\n"
1100 " | SIGERR | Signal handler setup error | TTYERR | Console terminal setup error |\r\n"
1101 " | NOFNC | Command not allowed | UDIS | Unit disabled |\r\n"
1102 " | NORO | Read only operation not allowed | INVSW | Invalid switch |\r\n"
1103 " | MISVAL | Missing value | 2FARG | Too few arguments |\r\n"
1104 " | 2MARG | Too many arguments | NXDEV | Non-existent device |\r\n"
1105 " | NXUN | Non-existent unit | NXREG | Non-existent register |\r\n"
1106 " | NXPAR | Non-existent parameter | NEST | Nested DO command limit exceeded |\r\n"
1107 " | IERR | Internal error | MTRLNT | Invalid magtape record length |\r\n"
1108 " | LOST | Console Telnet connection lost | TTMO | Console Telnet connection timed out |\r\n"
1109 " | STALL | Console Telnet output stall | AFAIL | Assertion failed |\r\n"
1110 " | INVREM | Invalid remote console command | | |\r\n"
1111 "\r\n\r\n"
1112 #define HLP_SHIFT "*Commands Executing_Command_Files Shift_Parameters"
1113 "3Shift Parameters\n"
1114 " Shift the command files positional parameters\r\n"
1115 #define HLP_CALL "*Commands Executing_Command_Files Call_a_subroutine"
1116 "3Call a subroutine\n"
1117 " Control can be transferred to a labeled subroutine using `CALL`.\r\n\r\n"
1118 " **Example**\r\n\r\n"
1119 "++CALL routine\r\n"
1120 "++BYE\r\n"
1121 "++\r\n"
1122 "++:routine\r\n"
1123 "++ECHO routine called\r\n"
1124 "++RETURN\r\n\r\n"
1125 #define HLP_ON "*Commands Executing_Command_Files ON"
1126 "3ON\n"
1127 " The `ON` command performs actions after a condition, or clears a condition.\r\n"
1128 "++ON <condition> <action> Perform action after condition\r\n"
1129 "++ON <condition> Clears action of specified condition\r\n"
1130 #define HLP_PROCEED "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1131 #define HLP_IGNORE "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1132
1133 "3PROCEED or IGNORE\n"
1134 " The `PROCEED` (or `IGNORE`) command does nothing. It is potentially\r\n"
1135 " useful as a placeholder for any `ON` action condition that should be\r\n"
1136 " explicitly ignored, allowing command file execution to continue without\r\n"
1137 " taking any specific action.\r\n"
1138 #define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1139
1140 "3Displaying Arbitrary Text\n"
1141 " The `ECHO` command is a useful way of annotating command files. `ECHO`\r\n"
1142 " prints out its arguments to the console (and to any applicable log file):\r\n\r\n"
1143 "++ECHO <string> Output string to console\r\n\r\n"
1144 " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\r\n"
1145 " This may be used to provide spacing for console messages or log file\r\n"
1146 " output.\r\n"
1147
1148 #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Assertions"
1149 "3Testing Assertions\n"
1150 " The `ASSERT` command tests a simulator state condition and halts command\r\n"
1151 " file execution if the condition is false:\r\n\r\n"
1152 "++ASSERT <Simulator State Expressions>\r\n\r\n"
1153 " * If the indicated expression evaluates to false, the command completes\r\n"
1154 " with an `AFAIL` condition. By default, when a command file encounters a\r\n"
1155 " command which returns the `AFAIL` condition, it will exit the running\r\n"
1156 " command file with the `AFAIL` status to the calling command file. This\r\n"
1157 " behavior can be changed with the `ON` command as well as switches to the\r\n"
1158 " invoking `DO` command.\r\n\r\n"
1159 " **Examples**\r\n\r\n"
1160 " The command file below might be used to bootstrap a hypothetical system\r\n"
1161 " that halts after the initial load from disk. The `ASSERT` command can then\r\n"
1162 " be used to confirm that the load completed successfully by examining the\r\n"
1163 " CPU's \"`A`\" register for the expected value:`\r\n\r\n"
1164 "++; Example INI file\r\n"
1165 "++BOOT\r\n"
1166 "++; A register contains error code; 0 = good boot\r\n"
1167 "++ASSERT A=0\r\n"
1168 "++RUN\r\n\r\n"
1169
1170 " * In the above example, if the \"`A`\" register is *not* `0`,\r\n"
1171 " the \"`ASSERT A=0`\" command will be displayed to the user, and the\r\n"
1172 " command file will be aborted with an \"`Assertion failed`\" message.\r\n"
1173 " Otherwise, the command file will continue to bring up the system.\r\n\r\n"
1174 " * See the **`IF`** command documentation for more information and details\r\n"
1175 " regarding simulator state expressions.\r\n\r\n"
1176 #define HLP_IF "*Commands Executing_Command_Files Testing_Conditions"
1177 "3Testing Conditions\n"
1178 " The `IF` command tests a simulator state condition and executes additional\r\n"
1179 " commands if the condition is true:\r\n\r\n"
1180 "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\r\n\r\n"
1181 " **Examples**\r\n\r\n"
1182 " The command file below might be used to bootstrap a hypothetical system\r\n"
1183 " that halts after the initial load from disk. The `IF` command can then\r\n"
1184 " be used to confirm that the load completed successfully by examining the\r\n"
1185 " CPU's \"`A`\" register for an expected value:\r\n\r\n"
1186 "++; Example INI file\r\n"
1187 "++BOOT\r\n"
1188 "++; A register contains error code; 0 = good boot\r\n"
1189 "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\r\n"
1190 "++RUN\r\n\r\n"
1191
1192 " * In the above example, if the \"`A`\" register is *not* `0`, the\r\n"
1193 " message \"`Boot failed - Failure Code `\" will be displayed, the contents\r\n"
1194 " of the \"`A`\" register will be displayed, and the command file will be\r\n"
1195 " aborted with an \"`Assertion failed`\" message. Otherwise, the command\r\n"
1196 " file will continue to bring up the system.\r\n"
1197 "4Conditional Expressions\n"
1198 " The `IF` and `ASSERT` commands evaluate the following two different forms\r\n"
1199 " of conditional expressions.\r\n\r\n"
1200 "5Simulator State Expressions\n"
1201 " \r\n \r\n"
1202 " The values of simulator registers can be evaluated with:\r\n\r\n"
1203 "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\r\n\r\n"
1204 " * If \"<`dev`>\" is not specified, `CPU` is assumed. \"<`reg`>\" is a\r\n"
1205 " register belonging to the indicated device.\r\n"
1206 " * The \"<`addr`>\" is an address in the address space of the indicated\r\n"
1207 " device.\r\n"
1208 " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\r\n"
1209 " the same as those used for \"search specifiers\" by the `EXAMINE` and\r\n"
1210 " `DEPOSIT` commands.\r\n"
1211 " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\r\n"
1212 " not in the radix for the device when referencing a register; when an\r\n"
1213 " address is referenced the device radix is used as the default.\r\n\r\n"
1214 " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\r\n"
1215 " register value is first altered as indicated. The result is then compared\r\n"
1216 " to the \"<`value`>\" via the \"<`conditional-op`>\".\r\n"
1217 " * * If the result is *true*, the command(s) are executed before proceeding\r\n"
1218 " to the next line in the command file.\r\n"
1219 " * * If the result is *false*, the next command in the command file is\r\n"
1220 " processed.\r\n\r\n"
1221 "5String Comparison Expressions\n"
1222 " \r\n \r\n"
1223 " String Values can be compared with:\r\n\r\n"
1224 "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\r\n\r\n"
1225 " * The \"`-i`\" switch, if present, causes a comparison to be case\r\n"
1226 " insensitive.\r\n"
1227 " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\r\n"
1228 " values which may have environment variables substituted as desired.\r\n"
1229 " * The \"<`compare-op`>\" may be one of:\r\n\r\n"
1230 " | | |\r\n"
1231 " | --------------:|:---------------------- |\r\n"
1232 " | \"**`==`**\" | equal |\r\n"
1233 " | \"**`EQU`**\" | equal |\r\n"
1234 " | \"**`!=`**\" | not equal |\r\n"
1235 " | \"**`NEQ`**\" | not equal |\r\n"
1236 " | \"**<**\" | less than |\r\n"
1237 " | \"**`LSS`**\" | less than |\r\n"
1238 " | \"**<=**\" | less than or equal |\r\n"
1239 " | \"**`LEQ`**\" | less than or equal |\r\n"
1240 " | \"**>**\" | greater than |\r\n"
1241 " | \"**`GTR`**\" | greater than |\r\n"
1242 " | \"**>=**\" | greater than or equal |\r\n"
1243 " | \"**`GEQ`**\" | greater than or equal |\r\n"
1244 " * **NOTE**: Comparisons are *generic*. This means that if\r\n"
1245 " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\r\n"
1246 " digits, then the strings are converted to numbers and a numeric\r\n"
1247 " comparison is performed. For example, the comparison\r\n"
1248 " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\r\n"
1249
1250 #define HLP_EXIT "*Commands Exiting_the_Simulator"
1251 "2Exiting the Simulator\n"
1252 " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\r\n"
1253 " returning control to the host operating system.\r\n"
1254
1255 #define HLP_SPAWN "*Commands Executing_System_Commands"
1256 "2Executing System Commands\n"
1257 " * The simulator can execute host operating system commands with\r\n"
1258 " the \"`!`\" (*spawn*) command.\r\n\r\n"
1259 " | | |\r\n"
1260 " |:----------------------- |:------------------------------------------- |\r\n"
1261 " | \"**`!`**\" | Spawn the hosts default command interpreter |\r\n"
1262 " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\r\n\r\n"
1263 " * **NOTE**: The *exit status* from the command which was executed is set\r\n"
1264 " as the *command completion status* for the \"`!`\" command. This may\r\n"
1265 " influence any enabled `ON` condition traps.\r\n" ;
1266
1267
1268 static CTAB cmd_table[] = {
1269 { "RESET", &reset_cmd, 0, HLP_RESET },
1270 { "EXAMINE", &exdep_cmd, EX_E, HLP_EXAMINE },
1271 { "IEXAMINE", &exdep_cmd, EX_E+EX_I, HLP_IEXAMINE },
1272 { "DEPOSIT", &exdep_cmd, EX_D, HLP_DEPOSIT },
1273 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, HLP_IDEPOSIT },
1274 { "EVALUATE", &eval_cmd, 0, HLP_EVALUATE },
1275 { "RUN", &run_cmd, RU_RUN, HLP_RUN, NULL, &run_cmd_message },
1276 { "GO", &run_cmd, RU_GO, HLP_GO, NULL, &run_cmd_message },
1277 { "STEP", &run_cmd, RU_STEP, HLP_STEP, NULL, &run_cmd_message },
1278 { "NEXT", &run_cmd, RU_NEXT, HLP_NEXT, NULL, &run_cmd_message },
1279 { "CONTINUE", &run_cmd, RU_CONT, HLP_CONTINUE, NULL, &run_cmd_message },
1280 { "BOOT", &run_cmd, RU_BOOT, HLP_BOOT, NULL, &run_cmd_message },
1281 { "BREAK", &brk_cmd, SSH_ST, HLP_BREAK },
1282 { "NOBREAK", &brk_cmd, SSH_CL, HLP_NOBREAK },
1283 { "ATTACH", &attach_cmd, 0, HLP_ATTACH },
1284 { "DETACH", &detach_cmd, 0, HLP_DETACH },
1285 { "EXIT", &exit_cmd, 0, HLP_EXIT },
1286 { "QUIT", &exit_cmd, 0, NULL },
1287 { "BYE", &exit_cmd, 0, NULL },
1288 { "SET", &set_cmd, 0, HLP_SET },
1289 { "SHOW", &show_cmd, 0, HLP_SHOW },
1290 { "DO", &do_cmd, 1, HLP_DO },
1291 { "GOTO", &goto_cmd, 1, HLP_GOTO },
1292 { "RETURN", &return_cmd, 0, HLP_RETURN },
1293 { "SHIFT", &shift_cmd, 0, HLP_SHIFT },
1294 { "CALL", &call_cmd, 0, HLP_CALL },
1295 { "ON", &on_cmd, 0, HLP_ON },
1296 { "IF", &assert_cmd, 0, HLP_IF },
1297 { "PROCEED", &noop_cmd, 0, HLP_PROCEED },
1298 { "IGNORE", &noop_cmd, 0, HLP_IGNORE },
1299 { "ECHO", &echo_cmd, 0, HLP_ECHO },
1300 { "ASSERT", &assert_cmd, 1, HLP_ASSERT },
1301 { "SEND", &send_cmd, 0 },
1302 { "EXPECT", &expect_cmd, 1 },
1303 { "NOEXPECT", &expect_cmd, 0 },
1304 { "!", &spawn_cmd, 0, HLP_SPAWN },
1305 { "HELP", &help_cmd, 0, HLP_HELP },
1306 { NULL, NULL, 0 }
1307 };
1308
1309 static CTAB set_glob_tab[] = {
1310 { "CONSOLE", &sim_set_console, 0 },
1311 { "REMOTE", &sim_set_remote_console, 0 },
1312 { "BREAK", &brk_cmd, SSH_ST },
1313 { "NOBREAK", &brk_cmd, SSH_CL },
1314 { "TELNET", &sim_set_telnet, 0 },
1315 { "NOTELNET", &sim_set_notelnet, 0 },
1316 { "LOG", &sim_set_logon, 0, HLP_SET_LOG },
1317 { "NOLOG", &sim_set_logoff, 0, HLP_SET_LOG },
1318 { "DEBUG", &sim_set_debon, 0, HLP_SET_DEBUG },
1319 { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
1320 { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
1321 { "ON", &set_on, 1, HLP_SET_ON },
1322 { "NOON", &set_on, 0, HLP_SET_ON },
1323 { "VERIFY", &set_verify, 1, HLP_SET_VERIFY },
1324 { "VERBOSE", &set_verify, 1, HLP_SET_VERIFY },
1325 { "NOVERIFY", &set_verify, 0, HLP_SET_VERIFY },
1326 { "NOVERBOSE", &set_verify, 0, HLP_SET_VERIFY },
1327 { "MESSAGE", &set_message, 1, HLP_SET_MESSAGE },
1328 { "NOMESSAGE", &set_message, 0, HLP_SET_MESSAGE },
1329 { "QUIET", &set_quiet, 1, HLP_SET_QUIET },
1330 { "NOQUIET", &set_quiet, 0, HLP_SET_QUIET },
1331 { "LOCALOPC", &set_localopc, 1, HLP_SET_LOCALOPC },
1332 { "NOLOCALOPC", &set_localopc, 0, HLP_SET_LOCALOPC },
1333 { "PROMPT", &set_prompt, 0, HLP_SET_PROMPT },
1334 { NULL, NULL, 0 }
1335 };
1336
1337 static C1TAB set_dev_tab[] = {
1338 { "OCTAL", &set_dev_radix, 8 },
1339 { "DECIMAL", &set_dev_radix, 10 },
1340 { "HEX", &set_dev_radix, 16 },
1341 { "ENABLED", &set_dev_enbdis, 1 },
1342 { "DISABLED", &set_dev_enbdis, 0 },
1343 { "DEBUG", &set_dev_debug, 1 },
1344 { "NODEBUG", &set_dev_debug, 0 },
1345 { NULL, NULL, 0 }
1346 };
1347
1348 static C1TAB set_unit_tab[] = {
1349 { "ENABLED", &set_unit_enbdis, 1 },
1350 { "DISABLED", &set_unit_enbdis, 0 },
1351 { NULL, NULL, 0 }
1352 };
1353
1354 static SHTAB show_glob_tab[] = {
1355 { "CONFIGURATION", &show_config, 0, HLP_SHOW_CONFIG },
1356 { "DEFAULT_BASE_SYSTEM_SCRIPT",
1357 &show_default_base_system_script, 0, HLP_SHOW_DBS },
1358 { "DEVICES", &show_config, 1, HLP_SHOW_DEVICES },
1359 { "FEATURES", &show_config, 2, HLP_SHOW_FEATURES },
1360 { "QUEUE", &show_queue, 0, HLP_SHOW_QUEUE },
1361 { "TIME", &show_time, 0, HLP_SHOW_TIME },
1362 { "MODIFIERS", &show_mod_names, 0, HLP_SHOW_MODIFIERS },
1363 { "NAMES", &show_log_names, 0, HLP_SHOW_NAMES },
1364 { "SHOW", &show_show_commands, 0, HLP_SHOW_SHOW },
1365 { "VERSION", &show_version, 1, HLP_SHOW_VERSION },
1366 { "BUILDINFO", &show_buildinfo, 1, HLP_SHOW_BUILDINFO },
1367 { "PROM", &show_prom, 0, HLP_SHOW_PROM },
1368 { "HINTS", &show_hints, 0, HLP_SHOW_HINTS },
1369 { "CONSOLE", &sim_show_console, 0, HLP_SHOW_CONSOLE },
1370 { "REMOTE", &sim_show_remote_console, 0, HLP_SHOW_REMOTE },
1371 { "BREAK", &show_break, 0, HLP_SHOW_BREAK },
1372 { "LOG", &sim_show_log, 0, HLP_SHOW_LOG },
1373 { "TELNET", &sim_show_telnet, 0 },
1374 { "DEBUG", &sim_show_debug, 0, HLP_SHOW_DEBUG },
1375 { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS },
1376 { "SEND", &sim_show_send, 0, HLP_SHOW_SEND },
1377 { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT },
1378 { "ON", &show_on, 0, HLP_SHOW_ON },
1379 { NULL, NULL, 0 }
1380 };
1381
1382 static SHTAB show_dev_tab[] = {
1383 { "RADIX", &show_dev_radix, 0 },
1384 { "DEBUG", &show_dev_debug, 0 },
1385 { "MODIFIERS", &show_dev_modifiers, 0 },
1386 { "NAMES", &show_dev_logicals, 0 },
1387 { "SHOW", &show_dev_show_commands, 0 },
1388 { NULL, NULL, 0 }
1389 };
1390
1391 static SHTAB show_unit_tab[] = {
1392 { NULL, NULL, 0 }
1393 };
1394
1395 #if defined(_WIN32)
1396 static
1397 int setenv(const char *envname, const char *envval, int overwrite)
1398 {
1399 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1400 int r;
1401
1402 (void)sprintf(envstr, "%s=%s", envname, envval);
1403 r = _putenv(envstr);
1404 FREE(envstr);
1405 return r;
1406 }
1407
1408 static
1409 int unsetenv(const char *envname)
1410 {
1411 setenv(envname, "", 1);
1412 return 0;
1413 }
1414 #endif
1415
1416 #if !defined(NO_LOCALE)
1417 # define XSTR_EMAXLEN 32767
1418
1419 const char
1420 *xstrerror_l(int errnum)
1421 {
1422 int saved = errno;
1423 const char *ret = NULL;
1424 static __thread char buf[XSTR_EMAXLEN];
1425
1426 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1427 defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1428 # if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1429 if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf;
1430 # else
1431 if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf;
1432 # endif
1433 # else
1434 # if defined(__NetBSD__)
1435 locale_t loc = LC_GLOBAL_LOCALE;
1436 # else
1437 locale_t loc = uselocale((locale_t)0);
1438 # endif
1439 locale_t copy = loc;
1440 if (copy == LC_GLOBAL_LOCALE)
1441 copy = duplocale(copy);
1442
1443 if (copy != (locale_t)0)
1444 {
1445 ret = strerror_l(errnum, copy);
1446 if (loc == LC_GLOBAL_LOCALE)
1447 {
1448 freelocale(copy);
1449 }
1450 }
1451 # endif
1452
1453 if (!ret)
1454 {
1455 (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1456 ret = buf;
1457 }
1458
1459 errno = saved;
1460 return ret;
1461 }
1462 #else
1463 # define xstrerror_l strerror
1464 #endif
1465
1466 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1467
1468
1469
1470 char *strremove(char *str, const char *sub)
1471 {
1472 char *p, *q, *r;
1473 if (*sub && (q = r = strstr(str, sub)) != NULL) {
1474 size_t len = strlen(sub);
1475 while ((r = strstr(p = r + len, sub)) != NULL) {
1476 while (p < r)
1477 *q++ = *p++;
1478 }
1479 while ((*q++ = *p++) != '\0')
1480 continue;
1481 }
1482 return str;
1483 }
1484
1485
1486
1487 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
1488 {
1489 while (*str_untrimmed != '\0') {
1490 if(!isspace((unsigned char)*str_untrimmed)) {
1491 *str_trimmed = (char)*str_untrimmed;
1492 str_trimmed++;
1493 }
1494 str_untrimmed++;
1495 }
1496 *str_trimmed = '\0';
1497 }
1498
1499 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1500 void allowCores(void)
1501 {
1502 int ret;
1503 struct rlimit limit;
1504 # if defined(RLIMIT_CORE)
1505 ret = getrlimit(RLIMIT_CORE, &limit);
1506 (void)ret;
1507 # if defined(TESTING)
1508 if (ret != 0)
1509 {
1510 sim_warn ("Failed to query core dump configuration.");
1511 return;
1512 }
1513 # endif
1514 limit.rlim_cur = limit.rlim_max;
1515 ret = setrlimit(RLIMIT_CORE, &limit);
1516 # if defined(TESTING)
1517 if (ret != 0)
1518 {
1519 sim_warn ("Failed to enable unlimited core dumps.");
1520 return;
1521 }
1522 # endif
1523 # else
1524 # if defined(TESTING)
1525 sim_warn ("Unable to query core dump configuration.");
1526 # endif
1527 # endif
1528 return;
1529 }
1530 #endif
1531
1532 #if defined(USE_DUMA)
1533 void CleanDUMA(void)
1534 {
1535 (void)fflush(stdout);
1536 DUMA_CHECKALL();
1537 (void)fflush(stderr);
1538 }
1539 # undef USE_DUMA
1540 # define USE_DUMA 1
1541 #endif
1542
1543 #if !defined(SIG_SETMASK)
1544 # undef USE_BACKTRACE
1545 #endif
1546
1547 #if defined(PERF_STRIP)
1548 # undef USE_BACKTRACE
1549 #endif
1550
1551 #if defined(USE_BACKTRACE)
1552 # include <backtrace.h>
1553 # include <backtrace-supported.h>
1554 # define BACKTRACE_SKIP 1
1555 # define BACKTRACE_MAIN "main"
1556 # undef USE_BACKTRACE
1557 # define USE_BACKTRACE 1
1558 #endif
1559
1560 #if defined(BACKTRACE_SUPPORTED)
1561 # if defined(BACKTRACE_SUPPORTS_THREADS)
1562 # if !(BACKTRACE_SUPPORTED)
1563 # undef USE_BACKTRACE
1564 # endif
1565 # else
1566 # undef USE_BACKTRACE
1567 # endif
1568 #else
1569 # undef USE_BACKTRACE
1570 #endif
1571
1572 #if defined(USE_BACKTRACE)
1573 # if defined(BACKTRACE_SUPPORTED)
1574 # include "backtrace_func.c"
1575 # endif
1576 #endif
1577
1578 #if !defined(__CYGWIN__)
1579 # if !defined(__APPLE__)
1580 # if !defined(_AIX)
1581 # if !defined(__MINGW32__)
1582 # if !defined(__MINGW64__)
1583 # if !defined(CROSS_MINGW32)
1584 # if !defined(CROSS_MINGW64)
1585 # if !defined(_WIN32)
1586 # if !defined(__HAIKU__)
1587 # if !defined(__QNX__)
1588 static int
1589 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
1590 {
1591 (void)size;
1592 (void)data;
1593
1594 if (strlen(info->dlpi_name) >= 2) {
1595 if (!dl_iterate_phdr_callback_called)
1596 (void)printf ("\r\n Loaded shared objects: ");
1597
1598 dl_iterate_phdr_callback_called++;
1599 (void)printf ("%s ", info->dlpi_name);
1600 }
1601
1602 return 0;
1603 }
1604 # endif
1605 # endif
1606 # endif
1607 # endif
1608 # endif
1609 # endif
1610 # endif
1611 # endif
1612 # endif
1613 #endif
1614
1615 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1616 # if defined(_UCRT)
1617 # define MINGW_CRT "UCRT"
1618 # else
1619 # define MINGW_CRT "MSVCRT"
1620 # endif
1621 #endif
1622
1623 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1624 struct UCRTVersion
1625 {
1626 uint16_t ProductVersion[4];
1627 };
1628
1629 int
1630 GetUCRTVersion (struct UCRTVersion *ucrtversion)
1631 {
1632 # ifdef _DEBUG
1633 static const wchar_t *DllName = L"ucrtbased.dll";
1634 # else
1635 static const wchar_t *DllName = L"ucrtbase.dll";
1636 # endif
1637
1638 HMODULE ucrt = GetModuleHandleW (DllName);
1639 if (!ucrt)
1640 return GetLastError ();
1641
1642 wchar_t path[SIR_MAXPATH];
1643 if (!GetModuleFileNameW (ucrt, path, SIR_MAXPATH))
1644 return GetLastError ();
1645
1646 DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1647 if (!versionInfoSize)
1648 return GetLastError ();
1649
1650 uint8_t versionInfo[versionInfoSize];
1651
1652 if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1653 return GetLastError ();
1654
1655 VS_FIXEDFILEINFO *fixedFileInfo;
1656 UINT fixedFileInfoSize;
1657 if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1658 return GetLastError ();
1659
1660 memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1661
1662 return 0;
1663 }
1664 #endif
1665
1666
1667
1668 #if !defined(PERF_STRIP)
1669 static int dps8_sir_report_error(void)
1670 {
1671 char message[SIR_MAXERROR] = {0};
1672 (void)sir_geterror(message);
1673 (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1674 return EXIT_FAILURE;
1675 }
1676
1677
1678
1679 int main (int argc, char *argv[])
1680 {
1681 char *cptr, *cptr2;
1682 char nbuf[PATH_MAX + 7];
1683 char cbuf[4*CBUFSIZE];
1684 char **targv = NULL;
1685 int32 i, sw;
1686 t_bool lookswitch;
1687 t_stat stat;
1688
1689
1690 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1691 uid_t real_uid = getuid();
1692 uid_t eff_uid = geteuid();
1693 if (0 == eff_uid && 0 != real_uid) {
1694 (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1695 exit(EXIT_FAILURE);
1696 }
1697 # endif
1698
1699 sunos_obtain_realtime_privileges();
1700
1701 sim_free_memory = sim_memory_available();
1702
1703 sim_appfilename = _sir_getappfilename();
1704 if (sim_appfilename == NULL) {
1705 sim_appfilename = "dps8";
1706 }
1707
1708
1709
1710 sirinit si;
1711 if (!sir_makeinit(&si))
1712 return dps8_sir_report_error();
1713
1714
1715 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1716
1717
1718 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1719
1720
1721 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1722
1723
1724 si.d_stderr.opts = SIRO_NOHOST;
1725
1726
1727 si.d_syslog.levels = SIRL_NONE;
1728
1729
1730 si.d_syslog.opts = SIRO_DEFAULT;
1731
1732
1733 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1734
1735
1736 if (!sir_init(&si))
1737 return dps8_sir_report_error();
1738
1739 # if defined(_AIX)
1740 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1741 if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1742 (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1743 __func__, __FILE__, __LINE__);
1744 abort();
1745 }
1746
1747 if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1748 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1749 }
1750
1751 if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1752 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1753 }
1754
1755 if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1756 (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1757 }
1758
1759 # if !defined(__PASE__)
1760 if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1761 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1762 }
1763 # else
1764 # if !defined(TESTING)
1765 if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1766 (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1767 }
1768 # endif
1769 # endif
1770
1771 if (execvp(argv[0], argv) == -1) {
1772 (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1773 __func__, __FILE__, __LINE__);
1774 abort();
1775 }
1776 }
1777 # endif
1778
1779 # if defined(USE_BACKTRACE)
1780 # if defined(BACKTRACE_SUPPORTED)
1781 # if defined(_INC_BACKTRACE_FUNC)
1782 bt_pid = (long)_sir_getpid();
1783 (void)bt_pid;
1784 # endif
1785 # endif
1786 # endif
1787
1788 # if defined(__MINGW32__)
1789 # undef IS_WINDOWS
1790 # define IS_WINDOWS 1
1791 # if !defined(NEED_CONSOLE_SETUP)
1792 # define NEED_CONSOLE_SETUP
1793 # endif
1794 # endif
1795
1796 # if defined(CROSS_MINGW32)
1797 # undef IS_WINDOWS
1798 # define IS_WINDOWS 1
1799 # if !defined(NEED_CONSOLE_SETUP)
1800 # define NEED_CONSOLE_SETUP
1801 # endif
1802 # endif
1803
1804 # if defined(__MINGW64__)
1805 # undef IS_WINDOWS
1806 # define IS_WINDOWS 1
1807 # if !defined(NEED_CONSOLE_SETUP)
1808 # define NEED_CONSOLE_SETUP
1809 # endif
1810 # endif
1811
1812 # if defined(CROSS_MINGW64)
1813 # undef IS_WINDOWS
1814 # define IS_WINDOWS 1
1815 # if !defined(NEED_CONSOLE_SETUP)
1816 # define NEED_CONSOLE_SETUP
1817 # endif
1818 # endif
1819
1820 # if defined(__CYGWIN__)
1821 # if defined(IS_WINDOWS)
1822 # undef IS_WINDOWS
1823 # endif
1824 # endif
1825
1826 # if defined(USE_DUMA)
1827 # if defined(DUMA_EXPLICIT_INIT)
1828 duma_init();
1829 (void)fflush(stderr);
1830 # endif
1831 # if defined(DUMA_MIN_ALIGNMENT)
1832 # if DUMA_MIN_ALIGNMENT > 0
1833 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1834 # endif
1835 # endif
1836 DUMA_SET_FILL(0x2E);
1837 (void)fflush(stderr);
1838 (void)atexit(CleanDUMA);
1839 # endif
1840
1841 # if defined(USE_BACKTRACE)
1842 # if defined(BACKTRACE_SUPPORTED)
1843 # include "backtrace_main.c"
1844 # endif
1845 # endif
1846
1847 # if !defined(NO_LOCALE)
1848 (void)setlocale(LC_ALL, "");
1849 # endif
1850
1851 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1852 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1853 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1854 # endif
1855 # endif
1856
1857 # if defined(NEED_CONSOLE_SETUP)
1858 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1859 if (handle != INVALID_HANDLE_VALUE)
1860 {
1861 DWORD mode = 0;
1862 if (GetConsoleMode(handle, &mode))
1863 {
1864 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1865 SetConsoleMode(handle, mode);
1866 }
1867 }
1868 puts ("\e[0m");
1869 # endif
1870
1871 # if defined(__HAIKU__)
1872 (void)disable_debugger(1);
1873 # endif
1874
1875 running_perf_test = false;
1876
1877
1878 char thread_name[SIR_MAXPID] = {0};
1879 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1880 (void)_sir_setthreadname(thread_name);
1881
1882
1883
1884 # if defined(__clang_analyzer__)
1885 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1886 return 1;
1887 # endif
1888
1889 if (argc == 0) {
1890 (void)fprintf (stderr, "Error: main() called directly!\r\n");
1891 return 1;
1892 }
1893
1894
1895 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1896 allowCores();
1897 # endif
1898
1899 int testEndian = decContextTestEndian();
1900 if (testEndian != 0) {
1901 if (testEndian == 1) {
1902 (void)fprintf (stderr,
1903 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1904 return 1;
1905 }
1906 if (testEndian == -1) {
1907 (void)fprintf (stderr,
1908 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1909 return 1;
1910 }
1911 (void)fprintf (stderr,
1912 "Error: Unable to determine system byte order; aborting.\r\n");
1913 return 1;
1914 }
1915 # if defined(NEED_128)
1916 test_math128();
1917 # endif
1918
1919 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1920
1921 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1922
1923
1924
1925
1926 nprocs = (unsigned int)uv_available_parallelism();
1927 # else
1928 nprocs = (unsigned int)_sir_nprocs();
1929 # endif
1930 ncores = (unsigned int)get_core_count();
1931
1932
1933 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1934 if (!targv)
1935 {
1936 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1937 __func__, __FILE__, __LINE__);
1938 # if defined(USE_BACKTRACE)
1939 # if defined(SIGUSR2)
1940 (void)raise(SIGUSR2);
1941
1942 # endif
1943 # endif
1944 abort();
1945 }
1946 for (i=0; i<argc; i++)
1947 targv[i] = argv[i];
1948 argv = targv;
1949
1950
1951 set_prompt (0, "sim>");
1952 *cbuf = 0;
1953 sim_switches = 0;
1954 lookswitch = TRUE;
1955 stdnul = fopen(NULL_DEVICE,"wb");
1956
1957
1958 for (i = 1; i < argc; i++) {
1959 if (argv[i] == NULL)
1960 continue;
1961
1962 # if defined(THREADZ) || defined(LOCKLESS)
1963
1964 int perftestflag = strcmp(argv[i], "--perftest");
1965 if (perftestflag == 0) {
1966 char * testName = NULL;
1967 if (i + 1 < argc)
1968 testName = argv[i + 1];
1969 perfTest (testName);
1970 return 0;
1971 }
1972 # endif
1973
1974
1975 int onlyvers = strcmp(argv[i], "--version");
1976 if (onlyvers == 0) {
1977 # if defined(VER_H_GIT_VERSION)
1978 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1979 # if VER_H_GIT_PATCH_INT < 1
1980 (void)fprintf (stdout, "%s simulator %s\r\n",
1981 sim_name, VER_H_GIT_VERSION);
1982 # else
1983 (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1984 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1985 # endif
1986 # else
1987 (void)fprintf (stdout, "%s simulator %s\r\n",
1988 sim_name, VER_H_GIT_VERSION);
1989 # endif
1990 # else
1991 (void)fprintf (stdout, "%s simulator\r\n", sim_name);
1992 # endif
1993 FREE (targv);
1994 return 0;
1995 }
1996
1997
1998 int longhelp = strcmp(argv[i], "--help");
1999 int shorthelp = strcmp(argv[i], "-h");
2000 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2001 if (longhelp == 0 || shorthelp == 0) {
2002 # if defined(VER_H_GIT_VERSION)
2003 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2004 # if VER_H_GIT_PATCH_INT < 1
2005 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2006 # else
2007 (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2008 # endif
2009 # else
2010 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2011 # endif
2012 # else
2013 (void)fprintf (stdout, "%s simulator", sim_name);
2014 # endif
2015 (void)fprintf (stdout, "\r\n");
2016 (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2017 (void)fprintf (stdout, "\r\n");
2018 (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2019 (void)fprintf (stdout, "\r\n");
2020 (void)fprintf (stdout, "\r\n Switches:");
2021 (void)fprintf (stdout, "\r\n -e, -E Aborts script processing immediately upon any error");
2022 (void)fprintf (stdout, "\r\n -h, -H, --help Prints only this informational help text and exits");
2023 (void)fprintf (stdout, "\r\n -k, -K Disables all support for exclusive file locking");
2024 (void)fprintf (stdout, "\r\n -l, -L Reports but ignores all exclusive file locking errors");
2025 (void)fprintf (stdout, "\r\n -o, -O Makes scripting ON conditions and actions inheritable");
2026 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2027 (void)fprintf (stdout, "\r\n -p, -P Enables real-time scheduling (may require privileges)");
2028 # endif
2029 (void)fprintf (stdout, "\r\n -q, -Q Disables printing of non-fatal informational messages");
2030 (void)fprintf (stdout, "\r\n -r, -R Enables an unlinked ephemeral system state file");
2031 (void)fprintf (stdout, "\r\n -s, -S Enables a randomized persistent system state file");
2032 (void)fprintf (stdout, "\r\n -t, -T Disables fsync and creation/usage of system state file");
2033 (void)fprintf (stdout, "\r\n -v, -V Prints commands read from script file before execution");
2034 (void)fprintf (stdout, "\r\n --version Prints only the simulator identification text and exits");
2035 (void)fprintf (stdout, "\r\n");
2036 # if defined(USE_DUMA)
2037 nodist++;
2038 # endif
2039 if (!nodist) {
2040 (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2041 (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2042 (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2043 }
2044 else
2045 {
2046 (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2047 }
2048 (void)fprintf (stdout, "\r\n");
2049 FREE(argv);
2050 return 0;
2051 }
2052
2053 if ((*argv[i] == '-') && lookswitch) {
2054 if ((sw = get_switches (argv[i])) < 0) {
2055 (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2056 FREE(argv);
2057 return 1;
2058 }
2059 sim_switches = sim_switches | sw;
2060 }
2061
2062 else {
2063 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2064 (void)fprintf (stderr, "Argument string too long\r\n");
2065 FREE(argv);
2066 return 1;
2067 }
2068 if (*cbuf)
2069 strcat (cbuf, " ");
2070 (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s",
2071 strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
2072 lookswitch = FALSE;
2073 }
2074 }
2075 sim_nolock = sim_switches & SWMASK ('K');
2076 sim_iglock = sim_switches & SWMASK ('L');
2077 sim_randompst = sim_switches & SWMASK ('S');
2078 sim_quiet = sim_switches & SWMASK ('Q');
2079 sim_randstate = sim_switches & SWMASK ('R');
2080 if (sim_randompst) sim_randstate = 1;
2081 sim_nostate = sim_switches & SWMASK ('T');
2082 if (sim_nostate)
2083 {
2084 sim_randompst = 0;
2085 sim_randstate = 0;
2086 }
2087 sim_on_inherit = sim_switches & SWMASK ('O');
2088
2089 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2090 !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2091 sim_realtime = sim_switches & SWMASK ('P');
2092 # endif
2093
2094 sim_init_sock ();
2095 if (sim_dflt_dev == NULL)
2096 sim_dflt_dev = sim_devices[0];
2097 if (sim_vm_init != NULL)
2098 (*sim_vm_init)();
2099 sim_finit ();
2100 for (i = 0; cmd_table[i].name; i++) {
2101 size_t alias_len = strlen (cmd_table[i].name);
2102 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2103 if (!cmd_name)
2104 {
2105 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2106 __func__, __FILE__, __LINE__);
2107 # if defined(USE_BACKTRACE)
2108 # if defined(SIGUSR2)
2109 (void)raise(SIGUSR2);
2110
2111 # endif
2112 # endif
2113 abort();
2114 }
2115
2116 strcpy (cmd_name, cmd_table[i].name);
2117 while (alias_len > 1) {
2118 cmd_name[alias_len] = '\0';
2119 --alias_len;
2120 if (getenv (cmd_name))
2121 unsetenv (cmd_name);
2122 }
2123 FREE (cmd_name);
2124 }
2125 stop_cpu = 0;
2126 sim_interval = 0;
2127 sim_time = sim_rtime = 0;
2128 noqueue_time = 0;
2129 sim_clock_queue = QUEUE_LIST_END;
2130 sim_is_running = 0;
2131 sim_log = NULL;
2132 if (sim_emax <= 0)
2133 sim_emax = 1;
2134
2135
2136 main_thread_id = pthread_self();
2137
2138
2139 save_thread_sched(pthread_self());
2140
2141
2142 if (sim_realtime) {
2143 if (nprocs < 2) {
2144 sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2145 exit(EXIT_FAILURE);
2146 } else {
2147 watchdog_startup();
2148 }
2149 }
2150
2151
2152 if (realtime_ok) {
2153 set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2154 check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2155 } else {
2156 # if !defined(__QNX__)
2157 (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2158 # endif
2159 }
2160
2161 sim_timer_init ();
2162
2163 if ((stat = sim_ttinit ()) != SCPE_OK) {
2164 (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2165 sim_error_text (stat));
2166 FREE(argv);
2167 return 1;
2168 }
2169 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2170 (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2171 FREE(argv);
2172 return 1;
2173 };
2174 if ((stat = reset_all_p (0)) != SCPE_OK) {
2175 (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2176 sim_error_text (stat));
2177 FREE(argv);
2178 return 1;
2179 }
2180 if ((stat = sim_brk_init ()) != SCPE_OK) {
2181 (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2182 sim_error_text (stat));
2183 FREE(argv);
2184 return 1;
2185 }
2186 if (!sim_quiet) {
2187 (void)printf ("\r\n");
2188 show_version (stdout, NULL, NULL, 0, NULL);
2189 }
2190
2191 cptr = getenv("HOME");
2192 if (cptr == NULL) {
2193 cptr = getenv("HOMEPATH");
2194 cptr2 = getenv("HOMEDRIVE");
2195 }
2196 else
2197 cptr2 = NULL;
2198 (void)cptr2;
2199 if ( (*cbuf) && (strcmp(cbuf, "")) )
2200 stat = do_cmd (0, cbuf);
2201 else if (*argv[0]) {
2202 char *np;
2203 nbuf[0] = '"';
2204 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
2205 if (stat == SCPE_OPENERR) {
2206 np = strrchr (nbuf, '/');
2207 if (np == NULL)
2208 np = strrchr (nbuf, '\\');
2209 if (np != NULL) {
2210 *np = '"';
2211 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
2212 }
2213 }
2214 }
2215
2216 argv = uv_setup_args(argc, argv);
2217
2218
2219 if (getenv("DPS8M_NO_HINTS") == NULL)
2220 if (!sim_quiet && 0 == strcmp(cbuf, ""))
2221 (void)show_hints(0, 0, 0, 1, 0);
2222
2223 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2224
2225 if (sim_vm_exit != NULL)
2226 (*sim_vm_exit)();
2227
2228 detach_all (0, TRUE);
2229 sim_set_deboff (0, NULL);
2230 sim_set_logoff (0, NULL);
2231 sim_set_notelnet (0, NULL);
2232 sim_ttclose ();
2233 sim_cleanup_sock ();
2234 fclose (stdnul);
2235 FREE (targv);
2236 FREE (sim_prompt);
2237 FREE (sim_eval);
2238 FREE (sim_internal_devices);
2239 FREE (sim_brk_tab);
2240 FREE (sim_staba.comp);
2241 FREE (sim_staba.mask);
2242 FREE (sim_stabr.comp);
2243 FREE (sim_stabr.mask);
2244 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2245 }
2246 #endif
2247
2248 t_stat process_stdin_commands (t_stat stat, char *argv[])
2249 {
2250 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2251 CONST char *cptr;
2252 t_stat stat_nomessage;
2253 CTAB *cmdp = NULL;
2254
2255 stat = SCPE_BARE_STATUS(stat);
2256 while (stat != SCPE_EXIT) {
2257 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
2258 (void)printf ("%s%s\r\n", sim_prompt, cptr);
2259 else if (sim_vm_read != NULL) {
2260 (void)printf ("%s", sim_prompt);
2261 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2262 }
2263 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
2264 if (cptr == NULL) {
2265 if (sim_ttisatty()) continue;
2266 else break;
2267 }
2268 if (*cptr == 0)
2269 continue;
2270 sim_sub_args (cbuf, sizeof(cbuf), argv);
2271 if (sim_log)
2272 (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2273 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2274 (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2275 cptr = get_glyph_cmd (cptr, gbuf);
2276 sim_switches = 0;
2277 if ((cmdp = find_cmd (gbuf)))
2278 stat = cmdp->action (cmdp->arg, cptr);
2279 else
2280 stat = SCPE_UNK;
2281 stat_nomessage = stat & SCPE_NOMESSAGE;
2282 stat_nomessage = stat_nomessage || (!sim_show_message);
2283 stat = SCPE_BARE_STATUS(stat);
2284 sim_last_cmd_stat = stat;
2285 if (!stat_nomessage) {
2286 if (cmdp && (cmdp->message))
2287 cmdp->message (NULL, stat);
2288 else
2289 if (stat >= SCPE_BASE)
2290 sim_printf ("%s\r\n", sim_error_text (stat));
2291 }
2292 if (sim_vm_post != NULL)
2293 (*sim_vm_post) (TRUE);
2294 }
2295 return stat;
2296 }
2297
2298
2299
2300 t_stat set_prompt (int32 flag, CONST char *cptr)
2301 {
2302 char gbuf[CBUFSIZE], *gptr;
2303
2304 if ((NULL == cptr) || (*cptr == '\0'))
2305 return SCPE_ARG;
2306
2307 cptr = get_glyph_nc (cptr, gbuf, '"');
2308 if (gbuf[0] == '\0') {
2309 gbuf[sizeof (gbuf)-1] = '\0';
2310 strncpy (gbuf, cptr, sizeof (gbuf)-1);
2311 gptr = strchr (gbuf, '"');
2312 if (NULL != gptr)
2313 *gptr = '\0';
2314 }
2315 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
2316 if (!sim_prompt)
2317 {
2318 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2319 __func__, __FILE__, __LINE__);
2320 #if defined(USE_BACKTRACE)
2321 # if defined(SIGUSR2)
2322 (void)raise(SIGUSR2);
2323
2324 # endif
2325 #endif
2326 abort();
2327 }
2328 (void)sprintf (sim_prompt, "%s ", gbuf);
2329 return SCPE_OK;
2330 }
2331
2332
2333
2334 CTAB *find_cmd (const char *gbuf)
2335 {
2336 CTAB *cmdp = NULL;
2337
2338 if (sim_vm_cmd)
2339 cmdp = find_ctab (sim_vm_cmd, gbuf);
2340 if (cmdp == NULL)
2341 cmdp = find_ctab (cmd_table, gbuf);
2342 return cmdp;
2343 }
2344
2345
2346
2347 t_stat exit_cmd (int32 flag, CONST char *cptr)
2348 {
2349 return SCPE_EXIT;
2350 }
2351
2352
2353
2354
2355 static int _cmd_name_compare (const void *pa, const void *pb)
2356 {
2357 CTAB * const *a = (CTAB * const *)pa;
2358 CTAB * const *b = (CTAB * const *)pb;
2359
2360 return strcmp((*a)->name, (*b)->name);
2361 }
2362
2363 void fprint_help (FILE *st)
2364 {
2365 CTAB *cmdp;
2366 CTAB **hlp_cmdp = NULL;
2367 size_t cmd_cnt = 0;
2368 size_t cmd_size = 0;
2369 size_t max_cmdname_size = 0;
2370 size_t i, line_offset;
2371
2372 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2373 if (cmdp->help) {
2374 if (cmd_cnt >= cmd_size) {
2375 cmd_size += 20;
2376 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2377 if (!hlp_cmdp)
2378 {
2379 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2380 __func__, __FILE__, __LINE__);
2381 #if defined(USE_BACKTRACE)
2382 # if defined(SIGUSR2)
2383 (void)raise(SIGUSR2);
2384
2385 # endif
2386 #endif
2387 abort();
2388 }
2389 }
2390 hlp_cmdp[cmd_cnt] = cmdp;
2391 ++cmd_cnt;
2392 if (strlen(cmdp->name) > max_cmdname_size)
2393 max_cmdname_size = strlen(cmdp->name);
2394 }
2395 }
2396 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2397 if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2398 if (cmd_cnt >= cmd_size) {
2399 cmd_size += 20;
2400 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2401 if (!hlp_cmdp)
2402 {
2403 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2404 __func__, __FILE__, __LINE__);
2405 #if defined(USE_BACKTRACE)
2406 # if defined(SIGUSR2)
2407 (void)raise(SIGUSR2);
2408
2409 # endif
2410 #endif
2411 abort();
2412 }
2413 }
2414 hlp_cmdp[cmd_cnt] = cmdp;
2415 ++cmd_cnt;
2416 if (strlen (cmdp->name) > max_cmdname_size)
2417 max_cmdname_size = strlen(cmdp->name);
2418 }
2419 }
2420 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n ");
2421 if (hlp_cmdp)
2422 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2423 line_offset = 4;
2424 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2425 fputs (hlp_cmdp[i]->name, st);
2426 line_offset += 5 + max_cmdname_size;
2427 if (line_offset + max_cmdname_size > 79) {
2428 line_offset = 4;
2429 (void)fprintf (st, "\r\n ");
2430 }
2431 else
2432 (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2433 }
2434 FREE (hlp_cmdp);
2435 (void)fprintf (st, "\r\n");
2436 return;
2437 }
2438
2439 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2440 {
2441 if (!*pdone)
2442 (void)fprintf (st, "%s", context);
2443 *pdone = TRUE;
2444 }
2445
2446 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2447 {
2448 REG *rptr, *trptr;
2449 t_bool found = FALSE;
2450 t_bool all_unique = TRUE;
2451 size_t max_namelen = 0;
2452 DEVICE *tdptr;
2453 CONST char *tptr;
2454 char *namebuf;
2455 char rangebuf[32];
2456
2457 if (dptr->registers)
2458 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2459 if (rptr->flags & REG_HIDDEN)
2460 continue;
2461 if (rptr->depth > 1)
2462 (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2463 else
2464 strcpy (rangebuf, "");
2465 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2466 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2467 found = TRUE;
2468 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2469 if ((trptr == NULL) || (tdptr != dptr))
2470 all_unique = FALSE;
2471 }
2472 if (!found) {
2473 if (!silent)
2474 (void)fprintf (st, "No register HELP available for the %s device\r\n",
2475 dptr->name);
2476 }
2477 else {
2478 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2479 if (!namebuf)
2480 {
2481 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2482 __func__, __FILE__, __LINE__);
2483 #if defined(USE_BACKTRACE)
2484 # if defined(SIGUSR2)
2485 (void)raise(SIGUSR2);
2486
2487 # endif
2488 #endif
2489 abort();
2490 }
2491 (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2492 dptr->name);
2493 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2494 if (rptr->flags & REG_HIDDEN)
2495 continue;
2496 if (rptr->depth <= 1)
2497 (void)sprintf (namebuf, "%*s",
2498 -((int)max_namelen),
2499 rptr->name);
2500 else {
2501 (void)sprintf (rangebuf, "[%d:%d]",
2502 0,
2503 rptr->depth-1);
2504 (void)sprintf (namebuf, "%s%*s",
2505 rptr->name,
2506 (int)(strlen(rptr->name))-((int)max_namelen),
2507 rangebuf);
2508 }
2509 if (all_unique) {
2510 (void)fprintf (st, " %s %4d %s\r\n",
2511 namebuf,
2512 rptr->width,
2513 rptr->desc ? rptr->desc : "");
2514 continue;
2515 }
2516 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2517 if ((trptr == NULL) || (tdptr != dptr))
2518 (void)fprintf (st, " %s %s %4d %s\r\n",
2519 dptr->name,
2520 namebuf,
2521 rptr->width,
2522 rptr->desc ? rptr->desc : "");
2523 else
2524 (void)fprintf (st, " %*s %s %4d %s\r\n",
2525 (int)strlen(dptr->name), "",
2526 namebuf,
2527 rptr->width,
2528 rptr->desc ? rptr->desc : "");
2529 }
2530 FREE (namebuf);
2531 }
2532 }
2533
2534 void fprint_reg_help (FILE *st, DEVICE *dptr)
2535 {
2536 fprint_reg_help_ex (st, dptr, TRUE);
2537 }
2538
2539 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2540 {
2541 if (dptr->attach_help) {
2542 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2543 dptr->attach_help (st, dptr, NULL, 0, NULL);
2544 return;
2545 }
2546 if (DEV_TYPE(dptr) == DEV_DISK) {
2547 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2548 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2549 return;
2550 }
2551 if (DEV_TYPE(dptr) == DEV_TAPE) {
2552 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2553 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2554 return;
2555 }
2556 if (!silent) {
2557 (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2558 if (dptr->help)
2559 dptr->help (st, dptr, NULL, 0, NULL);
2560 }
2561 }
2562
2563 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2564 {
2565 MTAB *mptr;
2566 DEBTAB *dep;
2567 t_bool found = FALSE;
2568 char buf[CBUFSIZE], header[CBUFSIZE];
2569 uint32 enabled_units = dptr->numunits;
2570 uint32 unit;
2571
2572 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2573 for (unit=0; unit < dptr->numunits; unit++)
2574 if (dptr->units[unit].flags & UNIT_DIS)
2575 --enabled_units;
2576 if (dptr->modifiers) {
2577 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2578 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2579 continue;
2580 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2581 continue;
2582 if (mptr->mstring) {
2583 fprint_header (st, &found, header);
2584 (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2585 mptr->mstring,
2586 (strchr(mptr->mstring, '=')) \
2587 ? "" : (MODMASK(mptr,MTAB_VALR) \
2588 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2589 ? "{=val}" : "")));
2590 if ((strlen (buf) < 30) || (NULL == mptr->help))
2591 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2592 else
2593 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2594 }
2595 }
2596 }
2597 if (dptr->flags & DEV_DISABLE) {
2598 fprint_header (st, &found, header);
2599 (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2600 (void)fprintf (st, "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2601 (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2602 (void)fprintf (st, "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2603 }
2604 if (dptr->flags & DEV_DEBUG) {
2605 fprint_header (st, &found, header);
2606 (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2607 (void)fprintf (st, "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2608 (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2609 (void)fprintf (st, "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2610 if (dptr->debflags) {
2611 t_bool desc_available = FALSE;
2612 strcpy (buf, "");
2613 (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2614 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2615 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2616 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2617 }
2618 (void)fprintf (st, "\r\n");
2619 (void)fprintf (st, "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2620 (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2621 for (dep = dptr->debflags; dep->name != NULL; dep++)
2622 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2623 (void)fprintf (st, "\r\n");
2624 (void)fprintf (st, "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2625 if (desc_available) {
2626 (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2627 for (dep = dptr->debflags; dep->name != NULL; dep++)
2628 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2629 }
2630 }
2631 }
2632 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2633 if (dptr->units->flags & UNIT_DISABLE) {
2634 fprint_header (st, &found, header);
2635 (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2636 (void)fprintf (st, "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2637 (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2638 (void)fprintf (st, "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2639 }
2640 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2641 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2642 continue;
2643 if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2644 continue;
2645 if (mptr->mstring) {
2646 fprint_header (st, &found, header);
2647 (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2648 (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2649 (strchr(mptr->mstring, '=')) \
2650 ? "" : (MODMASK(mptr,MTAB_VALR) \
2651 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2652 ? "{=val}" : "")));
2653 (void)fprintf (st, "%-30s\t%s\r\n", buf,
2654 (strchr(mptr->mstring, '=')) \
2655 ? "" : (mptr->help ? mptr->help : ""));
2656 }
2657 }
2658 }
2659 if (!found && !silent)
2660 (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2661 }
2662
2663 void fprint_set_help (FILE *st, DEVICE *dptr)
2664 {
2665 fprint_set_help_ex (st, dptr, TRUE);
2666 }
2667
2668 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2669 {
2670 MTAB *mptr;
2671 t_bool found = FALSE;
2672 char buf[CBUFSIZE], header[CBUFSIZE];
2673 uint32 enabled_units = dptr->numunits;
2674 uint32 unit;
2675
2676 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2677 for (unit=0; unit < dptr->numunits; unit++)
2678 if (dptr->units[unit].flags & UNIT_DIS)
2679 --enabled_units;
2680 if (dptr->modifiers) {
2681 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2682 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2683 continue;
2684 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2685 continue;
2686 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2687 continue;
2688 fprint_header (st, &found, header);
2689 (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2690 mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2691 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2692 }
2693 }
2694 if (dptr->flags & DEV_DEBUG) {
2695 fprint_header (st, &found, header);
2696 (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2697 (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2698 }
2699 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2700 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2701 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2702 continue;
2703 if ((!mptr->disp) || (!mptr->pstring))
2704 continue;
2705 fprint_header (st, &found, header);
2706 (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2707 (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2708 MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2709 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2710 }
2711 }
2712 if (!found && !silent)
2713 (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2714 }
2715
2716 void fprint_show_help (FILE *st, DEVICE *dptr)
2717 {
2718 fprint_show_help_ex (st, dptr, TRUE);
2719 }
2720
2721 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2722 {
2723 BRKTYPTAB *brkt = dptr->brk_types;
2724 char gbuf[CBUFSIZE];
2725
2726 if (sim_brk_types == 0) {
2727 if ((dptr != sim_dflt_dev) && (!silent)) {
2728 (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2729 if (dptr->help)
2730 dptr->help (st, dptr, NULL, 0, NULL);
2731 }
2732 return;
2733 }
2734 if (brkt == NULL) {
2735 int i;
2736
2737 if (dptr == sim_dflt_dev) {
2738 if (sim_brk_types & ~sim_brk_dflt) {
2739 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2740 for (i=0; i<26; i++) {
2741 if (sim_brk_types & (1<<i))
2742 (void)fprintf (st, " -%c\r\n", 'A'+i);
2743 }
2744 }
2745 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2746 }
2747 return;
2748 }
2749 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2750 while (brkt->btyp) {
2751 (void)fprintf (st, " %s %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2752 ++brkt;
2753 }
2754 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2755 }
2756
2757 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2758 {
2759 char gbuf[CBUFSIZE];
2760 CTAB *cmdp;
2761
2762 if (*cptr) {
2763 (void)get_glyph (cptr, gbuf, 0);
2764 if ((cmdp = find_cmd (gbuf))) {
2765 if (cmdp->action == &exdep_cmd) {
2766 if (dptr->help)
2767 return dptr->help (st, dptr, uptr, flag, cptr);
2768 else
2769 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2770 return SCPE_OK;
2771 }
2772 if (cmdp->action == &set_cmd) {
2773 fprint_set_help_ex (st, dptr, FALSE);
2774 return SCPE_OK;
2775 }
2776 if (cmdp->action == &show_cmd) {
2777 fprint_show_help_ex (st, dptr, FALSE);
2778 return SCPE_OK;
2779 }
2780 if (cmdp->action == &attach_cmd) {
2781 fprint_attach_help_ex (st, dptr, FALSE);
2782 return SCPE_OK;
2783 }
2784 if (cmdp->action == &brk_cmd) {
2785 fprint_brk_help_ex (st, dptr, FALSE);
2786 return SCPE_OK;
2787 }
2788 if (dptr->help)
2789 return dptr->help (st, dptr, uptr, flag, cptr);
2790 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2791 return SCPE_OK;
2792 }
2793 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2794 fprint_reg_help_ex (st, dptr, FALSE);
2795 return SCPE_OK;
2796 }
2797 if (dptr->help)
2798 return dptr->help (st, dptr, uptr, flag, cptr);
2799 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2800 return SCPE_OK;
2801 }
2802 if (dptr->help) {
2803 return dptr->help (st, dptr, uptr, flag, cptr);
2804 }
2805 if (dptr->description)
2806 (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2807 else
2808 (void)fprintf (st, "%s HELP\r\n", dptr->name);
2809 fprint_set_help_ex (st, dptr, TRUE);
2810 fprint_show_help_ex (st, dptr, TRUE);
2811 fprint_attach_help_ex (st, dptr, TRUE);
2812 fprint_reg_help_ex (st, dptr, TRUE);
2813 fprint_brk_help_ex (st, dptr, TRUE);
2814 return SCPE_OK;
2815 }
2816
2817 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2818 {
2819 switch (help[0]) {
2820 case '*':
2821 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2822 if (sim_log)
2823 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2824 break;
2825 default:
2826 fputs (help, stdout);
2827 if (sim_log)
2828 fputs (help, sim_log);
2829 break;
2830 }
2831 return SCPE_OK;
2832 }
2833
2834 t_stat help_cmd (int32 flag, CONST char *cptr)
2835 {
2836 char gbuf[CBUFSIZE];
2837 CTAB *cmdp;
2838
2839 GET_SWITCHES (cptr);
2840 if (sim_switches & SWMASK ('F'))
2841 flag = flag | SCP_HELP_FLAT;
2842 if (*cptr) {
2843 cptr = get_glyph (cptr, gbuf, 0);
2844 if ((cmdp = find_cmd (gbuf))) {
2845 if (*cptr) {
2846 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2847 DEVICE *dptr;
2848 UNIT *uptr;
2849 t_stat r;
2850 cptr = get_glyph (cptr, gbuf, 0);
2851 dptr = find_unit (gbuf, &uptr);
2852 if (dptr == NULL)
2853 dptr = find_dev (gbuf);
2854 if (dptr != NULL) {
2855 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2856 if (sim_log)
2857 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2858 return r;
2859 }
2860 if (cmdp->action == &set_cmd) {
2861
2862 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2863 (cmdp->help))
2864 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2865 }
2866 else {
2867 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2868 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2869 return SCPE_ARG;
2870 return help_cmd_output (flag, shptr->help, NULL);
2871 }
2872 return SCPE_ARG;
2873 }
2874 else
2875 return SCPE_2MARG;
2876 }
2877 if (cmdp->help) {
2878 if (strcmp (cmdp->name, "HELP") == 0) {
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913 }
2914 else {
2915 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2916 sim_dflt_dev && sim_dflt_dev->help) {
2917 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2918 if (sim_log)
2919 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2920 }
2921 }
2922 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2923 }
2924 else {
2925 CTAB *cmdpa;
2926 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2927 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2928 sim_printf ("%s is an alias for the %s command:\r\n%s",
2929 cmdp->name, cmdpa->name, cmdpa->help);
2930 break;
2931 }
2932 if (cmdpa->name == NULL)
2933 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2934 }
2935 }
2936 else {
2937 DEVICE *dptr;
2938 UNIT *uptr;
2939 t_stat r;
2940 dptr = find_unit (gbuf, &uptr);
2941 if (dptr == NULL) {
2942 dptr = find_dev (gbuf);
2943 if (dptr == NULL)
2944 return SCPE_ARG;
2945 if (dptr->flags & DEV_DIS)
2946 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2947 }
2948 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2949 if (sim_log)
2950 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2951 return r;
2952 }
2953 }
2954 else {
2955 fprint_help (stdout);
2956 if (sim_log)
2957 fprint_help (sim_log);
2958 }
2959 return SCPE_OK;
2960 }
2961
2962
2963
2964 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2965 {
2966 t_stat status;
2967 if ((cptr == NULL) || (strlen (cptr) == 0))
2968 cptr = getenv("SHELL");
2969 if ((cptr == NULL) || (strlen (cptr) == 0))
2970 cptr = getenv("ComSpec");
2971 (void)fflush(stdout);
2972 if (sim_log)
2973 (void)fflush (sim_log);
2974 if (sim_deb)
2975 (void)fflush (sim_deb);
2976 status = system (cptr);
2977
2978 return status;
2979 }
2980
2981
2982
2983 t_stat echo_cmd (int32 flag, CONST char *cptr)
2984 {
2985 sim_printf ("%s\r\n", cptr);
2986 return SCPE_OK;
2987 }
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009 t_stat do_cmd (int32 flag, CONST char *fcptr)
3010 {
3011 return do_cmd_label (flag, fcptr, NULL);
3012 }
3013
3014 static char *do_position(void)
3015 {
3016 static char cbuf[4*CBUFSIZE];
3017
3018 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3019 sim_do_label[sim_do_depth] ? "::" : "",
3020 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3021 sim_goto_line[sim_do_depth]);
3022 return cbuf;
3023 }
3024
3025 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
3026 {
3027 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3028 CONST char *cptr;
3029 FILE *fpin;
3030 CTAB *cmdp = NULL;
3031 int32 echo, nargs, errabort, i;
3032 int32 saved_sim_do_echo = sim_do_echo,
3033 saved_sim_show_message = sim_show_message,
3034 saved_sim_on_inherit = sim_on_inherit,
3035 saved_sim_quiet = sim_quiet;
3036 t_bool staying;
3037 t_stat stat, stat_nomessage;
3038
3039 stat = SCPE_OK;
3040 staying = TRUE;
3041 if (flag > 0)
3042 GET_SWITCHES (fcptr);
3043 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
3044 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
3045 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
3046 errabort = sim_switches & SWMASK ('E');
3047
3048 abuf[sizeof(abuf)-1] = '\0';
3049 strncpy (abuf, fcptr, sizeof(abuf)-1);
3050 c = abuf;
3051 do_arg[10] = NULL;
3052 for (nargs = 0; nargs < 10; ) {
3053 while (sim_isspace (*c))
3054 c++;
3055 if (*c == 0)
3056 do_arg [nargs++] = NULL;
3057 else {
3058 if (*c == '\'' || *c == '"')
3059 quote = *c++;
3060 else quote = 0;
3061 do_arg[nargs++] = c;
3062 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3063 c++;
3064 if (*c)
3065 *c++ = 0;
3066 }
3067 }
3068
3069 if (do_arg [0] == NULL)
3070 return SCPE_2FARG;
3071 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
3072 strcat (strcpy (cbuf, do_arg[0]), ".ini");
3073 if ((fpin = fopen (cbuf, "r")) == NULL) {
3074 if (flag == 0)
3075 (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3076 return SCPE_OPENERR;
3077 }
3078 }
3079 if (flag >= 0) {
3080 ++sim_do_depth;
3081 if (sim_on_inherit) {
3082 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
3083 for (i=0; i<SCPE_MAX_ERR; i++) {
3084 if (sim_on_actions[sim_do_depth-1][i]) {
3085 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3086 if (NULL == sim_on_actions[sim_do_depth][i]) {
3087 while (--i >= 0) {
3088 FREE(sim_on_actions[sim_do_depth][i]);
3089 sim_on_actions[sim_do_depth][i] = NULL;
3090 }
3091 sim_on_check[sim_do_depth] = 0;
3092 sim_brk_clract ();
3093 --sim_do_depth;
3094 fclose(fpin);
3095 return SCPE_MEM;
3096 }
3097 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3098 }
3099 }
3100 }
3101 }
3102
3103 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
3104 sim_do_label[sim_do_depth] = label;
3105 sim_goto_line[sim_do_depth] = 0;
3106 if (label) {
3107 sim_gotofile = fpin;
3108 sim_do_echo = echo;
3109 stat = goto_cmd (0, label);
3110 if (stat != SCPE_OK) {
3111 strcpy(cbuf, "RETURN SCPE_ARG");
3112 cptr = get_glyph (cbuf, gbuf, 0);
3113 cmdp = find_cmd (gbuf);
3114 goto Cleanup_Return;
3115 }
3116 }
3117 if (errabort)
3118 set_on (1, NULL);
3119
3120 do {
3121 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
3122 if (!sim_do_ocptr[sim_do_depth]) {
3123 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
3124 sim_goto_line[sim_do_depth] += 1;
3125 }
3126 if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {
3127 sim_sub_args(cbuf, sizeof(cbuf), do_arg);
3128 }
3129 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
3130 if (cptr == NULL) {
3131 stat = SCPE_OK;
3132 break;
3133 }
3134 if (*cptr == 0)
3135 continue;
3136 if (echo)
3137 sim_printf("%s> %s\r\n", do_position(), cptr);
3138 if (*cptr == ':')
3139 continue;
3140 cptr = get_glyph_cmd (cptr, gbuf);
3141 sim_switches = 0;
3142 sim_gotofile = fpin;
3143 sim_do_echo = echo;
3144 if ((cmdp = find_cmd (gbuf))) {
3145 if (cmdp->action == &return_cmd)
3146 break;
3147 if (cmdp->action == &do_cmd) {
3148 if (sim_do_depth >= MAX_DO_NEST_LVL)
3149 stat = SCPE_NEST;
3150 else
3151 stat = do_cmd (sim_do_depth+1, cptr);
3152 }
3153 else
3154 stat = cmdp->action (cmdp->arg, cptr);
3155 }
3156 else stat = SCPE_UNK;
3157 echo = sim_do_echo;
3158 stat_nomessage = stat & SCPE_NOMESSAGE;
3159 stat_nomessage = stat_nomessage || (!sim_show_message);
3160 stat = SCPE_BARE_STATUS(stat);
3161 if (cmdp)
3162 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3163 ((cmdp->action != &return_cmd) &&
3164 (cmdp->action != &goto_cmd) &&
3165 (cmdp->action != &on_cmd) &&
3166 (cmdp->action != &echo_cmd)))
3167 sim_last_cmd_stat = stat;
3168 switch (stat) {
3169 case SCPE_AFAIL:
3170 staying = (sim_on_check[sim_do_depth] &&
3171 sim_on_actions[sim_do_depth][stat]);
3172 break;
3173 case SCPE_EXIT:
3174 staying = FALSE;
3175 break;
3176 case SCPE_OK:
3177 case SCPE_STEP:
3178 break;
3179 default:
3180 break;
3181 }
3182 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
3183 (stat != SCPE_STEP)) {
3184 if (!echo && !sim_quiet &&
3185 !stat_nomessage &&
3186 !(cmdp && cmdp->message)) {
3187 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3188 }
3189 }
3190 if (!stat_nomessage) {
3191 if (cmdp && cmdp->message)
3192 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3193 else
3194 if (stat >= SCPE_BASE)
3195 sim_printf ("%s\r\n", sim_error_text (stat));
3196 }
3197 if (stat == SCPE_EXPECT)
3198 stat = SCPE_OK;
3199 if (staying &&
3200 (sim_on_check[sim_do_depth]) &&
3201 (stat != SCPE_OK) &&
3202 (stat != SCPE_STEP)) {
3203 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3204 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3205 else
3206 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3207 }
3208 if (sim_vm_post != NULL)
3209 (*sim_vm_post) (TRUE);
3210 } while (staying);
3211 Cleanup_Return:
3212 if (fpin)
3213 fclose (fpin);
3214 sim_gotofile = NULL;
3215 if (flag >= 0) {
3216 sim_do_echo = saved_sim_do_echo;
3217 sim_show_message = saved_sim_show_message;
3218 sim_on_inherit = saved_sim_on_inherit;
3219 }
3220 sim_quiet = saved_sim_quiet;
3221 if ((flag >= 0) || (!sim_on_inherit)) {
3222 for (i=0; i<SCPE_MAX_ERR; i++) {
3223 FREE (sim_on_actions[sim_do_depth][i]);
3224 sim_on_actions[sim_do_depth][i] = NULL;
3225 }
3226 sim_on_check[sim_do_depth] = 0;
3227 }
3228 if (flag >= 0)
3229 --sim_do_depth;
3230 sim_brk_clract ();
3231 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
3232 sim_string_to_stat (cptr, &stat);
3233 sim_last_cmd_stat = stat;
3234 if (sim_switches & SWMASK ('Q'))
3235 stat |= SCPE_NOMESSAGE;
3236 return stat;
3237 }
3238 return stat | SCPE_NOMESSAGE;
3239 }
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
3284 {
3285 char gbuf[CBUFSIZE];
3286 char *ip = instr, *op, *oend, *tmpbuf;
3287 const char *ap;
3288 char rbuf[CBUFSIZE];
3289 int i;
3290 time_t now;
3291 struct tm *tmnow;
3292
3293 time(&now);
3294 tmnow = localtime(&now);
3295 tmpbuf = (char *)malloc(instr_size);
3296 if (!tmpbuf)
3297 {
3298 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3299 __func__, __FILE__, __LINE__);
3300 #if defined(USE_BACKTRACE)
3301 # if defined(SIGUSR2)
3302 (void)raise(SIGUSR2);
3303
3304 # endif
3305 #endif
3306 abort();
3307 }
3308 op = tmpbuf;
3309 oend = tmpbuf + instr_size - 2;
3310 while (sim_isspace (*ip))
3311 *op++ = *ip++;
3312 for (; *ip && (op < oend); ) {
3313 if ((ip [0] == '\\') &&
3314 ((ip [1] == '%') || (ip [1] == '\\'))) {
3315 ip++;
3316 *op++ = *ip++;
3317 }
3318 else
3319 if ((*ip == '%') &&
3320 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
3321 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
3322 ap = do_arg[ip[1] - '0'];
3323 for (i=0; i<ip[1] - '0'; ++i)
3324 if (do_arg[i] == NULL) {
3325 ap = NULL;
3326 break;
3327 }
3328 ip = ip + 2;
3329 }
3330 else if (ip[1] == '*') {
3331 (void)memset (rbuf, '\0', sizeof(rbuf));
3332 ap = rbuf;
3333 for (i=1; i<=9; ++i)
3334 if (do_arg[i] == NULL)
3335 break;
3336 else
3337 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3338 if (strchr(do_arg[i], ' ')) {
3339 char quote = '"';
3340 if (strchr(do_arg[i], quote))
3341 quote = '\'';
3342 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3343 (i != 1) ? " " : "", quote,
3344 do_arg[i], quote);
3345 }
3346 else
3347 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3348 (i != 1) ? " " : "", do_arg[i]);
3349 }
3350 else
3351 break;
3352 ip = ip + 2;
3353 }
3354 else {
3355 ap = NULL;
3356 (void)get_glyph_nc (ip+1, gbuf, '%');
3357 ap = getenv(gbuf);
3358 if (!ap) {
3359 (void)get_glyph (ip+1, gbuf, '%');
3360 ap = getenv(gbuf);
3361 }
3362 ip += 1 + strlen (gbuf);
3363 if (*ip == '%') ++ip;
3364 if (!ap) {
3365
3366 if (!strcmp ("DATE", gbuf)) {
3367 (void)sprintf (rbuf, "%4d-%02d-%02d",
3368 tmnow->tm_year + 1900,
3369 tmnow->tm_mon + 1,
3370 tmnow->tm_mday);
3371 ap = rbuf;
3372 }
3373 else if (!strcmp ("TIME", gbuf)) {
3374 (void)sprintf (rbuf, "%02d:%02d:%02d",
3375 tmnow->tm_hour,
3376 tmnow->tm_min,
3377 tmnow->tm_sec);
3378 ap = rbuf;
3379 }
3380 else if (!strcmp ("DATETIME", gbuf)) {
3381 (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3382 tmnow->tm_year + 1900,
3383 tmnow->tm_mon + 1,
3384 tmnow->tm_mday,
3385 tmnow->tm_hour,
3386 tmnow->tm_min,
3387 tmnow->tm_sec);
3388 ap = rbuf;
3389 }
3390
3391 if (!strcmp ("LDATE", gbuf)) {
3392 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3393 ap = rbuf;
3394 }
3395 else if (!strcmp ("LTIME", gbuf)) {
3396 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3397 ap = rbuf;
3398 }
3399 else if (!strcmp ("CTIME", gbuf)) {
3400 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3401 ap = rbuf;
3402 }
3403
3404 else if (!strcmp ("DATE_YYYY", gbuf)) {
3405 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3406 ap = rbuf;
3407 }
3408 else if (!strcmp ("DATE_YY", gbuf)) {
3409 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3410 ap = rbuf;
3411 }
3412 else if (!strcmp ("DATE_YC", gbuf)) {
3413 (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3414 ap = rbuf;
3415 }
3416 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3417 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3418 int year = tmnow->tm_year + 1900;
3419 int days = year - 2001;
3420 int leaps = days/4 - days/100 + days/400;
3421 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3422 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3423 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3424 96, 80, 92, 76, 88, 72, 84};
3425 int cal_year = years[selector];
3426
3427 if (!strcmp ("DATE_19XX_YY", gbuf))
3428 (void)sprintf (rbuf, "%d", cal_year);
3429 else
3430 (void)sprintf (rbuf, "%d", cal_year + 1900);
3431 ap = rbuf;
3432 }
3433 else if (!strcmp ("DATE_MM", gbuf)) {
3434 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3435 ap = rbuf;
3436 }
3437 else if (!strcmp ("DATE_MMM", gbuf)) {
3438 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3439 ap = rbuf;
3440 }
3441 else if (!strcmp ("DATE_DD", gbuf)) {
3442 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3443 ap = rbuf;
3444 }
3445 else if (!strcmp ("DATE_D", gbuf)) {
3446 (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3447 ap = rbuf;
3448 }
3449 else if ((!strcmp ("DATE_WW", gbuf)) ||
3450 (!strcmp ("DATE_WYYYY", gbuf))) {
3451 int iso_yr = tmnow->tm_year + 1900;
3452 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3453
3454 if (iso_wk == 0) {
3455 iso_yr = iso_yr - 1;
3456 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3457 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3458 }
3459 else
3460 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3461 ++iso_yr;
3462 iso_wk = 1;
3463 }
3464 if (!strcmp ("DATE_WW", gbuf))
3465 (void)sprintf (rbuf, "%02d", iso_wk);
3466 else
3467 (void)sprintf (rbuf, "%04d", iso_yr);
3468 ap = rbuf;
3469 }
3470 else if (!strcmp ("DATE_JJJ", gbuf)) {
3471 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3472 ap = rbuf;
3473 }
3474 else if (!strcmp ("TIME_HH", gbuf)) {
3475 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3476 ap = rbuf;
3477 }
3478 else if (!strcmp ("TIME_MM", gbuf)) {
3479 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3480 ap = rbuf;
3481 }
3482 else if (!strcmp ("TIME_SS", gbuf)) {
3483 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3484 ap = rbuf;
3485 }
3486 else if (!strcmp ("STATUS", gbuf)) {
3487 (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3488 ap = rbuf;
3489 }
3490 else if (!strcmp ("TSTATUS", gbuf)) {
3491 (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3492 ap = rbuf;
3493 }
3494 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3495 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3496 ap = rbuf;
3497 }
3498 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3499 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3500 ap = rbuf;
3501 }
3502 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3503 (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3504 ap = rbuf;
3505 }
3506 else if (!strcmp ("SIM_QUIET", gbuf)) {
3507 (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3508 ap = rbuf;
3509 }
3510 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3511 (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3512 ap = rbuf;
3513 }
3514 else if (!strcmp ("HOSTID", gbuf)) {
3515 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3516 (void)sprintf (rbuf, "%ld", (long)gethostid());
3517 #else
3518 (void)sprintf (rbuf, "00000000");
3519 #endif
3520 ap = rbuf;
3521 }
3522 else if (!strcmp ("UID", gbuf)) {
3523 #if defined(HAVE_UNISTD)
3524 (void)sprintf (rbuf, "%ld", (long)getuid());
3525 #else
3526 (void)sprintf (rbuf, "0");
3527 #endif
3528 ap = rbuf;
3529 }
3530 else if (!strcmp ("GID", gbuf)) {
3531 #if defined(HAVE_UNISTD)
3532 (void)sprintf (rbuf, "%ld", (long)getgid());
3533 #else
3534 (void)sprintf (rbuf, "0");
3535 #endif
3536 ap = rbuf;
3537 }
3538 else if (!strcmp ("EUID", gbuf)) {
3539 #if defined(HAVE_UNISTD)
3540 (void)sprintf (rbuf, "%ld", (long)geteuid());
3541 #else
3542 (void)sprintf (rbuf, "0");
3543 #endif
3544 ap = rbuf;
3545 }
3546 else if (!strcmp ("EGID", gbuf)) {
3547 #if defined(HAVE_UNISTD)
3548 (void)sprintf (rbuf, "%ld", (long)getegid());
3549 #else
3550 (void)sprintf (rbuf, "0");
3551 #endif
3552 ap = rbuf;
3553 }
3554 else if (!strcmp ("PID", gbuf)) {
3555 #if defined(HAVE_UNISTD)
3556 (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3557 #else
3558 (void)sprintf (rbuf, "0");
3559 #endif
3560 ap = rbuf;
3561 }
3562 else if (!strcmp ("PPID", gbuf)) {
3563 #if defined(HAVE_UNISTD)
3564 (void)sprintf (rbuf, "%ld", (long)getppid());
3565 #else
3566 (void)sprintf (rbuf, "0");
3567 #endif
3568 ap = rbuf;
3569 }
3570 else if (!strcmp ("PGID", gbuf)) {
3571 #if defined(HAVE_UNISTD)
3572 (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3573 #else
3574 (void)sprintf (rbuf, "0");
3575 #endif
3576 ap = rbuf;
3577 }
3578 else if (!strcmp ("SID", gbuf)) {
3579 #if defined(HAVE_UNISTD)
3580 (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3581 #else
3582 (void)sprintf (rbuf, "0");
3583 #endif
3584 ap = rbuf;
3585 }
3586 else if (!strcmp ("ENDIAN", gbuf)) {
3587 #if ( defined(DECLITEND) && DECLITEND == 1 )
3588 (void)sprintf (rbuf, "LITTLE");
3589 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3590 (void)sprintf (rbuf, "BIG");
3591 #else
3592 (void)sprintf (rbuf, "UNKNOWN");
3593 #endif
3594 ap = rbuf;
3595 }
3596 else if (!strcmp("SIM_NAME", gbuf)) {
3597 (void)sprintf (rbuf, "%s", sim_name);
3598 ap = rbuf;
3599 }
3600 else if (!strcmp("SIM_VERSION", gbuf)) {
3601 #if defined(VER_H_GIT_VERSION)
3602 (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3603 #else
3604 (void)sprintf (rbuf, "UNKNOWN");
3605 #endif
3606 ap = rbuf;
3607 }
3608 else if (!strcmp("SIM_HASH", gbuf)) {
3609 #if defined(VER_H_GIT_HASH)
3610 (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3611 #else
3612 (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3613 #endif
3614 ap = rbuf;
3615 }
3616 else if (!strcmp("SIM_RELT", gbuf)) {
3617 #if defined(VER_H_GIT_RELT)
3618 (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3619 #else
3620 (void)sprintf (rbuf, "X");
3621 #endif
3622 ap = rbuf;
3623 }
3624 else if (!strcmp("SIM_DATE", gbuf)) {
3625 #if defined(VER_H_GIT_DATE)
3626 (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3627 #else
3628 (void)sprintf (rbuf, "UNKNOWN");
3629 #endif
3630 ap = rbuf;
3631 }
3632 else if ((!strcmp("CORES", gbuf)) ||
3633 (!strcmp("SIM_CORES", gbuf))) {
3634 (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3635 ap = rbuf;
3636 }
3637 else if ((!strcmp("CPUS", gbuf)) ||
3638 (!strcmp("SIM_PROCESSORS", gbuf))) {
3639 (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3640 ap = rbuf;
3641 }
3642 }
3643 }
3644 if (ap) {
3645 while (*ap && (op < oend))
3646 *op++ = *ap++;
3647 }
3648 }
3649 else
3650 *op++ = *ip++;
3651 }
3652 *op = 0;
3653 strcpy (instr, tmpbuf);
3654 FREE (tmpbuf);
3655 return;
3656 }
3657
3658 static
3659 int sim_cmp_string (const char *s1, const char *s2)
3660 {
3661 long int v1, v2;
3662 char *ep1, *ep2;
3663
3664 v1 = strtol(s1+1, &ep1, 0);
3665 v2 = strtol(s2+1, &ep2, 0);
3666 if ((ep1 != s1 + strlen (s1) - 1) ||
3667 (ep2 != s2 + strlen (s2) - 1))
3668 return strcmp (s1, s2);
3669 if (v1 == v2)
3670 return 0;
3671 if (v1 < v2)
3672 return -1;
3673 return 1;
3674 }
3675
3676
3677
3678 t_stat assert_cmd (int32 flag, CONST char *cptr)
3679 {
3680 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3681 CONST char *tptr, *gptr;
3682 REG *rptr;
3683 uint32 idx = 0;
3684 t_value val;
3685 t_stat r;
3686 t_bool Not = FALSE;
3687 t_bool result;
3688 t_addr addr = 0;
3689 t_stat reason = SCPE_AFAIL;
3690
3691 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3692
3693 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3694 # pragma diagnostic push
3695 # pragma diag_suppress = integer_sign_change
3696 #endif
3697 sim_stabr.boolop = sim_staba.boolop = -1;
3698 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3699 # pragma diagnostic pop
3700 #endif
3701 if (*cptr == 0)
3702 return SCPE_2FARG;
3703 tptr = get_glyph (cptr, gbuf, 0);
3704 if (!strcmp (gbuf, "NOT")) {
3705 Not = TRUE;
3706 cptr = (CONST char *)tptr;
3707 }
3708 if (*cptr == '"') {
3709 char op[CBUFSIZE];
3710 static struct {
3711 const char *op;
3712 int aval;
3713 int bval;
3714 t_bool invert;
3715 } *optr, compare_ops[] =
3716 {
3717 { "==", 0, 0, FALSE },
3718 { "EQU", 0, 0, FALSE },
3719 { "!=", 0, 0, TRUE },
3720 { "NEQ", 0, 0, TRUE },
3721 { "<", -1, -1, FALSE },
3722 { "LSS", -1, -1, FALSE },
3723 { "<=", 0, -1, FALSE },
3724 { "LEQ", 0, -1, FALSE },
3725 { ">", 1, 1, FALSE },
3726 { "GTR", 1, 1, FALSE },
3727 { ">=", 0, 1, FALSE },
3728 { "GEQ", 0, 1, FALSE },
3729 { NULL }
3730 };
3731
3732 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3733
3734 if (!*tptr)
3735 return SCPE_2FARG;
3736 cptr += strlen (gbuf);
3737 while (sim_isspace (*cptr))
3738 ++cptr;
3739 (void)get_glyph (cptr, op, '"');
3740 for (optr = compare_ops; optr->op; optr++)
3741 if (0 == strcmp (op, optr->op))
3742 break;
3743 if (!optr->op)
3744 return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3745 cptr += strlen (op);
3746 while (sim_isspace (*cptr))
3747 ++cptr;
3748 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3749
3750 if (*cptr) {
3751 if (flag)
3752 return SCPE_2MARG;
3753 }
3754 else {
3755 if (!flag)
3756 return SCPE_2FARG;
3757 }
3758 result = sim_cmp_string (gbuf, gbuf2);
3759 result = ((result == optr->aval) || (result == optr->bval));
3760 if (optr->invert)
3761 result = !result;
3762 }
3763 else {
3764 cptr = get_glyph (cptr, gbuf, 0);
3765 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3766 if (rptr) {
3767 if (*gptr == '[') {
3768 if (rptr->depth <= 1)
3769 return SCPE_ARG;
3770 idx = (uint32) strtotv (++gptr, &tptr, 10);
3771 if ((gptr == tptr) || (*tptr++ != ']'))
3772 return SCPE_ARG;
3773 gptr = tptr;
3774 }
3775 else idx = 0;
3776 if (idx >= rptr->depth)
3777 return SCPE_SUB;
3778 }
3779 else {
3780 if (sim_dfdev && sim_vm_parse_addr)
3781 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3782 else if (sim_dfdev)
3783 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3784 if (gbuf == gptr)
3785 return SCPE_NXREG;
3786 }
3787 if (*gptr != 0)
3788 (void)get_glyph (gptr, gbuf, 0);
3789 else {
3790 if (*cptr == 0)
3791 return SCPE_2FARG;
3792 cptr = get_glyph (cptr, gbuf, 0);
3793 }
3794 if (*cptr) {
3795 if (flag)
3796 return SCPE_2MARG;
3797 }
3798 else {
3799 if (!flag)
3800 return SCPE_2FARG;
3801 }
3802 if (rptr) {
3803 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3804 # pragma diagnostic push
3805 # pragma diag_suppress = integer_sign_change
3806 #endif
3807 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3808 (sim_stabr.boolop == -1))
3809 return SCPE_MISVAL;
3810 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3811 # pragma diagnostic pop
3812 #endif
3813 val = get_rval (rptr, idx);
3814 result = test_search (&val, &sim_stabr);
3815 }
3816 else {
3817 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3818 # pragma diagnostic push
3819 # pragma diag_suppress = integer_sign_change
3820 #endif
3821 if (sim_dfdev)
3822 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3823 (sim_staba.boolop == -1))
3824 return SCPE_MISVAL;
3825 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3826 # pragma diagnostic pop
3827 #endif
3828 if (sim_dfdev)
3829 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3830 if (reason != SCPE_OK)
3831 return reason;
3832 result = test_search (sim_eval, &sim_staba);
3833 }
3834 }
3835 if (Not ^ result) {
3836 if (!flag)
3837 sim_brk_setact (cptr);
3838 }
3839 else
3840 if (flag)
3841 return SCPE_AFAIL;
3842 return SCPE_OK;
3843 }
3844
3845
3846
3847 t_stat send_cmd (int32 flag, CONST char *cptr)
3848 {
3849 char gbuf[CBUFSIZE];
3850 CONST char *tptr;
3851 uint8 dbuf[CBUFSIZE];
3852 uint32 dsize = 0;
3853 uint32 delay = 0;
3854 uint32 after = 0;
3855 t_stat r;
3856 SEND *snd = NULL;
3857
3858 GET_SWITCHES (cptr);
3859 tptr = get_glyph (cptr, gbuf, ',');
3860 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3861 r = tmxr_locate_line_send (gbuf, &snd);
3862 if (r != SCPE_OK)
3863 return r;
3864 cptr = tptr;
3865 tptr = get_glyph (tptr, gbuf, ',');
3866 }
3867 else
3868 snd = sim_cons_get_send ();
3869
3870 while (*cptr) {
3871 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3872 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3873 if (r != SCPE_OK)
3874 return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3875 cptr = tptr;
3876 tptr = get_glyph (cptr, gbuf, ',');
3877 continue;
3878 }
3879 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3880 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3881 if (r != SCPE_OK)
3882 return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3883 cptr = tptr;
3884 tptr = get_glyph (cptr, gbuf, ',');
3885 continue;
3886 }
3887 if ((*cptr == '"') || (*cptr == '\''))
3888 break;
3889 return SCPE_ARG;
3890 }
3891 if (*cptr) {
3892 if ((*cptr != '"') && (*cptr != '\''))
3893 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3894 cptr = get_glyph_quoted (cptr, gbuf, 0);
3895 if (*cptr != '\0')
3896 return SCPE_2MARG;
3897
3898 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3899 return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3900 }
3901 if ((dsize == 0) && (delay == 0) && (after == 0))
3902 return SCPE_2FARG;
3903 return sim_send_input (snd, dbuf, dsize, after, delay);
3904 }
3905
3906 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3907 {
3908 char gbuf[CBUFSIZE];
3909 CONST char *tptr;
3910 t_stat r;
3911 SEND *snd = NULL;
3912
3913 tptr = get_glyph (cptr, gbuf, ',');
3914 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3915 r = tmxr_locate_line_send (gbuf, &snd);
3916 if (r != SCPE_OK)
3917 return r;
3918 cptr = tptr;
3919 }
3920 else
3921 snd = sim_cons_get_send ();
3922 if (*cptr)
3923 return SCPE_2MARG;
3924 return sim_show_send_input (st, snd);
3925 }
3926
3927 t_stat expect_cmd (int32 flag, CONST char *cptr)
3928 {
3929 char gbuf[CBUFSIZE];
3930 CONST char *tptr;
3931 EXPECT *exp = NULL;
3932
3933 GET_SWITCHES (cptr);
3934 tptr = get_glyph (cptr, gbuf, ',');
3935 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3936 cptr = tptr;
3937 } else {
3938 exp = sim_cons_get_expect ();
3939 }
3940
3941 if (flag) {
3942 return sim_set_expect (exp, cptr);
3943 } else {
3944 if (exp == NULL) {
3945 exp = sim_cons_get_expect();
3946 }
3947 return sim_set_noexpect (exp, cptr);
3948 }
3949 }
3950
3951 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3952 {
3953 char gbuf[CBUFSIZE];
3954 CONST char *tptr;
3955 EXPECT *exp = NULL;
3956 t_stat r;
3957
3958 tptr = get_glyph (cptr, gbuf, ',');
3959 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3960 r = tmxr_locate_line_expect (gbuf, &exp);
3961 if (r != SCPE_OK)
3962 return r;
3963 cptr = tptr;
3964 }
3965 else
3966 exp = sim_cons_get_expect ();
3967 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3968 return SCPE_ARG;
3969 tptr = get_glyph_quoted (cptr, gbuf, 0);
3970 if (*tptr != '\0')
3971 return SCPE_2MARG;
3972 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3973 return SCPE_ARG;
3974 return sim_exp_show (st, exp, gbuf);
3975 }
3976
3977
3978
3979 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3980 {
3981 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3982 const char *cptr;
3983 long fpos;
3984 int32 saved_do_echo = sim_do_echo;
3985 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3986
3987 if (NULL == sim_gotofile) return SCPE_UNK;
3988 (void)get_glyph (fcptr, gbuf1, 0);
3989 if ('\0' == gbuf1[0]) return SCPE_ARG;
3990 fpos = ftell(sim_gotofile);
3991 rewind(sim_gotofile);
3992 sim_goto_line[sim_do_depth] = 0;
3993 sim_do_echo = 0;
3994 while (1) {
3995 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
3996 if (cptr == NULL) break;
3997 sim_goto_line[sim_do_depth] += 1;
3998 if (*cptr == 0) continue;
3999 if (*cptr != ':') continue;
4000 ++cptr;
4001 while (sim_isspace (*cptr)) ++cptr;
4002 cptr = get_glyph (cptr, gbuf, 0);
4003 if (0 == strcmp(gbuf, gbuf1)) {
4004 sim_brk_clract ();
4005 sim_do_echo = saved_do_echo;
4006 if (sim_do_echo)
4007 sim_printf("%s> %s\r\n", do_position(), cbuf);
4008 return SCPE_OK;
4009 }
4010 }
4011 sim_do_echo = saved_do_echo;
4012 fseek(sim_gotofile, fpos, SEEK_SET);
4013 sim_goto_line[sim_do_depth] = saved_goto_line;
4014 return SCPE_ARG;
4015 }
4016
4017
4018
4019
4020
4021
4022
4023
4024 t_stat return_cmd (int32 flag, CONST char *fcptr)
4025 {
4026 return SCPE_UNK;
4027 }
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037 t_stat shift_cmd (int32 flag, CONST char *fcptr)
4038 {
4039 return SCPE_UNK;
4040 }
4041
4042
4043
4044
4045
4046
4047
4048
4049 t_stat call_cmd (int32 flag, CONST char *fcptr)
4050 {
4051 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4052 const char *cptr;
4053
4054 if (NULL == sim_gotofile) return SCPE_UNK;
4055 cptr = get_glyph (fcptr, gbuf, 0);
4056 if ('\0' == gbuf[0]) return SCPE_ARG;
4057 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4058 sim_switches |= SWMASK ('O');
4059 return do_cmd_label (flag, cbuf, gbuf);
4060 }
4061
4062
4063
4064 t_stat on_cmd (int32 flag, CONST char *cptr)
4065 {
4066 char gbuf[CBUFSIZE];
4067 t_stat cond;
4068
4069 cptr = get_glyph (cptr, gbuf, 0);
4070 if ('\0' == gbuf[0]) return SCPE_ARG;
4071 if (0 == strcmp("ERROR", gbuf))
4072 cond = 0;
4073 else
4074 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4075 return SCPE_ARG;
4076 if ((NULL == cptr) || ('\0' == *cptr)) {
4077 FREE(sim_on_actions[sim_do_depth][cond]);
4078 sim_on_actions[sim_do_depth][cond] = NULL; }
4079 else {
4080 sim_on_actions[sim_do_depth][cond] =
4081 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4082 if (!sim_on_actions[sim_do_depth][cond])
4083 {
4084 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4085 __func__, __FILE__, __LINE__);
4086 #if defined(USE_BACKTRACE)
4087 # if defined(SIGUSR2)
4088 (void)raise(SIGUSR2);
4089
4090 # endif
4091 #endif
4092 abort();
4093 }
4094 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4095 }
4096 return SCPE_OK;
4097 }
4098
4099
4100
4101 t_stat noop_cmd (int32 flag, CONST char *cptr)
4102 {
4103 if (cptr && (*cptr != 0))
4104 return SCPE_2MARG;
4105 return SCPE_OK;
4106 }
4107
4108
4109
4110 t_stat set_on (int32 flag, CONST char *cptr)
4111 {
4112 if ((flag) && (cptr) && (*cptr)) {
4113 char gbuf[CBUFSIZE];
4114
4115 cptr = get_glyph (cptr, gbuf, 0);
4116 if (((MATCH_CMD(gbuf,"INHERIT")) &&
4117 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
4118 (*cptr))
4119 return SCPE_2MARG;
4120 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
4121 sim_on_inherit = 1;
4122 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
4123 sim_on_inherit = 0;
4124 return SCPE_OK;
4125 }
4126 if (cptr && (*cptr != 0))
4127 return SCPE_2MARG;
4128 sim_on_check[sim_do_depth] = flag;
4129 if ((sim_do_depth != 0) &&
4130 (NULL == sim_on_actions[sim_do_depth][0])) {
4131 sim_on_actions[sim_do_depth][0] =
4132 (char *)malloc(1+strlen("RETURN"));
4133 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4134 }
4135 if ((sim_do_depth != 0) &&
4136 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
4137 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
4138 (char *)malloc(1+strlen("RETURN"));
4139 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4140 }
4141 return SCPE_OK;
4142 }
4143
4144
4145
4146 t_stat set_verify (int32 flag, CONST char *cptr)
4147 {
4148 if (cptr && (*cptr != 0))
4149 return SCPE_2MARG;
4150 if (flag == sim_do_echo)
4151 return SCPE_OK;
4152 sim_do_echo = flag;
4153 return SCPE_OK;
4154 }
4155
4156
4157
4158 t_stat set_message (int32 flag, CONST char *cptr)
4159 {
4160 if (cptr && (*cptr != 0))
4161 return SCPE_2MARG;
4162 if (flag == sim_show_message)
4163 return SCPE_OK;
4164 sim_show_message = flag;
4165 return SCPE_OK;
4166 }
4167
4168
4169
4170 t_stat set_localopc (int32 flag, CONST char *cptr)
4171 {
4172 if (cptr && (*cptr != 0))
4173 return SCPE_2MARG;
4174 if (flag == sim_localopc)
4175 return SCPE_OK;
4176 sim_localopc = flag;
4177 return SCPE_OK;
4178 }
4179
4180
4181 t_stat set_quiet (int32 flag, CONST char *cptr)
4182 {
4183 if (cptr && (*cptr != 0))
4184 return SCPE_2MARG;
4185 if (flag == sim_quiet)
4186 return SCPE_OK;
4187 sim_quiet = flag;
4188 return SCPE_OK;
4189 }
4190
4191
4192
4193 t_stat sim_set_environment (int32 flag, CONST char *cptr)
4194 {
4195 char varname[CBUFSIZE];
4196
4197 if ((NULL == cptr) || (*cptr == 0))
4198 return SCPE_2FARG;
4199 cptr = get_glyph (cptr, varname, '=');
4200 setenv(varname, cptr, 1);
4201 return SCPE_OK;
4202 }
4203
4204
4205
4206 t_stat set_cmd (int32 flag, CONST char *cptr)
4207 {
4208 uint32 lvl = 0;
4209 t_stat r;
4210 char gbuf[CBUFSIZE], *cvptr;
4211 CONST char *svptr;
4212 DEVICE *dptr;
4213 UNIT *uptr;
4214 MTAB *mptr;
4215 CTAB *gcmdp;
4216 C1TAB *ctbr = NULL, *glbr;
4217
4218 GET_SWITCHES (cptr);
4219 if ((NULL == cptr) || (*cptr == 0))
4220 return SCPE_2FARG;
4221 cptr = get_glyph (svptr = cptr, gbuf, 0);
4222
4223 if ((dptr = find_dev (gbuf))) {
4224 uptr = dptr->units;
4225 ctbr = set_dev_tab;
4226 lvl = MTAB_VDV;
4227 GET_SWITCHES (cptr);
4228 }
4229 else if ((dptr = find_unit (gbuf, &uptr))) {
4230 if (uptr == NULL)
4231 return SCPE_NXUN;
4232 ctbr = set_unit_tab;
4233 lvl = MTAB_VUN;
4234 GET_SWITCHES (cptr);
4235 }
4236 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
4237 GET_SWITCHES (cptr);
4238 return gcmdp->action (gcmdp->arg, cptr);
4239 }
4240 else {
4241 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4242 if ((cvptr = strchr (gbuf, '=')))
4243 *cvptr++ = 0;
4244 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4245 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4246 dptr = sim_dflt_dev;
4247 cptr = svptr;
4248 while (sim_isspace(*cptr))
4249 ++cptr;
4250 break;
4251 }
4252 }
4253 }
4254 if (!dptr)
4255 return SCPE_NXDEV;
4256 lvl = MTAB_VDV;
4257 uptr = dptr->units;
4258 }
4259 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4260 return SCPE_2FARG;
4261 GET_SWITCHES (cptr);
4262
4263 while (*cptr != 0) {
4264 cptr = get_glyph (svptr = cptr, gbuf, ',');
4265 if (0 == strcmp (gbuf, ";"))
4266 break;
4267 if ((cvptr = strchr (gbuf, '=')))
4268 *cvptr++ = 0;
4269 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4270 if ((mptr->mstring) &&
4271 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4272 if (mptr->mask & MTAB_XTD) {
4273 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4274 return SCPE_ARG;
4275 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4276 return SCPE_UDIS;
4277 if (mptr->valid) {
4278 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4279 svptr = get_glyph_quoted (svptr, gbuf, ',');
4280 if ((cvptr = strchr (gbuf, '='))) {
4281 *cvptr++ = 0;
4282 cptr = svptr;
4283 }
4284 }
4285 else {
4286 if (cvptr && MODMASK(mptr,MTAB_NC)) {
4287 (void)get_glyph_nc (svptr, gbuf, ',');
4288 if ((cvptr = strchr (gbuf, '=')))
4289 *cvptr++ = 0;
4290 }
4291 }
4292 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4293 if (r != SCPE_OK)
4294 return r;
4295 }
4296 else if (!mptr->desc)
4297 break;
4298 else if (cvptr)
4299 return SCPE_ARG;
4300 else *((int32 *) mptr->desc) = mptr->match;
4301 }
4302 else {
4303 if (cvptr)
4304 return SCPE_ARG;
4305 if (uptr->flags & UNIT_DIS)
4306 return SCPE_UDIS;
4307 if ((mptr->valid) &&
4308 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4309 return r;
4310 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4311 (mptr->match & mptr->mask);
4312 }
4313 break;
4314 }
4315 }
4316 if (!mptr || (mptr->mask == 0)) {
4317 if ((glbr = find_c1tab (ctbr, gbuf))) {
4318 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
4319 if (r != SCPE_OK)
4320 return r;
4321 }
4322 else if (!dptr->modifiers)
4323 return SCPE_NOPARAM;
4324 else return SCPE_NXPAR;
4325 }
4326 }
4327 return SCPE_OK;
4328 }
4329
4330
4331
4332 CTAB *find_ctab (CTAB *tab, const char *gbuf)
4333 {
4334 if (!tab)
4335 return NULL;
4336 for (; tab->name != NULL; tab++) {
4337 if (MATCH_CMD (gbuf, tab->name) == 0)
4338 return tab;
4339 }
4340 return NULL;
4341 }
4342
4343 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
4344 {
4345 if (!tab)
4346 return NULL;
4347 for (; tab->name != NULL; tab++) {
4348 if (MATCH_CMD (gbuf, tab->name) == 0)
4349 return tab;
4350 }
4351 return NULL;
4352 }
4353
4354
4355
4356 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4357 {
4358 if (cptr)
4359 return SCPE_ARG;
4360 dptr->dradix = flag & 037;
4361 return SCPE_OK;
4362 }
4363
4364
4365
4366 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4367 {
4368 UNIT *up;
4369 uint32 i;
4370
4371 if (cptr)
4372 return SCPE_ARG;
4373 if ((dptr->flags & DEV_DISABLE) == 0)
4374 return SCPE_NOFNC;
4375 if (flag) {
4376 if ((dptr->flags & DEV_DIS) == 0)
4377 return SCPE_OK;
4378 dptr->flags = dptr->flags & ~DEV_DIS;
4379 }
4380 else {
4381 if (dptr->flags & DEV_DIS)
4382 return SCPE_OK;
4383 for (i = 0; i < dptr->numunits; i++) {
4384 up = (dptr->units) + i;
4385 if ((up->flags & UNIT_ATT) || sim_is_active (up))
4386 return SCPE_NOFNC;
4387 }
4388 dptr->flags = dptr->flags | DEV_DIS;
4389 }
4390 if (dptr->reset)
4391 return dptr->reset (dptr);
4392 else return SCPE_OK;
4393 }
4394
4395
4396
4397 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4398 {
4399 if (cptr)
4400 return SCPE_ARG;
4401 if (!(uptr->flags & UNIT_DISABLE))
4402 return SCPE_NOFNC;
4403 if (flag)
4404 uptr->flags = uptr->flags & ~UNIT_DIS;
4405 else {
4406 if ((uptr->flags & UNIT_ATT) ||
4407 sim_is_active (uptr))
4408 return SCPE_NOFNC;
4409 uptr->flags = uptr->flags | UNIT_DIS;
4410 }
4411 return SCPE_OK;
4412 }
4413
4414
4415
4416 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4417 {
4418 char gbuf[CBUFSIZE];
4419 DEBTAB *dep;
4420
4421 if ((dptr->flags & DEV_DEBUG) == 0)
4422 return SCPE_NOFNC;
4423 if (cptr == NULL) {
4424 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4425 if (flag && dptr->debflags) {
4426 for (dep = dptr->debflags; dep->name != NULL; dep++)
4427 dptr->dctrl = dptr->dctrl | dep->mask;
4428 }
4429 return SCPE_OK;
4430 }
4431 if (dptr->debflags == NULL)
4432 return SCPE_ARG;
4433 while (*cptr) {
4434 cptr = get_glyph (cptr, gbuf, ';');
4435 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4436 if (strcmp (dep->name, gbuf) == 0) {
4437 if (flag)
4438 dptr->dctrl = dptr->dctrl | dep->mask;
4439 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4440 break;
4441 }
4442 }
4443 if (dep->mask == 0)
4444 return SCPE_ARG;
4445 }
4446 return SCPE_OK;
4447 }
4448
4449
4450
4451 t_stat show_cmd (int32 flag, CONST char *cptr)
4452 {
4453 t_stat r = SCPE_IERR;
4454
4455 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4456
4457 if (NULL == cptr)
4458 return r;
4459 if (sim_ofile) {
4460 r = show_cmd_fi (sim_ofile, flag, cptr);
4461 fclose (sim_ofile);
4462 }
4463 else {
4464 r = show_cmd_fi (stdout, flag, cptr);
4465 if (sim_log && (sim_log != stdout))
4466 show_cmd_fi (sim_log, flag, cptr);
4467 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4468 show_cmd_fi (sim_deb, flag, cptr);
4469 }
4470 return r;
4471 }
4472
4473 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4474 {
4475 uint32 lvl = 0xFFFFFFFF;
4476 char gbuf[CBUFSIZE], *cvptr;
4477 CONST char *svptr;
4478 DEVICE *dptr;
4479 UNIT *uptr;
4480 MTAB *mptr;
4481 SHTAB *shtb = NULL, *shptr;
4482
4483 GET_SWITCHES (cptr);
4484 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4485 return SCPE_2FARG;
4486 cptr = get_glyph (svptr = cptr, gbuf, 0);
4487
4488 if ((dptr = find_dev (gbuf))) {
4489 uptr = dptr->units;
4490 shtb = show_dev_tab;
4491 lvl = MTAB_VDV;
4492 GET_SWITCHES (cptr);
4493 }
4494 else if ((dptr = find_unit (gbuf, &uptr))) {
4495 if (uptr == NULL)
4496 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4497 if (uptr->flags & UNIT_DIS)
4498 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4499 shtb = show_unit_tab;
4500 lvl = MTAB_VUN;
4501 GET_SWITCHES (cptr);
4502 }
4503 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4504 GET_SWITCHES (cptr);
4505 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4506 }
4507 else {
4508 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4509 if ((cvptr = strchr (gbuf, '=')))
4510 *cvptr++ = 0;
4511 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4512 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4513 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4514 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4515 dptr = sim_dflt_dev;
4516 lvl = MTAB_VDV;
4517 cptr = svptr;
4518 while (sim_isspace(*cptr))
4519 ++cptr;
4520 break;
4521 }
4522 }
4523 }
4524 if (!dptr) {
4525 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4526 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4527 else
4528 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);
4529 }
4530 }
4531
4532 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4533 return (lvl == MTAB_VDV)?
4534 show_device (ofile, dptr, 0):
4535 show_unit (ofile, dptr, uptr, -1);
4536 }
4537 GET_SWITCHES (cptr);
4538
4539 while (*cptr != 0) {
4540 cptr = get_glyph (cptr, gbuf, ',');
4541 if ((cvptr = strchr (gbuf, '=')))
4542 *cvptr++ = 0;
4543 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4544 if (((mptr->mask & MTAB_XTD)?
4545 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4546 ((mptr->disp && mptr->pstring &&
4547 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4548 )) {
4549 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4550 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4551 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4552 break;
4553 }
4554 }
4555 if (!mptr || (mptr->mask == 0)) {
4556 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4557 t_stat r;
4558
4559 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4560 if (r != SCPE_OK)
4561 return r;
4562 }
4563 else {
4564 if (!dptr->modifiers)
4565 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4566 else
4567 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4568 }
4569 }
4570 }
4571 return SCPE_OK;
4572 }
4573
4574 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4575 {
4576 if (!tab)
4577 return NULL;
4578 for (; tab->name != NULL; tab++) {
4579 if (MATCH_CMD (gbuf, tab->name) == 0)
4580 return tab;
4581 }
4582 return NULL;
4583 }
4584
4585
4586
4587 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4588 {
4589 uint32 j, udbl, ucnt;
4590 UNIT *uptr;
4591 int32 toks = 0;
4592
4593 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4594 (void)fprintf (st, "%s", sim_dname (dptr));
4595 if ((flag == 2) && dptr->description) {
4596 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4597 }
4598 else {
4599 if ((sim_switches & SWMASK ('D')) && dptr->description)
4600 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4601 }
4602 if (qdisable (dptr)) {
4603 (void)fprintf (st, "\tdisabled\r\n");
4604 return SCPE_OK;
4605 }
4606 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4607 uptr = dptr->units + j;
4608 if (!(uptr->flags & UNIT_DIS))
4609 ucnt++;
4610 else if (uptr->flags & UNIT_DISABLE)
4611 udbl++;
4612 }
4613
4614 if (dptr->numunits == 0) {
4615
4616
4617 }
4618 else
4619 {
4620 if (ucnt == 0) {
4621 fprint_sep (st, &toks);
4622 (void)fprintf (st, "all units disabled\r\n");
4623 }
4624 else if ((ucnt + udbl) == 1) {
4625 fprint_sep (st, &toks);
4626 (void)fprintf (st, " 1 unit\r\n");
4627 }
4628 else if ((ucnt > 1) || (udbl > 0)) {
4629 fprint_sep (st, &toks);
4630 (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4631 }
4632 else
4633 if ((flag != 2) || !dptr->description || toks)
4634 (void)fprintf (st, "\r\n");
4635 toks = 0;
4636 }
4637 if (flag)
4638 return SCPE_OK;
4639 for (j = 0; j < dptr->numunits; j++) {
4640 uptr = dptr->units + j;
4641 if ((uptr->flags & UNIT_DIS) == 0)
4642 show_unit (st, dptr, uptr, ucnt + udbl);
4643 }
4644 }
4645 return SCPE_OK;
4646 }
4647
4648 void fprint_sep (FILE *st, int32 *tokens)
4649 {
4650 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4651 *tokens += 1;
4652 }
4653
4654 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4655 {
4656 int32 u = (int32)(uptr - dptr->units);
4657 int32 toks = 0;
4658
4659 if (flag > 1)
4660 (void)fprintf (st, " %s%d\r\n", sim_dname (dptr), u);
4661 else if (flag < 0)
4662 (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4663 if (uptr->flags & UNIT_ATT) {
4664 fprint_sep (st, &toks);
4665 (void)fprintf (st, "status : attached to %s", uptr->filename);
4666 if (uptr->flags & UNIT_RO)
4667 (void)fprintf (st, ", read only");
4668 }
4669 else {
4670 if (uptr->flags & UNIT_ATTABLE) {
4671 fprint_sep (st, &toks);
4672 (void)fprintf (st, "status : not attached");
4673 }
4674 }
4675 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4676 fprint_sep (st, &toks);
4677 fprint_capac (st, dptr, uptr);
4678 }
4679 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4680 if (toks || (flag < 0) || (flag > 1))
4681 (void)fprintf (st, "\r\n");
4682 return SCPE_OK;
4683 }
4684
4685 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4686 {
4687 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4688 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4689 t_offset mval;
4690 t_offset psize = (t_offset)uptr->capac;
4691 char *scale, *width;
4692
4693 if (sim_switches & SWMASK ('B'))
4694 kval = 1024;
4695 mval = kval * kval;
4696 if (dptr->flags & DEV_SECTORS) {
4697 kval = kval / 512;
4698 mval = mval / 512;
4699 }
4700 if ((dptr->dwidth / dptr->aincr) > 8)
4701 width = "W";
4702 else
4703 width = "B";
4704 if ((psize < (kval * 10)) &&
4705 (0 != (psize % kval))) {
4706 scale = "";
4707 }
4708 else if ((psize < (mval * 10)) &&
4709 (0 != (psize % mval))){
4710 scale = "K";
4711 psize = psize / kval;
4712 }
4713 else {
4714 scale = "M";
4715 psize = psize / mval;
4716 }
4717 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4718 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4719 return capac_buf;
4720 }
4721
4722 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4723 {
4724 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4725 }
4726
4727
4728
4729 extern void print_default_base_system_script (void);
4730 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4731 {
4732 #if !defined(PERF_STRIP)
4733 print_default_base_system_script();
4734 #endif
4735 return 0;
4736 }
4737
4738 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4739 sim_printf (" %s ", label);
4740 sim_printf (" %2d %3o(8) '", length, offset);
4741 for (int l = 0; l < length; l ++)
4742 {
4743 unsigned int byte = PROM[offset + l];
4744 if (byte == 255)
4745 {
4746 byte = ' ';
4747 }
4748 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4749 }
4750 sim_printf ("'\r\n");
4751 }
4752
4753 static void strip_spaces(char* str) {
4754 int i, x;
4755 for (i=x=0; str[i]; ++i)
4756 {
4757 if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)])))
4758 {
4759 str[x++] = str[i];
4760 }
4761 }
4762 str[x] = '\0';
4763 i = -1;
4764 x = 0;
4765 while (str[x] != '\0')
4766 {
4767 if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4768 {
4769 i=x;
4770 }
4771 x++;
4772 }
4773 str[i+1] = '\0';
4774 }
4775
4776 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
4777 char sx[1024];
4778 sx[1023] = '\0';
4779 unsigned int lastbyte = 0;
4780 for (int l = 0; l < length; l ++)
4781 {
4782 unsigned int byte = PROM[offset + l];
4783 if (byte == 255)
4784 {
4785 byte = 20;
4786 }
4787 if ((lastbyte != 20) && (byte != 20))
4788 {
4789 (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4790 }
4791 lastbyte = byte;
4792 }
4793 strip_spaces(sx);
4794 (void)fprintf (st, "%s", sx);
4795 }
4796
4797 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4798 {
4799 unsigned char PROM[1024];
4800 setupPROM (0, PROM);
4801
4802 sim_printf (" PROM size: %llu bytes\r\n",
4803 (long long unsigned)sizeof(PROM));
4804 sim_printf (" PROM initialization data:\r\n\r\n");
4805
4806 sim_printf (" Field Description Length Offset Contents\r\n");
4807 sim_printf (" ========================= ======== ======== ==================================\r\n");
4808 sim_printf ("\r\n");
4809
4810
4811
4812 printp (PROM, "CPU Model ", 0, 11);
4813 printp (PROM, "CPU Serial ", 11, 11);
4814 printp (PROM, "Ship Date ", 22, 6);
4815 printp (PROM, "PROM Layout Version ", 60, 1);
4816 printp (PROM, "Release Git Commit Date ", 70, 10);
4817 printp (PROM, "Release Major ", 80, 3);
4818 printp (PROM, "Release Minor ", 83, 3);
4819 printp (PROM, "Release Patch ", 86, 3);
4820 printp (PROM, "Release Iteration ", 89, 3);
4821 printp (PROM, "Release Build Number ", 92, 8);
4822 printp (PROM, "Release Type ", 100, 1);
4823 printp (PROM, "Release Version Text ", 101, 29);
4824 printp (PROM, "Build Architecture ", 130, 20);
4825 printp (PROM, "Build Operating System ", 150, 20);
4826 printp (PROM, "Target Architecture ", 170, 20);
4827 printp (PROM, "Target Operating System ", 190, 20);
4828
4829 sim_printf("\r\n");
4830 return 0;
4831 }
4832
4833 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4834 {
4835 (void)fprintf (st, "\r Build Information:\r\n");
4836 #if defined(BUILDINFO_scp)
4837 (void)fprintf (st, "\r\n Compilation info: %s\r\n", BUILDINFO_scp );
4838 #else
4839 (void)fprintf (st, "\r\n Compilation info: Not available\r\n" );
4840 #endif
4841 #if !defined(__CYGWIN__)
4842 # if !defined(__APPLE__)
4843 # if !defined(_AIX)
4844 # if !defined(__MINGW32__)
4845 # if !defined(__MINGW64__)
4846 # if !defined(CROSS_MINGW32)
4847 # if !defined(CROSS_MINGW64)
4848 # if !defined(_WIN32)
4849 # if !defined(__HAIKU__)
4850 # if !defined(__QNX__)
4851 (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4852 if (dl_iterate_phdr_callback_called)
4853 (void)fprintf (st, "\r\n");
4854 dl_iterate_phdr_callback_called = 0;
4855 # endif
4856 # endif
4857 # endif
4858 # endif
4859 # endif
4860 # endif
4861 # endif
4862 # endif
4863 # endif
4864 #endif
4865 #if defined(UV_VERSION_MAJOR) && \
4866 defined(UV_VERSION_MINOR) && \
4867 defined(UV_VERSION_PATCH)
4868 # if defined(UV_VERSION_MAJOR)
4869 # if !defined(UV_VERSION_MINOR) && \
4870 !defined(UV_VERSION_PATCH) && \
4871 !defined(UV_VERSION_SUFFIX)
4872 (void)fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4873 # endif
4874 # if defined(UV_VERSION_MINOR)
4875 # if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4876 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4877 UV_VERSION_MINOR);
4878 # endif
4879 # if defined(UV_VERSION_PATCH)
4880 # if !defined(UV_VERSION_SUFFIX)
4881 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4882 UV_VERSION_MINOR, UV_VERSION_PATCH);
4883 # endif
4884 # if defined(UV_VERSION_SUFFIX)
4885 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4886 UV_VERSION_MINOR, UV_VERSION_PATCH);
4887 # if defined(UV_VERSION_IS_RELEASE)
4888 # if UV_VERSION_IS_RELEASE == 1
4889 # define UV_RELEASE_TYPE " (release)"
4890 # endif
4891 # if UV_VERSION_IS_RELEASE == 0
4892 # define UV_RELEASE_TYPE "-dev"
4893 # endif
4894 # if !defined(UV_RELEASE_TYPE)
4895 # define UV_RELEASE_TYPE ""
4896 # endif
4897 # if defined(UV_RELEASE_TYPE)
4898 (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4899 # endif
4900 # endif
4901 # endif
4902 # endif
4903 # endif
4904 unsigned int CurrentUvVersion = uv_version();
4905 if (CurrentUvVersion > 0)
4906 if (uv_version_string() != NULL)
4907 (void)fprintf (st, "; %s in use", uv_version_string());
4908 # endif
4909 #else
4910 (void)fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4911 #endif
4912
4913
4914
4915 (void)fprintf (st, "\r\n Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4916 SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4917 SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4918 sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4919 #if defined(DECNUMBERLOC)
4920 # if defined(DECVERSION)
4921 # if defined(DECVERSEXT)
4922 (void)fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4923 # else
4924 # if defined(DECNLAUTHOR)
4925 (void)fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4926 # else
4927 (void)fprintf (st, "\r\n Math library: %s", DECVERSION);
4928 # endif
4929 # endif
4930 # else
4931 (void)fprintf (st, "\r\n Math library: decNumber, unknown version");
4932 # endif
4933 #endif
4934 #if defined(LOCKLESS)
4935 (void)fprintf (st, "\r\n Atomic operations: ");
4936 # if defined(AIX_ATOMICS)
4937 (void)fprintf (st, "C11 and IBM AIX-style");
4938 # elif defined(BSD_ATOMICS)
4939 (void)fprintf (st, "C11 and FreeBSD-style");
4940 # elif defined(GNU_ATOMICS)
4941 (void)fprintf (st, "C11 and GNU-style");
4942 # elif defined(SYNC_ATOMICS)
4943 (void)fprintf (st, "C11 and GNU sync-style");
4944 # elif defined(ISO_ATOMICS)
4945 (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4946 # elif defined(NT_ATOMICS)
4947 (void)fprintf (st, "C11 and Windows NT interlocked operations");
4948 # endif
4949 #endif
4950 (void)fprintf (st, "\r\n File locking: ");
4951 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4952 (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4953 #endif
4954 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4955 (void)fprintf (st, "POSIX-style fcntl() locking");
4956 #endif
4957 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4958 (void)fprintf (st, "BSD-style flock() locking");
4959 #endif
4960 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4961 (void)fprintf (st, "No file locking available");
4962 #endif
4963 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
4964 (void)fprintf (st, "\r\n Windows support: ");
4965 #endif
4966 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4967 # if defined(__MINGW64_VERSION_STR)
4968 (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4969 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4970 (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4971 # else
4972 (void)fprintf (st, "Built with MinGW");
4973 # endif
4974
4975 # if defined(MINGW_CRT)
4976 (void)fprintf (st, "; %s", MINGW_CRT);
4977 # if !defined(_UCRT)
4978 # if defined(__MSVCRT_VERSION__)
4979 # if __MSVCRT_VERSION__ > 0x00
4980 (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4981 # endif
4982 # endif
4983 # else
4984
4985 struct UCRTVersion ucrtversion;
4986 int result = GetUCRTVersion (&ucrtversion);
4987
4988 if (result == 0)
4989 (void)fprintf (st, " %u.%u.%u.%u",
4990 ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4991 ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4992 # endif
4993 (void)fprintf (st, " in use");
4994 # endif
4995 #elif defined(__CYGWIN__)
4996 struct utsname utsname;
4997 (void)fprintf (st, "Built with Cygwin %d.%d.%d",
4998 CYGWIN_VERSION_DLL_MAJOR / 1000,
4999 CYGWIN_VERSION_DLL_MAJOR % 1000,
5000 CYGWIN_VERSION_DLL_MINOR);
5001 if (uname(&utsname) == 0)
5002 fprintf (st, "; %s in use", utsname.release);
5003 #endif
5004
5005 (void)fprintf (st, "\r\n");
5006 return 0;
5007 }
5008
5009 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5010 {
5011 const char *arch = "";
5012 char *whydirty = " ";
5013 int dirty = 0;
5014
5015 if (cptr && (*cptr != 0))
5016 return SCPE_2MARG;
5017 if (flag) {
5018 (void)fprintf (st, " %s Simulator:", sim_name);
5019 #if defined(USE_DUMA)
5020 # undef NO_SUPPORT_VERSION
5021 # define NO_SUPPORT_VERSION 1
5022 nodist++;
5023 #endif
5024 #if defined(NO_SUPPORT_VERSION) || \
5025 defined(WITH_SOCKET_DEV) || \
5026 defined(WITH_ABSI_DEV) || \
5027 defined(WITH_MGP_DEV) || \
5028 defined(TESTING) || \
5029 defined(ISOLTS) || \
5030 defined(USE_DUMA)
5031 # if !defined(NO_SUPPORT_VERSION)
5032 # define NO_SUPPORT_VERSION 1
5033 # endif
5034 #endif
5035 #if defined(NO_SUPPORT_VERSION)
5036 dirty++;
5037 #endif
5038 #if defined(GENERATED_MAKE_VER_H)
5039 # if defined(VER_H_GIT_VERSION)
5040
5041
5042 if (strstr(VER_H_GIT_VERSION, "*"))
5043 {
5044 dirty++;
5045 }
5046
5047
5048 if ((strstr(VER_H_GIT_VERSION, "X")) || \
5049 (strstr(VER_H_GIT_VERSION, "D")) || \
5050 (strstr(VER_H_GIT_VERSION, "A")) || \
5051 (strstr(VER_H_GIT_VERSION, "B")))
5052 {
5053 dirty++;
5054 }
5055
5056
5057 if (dirty)
5058 {
5059 if ((strstr(VER_H_GIT_VERSION, "X")))
5060 {
5061 whydirty = " ";
5062 }
5063 else if ((strstr(VER_H_GIT_VERSION, "D")))
5064 {
5065 whydirty = " DEV ";
5066 }
5067 else if ((strstr(VER_H_GIT_VERSION, "A")))
5068 {
5069 whydirty = " ALPHA ";
5070 }
5071 else if ((strstr(VER_H_GIT_VERSION, "B")))
5072 {
5073 whydirty = " BETA ";
5074 }
5075 }
5076
5077 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5078 # if defined(VER_H_GIT_HASH)
5079 # if VER_H_GIT_PATCH_INT < 1
5080 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5081 VER_H_GIT_VERSION,
5082 (long)(CHAR_BIT*sizeof(void *)),
5083 VER_H_GIT_HASH);
5084 # else
5085 # define NO_SUPPORT_VERSION 1
5086 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)\r\n Commit: %s",
5087 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5088 (long)(CHAR_BIT*sizeof(void *)),
5089 VER_H_GIT_HASH);
5090 # endif
5091 # else
5092 # if VER_H_GIT_PATCH_INT < 1
5093 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5094 VER_H_GIT_VERSION,
5095 (long)(CHAR_BIT*sizeof(void *)));
5096 # else
5097 # define NO_SUPPORT_VERSION 1
5098 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)",
5099 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5100 (long)(CHAR_BIT*sizeof(void *)));
5101 # endif
5102 # endif
5103 # else
5104 # if defined(VER_H_GIT_HASH)
5105 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5106 VER_H_GIT_VERSION,
5107 (long)(CHAR_BIT*sizeof(void *)),
5108 VER_H_GIT_HASH);
5109 # else
5110 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5111 VER_H_GIT_VERSION,
5112 (long)(CHAR_BIT*sizeof(void *)));
5113 # endif
5114 # endif
5115 # endif
5116 #endif
5117
5118
5119 #if defined(TESTING)
5120 (void)fprintf (st, "\r\n Options: ");
5121 # if !defined(HAVE_DPSOPT)
5122 # define HAVE_DPSOPT 1
5123 # endif
5124 (void)fprintf (st, "TESTING");
5125 #endif
5126
5127
5128 #if defined(ISOLTS)
5129 # if defined(HAVE_DPSOPT)
5130 (void)fprintf (st, ", ");
5131 # else
5132 (void)fprintf (st, "\r\n Options: ");
5133 # endif
5134 # if !defined(HAVE_DPSOPT)
5135 # define HAVE_DPSOPT 1
5136 # endif
5137 (void)fprintf (st, "ISOLTS");
5138 #endif
5139
5140
5141 #if defined(NEED_128)
5142 # if defined(HAVE_DPSOPT)
5143 (void)fprintf (st, ", ");
5144 # else
5145 (void)fprintf (st, "\r\n Options: ");
5146 # endif
5147 # if !defined(HAVE_DPSOPT)
5148 # define HAVE_DPSOPT 1
5149 # endif
5150 (void)fprintf (st, "NEED_128");
5151 #endif
5152
5153
5154 #if !defined(LOCKLESS)
5155 # if defined(HAVE_DPSOPT)
5156 (void)fprintf (st, ", ");
5157 # else
5158 (void)fprintf (st, "\r\n Options: ");
5159 # endif
5160 # if !defined(HAVE_DPSOPT)
5161 # define HAVE_DPSOPT 1
5162 # endif
5163 (void)fprintf (st, "NO_LOCKLESS");
5164 #endif
5165
5166
5167 #if defined(PANEL68)
5168 # if defined(HAVE_DPSOPT)
5169 (void)fprintf (st, ", ");
5170 # else
5171 (void)fprintf (st, "\r\n Options: ");
5172 # endif
5173 # if !defined(HAVE_DPSOPT)
5174 # define HAVE_DPSOPT 1
5175 # endif
5176 (void)fprintf (st, "PANEL68");
5177 #endif
5178
5179
5180 #if defined(WITH_ABSI_DEV)
5181 # if defined(HAVE_DPSOPT)
5182 (void)fprintf (st, ", ");
5183 # else
5184 (void)fprintf (st, "\r\n Options: ");
5185 # endif
5186 # if !defined(HAVE_DPSOPT)
5187 # define HAVE_DPSOPT 1
5188 # endif
5189 (void)fprintf (st, "ABSI");
5190 #endif
5191
5192
5193 #if defined(WITH_SOCKET_DEV)
5194 # if defined(HAVE_DPSOPT)
5195 (void)fprintf (st, ", ");
5196 # else
5197 (void)fprintf (st, "\r\n Options: ");
5198 # endif
5199 # if !defined(HAVE_DPSOPT)
5200 # define HAVE_DPSOPT 1
5201 # endif
5202 (void)fprintf (st, "SOCKET");
5203 #endif
5204
5205
5206 #if defined(WITH_MGP_DEV)
5207 # if defined(HAVE_DPSOPT)
5208 (void)fprintf (st, ", ");
5209 # else
5210 (void)fprintf (st, "\r\n Options: ");
5211 # endif
5212 # if !defined(HAVE_DPSOPT)
5213 # define HAVE_DPSOPT 1
5214 # endif
5215 (void)fprintf (st, "CHAOSNET");
5216 # if USE_SOCKET_DEV_APPROACH
5217 (void)fprintf (st, "-S");
5218 # endif
5219 #endif
5220
5221
5222 #if defined(USE_DUMA)
5223 # if defined(HAVE_DPSOPT)
5224 (void)fprintf (st, ", ");
5225 # else
5226 (void)fprintf (st, "\r\n Options: ");
5227 # endif
5228 # if !defined(HAVE_DPSOPT)
5229 # define HAVE_DPSOPT 1
5230 # endif
5231 (void)fprintf (st, "DUMA");
5232 #endif
5233
5234 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5235 # if defined(NO_SUPPORT_VERSION)
5236 (void)fprintf (st, "\r\n Modified: %s", VER_H_GIT_DATE);
5237 # else
5238 (void)fprintf (st, "\r\n Released: %s", VER_H_GIT_DATE);
5239 # endif
5240 #endif
5241 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5242 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5243 #endif
5244 #if defined(VER_CURRENT_TIME)
5245 (void)fprintf (st, "\r\n Compiled: %s", VER_CURRENT_TIME);
5246 #endif
5247 if (dirty)
5248 {
5249 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5250 }
5251 (void)fprintf (st, "\r\n\r\n Build Information:");
5252 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5253 char build_os_version_raw[255];
5254 char build_os_arch_raw[255];
5255 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5256 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5257 char *build_os_version = strdup(build_os_version_raw);
5258 if (!build_os_version)
5259 {
5260 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5261 __func__, __FILE__, __LINE__);
5262 # if defined(USE_BACKTRACE)
5263 # if defined(SIGUSR2)
5264 (void)raise(SIGUSR2);
5265
5266 # endif
5267 # endif
5268 abort();
5269 }
5270 char *build_os_arch = strdup(build_os_arch_raw);
5271 if (!build_os_arch)
5272 {
5273 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5274 __func__, __FILE__, __LINE__);
5275 # if defined(USE_BACKTRACE)
5276 # if defined(SIGUSR2)
5277 (void)raise(SIGUSR2);
5278
5279 # endif
5280 # endif
5281 abort();
5282 }
5283 unsigned char SPROM[1024];
5284 setupPROM (0, SPROM);
5285 (void)fprintf (st, "\r\n Target: ");
5286 printpq (SPROM, st, 190, 20);
5287 if (SPROM[170] != 20)
5288 {
5289 if (SPROM[170] != 255)
5290 {
5291 (void)fprintf (st, " on ");
5292 printpq (SPROM, st, 170, 20);
5293 }
5294 }
5295 strtrimspace(build_os_version, build_os_version_raw);
5296 strtrimspace(build_os_arch, build_os_arch_raw);
5297 (void)fprintf (st, "\r\n Build OS: %s %s", build_os_version, build_os_arch);
5298 FREE(build_os_version);
5299 FREE(build_os_arch);
5300 #endif
5301 #if defined(__VERSION__)
5302 char gnumver[2];
5303 char postver[1024];
5304 (void)sprintf(gnumver, "%.1s", __VERSION__);
5305 (void)sprintf(postver, "%.1023s", __VERSION__);
5306 strremove(postver, "(TM)");
5307 strremove(postver, "(R)");
5308 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5309 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5310 strremove(postver, " gcc 4.9 mode");
5311 strremove(postver, "4.2.1 Compatible ");
5312 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5313 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5314 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5315 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5316 strremove(postver, "(experimental) ");
5317 strremove(postver, ".module+el8.7.0+20823+214a699d");
5318 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5319 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5320 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5321 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5322 strremove(postver, "llvmorg-16.0.6-0-");
5323 strremove(postver, " Clang 15.0.0 (build 760095e)");
5324 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5325 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5326 strremove(postver, " Clang 15.0.0 (build 232543c)");
5327 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5328 strremove(postver, "CLANG: ");
5329 #endif
5330 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5331 # if !defined(__clang_version__)
5332 if (isdigit((unsigned char)gnumver[0])) {
5333 (void)fprintf (st, "\r\n Compiler: GCC %s", postver);
5334 } else {
5335 (void)fprintf (st, "\r\n Compiler: %s", postver);
5336 }
5337 # endif
5338 # if defined(__clang_analyzer__ )
5339 (void)fprintf (st, "\r\n Compiler: Clang C/C++ Static Analyzer");
5340 # elif defined(__clang_version__) && defined(__VERSION__)
5341 char clangllvmver[1024];
5342 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5343 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5344 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5345 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5346 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5347 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5348 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5349 strremove(clangllvmver, " ( )");
5350 strremove(clangllvmver, " ()");
5351 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5352 (void)fprintf (st, "\r\n Compiler: Clang %s", clangllvmver);
5353 } else {
5354 (void)fprintf (st, "\r\n Compiler: %s", postver);
5355 }
5356 # elif defined(__clang_version__)
5357 (void)fprintf (st, "\r\n Compiler: %s", postver);
5358 # endif
5359 #elif defined(__PGI) && !defined(__NVCOMPILER)
5360 (void)fprintf (st, "\r\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5361 # if defined(__PGIC__)
5362 (void)fprintf (st, "%d", __PGIC__);
5363 # if defined(__PGIC_MINOR__)
5364 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5365 # if defined(__PGIC_PATCHLEVEL__)
5366 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5367 # endif
5368 # endif
5369 # endif
5370 #elif defined(__NVCOMPILER)
5371 (void)fprintf (st, "\r\n Compiler: NVIDIA HPC SDK C Compiler ");
5372 # if defined(__NVCOMPILER_MAJOR__)
5373 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5374 # if defined(__NVCOMPILER_MINOR__)
5375 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5376 # if defined(__NVCOMPILER_PATCHLEVEL__)
5377 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5378 # endif
5379 # endif
5380 # endif
5381 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5382 (void)fprintf (st, "\r\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5383 _MSC_FULL_VER/10000000,
5384 (_MSC_FULL_VER/100000)%100,
5385 _MSC_FULL_VER%100000,
5386 _MSC_BUILD);
5387 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5388 # if defined(_AIX) && defined(__PASE__)
5389 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5390 # endif
5391 # if defined(_AIX) && !defined(__PASE__)
5392 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5393 # endif
5394 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5395 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5396 # endif
5397 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5398 # if defined(__PPC__) && defined(__APPLE__)
5399 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5400 # else
5401 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s", __xlc__);
5402 # endif
5403 # endif
5404 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5405 # define VER_ENC(maj, min, rev) \
5406 (((maj) * 1000000) + ((min) * 1000) + (rev))
5407 # define VER_DEC_MAJ(ver) \
5408 ((ver) / 1000000)
5409 # define VER_DEC_MIN(ver) \
5410 (((ver) % 1000000) / 1000)
5411 # define VER_DEC_REV(ver) \
5412 ((ver) % 1000)
5413 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5414 # define COMP_VER VER_ENC( \
5415 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5416 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5417 (__SUNPRO_C & 0xf) * 10)
5418 # elif defined(__SUNPRO_C)
5419 # define COMP_VER VER_ENC( \
5420 (__SUNPRO_C >> 8) & 0xf, \
5421 (__SUNPRO_C >> 4) & 0xf, \
5422 (__SUNPRO_C) & 0xf)
5423 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5424 # define COMP_VER VER_ENC( \
5425 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5426 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5427 (__SUNPRO_CC & 0xf) * 10)
5428 # elif defined(__SUNPRO_CC)
5429 # define COMP_VER VER_ENC( \
5430 (__SUNPRO_CC >> 8) & 0xf, \
5431 (__SUNPRO_CC >> 4) & 0xf, \
5432 (__SUNPRO_CC) & 0xf)
5433 # endif
5434 # if !defined(COMP_VER)
5435 # define COMP_VER 0
5436 # endif
5437 (void)fprintf (st, "\r\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5438 VER_DEC_MAJ(COMP_VER),
5439 VER_DEC_MIN(COMP_VER),
5440 VER_DEC_REV(COMP_VER));
5441 #elif defined(__DMC__)
5442 (void)fprintf (st, "\r\n Compiler: Digital Mars C/C++");
5443 #elif defined(__PCC__)
5444 (void)fprintf (st, "\r\n Compiler: Portable C Compiler");
5445 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5446 (void)fprintf (st, "\r\n Compiler: Plan 9 Compiler Suite");
5447 #elif defined(__ACK__)
5448 (void)fprintf (st, "\r\n Compiler: Amsterdam Compiler Kit");
5449 #elif defined(__COMO__)
5450 (void)fprintf (st, "\r\n Compiler: Comeau C++");
5451 #elif defined(__COMPCERT__)
5452 (void)fprintf (st, "\r\n Compiler: CompCert C");
5453 #elif defined(__COVERITY__)
5454 (void)fprintf (st, "\r\n Compiler: Coverity C/C++ Static Analyzer");
5455 #elif defined(__LCC__)
5456 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5457 (void)fprintf (st, "\r\n Compiler: MCST Elbrus C Compiler");
5458 # if __LCC__ > 99
5459 (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5460 # if defined(__LCC_MINOR__)
5461 # if __LCC_MINOR__ > 0
5462 (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5463 # endif
5464 # endif
5465 # endif
5466 # if defined(__EDG__) && defined(__EDG_VERSION__)
5467 # if __EDG_VERSION__ > 99
5468 (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5469 (int)(((__EDG_VERSION__) % 100) % 10));
5470 # endif
5471 # endif
5472 # else
5473 (void)fprintf (st, "\r\n Compiler: Local/Little C Compiler (lcc)");
5474 # endif
5475 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5476 (void)fprintf (st, "\r\n Compiler: SGI MIPSpro");
5477 #elif defined(__OPEN64__)
5478 (void)fprintf (st, "\r\n Compiler: Open64 %s", __OPEN64__);
5479 #elif defined(__PGI) || defined(__PGIC__)
5480 (void)fprintf (st, "\r\n Compiler: Portland Group/PGI C/C++");
5481 #elif defined(__VBCC__)
5482 (void)fprintf (st, "\r\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5483 #elif defined(__WATCOMC__)
5484 (void)fprintf (st, "\r\n Compiler: Watcom C/C++ %d.%d",
5485 __WATCOMC__ / 100,
5486 __WATCOMC__ % 100);
5487 #elif defined(__xlC__)
5488 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++");
5489 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5490 # if defined(__INTEL_COMPILER_UPDATE)
5491 # if defined(__INTEL_COMPILER_BUILD_DATE)
5492 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d (%d)",
5493 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5494 __INTEL_COMPILER_BUILD_DATE);
5495 # else
5496 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d",
5497 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5498 # endif
5499 # else
5500 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d",
5501 __INTEL_COMPILER);
5502 # endif
5503 #elif defined(SIM_COMPILER)
5504 # define S_xstr(a) S_str(a)
5505 # define S_str(a) #a
5506 (void)fprintf (st, "\r\n Compiler: %s", S_xstr(SIM_COMPILER));
5507 # undef S_str
5508 # undef S_xstr
5509 #else
5510 (void)fprintf (st, "\r\n Compiler: Unknown");
5511 #endif
5512
5513 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5514 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5515 # define SC_IS_PPC64 1
5516 #else
5517 # define SC_IS_PPC64 0
5518 #endif
5519
5520 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5521 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5522 defined(__PPC32)
5523 # define SC_IS_PPC32 1
5524 #else
5525 # define SC_IS_PPC32 0
5526 #endif
5527
5528 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5529 arch = " x86_64";
5530 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5531 arch = " x86";
5532 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5533 arch = " arm64";
5534 #elif defined(_M_ARM) || defined(__arm__)
5535 arch = " arm";
5536 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5537 arch = " ia64";
5538 #elif SC_IS_PPC64
5539 arch = " powerpc64";
5540 #elif SC_IS_PPC32
5541 arch = " powerpc";
5542 #elif defined(__s390x__)
5543 arch = " s390x";
5544 #elif defined(__s390__)
5545 arch = " s390";
5546 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5547 arch = " j2";
5548 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5549 arch = " sh4";
5550 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5551 arch = " sh2";
5552 #elif defined(__alpha__)
5553 arch = " alpha";
5554 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5555 arch = " hppa";
5556 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5557 arch = " ice9";
5558 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5559 arch = " mips64";
5560 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5561 arch = " mips";
5562 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5563 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5564 arch = " openrisc";
5565 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5566 arch = " sparc64";
5567 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5568 arch = " sparc";
5569 #elif defined(__riscv) || defined(__riscv__)
5570 arch = " riscv";
5571 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5572 arch = " e2k";
5573 #elif defined(__myriad2__)
5574 arch = " myriad2";
5575 #elif defined(__loongarch64) || defined(__loongarch__)
5576 arch = " loongarch";
5577 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5578 arch = " m68k";
5579 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5580 arch = " m88k";
5581 #elif defined(__VAX__) || defined(__vax__)
5582 arch = " vax";
5583 #elif defined(__NIOS2__) || defined(__nios2__)
5584 arch = " nios2";
5585 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5586 arch = " microblaze";
5587 #else
5588 arch = " ";
5589 #endif
5590 (void)fprintf (st, "%s", arch);
5591 #if defined(BUILD_BY_USER)
5592 (void)fprintf (st, "\r\n Built by: %s", BUILD_BY_USER);
5593 #else
5594 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5595 (void)fprintf (st, "\r\n Built by: %s", VER_H_PREP_USER);
5596 # endif
5597 #endif
5598 (void)fprintf (st, "\r\n\r\n Host System Information:");
5599 #if defined(_WIN32)
5600 if (1) {
5601 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5602 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5603 char osversion[PATH_MAX+1] = "";
5604 FILE *f;
5605
5606 if ((f = _popen ("ver", "r"))) {
5607 (void)memset (osversion, 0, sizeof(osversion));
5608 do {
5609 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5610 break;
5611 sim_trim_endspc (osversion);
5612 } while (osversion[0] == '\0');
5613 _pclose (f);
5614 }
5615 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5616 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5617 }
5618 #else
5619 if (1) {
5620 char osversion[2*PATH_MAX+1] = "";
5621 FILE *f;
5622 # if !defined(_AIX)
5623 if ((f = popen \
5624 ("uname -mrs 2> /dev/null", "r"))) {
5625 # else
5626 if ((f = popen \
5627 ("sh -c 'echo \"$(command -p env uname -v \
5628 2> /dev/null).$(command -p env uname -r \
5629 2> /dev/null) $(command -p env uname -p \
5630 2> /dev/null)\"' 2> /dev/null", "r"))) {
5631 # endif
5632 (void)memset (osversion, 0, sizeof(osversion));
5633 do {
5634 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5635 break;
5636 }
5637 sim_trim_endspc (osversion);
5638 } while (osversion[0] == '\0');
5639 pclose (f);
5640 strremove(osversion, "0000000000000000 ");
5641 strremove(osversion, " 0000000000000000");
5642 strremove(osversion, "000000000000 ");
5643 strremove(osversion, " 000000000000");
5644 strremove(osversion, "IBM ");
5645 strremove(osversion, " (emulated by qemu)");
5646 strremove(osversion, " (emulated by QEMU)");
5647 }
5648 # if !defined(_AIX)
5649 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5650 # else
5651 strremove(osversion, "AIX ");
5652 # if !defined(__PASE__)
5653 (void)fprintf (st, "\r\n Host OS: IBM AIX %s", osversion);
5654 # else
5655 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE) %s", osversion);
5656 # endif
5657 # endif
5658 } else {
5659 # if !defined(_AIX)
5660 (void)fprintf (st, "\r\n Host OS: Unknown");
5661 # else
5662 # if !defined(__PASE__)
5663 (void)fprintf (st, "\r\n Host OS: IBM AIX");
5664 # else
5665 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE)");
5666 # endif
5667 # endif
5668 }
5669 #endif
5670 if (nodist)
5671 {
5672 sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5673 }
5674 else
5675 {
5676 (void)fprintf (st, "\r\n");
5677 (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5678 (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5679 (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5680 }
5681 (void)fprintf (st, "\r\n");
5682 }
5683 return SCPE_OK;
5684 }
5685
5686 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5687 {
5688 size_t i;
5689 DEVICE *dptr;
5690 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5691
5692 if (cptr && (*cptr != 0))
5693 return SCPE_2MARG;
5694 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5695 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5696 if (!only_enabled || !qdisable (dptr))
5697 show_device (st, dptr, flag);
5698 return SCPE_OK;
5699 }
5700
5701 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5702 {
5703 int32 i;
5704 DEVICE *dptr;
5705
5706 if (cptr && (*cptr != 0))
5707 return SCPE_2MARG;
5708 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5709 show_dev_logicals (st, dptr, NULL, 1, cptr);
5710 return SCPE_OK;
5711 }
5712
5713 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5714 {
5715 if (dptr->lname)
5716 (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5717 else if (!flag)
5718 fputs ("no logical name assigned\r\n", st);
5719 return SCPE_OK;
5720 }
5721
5722 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5723 {
5724 DEVICE *dptr;
5725 UNIT *uptr;
5726 int32 accum;
5727
5728 if (cptr && (*cptr != 0))
5729 return SCPE_2MARG;
5730 if (sim_clock_queue == QUEUE_LIST_END)
5731 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5732 sim_name, sim_time, sim_timer_inst_per_sec ());
5733 else {
5734 const char *tim;
5735
5736 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5737 sim_name, sim_time, sim_timer_inst_per_sec ());
5738 accum = 0;
5739 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5740 if (uptr == &sim_step_unit)
5741 (void)fprintf (st, " Step timer");
5742 else
5743 if (uptr == &sim_expect_unit)
5744 (void)fprintf (st, " Expect fired");
5745 else
5746 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5747 (void)fprintf (st, " %s", sim_dname (dptr));
5748 if (dptr->numunits > 1)
5749 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5750 }
5751 else
5752 (void)fprintf (st, " Unknown");
5753 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5754 (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5755 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5756 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5757 accum = accum + uptr->time;
5758 }
5759 }
5760 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5761 return SCPE_OK;
5762 }
5763
5764 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5765 {
5766 if (cptr && (*cptr != 0))
5767 return SCPE_2MARG;
5768 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5769 return SCPE_OK;
5770 }
5771
5772 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5773 {
5774 t_stat r;
5775
5776 if (cptr && (*cptr != 0))
5777 r = ssh_break (st, cptr, 1);
5778 else
5779 r = sim_brk_showall (st, (uint32)sim_switches);
5780 return r;
5781 }
5782
5783 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5784 {
5785 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5786 return SCPE_OK;
5787 }
5788
5789 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5790 {
5791 int32 any = 0;
5792 DEBTAB *dep;
5793
5794 if (dptr->flags & DEV_DEBUG) {
5795 if (dptr->dctrl == 0)
5796 fputs ("Debugging disabled", st);
5797 else if (dptr->debflags == NULL)
5798 fputs ("Debugging enabled", st);
5799 else {
5800 uint32 dctrl = dptr->dctrl;
5801
5802 fputs ("Debug=", st);
5803 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5804 if ((dctrl & dep->mask) == dep->mask) {
5805 dctrl &= ~dep->mask;
5806 if (any)
5807 fputc (';', st);
5808 fputs (dep->name, st);
5809 any = 1;
5810 }
5811 }
5812 }
5813 fputc ('\n', st);
5814 return SCPE_OK;
5815 }
5816 else return SCPE_NOFNC;
5817 }
5818
5819
5820
5821 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5822 {
5823 int32 lvl, i;
5824
5825 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5826 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5827 if (lvl > 0)
5828 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5829 else
5830 (void)fprintf(st, "On Processing for input commands");
5831 (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5832 for (i=1; i<SCPE_BASE; ++i) {
5833 if (sim_on_actions[lvl][i])
5834 (void)fprintf(st, " on %5d %s\r\n", i, sim_on_actions[lvl][i]); }
5835 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5836 if (sim_on_actions[lvl][i])
5837 (void)fprintf(st, " on %-5s %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5838 if (sim_on_actions[lvl][0])
5839 (void)fprintf(st, " on ERROR %s\r\n", sim_on_actions[lvl][0]);
5840 (void)fprintf(st, "\r\n");
5841 }
5842 if (sim_on_inherit)
5843 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5844 return SCPE_OK;
5845 }
5846
5847
5848
5849 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5850 {
5851 int32 i;
5852 DEVICE *dptr;
5853
5854 if (cptr && (*cptr != 0))
5855 return SCPE_2MARG;
5856 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5857 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5858 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5859 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5860 return SCPE_OK;
5861 }
5862
5863 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5864 {
5865 fprint_set_help (st, dptr);
5866 return SCPE_OK;
5867 }
5868
5869 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5870 {
5871 MTAB *mptr;
5872 t_stat r = SCPE_OK;
5873
5874 if (dptr->modifiers == NULL)
5875 return SCPE_OK;
5876 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5877 if (mptr->pstring &&
5878 ((mptr->mask & MTAB_XTD)?
5879 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5880 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5881 if (*toks > 0) {
5882 (void)fprintf (st, "\r\n");
5883 *toks = 0;
5884 }
5885 if (r == SCPE_OK)
5886 fprint_sep (st, toks);
5887 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5888 }
5889 }
5890 return SCPE_OK;
5891 }
5892
5893 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5894 CONST char *cptr, int32 flag)
5895 {
5896 t_stat r = SCPE_OK;
5897
5898 if (mptr->disp)
5899 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5900 else
5901 fputs (mptr->pstring, st);
5902 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5903 fputc ('\n', st);
5904 return r;
5905 }
5906
5907
5908
5909 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5910 {
5911 int32 i;
5912 DEVICE *dptr;
5913
5914 if (cptr && (*cptr != 0))
5915 return SCPE_2MARG;
5916 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5917 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5918 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5919 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5920 return SCPE_OK;
5921 }
5922
5923 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5924 {
5925 fprint_show_help (st, dptr);
5926 return SCPE_OK;
5927 }
5928
5929
5930
5931 t_stat brk_cmd (int32 flg, CONST char *cptr)
5932 {
5933 GET_SWITCHES (cptr);
5934 return ssh_break (NULL, cptr, flg);
5935 }
5936
5937 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
5938 {
5939 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5940 CONST char *tptr, *t1ptr;
5941 DEVICE *dptr = sim_dflt_dev;
5942 UNIT *uptr;
5943 t_stat r;
5944 t_addr lo, hi, max;
5945 int32 cnt;
5946
5947 if (sim_brk_types == 0)
5948 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
5949 if (dptr == NULL)
5950 return SCPE_IERR;
5951 uptr = dptr->units;
5952 if (uptr == NULL)
5953 return SCPE_IERR;
5954 max = uptr->capac - 1;
5955 abuf[sizeof(abuf)-1] = '\0';
5956 strncpy (abuf, cptr, sizeof(abuf)-1);
5957 cptr = abuf;
5958 if ((aptr = strchr (abuf, ';'))) {
5959 if (flg != SSH_ST)
5960 return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
5961 *aptr++ = 0;
5962 }
5963 if (*cptr == 0) {
5964 lo = (t_addr) get_rval (sim_PC, 0);
5965 return ssh_break_one (st, flg, lo, 0, aptr);
5966 }
5967 while (*cptr) {
5968 cptr = get_glyph (cptr, gbuf, ',');
5969 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5970 if (tptr == NULL)
5971 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
5972 if (*tptr == '[') {
5973 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5974 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5975 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
5976 tptr = t1ptr + 1;
5977 }
5978 else cnt = 0;
5979 if (*tptr != 0)
5980 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
5981 if ((lo == 0) && (hi == max)) {
5982 if (flg == SSH_CL)
5983 sim_brk_clrall (sim_switches);
5984 else
5985 if (flg == SSH_SH)
5986 sim_brk_showall (st, (uint32)sim_switches);
5987 else
5988 return SCPE_ARG;
5989 }
5990 else {
5991 for ( ; lo <= hi; lo = lo + 1) {
5992 r = ssh_break_one (st, flg, lo, cnt, aptr);
5993 if (r != SCPE_OK)
5994 return r;
5995 }
5996 }
5997 }
5998 return SCPE_OK;
5999 }
6000
6001 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
6002 {
6003 if (!sim_brk_types)
6004 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6005 switch (flg) {
6006 case SSH_ST:
6007 return sim_brk_set (lo, sim_switches, cnt, aptr);
6008
6009 break;
6010
6011 case SSH_CL:
6012 return sim_brk_clr (lo, sim_switches);
6013
6014 break;
6015
6016 case SSH_SH:
6017 return sim_brk_show (st, lo, sim_switches);
6018
6019 break;
6020
6021 default:
6022 return SCPE_ARG;
6023 }
6024 }
6025
6026
6027
6028 static t_bool run_cmd_did_reset = FALSE;
6029
6030 t_stat reset_cmd (int32 flag, CONST char *cptr)
6031 {
6032 char gbuf[CBUFSIZE];
6033 DEVICE *dptr;
6034
6035 GET_SWITCHES (cptr);
6036 run_cmd_did_reset = FALSE;
6037 if (*cptr == 0)
6038 return (reset_all (0));
6039 cptr = get_glyph (cptr, gbuf, 0);
6040 if (*cptr != 0)
6041 return SCPE_2MARG;
6042 if (strcmp (gbuf, "ALL") == 0)
6043 return (reset_all (0));
6044 dptr = find_dev (gbuf);
6045 if (dptr == NULL)
6046 return SCPE_NXDEV;
6047 if (dptr->reset != NULL)
6048 return dptr->reset (dptr);
6049 else return SCPE_OK;
6050 }
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060 t_stat reset_all (uint32 start)
6061 {
6062 DEVICE *dptr;
6063 uint32 i;
6064 t_stat reason;
6065
6066 for (i = 0; i < start; i++) {
6067 if (sim_devices[i] == NULL)
6068 return SCPE_IERR;
6069 }
6070 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6071 if (dptr->reset != NULL) {
6072 reason = dptr->reset (dptr);
6073 if (reason != SCPE_OK)
6074 return reason;
6075 }
6076 }
6077 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6078 if (dptr->reset != NULL) {
6079 reason = dptr->reset (dptr);
6080 if (reason != SCPE_OK)
6081 return reason;
6082 }
6083 }
6084 return SCPE_OK;
6085 }
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095 t_stat reset_all_p (uint32 start)
6096 {
6097 t_stat r;
6098 int32 old_sw = sim_switches;
6099
6100 sim_switches = SWMASK ('P');
6101 r = reset_all (start);
6102 sim_switches = old_sw;
6103 return r;
6104 }
6105
6106
6107
6108 t_stat attach_cmd (int32 flag, CONST char *cptr)
6109 {
6110 char gbuf[4*CBUFSIZE];
6111 DEVICE *dptr;
6112 UNIT *uptr;
6113 t_stat r;
6114
6115 GET_SWITCHES (cptr);
6116 if ((NULL == cptr) || (*cptr == 0))
6117 return SCPE_2FARG;
6118 cptr = get_glyph (cptr, gbuf, 0);
6119 GET_SWITCHES (cptr);
6120 if ((NULL == cptr) || (*cptr == 0))
6121 return SCPE_2FARG;
6122 dptr = find_unit (gbuf, &uptr);
6123 if (dptr == NULL)
6124 return SCPE_NXDEV;
6125 if (uptr == NULL)
6126 return SCPE_NXUN;
6127 if (uptr->flags & UNIT_ATT) {
6128 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6129 !(dptr->flags & DEV_DONTAUTO)) {
6130 r = scp_detach_unit (dptr, uptr);
6131 if (r != SCPE_OK)
6132 return r; }
6133 else {
6134 if (!(uptr->dynflags & UNIT_ATTMULT))
6135 return SCPE_ALATT;
6136 }
6137 }
6138 gbuf[sizeof(gbuf)-1] = '\0';
6139 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6140 sim_trim_endspc (gbuf);
6141 return scp_attach_unit (dptr, uptr, gbuf);
6142 }
6143
6144
6145
6146 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6147 {
6148 if (dptr->attach != NULL)
6149 return dptr->attach (uptr, (CONST char *)cptr);
6150 return attach_unit (uptr, (CONST char *)cptr);
6151 }
6152
6153
6154
6155 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6156 {
6157 DEVICE *dptr;
6158
6159 if (uptr->flags & UNIT_DIS)
6160 return SCPE_UDIS;
6161 if (!(uptr->flags & UNIT_ATTABLE))
6162 return SCPE_NOATT;
6163 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6164 return SCPE_NOATT;
6165 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6166 if (uptr->filename == NULL)
6167 return SCPE_MEM;
6168 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6169 if ((sim_switches & SWMASK ('R')) ||
6170 ((uptr->flags & UNIT_RO) != 0)) {
6171 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6172 ((uptr->flags & UNIT_RO) == 0))
6173 return attach_err (uptr, SCPE_NORO);
6174 uptr->fileref = sim_fopen (cptr, "rb");
6175 if (uptr->fileref == NULL)
6176 return attach_err (uptr, SCPE_OPENERR);
6177 uptr->flags = uptr->flags | UNIT_RO;
6178 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6179 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6180 }
6181 }
6182 else {
6183 if (sim_switches & SWMASK ('N')) {
6184 uptr->fileref = sim_fopen (cptr, "wb+");
6185 if (uptr->fileref == NULL)
6186 return attach_err (uptr, SCPE_OPENERR);
6187 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6188 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6189 }
6190 }
6191 else {
6192 uptr->fileref = sim_fopen (cptr, "rb+");
6193 if (uptr->fileref == NULL) {
6194 #if defined(EWOULDBLOCK)
6195 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6196 #else
6197 if ((errno == EAGAIN))
6198 #endif
6199 return attach_err (uptr, SCPE_OPENERR);
6200
6201 #if defined(EPERM)
6202 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6203 #else
6204 if ((errno == EROFS) || (errno == EACCES)) {
6205 #endif
6206 if ((uptr->flags & UNIT_ROABLE) == 0)
6207 return attach_err (uptr, SCPE_NORO);
6208 uptr->fileref = sim_fopen (cptr, "rb");
6209 if (uptr->fileref == NULL)
6210 return attach_err (uptr, SCPE_OPENERR);
6211 uptr->flags = uptr->flags | UNIT_RO;
6212 if (!sim_quiet) {
6213 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6214 }
6215 }
6216 else {
6217 if (sim_switches & SWMASK ('E'))
6218 return attach_err (uptr, SCPE_OPENERR);
6219 uptr->fileref = sim_fopen (cptr, "wb+");
6220 if (uptr->fileref == NULL)
6221 return attach_err (uptr, SCPE_OPENERR);
6222 if (!sim_quiet) {
6223 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6224 }
6225 }
6226 }
6227 }
6228 }
6229 if (uptr->flags & UNIT_BUFABLE) {
6230 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6231 if (uptr->flags & UNIT_MUSTBUF)
6232 uptr->filebuf = calloc (cap, SZ_D (dptr));
6233 if (uptr->filebuf == NULL)
6234 return attach_err (uptr, SCPE_MEM);
6235 if (!sim_quiet) {
6236 sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6237 }
6238 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6239 SZ_D (dptr), cap, uptr->fileref);
6240 uptr->flags = uptr->flags | UNIT_BUF;
6241 }
6242 uptr->flags = uptr->flags | UNIT_ATT;
6243 uptr->pos = 0;
6244 return SCPE_OK;
6245 }
6246
6247 t_stat attach_err (UNIT *uptr, t_stat stat)
6248 {
6249 FREE (uptr->filename);
6250 uptr->filename = NULL;
6251 return stat;
6252 }
6253
6254
6255
6256 t_stat detach_cmd (int32 flag, CONST char *cptr)
6257 {
6258 char gbuf[CBUFSIZE];
6259 DEVICE *dptr;
6260 UNIT *uptr;
6261
6262 GET_SWITCHES (cptr);
6263 if ((NULL == cptr) || (*cptr == 0))
6264 return SCPE_2FARG;
6265 cptr = get_glyph (cptr, gbuf, 0);
6266 if (*cptr != 0)
6267 return SCPE_2MARG;
6268 if (strcmp (gbuf, "ALL") == 0)
6269 return (detach_all (0, FALSE));
6270 dptr = find_unit (gbuf, &uptr);
6271 if (dptr == NULL)
6272 return SCPE_NXDEV;
6273 if (uptr == NULL)
6274 return SCPE_NXUN;
6275 return scp_detach_unit (dptr, uptr);
6276 }
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291 t_stat detach_all (int32 start, t_bool shutdown)
6292 {
6293 uint32 i, j;
6294 DEVICE *dptr;
6295 UNIT *uptr;
6296 t_stat r;
6297
6298 if ((start < 0) || (start > 1))
6299 return SCPE_IERR;
6300 if (shutdown)
6301 sim_switches = sim_switches | SIM_SW_SHUT;
6302 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6303 for (j = 0; j < dptr->numunits; j++) {
6304 uptr = (dptr->units) + j;
6305 if ((uptr->flags & UNIT_ATT) ||
6306 (shutdown && dptr->detach &&
6307 !(uptr->flags & UNIT_ATTABLE))) {
6308 r = scp_detach_unit (dptr, uptr);
6309
6310 if ((r != SCPE_OK) && !shutdown)
6311 return r;
6312 }
6313 }
6314 }
6315 return SCPE_OK;
6316 }
6317
6318
6319
6320 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6321 {
6322 if (dptr->detach != NULL)
6323 return dptr->detach (uptr);
6324 return detach_unit (uptr);
6325 }
6326
6327
6328
6329 t_stat detach_unit (UNIT *uptr)
6330 {
6331 DEVICE *dptr;
6332
6333 if (uptr == NULL)
6334 return SCPE_IERR;
6335 if (!(uptr->flags & UNIT_ATTABLE))
6336 return SCPE_NOATT;
6337 if (!(uptr->flags & UNIT_ATT)) {
6338 if (sim_switches & SIM_SW_REST)
6339 return SCPE_OK;
6340 else
6341 return SCPE_NOTATT;
6342 }
6343 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6344 return SCPE_OK;
6345 if (uptr->flags & UNIT_BUF) {
6346 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6347 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6348 if (!sim_quiet) {
6349 sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6350 }
6351 rewind (uptr->fileref);
6352 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6353 if (ferror (uptr->fileref))
6354 sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6355 sim_dname (dptr), xstrerror_l(errno), errno);
6356 }
6357 if (uptr->flags & UNIT_MUSTBUF) {
6358 FREE (uptr->filebuf);
6359 uptr->filebuf = NULL;
6360 }
6361 uptr->flags = uptr->flags & ~UNIT_BUF;
6362 }
6363 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6364 FREE (uptr->filename);
6365 uptr->filename = NULL;
6366 if (fclose (uptr->fileref) == EOF)
6367 return SCPE_IOERR;
6368 return SCPE_OK;
6369 }
6370
6371
6372
6373 const char *sim_dname (DEVICE *dptr)
6374 {
6375 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6376 }
6377
6378
6379
6380 const char *sim_uname (UNIT *uptr)
6381 {
6382 DEVICE *d = find_dev_from_unit(uptr);
6383 static char uname[CBUFSIZE];
6384
6385 if (!d)
6386 return "";
6387 if (d->numunits == 1)
6388 return sim_dname (d);
6389 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6390 return uname;
6391 }
6392
6393
6394
6395 t_stat run_cmd (int32 flag, CONST char *cptr)
6396 {
6397 char gbuf[CBUFSIZE] = "";
6398 CONST char *tptr;
6399 uint32 i, j;
6400 int32 sim_next = 0;
6401 int32 unitno;
6402 t_value pcv, orig_pcv;
6403 t_stat r;
6404 DEVICE *dptr;
6405 UNIT *uptr;
6406
6407 GET_SWITCHES (cptr);
6408 sim_step = 0;
6409 if ((flag == RU_RUN) || (flag == RU_GO)) {
6410 orig_pcv = get_rval (sim_PC, 0);
6411 if (*cptr != 0) {
6412 cptr = get_glyph (cptr, gbuf, 0);
6413 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6414 if (sim_dflt_dev && sim_vm_parse_addr)
6415 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6416 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6417 if ((tptr == gbuf) || (*tptr != 0) ||
6418 (pcv > width_mask[sim_PC->width]))
6419 return SCPE_ARG;
6420 put_rval (sim_PC, 0, pcv);
6421 }
6422 }
6423 if ((flag == RU_RUN) &&
6424 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6425 put_rval (sim_PC, 0, orig_pcv);
6426 return r;
6427 }
6428 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6429 int32 saved_switches = sim_switches;
6430
6431 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6432 cptr = get_glyph (cptr, gbuf, 0);
6433 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6434 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6435 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6436 sim_switches = 0;
6437 GET_SWITCHES (cptr);
6438 if ((*cptr == '\'') || (*cptr == '"')) {
6439 r = expect_cmd (1, cptr);
6440 if (r != SCPE_OK)
6441 return r;
6442 }
6443 else {
6444 if (sim_switches == 0)
6445 sim_switches = sim_brk_dflt;
6446 sim_switches |= BRK_TYP_TEMP;
6447 sim_brk_types |= BRK_TYP_TEMP;
6448 r = ssh_break (NULL, cptr, SSH_ST);
6449 if (r != SCPE_OK)
6450 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6451 }
6452 sim_switches = saved_switches;
6453 }
6454 }
6455
6456 else if ((flag == RU_STEP) ||
6457 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6458 static t_bool not_implemented_message = FALSE;
6459
6460 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6461 not_implemented_message = TRUE;
6462 flag = RU_STEP;
6463 }
6464 if (*cptr != 0) {
6465 cptr = get_glyph (cptr, gbuf, 0);
6466 if (*cptr != 0)
6467 return SCPE_2MARG;
6468 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6469 if ((r != SCPE_OK) || (sim_step <= 0))
6470 return SCPE_ARG;
6471 }
6472 else sim_step = 1;
6473 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6474 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6475 }
6476 else if (flag == RU_NEXT) {
6477 t_addr *addrs;
6478
6479 if (*cptr != 0) {
6480 cptr = get_glyph (cptr, gbuf, 0);
6481 if (*cptr != 0)
6482 return SCPE_2MARG;
6483 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6484 if ((r != SCPE_OK) || (sim_next <= 0))
6485 return SCPE_ARG;
6486 }
6487 else sim_next = 1;
6488 if (sim_vm_is_subroutine_call(&addrs)) {
6489 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6490 for (i=0; addrs[i]; i++)
6491 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6492 }
6493 else
6494 sim_step = 1;
6495 }
6496 else if (flag == RU_BOOT) {
6497 if (*cptr == 0)
6498 return SCPE_2FARG;
6499 cptr = get_glyph (cptr, gbuf, 0);
6500 if (*cptr != 0)
6501 return SCPE_2MARG;
6502 dptr = find_unit (gbuf, &uptr);
6503 if (dptr == NULL)
6504 return SCPE_NXDEV;
6505 if (uptr == NULL)
6506 return SCPE_NXUN;
6507 if (dptr->boot == NULL)
6508 return SCPE_NOFNC;
6509 if (uptr->flags & UNIT_DIS)
6510 return SCPE_UDIS;
6511 if ((uptr->flags & UNIT_ATTABLE) &&
6512 !(uptr->flags & UNIT_ATT))
6513 return SCPE_UNATT;
6514 unitno = (int32) (uptr - dptr->units);
6515 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6516 return r;
6517 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6518 return r;
6519 }
6520
6521 else
6522 if (flag != RU_CONT)
6523 return SCPE_IERR;
6524 else
6525 if (*cptr != 0)
6526 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6527
6528 if (sim_switches & SIM_SW_HIDE)
6529 return SCPE_OK;
6530
6531 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6532 for (j = 0; j < dptr->numunits; j++) {
6533 uptr = dptr->units + j;
6534 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6535 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6536 }
6537 }
6538 stop_cpu = 0;
6539 sim_is_running = 1;
6540 if (sim_ttrun () != SCPE_OK) {
6541 sim_is_running = 0;
6542 sim_ttcmd ();
6543 return SCPE_TTYERR;
6544 }
6545 if ((r = sim_check_console (30)) != SCPE_OK) {
6546 sim_is_running = 0;
6547 sim_ttcmd ();
6548 return r;
6549 }
6550 #if !defined(IS_WINDOWS)
6551 # if defined(SIGINT)
6552 if (signal (SIGINT, int_handler) == SIG_ERR) {
6553 sim_is_running = 0;
6554 sim_ttcmd ();
6555 return SCPE_SIGERR;
6556 }
6557 # endif
6558 #endif
6559 #if !defined(IS_WINDOWS)
6560 # if defined(SIGHUP)
6561 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6562 sim_is_running = 0;
6563 sim_ttcmd ();
6564 return SCPE_SIGERR;
6565 }
6566 # endif
6567 #endif
6568 #if !defined(IS_WINDOWS)
6569 # if defined(SIGTERM)
6570 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6571 sim_is_running = 0;
6572 sim_ttcmd ();
6573 return SCPE_SIGERR;
6574 }
6575 # endif
6576 #endif
6577 if (sim_step)
6578 sim_activate (&sim_step_unit, sim_step);
6579 (void)fflush(stdout);
6580 if (sim_log)
6581 (void)fflush (sim_log);
6582 sim_rtcn_init_all ();
6583 sim_start_timer_services ();
6584
6585 do {
6586 t_addr *addrs;
6587
6588 while (1) {
6589 r = sim_instr();
6590 if (r != SCPE_REMOTE)
6591 break;
6592 sim_remote_process_command ();
6593 }
6594 if ((flag != RU_NEXT) ||
6595 (--sim_next <=0))
6596 break;
6597 if (sim_step == 0) {
6598 t_addr val;
6599 BRKTAB *bp;
6600
6601 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6602 break;
6603 if (sim_vm_pc_value)
6604 val = (t_addr)(*sim_vm_pc_value)();
6605 else
6606 val = (t_addr)get_rval (sim_PC, 0);
6607 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6608 break;
6609 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6610 }
6611 else {
6612 if (r != SCPE_STEP)
6613 break;
6614 }
6615
6616 sim_step = 0;
6617 if (sim_vm_is_subroutine_call(&addrs)) {
6618 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6619 for (i=0; addrs[i]; i++)
6620 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6621 }
6622 else
6623 sim_step = 1;
6624 if (sim_step)
6625 sim_activate (&sim_step_unit, sim_step);
6626 } while (1);
6627
6628 sim_is_running = 0;
6629 sim_stop_timer_services ();
6630 sim_ttcmd ();
6631 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6632 signal (SIGINT, SIG_DFL);
6633 #if defined(SIGHUP)
6634 signal (SIGHUP, SIG_DFL);
6635 #endif
6636 signal (SIGTERM, SIG_DFL);
6637 if (sim_log)
6638 (void)fflush (sim_log);
6639 if (sim_deb)
6640 sim_debug_flush ();
6641 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6642 for (j = 0; j < dptr->numunits; j++) {
6643 uptr = dptr->units + j;
6644 if (uptr->flags & UNIT_ATT) {
6645 if (uptr->io_flush)
6646 uptr->io_flush (uptr);
6647 else {
6648 if (!(uptr->flags & UNIT_BUF) &&
6649 (uptr->fileref) &&
6650 !(uptr->dynflags & UNIT_NO_FIO) &&
6651 !(uptr->flags & UNIT_RO))
6652 (void)fflush (uptr->fileref);
6653 }
6654 }
6655 }
6656 }
6657 sim_cancel (&sim_step_unit);
6658 UPDATE_SIM_TIME;
6659 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6660 }
6661
6662
6663
6664 void
6665 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6666 {
6667 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6668 sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6669 #if defined(WIN_STDIO)
6670 (void)fflush(stderr);
6671 (void)fflush(stdout);
6672 #endif
6673 fprint_stopped (stdout, r);
6674 if (sim_log && (sim_log != stdout))
6675 fprint_stopped (sim_log, r);
6676 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6677 fprint_stopped (sim_deb, r);
6678 #if defined(WIN_STDIO)
6679 (void)fflush(stderr);
6680 (void)fflush(stdout);
6681 #endif
6682 }
6683
6684
6685
6686 t_stat sim_run_boot_prep (int32 flag)
6687 {
6688 UNIT *uptr;
6689 t_stat r;
6690
6691 sim_interval = 0;
6692 sim_time = sim_rtime = 0;
6693 noqueue_time = 0;
6694 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6695 sim_clock_queue = uptr->next;
6696 uptr->next = NULL;
6697 }
6698 r = reset_all (0);
6699 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6700 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6701 sim_printf ("Resetting all devices... This may not have been your intention.\r\n");
6702 sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6703 }
6704 run_cmd_did_reset = TRUE;
6705 }
6706 return r;
6707 }
6708
6709
6710
6711
6712
6713
6714
6715
6716 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6717 {
6718 int32 i;
6719 t_stat r = 0;
6720 t_addr k;
6721 t_value pcval;
6722
6723 fputc ('\n', st);
6724
6725 if (v >= SCPE_BASE)
6726 fputs (sim_error_text (v), st);
6727 else {
6728 fputs (sim_stop_messages [v], st);
6729
6730 if ((sim_vm_fprint_stopped != NULL) &&
6731 (!sim_vm_fprint_stopped (st, v)))
6732 return;
6733 }
6734
6735 (void)fprintf (st, ", %s: ", pc->name);
6736
6737 pcval = get_rval (pc, 0);
6738 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6739 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6740 else fprint_val (st, pcval, pc->radix, pc->width,
6741 pc->flags & REG_FMT);
6742 if ((dptr != NULL) && (dptr->examine != NULL)) {
6743 for (i = 0; i < sim_emax; i++)
6744 sim_eval[i] = 0;
6745 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6746 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6747 break;
6748 }
6749 if ((r == SCPE_OK) || (i > 0)) {
6750 (void)fprintf (st, " (");
6751 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6752 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6753 (void)fprintf (st, ")");
6754 }
6755 }
6756 (void)fprintf (st, "\r\n");
6757 return;
6758 }
6759
6760 void fprint_stopped (FILE *st, t_stat v)
6761 {
6762 #if defined(WIN_STDIO)
6763 (void)fflush(stderr);
6764 (void)fflush(stdout);
6765 #endif
6766 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6767 return;
6768 }
6769
6770
6771
6772
6773 t_stat step_svc (UNIT *uptr)
6774 {
6775 return SCPE_STEP;
6776 }
6777
6778
6779
6780
6781 t_stat expect_svc (UNIT *uptr)
6782 {
6783 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6784 }
6785
6786
6787
6788 void int_handler (int sig)
6789 {
6790 stop_cpu = 1;
6791 return;
6792 }
6793
6794
6795
6796 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6797 {
6798 char gbuf[CBUFSIZE];
6799 CONST char *gptr;
6800 CONST char *tptr = NULL;
6801 int32 opt;
6802 t_addr low, high;
6803 t_stat reason = SCPE_IERR;
6804 DEVICE *tdptr;
6805 REG *lowr, *highr;
6806 FILE *ofile;
6807
6808 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6809 if (flag == EX_E)
6810 opt = opt | CMD_OPT_OF;
6811 cptr = get_sim_opt (opt, cptr, &reason);
6812 if (NULL == cptr)
6813 return reason;
6814 if (*cptr == 0)
6815 return SCPE_2FARG;
6816 if (sim_dfunit == NULL)
6817 return SCPE_NXUN;
6818 cptr = get_glyph (cptr, gbuf, 0);
6819 if ((flag == EX_D) && (*cptr == 0))
6820
6821 return SCPE_2FARG;
6822 ofile = sim_ofile? sim_ofile: stdout;
6823
6824 for (gptr = gbuf, reason = SCPE_OK;
6825 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6826 tdptr = sim_dfdev;
6827 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6828 tptr = gptr + strlen ("STATE");
6829 if (*tptr && (*tptr++ != ','))
6830 return SCPE_ARG;
6831 if ((lowr = sim_dfdev->registers) == NULL)
6832 return SCPE_NXREG;
6833 for (highr = lowr; highr->name != NULL; highr++) ;
6834 sim_switches = sim_switches | SIM_SW_HIDE;
6835 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6836 lowr, --highr, 0, 0);
6837 continue;
6838 }
6839
6840
6841 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6842 (!(sim_opt_out & CMD_OPT_DFT) &&
6843 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6844 low = high = 0;
6845 if ((*tptr == '-') || (*tptr == ':')) {
6846 highr = find_reg (tptr + 1, &tptr, tdptr);
6847 if (highr == NULL)
6848 return SCPE_NXREG;
6849 }
6850 else {
6851 highr = lowr;
6852 if (*tptr == '[') {
6853 if (lowr->depth <= 1)
6854 return SCPE_ARG;
6855 tptr = get_range (NULL, tptr + 1, &low, &high,
6856 10, lowr->depth - 1, ']');
6857 if (tptr == NULL)
6858 return SCPE_ARG;
6859 }
6860 }
6861 if (*tptr && (*tptr++ != ','))
6862 return SCPE_ARG;
6863 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6864 lowr, highr, (uint32) low, (uint32) high);
6865 continue;
6866 }
6867
6868 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6869 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6870 sim_dfunit->capac - sim_dfdev->aincr), 0);
6871 if (tptr == NULL)
6872 return SCPE_ARG;
6873 if (*tptr && (*tptr++ != ','))
6874 return SCPE_ARG;
6875 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6876 sim_dfdev, sim_dfunit);
6877 }
6878 if (sim_ofile)
6879 fclose (sim_ofile);
6880 return reason;
6881 }
6882
6883
6884
6885
6886
6887
6888
6889 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6890 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6891 {
6892 t_stat reason;
6893 uint32 idx, val_start=lows;
6894 t_value val, last_val;
6895 REG *rptr;
6896
6897 if ((lowr == NULL) || (highr == NULL))
6898 return SCPE_IERR;
6899 if (lowr > highr)
6900 return SCPE_ARG;
6901 for (rptr = lowr; rptr <= highr; rptr++) {
6902 if ((sim_switches & SIM_SW_HIDE) &&
6903 (rptr->flags & REG_HIDDEN))
6904 continue;
6905 val = last_val = 0;
6906 for (idx = lows; idx <= highs; idx++) {
6907 if (idx >= rptr->depth)
6908 return SCPE_SUB;
6909 val = get_rval (rptr, idx);
6910 if (schptr && !test_search (&val, schptr))
6911 continue;
6912 if (flag == EX_E) {
6913 if ((idx > lows) && (val == last_val))
6914 continue;
6915 if (idx > val_start+1) {
6916 if (idx-1 == val_start+1) {
6917 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6918 if (reason != SCPE_OK)
6919 return reason;
6920 if (sim_log && (ofile == stdout))
6921 ex_reg (sim_log, val, flag, rptr, idx-1);
6922 }
6923 else {
6924 if (val_start+1 != idx-1) {
6925 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6926 if (sim_log && (ofile == stdout))
6927 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6928 }
6929 else {
6930 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6931 if (sim_log && (ofile == stdout))
6932 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6933 }
6934 }
6935 }
6936 sim_last_val = last_val = val;
6937 val_start = idx;
6938 reason = ex_reg (ofile, val, flag, rptr, idx);
6939 if (reason != SCPE_OK)
6940 return reason;
6941 if (sim_log && (ofile == stdout))
6942 ex_reg (sim_log, val, flag, rptr, idx);
6943 }
6944 if (flag != EX_E) {
6945 reason = dep_reg (flag, cptr, rptr, idx);
6946 if (reason != SCPE_OK)
6947 return reason;
6948 }
6949 }
6950 if ((flag == EX_E) && (val_start != highs)) {
6951 if (highs == val_start+1) {
6952 reason = ex_reg (ofile, val, flag, rptr, highs);
6953 if (reason != SCPE_OK)
6954 return reason;
6955 if (sim_log && (ofile == stdout))
6956 ex_reg (sim_log, val, flag, rptr, highs);
6957 }
6958 else {
6959 if (val_start+1 != highs) {
6960 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6961 if (sim_log && (ofile == stdout))
6962 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6963 }
6964 else {
6965 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6966 if (sim_log && (ofile == stdout))
6967 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6968 }
6969 }
6970 }
6971 }
6972 return SCPE_OK;
6973 }
6974
6975 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
6976 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6977 {
6978 t_addr i, mask;
6979 t_stat reason;
6980
6981 if (uptr->flags & UNIT_DIS)
6982 return SCPE_UDIS;
6983 mask = (t_addr) width_mask[dptr->awidth];
6984 if ((low > mask) || (high > mask) || (low > high))
6985 return SCPE_ARG;
6986 for (i = low; i <= high; ) {
6987 reason = get_aval (i, dptr, uptr);
6988 if (reason != SCPE_OK)
6989 return reason;
6990 if (schptr && !test_search (sim_eval, schptr))
6991 i = i + dptr->aincr;
6992 else {
6993 if (flag != EX_D) {
6994 reason = ex_addr (ofile, flag, i, dptr, uptr);
6995 if (reason > SCPE_OK)
6996 return reason;
6997 if (sim_log && (ofile == stdout))
6998 ex_addr (sim_log, flag, i, dptr, uptr);
6999 }
7000 else reason = 1 - dptr->aincr;
7001 if (flag != EX_E) {
7002 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7003 if (reason > SCPE_OK)
7004 return reason;
7005 }
7006 i = i + (1 - reason);
7007 }
7008 }
7009 return SCPE_OK;
7010 }
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
7025 {
7026 int32 rdx;
7027
7028 if (rptr == NULL)
7029 return SCPE_IERR;
7030 if (rptr->depth > 1)
7031 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7032 else
7033 (void)Fprintf (ofile, "%s:\t", rptr->name);
7034 if (!(flag & EX_E))
7035 return SCPE_OK;
7036 GET_RADIX (rdx, rptr->radix);
7037 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7038 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7039 else if (!(rptr->flags & REG_VMFLAGS) ||
7040 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7041 NULL, sim_switches | SIM_SW_REG) > 0)) {
7042 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7043 if (rptr->fields) {
7044 (void)Fprintf (ofile, "\t");
7045 fprint_fields (ofile, val, val, rptr->fields);
7046 }
7047 }
7048 if (flag & EX_I)
7049 (void)Fprintf (ofile, "\t");
7050 else
7051 (void)Fprintf (ofile, "\r\n");
7052 return SCPE_OK;
7053 }
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064 t_value get_rval (REG *rptr, uint32 idx)
7065 {
7066 size_t sz;
7067 t_value val;
7068 uint32 *ptr;
7069
7070 sz = SZ_R (rptr);
7071 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7072 idx = idx + rptr->qptr;
7073 if (idx >= rptr->depth) idx = idx - rptr->depth;
7074 }
7075 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7076 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7077 if (sz <= sizeof (uint32))
7078 val = *ptr;
7079 else val = *((t_uint64 *) ptr);
7080 }
7081 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7082 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7083 if (sz <= sizeof (uint32))
7084 val = *ptr;
7085 else val = *((t_uint64 *) ptr);
7086 }
7087 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7088 (sz == sizeof (uint8)))
7089 val = *(((uint8 *) rptr->loc) + idx);
7090 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7091 (sz == sizeof (uint16)))
7092 val = *(((uint16 *) rptr->loc) + idx);
7093 else if (sz <= sizeof (uint32))
7094 val = *(((uint32 *) rptr->loc) + idx);
7095 else val = *(((t_uint64 *) rptr->loc) + idx);
7096 val = (val >> rptr->offset) & width_mask[rptr->width];
7097 return val;
7098 }
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7112 {
7113 t_stat r;
7114 t_value val, mask;
7115 int32 rdx;
7116 CONST char *tptr;
7117 char gbuf[CBUFSIZE];
7118
7119 if ((cptr == NULL) || (rptr == NULL))
7120 return SCPE_IERR;
7121 if (rptr->flags & REG_RO)
7122 return SCPE_RO;
7123 if (flag & EX_I) {
7124 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7125 if (sim_log)
7126 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7127 if (cptr == NULL)
7128 return 1;
7129 if (*cptr == 0)
7130 return SCPE_OK;
7131 }
7132 mask = width_mask[rptr->width];
7133 GET_RADIX (rdx, rptr->radix);
7134 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7135 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7136 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7137 return SCPE_ARG;
7138 }
7139 else
7140 if (!(rptr->flags & REG_VMFLAGS) ||
7141 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7142 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7143 val = get_uint (cptr, rdx, mask, &r);
7144 if (r != SCPE_OK)
7145 return SCPE_ARG;
7146 }
7147 if ((rptr->flags & REG_NZ) && (val == 0))
7148 return SCPE_ARG;
7149 put_rval (rptr, idx, val);
7150 return SCPE_OK;
7151 }
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164 void put_rval (REG *rptr, uint32 idx, t_value val)
7165 {
7166 size_t sz;
7167 t_value mask;
7168 uint32 *ptr;
7169
7170 #define PUT_RVAL(sz,rp,id,v,m) \
7171 *(((sz *) rp->loc) + id) = \
7172 (sz)((*(((sz *) rp->loc) + id) & \
7173 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7174
7175 if (rptr == sim_PC)
7176 sim_brk_npc (0);
7177 sz = SZ_R (rptr);
7178 mask = width_mask[rptr->width];
7179 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7180 idx = idx + rptr->qptr;
7181 if (idx >= rptr->depth)
7182 idx = idx - rptr->depth;
7183 }
7184 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7185 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7186 if (sz <= sizeof (uint32))
7187 *ptr = (*ptr &
7188 ~(((uint32) mask) << rptr->offset)) |
7189 (((uint32) val) << rptr->offset);
7190 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7191 & ~(mask << rptr->offset)) | (val << rptr->offset);
7192 }
7193 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7194 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7195 if (sz <= sizeof (uint32))
7196 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7197 ~(((uint32) mask) << rptr->offset)) |
7198 (((uint32) val) << rptr->offset);
7199 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7200 & ~(mask << rptr->offset)) | (val << rptr->offset);
7201 }
7202 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7203 (sz == sizeof (uint8)))
7204 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7205 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7206 (sz == sizeof (uint16)))
7207 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7208 else if (sz <= sizeof (uint32))
7209 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7210 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7211 return;
7212 }
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7228 {
7229 t_stat reason;
7230 int32 rdx;
7231
7232 if (sim_vm_fprint_addr)
7233 sim_vm_fprint_addr (ofile, dptr, addr);
7234 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7235 (void)Fprintf (ofile, ":\t");
7236 if (!(flag & EX_E))
7237 return (1 - dptr->aincr);
7238
7239 GET_RADIX (rdx, dptr->dradix);
7240 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7241 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7242 reason = 1 - dptr->aincr;
7243 }
7244 if (flag & EX_I)
7245 (void)Fprintf (ofile, "\t");
7246 else
7247 (void)Fprintf (ofile, "\r\n");
7248 return reason;
7249 }
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7263 {
7264 int32 i;
7265 t_value mask;
7266 t_addr j, loc;
7267 size_t sz;
7268 t_stat reason = SCPE_OK;
7269
7270 if ((dptr == NULL) || (uptr == NULL))
7271 return SCPE_IERR;
7272 mask = width_mask[dptr->dwidth];
7273 for (i = 0; i < sim_emax; i++)
7274 sim_eval[i] = 0;
7275 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7276 if (dptr->examine != NULL) {
7277 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7278 if (reason != SCPE_OK)
7279 break;
7280 }
7281 else {
7282 if (!(uptr->flags & UNIT_ATT))
7283 return SCPE_UNATT;
7284 if (uptr->dynflags & UNIT_NO_FIO)
7285 return SCPE_NOFNC;
7286 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7287 reason = SCPE_NXM;
7288 break;
7289 }
7290 sz = SZ_D (dptr);
7291 loc = j / dptr->aincr;
7292 if (uptr->flags & UNIT_BUF) {
7293 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7294 }
7295 else {
7296 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7297 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7298 if ((feof (uptr->fileref)) &&
7299 !(uptr->flags & UNIT_FIX)) {
7300 reason = SCPE_EOF;
7301 break;
7302 }
7303 else if (ferror (uptr->fileref)) {
7304 clearerr (uptr->fileref);
7305 reason = SCPE_IOERR;
7306 break;
7307 }
7308 }
7309 }
7310 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7311 }
7312 if ((reason != SCPE_OK) && (i == 0))
7313 return reason;
7314 return SCPE_OK;
7315 }
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7332 UNIT *uptr, int32 dfltinc)
7333 {
7334 int32 i, count, rdx;
7335 t_addr j, loc;
7336 t_stat r, reason;
7337 t_value mask;
7338 size_t sz;
7339 char gbuf[CBUFSIZE];
7340
7341 if (dptr == NULL)
7342 return SCPE_IERR;
7343 if (flag & EX_I) {
7344 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7345 if (sim_log)
7346 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7347 if (cptr == NULL)
7348 return 1;
7349 if (*cptr == 0)
7350 return dfltinc;
7351 }
7352 if (uptr->flags & UNIT_RO)
7353 return SCPE_RO;
7354 mask = width_mask[dptr->dwidth];
7355
7356 GET_RADIX (rdx, dptr->dradix);
7357 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7358 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7359 if (reason != SCPE_OK)
7360 return reason;
7361 reason = dfltinc;
7362 }
7363 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7364
7365 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7366 sim_eval[i] = sim_eval[i] & mask;
7367 if (dptr->deposit != NULL) {
7368 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7369 if (r != SCPE_OK)
7370 return r;
7371 }
7372 else {
7373 if (!(uptr->flags & UNIT_ATT))
7374 return SCPE_UNATT;
7375 if (uptr->dynflags & UNIT_NO_FIO)
7376 return SCPE_NOFNC;
7377 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7378 return SCPE_NXM;
7379 sz = SZ_D (dptr);
7380 loc = j / dptr->aincr;
7381 if (uptr->flags & UNIT_BUF) {
7382 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7383 if (loc >= uptr->hwmark)
7384 uptr->hwmark = (uint32) loc + 1;
7385 }
7386 else {
7387 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7388 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7389 if (ferror (uptr->fileref)) {
7390 clearerr (uptr->fileref);
7391 return SCPE_IOERR;
7392 }
7393 }
7394 }
7395 }
7396 return reason;
7397 }
7398
7399
7400
7401 t_stat eval_cmd (int32 flg, CONST char *cptr)
7402 {
7403 if (!sim_dflt_dev)
7404 return SCPE_ARG;
7405 DEVICE *dptr = sim_dflt_dev;
7406 int32 i, rdx, a, lim;
7407 t_stat r;
7408
7409 GET_SWITCHES (cptr);
7410 GET_RADIX (rdx, dptr->dradix);
7411 for (i = 0; i < sim_emax; i++)
7412 sim_eval[i] = 0;
7413 if (*cptr == 0)
7414 return SCPE_2FARG;
7415 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7416 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7417 if (r != SCPE_OK)
7418 return r;
7419 }
7420 lim = 1 - r;
7421 for (i = a = 0; a < lim; ) {
7422 sim_printf ("%d:\t", a);
7423 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7424 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7425 if (sim_log) {
7426 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7427 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7428 }
7429 sim_printf ("\r\n");
7430 if (r < 0)
7431 a = a + 1 - r;
7432 else a = a + dptr->aincr;
7433 i = a / dptr->aincr;
7434 }
7435 return SCPE_OK;
7436 }
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451 char *read_line (char *cptr, int32 size, FILE *stream)
7452 {
7453 return read_line_p (NULL, cptr, size, stream);
7454 }
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7469 {
7470 char *tptr;
7471
7472 if (prompt) {
7473 #if defined(HAVE_LINEHISTORY)
7474 char *tmpc = linenoise (prompt);
7475 if (tmpc == NULL)
7476 cptr = NULL;
7477 else {
7478 strncpy (cptr, tmpc, size-1);
7479 linenoiseHistoryAdd (tmpc);
7480 FREE (tmpc);
7481 }
7482 }
7483 #else
7484 (void)fflush (stdout);
7485 (void)printf ("%s", prompt);
7486 (void)fflush (stdout);
7487 cptr = fgets (cptr, size, stream);
7488 }
7489 #endif
7490 else cptr = fgets (cptr, size, stream);
7491
7492 if (cptr == NULL) {
7493 clearerr (stream);
7494 return NULL;
7495 }
7496 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7497 if ((*tptr == '\n') || (*tptr == '\r') ||
7498 (tptr == (cptr + size - 1))) {
7499 *tptr = 0;
7500 break;
7501 }
7502 }
7503 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7504 memmove (cptr, cptr + 3, strlen (cptr + 3));
7505 while (sim_isspace (*cptr))
7506 cptr++;
7507 if ((*cptr == ';') || (*cptr == '#')) {
7508 if (sim_do_echo)
7509 sim_printf("%s> %s\r\n", do_position(), cptr);
7510 *cptr = 0;
7511 }
7512
7513 return cptr;
7514 }
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7535 {
7536 t_bool quoting = FALSE;
7537 t_bool escaping = FALSE;
7538 char quote_char = 0;
7539
7540 while ((*iptr != 0) &&
7541 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7542 if (quote) {
7543 if (quoting) {
7544 if (!escaping) {
7545 if (*iptr == escape_char)
7546 escaping = TRUE;
7547 else
7548 if (*iptr == quote_char)
7549 quoting = FALSE;
7550 }
7551 else
7552 escaping = FALSE;
7553 }
7554 else {
7555 if ((*iptr == '"') || (*iptr == '\'')) {
7556 quoting = TRUE;
7557 quote_char = *iptr;
7558 }
7559 }
7560 }
7561 if (sim_islower (*iptr) && uc)
7562 *optr = (char)toupper (*iptr);
7563 else *optr = *iptr;
7564 iptr++; optr++;
7565 }
7566 if (mchar && (*iptr == mchar))
7567 iptr++;
7568 *optr = 0;
7569 while (sim_isspace (*iptr))
7570 iptr++;
7571 return iptr;
7572 }
7573
7574 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7575 {
7576 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7577 }
7578
7579 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7580 {
7581 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7582 }
7583
7584 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7585 {
7586 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7587 }
7588
7589 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7590 {
7591
7592 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7593 strcpy (optr, "!");
7594 return (CONST char *)(iptr + 1);
7595 }
7596 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7597 }
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607 char *sim_trim_endspc (char *cptr)
7608 {
7609 char *tptr;
7610
7611 tptr = cptr + strlen (cptr);
7612 while ((--tptr >= cptr) && sim_isspace (*tptr))
7613 *tptr = 0;
7614 return cptr;
7615 }
7616
7617 int sim_isspace (char c)
7618 {
7619 return (c & 0x80) ? 0 : isspace (c);
7620 }
7621
7622 int sim_islower (char c)
7623 {
7624 return (c & 0x80) ? 0 : islower (c);
7625 }
7626
7627 int sim_isalpha (char c)
7628 {
7629 return (c & 0x80) ? 0 : isalpha (c);
7630 }
7631
7632 int sim_isprint (char c)
7633 {
7634 return (c & 0x80) ? 0 : isprint (c);
7635 }
7636
7637 int sim_isdigit (char c)
7638 {
7639 return (c & 0x80) ? 0 : isdigit (c);
7640 }
7641
7642 int sim_isgraph (char c)
7643 {
7644 return (c & 0x80) ? 0 : isgraph (c);
7645 }
7646
7647 int sim_isalnum (char c)
7648 {
7649 return (c & 0x80) ? 0 : isalnum (c);
7650 }
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7664 {
7665 t_value val;
7666 CONST char *tptr;
7667
7668 *status = SCPE_OK;
7669 val = strtotv ((CONST char *)cptr, &tptr, radix);
7670 if ((cptr == tptr) || (val > max))
7671 *status = SCPE_ARG;
7672 else {
7673 while (sim_isspace (*tptr)) tptr++;
7674 if (*tptr != 0)
7675 *status = SCPE_ARG;
7676 }
7677 return val;
7678 }
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7696 uint32 rdx, t_addr max, char term)
7697 {
7698 CONST char *tptr;
7699
7700 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7701 tptr = cptr + strlen ("ALL");
7702 *lo = 0;
7703 *hi = max;
7704 }
7705 else {
7706 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7707 ((cptr[1] == '\0') ||
7708 (cptr[1] == '-') ||
7709 (cptr[1] == ':') ||
7710 (cptr[1] == '/'))) {
7711 tptr = cptr + strlen (".");
7712 *lo = *hi = sim_last_addr;
7713 }
7714 else {
7715 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7716 tptr = cptr + strlen ("$");
7717 *hi = *lo = (t_addr)sim_last_val;
7718 }
7719 else {
7720 if (dptr && sim_vm_parse_addr)
7721 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7722 else
7723 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7724 if (cptr == tptr)
7725 return NULL;
7726 }
7727 }
7728 if ((*tptr == '-') || (*tptr == ':')) {
7729 cptr = tptr + 1;
7730 if (dptr && sim_vm_parse_addr)
7731 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7732 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7733 if (cptr == tptr)
7734 return NULL;
7735 if (*lo > *hi)
7736 return NULL;
7737 }
7738 else if (*tptr == '/') {
7739 cptr = tptr + 1;
7740 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7741 if ((cptr == tptr) || (*hi == 0))
7742 return NULL;
7743 *hi = *lo + *hi - 1;
7744 }
7745 else *hi = *lo;
7746 }
7747 sim_last_addr = *hi;
7748 if (term && (*tptr++ != term))
7749 return NULL;
7750 return tptr;
7751 }
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7772 {
7773 char quote_char;
7774 uint8 *ostart = optr;
7775
7776 *osize = 0;
7777 if ((strlen(iptr) == 1) ||
7778 (iptr[0] != iptr[strlen(iptr)-1]) ||
7779 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7780 return SCPE_ARG;
7781 quote_char = *iptr++;
7782 while (iptr[1]) {
7783 if (*iptr != '\\') {
7784 if (*iptr == quote_char)
7785 return SCPE_ARG;
7786 *(optr++) = (uint8)(*(iptr++));
7787 continue;
7788 }
7789 ++iptr;
7790 switch (*iptr) {
7791 case 'r':
7792 *(optr++) = 13; ++iptr;
7793 break;
7794 case 'n':
7795 *(optr++) = 10; ++iptr;
7796 break;
7797 case 'f':
7798 *(optr++) = 12; ++iptr;
7799 break;
7800 case 't':
7801 *(optr++) = 9; ++iptr;
7802 break;
7803 case 'v':
7804 *(optr++) = 11; ++iptr;
7805 break;
7806 case 'b':
7807 *(optr++) = 8; ++iptr;
7808 break;
7809 case '\\':
7810 *(optr++) = 92; ++iptr;
7811 break;
7812 case 'e':
7813 *(optr++) = 27; ++iptr;
7814 break;
7815 case '\'':
7816 *(optr++) = 39; ++iptr;
7817 break;
7818 case '"':
7819 *(optr++) = 34; ++iptr;
7820 break;
7821 case '?':
7822 *(optr++) = 63; ++iptr;
7823 break;
7824 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7825 *optr = *(iptr++) - '0';
7826 if ((*iptr >= '0') && (*iptr <= '7'))
7827 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7828 if ((*iptr >= '0') && (*iptr <= '7'))
7829 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7830 ++optr;
7831 break;
7832 case 'x':
7833 if (1) {
7834 static const char *hex_digits = "0123456789ABCDEF";
7835 const char *c;
7836
7837 ++iptr;
7838 *optr = 0;
7839 c = strchr (hex_digits, toupper(*iptr));
7840 if (c) {
7841 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7842 ++iptr;
7843 }
7844 c = strchr (hex_digits, toupper(*iptr));
7845 if (c) {
7846 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7847 ++iptr;
7848 }
7849 ++optr;
7850 }
7851 break;
7852 default:
7853 return SCPE_ARG;
7854 }
7855 }
7856 *optr = '\0';
7857 *osize = (uint32)(optr-ostart);
7858 return SCPE_OK;
7859 }
7860
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7875 {
7876 size_t i;
7877 t_bool double_quote_found = FALSE;
7878 t_bool single_quote_found = FALSE;
7879 char quote = '"';
7880 char *tptr, *optr;
7881
7882 optr = (char *)malloc (4*size + 3);
7883 if (optr == NULL)
7884 return NULL;
7885 tptr = optr;
7886 for (i=0; i<size; i++)
7887 switch ((char)iptr[i]) {
7888 case '"':
7889 double_quote_found = TRUE;
7890 break;
7891 case '\'':
7892 single_quote_found = TRUE;
7893 break;
7894 }
7895 if (double_quote_found && (!single_quote_found))
7896 quote = '\'';
7897 *tptr++ = quote;
7898 while (size--) {
7899 switch (*iptr) {
7900 case '\r':
7901 *tptr++ = '\\'; *tptr++ = 'r'; break;
7902 case '\n':
7903 *tptr++ = '\\'; *tptr++ = 'n'; break;
7904 case '\f':
7905 *tptr++ = '\\'; *tptr++ = 'f'; break;
7906 case '\t':
7907 *tptr++ = '\\'; *tptr++ = 't'; break;
7908 case '\v':
7909 *tptr++ = '\\'; *tptr++ = 'v'; break;
7910 case '\b':
7911 *tptr++ = '\\'; *tptr++ = 'b'; break;
7912 case '\\':
7913 *tptr++ = '\\'; *tptr++ = '\\'; break;
7914 case '"':
7915 case '\'':
7916 if (quote == *iptr)
7917 *tptr++ = '\\';
7918
7919 default:
7920 if (sim_isprint (*iptr))
7921 *tptr++ = *iptr;
7922 else {
7923 (void)sprintf (tptr, "\\%03o", *iptr);
7924 tptr += 4;
7925 }
7926 break;
7927 }
7928 ++iptr;
7929 }
7930 *tptr++ = quote;
7931 *tptr++ = '\0';
7932 return optr;
7933 }
7934
7935 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
7936 {
7937 char *string;
7938
7939 string = sim_encode_quoted_string (buf, size);
7940 (void)fprintf (st, "%s", string);
7941 FREE (string);
7942 }
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952 DEVICE *find_dev (const char *cptr)
7953 {
7954 int32 i;
7955 DEVICE *dptr;
7956
7957 if (cptr == NULL)
7958 return NULL;
7959 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7960 if ((strcmp (cptr, dptr->name) == 0) ||
7961 (dptr->lname &&
7962 (strcmp (cptr, dptr->lname) == 0)))
7963 return dptr;
7964 }
7965 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7966 if ((strcmp (cptr, dptr->name) == 0) ||
7967 (dptr->lname &&
7968 (strcmp (cptr, dptr->lname) == 0)))
7969 return dptr;
7970 }
7971 return NULL;
7972 }
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985 DEVICE *find_unit (const char *cptr, UNIT **uptr)
7986 {
7987 uint32 i, u;
7988 const char *nptr;
7989 const char *tptr;
7990 t_stat r;
7991 DEVICE *dptr;
7992
7993 if (uptr == NULL)
7994 return NULL;
7995 *uptr = NULL;
7996 if ((dptr = find_dev (cptr))) {
7997 if (qdisable (dptr))
7998 return NULL;
7999 *uptr = dptr->units;
8000 return dptr;
8001 }
8002
8003 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8004 if (qdisable (dptr))
8005 continue;
8006 if (dptr->numunits &&
8007 (((nptr = dptr->name) &&
8008 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
8009 ((nptr = dptr->lname) &&
8010 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8011 tptr = cptr + strlen (nptr);
8012 if (sim_isdigit (*tptr)) {
8013 if (qdisable (dptr))
8014 return NULL;
8015 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8016 if (r != SCPE_OK)
8017 *uptr = NULL;
8018 else
8019 *uptr = dptr->units + u;
8020 return dptr;
8021 }
8022 }
8023 for (u = 0; u < dptr->numunits; u++) {
8024 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8025 *uptr = &dptr->units[u];
8026 return dptr;
8027 }
8028 }
8029 }
8030 return NULL;
8031 }
8032
8033
8034
8035
8036
8037
8038
8039 t_stat sim_register_internal_device (DEVICE *dptr)
8040 {
8041 uint32 i;
8042
8043 for (i = 0; (sim_devices[i] != NULL); i++)
8044 if (sim_devices[i] == dptr)
8045 return SCPE_OK;
8046 for (i = 0; i < sim_internal_device_count; i++)
8047 if (sim_internal_devices[i] == dptr)
8048 return SCPE_OK;
8049 ++sim_internal_device_count;
8050 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8051 if (!sim_internal_devices)
8052 {
8053 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8054 __func__, __FILE__, __LINE__);
8055 #if defined(USE_BACKTRACE)
8056 # if defined(SIGUSR2)
8057 (void)raise(SIGUSR2);
8058
8059 # endif
8060 #endif
8061 abort();
8062 }
8063 sim_internal_devices[sim_internal_device_count-1] = dptr;
8064 sim_internal_devices[sim_internal_device_count] = NULL;
8065 return SCPE_OK;
8066 }
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076 DEVICE *find_dev_from_unit (UNIT *uptr)
8077 {
8078 DEVICE *dptr;
8079 uint32 i, j;
8080
8081 if (uptr == NULL)
8082 return NULL;
8083 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8084 for (j = 0; j < dptr->numunits; j++) {
8085 if (uptr == (dptr->units + j))
8086 return dptr;
8087 }
8088 }
8089 for (i = 0; i<sim_internal_device_count; i++) {
8090 dptr = sim_internal_devices[i];
8091 for (j = 0; j < dptr->numunits; j++) {
8092 if (uptr == (dptr->units + j))
8093 return dptr;
8094 }
8095 }
8096 return NULL;
8097 }
8098
8099
8100
8101 t_bool qdisable (DEVICE *dptr)
8102 {
8103 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8104 }
8105
8106
8107
8108
8109
8110
8111
8112
8113
8114
8115
8116
8117
8118 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8119 {
8120 int32 i;
8121 DEVICE *dptr;
8122 REG *rptr, *srptr = NULL;
8123
8124 *gdptr = NULL;
8125 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8126 if (dptr->flags & DEV_DIS)
8127 continue;
8128 if ((rptr = find_reg (cptr, optr, dptr))) {
8129 if (srptr)
8130 return NULL;
8131 srptr = rptr;
8132 *gdptr = dptr;
8133 }
8134 }
8135 return srptr;
8136 }
8137
8138
8139
8140
8141
8142
8143
8144
8145
8146
8147
8148
8149 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8150 {
8151 CONST char *tptr;
8152 REG *rptr;
8153 size_t slnt;
8154
8155 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8156 return NULL;
8157 tptr = cptr;
8158 do {
8159 tptr++;
8160 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8161 slnt = tptr - cptr;
8162 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8163 if ((slnt == strlen (rptr->name)) &&
8164 (strncmp (cptr, rptr->name, slnt) == 0)) {
8165 if (optr != NULL)
8166 *optr = tptr;
8167 return rptr;
8168 }
8169 }
8170 return NULL;
8171 }
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182 int32 get_switches (const char *cptr)
8183 {
8184 int32 sw;
8185
8186 if (*cptr != '-')
8187 return 0;
8188 sw = 0;
8189 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8190 if (sim_isalpha (*cptr) == 0)
8191 return -1;
8192 sw = sw | SWMASK (toupper (*cptr));
8193 }
8194 return sw;
8195 }
8196
8197
8198
8199
8200
8201
8202
8203
8204
8205
8206 CONST char *get_sim_sw (CONST char *cptr)
8207 {
8208 int32 lsw;
8209 char gbuf[CBUFSIZE];
8210
8211 while (*cptr == '-') {
8212 cptr = get_glyph (cptr, gbuf, 0);
8213 lsw = get_switches (gbuf);
8214 if (lsw <= 0)
8215 return NULL;
8216 sim_switches = sim_switches | lsw;
8217 }
8218 return cptr;
8219 }
8220
8221
8222
8223
8224
8225
8226
8227
8228
8229
8230
8231 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8232 {
8233 int32 t;
8234 char gbuf[CBUFSIZE];
8235 CONST char *svptr;
8236 DEVICE *tdptr;
8237 UNIT *tuptr;
8238
8239 sim_switches = 0;
8240 sim_ofile = NULL;
8241 sim_schrptr = NULL;
8242 sim_schaptr = NULL;
8243 sim_stabr.logic = sim_staba.logic = SCH_OR;
8244 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8245 sim_stabr.count = 1;
8246 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8247 if (!sim_stabr.mask)
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_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8260 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8261 if (!sim_stabr.comp)
8262 {
8263 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8264 __func__, __FILE__, __LINE__);
8265 #if defined(USE_BACKTRACE)
8266 # if defined(SIGUSR2)
8267 (void)raise(SIGUSR2);
8268
8269 # endif
8270 #endif
8271 abort();
8272 }
8273 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8274 sim_staba.count = sim_emax;
8275 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8276 if (!sim_staba.mask)
8277 {
8278 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8279 __func__, __FILE__, __LINE__);
8280 #if defined(USE_BACKTRACE)
8281 # if defined(SIGUSR2)
8282 (void)raise(SIGUSR2);
8283
8284 # endif
8285 #endif
8286 abort();
8287 }
8288 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8289 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8290 if (!sim_staba.comp)
8291 {
8292 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8293 __func__, __FILE__, __LINE__);
8294 #if defined(USE_BACKTRACE)
8295 # if defined(SIGUSR2)
8296 (void)raise(SIGUSR2);
8297
8298 # endif
8299 #endif
8300 abort();
8301 }
8302 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8303 if (! sim_dflt_dev)
8304 return NULL;
8305 sim_dfdev = sim_dflt_dev;
8306 sim_dfunit = sim_dfdev->units;
8307 sim_opt_out = 0;
8308 *st = SCPE_OK;
8309 while (*cptr) {
8310 svptr = cptr;
8311 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8312 if (sim_ofile) {
8313 fclose (sim_ofile);
8314 *st = SCPE_ARG;
8315 return NULL;
8316 }
8317 cptr = get_glyph (cptr + 1, gbuf, 0);
8318 sim_ofile = sim_fopen (gbuf, "a");
8319 if (sim_ofile == NULL) {
8320 *st = SCPE_OPENERR;
8321 return NULL;
8322 }
8323 sim_opt_out |= CMD_OPT_OF;
8324 continue;
8325 }
8326 cptr = get_glyph (cptr, gbuf, 0);
8327 if ((t = get_switches (gbuf)) != 0) {
8328 if (t < 0) {
8329 *st = SCPE_INVSW;
8330 return NULL;
8331 }
8332 sim_switches = sim_switches | t;
8333 }
8334 else if ((opt & CMD_OPT_SCH) &&
8335 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8336 sim_schrptr = &sim_stabr;
8337 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8338 sim_opt_out |= CMD_OPT_SCH;
8339 }
8340 else if ((opt & CMD_OPT_DFT) &&
8341 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8342 (tdptr = find_unit (gbuf, &tuptr)) &&
8343 (tuptr != NULL)) {
8344 sim_dfdev = tdptr;
8345 sim_dfunit = tuptr;
8346 sim_opt_out |= CMD_OPT_DFT;
8347 }
8348 else return svptr;
8349 }
8350 return cptr;
8351 }
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8364 {
8365 char *optr = buf;
8366 int32 bit;
8367
8368 (void)memset (buf, 0, bufsize);
8369 if ((sw == 0) || (bufsize < 3))
8370 return buf;
8371 --bufsize;
8372 *optr++ = '-';
8373 for (bit=0; bit <= ('Z'-'A'); bit++)
8374 if (sw & (1 << bit))
8375 if ((size_t)(optr - buf) < bufsize)
8376 *optr++ = 'A' + bit;
8377 return buf;
8378 }
8379
8380
8381
8382
8383
8384
8385
8386
8387
8388
8389
8390
8391 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8392 {
8393 int32 c;
8394 size_t logop, cmpop;
8395 t_value logval, cmpval;
8396 const char *sptr;
8397 CONST char *tptr;
8398 const char logstr[] = "|&^", cmpstr[] = "=!><";
8399
8400 const size_t invalid_op = (size_t) -1;
8401
8402 logval = cmpval = 0;
8403 if (*cptr == 0)
8404 return NULL;
8405
8406 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8407 if ((sptr = strchr (logstr, c))) {
8408 logop = sptr - logstr;
8409 logval = strtotv (cptr, &tptr, radix);
8410 if (cptr == tptr)
8411 return NULL;
8412 cptr = tptr;
8413 }
8414 else if ((sptr = strchr (cmpstr, c))) {
8415 cmpop = sptr - cmpstr;
8416 if (*cptr == '=') {
8417 cmpop = cmpop + strlen (cmpstr);
8418 cptr++;
8419 }
8420 cmpval = strtotv (cptr, &tptr, radix);
8421 if (cptr == tptr)
8422 return NULL;
8423 cptr = tptr;
8424 }
8425 else return NULL;
8426 }
8427 if (schptr->count != 1) {
8428 FREE (schptr->mask);
8429 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8430 FREE (schptr->comp);
8431 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8432 }
8433 if (logop != invalid_op) {
8434 schptr->logic = logop;
8435 schptr->mask[0] = logval;
8436 }
8437 if (cmpop != invalid_op) {
8438 schptr->boolop = cmpop;
8439 schptr->comp[0] = cmpval;
8440 }
8441 schptr->count = 1;
8442 return schptr;
8443 }
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454
8455
8456 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8457 {
8458 int32 c;
8459 size_t logop, cmpop;
8460 t_value *logval, *cmpval;
8461 t_stat reason = SCPE_OK;
8462 CONST char *ocptr = cptr;
8463 const char *sptr;
8464 char gbuf[CBUFSIZE];
8465 const char logstr[] = "|&^", cmpstr[] = "=!><";
8466
8467 const size_t invalid_op = (size_t) -1;
8468
8469 if (*cptr == 0)
8470 return NULL;
8471 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8472 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8473
8474 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8475 if (NULL != (sptr = strchr (logstr, c))) {
8476 logop = sptr - logstr;
8477 cptr = get_glyph (cptr, gbuf, 0);
8478 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8479 if (reason > 0) {
8480 FREE (logval);
8481 FREE (cmpval);
8482 return get_rsearch (ocptr, radix, schptr);
8483 }
8484 }
8485 else if (NULL != (sptr = strchr (cmpstr, c))) {
8486 cmpop = sptr - cmpstr;
8487 if (*cptr == '=') {
8488 cmpop = cmpop + strlen (cmpstr);
8489 cptr++;
8490 }
8491 cptr = get_glyph (cptr, gbuf, 0);
8492 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8493 if (reason > 0) {
8494 FREE (logval);
8495 FREE (cmpval);
8496 return get_rsearch (ocptr, radix, schptr);
8497 }
8498 }
8499 else {
8500 FREE (logval);
8501 FREE (cmpval);
8502 return NULL;
8503 }
8504 }
8505 if (schptr->count != (uint32)(1 - reason)) {
8506 schptr->count = 1 - reason;
8507 FREE (schptr->mask);
8508 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8509 FREE (schptr->comp);
8510 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8511 }
8512 if (logop != invalid_op) {
8513 schptr->logic = logop;
8514 FREE (schptr->mask);
8515 schptr->mask = logval;
8516 }
8517 else {
8518 FREE (logval);
8519 }
8520 if (cmpop != invalid_op) {
8521 schptr->boolop = cmpop;
8522 FREE (schptr->comp);
8523 schptr->comp = cmpval;
8524 }
8525 else {
8526 FREE (cmpval);
8527 }
8528 return schptr;
8529 }
8530
8531
8532
8533
8534
8535
8536
8537
8538
8539
8540 int32 test_search (t_value *values, SCHTAB *schptr)
8541 {
8542 t_value *val = NULL;
8543 int32 i, updown;
8544 int32 ret = 0;
8545
8546 if (schptr == NULL)
8547 return ret;
8548
8549 val = (t_value *)malloc (schptr->count * sizeof (*values));
8550 if (!val)
8551 {
8552 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8553 __func__, __FILE__, __LINE__);
8554 #if defined(USE_BACKTRACE)
8555 # if defined(SIGUSR2)
8556 (void)raise(SIGUSR2);
8557
8558 # endif
8559 #endif
8560 abort();
8561 }
8562 for (i=0; i<(int32)schptr->count; i++) {
8563 val[i] = values[i];
8564 switch (schptr->logic) {
8565
8566 case SCH_OR:
8567 val[i] = val[i] | schptr->mask[i];
8568 break;
8569
8570 case SCH_AND:
8571 val[i] = val[i] & schptr->mask[i];
8572 break;
8573
8574 case SCH_XOR:
8575 val[i] = val[i] ^ schptr->mask[i];
8576 break;
8577 }
8578 }
8579
8580 ret = 1;
8581 if (1) {
8582 updown = -1;
8583 i=schptr->count-1;
8584 }
8585 else {
8586 updown = 1;
8587 i=0;
8588 }
8589 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8590 switch (schptr->boolop) {
8591
8592 case SCH_E: case SCH_EE:
8593 if (val[i] != schptr->comp[i])
8594 ret = 0;
8595 break;
8596
8597 case SCH_N: case SCH_NE:
8598 if (val[i] == schptr->comp[i])
8599 ret = 0;
8600 break;
8601
8602 case SCH_G:
8603 if (val[i] <= schptr->comp[i])
8604 ret = 0;
8605 break;
8606
8607 case SCH_GE:
8608 if (val[i] < schptr->comp[i])
8609 ret = 0;
8610 break;
8611
8612 case SCH_L:
8613 if (val[i] >= schptr->comp[i])
8614 ret = 0;
8615 break;
8616
8617 case SCH_LE:
8618 if (val[i] > schptr->comp[i])
8619 ret = 0;
8620 break;
8621 }
8622 }
8623 FREE (val);
8624 return ret;
8625 }
8626
8627
8628
8629
8630
8631
8632
8633
8634
8635
8636
8637
8638
8639
8640
8641 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8642 {
8643 int32 nodigit;
8644 t_value val;
8645 uint32 c, digit;
8646
8647 *endptr = inptr;
8648 if ((radix < 2) || (radix > 36))
8649 return 0;
8650 while (sim_isspace (*inptr))
8651 inptr++;
8652 val = 0;
8653 nodigit = 1;
8654 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8655 if (sim_islower (c))
8656 c = toupper (c);
8657 if (sim_isdigit (c))
8658 digit = c - (uint32) '0';
8659 else if (radix <= 10)
8660 break;
8661 else digit = c + 10 - (uint32) 'A';
8662 if (digit >= radix)
8663 return 0;
8664 val = (val * radix) + digit;
8665 nodigit = 0;
8666 }
8667 if (nodigit)
8668 return 0;
8669 *endptr = inptr;
8670 return val;
8671 }
8672
8673
8674
8675
8676
8677
8678
8679
8680
8681
8682
8683
8684
8685
8686
8687 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8688 size_t width, uint32 format)
8689 {
8690 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8691 t_value owtest, wtest;
8692 size_t d;
8693 size_t digit;
8694 size_t ndigits;
8695 size_t commas = 0;
8696 char dbuf[MAX_WIDTH + 1];
8697
8698 for (d = 0; d < MAX_WIDTH; d++)
8699 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8700 dbuf[MAX_WIDTH] = 0;
8701 d = MAX_WIDTH;
8702 do {
8703 d = d - 1;
8704 digit = val % radix;
8705 val = val / radix;
8706 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8707 } while ((d > 0) && (val != 0));
8708
8709 switch (format) {
8710 case PV_LEFT:
8711 break;
8712 case PV_RZRO:
8713 wtest = owtest = radix;
8714 ndigits = 1;
8715 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8716 owtest = wtest;
8717 wtest = wtest * radix;
8718 ndigits = ndigits + 1;
8719 }
8720 if ((MAX_WIDTH - (ndigits + commas)) < d)
8721 d = MAX_WIDTH - (ndigits + commas);
8722 break;
8723 }
8724 if (NULL == buffer)
8725 return ((t_stat) strlen(dbuf+d));
8726 *buffer = '\0';
8727 if (width < strlen(dbuf+d))
8728 return SCPE_IOERR;
8729 strcpy(buffer, dbuf+d);
8730 return SCPE_OK;
8731 }
8732
8733 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8734 uint32 width, uint32 format)
8735 {
8736 char dbuf[MAX_WIDTH + 1];
8737
8738 if (!stream)
8739 return sprint_val (NULL, val, radix, width, format);
8740 if (width > MAX_WIDTH)
8741 width = MAX_WIDTH;
8742 sprint_val (dbuf, val, radix, width, format);
8743 if (Fprintf (stream, "%s", dbuf) < 0)
8744 return SCPE_IOERR;
8745 return SCPE_OK;
8746 }
8747
8748 const char *sim_fmt_secs (double seconds)
8749 {
8750 static char buf[60];
8751 char frac[16] = "";
8752 const char *sign = "";
8753 double val = seconds;
8754 double days, hours, mins, secs, msecs, usecs;
8755
8756 if (val == 0.0)
8757 return "";
8758 if (val < 0.0) {
8759 sign = "-";
8760 val = -val;
8761 }
8762 days = floor (val / (24.0*60.0*60.0));
8763 val -= (days * 24.0*60.0*60.0);
8764 hours = floor (val / (60.0*60.0));
8765 val -= (hours * 60.0 * 60.0);
8766 mins = floor (val / 60.0);
8767 val -= (mins * 60.0);
8768 secs = floor (val);
8769 val -= secs;
8770 val *= 1000.0;
8771 msecs = floor (val);
8772 val -= msecs;
8773 val *= 1000.0;
8774 usecs = floor (val+0.5);
8775 if (usecs == 1000.0) {
8776 usecs = 0.0;
8777 msecs += 1;
8778 }
8779 if ((msecs > 0.0) || (usecs > 0.0)) {
8780 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8781 while (frac[strlen (frac) - 1] == '0')
8782 frac[strlen (frac) - 1] = '\0';
8783 if (strlen (frac) == 1)
8784 frac[0] = '\0';
8785 }
8786 if (days > 0)
8787 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8788 sign, days, (days != 1) ? "s" : "", hours, mins,
8789 secs, frac, (days == 1) ? "s" : "");
8790 else
8791 if (hours > 0)
8792 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8793 sign, hours, mins, secs, frac);
8794 else
8795 if (mins > 0)
8796 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8797 sign, mins, secs, frac);
8798 else
8799 if (secs > 0)
8800 (void)sprintf (buf, "%s%.0f%s second",
8801 sign, secs, frac);
8802 else
8803 if (msecs > 0) {
8804 if (usecs > 0)
8805 (void)sprintf (buf, "%s%.0f.%s msec",
8806 sign, msecs, frac+4);
8807 else
8808 (void)sprintf (buf, "%s%.0f msec",
8809 sign, msecs);
8810 }
8811 else
8812 (void)sprintf (buf, "%s%.0f usec",
8813 sign, usecs);
8814 if (0 != strncmp ("1 ", buf, 2))
8815 strcpy (&buf[strlen (buf)], "s");
8816 return buf;
8817 }
8818
8819
8820
8821
8822
8823
8824
8825
8826
8827
8828
8829
8830
8831
8832
8833
8834 t_stat sim_process_event (void)
8835 {
8836 UNIT *uptr;
8837 t_stat reason;
8838 #if defined(TESTING)
8839 cpu_state_t * cpup = _cpup;
8840 #endif
8841
8842 if (stop_cpu)
8843 {
8844 #if defined(WIN_STDIO)
8845 (void)fflush(stdout);
8846 (void)fflush(stderr);
8847 #endif
8848 return SCPE_STOP;
8849 }
8850 UPDATE_SIM_TIME;
8851
8852 if (sim_clock_queue == QUEUE_LIST_END) {
8853 sim_interval = noqueue_time = NOQUEUE_WAIT;
8854 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8855 "Queue Empty New Interval = %d\r\n",
8856 sim_interval);
8857 return SCPE_OK;
8858 }
8859 sim_processing_event = TRUE;
8860 do {
8861 uptr = sim_clock_queue;
8862 sim_clock_queue = uptr->next;
8863 uptr->next = NULL;
8864 sim_interval -= uptr->time;
8865 uptr->time = 0;
8866 if (sim_clock_queue != QUEUE_LIST_END)
8867 sim_interval = sim_clock_queue->time;
8868 else
8869 sim_interval = noqueue_time = NOQUEUE_WAIT;
8870 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8871 "Processing Event for %s\r\n", sim_uname (uptr));
8872 if (uptr->action != NULL)
8873 reason = uptr->action (uptr);
8874 else
8875 reason = SCPE_OK;
8876 } while ((reason == SCPE_OK) &&
8877 (sim_interval <= 0) &&
8878 (sim_clock_queue != QUEUE_LIST_END) &&
8879 (!stop_cpu));
8880
8881 if (sim_clock_queue == QUEUE_LIST_END) {
8882 sim_interval = noqueue_time = NOQUEUE_WAIT;
8883 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8884 "Processing Queue Complete New Interval = %d\r\n",
8885 sim_interval);
8886 }
8887 else
8888 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8889 "Processing Queue Complete New Interval = %d(%s)\r\n",
8890 sim_interval, sim_uname(sim_clock_queue));
8891
8892 if ((reason == SCPE_OK) && stop_cpu)
8893 {
8894 #if defined(WIN_STDIO)
8895 (void)fflush(stdout);
8896 (void)fflush(stderr);
8897 #endif
8898 reason = SCPE_STOP;
8899 }
8900 sim_processing_event = FALSE;
8901 return reason;
8902 }
8903
8904
8905
8906
8907
8908
8909
8910
8911
8912
8913 t_stat sim_activate (UNIT *uptr, int32 event_time)
8914 {
8915 if (uptr->dynflags & UNIT_TMR_UNIT)
8916 return sim_timer_activate (uptr, event_time);
8917 return _sim_activate (uptr, event_time);
8918 }
8919
8920 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8921 {
8922 UNIT *cptr, *prvptr;
8923 int32 accum;
8924 #if defined(TESTING)
8925 cpu_state_t * cpup = _cpup;
8926 #endif
8927
8928 if (sim_is_active (uptr))
8929 return SCPE_OK;
8930 UPDATE_SIM_TIME;
8931
8932 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
8933
8934 prvptr = NULL;
8935 accum = 0;
8936 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8937 if (event_time < (accum + cptr->time))
8938 break;
8939 accum = accum + cptr->time;
8940 prvptr = cptr;
8941 }
8942 if (prvptr == NULL) {
8943 cptr = uptr->next = sim_clock_queue;
8944 sim_clock_queue = uptr;
8945 }
8946 else {
8947 cptr = uptr->next = prvptr->next;
8948 prvptr->next = uptr;
8949 }
8950 uptr->time = event_time - accum;
8951 if (cptr != QUEUE_LIST_END)
8952 cptr->time = cptr->time - uptr->time;
8953 sim_interval = sim_clock_queue->time;
8954 return SCPE_OK;
8955 }
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
8967 {
8968 sim_cancel (uptr);
8969 return _sim_activate (uptr, event_time);
8970 }
8971
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
8982 {
8983 return _sim_activate_after (uptr, usec_delay);
8984 }
8985
8986 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
8987 {
8988 if (sim_is_active (uptr))
8989 return SCPE_OK;
8990 return sim_timer_activate_after (uptr, usec_delay);
8991 }
8992
8993
8994
8995
8996
8997
8998
8999
9000
9001
9002 t_stat sim_cancel (UNIT *uptr)
9003 {
9004 UNIT *cptr, *nptr;
9005 #if defined(TESTING)
9006 cpu_state_t * cpup = _cpup;
9007 #endif
9008
9009 if (sim_clock_queue == QUEUE_LIST_END)
9010 return SCPE_OK;
9011 if (!sim_is_active (uptr))
9012 return SCPE_OK;
9013 UPDATE_SIM_TIME;
9014 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9015 nptr = QUEUE_LIST_END;
9016
9017 if (sim_clock_queue == uptr) {
9018 nptr = sim_clock_queue = uptr->next;
9019 uptr->next = NULL;
9020 }
9021 else {
9022 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9023 if (cptr->next == uptr) {
9024 nptr = cptr->next = uptr->next;
9025 uptr->next = NULL;
9026 break;
9027 }
9028 }
9029 }
9030 if (nptr != QUEUE_LIST_END)
9031 nptr->time += (uptr->next) ? 0 : uptr->time;
9032 if (!uptr->next)
9033 uptr->time = 0;
9034 if (sim_clock_queue != QUEUE_LIST_END)
9035 sim_interval = sim_clock_queue->time;
9036 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9037 if (uptr->next) {
9038 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9039 if (sim_deb)
9040 fclose(sim_deb);
9041 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9042 __func__, __FILE__, __LINE__);
9043 abort ();
9044 }
9045 return SCPE_OK;
9046 }
9047
9048
9049
9050
9051
9052
9053
9054
9055
9056 t_bool sim_is_active (UNIT *uptr)
9057 {
9058 if (uptr->next == NULL)
9059 return FALSE;
9060 else
9061 return TRUE;
9062 }
9063
9064
9065
9066
9067
9068
9069
9070
9071
9072 int32 sim_activate_time (UNIT *uptr)
9073 {
9074 UNIT *cptr;
9075 int32 accum = 0;
9076
9077 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9078 if (cptr == sim_clock_queue) {
9079 if (sim_interval > 0)
9080 accum = accum + sim_interval;
9081 }
9082 else
9083 accum = accum + cptr->time;
9084 if (cptr == uptr)
9085 return accum + 1;
9086 }
9087 return 0;
9088 }
9089
9090
9091
9092
9093
9094
9095
9096
9097 double sim_gtime (void)
9098 {
9099 return sim_time;
9100 }
9101
9102
9103
9104
9105
9106
9107
9108
9109 int32 sim_qcount (void)
9110 {
9111 int32 cnt;
9112 UNIT *uptr;
9113
9114 cnt = 0;
9115 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9116 cnt++;
9117 return cnt;
9118 }
9119
9120
9121
9122
9123
9124
9125
9126
9127
9128
9129
9130
9131
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141
9142
9143
9144
9145
9146
9147
9148
9149
9150
9151
9152
9153
9154
9155 t_stat sim_brk_init (void)
9156 {
9157 int32 i;
9158
9159 for (i=0; i<sim_brk_lnt; i++) {
9160 BRKTAB *bp;
9161 if (sim_brk_tab)
9162 {
9163 bp = sim_brk_tab[i];
9164
9165 while (bp)
9166 {
9167 BRKTAB *bpt = bp->next;
9168
9169 FREE (bp->act);
9170 FREE (bp);
9171 bp = bpt;
9172 }
9173 }
9174 }
9175 if (sim_brk_tab != NULL)
9176 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9177 sim_brk_lnt = SIM_BRK_INILNT;
9178 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9179 if (sim_brk_tab == NULL)
9180 return SCPE_MEM;
9181 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9182 sim_brk_ent = sim_brk_ins = 0;
9183 sim_brk_clract ();
9184 sim_brk_npc (0);
9185 return SCPE_OK;
9186 }
9187
9188
9189
9190 BRKTAB *sim_brk_fnd (t_addr loc)
9191 {
9192 int32 lo, hi, p;
9193 BRKTAB *bp;
9194
9195 if (sim_brk_ent == 0) {
9196 sim_brk_ins = 0;
9197 return NULL;
9198 }
9199 lo = 0;
9200 hi = sim_brk_ent - 1;
9201 do {
9202 p = (lo + hi) >> 1;
9203 bp = sim_brk_tab[p];
9204 if (loc == bp->addr) {
9205 sim_brk_ins = p;
9206 return bp;
9207 }
9208 else if (loc < bp->addr)
9209 hi = p - 1;
9210 else lo = p + 1;
9211 } while (lo <= hi);
9212 if (loc < bp->addr)
9213 sim_brk_ins = p;
9214 else sim_brk_ins = p + 1;
9215 return NULL;
9216 }
9217
9218 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9219 {
9220 BRKTAB *bp = sim_brk_fnd (loc);
9221
9222 while (bp) {
9223 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9224 (bp->typ == btyp))
9225 return bp;
9226 bp = bp->next;
9227 }
9228 return bp;
9229 }
9230
9231
9232
9233 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9234 {
9235 int32 i, t;
9236 BRKTAB *bp, **newp;
9237
9238 if (sim_brk_ins < 0)
9239 return NULL;
9240 if (sim_brk_ent >= sim_brk_lnt) {
9241 t = sim_brk_lnt + SIM_BRK_INILNT;
9242 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9243 if (newp == NULL)
9244 return NULL;
9245 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9246 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9247 FREE (sim_brk_tab);
9248 sim_brk_tab = newp;
9249 sim_brk_lnt = t;
9250 }
9251 if ((sim_brk_ins == sim_brk_ent) ||
9252 ((sim_brk_ins != sim_brk_ent) &&
9253 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9254 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9255 sim_brk_tab[i] = sim_brk_tab[i - 1];
9256 sim_brk_tab[sim_brk_ins] = NULL;
9257 }
9258 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9259 if (!bp)
9260 {
9261 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9262 __func__, __FILE__, __LINE__);
9263 #if defined(USE_BACKTRACE)
9264 # if defined(SIGUSR2)
9265 (void)raise(SIGUSR2);
9266
9267 # endif
9268 #endif
9269 abort();
9270 }
9271 bp->next = sim_brk_tab[sim_brk_ins];
9272 sim_brk_tab[sim_brk_ins] = bp;
9273 if (bp->next == NULL)
9274 sim_brk_ent += 1;
9275 bp->addr = loc;
9276 bp->typ = btyp;
9277 bp->cnt = 0;
9278 bp->act = NULL;
9279 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9280 bp->time_fired[i] = -1.0;
9281 return bp;
9282 }
9283
9284
9285
9286 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9287 {
9288 BRKTAB *bp;
9289
9290 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9291 sw |= sim_brk_dflt;
9292 if (~sim_brk_types & sw) {
9293 char gbuf[CBUFSIZE];
9294
9295 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9296 }
9297 if ((sw & BRK_TYP_DYN_ALL) && act)
9298 return SCPE_ARG;
9299 bp = sim_brk_fnd (loc);
9300 if (!bp)
9301 bp = sim_brk_new (loc, sw);
9302 else {
9303 while (bp && (bp->typ != (uint32)sw))
9304 bp = bp->next;
9305 if (!bp)
9306 bp = sim_brk_new (loc, sw);
9307 }
9308 if (!bp)
9309 return SCPE_MEM;
9310 bp->cnt = ncnt;
9311 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9312 (bp->act != NULL) && (act != NULL)) {
9313 FREE (bp->act);
9314 bp->act = NULL;
9315 }
9316 if ((act != NULL) && (*act != 0)) {
9317 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9318 if (newp == NULL)
9319 return SCPE_MEM;
9320 strncpy (newp, act, CBUFSIZE);
9321 bp->act = newp;
9322 }
9323 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9324 return SCPE_OK;
9325 }
9326
9327
9328
9329 t_stat sim_brk_clr (t_addr loc, int32 sw)
9330 {
9331 BRKTAB *bpl = NULL;
9332 BRKTAB *bp = sim_brk_fnd (loc);
9333 int32 i;
9334
9335 if (!bp)
9336 return SCPE_OK;
9337 if (sw == 0)
9338 sw = SIM_BRK_ALLTYP;
9339
9340 #if !defined(__clang_analyzer__)
9341 while (bp) {
9342 if (bp->typ == (bp->typ & sw)) {
9343 FREE (bp->act);
9344 if (bp == sim_brk_tab[sim_brk_ins])
9345 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9346 else
9347 {
9348 if (bpl)
9349 bpl->next = bp->next;
9350 }
9351 FREE (bp);
9352 bp = bpl;
9353 }
9354 else {
9355 bpl = bp;
9356 bp = bp->next;
9357 }
9358 }
9359 #endif
9360 if (sim_brk_tab[sim_brk_ins] == NULL) {
9361 sim_brk_ent = sim_brk_ent - 1;
9362 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9363 sim_brk_tab[i] = sim_brk_tab[i+1];
9364 }
9365 sim_brk_summ = 0;
9366 for (i = 0; i < sim_brk_ent; i++) {
9367 bp = sim_brk_tab[i];
9368 while (bp) {
9369 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9370 bp = bp->next;
9371 }
9372 }
9373 return SCPE_OK;
9374 }
9375
9376
9377
9378 t_stat sim_brk_clrall (int32 sw)
9379 {
9380 int32 i;
9381
9382 if (sw == 0)
9383 sw = SIM_BRK_ALLTYP;
9384 for (i = 0; i < sim_brk_ent;) {
9385 t_addr loc = sim_brk_tab[i]->addr;
9386 sim_brk_clr (loc, sw);
9387 if ((i < sim_brk_ent) &&
9388 (loc == sim_brk_tab[i]->addr))
9389 ++i;
9390 }
9391 return SCPE_OK;
9392 }
9393
9394
9395
9396 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9397 {
9398 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9399 DEVICE *dptr;
9400 uint32 i, any;
9401
9402 if ((sw == 0) || (sw == SWMASK ('C'))) {
9403 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9404 if (!bp || (!(bp->typ & sw))) {
9405 return SCPE_OK; }
9406 dptr = sim_dflt_dev;
9407 if (dptr == NULL) {
9408 return SCPE_OK; }
9409 if (sw & SWMASK ('C')) {
9410 if (st != NULL) {
9411 (void)fprintf (st, "SET BREAK "); }
9412 } else {
9413 if (sim_vm_fprint_addr) {
9414 sim_vm_fprint_addr
9415 (st, dptr, loc);
9416 } else {
9417 fprint_val
9418 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9419 if (st != NULL) {
9420 (void)fprintf (st, ":\t"); }
9421 }
9422 for (i = any = 0; i < 26; i++) {
9423 if ((bp->typ >> i) & 1) {
9424 if ((sw & SWMASK ('C')) == 0) {
9425 if (any) {
9426 if (st != NULL) {
9427 (void)fprintf (st, ", "); } }
9428 if (st != NULL) {
9429 fputc (i + 'A', st); }
9430 }
9431 } else {
9432 if (st != NULL) {
9433 (void)fprintf (st, "-%c", i + 'A'); }
9434 any = 1;
9435 }
9436 }
9437 if (sw & SWMASK ('C')) {
9438 if (st != NULL) {
9439 (void)fprintf (st, " "); }
9440 if (sim_vm_fprint_addr) {
9441 if (st != NULL) {
9442 sim_vm_fprint_addr (st, dptr, loc); }
9443 } else {
9444 fprint_val
9445 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9446 }
9447 if (bp->cnt > 0) {
9448 if (st != NULL) {
9449 (void)fprintf (st, "[%d]", bp->cnt); } }
9450 if (bp->act != NULL) {
9451 if (st != NULL) {
9452 (void)fprintf (st, "; %s", bp->act); } }
9453 (void)fprintf (st, "\r\n");
9454 return SCPE_OK;
9455 }
9456
9457
9458
9459 t_stat sim_brk_showall (FILE *st, uint32 sw)
9460 {
9461 int32 bit, mask, types;
9462 BRKTAB **bpt;
9463
9464 if ((sw == 0) || (sw == SWMASK ('C')))
9465 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9466 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9467 if (sim_brk_types & (1 << bit))
9468 ++types;
9469 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9470 (void)fprintf (st, "Supported Breakpoint Types:");
9471 for (bit=0; bit <= ('Z'-'A'); bit++)
9472 if (sim_brk_types & (1 << bit))
9473 (void)fprintf (st, " -%c", 'A' + bit);
9474 (void)fprintf (st, "\r\n");
9475 }
9476 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9477 mask = (sw & sim_brk_types);
9478 (void)fprintf (st, "Displaying Breakpoint Types:");
9479 for (bit=0; bit <= ('Z'-'A'); bit++)
9480 if (mask & (1 << bit))
9481 (void)fprintf (st, " -%c", 'A' + bit);
9482 (void)fprintf (st, "\r\n");
9483 }
9484 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9485 BRKTAB *prev = NULL;
9486 BRKTAB *cur = *bpt;
9487 BRKTAB *next;
9488
9489 while (cur) {
9490 next = cur->next;
9491 cur->next = prev;
9492 prev = cur;
9493 cur = next;
9494 }
9495
9496 *bpt = prev;
9497
9498 cur = prev;
9499 while (cur) {
9500 if (cur->typ & sw)
9501 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9502 cur = cur->next;
9503 }
9504
9505 cur = prev;
9506 prev = NULL;
9507 while (cur) {
9508 next = cur->next;
9509 cur->next = prev;
9510 prev = cur;
9511 cur = next;
9512 }
9513
9514 *bpt = prev;
9515 }
9516 return SCPE_OK;
9517 }
9518
9519
9520
9521 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9522 {
9523 BRKTAB *bp;
9524 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9525
9526 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9527 btyp |= BRK_TYP_DYN_ALL;
9528
9529 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9530 double s_gtime = sim_gtime ();
9531
9532 if (bp->time_fired[spc] == s_gtime)
9533 return 0;
9534 bp->time_fired[spc] = s_gtime;
9535 if (--bp->cnt > 0)
9536 return 0;
9537 bp->cnt = 0;
9538 sim_brk_setact (bp->act);
9539 sim_brk_match_type = btyp & bp->typ;
9540 if (bp->typ & BRK_TYP_TEMP)
9541 sim_brk_clr (loc, bp->typ);
9542 sim_brk_match_addr = loc;
9543 return sim_brk_match_type;
9544 }
9545 return 0;
9546 }
9547
9548
9549
9550 CONST char *sim_brk_getact (char *buf, int32 size)
9551 {
9552 char *ep;
9553 size_t lnt;
9554
9555 if (sim_brk_act[sim_do_depth] == NULL)
9556 return NULL;
9557 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9558 sim_brk_act[sim_do_depth]++;
9559 if (*sim_brk_act[sim_do_depth] == 0) {
9560 return sim_brk_clract ();
9561 }
9562 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9563 lnt = ep - sim_brk_act[sim_do_depth];
9564 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9565 buf[lnt] = 0;
9566 sim_brk_act[sim_do_depth] += lnt + 1;
9567 }
9568 else {
9569 strncpy (buf, sim_brk_act[sim_do_depth], size);
9570 sim_brk_clract ();
9571 }
9572 return buf;
9573 }
9574
9575
9576
9577 char *sim_brk_clract (void)
9578 {
9579 FREE (sim_brk_act_buf[sim_do_depth]);
9580 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9581 }
9582
9583
9584
9585 void sim_brk_setact (const char *action)
9586 {
9587 if (action) {
9588 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9589 if (!sim_brk_act_buf[sim_do_depth])
9590 {
9591 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9592 __func__, __FILE__, __LINE__);
9593 #if defined(USE_BACKTRACE)
9594 # if defined(SIGUSR2)
9595 (void)raise(SIGUSR2);
9596
9597 # endif
9598 #endif
9599 abort();
9600 }
9601 strcpy (sim_brk_act_buf[sim_do_depth], action);
9602 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9603 }
9604 else
9605 sim_brk_clract ();
9606 }
9607
9608
9609
9610 void sim_brk_npc (uint32 cnt)
9611 {
9612 uint32 spc;
9613 BRKTAB **bpt, *bp;
9614
9615 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9616 cnt = SIM_BKPT_N_SPC;
9617 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9618 for (bp = *bpt; bp; bp = bp->next) {
9619 for (spc = 0; spc < cnt; spc++)
9620 bp->time_fired[spc] = -1.0;
9621 }
9622 }
9623 }
9624
9625
9626
9627 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9628 {
9629 BRKTAB **bpt, *bp;
9630
9631 if (spc < SIM_BKPT_N_SPC) {
9632 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9633 for (bp = *bpt; bp; bp = bp->next) {
9634 if (bp->typ & btyp)
9635 bp->time_fired[spc] = -1.0;
9636 }
9637 }
9638 }
9639 }
9640
9641 const char *sim_brk_message(void)
9642 {
9643 static char msg[256];
9644 char addr[65] = "";
9645 char buf[32];
9646
9647 msg[0] = '\0';
9648 if (sim_dflt_dev) {
9649 if (sim_vm_sprint_addr)
9650 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9651 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9652 }
9653 if (sim_brk_type_desc) {
9654 BRKTYPTAB *brk = sim_brk_type_desc;
9655
9656 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9657 if (brk->btyp == sim_brk_match_type) {
9658 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9659 break;
9660 }
9661 brk++;
9662 }
9663 }
9664 if (!msg[0])
9665 (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9666 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9667
9668 return msg;
9669 }
9670
9671
9672
9673
9674
9675
9676
9677
9678
9679
9680
9681
9682
9683
9684
9685
9686
9687
9688
9689
9690
9691
9692
9693
9694
9695
9696
9697
9698
9699
9700
9701
9702
9703
9704
9705
9706
9707 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9708 {
9709 char gbuf[CBUFSIZE];
9710 CONST char *tptr;
9711 CONST char *c1ptr;
9712 t_bool after_set = FALSE;
9713 uint32 after;
9714 int32 cnt = 0;
9715 t_stat r;
9716
9717 if (exp == NULL)
9718 return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9719 after = exp->after;
9720
9721 if ((cptr == NULL) || (*cptr == 0))
9722 return SCPE_2FARG;
9723 if (*cptr == '[') {
9724 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9725 if ((cptr == c1ptr) || (*c1ptr != ']'))
9726 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9727 cptr = c1ptr + 1;
9728 while (sim_isspace(*cptr))
9729 ++cptr;
9730 }
9731 tptr = get_glyph (cptr, gbuf, ',');
9732 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9733 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9734 if (r != SCPE_OK)
9735 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9736 after_set = TRUE;
9737 cptr = tptr;
9738 }
9739 if ((*cptr != '"') && (*cptr != '\''))
9740 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9741 cptr = get_glyph_quoted (cptr, gbuf, 0);
9742
9743 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9744 }
9745
9746
9747
9748 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9749 {
9750 char gbuf[CBUFSIZE];
9751
9752 if (NULL == cptr || !*cptr)
9753 return sim_exp_clrall (exp);
9754 if ((*cptr != '"') && (*cptr != '\''))
9755 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9756 cptr = get_glyph_quoted (cptr, gbuf, 0);
9757 if (*cptr != '\0')
9758 return SCPE_2MARG;
9759 return sim_exp_clr (exp, gbuf);
9760 }
9761
9762
9763
9764 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9765 {
9766 size_t i;
9767
9768 if (NULL == exp->rules)
9769 return NULL;
9770 for (i=start_rule; i<exp->size; i++)
9771 if (!strcmp (exp->rules[i].match_pattern, match))
9772 return &exp->rules[i];
9773 return NULL;
9774 }
9775
9776
9777
9778 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9779 {
9780 size_t i;
9781
9782 if (NULL == ep)
9783 return SCPE_OK;
9784 FREE (ep->match);
9785 FREE (ep->match_pattern);
9786 FREE (ep->act);
9787 exp->size -= 1;
9788 #if !defined(__clang_analyzer__)
9789 for (i=ep-exp->rules; i<exp->size; i++)
9790 exp->rules[i] = exp->rules[i+1];
9791 if (exp->size == 0) {
9792 FREE (exp->rules);
9793 exp->rules = NULL;
9794 }
9795 #endif
9796 return SCPE_OK;
9797 }
9798
9799 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9800 {
9801 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9802
9803 while (ep) {
9804 sim_exp_clr_tab (exp, ep);
9805 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9806 }
9807 return SCPE_OK;
9808 }
9809
9810
9811
9812 t_stat sim_exp_clrall (EXPECT *exp)
9813 {
9814 int32 i;
9815
9816 for (i=0; i<exp->size; i++) {
9817 FREE (exp->rules[i].match);
9818 FREE (exp->rules[i].match_pattern);
9819 FREE (exp->rules[i].act);
9820 }
9821 FREE (exp->rules);
9822 exp->rules = NULL;
9823 exp->size = 0;
9824 FREE (exp->buf);
9825 exp->buf = NULL;
9826 exp->buf_size = 0;
9827 exp->buf_ins = 0;
9828 return SCPE_OK;
9829 }
9830
9831
9832
9833 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9834 {
9835 EXPTAB *ep;
9836 uint8 *match_buf;
9837 uint32 match_size;
9838 size_t i;
9839
9840
9841 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9842 if (!match_buf)
9843 return SCPE_MEM;
9844 if (switches & EXP_TYP_REGEX) {
9845 FREE (match_buf);
9846 return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9847 }
9848 else {
9849 if (switches & EXP_TYP_REGEX_I) {
9850 FREE (match_buf);
9851 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9852 }
9853 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9854 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9855 FREE (match_buf);
9856 return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9857 }
9858 }
9859 FREE (match_buf);
9860 for (i=0; i<exp->size; i++) {
9861 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9862 (exp->rules[i].switches & EXP_TYP_PERSIST))
9863 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9864 }
9865 if (after && exp->size)
9866 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9867 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9868 if (!exp->rules)
9869 {
9870 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9871 __func__, __FILE__, __LINE__);
9872 #if defined(USE_BACKTRACE)
9873 # if defined(SIGUSR2)
9874 (void)raise(SIGUSR2);
9875
9876 # endif
9877 #endif
9878 abort();
9879 }
9880 ep = &exp->rules[exp->size];
9881 exp->size += 1;
9882 exp->after = after;
9883 (void)memset (ep, 0, sizeof(*ep));
9884 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9885 if (ep->match_pattern)
9886 strcpy (ep->match_pattern, match);
9887 ep->cnt = cnt;
9888 ep->switches = switches;
9889 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9890 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9891 sim_exp_clr_tab (exp, ep);
9892 FREE (match_buf);
9893 return SCPE_MEM;
9894 }
9895 if (switches & EXP_TYP_REGEX) {
9896 FREE (match_buf);
9897 match_buf = NULL;
9898 }
9899 else {
9900 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9901 sim_decode_quoted_string (match, match_buf, &match_size);
9902 ep->match = match_buf;
9903 ep->size = match_size;
9904 }
9905 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9906 if (!ep->match_pattern)
9907 {
9908 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9909 __func__, __FILE__, __LINE__);
9910 #if defined(USE_BACKTRACE)
9911 # if defined(SIGUSR2)
9912 (void)raise(SIGUSR2);
9913
9914 # endif
9915 #endif
9916 abort();
9917 }
9918 strcpy (ep->match_pattern, match);
9919 if (ep->act) {
9920 FREE (ep->act);
9921 ep->act = NULL;
9922 }
9923 if (act) while (sim_isspace(*act)) ++act;
9924 if ((act != NULL) && (*act != 0)) {
9925 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9926 if (newp == NULL)
9927 return SCPE_MEM;
9928 strcpy (newp, act);
9929 ep->act = newp;
9930 }
9931
9932 for (i=0; i<exp->size; i++) {
9933 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9934 if (compare_size >= exp->buf_size) {
9935 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
9936 exp->buf_size = compare_size + 1;
9937 }
9938 }
9939 return SCPE_OK;
9940 }
9941
9942
9943
9944 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
9945 {
9946 if (!ep)
9947 return SCPE_OK;
9948 (void)fprintf (st, "EXPECT");
9949 if (ep->switches & EXP_TYP_PERSIST)
9950 (void)fprintf (st, " -p");
9951 if (ep->switches & EXP_TYP_CLEARALL)
9952 (void)fprintf (st, " -c");
9953 if (ep->switches & EXP_TYP_REGEX)
9954 (void)fprintf (st, " -r");
9955 if (ep->switches & EXP_TYP_REGEX_I)
9956 (void)fprintf (st, " -i");
9957 (void)fprintf (st, " %s", ep->match_pattern);
9958 if (ep->cnt > 0)
9959 (void)fprintf (st, " [%d]", ep->cnt);
9960 if (ep->act)
9961 (void)fprintf (st, " %s", ep->act);
9962 (void)fprintf (st, "\r\n");
9963 return SCPE_OK;
9964 }
9965
9966 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
9967 {
9968 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9969
9970 if (exp->buf_size) {
9971 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9972
9973 (void)fprintf (st, "Match Buffer Size: %lld\r\n",
9974 (long long)exp->buf_size);
9975 (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
9976 (long long)exp->buf_ins);
9977 (void)fprintf (st, "Buffer Contents: %s\r\n",
9978 bstr);
9979 FREE (bstr);
9980 }
9981 if (exp->after)
9982 (void)fprintf (st, "Halt After: %lld instructions\r\n",
9983 (long long)exp->after);
9984 if (exp->dptr && exp->dbit)
9985 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
9986 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
9987 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9988 (void)fprintf (st, "Match Rules:\r\n");
9989 if (!*match)
9990 return sim_exp_showall (st, exp);
9991 if (!ep) {
9992 (void)fprintf (st, "No Rules match '%s'\r\n", match);
9993 return SCPE_ARG;
9994 }
9995 do {
9996 sim_exp_show_tab (st, exp, ep);
9997 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9998 } while (ep);
9999 return SCPE_OK;
10000 }
10001
10002
10003
10004 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
10005 {
10006 size_t i;
10007
10008 for (i=0; i < exp->size; i++)
10009 sim_exp_show_tab (st, exp, &exp->rules[i]);
10010 return SCPE_OK;
10011 }
10012
10013
10014
10015 t_stat sim_exp_check (EXPECT *exp, uint8 data)
10016 {
10017 size_t i;
10018 EXPTAB *ep = NULL;
10019 char *tstr = NULL;
10020 #if defined(TESTING)
10021 cpu_state_t * cpup = _cpup;
10022 #endif
10023
10024 if ((!exp) || (!exp->rules))
10025 return SCPE_OK;
10026
10027 exp->buf[exp->buf_ins++] = data;
10028 exp->buf[exp->buf_ins] = '\0';
10029
10030 for (i=0; i < exp->size; i++) {
10031 ep = &exp->rules[i];
10032 if (ep == NULL)
10033 break;
10034 if (ep->switches & EXP_TYP_REGEX) {
10035 }
10036 else {
10037 if (exp->buf_ins < ep->size) {
10038
10039
10040
10041
10042 if (exp->buf_ins > 0) {
10043 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10044 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10045 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10046
10047 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10048 (long long)exp->buf_ins, estr);
10049 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10050 FREE (estr);
10051 FREE (mstr);
10052 }
10053 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10054 continue;
10055 }
10056 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10057 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10058 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10059
10060 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10061 (long long)exp->buf_size-(ep->size-exp->buf_ins),
10062 (long long)ep->size-exp->buf_ins, estr);
10063 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10064 FREE (estr);
10065 FREE (mstr);
10066 }
10067 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10068 continue;
10069 break;
10070 }
10071 else {
10072 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10073 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10074 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10075
10076 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10077 (long long)exp->buf_ins-ep->size,
10078 (long long)ep->size, estr);
10079 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10080 FREE (estr);
10081 FREE (mstr);
10082 }
10083 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10084 continue;
10085 break;
10086 }
10087 }
10088 }
10089 if (exp->buf_ins == exp->buf_size) {
10090 exp->buf_ins = 0;
10091 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10092 }
10093 if ((ep != NULL) && (i != exp->size)) {
10094 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10095 if (ep->cnt > 0) {
10096 ep->cnt -= 1;
10097 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10098 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10099 }
10100 else {
10101 uint32 after = exp->after;
10102 int32 switches = ep->switches;
10103 if (ep->act && *ep->act) {
10104 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10105 }
10106 else {
10107 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10108 }
10109 sim_brk_setact (ep->act);
10110 if (ep->switches & EXP_TYP_CLEARALL)
10111 sim_exp_clrall (exp);
10112 else {
10113 if (!(ep->switches & EXP_TYP_PERSIST))
10114 sim_exp_clr_tab (exp, ep);
10115 }
10116 sim_activate (&sim_expect_unit,
10117 (switches & EXP_TYP_TIME) ?
10118 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10119 after);
10120 }
10121
10122 exp->buf_ins = 0;
10123 }
10124 if (tstr)
10125 FREE (tstr);
10126 return SCPE_OK;
10127 }
10128
10129
10130
10131 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10132 {
10133 if (snd->extoff != 0) {
10134 if (snd->insoff > snd->extoff)
10135 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10136 snd->insoff -= snd->extoff;
10137 snd->extoff = 0;
10138 }
10139 if (snd->insoff+size > snd->bufsize) {
10140 snd->bufsize = snd->insoff+size;
10141 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10142 if (!snd->buffer)
10143 {
10144 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10145 __func__, __FILE__, __LINE__);
10146 #if defined(USE_BACKTRACE)
10147 # if defined(SIGUSR2)
10148 (void)raise(SIGUSR2);
10149
10150 # endif
10151 #endif
10152 abort();
10153 }
10154 }
10155 memcpy(snd->buffer+snd->insoff, data, size);
10156 snd->insoff += size;
10157 if (delay)
10158 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10159 if (after)
10160 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10161 if (snd->after == 0)
10162 snd->after = snd->delay;
10163 snd->next_time = sim_gtime() + snd->after;
10164 return SCPE_OK;
10165 }
10166
10167
10168 t_stat sim_send_clear (SEND *snd)
10169 {
10170 snd->insoff = 0;
10171 snd->extoff = 0;
10172 return SCPE_OK;
10173 }
10174
10175
10176
10177 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10178 {
10179 if (snd->extoff < snd->insoff) {
10180 (void)fprintf (st, "%lld bytes of pending input Data:\r\n ",
10181 (long long)snd->insoff-snd->extoff);
10182 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10183 (void)fprintf (st, "\r\n");
10184 }
10185 else
10186 (void)fprintf (st, "No Pending Input Data\r\n");
10187 if ((snd->next_time - sim_gtime()) > 0) {
10188 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10189 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10190 (int)(snd->next_time - sim_gtime()),
10191 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10192 else
10193 (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10194 (int)(snd->next_time - sim_gtime()));
10195 }
10196 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10197 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10198 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10199 else
10200 (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10201 (int)snd->delay);
10202 if (snd->dptr && snd->dbit)
10203 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10204 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10205 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10206 return SCPE_OK;
10207 }
10208
10209
10210
10211 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10212 {
10213 #if defined(TESTING)
10214 cpu_state_t * cpup = _cpup;
10215 #endif
10216 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10217 if (sim_gtime() < snd->next_time) {
10218 *stat = SCPE_OK;
10219 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10220 }
10221 else {
10222 char dstr[8] = "";
10223 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10224 snd->next_time = sim_gtime() + snd->delay;
10225 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10226 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10227 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10228 }
10229 return TRUE;
10230 }
10231 return FALSE;
10232 }
10233
10234
10235
10236 const char *sim_error_text (t_stat stat)
10237 {
10238 static char msgbuf[64];
10239
10240 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10241 if (stat == SCPE_OK)
10242 return "No Error";
10243 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10244 return scp_errors[stat-SCPE_BASE].message;
10245 (void)sprintf(msgbuf, "Error %d", stat);
10246 return msgbuf;
10247 }
10248
10249 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10250 {
10251 char gbuf[CBUFSIZE];
10252 size_t cond;
10253
10254 *stat = SCPE_ARG;
10255 cptr = get_glyph (cptr, gbuf, 0);
10256 if (0 == memcmp("SCPE_", gbuf, 5))
10257 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10258 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10259 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10260 cond += SCPE_BASE;
10261 break;
10262 }
10263 if (0 == strcmp(gbuf, "OK"))
10264 cond = SCPE_OK;
10265 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10266 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10267 if (0 == numeric_cond)
10268 return SCPE_ARG;
10269 cond = (t_stat) numeric_cond;
10270 }
10271 if (cond > SCPE_MAX_ERR)
10272 return SCPE_ARG;
10273 *stat = cond;
10274 return SCPE_OK;
10275 }
10276
10277
10278
10279 const char* debug_bstates = "01_^";
10280 char debug_line_prefix[256];
10281 int32 debug_unterm = 0;
10282
10283
10284
10285 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10286 {
10287 static const char *debtab_none = "DEBTAB_ISNULL";
10288 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10289 const char *some_match = NULL;
10290 int32 offset = 0;
10291
10292 if (dptr->debflags == 0)
10293 return debtab_none;
10294
10295 dbits &= dptr->dctrl;
10296
10297
10298
10299 while ((offset < 32) && dptr->debflags[offset].name) {
10300 if (dptr->debflags[offset].mask == dbits)
10301 return dptr->debflags[offset].name;
10302 if (dptr->debflags[offset].mask & dbits)
10303 some_match = dptr->debflags[offset].name;
10304 offset++;
10305 }
10306 return some_match ? some_match : debtab_nomatch;
10307 }
10308
10309
10310
10311 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10312 {
10313 const char* debug_type = get_dbg_verb (dbits, dptr);
10314 char tim_t[32] = "";
10315 char tim_a[32] = "";
10316 char pc_s[64] = "";
10317 struct timespec time_now;
10318
10319 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10320 clock_gettime(CLOCK_REALTIME, &time_now);
10321 if (sim_deb_switches & SWMASK ('R'))
10322 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10323 if (sim_deb_switches & SWMASK ('T')) {
10324 time_t tnow = (time_t)time_now.tv_sec;
10325 struct tm *now = gmtime(&tnow);
10326 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10327 (int)now->tm_hour,
10328 (int)now->tm_min,
10329 (int)now->tm_sec,
10330 (long)(time_now.tv_nsec / 1000000));
10331 }
10332 if (sim_deb_switches & SWMASK ('A')) {
10333 (void)sprintf(tim_t, "%d.%03ld ",
10334 (int)(time_now.tv_sec),
10335 (long)(time_now.tv_nsec / 1000000));
10336 }
10337 }
10338 if (sim_deb_switches & SWMASK ('P')) {
10339 t_value val;
10340
10341 if (sim_vm_pc_value)
10342 val = (*sim_vm_pc_value)();
10343 else
10344 val = get_rval (sim_PC, 0);
10345 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10346 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10347 }
10348 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10349 tim_t, tim_a, sim_gtime(), pc_s,
10350 "", dptr->name, debug_type);
10351 return debug_line_prefix;
10352 }
10353
10354 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10355 {
10356 int32 i, fields, offset;
10357 uint32 value, beforevalue, mask;
10358
10359 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10360 if (bitdefs[fields].offset == 0xffffffff)
10361 bitdefs[fields].offset = offset;
10362 offset += bitdefs[fields].width;
10363 }
10364 for (i = fields-1; i >= 0; i--) {
10365 if (bitdefs[i].name[0] == '\0')
10366 continue;
10367 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10368 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10369 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10370 }
10371 else {
10372 const char *delta = "";
10373 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10374 value = (uint32)((after >> bitdefs[i].offset) & mask);
10375 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10376 if (value < beforevalue)
10377 delta = "_";
10378 if (value > beforevalue)
10379 delta = "^";
10380 if (bitdefs[i].valuenames)
10381 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10382 else
10383 if (bitdefs[i].format) {
10384 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10385 (void)Fprintf(stream, bitdefs[i].format, value);
10386 (void)Fprintf(stream, " ");
10387 }
10388 else
10389 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10390 }
10391 }
10392 }
10393
10394
10395
10396
10397
10398 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10399 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10400 {
10401 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10402 if (!debug_unterm)
10403 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10404 if (header)
10405 (void)fprintf(sim_deb, "%s: ", header);
10406 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10407 if (terminate)
10408 (void)fprintf(sim_deb, "\r\n");
10409 debug_unterm = terminate ? 0 : 1;
10410 }
10411 }
10412 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10413 uint32 before, uint32 after, int terminate)
10414 {
10415 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10416 }
10417
10418
10419 void sim_printf (const char* fmt, ...)
10420 {
10421 char stackbuf[STACKBUFSIZE];
10422 int32 bufsize = sizeof(stackbuf);
10423 char *buf = stackbuf;
10424 int32 len;
10425 va_list arglist;
10426
10427 while (1) {
10428 va_start (arglist, fmt);
10429 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10430 va_end (arglist);
10431
10432
10433
10434 if ((len < 0) || (len >= bufsize-1)) {
10435 if (buf != stackbuf)
10436 FREE (buf);
10437 if (bufsize >= (INT_MAX / 2))
10438 return;
10439 bufsize = bufsize * 2;
10440 if (bufsize < len + 2)
10441 bufsize = len + 2;
10442 buf = (char *) malloc (bufsize);
10443 if (buf == NULL)
10444 return;
10445 buf[bufsize-1] = '\0';
10446 continue;
10447 }
10448 break;
10449 }
10450
10451 if (sim_is_running) {
10452 char *c, *remnant = buf;
10453 while ((c = strchr(remnant, '\n'))) {
10454 if ((c != buf) && (*(c - 1) != '\r'))
10455 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10456 else
10457 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10458 remnant = c + 1;
10459 }
10460 (void)printf("%s", remnant);
10461 }
10462 else
10463 (void)printf("%s", buf);
10464 if (sim_log && (sim_log != stdout))
10465 (void)fprintf (sim_log, "%s", buf);
10466 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10467 (void)fprintf (sim_deb, "%s", buf);
10468
10469 if (buf != stackbuf)
10470 FREE (buf);
10471 }
10472
10473
10474 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10475 {
10476 char stackbuf[STACKBUFSIZE];
10477 size_t bufsize = sizeof(stackbuf);
10478 char *buf = stackbuf;
10479 size_t len;
10480 va_list arglist;
10481 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10482
10483 while (1) {
10484 va_start (arglist, fmt);
10485 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10486 va_end (arglist);
10487
10488
10489
10490 if (len >= bufsize - 1) {
10491 if (buf != stackbuf)
10492 FREE (buf);
10493 bufsize = bufsize * 2;
10494 if (bufsize < len + 2)
10495 bufsize = len + 2;
10496 buf = (char *) malloc (bufsize);
10497 if (buf == NULL)
10498 return SCPE_MEM;
10499 buf[bufsize-1] = '\0';
10500 continue;
10501 }
10502 break;
10503 }
10504
10505 if (sim_do_ocptr[sim_do_depth]) {
10506 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10507 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10508 else {
10509 if (sim_deb)
10510 (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10511 }
10512 }
10513 if (sim_is_running && !inhibit_message) {
10514 char *c, *remnant = buf;
10515 while ((c = strchr(remnant, '\n'))) {
10516 if ((c != buf) && (*(c - 1) != '\r'))
10517 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10518 else
10519 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10520 remnant = c + 1;
10521 }
10522 (void)printf("%s", remnant);
10523 }
10524 else {
10525 if (!inhibit_message)
10526 (void)printf("%s", buf);
10527 }
10528 if (sim_log && (sim_log != stdout) && !inhibit_message)
10529 (void)fprintf (sim_log, "%s", buf);
10530 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10531 (void)fprintf (sim_deb, "%s", buf);
10532
10533 if (buf != stackbuf)
10534 FREE (buf);
10535 return stat | SCPE_NOMESSAGE;
10536 }
10537
10538
10539
10540
10541
10542
10543
10544
10545
10546 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10547 {
10548 DEVICE *dptr = (DEVICE *)vdptr;
10549 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10550 char stackbuf[STACKBUFSIZE];
10551 int32 bufsize = sizeof(stackbuf);
10552 char *buf = stackbuf;
10553 va_list arglist;
10554 int32 i, j, len;
10555 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10556
10557 buf[bufsize-1] = '\0';
10558 while (1) {
10559 va_start (arglist, fmt);
10560 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10561 va_end (arglist);
10562
10563
10564
10565 if ((len < 0) || (len >= bufsize-1)) {
10566 if (buf != stackbuf)
10567 FREE (buf);
10568 if (bufsize >= (INT_MAX / 2))
10569 return;
10570 bufsize = bufsize * 2;
10571 if (bufsize < len + 2)
10572 bufsize = len + 2;
10573 buf = (char *) malloc (bufsize);
10574 if (buf == NULL)
10575 return;
10576 buf[bufsize-1] = '\0';
10577 continue;
10578 }
10579 break;
10580 }
10581
10582
10583
10584 for (i = j = 0; i < len; ++i) {
10585 if ('\n' == buf[i]) {
10586 if (i >= j) {
10587 if ((i != j) || (i == 0)) {
10588 if (debug_unterm)
10589 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10590 else
10591 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10592 }
10593 debug_unterm = 0;
10594 }
10595 j = i + 1;
10596 }
10597 }
10598 if (i > j) {
10599 if (debug_unterm)
10600 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10601 else
10602 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10603 }
10604
10605
10606
10607 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10608 if (buf != stackbuf)
10609 FREE (buf);
10610 }
10611 return;
10612 }
10613
10614 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10615 {
10616 #if defined(TESTING)
10617 cpu_state_t * cpup = _cpup;
10618 #endif
10619 if (sim_deb && (dptr->dctrl & reason)) {
10620 sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10621 if (data && len) {
10622 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10623 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10624 static char hex[] = "0123456789ABCDEF";
10625 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10626 static unsigned char ebcdic2ascii[] = {
10627 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10628 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10629 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10630 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10631 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10632 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10633 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10634 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10635 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10636 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10637 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10638 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10639 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10640 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10641 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10642 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10643 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10644 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10645 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10646 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10647 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10648 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10649 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10650 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10651 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10652 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10653 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10654 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10655 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10656 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10657 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10658 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10659 };
10660
10661 for (i=same=0; i<len; i += 16) {
10662 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10663 ++same;
10664 continue;
10665 }
10666 if (same > 0) {
10667 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10668 (unsigned long int)(i - (16*same)),
10669 (unsigned long int)(i - 1));
10670 same = 0;
10671 }
10672 group = (((len - i) > 16) ? 16 : (len - i));
10673 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10674 eidx = strlen(ebcdicbuf);
10675 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10676 ridx = strlen(rad50buf);
10677 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10678 soff = strlen(strbuf);
10679 for (sidx=oidx=0; sidx<group; ++sidx) {
10680 outbuf[oidx++] = ' ';
10681 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10682 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10683 if (sim_isprint (data[i+sidx]))
10684 strbuf[soff+sidx] = data[i+sidx];
10685 else
10686 strbuf[soff+sidx] = '.';
10687 if (ridx && ((sidx&1) == 0)) {
10688 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10689
10690 if (word >= 64000) {
10691 rad50buf[ridx++] = '|';
10692 rad50buf[ridx++] = '|';
10693 rad50buf[ridx++] = '|';
10694 }
10695 else {
10696 rad50buf[ridx++] = rad50[word/1600];
10697 rad50buf[ridx++] = rad50[(word/40)%40];
10698 rad50buf[ridx++] = rad50[word%40];
10699 }
10700 }
10701 if (eidx) {
10702 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10703 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10704 else
10705 ebcdicbuf[eidx++] = '.';
10706 }
10707 }
10708 outbuf[oidx] = '\0';
10709 strbuf[soff+sidx] = '\0';
10710 ebcdicbuf[eidx] = '\0';
10711 rad50buf[ridx] = '\0';
10712 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10713 (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10714 }
10715 if (same > 0) {
10716 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10717 (unsigned long int)(i-(16*same)),
10718 (unsigned long int)(len-1));
10719 }
10720 }
10721 }
10722 }
10723
10724 int Fprintf (FILE *f, const char* fmt, ...)
10725 {
10726 int ret = 0;
10727 va_list args;
10728
10729 va_start (args, fmt);
10730 ret = vfprintf (f, fmt, args);
10731 va_end (args);
10732 return ret;
10733 }
10734
10735
10736
10737
10738
10739
10740
10741
10742
10743
10744
10745
10746
10747
10748
10749
10750
10751
10752
10753 #define blankch(x) ((x) == ' ' || (x) == '\t')
10754
10755 typedef struct topic {
10756 size_t level;
10757 char *title;
10758 char *label;
10759 struct topic *parent;
10760 struct topic **children;
10761 uint32 kids;
10762 char *text;
10763 size_t len;
10764 uint32 flags;
10765 size_t kidwid;
10766 #define HLP_MAGIC_TOPIC 1
10767 } TOPIC;
10768
10769 static volatile struct {
10770 const char *error;
10771 const char *prox;
10772 size_t block;
10773 size_t line;
10774 } help_where = { "", NULL, 0, 0 };
10775 jmp_buf help_env;
10776
10777 #define FAIL(why,text,here) \
10778 { \
10779 help_where.error = #text; \
10780 help_where.prox = here; \
10781 longjmp ( help_env, (why) ); \
10782 \
10783 }
10784
10785
10786
10787
10788
10789
10790 static void appendText (TOPIC *topic, const char *text, size_t len)
10791 {
10792 char *newt;
10793
10794 if (!len)
10795 return;
10796
10797 newt = (char *)realloc (topic->text, topic->len + len +1);
10798 if (!newt) {
10799 #if !defined(SUNLINT)
10800 FAIL (SCPE_MEM, No memory, NULL);
10801 #endif
10802 }
10803 topic->text = newt;
10804 memcpy (newt + topic->len, text, len);
10805 topic->len +=len;
10806 newt[topic->len] = '\0';
10807 return;
10808 }
10809
10810
10811
10812 static void cleanHelp (TOPIC *topic)
10813 {
10814 TOPIC *child;
10815 size_t i;
10816
10817 FREE (topic->title);
10818 FREE (topic->text);
10819 FREE (topic->label);
10820 for (i = 0; i < topic->kids; i++) {
10821 child = topic->children[i];
10822 cleanHelp (child);
10823 FREE (child);
10824 }
10825 FREE (topic->children);
10826 return;
10827 }
10828
10829
10830
10831
10832 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10833 UNIT *uptr, const char *htext, va_list ap)
10834 {
10835 char *end;
10836 size_t n, ilvl;
10837 #define VSMAX 100
10838 char *vstrings[VSMAX];
10839 size_t vsnum = 0;
10840 char * astrings[VSMAX+1];
10841 size_t asnum = 0;
10842 char *const *hblock;
10843 const char *ep;
10844 t_bool excluded = FALSE;
10845
10846
10847
10848
10849
10850
10851
10852 (void)memset (vstrings, 0, sizeof (vstrings));
10853 (void)memset (astrings, 0, sizeof (astrings));
10854 astrings[asnum++] = (char *) htext;
10855
10856 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10857 help_where.block = hblock - astrings;
10858 help_where.line = 0;
10859 while (*htext) {
10860 const char *start;
10861
10862 help_where.line++;
10863 if (sim_isspace (*htext) || *htext == '+') {
10864 if (excluded) {
10865 while (*htext && *htext != '\n')
10866 htext++;
10867 if (*htext)
10868 ++htext;
10869 continue;
10870 }
10871 ilvl = 1;
10872 appendText (topic, " ", 4);
10873 if (*htext == '+') {
10874 while (*htext == '+') {
10875 ilvl++;
10876 appendText (topic, " ", 4);
10877 htext++;
10878 }
10879 }
10880 while (*htext && *htext != '\n' && sim_isspace (*htext))
10881 htext++;
10882 if (!*htext)
10883 break;
10884 start = htext;
10885 while (*htext) {
10886 if (*htext == '%') {
10887 appendText (topic, start, htext - start);
10888 switch (*++htext) {
10889 case 'U':
10890 if (dptr) {
10891 char buf[129];
10892 n = uptr? uptr - dptr->units: 0;
10893 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10894 appendText (topic, buf, strlen (buf));
10895 }
10896 break;
10897 case 'D':
10898 if (dptr != NULL)
10899 appendText (topic, dptr->name, strlen (dptr->name));
10900 break;
10901 case 'S':
10902 appendText (topic, sim_name, strlen (sim_name));
10903 break;
10904 case '%':
10905 appendText (topic, "%", 1);
10906 break;
10907 case '+':
10908 appendText (topic, "+", 1);
10909 break;
10910 default:
10911 if (sim_isdigit (*htext)) {
10912 n = 0;
10913 while (sim_isdigit (*htext))
10914 n += (n * 10) + (*htext++ - '0');
10915 if (( *htext != 'H' && *htext != 's') ||
10916 n == 0 || n >= VSMAX) {
10917 #if !defined(SUNLINT)
10918 FAIL (SCPE_ARG, Invalid escape, htext);
10919 #endif
10920 }
10921 while (n > vsnum)
10922 vstrings[vsnum++] = va_arg (ap, char *);
10923 start = vstrings[n-1];
10924 if (*htext == 'H') {
10925 if (asnum >= VSMAX) {
10926 #if !defined(SUNLINT)
10927 FAIL (SCPE_ARG, Too many blocks, htext);
10928 #endif
10929 }
10930 astrings[asnum++] = (char *)start;
10931 break;
10932 }
10933 ep = start;
10934 while (*ep) {
10935 if (*ep == '\n') {
10936 ep++;
10937 appendText (topic, start, ep - start);
10938 if (*ep) {
10939 size_t i;
10940 for (i = 0; i < ilvl; i++)
10941 appendText (topic, " ", 4);
10942 }
10943 start = ep;
10944 }
10945 else
10946 ep++;
10947 }
10948 appendText (topic, start, ep-start);
10949 break;
10950 }
10951 #if !defined(SUNLINT)
10952 FAIL (SCPE_ARG, Invalid escape, htext);
10953 #endif
10954 }
10955 start = ++htext;
10956 continue;
10957 }
10958 if (*htext == '\n') {
10959 htext++;
10960 appendText (topic, start, htext - start);
10961 break;
10962 }
10963 htext++;
10964 }
10965 continue;
10966 }
10967 if (sim_isdigit (*htext)) {
10968 TOPIC **children;
10969 TOPIC *newt;
10970 char nbuf[100];
10971
10972 n = 0;
10973 start = htext;
10974 while (sim_isdigit (*htext))
10975 n += (n * 10) + (*htext++ - '0');
10976 if ((htext == start) || !n) {
10977 #if !defined(SUNLINT)
10978 FAIL (SCPE_ARG, Invalid topic heading, htext);
10979 #endif
10980 }
10981 if (n <= topic->level) {
10982 while (n <= topic->level)
10983 topic = topic->parent;
10984 }
10985 else {
10986 if (n > topic->level + 1) {
10987 #if !defined(SUNLINT)
10988 FAIL (SCPE_ARG, Level not contiguous, htext);
10989 #endif
10990 }
10991 }
10992 while (*htext && (*htext != '\n') && sim_isspace (*htext))
10993 htext++;
10994 if (!*htext || (*htext == '\n')) {
10995 #if !defined(SUNLINT)
10996 FAIL (SCPE_ARG, Missing topic name, htext);
10997 #endif
10998 }
10999 start = htext;
11000 while (*htext && (*htext != '\n'))
11001 htext++;
11002 if (start == htext) {
11003 #if !defined(SUNLINT)
11004 FAIL (SCPE_ARG, Null topic name, htext);
11005 #endif
11006 }
11007 excluded = FALSE;
11008 if (*start == '?') {
11009 size_t n = 0;
11010 start++;
11011 while (sim_isdigit (*start))
11012 n += (n * 10) + (*start++ - '0');
11013 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11014 #if !defined(SUNLINT)
11015 FAIL (SCPE_ARG, Invalid parameter number, start);
11016 #endif
11017 }
11018 while (n > vsnum)
11019 vstrings[vsnum++] = va_arg (ap, char *);
11020 end = vstrings[n-1];
11021 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11022 excluded = TRUE;
11023 if (*htext)
11024 htext++;
11025 continue;
11026 }
11027 }
11028 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11029 if (!newt) {
11030 #if !defined(SUNLINT)
11031 FAIL (SCPE_MEM, No memory, NULL);
11032 #endif
11033 }
11034 size_t len = (htext > start) ? (htext - start) : 0;
11035 newt->title = (char *) malloc(len + 1);
11036 if (!newt->title) {
11037 FREE (newt);
11038 #if !defined(SUNLINT)
11039 FAIL (SCPE_MEM, No memory, NULL);
11040 #endif
11041 }
11042 memcpy (newt->title, start, htext - start);
11043 newt->title[htext - start] = '\0';
11044 if (*htext)
11045 htext++;
11046
11047 if (newt->title[0] == '$')
11048 newt->flags |= HLP_MAGIC_TOPIC;
11049
11050 children = (TOPIC **) realloc (topic->children,
11051 (topic->kids +1) * sizeof (TOPIC *));
11052 if (NULL == children) {
11053 FREE (newt->title);
11054 FREE (newt);
11055 #if !defined(SUNLINT)
11056 FAIL (SCPE_MEM, No memory, NULL);
11057 #endif
11058 }
11059 topic->children = children;
11060 topic->children[topic->kids++] = newt;
11061 newt->level = n;
11062 newt->parent = topic;
11063 n = strlen (newt->title);
11064 if (n > topic->kidwid)
11065 topic->kidwid = n;
11066 (void)sprintf (nbuf, ".%u", topic->kids);
11067 n = strlen (topic->label) + strlen (nbuf) + 1;
11068 newt->label = (char *) malloc (n);
11069 if (NULL == newt->label) {
11070 FREE (newt->title);
11071 topic->children[topic->kids -1] = NULL;
11072 FREE (newt);
11073 #if !defined(SUNLINT)
11074 FAIL (SCPE_MEM, No memory, NULL);
11075 #endif
11076 }
11077 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11078 topic = newt;
11079 continue;
11080 }
11081 if (*htext == ';') {
11082 while (*htext && *htext != '\n')
11083 htext++;
11084 continue;
11085 }
11086 #if !defined(SUNLINT)
11087 FAIL (SCPE_ARG, Unknown line type, htext);
11088 #endif
11089 }
11090 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11091 vsnum = 0;
11092 }
11093
11094 return topic;
11095 }
11096
11097
11098
11099
11100
11101 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
11102 {
11103 char *prefix;
11104 char *newp, *newt;
11105
11106 if (topic->level == 0) {
11107 prefix = (char *) calloc (2,1);
11108 if (!prefix) {
11109 #if !defined(SUNLINT)
11110 FAIL (SCPE_MEM, No memory, NULL);
11111 #endif
11112 }
11113 prefix[0] = '\n';
11114 }
11115 else
11116 prefix = helpPrompt (topic->parent, "", oneword);
11117
11118 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11119 strlen (pstring) +1);
11120 if (!newp) {
11121 FREE (prefix);
11122 #if !defined(SUNLINT)
11123 FAIL (SCPE_MEM, No memory, NULL);
11124 #endif
11125 }
11126 strcpy (newp, prefix);
11127 if (topic->children) {
11128 if (topic->level != 0)
11129 strcat (newp, " ");
11130 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11131 topic->title+1: topic->title;
11132 if (oneword) {
11133 char *np = newp + strlen (newp);
11134 while (*newt) {
11135 *np++ = blankch (*newt)? '_' : *newt;
11136 newt++;
11137 }
11138 *np = '\0';
11139 }
11140 else
11141 strcat (newp, newt);
11142 if (*pstring && *pstring != '?')
11143 strcat (newp, " ");
11144 }
11145 strcat (newp, pstring);
11146 FREE (prefix);
11147 return newp;
11148 }
11149
11150 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11151 {
11152 char tbuf[CBUFSIZE];
11153 size_t i, skiplines;
11154 #if defined(_WIN32)
11155 FILE *tmp;
11156 char *tmpnam;
11157
11158 do {
11159 int fd;
11160 tmpnam = _tempnam (NULL, "simh");
11161 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11162 if (fd != -1) {
11163 tmp = _fdopen (fd, "w+");
11164 break;
11165 }
11166 } while (1);
11167 #else
11168 FILE *tmp = tmpfile();
11169 #endif
11170
11171 if (!tmp) {
11172 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11173 xstrerror_l(errno), errno);
11174 return;
11175 }
11176
11177 if (topic->title)
11178 (void)fprintf (st, "%s\r\n", topic->title+1);
11179
11180 skiplines = 0;
11181 if (topic->title) {
11182 if (!strcmp (topic->title+1, "Registers")) {
11183 fprint_reg_help (tmp, dptr) ;
11184 skiplines = 1;
11185 }
11186 else
11187 if (!strcmp (topic->title+1, "Set commands")) {
11188 fprint_set_help (tmp, dptr);
11189 skiplines = 3;
11190 }
11191 else
11192 if (!strcmp (topic->title+1, "Show commands")) {
11193 fprint_show_help (tmp, dptr);
11194 skiplines = 3;
11195 }
11196 }
11197 rewind (tmp);
11198 if (errno) {
11199 (void)fprintf (st, "rewind: error %d\r\n", errno);
11200 }
11201
11202
11203
11204 for (i =0; i < skiplines; i++)
11205 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11206
11207 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11208 if (tbuf[0] != '\n')
11209 fputs (" ", st);
11210 fputs (tbuf, st);
11211 }
11212 fclose (tmp);
11213 #if defined(_WIN32)
11214 remove (tmpnam);
11215 FREE (tmpnam);
11216 #endif
11217 return;
11218 }
11219
11220
11221 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11222 UNIT *uptr, int32 flag,
11223 TOPIC *topic, va_list ap )
11224 {
11225 size_t i;
11226
11227 if (topic->flags & HLP_MAGIC_TOPIC) {
11228 (void)fprintf (st, "\r\n%s ", topic->label);
11229 displayMagicTopic (st, dptr, topic);
11230 }
11231 else
11232 (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11233
11234
11235
11236
11237
11238
11239 if (topic->text)
11240 fputs (topic->text, st);
11241
11242 for (i = 0; i < topic->kids; i++)
11243 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11244
11245 return SCPE_OK;
11246 }
11247
11248 #define HLP_MATCH_AMBIGUOUS (~0u)
11249 #define HLP_MATCH_WILDCARD (~1U)
11250 #define HLP_MATCH_NONE 0
11251 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11252 {
11253 size_t i, match;
11254 char cbuf[CBUFSIZE], *cptr;
11255
11256 if (!strcmp (token, "*"))
11257 return HLP_MATCH_WILDCARD;
11258
11259 match = 0;
11260 for (i = 0; i < topic->kids; i++) {
11261 strcpy (cbuf,topic->children[i]->title +
11262 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11263 cptr = cbuf;
11264 while (*cptr) {
11265 if (blankch (*cptr)) {
11266 *cptr++ = '_';
11267 }
11268 else {
11269 *cptr = (char)toupper (*cptr);
11270 cptr++;
11271 }
11272 }
11273 if (!strcmp (cbuf, token))
11274 return i+1;
11275 if (!strncmp (cbuf, token, strlen (token))) {
11276 if (match)
11277 return HLP_MATCH_AMBIGUOUS;
11278 match = i+1;
11279 }
11280 }
11281 return match;
11282 }
11283
11284
11285
11286 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11287 UNIT *uptr, int32 flag,
11288 const char *help, const char *cptr, va_list ap)
11289 {
11290 TOPIC top;
11291 TOPIC *topic = ⊤
11292 int failed;
11293 size_t match;
11294 size_t i;
11295 const char *p;
11296 t_bool flat_help = FALSE;
11297 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11298
11299 static const char attach_help[] = { " ATTACH" };
11300 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\r\n" };
11301 static const char onecmd_help[] = { "%s help.\r\n" };
11302 static const char help_help[] = {
11303
11304 " To see more HELP information, type the listed subtopic name. To move\r\n"
11305 " up a level, just type <CR>. To review the current subtopic, type \"?\".\r\n"
11306 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11307 };
11308
11309 (void)memset (&top, 0, sizeof(top));
11310 top.parent = ⊤
11311 if ((failed = setjmp (help_env)) != 0) {
11312 (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11313 "Error in block %u line %u: %s\r\n"
11314 "%s%*.*s%s\r\n",
11315 (int)help_where.block, (int)help_where.line, help_where.error,
11316 help_where.prox ? "Near '" : "",
11317 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11318 help_where.prox ? help_where.prox : "",
11319 help_where.prox ? "'" : "");
11320 cleanHelp (&top);
11321 return failed;
11322 }
11323
11324
11325
11326
11327
11328 if (dptr) {
11329 p = dptr->name;
11330 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11331 }
11332 else
11333 p = sim_name;
11334 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11335 if (!top.title)
11336 {
11337 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11338 __func__, __FILE__, __LINE__);
11339 #if defined(USE_BACKTRACE)
11340 # if defined(SIGUSR2)
11341 (void)raise(SIGUSR2);
11342
11343 # endif
11344 #endif
11345 abort();
11346 }
11347 for (i = 0; p[i]; i++ )
11348 top.title[i] = (char)toupper (p[i]);
11349 top.title[i] = '\0';
11350 if (flag & SCP_HELP_ATTACH)
11351 strcpy (top.title+i, attach_help);
11352
11353 top.label = (char *) malloc (sizeof ("1"));
11354 if (!top.label)
11355 {
11356 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11357 __func__, __FILE__, __LINE__);
11358 #if defined(USE_BACKTRACE)
11359 # if defined(SIGUSR2)
11360 (void)raise(SIGUSR2);
11361
11362 # endif
11363 #endif
11364 abort();
11365 }
11366 strcpy (top.label, "1");
11367
11368 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11369
11370 if (flat_help) {
11371 flag |= SCP_HELP_FLAT;
11372 if (sim_ttisatty())
11373 (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11374 else
11375 (void)fprintf (st, "%s help.\r\n", top.title);
11376 }
11377 else
11378 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11379
11380
11381
11382 (void) buildHelp (&top, dptr, uptr, help, ap);
11383
11384
11385
11386 while (cptr && *cptr) {
11387 cptr = get_glyph (cptr, gbuf, 0);
11388 if (!gbuf[0])
11389 break;
11390 if (!strcmp (gbuf, "HELP")) {
11391 (void)fprintf (st, "\r\n");
11392 fputs (help_help, st);
11393 break;
11394 }
11395 match = matchHelpTopicName (topic, gbuf);
11396 if (match == HLP_MATCH_WILDCARD) {
11397 if (dptr)
11398 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11399 cleanHelp (&top);
11400 return SCPE_OK;
11401 }
11402 if (match == HLP_MATCH_AMBIGUOUS) {
11403 (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11404 break;
11405 }
11406 if (match == HLP_MATCH_NONE) {
11407 (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11408 break;
11409 }
11410 topic = topic->children[match-1];
11411 }
11412 cptr = NULL;
11413
11414 if (flat_help) {
11415 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11416 cleanHelp (&top);
11417 return SCPE_OK;
11418 }
11419
11420
11421
11422 while (TRUE) {
11423 char *pstring;
11424 const char *prompt[2] = {"? ", "Subtopic? "};
11425
11426
11427
11428 if (topic->flags & HLP_MAGIC_TOPIC) {
11429 fputc ('\n', st);
11430 displayMagicTopic (st, dptr, topic);
11431 }
11432 else
11433 (void)fprintf (st, "\r\n%s\r\n", topic->title);
11434
11435
11436
11437
11438
11439 if (topic->text)
11440 fputs (topic->text, st);
11441
11442 if (topic->kids) {
11443 size_t w = 0;
11444 char *p;
11445 char tbuf[CBUFSIZE];
11446
11447 (void)fprintf (st, "\r\n Additional information available:\r\n\r\n");
11448 for (i = 0; i < topic->kids; i++) {
11449 strcpy (tbuf, topic->children[i]->title +
11450 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11451 for (p = tbuf; *p; p++) {
11452 if (blankch (*p))
11453 *p = '_';
11454 }
11455 w += 4 + topic->kidwid;
11456 if (w > 80) {
11457 w = 4 + topic->kidwid;
11458 fputc ('\r', st);
11459 fputc ('\n', st);
11460 }
11461 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11462 }
11463 (void)fprintf (st, "\r\n\r\n");
11464 if (flag & SCP_HELP_ONECMD) {
11465 pstring = helpPrompt (topic, "", TRUE);
11466 (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11467 FREE (pstring);
11468 break;
11469 }
11470 }
11471
11472 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11473 break;
11474
11475 reprompt:
11476 if (NULL == cptr || !*cptr) {
11477 if (topic->kids == 0)
11478 topic = topic->parent;
11479 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11480
11481 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11482 FREE (pstring);
11483 if ((cptr != NULL) &&
11484 ((0 == strcmp (cptr, "\x04")) ||
11485 (0 == strcmp (cptr, "\x1A"))))
11486 cptr = NULL;
11487 }
11488
11489 if (NULL == cptr)
11490 break;
11491
11492 cptr = get_glyph (cptr, gbuf, 0);
11493 if (!strcmp (gbuf, "*")) {
11494 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11495 gbuf[0] = '\0';
11496 }
11497 if (!gbuf[0]) {
11498 if (topic->level == 0)
11499 break;
11500 topic = topic->parent;
11501 continue;
11502 }
11503 if (!strcmp (gbuf, "?"))
11504 continue;
11505 if (!strcmp (gbuf, "HELP")) {
11506 fputs (help_help, st);
11507 goto reprompt;
11508 }
11509 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11510 break;
11511
11512
11513
11514 if (!topic->kids) {
11515 (void)fprintf (st, "No additional help at this level.\r\n");
11516 cptr = NULL;
11517 goto reprompt;
11518 }
11519 match = matchHelpTopicName (topic, gbuf);
11520 if (match == HLP_MATCH_AMBIGUOUS) {
11521 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11522 cptr = NULL;
11523 goto reprompt;
11524 }
11525
11526 if (match == HLP_MATCH_NONE) {
11527 (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11528 cptr = NULL;
11529 goto reprompt;
11530 }
11531
11532
11533 topic = topic->children[match-1];
11534 }
11535
11536
11537
11538 cleanHelp (&top);
11539
11540 return SCPE_OK;
11541 }
11542
11543
11544
11545 t_stat scp_help (FILE *st, DEVICE *dptr,
11546 UNIT *uptr, int32 flag,
11547 const char *help, const char *cptr, ...)
11548 {
11549 t_stat r;
11550 va_list ap;
11551
11552 va_start (ap, cptr);
11553 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11554 va_end (ap);
11555
11556 return r;
11557 }
11558
11559 #if defined(_MSC_VER)
11560 # pragma warning(pop)
11561 #endif