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(WAM)
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, "WAM");
5164 #endif
5165
5166
5167 #if !defined(LOCKLESS)
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, "NO_LOCKLESS");
5177 #endif
5178
5179
5180 #if defined(PANEL68)
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, "PANEL68");
5190 #endif
5191
5192
5193 #if defined(WITH_ABSI_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, "ABSI");
5203 #endif
5204
5205
5206 #if defined(WITH_SOCKET_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, "SOCKET");
5216 #endif
5217
5218
5219 #if defined(WITH_MGP_DEV)
5220 # if defined(HAVE_DPSOPT)
5221 (void)fprintf (st, ", ");
5222 # else
5223 (void)fprintf (st, "\r\n Options: ");
5224 # endif
5225 # if !defined(HAVE_DPSOPT)
5226 # define HAVE_DPSOPT 1
5227 # endif
5228 (void)fprintf (st, "CHAOSNET");
5229 # if USE_SOCKET_DEV_APPROACH
5230 (void)fprintf (st, "-S");
5231 # endif
5232 #endif
5233
5234
5235 #if defined(USE_DUMA)
5236 # if defined(HAVE_DPSOPT)
5237 (void)fprintf (st, ", ");
5238 # else
5239 (void)fprintf (st, "\r\n Options: ");
5240 # endif
5241 # if !defined(HAVE_DPSOPT)
5242 # define HAVE_DPSOPT 1
5243 # endif
5244 (void)fprintf (st, "DUMA");
5245 #endif
5246
5247 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5248 # if defined(NO_SUPPORT_VERSION)
5249 (void)fprintf (st, "\r\n Modified: %s", VER_H_GIT_DATE);
5250 # else
5251 (void)fprintf (st, "\r\n Released: %s", VER_H_GIT_DATE);
5252 # endif
5253 #endif
5254 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5255 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5256 #endif
5257 #if defined(VER_CURRENT_TIME)
5258 (void)fprintf (st, "\r\n Compiled: %s", VER_CURRENT_TIME);
5259 #endif
5260 if (dirty)
5261 {
5262 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5263 }
5264 (void)fprintf (st, "\r\n\r\n Build Information:");
5265 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5266 char build_os_version_raw[255];
5267 char build_os_arch_raw[255];
5268 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5269 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5270 char *build_os_version = strdup(build_os_version_raw);
5271 if (!build_os_version)
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 char *build_os_arch = strdup(build_os_arch_raw);
5284 if (!build_os_arch)
5285 {
5286 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5287 __func__, __FILE__, __LINE__);
5288 # if defined(USE_BACKTRACE)
5289 # if defined(SIGUSR2)
5290 (void)raise(SIGUSR2);
5291
5292 # endif
5293 # endif
5294 abort();
5295 }
5296 unsigned char SPROM[1024];
5297 setupPROM (0, SPROM);
5298 (void)fprintf (st, "\r\n Target: ");
5299 printpq (SPROM, st, 190, 20);
5300 if (SPROM[170] != 20)
5301 {
5302 if (SPROM[170] != 255)
5303 {
5304 (void)fprintf (st, " on ");
5305 printpq (SPROM, st, 170, 20);
5306 }
5307 }
5308 strtrimspace(build_os_version, build_os_version_raw);
5309 strtrimspace(build_os_arch, build_os_arch_raw);
5310 (void)fprintf (st, "\r\n Build OS: %s %s", build_os_version, build_os_arch);
5311 FREE(build_os_version);
5312 FREE(build_os_arch);
5313 #endif
5314 #if defined(__VERSION__)
5315 char gnumver[2];
5316 char postver[1024];
5317 (void)sprintf(gnumver, "%.1s", __VERSION__);
5318 (void)sprintf(postver, "%.1023s", __VERSION__);
5319 strremove(postver, "(TM)");
5320 strremove(postver, "(R)");
5321 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5322 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5323 strremove(postver, " gcc 4.9 mode");
5324 strremove(postver, "4.2.1 Compatible ");
5325 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5326 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5327 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5328 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5329 strremove(postver, "(experimental) ");
5330 strremove(postver, ".module+el8.7.0+20823+214a699d");
5331 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5332 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5333 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5334 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5335 strremove(postver, "llvmorg-16.0.6-0-");
5336 strremove(postver, " Clang 15.0.0 (build 760095e)");
5337 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5338 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5339 strremove(postver, " Clang 15.0.0 (build 232543c)");
5340 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5341 strremove(postver, "CLANG: ");
5342 #endif
5343 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5344 # if !defined(__clang_version__)
5345 if (isdigit((unsigned char)gnumver[0])) {
5346 (void)fprintf (st, "\r\n Compiler: GCC %s", postver);
5347 } else {
5348 (void)fprintf (st, "\r\n Compiler: %s", postver);
5349 }
5350 # endif
5351 # if defined(__clang_analyzer__ )
5352 (void)fprintf (st, "\r\n Compiler: Clang C/C++ Static Analyzer");
5353 # elif defined(__clang_version__) && defined(__VERSION__)
5354 char clangllvmver[1024];
5355 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5356 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5357 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5358 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5359 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5360 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5361 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5362 strremove(clangllvmver, " ( )");
5363 strremove(clangllvmver, " ()");
5364 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5365 (void)fprintf (st, "\r\n Compiler: Clang %s", clangllvmver);
5366 } else {
5367 (void)fprintf (st, "\r\n Compiler: %s", postver);
5368 }
5369 # elif defined(__clang_version__)
5370 (void)fprintf (st, "\r\n Compiler: %s", postver);
5371 # endif
5372 #elif defined(__PGI) && !defined(__NVCOMPILER)
5373 (void)fprintf (st, "\r\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5374 # if defined(__PGIC__)
5375 (void)fprintf (st, "%d", __PGIC__);
5376 # if defined(__PGIC_MINOR__)
5377 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5378 # if defined(__PGIC_PATCHLEVEL__)
5379 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5380 # endif
5381 # endif
5382 # endif
5383 #elif defined(__NVCOMPILER)
5384 (void)fprintf (st, "\r\n Compiler: NVIDIA HPC SDK C Compiler ");
5385 # if defined(__NVCOMPILER_MAJOR__)
5386 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5387 # if defined(__NVCOMPILER_MINOR__)
5388 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5389 # if defined(__NVCOMPILER_PATCHLEVEL__)
5390 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5391 # endif
5392 # endif
5393 # endif
5394 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5395 (void)fprintf (st, "\r\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5396 _MSC_FULL_VER/10000000,
5397 (_MSC_FULL_VER/100000)%100,
5398 _MSC_FULL_VER%100000,
5399 _MSC_BUILD);
5400 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5401 # if defined(_AIX) && defined(__PASE__)
5402 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5403 # endif
5404 # if defined(_AIX) && !defined(__PASE__)
5405 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5406 # endif
5407 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5408 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5409 # endif
5410 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5411 # if defined(__PPC__) && defined(__APPLE__)
5412 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5413 # else
5414 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s", __xlc__);
5415 # endif
5416 # endif
5417 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5418 # define VER_ENC(maj, min, rev) \
5419 (((maj) * 1000000) + ((min) * 1000) + (rev))
5420 # define VER_DEC_MAJ(ver) \
5421 ((ver) / 1000000)
5422 # define VER_DEC_MIN(ver) \
5423 (((ver) % 1000000) / 1000)
5424 # define VER_DEC_REV(ver) \
5425 ((ver) % 1000)
5426 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5427 # define COMP_VER VER_ENC( \
5428 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5429 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5430 (__SUNPRO_C & 0xf) * 10)
5431 # elif defined(__SUNPRO_C)
5432 # define COMP_VER VER_ENC( \
5433 (__SUNPRO_C >> 8) & 0xf, \
5434 (__SUNPRO_C >> 4) & 0xf, \
5435 (__SUNPRO_C) & 0xf)
5436 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5437 # define COMP_VER VER_ENC( \
5438 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5439 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5440 (__SUNPRO_CC & 0xf) * 10)
5441 # elif defined(__SUNPRO_CC)
5442 # define COMP_VER VER_ENC( \
5443 (__SUNPRO_CC >> 8) & 0xf, \
5444 (__SUNPRO_CC >> 4) & 0xf, \
5445 (__SUNPRO_CC) & 0xf)
5446 # endif
5447 # if !defined(COMP_VER)
5448 # define COMP_VER 0
5449 # endif
5450 (void)fprintf (st, "\r\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5451 VER_DEC_MAJ(COMP_VER),
5452 VER_DEC_MIN(COMP_VER),
5453 VER_DEC_REV(COMP_VER));
5454 #elif defined(__DMC__)
5455 (void)fprintf (st, "\r\n Compiler: Digital Mars C/C++");
5456 #elif defined(__PCC__)
5457 (void)fprintf (st, "\r\n Compiler: Portable C Compiler");
5458 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5459 (void)fprintf (st, "\r\n Compiler: Plan 9 Compiler Suite");
5460 #elif defined(__ACK__)
5461 (void)fprintf (st, "\r\n Compiler: Amsterdam Compiler Kit");
5462 #elif defined(__COMO__)
5463 (void)fprintf (st, "\r\n Compiler: Comeau C++");
5464 #elif defined(__COMPCERT__)
5465 (void)fprintf (st, "\r\n Compiler: CompCert C");
5466 #elif defined(__COVERITY__)
5467 (void)fprintf (st, "\r\n Compiler: Coverity C/C++ Static Analyzer");
5468 #elif defined(__LCC__)
5469 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5470 (void)fprintf (st, "\r\n Compiler: MCST Elbrus C Compiler");
5471 # if __LCC__ > 99
5472 (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5473 # if defined(__LCC_MINOR__)
5474 # if __LCC_MINOR__ > 0
5475 (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5476 # endif
5477 # endif
5478 # endif
5479 # if defined(__EDG__) && defined(__EDG_VERSION__)
5480 # if __EDG_VERSION__ > 99
5481 (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5482 (int)(((__EDG_VERSION__) % 100) % 10));
5483 # endif
5484 # endif
5485 # else
5486 (void)fprintf (st, "\r\n Compiler: Local/Little C Compiler (lcc)");
5487 # endif
5488 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5489 (void)fprintf (st, "\r\n Compiler: SGI MIPSpro");
5490 #elif defined(__OPEN64__)
5491 (void)fprintf (st, "\r\n Compiler: Open64 %s", __OPEN64__);
5492 #elif defined(__PGI) || defined(__PGIC__)
5493 (void)fprintf (st, "\r\n Compiler: Portland Group/PGI C/C++");
5494 #elif defined(__VBCC__)
5495 (void)fprintf (st, "\r\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5496 #elif defined(__WATCOMC__)
5497 (void)fprintf (st, "\r\n Compiler: Watcom C/C++ %d.%d",
5498 __WATCOMC__ / 100,
5499 __WATCOMC__ % 100);
5500 #elif defined(__xlC__)
5501 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++");
5502 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5503 # if defined(__INTEL_COMPILER_UPDATE)
5504 # if defined(__INTEL_COMPILER_BUILD_DATE)
5505 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d (%d)",
5506 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5507 __INTEL_COMPILER_BUILD_DATE);
5508 # else
5509 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d",
5510 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5511 # endif
5512 # else
5513 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d",
5514 __INTEL_COMPILER);
5515 # endif
5516 #elif defined(SIM_COMPILER)
5517 # define S_xstr(a) S_str(a)
5518 # define S_str(a) #a
5519 (void)fprintf (st, "\r\n Compiler: %s", S_xstr(SIM_COMPILER));
5520 # undef S_str
5521 # undef S_xstr
5522 #else
5523 (void)fprintf (st, "\r\n Compiler: Unknown");
5524 #endif
5525
5526 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5527 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5528 # define SC_IS_PPC64 1
5529 #else
5530 # define SC_IS_PPC64 0
5531 #endif
5532
5533 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5534 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5535 defined(__PPC32)
5536 # define SC_IS_PPC32 1
5537 #else
5538 # define SC_IS_PPC32 0
5539 #endif
5540
5541 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5542 arch = " x86_64";
5543 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5544 arch = " x86";
5545 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5546 arch = " arm64";
5547 #elif defined(_M_ARM) || defined(__arm__)
5548 arch = " arm";
5549 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5550 arch = " ia64";
5551 #elif SC_IS_PPC64
5552 arch = " powerpc64";
5553 #elif SC_IS_PPC32
5554 arch = " powerpc";
5555 #elif defined(__s390x__)
5556 arch = " s390x";
5557 #elif defined(__s390__)
5558 arch = " s390";
5559 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5560 arch = " j2";
5561 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5562 arch = " sh4";
5563 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5564 arch = " sh2";
5565 #elif defined(__alpha__)
5566 arch = " alpha";
5567 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5568 arch = " hppa";
5569 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5570 arch = " ice9";
5571 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5572 arch = " mips64";
5573 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5574 arch = " mips";
5575 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5576 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5577 arch = " openrisc";
5578 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5579 arch = " sparc64";
5580 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5581 arch = " sparc";
5582 #elif defined(__riscv) || defined(__riscv__)
5583 arch = " riscv";
5584 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5585 arch = " e2k";
5586 #elif defined(__myriad2__)
5587 arch = " myriad2";
5588 #elif defined(__loongarch64) || defined(__loongarch__)
5589 arch = " loongarch";
5590 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5591 arch = " m68k";
5592 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5593 arch = " m88k";
5594 #elif defined(__VAX__) || defined(__vax__)
5595 arch = " vax";
5596 #elif defined(__NIOS2__) || defined(__nios2__)
5597 arch = " nios2";
5598 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5599 arch = " microblaze";
5600 #else
5601 arch = " ";
5602 #endif
5603 (void)fprintf (st, "%s", arch);
5604 #if defined(BUILD_BY_USER)
5605 (void)fprintf (st, "\r\n Built by: %s", BUILD_BY_USER);
5606 #else
5607 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5608 (void)fprintf (st, "\r\n Built by: %s", VER_H_PREP_USER);
5609 # endif
5610 #endif
5611 (void)fprintf (st, "\r\n\r\n Host System Information:");
5612 #if defined(_WIN32)
5613 if (1) {
5614 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5615 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5616 char osversion[PATH_MAX+1] = "";
5617 FILE *f;
5618
5619 if ((f = _popen ("ver", "r"))) {
5620 (void)memset (osversion, 0, sizeof(osversion));
5621 do {
5622 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5623 break;
5624 sim_trim_endspc (osversion);
5625 } while (osversion[0] == '\0');
5626 _pclose (f);
5627 }
5628 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5629 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5630 }
5631 #else
5632 if (1) {
5633 char osversion[2*PATH_MAX+1] = "";
5634 FILE *f;
5635 # if !defined(_AIX)
5636 if ((f = popen \
5637 ("uname -mrs 2> /dev/null", "r"))) {
5638 # else
5639 if ((f = popen \
5640 ("sh -c 'echo \"$(command -p env uname -v \
5641 2> /dev/null).$(command -p env uname -r \
5642 2> /dev/null) $(command -p env uname -p \
5643 2> /dev/null)\"' 2> /dev/null", "r"))) {
5644 # endif
5645 (void)memset (osversion, 0, sizeof(osversion));
5646 do {
5647 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5648 break;
5649 }
5650 sim_trim_endspc (osversion);
5651 } while (osversion[0] == '\0');
5652 pclose (f);
5653 strremove(osversion, "0000000000000000 ");
5654 strremove(osversion, " 0000000000000000");
5655 strremove(osversion, "000000000000 ");
5656 strremove(osversion, " 000000000000");
5657 strremove(osversion, "IBM ");
5658 strremove(osversion, " (emulated by qemu)");
5659 strremove(osversion, " (emulated by QEMU)");
5660 }
5661 # if !defined(_AIX)
5662 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5663 # else
5664 strremove(osversion, "AIX ");
5665 # if !defined(__PASE__)
5666 (void)fprintf (st, "\r\n Host OS: IBM AIX %s", osversion);
5667 # else
5668 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE) %s", osversion);
5669 # endif
5670 # endif
5671 } else {
5672 # if !defined(_AIX)
5673 (void)fprintf (st, "\r\n Host OS: Unknown");
5674 # else
5675 # if !defined(__PASE__)
5676 (void)fprintf (st, "\r\n Host OS: IBM AIX");
5677 # else
5678 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE)");
5679 # endif
5680 # endif
5681 }
5682 #endif
5683 if (nodist)
5684 {
5685 sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5686 }
5687 else
5688 {
5689 (void)fprintf (st, "\r\n");
5690 (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5691 (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5692 (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5693 }
5694 (void)fprintf (st, "\r\n");
5695 }
5696 return SCPE_OK;
5697 }
5698
5699 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5700 {
5701 size_t i;
5702 DEVICE *dptr;
5703 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5704
5705 if (cptr && (*cptr != 0))
5706 return SCPE_2MARG;
5707 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5708 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5709 if (!only_enabled || !qdisable (dptr))
5710 show_device (st, dptr, flag);
5711 return SCPE_OK;
5712 }
5713
5714 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5715 {
5716 int32 i;
5717 DEVICE *dptr;
5718
5719 if (cptr && (*cptr != 0))
5720 return SCPE_2MARG;
5721 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5722 show_dev_logicals (st, dptr, NULL, 1, cptr);
5723 return SCPE_OK;
5724 }
5725
5726 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5727 {
5728 if (dptr->lname)
5729 (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5730 else if (!flag)
5731 fputs ("no logical name assigned\r\n", st);
5732 return SCPE_OK;
5733 }
5734
5735 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5736 {
5737 DEVICE *dptr;
5738 UNIT *uptr;
5739 int32 accum;
5740
5741 if (cptr && (*cptr != 0))
5742 return SCPE_2MARG;
5743 if (sim_clock_queue == QUEUE_LIST_END)
5744 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5745 sim_name, sim_time, sim_timer_inst_per_sec ());
5746 else {
5747 const char *tim;
5748
5749 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5750 sim_name, sim_time, sim_timer_inst_per_sec ());
5751 accum = 0;
5752 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5753 if (uptr == &sim_step_unit)
5754 (void)fprintf (st, " Step timer");
5755 else
5756 if (uptr == &sim_expect_unit)
5757 (void)fprintf (st, " Expect fired");
5758 else
5759 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5760 (void)fprintf (st, " %s", sim_dname (dptr));
5761 if (dptr->numunits > 1)
5762 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5763 }
5764 else
5765 (void)fprintf (st, " Unknown");
5766 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5767 (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5768 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5769 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5770 accum = accum + uptr->time;
5771 }
5772 }
5773 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5774 return SCPE_OK;
5775 }
5776
5777 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5778 {
5779 if (cptr && (*cptr != 0))
5780 return SCPE_2MARG;
5781 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5782 return SCPE_OK;
5783 }
5784
5785 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5786 {
5787 t_stat r;
5788
5789 if (cptr && (*cptr != 0))
5790 r = ssh_break (st, cptr, 1);
5791 else
5792 r = sim_brk_showall (st, (uint32)sim_switches);
5793 return r;
5794 }
5795
5796 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5797 {
5798 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5799 return SCPE_OK;
5800 }
5801
5802 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5803 {
5804 int32 any = 0;
5805 DEBTAB *dep;
5806
5807 if (dptr->flags & DEV_DEBUG) {
5808 if (dptr->dctrl == 0)
5809 fputs ("Debugging disabled", st);
5810 else if (dptr->debflags == NULL)
5811 fputs ("Debugging enabled", st);
5812 else {
5813 uint32 dctrl = dptr->dctrl;
5814
5815 fputs ("Debug=", st);
5816 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5817 if ((dctrl & dep->mask) == dep->mask) {
5818 dctrl &= ~dep->mask;
5819 if (any)
5820 fputc (';', st);
5821 fputs (dep->name, st);
5822 any = 1;
5823 }
5824 }
5825 }
5826 fputc ('\n', st);
5827 return SCPE_OK;
5828 }
5829 else return SCPE_NOFNC;
5830 }
5831
5832
5833
5834 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5835 {
5836 int32 lvl, i;
5837
5838 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5839 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5840 if (lvl > 0)
5841 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5842 else
5843 (void)fprintf(st, "On Processing for input commands");
5844 (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5845 for (i=1; i<SCPE_BASE; ++i) {
5846 if (sim_on_actions[lvl][i])
5847 (void)fprintf(st, " on %5d %s\r\n", i, sim_on_actions[lvl][i]); }
5848 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5849 if (sim_on_actions[lvl][i])
5850 (void)fprintf(st, " on %-5s %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5851 if (sim_on_actions[lvl][0])
5852 (void)fprintf(st, " on ERROR %s\r\n", sim_on_actions[lvl][0]);
5853 (void)fprintf(st, "\r\n");
5854 }
5855 if (sim_on_inherit)
5856 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5857 return SCPE_OK;
5858 }
5859
5860
5861
5862 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5863 {
5864 int32 i;
5865 DEVICE *dptr;
5866
5867 if (cptr && (*cptr != 0))
5868 return SCPE_2MARG;
5869 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5870 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5871 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5872 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5873 return SCPE_OK;
5874 }
5875
5876 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5877 {
5878 fprint_set_help (st, dptr);
5879 return SCPE_OK;
5880 }
5881
5882 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5883 {
5884 MTAB *mptr;
5885 t_stat r = SCPE_OK;
5886
5887 if (dptr->modifiers == NULL)
5888 return SCPE_OK;
5889 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5890 if (mptr->pstring &&
5891 ((mptr->mask & MTAB_XTD)?
5892 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5893 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5894 if (*toks > 0) {
5895 (void)fprintf (st, "\r\n");
5896 *toks = 0;
5897 }
5898 if (r == SCPE_OK)
5899 fprint_sep (st, toks);
5900 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5901 }
5902 }
5903 return SCPE_OK;
5904 }
5905
5906 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5907 CONST char *cptr, int32 flag)
5908 {
5909 t_stat r = SCPE_OK;
5910
5911 if (mptr->disp)
5912 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5913 else
5914 fputs (mptr->pstring, st);
5915 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5916 fputc ('\n', st);
5917 return r;
5918 }
5919
5920
5921
5922 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5923 {
5924 int32 i;
5925 DEVICE *dptr;
5926
5927 if (cptr && (*cptr != 0))
5928 return SCPE_2MARG;
5929 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5930 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5931 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5932 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5933 return SCPE_OK;
5934 }
5935
5936 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5937 {
5938 fprint_show_help (st, dptr);
5939 return SCPE_OK;
5940 }
5941
5942
5943
5944 t_stat brk_cmd (int32 flg, CONST char *cptr)
5945 {
5946 GET_SWITCHES (cptr);
5947 return ssh_break (NULL, cptr, flg);
5948 }
5949
5950 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
5951 {
5952 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5953 CONST char *tptr, *t1ptr;
5954 DEVICE *dptr = sim_dflt_dev;
5955 UNIT *uptr;
5956 t_stat r;
5957 t_addr lo, hi, max;
5958 int32 cnt;
5959
5960 if (sim_brk_types == 0)
5961 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
5962 if (dptr == NULL)
5963 return SCPE_IERR;
5964 uptr = dptr->units;
5965 if (uptr == NULL)
5966 return SCPE_IERR;
5967 max = uptr->capac - 1;
5968 abuf[sizeof(abuf)-1] = '\0';
5969 strncpy (abuf, cptr, sizeof(abuf)-1);
5970 cptr = abuf;
5971 if ((aptr = strchr (abuf, ';'))) {
5972 if (flg != SSH_ST)
5973 return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
5974 *aptr++ = 0;
5975 }
5976 if (*cptr == 0) {
5977 lo = (t_addr) get_rval (sim_PC, 0);
5978 return ssh_break_one (st, flg, lo, 0, aptr);
5979 }
5980 while (*cptr) {
5981 cptr = get_glyph (cptr, gbuf, ',');
5982 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5983 if (tptr == NULL)
5984 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
5985 if (*tptr == '[') {
5986 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5987 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5988 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
5989 tptr = t1ptr + 1;
5990 }
5991 else cnt = 0;
5992 if (*tptr != 0)
5993 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
5994 if ((lo == 0) && (hi == max)) {
5995 if (flg == SSH_CL)
5996 sim_brk_clrall (sim_switches);
5997 else
5998 if (flg == SSH_SH)
5999 sim_brk_showall (st, (uint32)sim_switches);
6000 else
6001 return SCPE_ARG;
6002 }
6003 else {
6004 for ( ; lo <= hi; lo = lo + 1) {
6005 r = ssh_break_one (st, flg, lo, cnt, aptr);
6006 if (r != SCPE_OK)
6007 return r;
6008 }
6009 }
6010 }
6011 return SCPE_OK;
6012 }
6013
6014 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
6015 {
6016 if (!sim_brk_types)
6017 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6018 switch (flg) {
6019 case SSH_ST:
6020 return sim_brk_set (lo, sim_switches, cnt, aptr);
6021
6022 break;
6023
6024 case SSH_CL:
6025 return sim_brk_clr (lo, sim_switches);
6026
6027 break;
6028
6029 case SSH_SH:
6030 return sim_brk_show (st, lo, sim_switches);
6031
6032 break;
6033
6034 default:
6035 return SCPE_ARG;
6036 }
6037 }
6038
6039
6040
6041 static t_bool run_cmd_did_reset = FALSE;
6042
6043 t_stat reset_cmd (int32 flag, CONST char *cptr)
6044 {
6045 char gbuf[CBUFSIZE];
6046 DEVICE *dptr;
6047
6048 GET_SWITCHES (cptr);
6049 run_cmd_did_reset = FALSE;
6050 if (*cptr == 0)
6051 return (reset_all (0));
6052 cptr = get_glyph (cptr, gbuf, 0);
6053 if (*cptr != 0)
6054 return SCPE_2MARG;
6055 if (strcmp (gbuf, "ALL") == 0)
6056 return (reset_all (0));
6057 dptr = find_dev (gbuf);
6058 if (dptr == NULL)
6059 return SCPE_NXDEV;
6060 if (dptr->reset != NULL)
6061 return dptr->reset (dptr);
6062 else return SCPE_OK;
6063 }
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073 t_stat reset_all (uint32 start)
6074 {
6075 DEVICE *dptr;
6076 uint32 i;
6077 t_stat reason;
6078
6079 for (i = 0; i < start; i++) {
6080 if (sim_devices[i] == NULL)
6081 return SCPE_IERR;
6082 }
6083 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6084 if (dptr->reset != NULL) {
6085 reason = dptr->reset (dptr);
6086 if (reason != SCPE_OK)
6087 return reason;
6088 }
6089 }
6090 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6091 if (dptr->reset != NULL) {
6092 reason = dptr->reset (dptr);
6093 if (reason != SCPE_OK)
6094 return reason;
6095 }
6096 }
6097 return SCPE_OK;
6098 }
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108 t_stat reset_all_p (uint32 start)
6109 {
6110 t_stat r;
6111 int32 old_sw = sim_switches;
6112
6113 sim_switches = SWMASK ('P');
6114 r = reset_all (start);
6115 sim_switches = old_sw;
6116 return r;
6117 }
6118
6119
6120
6121 t_stat attach_cmd (int32 flag, CONST char *cptr)
6122 {
6123 char gbuf[4*CBUFSIZE];
6124 DEVICE *dptr;
6125 UNIT *uptr;
6126 t_stat r;
6127
6128 GET_SWITCHES (cptr);
6129 if ((NULL == cptr) || (*cptr == 0))
6130 return SCPE_2FARG;
6131 cptr = get_glyph (cptr, gbuf, 0);
6132 GET_SWITCHES (cptr);
6133 if ((NULL == cptr) || (*cptr == 0))
6134 return SCPE_2FARG;
6135 dptr = find_unit (gbuf, &uptr);
6136 if (dptr == NULL)
6137 return SCPE_NXDEV;
6138 if (uptr == NULL)
6139 return SCPE_NXUN;
6140 if (uptr->flags & UNIT_ATT) {
6141 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6142 !(dptr->flags & DEV_DONTAUTO)) {
6143 r = scp_detach_unit (dptr, uptr);
6144 if (r != SCPE_OK)
6145 return r; }
6146 else {
6147 if (!(uptr->dynflags & UNIT_ATTMULT))
6148 return SCPE_ALATT;
6149 }
6150 }
6151 gbuf[sizeof(gbuf)-1] = '\0';
6152 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6153 sim_trim_endspc (gbuf);
6154 return scp_attach_unit (dptr, uptr, gbuf);
6155 }
6156
6157
6158
6159 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6160 {
6161 if (dptr->attach != NULL)
6162 return dptr->attach (uptr, (CONST char *)cptr);
6163 return attach_unit (uptr, (CONST char *)cptr);
6164 }
6165
6166
6167
6168 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6169 {
6170 DEVICE *dptr;
6171
6172 if (uptr->flags & UNIT_DIS)
6173 return SCPE_UDIS;
6174 if (!(uptr->flags & UNIT_ATTABLE))
6175 return SCPE_NOATT;
6176 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6177 return SCPE_NOATT;
6178 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6179 if (uptr->filename == NULL)
6180 return SCPE_MEM;
6181 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6182 if ((sim_switches & SWMASK ('R')) ||
6183 ((uptr->flags & UNIT_RO) != 0)) {
6184 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6185 ((uptr->flags & UNIT_RO) == 0))
6186 return attach_err (uptr, SCPE_NORO);
6187 uptr->fileref = sim_fopen (cptr, "rb");
6188 if (uptr->fileref == NULL)
6189 return attach_err (uptr, SCPE_OPENERR);
6190 uptr->flags = uptr->flags | UNIT_RO;
6191 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6192 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6193 }
6194 }
6195 else {
6196 if (sim_switches & SWMASK ('N')) {
6197 uptr->fileref = sim_fopen (cptr, "wb+");
6198 if (uptr->fileref == NULL)
6199 return attach_err (uptr, SCPE_OPENERR);
6200 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6201 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6202 }
6203 }
6204 else {
6205 uptr->fileref = sim_fopen (cptr, "rb+");
6206 if (uptr->fileref == NULL) {
6207 #if defined(EWOULDBLOCK)
6208 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6209 #else
6210 if ((errno == EAGAIN))
6211 #endif
6212 return attach_err (uptr, SCPE_OPENERR);
6213
6214 #if defined(EPERM)
6215 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6216 #else
6217 if ((errno == EROFS) || (errno == EACCES)) {
6218 #endif
6219 if ((uptr->flags & UNIT_ROABLE) == 0)
6220 return attach_err (uptr, SCPE_NORO);
6221 uptr->fileref = sim_fopen (cptr, "rb");
6222 if (uptr->fileref == NULL)
6223 return attach_err (uptr, SCPE_OPENERR);
6224 uptr->flags = uptr->flags | UNIT_RO;
6225 if (!sim_quiet) {
6226 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6227 }
6228 }
6229 else {
6230 if (sim_switches & SWMASK ('E'))
6231 return attach_err (uptr, SCPE_OPENERR);
6232 uptr->fileref = sim_fopen (cptr, "wb+");
6233 if (uptr->fileref == NULL)
6234 return attach_err (uptr, SCPE_OPENERR);
6235 if (!sim_quiet) {
6236 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6237 }
6238 }
6239 }
6240 }
6241 }
6242 if (uptr->flags & UNIT_BUFABLE) {
6243 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6244 if (uptr->flags & UNIT_MUSTBUF)
6245 uptr->filebuf = calloc (cap, SZ_D (dptr));
6246 if (uptr->filebuf == NULL)
6247 return attach_err (uptr, SCPE_MEM);
6248 if (!sim_quiet) {
6249 sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6250 }
6251 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6252 SZ_D (dptr), cap, uptr->fileref);
6253 uptr->flags = uptr->flags | UNIT_BUF;
6254 }
6255 uptr->flags = uptr->flags | UNIT_ATT;
6256 uptr->pos = 0;
6257 return SCPE_OK;
6258 }
6259
6260 t_stat attach_err (UNIT *uptr, t_stat stat)
6261 {
6262 FREE (uptr->filename);
6263 uptr->filename = NULL;
6264 return stat;
6265 }
6266
6267
6268
6269 t_stat detach_cmd (int32 flag, CONST char *cptr)
6270 {
6271 char gbuf[CBUFSIZE];
6272 DEVICE *dptr;
6273 UNIT *uptr;
6274
6275 GET_SWITCHES (cptr);
6276 if ((NULL == cptr) || (*cptr == 0))
6277 return SCPE_2FARG;
6278 cptr = get_glyph (cptr, gbuf, 0);
6279 if (*cptr != 0)
6280 return SCPE_2MARG;
6281 if (strcmp (gbuf, "ALL") == 0)
6282 return (detach_all (0, FALSE));
6283 dptr = find_unit (gbuf, &uptr);
6284 if (dptr == NULL)
6285 return SCPE_NXDEV;
6286 if (uptr == NULL)
6287 return SCPE_NXUN;
6288 return scp_detach_unit (dptr, uptr);
6289 }
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304 t_stat detach_all (int32 start, t_bool shutdown)
6305 {
6306 uint32 i, j;
6307 DEVICE *dptr;
6308 UNIT *uptr;
6309 t_stat r;
6310
6311 if ((start < 0) || (start > 1))
6312 return SCPE_IERR;
6313 if (shutdown)
6314 sim_switches = sim_switches | SIM_SW_SHUT;
6315 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6316 for (j = 0; j < dptr->numunits; j++) {
6317 uptr = (dptr->units) + j;
6318 if ((uptr->flags & UNIT_ATT) ||
6319 (shutdown && dptr->detach &&
6320 !(uptr->flags & UNIT_ATTABLE))) {
6321 r = scp_detach_unit (dptr, uptr);
6322
6323 if ((r != SCPE_OK) && !shutdown)
6324 return r;
6325 }
6326 }
6327 }
6328 return SCPE_OK;
6329 }
6330
6331
6332
6333 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6334 {
6335 if (dptr->detach != NULL)
6336 return dptr->detach (uptr);
6337 return detach_unit (uptr);
6338 }
6339
6340
6341
6342 t_stat detach_unit (UNIT *uptr)
6343 {
6344 DEVICE *dptr;
6345
6346 if (uptr == NULL)
6347 return SCPE_IERR;
6348 if (!(uptr->flags & UNIT_ATTABLE))
6349 return SCPE_NOATT;
6350 if (!(uptr->flags & UNIT_ATT)) {
6351 if (sim_switches & SIM_SW_REST)
6352 return SCPE_OK;
6353 else
6354 return SCPE_NOTATT;
6355 }
6356 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6357 return SCPE_OK;
6358 if (uptr->flags & UNIT_BUF) {
6359 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6360 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6361 if (!sim_quiet) {
6362 sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6363 }
6364 rewind (uptr->fileref);
6365 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6366 if (ferror (uptr->fileref))
6367 sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6368 sim_dname (dptr), xstrerror_l(errno), errno);
6369 }
6370 if (uptr->flags & UNIT_MUSTBUF) {
6371 FREE (uptr->filebuf);
6372 uptr->filebuf = NULL;
6373 }
6374 uptr->flags = uptr->flags & ~UNIT_BUF;
6375 }
6376 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6377 FREE (uptr->filename);
6378 uptr->filename = NULL;
6379 if (fclose (uptr->fileref) == EOF)
6380 return SCPE_IOERR;
6381 return SCPE_OK;
6382 }
6383
6384
6385
6386 const char *sim_dname (DEVICE *dptr)
6387 {
6388 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6389 }
6390
6391
6392
6393 const char *sim_uname (UNIT *uptr)
6394 {
6395 DEVICE *d = find_dev_from_unit(uptr);
6396 static char uname[CBUFSIZE];
6397
6398 if (!d)
6399 return "";
6400 if (d->numunits == 1)
6401 return sim_dname (d);
6402 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6403 return uname;
6404 }
6405
6406
6407
6408 t_stat run_cmd (int32 flag, CONST char *cptr)
6409 {
6410 char gbuf[CBUFSIZE] = "";
6411 CONST char *tptr;
6412 uint32 i, j;
6413 int32 sim_next = 0;
6414 int32 unitno;
6415 t_value pcv, orig_pcv;
6416 t_stat r;
6417 DEVICE *dptr;
6418 UNIT *uptr;
6419
6420 GET_SWITCHES (cptr);
6421 sim_step = 0;
6422 if ((flag == RU_RUN) || (flag == RU_GO)) {
6423 orig_pcv = get_rval (sim_PC, 0);
6424 if (*cptr != 0) {
6425 cptr = get_glyph (cptr, gbuf, 0);
6426 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6427 if (sim_dflt_dev && sim_vm_parse_addr)
6428 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6429 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6430 if ((tptr == gbuf) || (*tptr != 0) ||
6431 (pcv > width_mask[sim_PC->width]))
6432 return SCPE_ARG;
6433 put_rval (sim_PC, 0, pcv);
6434 }
6435 }
6436 if ((flag == RU_RUN) &&
6437 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6438 put_rval (sim_PC, 0, orig_pcv);
6439 return r;
6440 }
6441 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6442 int32 saved_switches = sim_switches;
6443
6444 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6445 cptr = get_glyph (cptr, gbuf, 0);
6446 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6447 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6448 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6449 sim_switches = 0;
6450 GET_SWITCHES (cptr);
6451 if ((*cptr == '\'') || (*cptr == '"')) {
6452 r = expect_cmd (1, cptr);
6453 if (r != SCPE_OK)
6454 return r;
6455 }
6456 else {
6457 if (sim_switches == 0)
6458 sim_switches = sim_brk_dflt;
6459 sim_switches |= BRK_TYP_TEMP;
6460 sim_brk_types |= BRK_TYP_TEMP;
6461 r = ssh_break (NULL, cptr, SSH_ST);
6462 if (r != SCPE_OK)
6463 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6464 }
6465 sim_switches = saved_switches;
6466 }
6467 }
6468
6469 else if ((flag == RU_STEP) ||
6470 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6471 static t_bool not_implemented_message = FALSE;
6472
6473 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6474 not_implemented_message = TRUE;
6475 flag = RU_STEP;
6476 }
6477 if (*cptr != 0) {
6478 cptr = get_glyph (cptr, gbuf, 0);
6479 if (*cptr != 0)
6480 return SCPE_2MARG;
6481 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6482 if ((r != SCPE_OK) || (sim_step <= 0))
6483 return SCPE_ARG;
6484 }
6485 else sim_step = 1;
6486 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6487 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6488 }
6489 else if (flag == RU_NEXT) {
6490 t_addr *addrs;
6491
6492 if (*cptr != 0) {
6493 cptr = get_glyph (cptr, gbuf, 0);
6494 if (*cptr != 0)
6495 return SCPE_2MARG;
6496 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6497 if ((r != SCPE_OK) || (sim_next <= 0))
6498 return SCPE_ARG;
6499 }
6500 else sim_next = 1;
6501 if (sim_vm_is_subroutine_call(&addrs)) {
6502 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6503 for (i=0; addrs[i]; i++)
6504 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6505 }
6506 else
6507 sim_step = 1;
6508 }
6509 else if (flag == RU_BOOT) {
6510 if (*cptr == 0)
6511 return SCPE_2FARG;
6512 cptr = get_glyph (cptr, gbuf, 0);
6513 if (*cptr != 0)
6514 return SCPE_2MARG;
6515 dptr = find_unit (gbuf, &uptr);
6516 if (dptr == NULL)
6517 return SCPE_NXDEV;
6518 if (uptr == NULL)
6519 return SCPE_NXUN;
6520 if (dptr->boot == NULL)
6521 return SCPE_NOFNC;
6522 if (uptr->flags & UNIT_DIS)
6523 return SCPE_UDIS;
6524 if ((uptr->flags & UNIT_ATTABLE) &&
6525 !(uptr->flags & UNIT_ATT))
6526 return SCPE_UNATT;
6527 unitno = (int32) (uptr - dptr->units);
6528 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6529 return r;
6530 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6531 return r;
6532 }
6533
6534 else
6535 if (flag != RU_CONT)
6536 return SCPE_IERR;
6537 else
6538 if (*cptr != 0)
6539 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6540
6541 if (sim_switches & SIM_SW_HIDE)
6542 return SCPE_OK;
6543
6544 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6545 for (j = 0; j < dptr->numunits; j++) {
6546 uptr = dptr->units + j;
6547 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6548 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6549 }
6550 }
6551 stop_cpu = 0;
6552 sim_is_running = 1;
6553 if (sim_ttrun () != SCPE_OK) {
6554 sim_is_running = 0;
6555 sim_ttcmd ();
6556 return SCPE_TTYERR;
6557 }
6558 if ((r = sim_check_console (30)) != SCPE_OK) {
6559 sim_is_running = 0;
6560 sim_ttcmd ();
6561 return r;
6562 }
6563 #if !defined(IS_WINDOWS)
6564 # if defined(SIGINT)
6565 if (signal (SIGINT, int_handler) == SIG_ERR) {
6566 sim_is_running = 0;
6567 sim_ttcmd ();
6568 return SCPE_SIGERR;
6569 }
6570 # endif
6571 #endif
6572 #if !defined(IS_WINDOWS)
6573 # if defined(SIGHUP)
6574 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6575 sim_is_running = 0;
6576 sim_ttcmd ();
6577 return SCPE_SIGERR;
6578 }
6579 # endif
6580 #endif
6581 #if !defined(IS_WINDOWS)
6582 # if defined(SIGTERM)
6583 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6584 sim_is_running = 0;
6585 sim_ttcmd ();
6586 return SCPE_SIGERR;
6587 }
6588 # endif
6589 #endif
6590 if (sim_step)
6591 sim_activate (&sim_step_unit, sim_step);
6592 (void)fflush(stdout);
6593 if (sim_log)
6594 (void)fflush (sim_log);
6595 sim_rtcn_init_all ();
6596 sim_start_timer_services ();
6597
6598 do {
6599 t_addr *addrs;
6600
6601 while (1) {
6602 r = sim_instr();
6603 if (r != SCPE_REMOTE)
6604 break;
6605 sim_remote_process_command ();
6606 }
6607 if ((flag != RU_NEXT) ||
6608 (--sim_next <=0))
6609 break;
6610 if (sim_step == 0) {
6611 t_addr val;
6612 BRKTAB *bp;
6613
6614 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6615 break;
6616 if (sim_vm_pc_value)
6617 val = (t_addr)(*sim_vm_pc_value)();
6618 else
6619 val = (t_addr)get_rval (sim_PC, 0);
6620 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6621 break;
6622 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6623 }
6624 else {
6625 if (r != SCPE_STEP)
6626 break;
6627 }
6628
6629 sim_step = 0;
6630 if (sim_vm_is_subroutine_call(&addrs)) {
6631 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6632 for (i=0; addrs[i]; i++)
6633 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6634 }
6635 else
6636 sim_step = 1;
6637 if (sim_step)
6638 sim_activate (&sim_step_unit, sim_step);
6639 } while (1);
6640
6641 sim_is_running = 0;
6642 sim_stop_timer_services ();
6643 sim_ttcmd ();
6644 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6645 signal (SIGINT, SIG_DFL);
6646 #if defined(SIGHUP)
6647 signal (SIGHUP, SIG_DFL);
6648 #endif
6649 signal (SIGTERM, SIG_DFL);
6650 if (sim_log)
6651 (void)fflush (sim_log);
6652 if (sim_deb)
6653 sim_debug_flush ();
6654 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6655 for (j = 0; j < dptr->numunits; j++) {
6656 uptr = dptr->units + j;
6657 if (uptr->flags & UNIT_ATT) {
6658 if (uptr->io_flush)
6659 uptr->io_flush (uptr);
6660 else {
6661 if (!(uptr->flags & UNIT_BUF) &&
6662 (uptr->fileref) &&
6663 !(uptr->dynflags & UNIT_NO_FIO) &&
6664 !(uptr->flags & UNIT_RO))
6665 (void)fflush (uptr->fileref);
6666 }
6667 }
6668 }
6669 }
6670 sim_cancel (&sim_step_unit);
6671 UPDATE_SIM_TIME;
6672 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6673 }
6674
6675
6676
6677 void
6678 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6679 {
6680 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6681 sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6682 #if defined(WIN_STDIO)
6683 (void)fflush(stderr);
6684 (void)fflush(stdout);
6685 #endif
6686 fprint_stopped (stdout, r);
6687 if (sim_log && (sim_log != stdout))
6688 fprint_stopped (sim_log, r);
6689 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6690 fprint_stopped (sim_deb, r);
6691 #if defined(WIN_STDIO)
6692 (void)fflush(stderr);
6693 (void)fflush(stdout);
6694 #endif
6695 }
6696
6697
6698
6699 t_stat sim_run_boot_prep (int32 flag)
6700 {
6701 UNIT *uptr;
6702 t_stat r;
6703
6704 sim_interval = 0;
6705 sim_time = sim_rtime = 0;
6706 noqueue_time = 0;
6707 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6708 sim_clock_queue = uptr->next;
6709 uptr->next = NULL;
6710 }
6711 r = reset_all (0);
6712 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6713 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6714 sim_printf ("Resetting all devices... This may not have been your intention.\r\n");
6715 sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6716 }
6717 run_cmd_did_reset = TRUE;
6718 }
6719 return r;
6720 }
6721
6722
6723
6724
6725
6726
6727
6728
6729 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6730 {
6731 int32 i;
6732 t_stat r = 0;
6733 t_addr k;
6734 t_value pcval;
6735
6736 fputc ('\n', st);
6737
6738 if (v >= SCPE_BASE)
6739 fputs (sim_error_text (v), st);
6740 else {
6741 fputs (sim_stop_messages [v], st);
6742
6743 if ((sim_vm_fprint_stopped != NULL) &&
6744 (!sim_vm_fprint_stopped (st, v)))
6745 return;
6746 }
6747
6748 (void)fprintf (st, ", %s: ", pc->name);
6749
6750 pcval = get_rval (pc, 0);
6751 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6752 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6753 else fprint_val (st, pcval, pc->radix, pc->width,
6754 pc->flags & REG_FMT);
6755 if ((dptr != NULL) && (dptr->examine != NULL)) {
6756 for (i = 0; i < sim_emax; i++)
6757 sim_eval[i] = 0;
6758 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6759 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6760 break;
6761 }
6762 if ((r == SCPE_OK) || (i > 0)) {
6763 (void)fprintf (st, " (");
6764 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6765 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6766 (void)fprintf (st, ")");
6767 }
6768 }
6769 (void)fprintf (st, "\r\n");
6770 return;
6771 }
6772
6773 void fprint_stopped (FILE *st, t_stat v)
6774 {
6775 #if defined(WIN_STDIO)
6776 (void)fflush(stderr);
6777 (void)fflush(stdout);
6778 #endif
6779 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6780 return;
6781 }
6782
6783
6784
6785
6786 t_stat step_svc (UNIT *uptr)
6787 {
6788 return SCPE_STEP;
6789 }
6790
6791
6792
6793
6794 t_stat expect_svc (UNIT *uptr)
6795 {
6796 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6797 }
6798
6799
6800
6801 void int_handler (int sig)
6802 {
6803 stop_cpu = 1;
6804 return;
6805 }
6806
6807
6808
6809 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6810 {
6811 char gbuf[CBUFSIZE];
6812 CONST char *gptr;
6813 CONST char *tptr = NULL;
6814 int32 opt;
6815 t_addr low, high;
6816 t_stat reason = SCPE_IERR;
6817 DEVICE *tdptr;
6818 REG *lowr, *highr;
6819 FILE *ofile;
6820
6821 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6822 if (flag == EX_E)
6823 opt = opt | CMD_OPT_OF;
6824 cptr = get_sim_opt (opt, cptr, &reason);
6825 if (NULL == cptr)
6826 return reason;
6827 if (*cptr == 0)
6828 return SCPE_2FARG;
6829 if (sim_dfunit == NULL)
6830 return SCPE_NXUN;
6831 cptr = get_glyph (cptr, gbuf, 0);
6832 if ((flag == EX_D) && (*cptr == 0))
6833
6834 return SCPE_2FARG;
6835 ofile = sim_ofile? sim_ofile: stdout;
6836
6837 for (gptr = gbuf, reason = SCPE_OK;
6838 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6839 tdptr = sim_dfdev;
6840 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6841 tptr = gptr + strlen ("STATE");
6842 if (*tptr && (*tptr++ != ','))
6843 return SCPE_ARG;
6844 if ((lowr = sim_dfdev->registers) == NULL)
6845 return SCPE_NXREG;
6846 for (highr = lowr; highr->name != NULL; highr++) ;
6847 sim_switches = sim_switches | SIM_SW_HIDE;
6848 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6849 lowr, --highr, 0, 0);
6850 continue;
6851 }
6852
6853
6854 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6855 (!(sim_opt_out & CMD_OPT_DFT) &&
6856 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6857 low = high = 0;
6858 if ((*tptr == '-') || (*tptr == ':')) {
6859 highr = find_reg (tptr + 1, &tptr, tdptr);
6860 if (highr == NULL)
6861 return SCPE_NXREG;
6862 }
6863 else {
6864 highr = lowr;
6865 if (*tptr == '[') {
6866 if (lowr->depth <= 1)
6867 return SCPE_ARG;
6868 tptr = get_range (NULL, tptr + 1, &low, &high,
6869 10, lowr->depth - 1, ']');
6870 if (tptr == NULL)
6871 return SCPE_ARG;
6872 }
6873 }
6874 if (*tptr && (*tptr++ != ','))
6875 return SCPE_ARG;
6876 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6877 lowr, highr, (uint32) low, (uint32) high);
6878 continue;
6879 }
6880
6881 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6882 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6883 sim_dfunit->capac - sim_dfdev->aincr), 0);
6884 if (tptr == NULL)
6885 return SCPE_ARG;
6886 if (*tptr && (*tptr++ != ','))
6887 return SCPE_ARG;
6888 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6889 sim_dfdev, sim_dfunit);
6890 }
6891 if (sim_ofile)
6892 fclose (sim_ofile);
6893 return reason;
6894 }
6895
6896
6897
6898
6899
6900
6901
6902 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6903 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6904 {
6905 t_stat reason;
6906 uint32 idx, val_start=lows;
6907 t_value val, last_val;
6908 REG *rptr;
6909
6910 if ((lowr == NULL) || (highr == NULL))
6911 return SCPE_IERR;
6912 if (lowr > highr)
6913 return SCPE_ARG;
6914 for (rptr = lowr; rptr <= highr; rptr++) {
6915 if ((sim_switches & SIM_SW_HIDE) &&
6916 (rptr->flags & REG_HIDDEN))
6917 continue;
6918 val = last_val = 0;
6919 for (idx = lows; idx <= highs; idx++) {
6920 if (idx >= rptr->depth)
6921 return SCPE_SUB;
6922 val = get_rval (rptr, idx);
6923 if (schptr && !test_search (&val, schptr))
6924 continue;
6925 if (flag == EX_E) {
6926 if ((idx > lows) && (val == last_val))
6927 continue;
6928 if (idx > val_start+1) {
6929 if (idx-1 == val_start+1) {
6930 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6931 if (reason != SCPE_OK)
6932 return reason;
6933 if (sim_log && (ofile == stdout))
6934 ex_reg (sim_log, val, flag, rptr, idx-1);
6935 }
6936 else {
6937 if (val_start+1 != idx-1) {
6938 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6939 if (sim_log && (ofile == stdout))
6940 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6941 }
6942 else {
6943 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6944 if (sim_log && (ofile == stdout))
6945 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6946 }
6947 }
6948 }
6949 sim_last_val = last_val = val;
6950 val_start = idx;
6951 reason = ex_reg (ofile, val, flag, rptr, idx);
6952 if (reason != SCPE_OK)
6953 return reason;
6954 if (sim_log && (ofile == stdout))
6955 ex_reg (sim_log, val, flag, rptr, idx);
6956 }
6957 if (flag != EX_E) {
6958 reason = dep_reg (flag, cptr, rptr, idx);
6959 if (reason != SCPE_OK)
6960 return reason;
6961 }
6962 }
6963 if ((flag == EX_E) && (val_start != highs)) {
6964 if (highs == val_start+1) {
6965 reason = ex_reg (ofile, val, flag, rptr, highs);
6966 if (reason != SCPE_OK)
6967 return reason;
6968 if (sim_log && (ofile == stdout))
6969 ex_reg (sim_log, val, flag, rptr, highs);
6970 }
6971 else {
6972 if (val_start+1 != highs) {
6973 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6974 if (sim_log && (ofile == stdout))
6975 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6976 }
6977 else {
6978 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6979 if (sim_log && (ofile == stdout))
6980 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6981 }
6982 }
6983 }
6984 }
6985 return SCPE_OK;
6986 }
6987
6988 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
6989 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6990 {
6991 t_addr i, mask;
6992 t_stat reason;
6993
6994 if (uptr->flags & UNIT_DIS)
6995 return SCPE_UDIS;
6996 mask = (t_addr) width_mask[dptr->awidth];
6997 if ((low > mask) || (high > mask) || (low > high))
6998 return SCPE_ARG;
6999 for (i = low; i <= high; ) {
7000 reason = get_aval (i, dptr, uptr);
7001 if (reason != SCPE_OK)
7002 return reason;
7003 if (schptr && !test_search (sim_eval, schptr))
7004 i = i + dptr->aincr;
7005 else {
7006 if (flag != EX_D) {
7007 reason = ex_addr (ofile, flag, i, dptr, uptr);
7008 if (reason > SCPE_OK)
7009 return reason;
7010 if (sim_log && (ofile == stdout))
7011 ex_addr (sim_log, flag, i, dptr, uptr);
7012 }
7013 else reason = 1 - dptr->aincr;
7014 if (flag != EX_E) {
7015 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7016 if (reason > SCPE_OK)
7017 return reason;
7018 }
7019 i = i + (1 - reason);
7020 }
7021 }
7022 return SCPE_OK;
7023 }
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
7038 {
7039 int32 rdx;
7040
7041 if (rptr == NULL)
7042 return SCPE_IERR;
7043 if (rptr->depth > 1)
7044 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7045 else
7046 (void)Fprintf (ofile, "%s:\t", rptr->name);
7047 if (!(flag & EX_E))
7048 return SCPE_OK;
7049 GET_RADIX (rdx, rptr->radix);
7050 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7051 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7052 else if (!(rptr->flags & REG_VMFLAGS) ||
7053 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7054 NULL, sim_switches | SIM_SW_REG) > 0)) {
7055 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7056 if (rptr->fields) {
7057 (void)Fprintf (ofile, "\t");
7058 fprint_fields (ofile, val, val, rptr->fields);
7059 }
7060 }
7061 if (flag & EX_I)
7062 (void)Fprintf (ofile, "\t");
7063 else
7064 (void)Fprintf (ofile, "\r\n");
7065 return SCPE_OK;
7066 }
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077 t_value get_rval (REG *rptr, uint32 idx)
7078 {
7079 size_t sz;
7080 t_value val;
7081 uint32 *ptr;
7082
7083 sz = SZ_R (rptr);
7084 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7085 idx = idx + rptr->qptr;
7086 if (idx >= rptr->depth) idx = idx - rptr->depth;
7087 }
7088 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7089 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7090 if (sz <= sizeof (uint32))
7091 val = *ptr;
7092 else val = *((t_uint64 *) ptr);
7093 }
7094 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7095 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7096 if (sz <= sizeof (uint32))
7097 val = *ptr;
7098 else val = *((t_uint64 *) ptr);
7099 }
7100 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7101 (sz == sizeof (uint8)))
7102 val = *(((uint8 *) rptr->loc) + idx);
7103 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7104 (sz == sizeof (uint16)))
7105 val = *(((uint16 *) rptr->loc) + idx);
7106 else if (sz <= sizeof (uint32))
7107 val = *(((uint32 *) rptr->loc) + idx);
7108 else val = *(((t_uint64 *) rptr->loc) + idx);
7109 val = (val >> rptr->offset) & width_mask[rptr->width];
7110 return val;
7111 }
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7125 {
7126 t_stat r;
7127 t_value val, mask;
7128 int32 rdx;
7129 CONST char *tptr;
7130 char gbuf[CBUFSIZE];
7131
7132 if ((cptr == NULL) || (rptr == NULL))
7133 return SCPE_IERR;
7134 if (rptr->flags & REG_RO)
7135 return SCPE_RO;
7136 if (flag & EX_I) {
7137 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7138 if (sim_log)
7139 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7140 if (cptr == NULL)
7141 return 1;
7142 if (*cptr == 0)
7143 return SCPE_OK;
7144 }
7145 mask = width_mask[rptr->width];
7146 GET_RADIX (rdx, rptr->radix);
7147 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7148 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7149 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7150 return SCPE_ARG;
7151 }
7152 else
7153 if (!(rptr->flags & REG_VMFLAGS) ||
7154 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7155 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7156 val = get_uint (cptr, rdx, mask, &r);
7157 if (r != SCPE_OK)
7158 return SCPE_ARG;
7159 }
7160 if ((rptr->flags & REG_NZ) && (val == 0))
7161 return SCPE_ARG;
7162 put_rval (rptr, idx, val);
7163 return SCPE_OK;
7164 }
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177 void put_rval (REG *rptr, uint32 idx, t_value val)
7178 {
7179 size_t sz;
7180 t_value mask;
7181 uint32 *ptr;
7182
7183 #define PUT_RVAL(sz,rp,id,v,m) \
7184 *(((sz *) rp->loc) + id) = \
7185 (sz)((*(((sz *) rp->loc) + id) & \
7186 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7187
7188 if (rptr == sim_PC)
7189 sim_brk_npc (0);
7190 sz = SZ_R (rptr);
7191 mask = width_mask[rptr->width];
7192 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7193 idx = idx + rptr->qptr;
7194 if (idx >= rptr->depth)
7195 idx = idx - rptr->depth;
7196 }
7197 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7198 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7199 if (sz <= sizeof (uint32))
7200 *ptr = (*ptr &
7201 ~(((uint32) mask) << rptr->offset)) |
7202 (((uint32) val) << rptr->offset);
7203 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7204 & ~(mask << rptr->offset)) | (val << rptr->offset);
7205 }
7206 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7207 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7208 if (sz <= sizeof (uint32))
7209 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7210 ~(((uint32) mask) << rptr->offset)) |
7211 (((uint32) val) << rptr->offset);
7212 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7213 & ~(mask << rptr->offset)) | (val << rptr->offset);
7214 }
7215 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7216 (sz == sizeof (uint8)))
7217 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7218 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7219 (sz == sizeof (uint16)))
7220 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7221 else if (sz <= sizeof (uint32))
7222 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7223 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7224 return;
7225 }
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7241 {
7242 t_stat reason;
7243 int32 rdx;
7244
7245 if (sim_vm_fprint_addr)
7246 sim_vm_fprint_addr (ofile, dptr, addr);
7247 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7248 (void)Fprintf (ofile, ":\t");
7249 if (!(flag & EX_E))
7250 return (1 - dptr->aincr);
7251
7252 GET_RADIX (rdx, dptr->dradix);
7253 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7254 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7255 reason = 1 - dptr->aincr;
7256 }
7257 if (flag & EX_I)
7258 (void)Fprintf (ofile, "\t");
7259 else
7260 (void)Fprintf (ofile, "\r\n");
7261 return reason;
7262 }
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7276 {
7277 int32 i;
7278 t_value mask;
7279 t_addr j, loc;
7280 size_t sz;
7281 t_stat reason = SCPE_OK;
7282
7283 if ((dptr == NULL) || (uptr == NULL))
7284 return SCPE_IERR;
7285 mask = width_mask[dptr->dwidth];
7286 for (i = 0; i < sim_emax; i++)
7287 sim_eval[i] = 0;
7288 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7289 if (dptr->examine != NULL) {
7290 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7291 if (reason != SCPE_OK)
7292 break;
7293 }
7294 else {
7295 if (!(uptr->flags & UNIT_ATT))
7296 return SCPE_UNATT;
7297 if (uptr->dynflags & UNIT_NO_FIO)
7298 return SCPE_NOFNC;
7299 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7300 reason = SCPE_NXM;
7301 break;
7302 }
7303 sz = SZ_D (dptr);
7304 loc = j / dptr->aincr;
7305 if (uptr->flags & UNIT_BUF) {
7306 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7307 }
7308 else {
7309 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7310 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7311 if ((feof (uptr->fileref)) &&
7312 !(uptr->flags & UNIT_FIX)) {
7313 reason = SCPE_EOF;
7314 break;
7315 }
7316 else if (ferror (uptr->fileref)) {
7317 clearerr (uptr->fileref);
7318 reason = SCPE_IOERR;
7319 break;
7320 }
7321 }
7322 }
7323 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7324 }
7325 if ((reason != SCPE_OK) && (i == 0))
7326 return reason;
7327 return SCPE_OK;
7328 }
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7345 UNIT *uptr, int32 dfltinc)
7346 {
7347 int32 i, count, rdx;
7348 t_addr j, loc;
7349 t_stat r, reason;
7350 t_value mask;
7351 size_t sz;
7352 char gbuf[CBUFSIZE];
7353
7354 if (dptr == NULL)
7355 return SCPE_IERR;
7356 if (flag & EX_I) {
7357 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7358 if (sim_log)
7359 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7360 if (cptr == NULL)
7361 return 1;
7362 if (*cptr == 0)
7363 return dfltinc;
7364 }
7365 if (uptr->flags & UNIT_RO)
7366 return SCPE_RO;
7367 mask = width_mask[dptr->dwidth];
7368
7369 GET_RADIX (rdx, dptr->dradix);
7370 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7371 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7372 if (reason != SCPE_OK)
7373 return reason;
7374 reason = dfltinc;
7375 }
7376 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7377
7378 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7379 sim_eval[i] = sim_eval[i] & mask;
7380 if (dptr->deposit != NULL) {
7381 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7382 if (r != SCPE_OK)
7383 return r;
7384 }
7385 else {
7386 if (!(uptr->flags & UNIT_ATT))
7387 return SCPE_UNATT;
7388 if (uptr->dynflags & UNIT_NO_FIO)
7389 return SCPE_NOFNC;
7390 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7391 return SCPE_NXM;
7392 sz = SZ_D (dptr);
7393 loc = j / dptr->aincr;
7394 if (uptr->flags & UNIT_BUF) {
7395 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7396 if (loc >= uptr->hwmark)
7397 uptr->hwmark = (uint32) loc + 1;
7398 }
7399 else {
7400 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7401 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7402 if (ferror (uptr->fileref)) {
7403 clearerr (uptr->fileref);
7404 return SCPE_IOERR;
7405 }
7406 }
7407 }
7408 }
7409 return reason;
7410 }
7411
7412
7413
7414 t_stat eval_cmd (int32 flg, CONST char *cptr)
7415 {
7416 if (!sim_dflt_dev)
7417 return SCPE_ARG;
7418 DEVICE *dptr = sim_dflt_dev;
7419 int32 i, rdx, a, lim;
7420 t_stat r;
7421
7422 GET_SWITCHES (cptr);
7423 GET_RADIX (rdx, dptr->dradix);
7424 for (i = 0; i < sim_emax; i++)
7425 sim_eval[i] = 0;
7426 if (*cptr == 0)
7427 return SCPE_2FARG;
7428 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7429 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7430 if (r != SCPE_OK)
7431 return r;
7432 }
7433 lim = 1 - r;
7434 for (i = a = 0; a < lim; ) {
7435 sim_printf ("%d:\t", a);
7436 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7437 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7438 if (sim_log) {
7439 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7440 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7441 }
7442 sim_printf ("\r\n");
7443 if (r < 0)
7444 a = a + 1 - r;
7445 else a = a + dptr->aincr;
7446 i = a / dptr->aincr;
7447 }
7448 return SCPE_OK;
7449 }
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464 char *read_line (char *cptr, int32 size, FILE *stream)
7465 {
7466 return read_line_p (NULL, cptr, size, stream);
7467 }
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7482 {
7483 char *tptr;
7484
7485 if (prompt) {
7486 #if defined(HAVE_LINEHISTORY)
7487 char *tmpc = linenoise (prompt);
7488 if (tmpc == NULL)
7489 cptr = NULL;
7490 else {
7491 strncpy (cptr, tmpc, size-1);
7492 linenoiseHistoryAdd (tmpc);
7493 FREE (tmpc);
7494 }
7495 }
7496 #else
7497 (void)fflush (stdout);
7498 (void)printf ("%s", prompt);
7499 (void)fflush (stdout);
7500 cptr = fgets (cptr, size, stream);
7501 }
7502 #endif
7503 else cptr = fgets (cptr, size, stream);
7504
7505 if (cptr == NULL) {
7506 clearerr (stream);
7507 return NULL;
7508 }
7509 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7510 if ((*tptr == '\n') || (*tptr == '\r') ||
7511 (tptr == (cptr + size - 1))) {
7512 *tptr = 0;
7513 break;
7514 }
7515 }
7516 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7517 memmove (cptr, cptr + 3, strlen (cptr + 3));
7518 while (sim_isspace (*cptr))
7519 cptr++;
7520 if ((*cptr == ';') || (*cptr == '#')) {
7521 if (sim_do_echo)
7522 sim_printf("%s> %s\r\n", do_position(), cptr);
7523 *cptr = 0;
7524 }
7525
7526 return cptr;
7527 }
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7548 {
7549 t_bool quoting = FALSE;
7550 t_bool escaping = FALSE;
7551 char quote_char = 0;
7552
7553 while ((*iptr != 0) &&
7554 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7555 if (quote) {
7556 if (quoting) {
7557 if (!escaping) {
7558 if (*iptr == escape_char)
7559 escaping = TRUE;
7560 else
7561 if (*iptr == quote_char)
7562 quoting = FALSE;
7563 }
7564 else
7565 escaping = FALSE;
7566 }
7567 else {
7568 if ((*iptr == '"') || (*iptr == '\'')) {
7569 quoting = TRUE;
7570 quote_char = *iptr;
7571 }
7572 }
7573 }
7574 if (sim_islower (*iptr) && uc)
7575 *optr = (char)toupper (*iptr);
7576 else *optr = *iptr;
7577 iptr++; optr++;
7578 }
7579 if (mchar && (*iptr == mchar))
7580 iptr++;
7581 *optr = 0;
7582 while (sim_isspace (*iptr))
7583 iptr++;
7584 return iptr;
7585 }
7586
7587 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7588 {
7589 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7590 }
7591
7592 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7593 {
7594 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7595 }
7596
7597 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7598 {
7599 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7600 }
7601
7602 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7603 {
7604
7605 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7606 strcpy (optr, "!");
7607 return (CONST char *)(iptr + 1);
7608 }
7609 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7610 }
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620 char *sim_trim_endspc (char *cptr)
7621 {
7622 char *tptr;
7623
7624 tptr = cptr + strlen (cptr);
7625 while ((--tptr >= cptr) && sim_isspace (*tptr))
7626 *tptr = 0;
7627 return cptr;
7628 }
7629
7630 int sim_isspace (char c)
7631 {
7632 return (c & 0x80) ? 0 : isspace (c);
7633 }
7634
7635 int sim_islower (char c)
7636 {
7637 return (c & 0x80) ? 0 : islower (c);
7638 }
7639
7640 int sim_isalpha (char c)
7641 {
7642 return (c & 0x80) ? 0 : isalpha (c);
7643 }
7644
7645 int sim_isprint (char c)
7646 {
7647 return (c & 0x80) ? 0 : isprint (c);
7648 }
7649
7650 int sim_isdigit (char c)
7651 {
7652 return (c & 0x80) ? 0 : isdigit (c);
7653 }
7654
7655 int sim_isgraph (char c)
7656 {
7657 return (c & 0x80) ? 0 : isgraph (c);
7658 }
7659
7660 int sim_isalnum (char c)
7661 {
7662 return (c & 0x80) ? 0 : isalnum (c);
7663 }
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7677 {
7678 t_value val;
7679 CONST char *tptr;
7680
7681 *status = SCPE_OK;
7682 val = strtotv ((CONST char *)cptr, &tptr, radix);
7683 if ((cptr == tptr) || (val > max))
7684 *status = SCPE_ARG;
7685 else {
7686 while (sim_isspace (*tptr)) tptr++;
7687 if (*tptr != 0)
7688 *status = SCPE_ARG;
7689 }
7690 return val;
7691 }
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7709 uint32 rdx, t_addr max, char term)
7710 {
7711 CONST char *tptr;
7712
7713 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7714 tptr = cptr + strlen ("ALL");
7715 *lo = 0;
7716 *hi = max;
7717 }
7718 else {
7719 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7720 ((cptr[1] == '\0') ||
7721 (cptr[1] == '-') ||
7722 (cptr[1] == ':') ||
7723 (cptr[1] == '/'))) {
7724 tptr = cptr + strlen (".");
7725 *lo = *hi = sim_last_addr;
7726 }
7727 else {
7728 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7729 tptr = cptr + strlen ("$");
7730 *hi = *lo = (t_addr)sim_last_val;
7731 }
7732 else {
7733 if (dptr && sim_vm_parse_addr)
7734 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7735 else
7736 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7737 if (cptr == tptr)
7738 return NULL;
7739 }
7740 }
7741 if ((*tptr == '-') || (*tptr == ':')) {
7742 cptr = tptr + 1;
7743 if (dptr && sim_vm_parse_addr)
7744 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7745 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7746 if (cptr == tptr)
7747 return NULL;
7748 if (*lo > *hi)
7749 return NULL;
7750 }
7751 else if (*tptr == '/') {
7752 cptr = tptr + 1;
7753 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7754 if ((cptr == tptr) || (*hi == 0))
7755 return NULL;
7756 *hi = *lo + *hi - 1;
7757 }
7758 else *hi = *lo;
7759 }
7760 sim_last_addr = *hi;
7761 if (term && (*tptr++ != term))
7762 return NULL;
7763 return tptr;
7764 }
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
7779
7780
7781
7782
7783
7784 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7785 {
7786 char quote_char;
7787 uint8 *ostart = optr;
7788
7789 *osize = 0;
7790 if ((strlen(iptr) == 1) ||
7791 (iptr[0] != iptr[strlen(iptr)-1]) ||
7792 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7793 return SCPE_ARG;
7794 quote_char = *iptr++;
7795 while (iptr[1]) {
7796 if (*iptr != '\\') {
7797 if (*iptr == quote_char)
7798 return SCPE_ARG;
7799 *(optr++) = (uint8)(*(iptr++));
7800 continue;
7801 }
7802 ++iptr;
7803 switch (*iptr) {
7804 case 'r':
7805 *(optr++) = 13; ++iptr;
7806 break;
7807 case 'n':
7808 *(optr++) = 10; ++iptr;
7809 break;
7810 case 'f':
7811 *(optr++) = 12; ++iptr;
7812 break;
7813 case 't':
7814 *(optr++) = 9; ++iptr;
7815 break;
7816 case 'v':
7817 *(optr++) = 11; ++iptr;
7818 break;
7819 case 'b':
7820 *(optr++) = 8; ++iptr;
7821 break;
7822 case '\\':
7823 *(optr++) = 92; ++iptr;
7824 break;
7825 case 'e':
7826 *(optr++) = 27; ++iptr;
7827 break;
7828 case '\'':
7829 *(optr++) = 39; ++iptr;
7830 break;
7831 case '"':
7832 *(optr++) = 34; ++iptr;
7833 break;
7834 case '?':
7835 *(optr++) = 63; ++iptr;
7836 break;
7837 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7838 *optr = *(iptr++) - '0';
7839 if ((*iptr >= '0') && (*iptr <= '7'))
7840 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7841 if ((*iptr >= '0') && (*iptr <= '7'))
7842 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7843 ++optr;
7844 break;
7845 case 'x':
7846 if (1) {
7847 static const char *hex_digits = "0123456789ABCDEF";
7848 const char *c;
7849
7850 ++iptr;
7851 *optr = 0;
7852 c = strchr (hex_digits, toupper(*iptr));
7853 if (c) {
7854 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7855 ++iptr;
7856 }
7857 c = strchr (hex_digits, toupper(*iptr));
7858 if (c) {
7859 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7860 ++iptr;
7861 }
7862 ++optr;
7863 }
7864 break;
7865 default:
7866 return SCPE_ARG;
7867 }
7868 }
7869 *optr = '\0';
7870 *osize = (uint32)(optr-ostart);
7871 return SCPE_OK;
7872 }
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7888 {
7889 size_t i;
7890 t_bool double_quote_found = FALSE;
7891 t_bool single_quote_found = FALSE;
7892 char quote = '"';
7893 char *tptr, *optr;
7894
7895 optr = (char *)malloc (4*size + 3);
7896 if (optr == NULL)
7897 return NULL;
7898 tptr = optr;
7899 for (i=0; i<size; i++)
7900 switch ((char)iptr[i]) {
7901 case '"':
7902 double_quote_found = TRUE;
7903 break;
7904 case '\'':
7905 single_quote_found = TRUE;
7906 break;
7907 }
7908 if (double_quote_found && (!single_quote_found))
7909 quote = '\'';
7910 *tptr++ = quote;
7911 while (size--) {
7912 switch (*iptr) {
7913 case '\r':
7914 *tptr++ = '\\'; *tptr++ = 'r'; break;
7915 case '\n':
7916 *tptr++ = '\\'; *tptr++ = 'n'; break;
7917 case '\f':
7918 *tptr++ = '\\'; *tptr++ = 'f'; break;
7919 case '\t':
7920 *tptr++ = '\\'; *tptr++ = 't'; break;
7921 case '\v':
7922 *tptr++ = '\\'; *tptr++ = 'v'; break;
7923 case '\b':
7924 *tptr++ = '\\'; *tptr++ = 'b'; break;
7925 case '\\':
7926 *tptr++ = '\\'; *tptr++ = '\\'; break;
7927 case '"':
7928 case '\'':
7929 if (quote == *iptr)
7930 *tptr++ = '\\';
7931
7932 default:
7933 if (sim_isprint (*iptr))
7934 *tptr++ = *iptr;
7935 else {
7936 (void)sprintf (tptr, "\\%03o", *iptr);
7937 tptr += 4;
7938 }
7939 break;
7940 }
7941 ++iptr;
7942 }
7943 *tptr++ = quote;
7944 *tptr++ = '\0';
7945 return optr;
7946 }
7947
7948 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
7949 {
7950 char *string;
7951
7952 string = sim_encode_quoted_string (buf, size);
7953 (void)fprintf (st, "%s", string);
7954 FREE (string);
7955 }
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965 DEVICE *find_dev (const char *cptr)
7966 {
7967 int32 i;
7968 DEVICE *dptr;
7969
7970 if (cptr == NULL)
7971 return NULL;
7972 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7973 if ((strcmp (cptr, dptr->name) == 0) ||
7974 (dptr->lname &&
7975 (strcmp (cptr, dptr->lname) == 0)))
7976 return dptr;
7977 }
7978 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7979 if ((strcmp (cptr, dptr->name) == 0) ||
7980 (dptr->lname &&
7981 (strcmp (cptr, dptr->lname) == 0)))
7982 return dptr;
7983 }
7984 return NULL;
7985 }
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998 DEVICE *find_unit (const char *cptr, UNIT **uptr)
7999 {
8000 uint32 i, u;
8001 const char *nptr;
8002 const char *tptr;
8003 t_stat r;
8004 DEVICE *dptr;
8005
8006 if (uptr == NULL)
8007 return NULL;
8008 *uptr = NULL;
8009 if ((dptr = find_dev (cptr))) {
8010 if (qdisable (dptr))
8011 return NULL;
8012 *uptr = dptr->units;
8013 return dptr;
8014 }
8015
8016 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8017 if (qdisable (dptr))
8018 continue;
8019 if (dptr->numunits &&
8020 (((nptr = dptr->name) &&
8021 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
8022 ((nptr = dptr->lname) &&
8023 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8024 tptr = cptr + strlen (nptr);
8025 if (sim_isdigit (*tptr)) {
8026 if (qdisable (dptr))
8027 return NULL;
8028 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8029 if (r != SCPE_OK)
8030 *uptr = NULL;
8031 else
8032 *uptr = dptr->units + u;
8033 return dptr;
8034 }
8035 }
8036 for (u = 0; u < dptr->numunits; u++) {
8037 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8038 *uptr = &dptr->units[u];
8039 return dptr;
8040 }
8041 }
8042 }
8043 return NULL;
8044 }
8045
8046
8047
8048
8049
8050
8051
8052 t_stat sim_register_internal_device (DEVICE *dptr)
8053 {
8054 uint32 i;
8055
8056 for (i = 0; (sim_devices[i] != NULL); i++)
8057 if (sim_devices[i] == dptr)
8058 return SCPE_OK;
8059 for (i = 0; i < sim_internal_device_count; i++)
8060 if (sim_internal_devices[i] == dptr)
8061 return SCPE_OK;
8062 ++sim_internal_device_count;
8063 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8064 if (!sim_internal_devices)
8065 {
8066 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8067 __func__, __FILE__, __LINE__);
8068 #if defined(USE_BACKTRACE)
8069 # if defined(SIGUSR2)
8070 (void)raise(SIGUSR2);
8071
8072 # endif
8073 #endif
8074 abort();
8075 }
8076 sim_internal_devices[sim_internal_device_count-1] = dptr;
8077 sim_internal_devices[sim_internal_device_count] = NULL;
8078 return SCPE_OK;
8079 }
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089 DEVICE *find_dev_from_unit (UNIT *uptr)
8090 {
8091 DEVICE *dptr;
8092 uint32 i, j;
8093
8094 if (uptr == NULL)
8095 return NULL;
8096 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8097 for (j = 0; j < dptr->numunits; j++) {
8098 if (uptr == (dptr->units + j))
8099 return dptr;
8100 }
8101 }
8102 for (i = 0; i<sim_internal_device_count; i++) {
8103 dptr = sim_internal_devices[i];
8104 for (j = 0; j < dptr->numunits; j++) {
8105 if (uptr == (dptr->units + j))
8106 return dptr;
8107 }
8108 }
8109 return NULL;
8110 }
8111
8112
8113
8114 t_bool qdisable (DEVICE *dptr)
8115 {
8116 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8117 }
8118
8119
8120
8121
8122
8123
8124
8125
8126
8127
8128
8129
8130
8131 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8132 {
8133 int32 i;
8134 DEVICE *dptr;
8135 REG *rptr, *srptr = NULL;
8136
8137 *gdptr = NULL;
8138 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8139 if (dptr->flags & DEV_DIS)
8140 continue;
8141 if ((rptr = find_reg (cptr, optr, dptr))) {
8142 if (srptr)
8143 return NULL;
8144 srptr = rptr;
8145 *gdptr = dptr;
8146 }
8147 }
8148 return srptr;
8149 }
8150
8151
8152
8153
8154
8155
8156
8157
8158
8159
8160
8161
8162 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8163 {
8164 CONST char *tptr;
8165 REG *rptr;
8166 size_t slnt;
8167
8168 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8169 return NULL;
8170 tptr = cptr;
8171 do {
8172 tptr++;
8173 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8174 slnt = tptr - cptr;
8175 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8176 if ((slnt == strlen (rptr->name)) &&
8177 (strncmp (cptr, rptr->name, slnt) == 0)) {
8178 if (optr != NULL)
8179 *optr = tptr;
8180 return rptr;
8181 }
8182 }
8183 return NULL;
8184 }
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195 int32 get_switches (const char *cptr)
8196 {
8197 int32 sw;
8198
8199 if (*cptr != '-')
8200 return 0;
8201 sw = 0;
8202 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8203 if (sim_isalpha (*cptr) == 0)
8204 return -1;
8205 sw = sw | SWMASK (toupper (*cptr));
8206 }
8207 return sw;
8208 }
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218
8219 CONST char *get_sim_sw (CONST char *cptr)
8220 {
8221 int32 lsw;
8222 char gbuf[CBUFSIZE];
8223
8224 while (*cptr == '-') {
8225 cptr = get_glyph (cptr, gbuf, 0);
8226 lsw = get_switches (gbuf);
8227 if (lsw <= 0)
8228 return NULL;
8229 sim_switches = sim_switches | lsw;
8230 }
8231 return cptr;
8232 }
8233
8234
8235
8236
8237
8238
8239
8240
8241
8242
8243
8244 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8245 {
8246 int32 t;
8247 char gbuf[CBUFSIZE];
8248 CONST char *svptr;
8249 DEVICE *tdptr;
8250 UNIT *tuptr;
8251
8252 sim_switches = 0;
8253 sim_ofile = NULL;
8254 sim_schrptr = NULL;
8255 sim_schaptr = NULL;
8256 sim_stabr.logic = sim_staba.logic = SCH_OR;
8257 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8258 sim_stabr.count = 1;
8259 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8260 if (!sim_stabr.mask)
8261 {
8262 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8263 __func__, __FILE__, __LINE__);
8264 #if defined(USE_BACKTRACE)
8265 # if defined(SIGUSR2)
8266 (void)raise(SIGUSR2);
8267
8268 # endif
8269 #endif
8270 abort();
8271 }
8272 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8273 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8274 if (!sim_stabr.comp)
8275 {
8276 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8277 __func__, __FILE__, __LINE__);
8278 #if defined(USE_BACKTRACE)
8279 # if defined(SIGUSR2)
8280 (void)raise(SIGUSR2);
8281
8282 # endif
8283 #endif
8284 abort();
8285 }
8286 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8287 sim_staba.count = sim_emax;
8288 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8289 if (!sim_staba.mask)
8290 {
8291 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8292 __func__, __FILE__, __LINE__);
8293 #if defined(USE_BACKTRACE)
8294 # if defined(SIGUSR2)
8295 (void)raise(SIGUSR2);
8296
8297 # endif
8298 #endif
8299 abort();
8300 }
8301 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8302 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8303 if (!sim_staba.comp)
8304 {
8305 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8306 __func__, __FILE__, __LINE__);
8307 #if defined(USE_BACKTRACE)
8308 # if defined(SIGUSR2)
8309 (void)raise(SIGUSR2);
8310
8311 # endif
8312 #endif
8313 abort();
8314 }
8315 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8316 if (! sim_dflt_dev)
8317 return NULL;
8318 sim_dfdev = sim_dflt_dev;
8319 sim_dfunit = sim_dfdev->units;
8320 sim_opt_out = 0;
8321 *st = SCPE_OK;
8322 while (*cptr) {
8323 svptr = cptr;
8324 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8325 if (sim_ofile) {
8326 fclose (sim_ofile);
8327 *st = SCPE_ARG;
8328 return NULL;
8329 }
8330 cptr = get_glyph (cptr + 1, gbuf, 0);
8331 sim_ofile = sim_fopen (gbuf, "a");
8332 if (sim_ofile == NULL) {
8333 *st = SCPE_OPENERR;
8334 return NULL;
8335 }
8336 sim_opt_out |= CMD_OPT_OF;
8337 continue;
8338 }
8339 cptr = get_glyph (cptr, gbuf, 0);
8340 if ((t = get_switches (gbuf)) != 0) {
8341 if (t < 0) {
8342 *st = SCPE_INVSW;
8343 return NULL;
8344 }
8345 sim_switches = sim_switches | t;
8346 }
8347 else if ((opt & CMD_OPT_SCH) &&
8348 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8349 sim_schrptr = &sim_stabr;
8350 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8351 sim_opt_out |= CMD_OPT_SCH;
8352 }
8353 else if ((opt & CMD_OPT_DFT) &&
8354 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8355 (tdptr = find_unit (gbuf, &tuptr)) &&
8356 (tuptr != NULL)) {
8357 sim_dfdev = tdptr;
8358 sim_dfunit = tuptr;
8359 sim_opt_out |= CMD_OPT_DFT;
8360 }
8361 else return svptr;
8362 }
8363 return cptr;
8364 }
8365
8366
8367
8368
8369
8370
8371
8372
8373
8374
8375
8376 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8377 {
8378 char *optr = buf;
8379 int32 bit;
8380
8381 (void)memset (buf, 0, bufsize);
8382 if ((sw == 0) || (bufsize < 3))
8383 return buf;
8384 --bufsize;
8385 *optr++ = '-';
8386 for (bit=0; bit <= ('Z'-'A'); bit++)
8387 if (sw & (1 << bit))
8388 if ((size_t)(optr - buf) < bufsize)
8389 *optr++ = 'A' + bit;
8390 return buf;
8391 }
8392
8393
8394
8395
8396
8397
8398
8399
8400
8401
8402
8403
8404 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8405 {
8406 int32 c;
8407 size_t logop, cmpop;
8408 t_value logval, cmpval;
8409 const char *sptr;
8410 CONST char *tptr;
8411 const char logstr[] = "|&^", cmpstr[] = "=!><";
8412
8413 const size_t invalid_op = (size_t) -1;
8414
8415 logval = cmpval = 0;
8416 if (*cptr == 0)
8417 return NULL;
8418
8419 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8420 if ((sptr = strchr (logstr, c))) {
8421 logop = sptr - logstr;
8422 logval = strtotv (cptr, &tptr, radix);
8423 if (cptr == tptr)
8424 return NULL;
8425 cptr = tptr;
8426 }
8427 else if ((sptr = strchr (cmpstr, c))) {
8428 cmpop = sptr - cmpstr;
8429 if (*cptr == '=') {
8430 cmpop = cmpop + strlen (cmpstr);
8431 cptr++;
8432 }
8433 cmpval = strtotv (cptr, &tptr, radix);
8434 if (cptr == tptr)
8435 return NULL;
8436 cptr = tptr;
8437 }
8438 else return NULL;
8439 }
8440 if (schptr->count != 1) {
8441 FREE (schptr->mask);
8442 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8443 FREE (schptr->comp);
8444 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8445 }
8446 if (logop != invalid_op) {
8447 schptr->logic = logop;
8448 schptr->mask[0] = logval;
8449 }
8450 if (cmpop != invalid_op) {
8451 schptr->boolop = cmpop;
8452 schptr->comp[0] = cmpval;
8453 }
8454 schptr->count = 1;
8455 return schptr;
8456 }
8457
8458
8459
8460
8461
8462
8463
8464
8465
8466
8467
8468
8469 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8470 {
8471 int32 c;
8472 size_t logop, cmpop;
8473 t_value *logval, *cmpval;
8474 t_stat reason = SCPE_OK;
8475 CONST char *ocptr = cptr;
8476 const char *sptr;
8477 char gbuf[CBUFSIZE];
8478 const char logstr[] = "|&^", cmpstr[] = "=!><";
8479
8480 const size_t invalid_op = (size_t) -1;
8481
8482 if (*cptr == 0)
8483 return NULL;
8484 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8485 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8486
8487 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8488 if (NULL != (sptr = strchr (logstr, c))) {
8489 logop = sptr - logstr;
8490 cptr = get_glyph (cptr, gbuf, 0);
8491 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8492 if (reason > 0) {
8493 FREE (logval);
8494 FREE (cmpval);
8495 return get_rsearch (ocptr, radix, schptr);
8496 }
8497 }
8498 else if (NULL != (sptr = strchr (cmpstr, c))) {
8499 cmpop = sptr - cmpstr;
8500 if (*cptr == '=') {
8501 cmpop = cmpop + strlen (cmpstr);
8502 cptr++;
8503 }
8504 cptr = get_glyph (cptr, gbuf, 0);
8505 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8506 if (reason > 0) {
8507 FREE (logval);
8508 FREE (cmpval);
8509 return get_rsearch (ocptr, radix, schptr);
8510 }
8511 }
8512 else {
8513 FREE (logval);
8514 FREE (cmpval);
8515 return NULL;
8516 }
8517 }
8518 if (schptr->count != (uint32)(1 - reason)) {
8519 schptr->count = 1 - reason;
8520 FREE (schptr->mask);
8521 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8522 FREE (schptr->comp);
8523 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8524 }
8525 if (logop != invalid_op) {
8526 schptr->logic = logop;
8527 FREE (schptr->mask);
8528 schptr->mask = logval;
8529 }
8530 else {
8531 FREE (logval);
8532 }
8533 if (cmpop != invalid_op) {
8534 schptr->boolop = cmpop;
8535 FREE (schptr->comp);
8536 schptr->comp = cmpval;
8537 }
8538 else {
8539 FREE (cmpval);
8540 }
8541 return schptr;
8542 }
8543
8544
8545
8546
8547
8548
8549
8550
8551
8552
8553 int32 test_search (t_value *values, SCHTAB *schptr)
8554 {
8555 t_value *val = NULL;
8556 int32 i, updown;
8557 int32 ret = 0;
8558
8559 if (schptr == NULL)
8560 return ret;
8561
8562 val = (t_value *)malloc (schptr->count * sizeof (*values));
8563 if (!val)
8564 {
8565 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8566 __func__, __FILE__, __LINE__);
8567 #if defined(USE_BACKTRACE)
8568 # if defined(SIGUSR2)
8569 (void)raise(SIGUSR2);
8570
8571 # endif
8572 #endif
8573 abort();
8574 }
8575 for (i=0; i<(int32)schptr->count; i++) {
8576 val[i] = values[i];
8577 switch (schptr->logic) {
8578
8579 case SCH_OR:
8580 val[i] = val[i] | schptr->mask[i];
8581 break;
8582
8583 case SCH_AND:
8584 val[i] = val[i] & schptr->mask[i];
8585 break;
8586
8587 case SCH_XOR:
8588 val[i] = val[i] ^ schptr->mask[i];
8589 break;
8590 }
8591 }
8592
8593 ret = 1;
8594 if (1) {
8595 updown = -1;
8596 i=schptr->count-1;
8597 }
8598 else {
8599 updown = 1;
8600 i=0;
8601 }
8602 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8603 switch (schptr->boolop) {
8604
8605 case SCH_E: case SCH_EE:
8606 if (val[i] != schptr->comp[i])
8607 ret = 0;
8608 break;
8609
8610 case SCH_N: case SCH_NE:
8611 if (val[i] == schptr->comp[i])
8612 ret = 0;
8613 break;
8614
8615 case SCH_G:
8616 if (val[i] <= schptr->comp[i])
8617 ret = 0;
8618 break;
8619
8620 case SCH_GE:
8621 if (val[i] < schptr->comp[i])
8622 ret = 0;
8623 break;
8624
8625 case SCH_L:
8626 if (val[i] >= schptr->comp[i])
8627 ret = 0;
8628 break;
8629
8630 case SCH_LE:
8631 if (val[i] > schptr->comp[i])
8632 ret = 0;
8633 break;
8634 }
8635 }
8636 FREE (val);
8637 return ret;
8638 }
8639
8640
8641
8642
8643
8644
8645
8646
8647
8648
8649
8650
8651
8652
8653
8654 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8655 {
8656 int32 nodigit;
8657 t_value val;
8658 uint32 c, digit;
8659
8660 *endptr = inptr;
8661 if ((radix < 2) || (radix > 36))
8662 return 0;
8663 while (sim_isspace (*inptr))
8664 inptr++;
8665 val = 0;
8666 nodigit = 1;
8667 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8668 if (sim_islower (c))
8669 c = toupper (c);
8670 if (sim_isdigit (c))
8671 digit = c - (uint32) '0';
8672 else if (radix <= 10)
8673 break;
8674 else digit = c + 10 - (uint32) 'A';
8675 if (digit >= radix)
8676 return 0;
8677 val = (val * radix) + digit;
8678 nodigit = 0;
8679 }
8680 if (nodigit)
8681 return 0;
8682 *endptr = inptr;
8683 return val;
8684 }
8685
8686
8687
8688
8689
8690
8691
8692
8693
8694
8695
8696
8697
8698
8699
8700 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8701 size_t width, uint32 format)
8702 {
8703 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8704 t_value owtest, wtest;
8705 size_t d;
8706 size_t digit;
8707 size_t ndigits;
8708 size_t commas = 0;
8709 char dbuf[MAX_WIDTH + 1];
8710
8711 for (d = 0; d < MAX_WIDTH; d++)
8712 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8713 dbuf[MAX_WIDTH] = 0;
8714 d = MAX_WIDTH;
8715 do {
8716 d = d - 1;
8717 digit = val % radix;
8718 val = val / radix;
8719 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8720 } while ((d > 0) && (val != 0));
8721
8722 switch (format) {
8723 case PV_LEFT:
8724 break;
8725 case PV_RZRO:
8726 wtest = owtest = radix;
8727 ndigits = 1;
8728 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8729 owtest = wtest;
8730 wtest = wtest * radix;
8731 ndigits = ndigits + 1;
8732 }
8733 if ((MAX_WIDTH - (ndigits + commas)) < d)
8734 d = MAX_WIDTH - (ndigits + commas);
8735 break;
8736 }
8737 if (NULL == buffer)
8738 return ((t_stat) strlen(dbuf+d));
8739 *buffer = '\0';
8740 if (width < strlen(dbuf+d))
8741 return SCPE_IOERR;
8742 strcpy(buffer, dbuf+d);
8743 return SCPE_OK;
8744 }
8745
8746 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8747 uint32 width, uint32 format)
8748 {
8749 char dbuf[MAX_WIDTH + 1];
8750
8751 if (!stream)
8752 return sprint_val (NULL, val, radix, width, format);
8753 if (width > MAX_WIDTH)
8754 width = MAX_WIDTH;
8755 sprint_val (dbuf, val, radix, width, format);
8756 if (Fprintf (stream, "%s", dbuf) < 0)
8757 return SCPE_IOERR;
8758 return SCPE_OK;
8759 }
8760
8761 const char *sim_fmt_secs (double seconds)
8762 {
8763 static char buf[60];
8764 char frac[16] = "";
8765 const char *sign = "";
8766 double val = seconds;
8767 double days, hours, mins, secs, msecs, usecs;
8768
8769 if (val == 0.0)
8770 return "";
8771 if (val < 0.0) {
8772 sign = "-";
8773 val = -val;
8774 }
8775 days = floor (val / (24.0*60.0*60.0));
8776 val -= (days * 24.0*60.0*60.0);
8777 hours = floor (val / (60.0*60.0));
8778 val -= (hours * 60.0 * 60.0);
8779 mins = floor (val / 60.0);
8780 val -= (mins * 60.0);
8781 secs = floor (val);
8782 val -= secs;
8783 val *= 1000.0;
8784 msecs = floor (val);
8785 val -= msecs;
8786 val *= 1000.0;
8787 usecs = floor (val+0.5);
8788 if (usecs == 1000.0) {
8789 usecs = 0.0;
8790 msecs += 1;
8791 }
8792 if ((msecs > 0.0) || (usecs > 0.0)) {
8793 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8794 while (frac[strlen (frac) - 1] == '0')
8795 frac[strlen (frac) - 1] = '\0';
8796 if (strlen (frac) == 1)
8797 frac[0] = '\0';
8798 }
8799 if (days > 0)
8800 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8801 sign, days, (days != 1) ? "s" : "", hours, mins,
8802 secs, frac, (days == 1) ? "s" : "");
8803 else
8804 if (hours > 0)
8805 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8806 sign, hours, mins, secs, frac);
8807 else
8808 if (mins > 0)
8809 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8810 sign, mins, secs, frac);
8811 else
8812 if (secs > 0)
8813 (void)sprintf (buf, "%s%.0f%s second",
8814 sign, secs, frac);
8815 else
8816 if (msecs > 0) {
8817 if (usecs > 0)
8818 (void)sprintf (buf, "%s%.0f.%s msec",
8819 sign, msecs, frac+4);
8820 else
8821 (void)sprintf (buf, "%s%.0f msec",
8822 sign, msecs);
8823 }
8824 else
8825 (void)sprintf (buf, "%s%.0f usec",
8826 sign, usecs);
8827 if (0 != strncmp ("1 ", buf, 2))
8828 strcpy (&buf[strlen (buf)], "s");
8829 return buf;
8830 }
8831
8832
8833
8834
8835
8836
8837
8838
8839
8840
8841
8842
8843
8844
8845
8846
8847 t_stat sim_process_event (void)
8848 {
8849 UNIT *uptr;
8850 t_stat reason;
8851 #if defined(TESTING)
8852 cpu_state_t * cpup = _cpup;
8853 #endif
8854
8855 if (stop_cpu)
8856 {
8857 #if defined(WIN_STDIO)
8858 (void)fflush(stdout);
8859 (void)fflush(stderr);
8860 #endif
8861 return SCPE_STOP;
8862 }
8863 UPDATE_SIM_TIME;
8864
8865 if (sim_clock_queue == QUEUE_LIST_END) {
8866 sim_interval = noqueue_time = NOQUEUE_WAIT;
8867 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8868 "Queue Empty New Interval = %d\r\n",
8869 sim_interval);
8870 return SCPE_OK;
8871 }
8872 sim_processing_event = TRUE;
8873 do {
8874 uptr = sim_clock_queue;
8875 sim_clock_queue = uptr->next;
8876 uptr->next = NULL;
8877 sim_interval -= uptr->time;
8878 uptr->time = 0;
8879 if (sim_clock_queue != QUEUE_LIST_END)
8880 sim_interval = sim_clock_queue->time;
8881 else
8882 sim_interval = noqueue_time = NOQUEUE_WAIT;
8883 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8884 "Processing Event for %s\r\n", sim_uname (uptr));
8885 if (uptr->action != NULL)
8886 reason = uptr->action (uptr);
8887 else
8888 reason = SCPE_OK;
8889 } while ((reason == SCPE_OK) &&
8890 (sim_interval <= 0) &&
8891 (sim_clock_queue != QUEUE_LIST_END) &&
8892 (!stop_cpu));
8893
8894 if (sim_clock_queue == QUEUE_LIST_END) {
8895 sim_interval = noqueue_time = NOQUEUE_WAIT;
8896 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8897 "Processing Queue Complete New Interval = %d\r\n",
8898 sim_interval);
8899 }
8900 else
8901 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8902 "Processing Queue Complete New Interval = %d(%s)\r\n",
8903 sim_interval, sim_uname(sim_clock_queue));
8904
8905 if ((reason == SCPE_OK) && stop_cpu)
8906 {
8907 #if defined(WIN_STDIO)
8908 (void)fflush(stdout);
8909 (void)fflush(stderr);
8910 #endif
8911 reason = SCPE_STOP;
8912 }
8913 sim_processing_event = FALSE;
8914 return reason;
8915 }
8916
8917
8918
8919
8920
8921
8922
8923
8924
8925
8926 t_stat sim_activate (UNIT *uptr, int32 event_time)
8927 {
8928 if (uptr->dynflags & UNIT_TMR_UNIT)
8929 return sim_timer_activate (uptr, event_time);
8930 return _sim_activate (uptr, event_time);
8931 }
8932
8933 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8934 {
8935 UNIT *cptr, *prvptr;
8936 int32 accum;
8937 #if defined(TESTING)
8938 cpu_state_t * cpup = _cpup;
8939 #endif
8940
8941 if (sim_is_active (uptr))
8942 return SCPE_OK;
8943 UPDATE_SIM_TIME;
8944
8945 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
8946
8947 prvptr = NULL;
8948 accum = 0;
8949 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8950 if (event_time < (accum + cptr->time))
8951 break;
8952 accum = accum + cptr->time;
8953 prvptr = cptr;
8954 }
8955 if (prvptr == NULL) {
8956 cptr = uptr->next = sim_clock_queue;
8957 sim_clock_queue = uptr;
8958 }
8959 else {
8960 cptr = uptr->next = prvptr->next;
8961 prvptr->next = uptr;
8962 }
8963 uptr->time = event_time - accum;
8964 if (cptr != QUEUE_LIST_END)
8965 cptr->time = cptr->time - uptr->time;
8966 sim_interval = sim_clock_queue->time;
8967 return SCPE_OK;
8968 }
8969
8970
8971
8972
8973
8974
8975
8976
8977
8978
8979 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
8980 {
8981 sim_cancel (uptr);
8982 return _sim_activate (uptr, event_time);
8983 }
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
8995 {
8996 return _sim_activate_after (uptr, usec_delay);
8997 }
8998
8999 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
9000 {
9001 if (sim_is_active (uptr))
9002 return SCPE_OK;
9003 return sim_timer_activate_after (uptr, usec_delay);
9004 }
9005
9006
9007
9008
9009
9010
9011
9012
9013
9014
9015 t_stat sim_cancel (UNIT *uptr)
9016 {
9017 UNIT *cptr, *nptr;
9018 #if defined(TESTING)
9019 cpu_state_t * cpup = _cpup;
9020 #endif
9021
9022 if (sim_clock_queue == QUEUE_LIST_END)
9023 return SCPE_OK;
9024 if (!sim_is_active (uptr))
9025 return SCPE_OK;
9026 UPDATE_SIM_TIME;
9027 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9028 nptr = QUEUE_LIST_END;
9029
9030 if (sim_clock_queue == uptr) {
9031 nptr = sim_clock_queue = uptr->next;
9032 uptr->next = NULL;
9033 }
9034 else {
9035 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9036 if (cptr->next == uptr) {
9037 nptr = cptr->next = uptr->next;
9038 uptr->next = NULL;
9039 break;
9040 }
9041 }
9042 }
9043 if (nptr != QUEUE_LIST_END)
9044 nptr->time += (uptr->next) ? 0 : uptr->time;
9045 if (!uptr->next)
9046 uptr->time = 0;
9047 if (sim_clock_queue != QUEUE_LIST_END)
9048 sim_interval = sim_clock_queue->time;
9049 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9050 if (uptr->next) {
9051 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9052 if (sim_deb)
9053 fclose(sim_deb);
9054 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9055 __func__, __FILE__, __LINE__);
9056 abort ();
9057 }
9058 return SCPE_OK;
9059 }
9060
9061
9062
9063
9064
9065
9066
9067
9068
9069 t_bool sim_is_active (UNIT *uptr)
9070 {
9071 if (uptr->next == NULL)
9072 return FALSE;
9073 else
9074 return TRUE;
9075 }
9076
9077
9078
9079
9080
9081
9082
9083
9084
9085 int32 sim_activate_time (UNIT *uptr)
9086 {
9087 UNIT *cptr;
9088 int32 accum = 0;
9089
9090 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9091 if (cptr == sim_clock_queue) {
9092 if (sim_interval > 0)
9093 accum = accum + sim_interval;
9094 }
9095 else
9096 accum = accum + cptr->time;
9097 if (cptr == uptr)
9098 return accum + 1;
9099 }
9100 return 0;
9101 }
9102
9103
9104
9105
9106
9107
9108
9109
9110 double sim_gtime (void)
9111 {
9112 return sim_time;
9113 }
9114
9115
9116
9117
9118
9119
9120
9121
9122 int32 sim_qcount (void)
9123 {
9124 int32 cnt;
9125 UNIT *uptr;
9126
9127 cnt = 0;
9128 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9129 cnt++;
9130 return cnt;
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
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
9166
9167
9168 t_stat sim_brk_init (void)
9169 {
9170 int32 i;
9171
9172 for (i=0; i<sim_brk_lnt; i++) {
9173 BRKTAB *bp;
9174 if (sim_brk_tab)
9175 {
9176 bp = sim_brk_tab[i];
9177
9178 while (bp)
9179 {
9180 BRKTAB *bpt = bp->next;
9181
9182 FREE (bp->act);
9183 FREE (bp);
9184 bp = bpt;
9185 }
9186 }
9187 }
9188 if (sim_brk_tab != NULL)
9189 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9190 sim_brk_lnt = SIM_BRK_INILNT;
9191 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9192 if (sim_brk_tab == NULL)
9193 return SCPE_MEM;
9194 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9195 sim_brk_ent = sim_brk_ins = 0;
9196 sim_brk_clract ();
9197 sim_brk_npc (0);
9198 return SCPE_OK;
9199 }
9200
9201
9202
9203 BRKTAB *sim_brk_fnd (t_addr loc)
9204 {
9205 int32 lo, hi, p;
9206 BRKTAB *bp;
9207
9208 if (sim_brk_ent == 0) {
9209 sim_brk_ins = 0;
9210 return NULL;
9211 }
9212 lo = 0;
9213 hi = sim_brk_ent - 1;
9214 do {
9215 p = (lo + hi) >> 1;
9216 bp = sim_brk_tab[p];
9217 if (loc == bp->addr) {
9218 sim_brk_ins = p;
9219 return bp;
9220 }
9221 else if (loc < bp->addr)
9222 hi = p - 1;
9223 else lo = p + 1;
9224 } while (lo <= hi);
9225 if (loc < bp->addr)
9226 sim_brk_ins = p;
9227 else sim_brk_ins = p + 1;
9228 return NULL;
9229 }
9230
9231 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9232 {
9233 BRKTAB *bp = sim_brk_fnd (loc);
9234
9235 while (bp) {
9236 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9237 (bp->typ == btyp))
9238 return bp;
9239 bp = bp->next;
9240 }
9241 return bp;
9242 }
9243
9244
9245
9246 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9247 {
9248 int32 i, t;
9249 BRKTAB *bp, **newp;
9250
9251 if (sim_brk_ins < 0)
9252 return NULL;
9253 if (sim_brk_ent >= sim_brk_lnt) {
9254 t = sim_brk_lnt + SIM_BRK_INILNT;
9255 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9256 if (newp == NULL)
9257 return NULL;
9258 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9259 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9260 FREE (sim_brk_tab);
9261 sim_brk_tab = newp;
9262 sim_brk_lnt = t;
9263 }
9264 if ((sim_brk_ins == sim_brk_ent) ||
9265 ((sim_brk_ins != sim_brk_ent) &&
9266 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9267 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9268 sim_brk_tab[i] = sim_brk_tab[i - 1];
9269 sim_brk_tab[sim_brk_ins] = NULL;
9270 }
9271 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9272 if (!bp)
9273 {
9274 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9275 __func__, __FILE__, __LINE__);
9276 #if defined(USE_BACKTRACE)
9277 # if defined(SIGUSR2)
9278 (void)raise(SIGUSR2);
9279
9280 # endif
9281 #endif
9282 abort();
9283 }
9284 bp->next = sim_brk_tab[sim_brk_ins];
9285 sim_brk_tab[sim_brk_ins] = bp;
9286 if (bp->next == NULL)
9287 sim_brk_ent += 1;
9288 bp->addr = loc;
9289 bp->typ = btyp;
9290 bp->cnt = 0;
9291 bp->act = NULL;
9292 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9293 bp->time_fired[i] = -1.0;
9294 return bp;
9295 }
9296
9297
9298
9299 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9300 {
9301 BRKTAB *bp;
9302
9303 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9304 sw |= sim_brk_dflt;
9305 if (~sim_brk_types & sw) {
9306 char gbuf[CBUFSIZE];
9307
9308 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9309 }
9310 if ((sw & BRK_TYP_DYN_ALL) && act)
9311 return SCPE_ARG;
9312 bp = sim_brk_fnd (loc);
9313 if (!bp)
9314 bp = sim_brk_new (loc, sw);
9315 else {
9316 while (bp && (bp->typ != (uint32)sw))
9317 bp = bp->next;
9318 if (!bp)
9319 bp = sim_brk_new (loc, sw);
9320 }
9321 if (!bp)
9322 return SCPE_MEM;
9323 bp->cnt = ncnt;
9324 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9325 (bp->act != NULL) && (act != NULL)) {
9326 FREE (bp->act);
9327 bp->act = NULL;
9328 }
9329 if ((act != NULL) && (*act != 0)) {
9330 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9331 if (newp == NULL)
9332 return SCPE_MEM;
9333 strncpy (newp, act, CBUFSIZE);
9334 bp->act = newp;
9335 }
9336 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9337 return SCPE_OK;
9338 }
9339
9340
9341
9342 t_stat sim_brk_clr (t_addr loc, int32 sw)
9343 {
9344 BRKTAB *bpl = NULL;
9345 BRKTAB *bp = sim_brk_fnd (loc);
9346 int32 i;
9347
9348 if (!bp)
9349 return SCPE_OK;
9350 if (sw == 0)
9351 sw = SIM_BRK_ALLTYP;
9352
9353 #if !defined(__clang_analyzer__)
9354 while (bp) {
9355 if (bp->typ == (bp->typ & sw)) {
9356 FREE (bp->act);
9357 if (bp == sim_brk_tab[sim_brk_ins])
9358 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9359 else
9360 {
9361 if (bpl)
9362 bpl->next = bp->next;
9363 }
9364 FREE (bp);
9365 bp = bpl;
9366 }
9367 else {
9368 bpl = bp;
9369 bp = bp->next;
9370 }
9371 }
9372 #endif
9373 if (sim_brk_tab[sim_brk_ins] == NULL) {
9374 sim_brk_ent = sim_brk_ent - 1;
9375 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9376 sim_brk_tab[i] = sim_brk_tab[i+1];
9377 }
9378 sim_brk_summ = 0;
9379 for (i = 0; i < sim_brk_ent; i++) {
9380 bp = sim_brk_tab[i];
9381 while (bp) {
9382 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9383 bp = bp->next;
9384 }
9385 }
9386 return SCPE_OK;
9387 }
9388
9389
9390
9391 t_stat sim_brk_clrall (int32 sw)
9392 {
9393 int32 i;
9394
9395 if (sw == 0)
9396 sw = SIM_BRK_ALLTYP;
9397 for (i = 0; i < sim_brk_ent;) {
9398 t_addr loc = sim_brk_tab[i]->addr;
9399 sim_brk_clr (loc, sw);
9400 if ((i < sim_brk_ent) &&
9401 (loc == sim_brk_tab[i]->addr))
9402 ++i;
9403 }
9404 return SCPE_OK;
9405 }
9406
9407
9408
9409 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9410 {
9411 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9412 DEVICE *dptr;
9413 uint32 i, any;
9414
9415 if ((sw == 0) || (sw == SWMASK ('C'))) {
9416 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9417 if (!bp || (!(bp->typ & sw))) {
9418 return SCPE_OK; }
9419 dptr = sim_dflt_dev;
9420 if (dptr == NULL) {
9421 return SCPE_OK; }
9422 if (sw & SWMASK ('C')) {
9423 if (st != NULL) {
9424 (void)fprintf (st, "SET BREAK "); }
9425 } else {
9426 if (sim_vm_fprint_addr) {
9427 sim_vm_fprint_addr
9428 (st, dptr, loc);
9429 } else {
9430 fprint_val
9431 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9432 if (st != NULL) {
9433 (void)fprintf (st, ":\t"); }
9434 }
9435 for (i = any = 0; i < 26; i++) {
9436 if ((bp->typ >> i) & 1) {
9437 if ((sw & SWMASK ('C')) == 0) {
9438 if (any) {
9439 if (st != NULL) {
9440 (void)fprintf (st, ", "); } }
9441 if (st != NULL) {
9442 fputc (i + 'A', st); }
9443 }
9444 } else {
9445 if (st != NULL) {
9446 (void)fprintf (st, "-%c", i + 'A'); }
9447 any = 1;
9448 }
9449 }
9450 if (sw & SWMASK ('C')) {
9451 if (st != NULL) {
9452 (void)fprintf (st, " "); }
9453 if (sim_vm_fprint_addr) {
9454 if (st != NULL) {
9455 sim_vm_fprint_addr (st, dptr, loc); }
9456 } else {
9457 fprint_val
9458 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9459 }
9460 if (bp->cnt > 0) {
9461 if (st != NULL) {
9462 (void)fprintf (st, "[%d]", bp->cnt); } }
9463 if (bp->act != NULL) {
9464 if (st != NULL) {
9465 (void)fprintf (st, "; %s", bp->act); } }
9466 (void)fprintf (st, "\r\n");
9467 return SCPE_OK;
9468 }
9469
9470
9471
9472 t_stat sim_brk_showall (FILE *st, uint32 sw)
9473 {
9474 int32 bit, mask, types;
9475 BRKTAB **bpt;
9476
9477 if ((sw == 0) || (sw == SWMASK ('C')))
9478 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9479 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9480 if (sim_brk_types & (1 << bit))
9481 ++types;
9482 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9483 (void)fprintf (st, "Supported Breakpoint Types:");
9484 for (bit=0; bit <= ('Z'-'A'); bit++)
9485 if (sim_brk_types & (1 << bit))
9486 (void)fprintf (st, " -%c", 'A' + bit);
9487 (void)fprintf (st, "\r\n");
9488 }
9489 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9490 mask = (sw & sim_brk_types);
9491 (void)fprintf (st, "Displaying Breakpoint Types:");
9492 for (bit=0; bit <= ('Z'-'A'); bit++)
9493 if (mask & (1 << bit))
9494 (void)fprintf (st, " -%c", 'A' + bit);
9495 (void)fprintf (st, "\r\n");
9496 }
9497 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9498 BRKTAB *prev = NULL;
9499 BRKTAB *cur = *bpt;
9500 BRKTAB *next;
9501
9502 while (cur) {
9503 next = cur->next;
9504 cur->next = prev;
9505 prev = cur;
9506 cur = next;
9507 }
9508
9509 *bpt = prev;
9510
9511 cur = prev;
9512 while (cur) {
9513 if (cur->typ & sw)
9514 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9515 cur = cur->next;
9516 }
9517
9518 cur = prev;
9519 prev = NULL;
9520 while (cur) {
9521 next = cur->next;
9522 cur->next = prev;
9523 prev = cur;
9524 cur = next;
9525 }
9526
9527 *bpt = prev;
9528 }
9529 return SCPE_OK;
9530 }
9531
9532
9533
9534 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9535 {
9536 BRKTAB *bp;
9537 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9538
9539 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9540 btyp |= BRK_TYP_DYN_ALL;
9541
9542 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9543 double s_gtime = sim_gtime ();
9544
9545 if (bp->time_fired[spc] == s_gtime)
9546 return 0;
9547 bp->time_fired[spc] = s_gtime;
9548 if (--bp->cnt > 0)
9549 return 0;
9550 bp->cnt = 0;
9551 sim_brk_setact (bp->act);
9552 sim_brk_match_type = btyp & bp->typ;
9553 if (bp->typ & BRK_TYP_TEMP)
9554 sim_brk_clr (loc, bp->typ);
9555 sim_brk_match_addr = loc;
9556 return sim_brk_match_type;
9557 }
9558 return 0;
9559 }
9560
9561
9562
9563 CONST char *sim_brk_getact (char *buf, int32 size)
9564 {
9565 char *ep;
9566 size_t lnt;
9567
9568 if (sim_brk_act[sim_do_depth] == NULL)
9569 return NULL;
9570 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9571 sim_brk_act[sim_do_depth]++;
9572 if (*sim_brk_act[sim_do_depth] == 0) {
9573 return sim_brk_clract ();
9574 }
9575 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9576 lnt = ep - sim_brk_act[sim_do_depth];
9577 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9578 buf[lnt] = 0;
9579 sim_brk_act[sim_do_depth] += lnt + 1;
9580 }
9581 else {
9582 strncpy (buf, sim_brk_act[sim_do_depth], size);
9583 sim_brk_clract ();
9584 }
9585 return buf;
9586 }
9587
9588
9589
9590 char *sim_brk_clract (void)
9591 {
9592 FREE (sim_brk_act_buf[sim_do_depth]);
9593 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9594 }
9595
9596
9597
9598 void sim_brk_setact (const char *action)
9599 {
9600 if (action) {
9601 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9602 if (!sim_brk_act_buf[sim_do_depth])
9603 {
9604 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9605 __func__, __FILE__, __LINE__);
9606 #if defined(USE_BACKTRACE)
9607 # if defined(SIGUSR2)
9608 (void)raise(SIGUSR2);
9609
9610 # endif
9611 #endif
9612 abort();
9613 }
9614 strcpy (sim_brk_act_buf[sim_do_depth], action);
9615 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9616 }
9617 else
9618 sim_brk_clract ();
9619 }
9620
9621
9622
9623 void sim_brk_npc (uint32 cnt)
9624 {
9625 uint32 spc;
9626 BRKTAB **bpt, *bp;
9627
9628 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9629 cnt = SIM_BKPT_N_SPC;
9630 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9631 for (bp = *bpt; bp; bp = bp->next) {
9632 for (spc = 0; spc < cnt; spc++)
9633 bp->time_fired[spc] = -1.0;
9634 }
9635 }
9636 }
9637
9638
9639
9640 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9641 {
9642 BRKTAB **bpt, *bp;
9643
9644 if (spc < SIM_BKPT_N_SPC) {
9645 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9646 for (bp = *bpt; bp; bp = bp->next) {
9647 if (bp->typ & btyp)
9648 bp->time_fired[spc] = -1.0;
9649 }
9650 }
9651 }
9652 }
9653
9654 const char *sim_brk_message(void)
9655 {
9656 static char msg[256];
9657 char addr[65] = "";
9658 char buf[32];
9659
9660 msg[0] = '\0';
9661 if (sim_dflt_dev) {
9662 if (sim_vm_sprint_addr)
9663 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9664 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9665 }
9666 if (sim_brk_type_desc) {
9667 BRKTYPTAB *brk = sim_brk_type_desc;
9668
9669 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9670 if (brk->btyp == sim_brk_match_type) {
9671 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9672 break;
9673 }
9674 brk++;
9675 }
9676 }
9677 if (!msg[0])
9678 (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9679 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9680
9681 return msg;
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
9708
9709
9710
9711
9712
9713
9714
9715
9716
9717
9718
9719
9720 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9721 {
9722 char gbuf[CBUFSIZE];
9723 CONST char *tptr;
9724 CONST char *c1ptr;
9725 t_bool after_set = FALSE;
9726 uint32 after;
9727 int32 cnt = 0;
9728 t_stat r;
9729
9730 if (exp == NULL)
9731 return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9732 after = exp->after;
9733
9734 if ((cptr == NULL) || (*cptr == 0))
9735 return SCPE_2FARG;
9736 if (*cptr == '[') {
9737 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9738 if ((cptr == c1ptr) || (*c1ptr != ']'))
9739 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9740 cptr = c1ptr + 1;
9741 while (sim_isspace(*cptr))
9742 ++cptr;
9743 }
9744 tptr = get_glyph (cptr, gbuf, ',');
9745 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9746 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9747 if (r != SCPE_OK)
9748 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9749 after_set = TRUE;
9750 cptr = tptr;
9751 }
9752 if ((*cptr != '"') && (*cptr != '\''))
9753 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9754 cptr = get_glyph_quoted (cptr, gbuf, 0);
9755
9756 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9757 }
9758
9759
9760
9761 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9762 {
9763 char gbuf[CBUFSIZE];
9764
9765 if (NULL == cptr || !*cptr)
9766 return sim_exp_clrall (exp);
9767 if ((*cptr != '"') && (*cptr != '\''))
9768 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9769 cptr = get_glyph_quoted (cptr, gbuf, 0);
9770 if (*cptr != '\0')
9771 return SCPE_2MARG;
9772 return sim_exp_clr (exp, gbuf);
9773 }
9774
9775
9776
9777 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9778 {
9779 size_t i;
9780
9781 if (NULL == exp->rules)
9782 return NULL;
9783 for (i=start_rule; i<exp->size; i++)
9784 if (!strcmp (exp->rules[i].match_pattern, match))
9785 return &exp->rules[i];
9786 return NULL;
9787 }
9788
9789
9790
9791 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9792 {
9793 size_t i;
9794
9795 if (NULL == ep)
9796 return SCPE_OK;
9797 FREE (ep->match);
9798 FREE (ep->match_pattern);
9799 FREE (ep->act);
9800 exp->size -= 1;
9801 #if !defined(__clang_analyzer__)
9802 for (i=ep-exp->rules; i<exp->size; i++)
9803 exp->rules[i] = exp->rules[i+1];
9804 if (exp->size == 0) {
9805 FREE (exp->rules);
9806 exp->rules = NULL;
9807 }
9808 #endif
9809 return SCPE_OK;
9810 }
9811
9812 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9813 {
9814 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9815
9816 while (ep) {
9817 sim_exp_clr_tab (exp, ep);
9818 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9819 }
9820 return SCPE_OK;
9821 }
9822
9823
9824
9825 t_stat sim_exp_clrall (EXPECT *exp)
9826 {
9827 int32 i;
9828
9829 for (i=0; i<exp->size; i++) {
9830 FREE (exp->rules[i].match);
9831 FREE (exp->rules[i].match_pattern);
9832 FREE (exp->rules[i].act);
9833 }
9834 FREE (exp->rules);
9835 exp->rules = NULL;
9836 exp->size = 0;
9837 FREE (exp->buf);
9838 exp->buf = NULL;
9839 exp->buf_size = 0;
9840 exp->buf_ins = 0;
9841 return SCPE_OK;
9842 }
9843
9844
9845
9846 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9847 {
9848 EXPTAB *ep;
9849 uint8 *match_buf;
9850 uint32 match_size;
9851 size_t i;
9852
9853
9854 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9855 if (!match_buf)
9856 return SCPE_MEM;
9857 if (switches & EXP_TYP_REGEX) {
9858 FREE (match_buf);
9859 return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9860 }
9861 else {
9862 if (switches & EXP_TYP_REGEX_I) {
9863 FREE (match_buf);
9864 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9865 }
9866 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9867 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9868 FREE (match_buf);
9869 return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9870 }
9871 }
9872 FREE (match_buf);
9873 for (i=0; i<exp->size; i++) {
9874 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9875 (exp->rules[i].switches & EXP_TYP_PERSIST))
9876 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9877 }
9878 if (after && exp->size)
9879 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9880 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9881 if (!exp->rules)
9882 {
9883 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9884 __func__, __FILE__, __LINE__);
9885 #if defined(USE_BACKTRACE)
9886 # if defined(SIGUSR2)
9887 (void)raise(SIGUSR2);
9888
9889 # endif
9890 #endif
9891 abort();
9892 }
9893 ep = &exp->rules[exp->size];
9894 exp->size += 1;
9895 exp->after = after;
9896 (void)memset (ep, 0, sizeof(*ep));
9897 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9898 if (ep->match_pattern)
9899 strcpy (ep->match_pattern, match);
9900 ep->cnt = cnt;
9901 ep->switches = switches;
9902 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9903 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9904 sim_exp_clr_tab (exp, ep);
9905 FREE (match_buf);
9906 return SCPE_MEM;
9907 }
9908 if (switches & EXP_TYP_REGEX) {
9909 FREE (match_buf);
9910 match_buf = NULL;
9911 }
9912 else {
9913 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9914 sim_decode_quoted_string (match, match_buf, &match_size);
9915 ep->match = match_buf;
9916 ep->size = match_size;
9917 }
9918 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9919 if (!ep->match_pattern)
9920 {
9921 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9922 __func__, __FILE__, __LINE__);
9923 #if defined(USE_BACKTRACE)
9924 # if defined(SIGUSR2)
9925 (void)raise(SIGUSR2);
9926
9927 # endif
9928 #endif
9929 abort();
9930 }
9931 strcpy (ep->match_pattern, match);
9932 if (ep->act) {
9933 FREE (ep->act);
9934 ep->act = NULL;
9935 }
9936 if (act) while (sim_isspace(*act)) ++act;
9937 if ((act != NULL) && (*act != 0)) {
9938 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9939 if (newp == NULL)
9940 return SCPE_MEM;
9941 strcpy (newp, act);
9942 ep->act = newp;
9943 }
9944
9945 for (i=0; i<exp->size; i++) {
9946 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9947 if (compare_size >= exp->buf_size) {
9948 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
9949 exp->buf_size = compare_size + 1;
9950 }
9951 }
9952 return SCPE_OK;
9953 }
9954
9955
9956
9957 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
9958 {
9959 if (!ep)
9960 return SCPE_OK;
9961 (void)fprintf (st, "EXPECT");
9962 if (ep->switches & EXP_TYP_PERSIST)
9963 (void)fprintf (st, " -p");
9964 if (ep->switches & EXP_TYP_CLEARALL)
9965 (void)fprintf (st, " -c");
9966 if (ep->switches & EXP_TYP_REGEX)
9967 (void)fprintf (st, " -r");
9968 if (ep->switches & EXP_TYP_REGEX_I)
9969 (void)fprintf (st, " -i");
9970 (void)fprintf (st, " %s", ep->match_pattern);
9971 if (ep->cnt > 0)
9972 (void)fprintf (st, " [%d]", ep->cnt);
9973 if (ep->act)
9974 (void)fprintf (st, " %s", ep->act);
9975 (void)fprintf (st, "\r\n");
9976 return SCPE_OK;
9977 }
9978
9979 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
9980 {
9981 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9982
9983 if (exp->buf_size) {
9984 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9985
9986 (void)fprintf (st, "Match Buffer Size: %lld\r\n",
9987 (long long)exp->buf_size);
9988 (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
9989 (long long)exp->buf_ins);
9990 (void)fprintf (st, "Buffer Contents: %s\r\n",
9991 bstr);
9992 FREE (bstr);
9993 }
9994 if (exp->after)
9995 (void)fprintf (st, "Halt After: %lld instructions\r\n",
9996 (long long)exp->after);
9997 if (exp->dptr && exp->dbit)
9998 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
9999 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10000 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10001 (void)fprintf (st, "Match Rules:\r\n");
10002 if (!*match)
10003 return sim_exp_showall (st, exp);
10004 if (!ep) {
10005 (void)fprintf (st, "No Rules match '%s'\r\n", match);
10006 return SCPE_ARG;
10007 }
10008 do {
10009 sim_exp_show_tab (st, exp, ep);
10010 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10011 } while (ep);
10012 return SCPE_OK;
10013 }
10014
10015
10016
10017 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
10018 {
10019 size_t i;
10020
10021 for (i=0; i < exp->size; i++)
10022 sim_exp_show_tab (st, exp, &exp->rules[i]);
10023 return SCPE_OK;
10024 }
10025
10026
10027
10028 t_stat sim_exp_check (EXPECT *exp, uint8 data)
10029 {
10030 size_t i;
10031 EXPTAB *ep = NULL;
10032 char *tstr = NULL;
10033 #if defined(TESTING)
10034 cpu_state_t * cpup = _cpup;
10035 #endif
10036
10037 if ((!exp) || (!exp->rules))
10038 return SCPE_OK;
10039
10040 exp->buf[exp->buf_ins++] = data;
10041 exp->buf[exp->buf_ins] = '\0';
10042
10043 for (i=0; i < exp->size; i++) {
10044 ep = &exp->rules[i];
10045 if (ep == NULL)
10046 break;
10047 if (ep->switches & EXP_TYP_REGEX) {
10048 }
10049 else {
10050 if (exp->buf_ins < ep->size) {
10051
10052
10053
10054
10055 if (exp->buf_ins > 0) {
10056 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10057 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10058 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10059
10060 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10061 (long long)exp->buf_ins, estr);
10062 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10063 FREE (estr);
10064 FREE (mstr);
10065 }
10066 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10067 continue;
10068 }
10069 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10070 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10071 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10072
10073 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10074 (long long)exp->buf_size-(ep->size-exp->buf_ins),
10075 (long long)ep->size-exp->buf_ins, estr);
10076 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10077 FREE (estr);
10078 FREE (mstr);
10079 }
10080 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10081 continue;
10082 break;
10083 }
10084 else {
10085 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10086 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10087 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10088
10089 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10090 (long long)exp->buf_ins-ep->size,
10091 (long long)ep->size, estr);
10092 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10093 FREE (estr);
10094 FREE (mstr);
10095 }
10096 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10097 continue;
10098 break;
10099 }
10100 }
10101 }
10102 if (exp->buf_ins == exp->buf_size) {
10103 exp->buf_ins = 0;
10104 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10105 }
10106 if ((ep != NULL) && (i != exp->size)) {
10107 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10108 if (ep->cnt > 0) {
10109 ep->cnt -= 1;
10110 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10111 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10112 }
10113 else {
10114 uint32 after = exp->after;
10115 int32 switches = ep->switches;
10116 if (ep->act && *ep->act) {
10117 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10118 }
10119 else {
10120 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10121 }
10122 sim_brk_setact (ep->act);
10123 if (ep->switches & EXP_TYP_CLEARALL)
10124 sim_exp_clrall (exp);
10125 else {
10126 if (!(ep->switches & EXP_TYP_PERSIST))
10127 sim_exp_clr_tab (exp, ep);
10128 }
10129 sim_activate (&sim_expect_unit,
10130 (switches & EXP_TYP_TIME) ?
10131 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10132 after);
10133 }
10134
10135 exp->buf_ins = 0;
10136 }
10137 if (tstr)
10138 FREE (tstr);
10139 return SCPE_OK;
10140 }
10141
10142
10143
10144 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10145 {
10146 if (snd->extoff != 0) {
10147 if (snd->insoff > snd->extoff)
10148 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10149 snd->insoff -= snd->extoff;
10150 snd->extoff = 0;
10151 }
10152 if (snd->insoff+size > snd->bufsize) {
10153 snd->bufsize = snd->insoff+size;
10154 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10155 if (!snd->buffer)
10156 {
10157 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10158 __func__, __FILE__, __LINE__);
10159 #if defined(USE_BACKTRACE)
10160 # if defined(SIGUSR2)
10161 (void)raise(SIGUSR2);
10162
10163 # endif
10164 #endif
10165 abort();
10166 }
10167 }
10168 memcpy(snd->buffer+snd->insoff, data, size);
10169 snd->insoff += size;
10170 if (delay)
10171 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10172 if (after)
10173 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10174 if (snd->after == 0)
10175 snd->after = snd->delay;
10176 snd->next_time = sim_gtime() + snd->after;
10177 return SCPE_OK;
10178 }
10179
10180
10181 t_stat sim_send_clear (SEND *snd)
10182 {
10183 snd->insoff = 0;
10184 snd->extoff = 0;
10185 return SCPE_OK;
10186 }
10187
10188
10189
10190 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10191 {
10192 if (snd->extoff < snd->insoff) {
10193 (void)fprintf (st, "%lld bytes of pending input Data:\r\n ",
10194 (long long)snd->insoff-snd->extoff);
10195 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10196 (void)fprintf (st, "\r\n");
10197 }
10198 else
10199 (void)fprintf (st, "No Pending Input Data\r\n");
10200 if ((snd->next_time - sim_gtime()) > 0) {
10201 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10202 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10203 (int)(snd->next_time - sim_gtime()),
10204 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10205 else
10206 (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10207 (int)(snd->next_time - sim_gtime()));
10208 }
10209 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10210 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10211 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10212 else
10213 (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10214 (int)snd->delay);
10215 if (snd->dptr && snd->dbit)
10216 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10217 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10218 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10219 return SCPE_OK;
10220 }
10221
10222
10223
10224 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10225 {
10226 #if defined(TESTING)
10227 cpu_state_t * cpup = _cpup;
10228 #endif
10229 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10230 if (sim_gtime() < snd->next_time) {
10231 *stat = SCPE_OK;
10232 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10233 }
10234 else {
10235 char dstr[8] = "";
10236 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10237 snd->next_time = sim_gtime() + snd->delay;
10238 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10239 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10240 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10241 }
10242 return TRUE;
10243 }
10244 return FALSE;
10245 }
10246
10247
10248
10249 const char *sim_error_text (t_stat stat)
10250 {
10251 static char msgbuf[64];
10252
10253 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10254 if (stat == SCPE_OK)
10255 return "No Error";
10256 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10257 return scp_errors[stat-SCPE_BASE].message;
10258 (void)sprintf(msgbuf, "Error %d", stat);
10259 return msgbuf;
10260 }
10261
10262 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10263 {
10264 char gbuf[CBUFSIZE];
10265 size_t cond;
10266
10267 *stat = SCPE_ARG;
10268 cptr = get_glyph (cptr, gbuf, 0);
10269 if (0 == memcmp("SCPE_", gbuf, 5))
10270 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10271 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10272 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10273 cond += SCPE_BASE;
10274 break;
10275 }
10276 if (0 == strcmp(gbuf, "OK"))
10277 cond = SCPE_OK;
10278 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10279 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10280 if (0 == numeric_cond)
10281 return SCPE_ARG;
10282 cond = (t_stat) numeric_cond;
10283 }
10284 if (cond > SCPE_MAX_ERR)
10285 return SCPE_ARG;
10286 *stat = cond;
10287 return SCPE_OK;
10288 }
10289
10290
10291
10292 const char* debug_bstates = "01_^";
10293 char debug_line_prefix[256];
10294 int32 debug_unterm = 0;
10295
10296
10297
10298 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10299 {
10300 static const char *debtab_none = "DEBTAB_ISNULL";
10301 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10302 const char *some_match = NULL;
10303 int32 offset = 0;
10304
10305 if (dptr->debflags == 0)
10306 return debtab_none;
10307
10308 dbits &= dptr->dctrl;
10309
10310
10311
10312 while ((offset < 32) && dptr->debflags[offset].name) {
10313 if (dptr->debflags[offset].mask == dbits)
10314 return dptr->debflags[offset].name;
10315 if (dptr->debflags[offset].mask & dbits)
10316 some_match = dptr->debflags[offset].name;
10317 offset++;
10318 }
10319 return some_match ? some_match : debtab_nomatch;
10320 }
10321
10322
10323
10324 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10325 {
10326 const char* debug_type = get_dbg_verb (dbits, dptr);
10327 char tim_t[32] = "";
10328 char tim_a[32] = "";
10329 char pc_s[64] = "";
10330 struct timespec time_now;
10331
10332 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10333 clock_gettime(CLOCK_REALTIME, &time_now);
10334 if (sim_deb_switches & SWMASK ('R'))
10335 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10336 if (sim_deb_switches & SWMASK ('T')) {
10337 time_t tnow = (time_t)time_now.tv_sec;
10338 struct tm *now = gmtime(&tnow);
10339 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10340 (int)now->tm_hour,
10341 (int)now->tm_min,
10342 (int)now->tm_sec,
10343 (long)(time_now.tv_nsec / 1000000));
10344 }
10345 if (sim_deb_switches & SWMASK ('A')) {
10346 (void)sprintf(tim_t, "%d.%03ld ",
10347 (int)(time_now.tv_sec),
10348 (long)(time_now.tv_nsec / 1000000));
10349 }
10350 }
10351 if (sim_deb_switches & SWMASK ('P')) {
10352 t_value val;
10353
10354 if (sim_vm_pc_value)
10355 val = (*sim_vm_pc_value)();
10356 else
10357 val = get_rval (sim_PC, 0);
10358 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10359 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10360 }
10361 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10362 tim_t, tim_a, sim_gtime(), pc_s,
10363 "", dptr->name, debug_type);
10364 return debug_line_prefix;
10365 }
10366
10367 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10368 {
10369 int32 i, fields, offset;
10370 uint32 value, beforevalue, mask;
10371
10372 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10373 if (bitdefs[fields].offset == 0xffffffff)
10374 bitdefs[fields].offset = offset;
10375 offset += bitdefs[fields].width;
10376 }
10377 for (i = fields-1; i >= 0; i--) {
10378 if (bitdefs[i].name[0] == '\0')
10379 continue;
10380 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10381 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10382 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10383 }
10384 else {
10385 const char *delta = "";
10386 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10387 value = (uint32)((after >> bitdefs[i].offset) & mask);
10388 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10389 if (value < beforevalue)
10390 delta = "_";
10391 if (value > beforevalue)
10392 delta = "^";
10393 if (bitdefs[i].valuenames)
10394 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10395 else
10396 if (bitdefs[i].format) {
10397 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10398 (void)Fprintf(stream, bitdefs[i].format, value);
10399 (void)Fprintf(stream, " ");
10400 }
10401 else
10402 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10403 }
10404 }
10405 }
10406
10407
10408
10409
10410
10411 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10412 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10413 {
10414 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10415 if (!debug_unterm)
10416 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10417 if (header)
10418 (void)fprintf(sim_deb, "%s: ", header);
10419 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10420 if (terminate)
10421 (void)fprintf(sim_deb, "\r\n");
10422 debug_unterm = terminate ? 0 : 1;
10423 }
10424 }
10425 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10426 uint32 before, uint32 after, int terminate)
10427 {
10428 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10429 }
10430
10431
10432 void sim_printf (const char* fmt, ...)
10433 {
10434 char stackbuf[STACKBUFSIZE];
10435 int32 bufsize = sizeof(stackbuf);
10436 char *buf = stackbuf;
10437 int32 len;
10438 va_list arglist;
10439
10440 while (1) {
10441 va_start (arglist, fmt);
10442 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10443 va_end (arglist);
10444
10445
10446
10447 if ((len < 0) || (len >= bufsize-1)) {
10448 if (buf != stackbuf)
10449 FREE (buf);
10450 if (bufsize >= (INT_MAX / 2))
10451 return;
10452 bufsize = bufsize * 2;
10453 if (bufsize < len + 2)
10454 bufsize = len + 2;
10455 buf = (char *) malloc (bufsize);
10456 if (buf == NULL)
10457 return;
10458 buf[bufsize-1] = '\0';
10459 continue;
10460 }
10461 break;
10462 }
10463
10464 if (sim_is_running) {
10465 char *c, *remnant = buf;
10466 while ((c = strchr(remnant, '\n'))) {
10467 if ((c != buf) && (*(c - 1) != '\r'))
10468 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10469 else
10470 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10471 remnant = c + 1;
10472 }
10473 (void)printf("%s", remnant);
10474 }
10475 else
10476 (void)printf("%s", buf);
10477 if (sim_log && (sim_log != stdout))
10478 (void)fprintf (sim_log, "%s", buf);
10479 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10480 (void)fprintf (sim_deb, "%s", buf);
10481
10482 if (buf != stackbuf)
10483 FREE (buf);
10484 }
10485
10486
10487 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10488 {
10489 char stackbuf[STACKBUFSIZE];
10490 size_t bufsize = sizeof(stackbuf);
10491 char *buf = stackbuf;
10492 size_t len;
10493 va_list arglist;
10494 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10495
10496 while (1) {
10497 va_start (arglist, fmt);
10498 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10499 va_end (arglist);
10500
10501
10502
10503 if (len >= bufsize - 1) {
10504 if (buf != stackbuf)
10505 FREE (buf);
10506 bufsize = bufsize * 2;
10507 if (bufsize < len + 2)
10508 bufsize = len + 2;
10509 buf = (char *) malloc (bufsize);
10510 if (buf == NULL)
10511 return SCPE_MEM;
10512 buf[bufsize-1] = '\0';
10513 continue;
10514 }
10515 break;
10516 }
10517
10518 if (sim_do_ocptr[sim_do_depth]) {
10519 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10520 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10521 else {
10522 if (sim_deb)
10523 (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10524 }
10525 }
10526 if (sim_is_running && !inhibit_message) {
10527 char *c, *remnant = buf;
10528 while ((c = strchr(remnant, '\n'))) {
10529 if ((c != buf) && (*(c - 1) != '\r'))
10530 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10531 else
10532 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10533 remnant = c + 1;
10534 }
10535 (void)printf("%s", remnant);
10536 }
10537 else {
10538 if (!inhibit_message)
10539 (void)printf("%s", buf);
10540 }
10541 if (sim_log && (sim_log != stdout) && !inhibit_message)
10542 (void)fprintf (sim_log, "%s", buf);
10543 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10544 (void)fprintf (sim_deb, "%s", buf);
10545
10546 if (buf != stackbuf)
10547 FREE (buf);
10548 return stat | SCPE_NOMESSAGE;
10549 }
10550
10551
10552
10553
10554
10555
10556
10557
10558
10559 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10560 {
10561 DEVICE *dptr = (DEVICE *)vdptr;
10562 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10563 char stackbuf[STACKBUFSIZE];
10564 int32 bufsize = sizeof(stackbuf);
10565 char *buf = stackbuf;
10566 va_list arglist;
10567 int32 i, j, len;
10568 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10569
10570 buf[bufsize-1] = '\0';
10571 while (1) {
10572 va_start (arglist, fmt);
10573 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10574 va_end (arglist);
10575
10576
10577
10578 if ((len < 0) || (len >= bufsize-1)) {
10579 if (buf != stackbuf)
10580 FREE (buf);
10581 if (bufsize >= (INT_MAX / 2))
10582 return;
10583 bufsize = bufsize * 2;
10584 if (bufsize < len + 2)
10585 bufsize = len + 2;
10586 buf = (char *) malloc (bufsize);
10587 if (buf == NULL)
10588 return;
10589 buf[bufsize-1] = '\0';
10590 continue;
10591 }
10592 break;
10593 }
10594
10595
10596
10597 for (i = j = 0; i < len; ++i) {
10598 if ('\n' == buf[i]) {
10599 if (i >= j) {
10600 if ((i != j) || (i == 0)) {
10601 if (debug_unterm)
10602 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10603 else
10604 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10605 }
10606 debug_unterm = 0;
10607 }
10608 j = i + 1;
10609 }
10610 }
10611 if (i > j) {
10612 if (debug_unterm)
10613 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10614 else
10615 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10616 }
10617
10618
10619
10620 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10621 if (buf != stackbuf)
10622 FREE (buf);
10623 }
10624 return;
10625 }
10626
10627 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10628 {
10629 #if defined(TESTING)
10630 cpu_state_t * cpup = _cpup;
10631 #endif
10632 if (sim_deb && (dptr->dctrl & reason)) {
10633 sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10634 if (data && len) {
10635 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10636 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10637 static char hex[] = "0123456789ABCDEF";
10638 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10639 static unsigned char ebcdic2ascii[] = {
10640 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10641 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10642 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10643 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10644 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10645 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10646 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10647 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10648 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10649 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10650 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10651 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10652 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10653 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10654 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10655 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10656 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10657 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10658 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10659 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10660 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10661 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10662 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10663 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10664 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10665 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10666 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10667 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10668 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10669 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10670 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10671 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10672 };
10673
10674 for (i=same=0; i<len; i += 16) {
10675 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10676 ++same;
10677 continue;
10678 }
10679 if (same > 0) {
10680 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10681 (unsigned long int)(i - (16*same)),
10682 (unsigned long int)(i - 1));
10683 same = 0;
10684 }
10685 group = (((len - i) > 16) ? 16 : (len - i));
10686 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10687 eidx = strlen(ebcdicbuf);
10688 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10689 ridx = strlen(rad50buf);
10690 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10691 soff = strlen(strbuf);
10692 for (sidx=oidx=0; sidx<group; ++sidx) {
10693 outbuf[oidx++] = ' ';
10694 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10695 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10696 if (sim_isprint (data[i+sidx]))
10697 strbuf[soff+sidx] = data[i+sidx];
10698 else
10699 strbuf[soff+sidx] = '.';
10700 if (ridx && ((sidx&1) == 0)) {
10701 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10702
10703 if (word >= 64000) {
10704 rad50buf[ridx++] = '|';
10705 rad50buf[ridx++] = '|';
10706 rad50buf[ridx++] = '|';
10707 }
10708 else {
10709 rad50buf[ridx++] = rad50[word/1600];
10710 rad50buf[ridx++] = rad50[(word/40)%40];
10711 rad50buf[ridx++] = rad50[word%40];
10712 }
10713 }
10714 if (eidx) {
10715 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10716 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10717 else
10718 ebcdicbuf[eidx++] = '.';
10719 }
10720 }
10721 outbuf[oidx] = '\0';
10722 strbuf[soff+sidx] = '\0';
10723 ebcdicbuf[eidx] = '\0';
10724 rad50buf[ridx] = '\0';
10725 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10726 (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10727 }
10728 if (same > 0) {
10729 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10730 (unsigned long int)(i-(16*same)),
10731 (unsigned long int)(len-1));
10732 }
10733 }
10734 }
10735 }
10736
10737 int Fprintf (FILE *f, const char* fmt, ...)
10738 {
10739 int ret = 0;
10740 va_list args;
10741
10742 va_start (args, fmt);
10743 ret = vfprintf (f, fmt, args);
10744 va_end (args);
10745 return ret;
10746 }
10747
10748
10749
10750
10751
10752
10753
10754
10755
10756
10757
10758
10759
10760
10761
10762
10763
10764
10765
10766 #define blankch(x) ((x) == ' ' || (x) == '\t')
10767
10768 typedef struct topic {
10769 size_t level;
10770 char *title;
10771 char *label;
10772 struct topic *parent;
10773 struct topic **children;
10774 uint32 kids;
10775 char *text;
10776 size_t len;
10777 uint32 flags;
10778 size_t kidwid;
10779 #define HLP_MAGIC_TOPIC 1
10780 } TOPIC;
10781
10782 static volatile struct {
10783 const char *error;
10784 const char *prox;
10785 size_t block;
10786 size_t line;
10787 } help_where = { "", NULL, 0, 0 };
10788 jmp_buf help_env;
10789
10790 #define FAIL(why,text,here) \
10791 { \
10792 help_where.error = #text; \
10793 help_where.prox = here; \
10794 longjmp ( help_env, (why) ); \
10795 \
10796 }
10797
10798
10799
10800
10801
10802
10803 static void appendText (TOPIC *topic, const char *text, size_t len)
10804 {
10805 char *newt;
10806
10807 if (!len)
10808 return;
10809
10810 newt = (char *)realloc (topic->text, topic->len + len +1);
10811 if (!newt) {
10812 #if !defined(SUNLINT)
10813 FAIL (SCPE_MEM, No memory, NULL);
10814 #endif
10815 }
10816 topic->text = newt;
10817 memcpy (newt + topic->len, text, len);
10818 topic->len +=len;
10819 newt[topic->len] = '\0';
10820 return;
10821 }
10822
10823
10824
10825 static void cleanHelp (TOPIC *topic)
10826 {
10827 TOPIC *child;
10828 size_t i;
10829
10830 FREE (topic->title);
10831 FREE (topic->text);
10832 FREE (topic->label);
10833 for (i = 0; i < topic->kids; i++) {
10834 child = topic->children[i];
10835 cleanHelp (child);
10836 FREE (child);
10837 }
10838 FREE (topic->children);
10839 return;
10840 }
10841
10842
10843
10844
10845 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10846 UNIT *uptr, const char *htext, va_list ap)
10847 {
10848 char *end;
10849 size_t n, ilvl;
10850 #define VSMAX 100
10851 char *vstrings[VSMAX];
10852 size_t vsnum = 0;
10853 char * astrings[VSMAX+1];
10854 size_t asnum = 0;
10855 char *const *hblock;
10856 const char *ep;
10857 t_bool excluded = FALSE;
10858
10859
10860
10861
10862
10863
10864
10865 (void)memset (vstrings, 0, sizeof (vstrings));
10866 (void)memset (astrings, 0, sizeof (astrings));
10867 astrings[asnum++] = (char *) htext;
10868
10869 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10870 help_where.block = hblock - astrings;
10871 help_where.line = 0;
10872 while (*htext) {
10873 const char *start;
10874
10875 help_where.line++;
10876 if (sim_isspace (*htext) || *htext == '+') {
10877 if (excluded) {
10878 while (*htext && *htext != '\n')
10879 htext++;
10880 if (*htext)
10881 ++htext;
10882 continue;
10883 }
10884 ilvl = 1;
10885 appendText (topic, " ", 4);
10886 if (*htext == '+') {
10887 while (*htext == '+') {
10888 ilvl++;
10889 appendText (topic, " ", 4);
10890 htext++;
10891 }
10892 }
10893 while (*htext && *htext != '\n' && sim_isspace (*htext))
10894 htext++;
10895 if (!*htext)
10896 break;
10897 start = htext;
10898 while (*htext) {
10899 if (*htext == '%') {
10900 appendText (topic, start, htext - start);
10901 switch (*++htext) {
10902 case 'U':
10903 if (dptr) {
10904 char buf[129];
10905 n = uptr? uptr - dptr->units: 0;
10906 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10907 appendText (topic, buf, strlen (buf));
10908 }
10909 break;
10910 case 'D':
10911 if (dptr != NULL)
10912 appendText (topic, dptr->name, strlen (dptr->name));
10913 break;
10914 case 'S':
10915 appendText (topic, sim_name, strlen (sim_name));
10916 break;
10917 case '%':
10918 appendText (topic, "%", 1);
10919 break;
10920 case '+':
10921 appendText (topic, "+", 1);
10922 break;
10923 default:
10924 if (sim_isdigit (*htext)) {
10925 n = 0;
10926 while (sim_isdigit (*htext))
10927 n += (n * 10) + (*htext++ - '0');
10928 if (( *htext != 'H' && *htext != 's') ||
10929 n == 0 || n >= VSMAX) {
10930 #if !defined(SUNLINT)
10931 FAIL (SCPE_ARG, Invalid escape, htext);
10932 #endif
10933 }
10934 while (n > vsnum)
10935 vstrings[vsnum++] = va_arg (ap, char *);
10936 start = vstrings[n-1];
10937 if (*htext == 'H') {
10938 if (asnum >= VSMAX) {
10939 #if !defined(SUNLINT)
10940 FAIL (SCPE_ARG, Too many blocks, htext);
10941 #endif
10942 }
10943 astrings[asnum++] = (char *)start;
10944 break;
10945 }
10946 ep = start;
10947 while (*ep) {
10948 if (*ep == '\n') {
10949 ep++;
10950 appendText (topic, start, ep - start);
10951 if (*ep) {
10952 size_t i;
10953 for (i = 0; i < ilvl; i++)
10954 appendText (topic, " ", 4);
10955 }
10956 start = ep;
10957 }
10958 else
10959 ep++;
10960 }
10961 appendText (topic, start, ep-start);
10962 break;
10963 }
10964 #if !defined(SUNLINT)
10965 FAIL (SCPE_ARG, Invalid escape, htext);
10966 #endif
10967 }
10968 start = ++htext;
10969 continue;
10970 }
10971 if (*htext == '\n') {
10972 htext++;
10973 appendText (topic, start, htext - start);
10974 break;
10975 }
10976 htext++;
10977 }
10978 continue;
10979 }
10980 if (sim_isdigit (*htext)) {
10981 TOPIC **children;
10982 TOPIC *newt;
10983 char nbuf[100];
10984
10985 n = 0;
10986 start = htext;
10987 while (sim_isdigit (*htext))
10988 n += (n * 10) + (*htext++ - '0');
10989 if ((htext == start) || !n) {
10990 #if !defined(SUNLINT)
10991 FAIL (SCPE_ARG, Invalid topic heading, htext);
10992 #endif
10993 }
10994 if (n <= topic->level) {
10995 while (n <= topic->level)
10996 topic = topic->parent;
10997 }
10998 else {
10999 if (n > topic->level + 1) {
11000 #if !defined(SUNLINT)
11001 FAIL (SCPE_ARG, Level not contiguous, htext);
11002 #endif
11003 }
11004 }
11005 while (*htext && (*htext != '\n') && sim_isspace (*htext))
11006 htext++;
11007 if (!*htext || (*htext == '\n')) {
11008 #if !defined(SUNLINT)
11009 FAIL (SCPE_ARG, Missing topic name, htext);
11010 #endif
11011 }
11012 start = htext;
11013 while (*htext && (*htext != '\n'))
11014 htext++;
11015 if (start == htext) {
11016 #if !defined(SUNLINT)
11017 FAIL (SCPE_ARG, Null topic name, htext);
11018 #endif
11019 }
11020 excluded = FALSE;
11021 if (*start == '?') {
11022 size_t n = 0;
11023 start++;
11024 while (sim_isdigit (*start))
11025 n += (n * 10) + (*start++ - '0');
11026 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11027 #if !defined(SUNLINT)
11028 FAIL (SCPE_ARG, Invalid parameter number, start);
11029 #endif
11030 }
11031 while (n > vsnum)
11032 vstrings[vsnum++] = va_arg (ap, char *);
11033 end = vstrings[n-1];
11034 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11035 excluded = TRUE;
11036 if (*htext)
11037 htext++;
11038 continue;
11039 }
11040 }
11041 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11042 if (!newt) {
11043 #if !defined(SUNLINT)
11044 FAIL (SCPE_MEM, No memory, NULL);
11045 #endif
11046 }
11047 size_t len = (htext > start) ? (htext - start) : 0;
11048 newt->title = (char *) malloc(len + 1);
11049 if (!newt->title) {
11050 FREE (newt);
11051 #if !defined(SUNLINT)
11052 FAIL (SCPE_MEM, No memory, NULL);
11053 #endif
11054 }
11055 memcpy (newt->title, start, htext - start);
11056 newt->title[htext - start] = '\0';
11057 if (*htext)
11058 htext++;
11059
11060 if (newt->title[0] == '$')
11061 newt->flags |= HLP_MAGIC_TOPIC;
11062
11063 children = (TOPIC **) realloc (topic->children,
11064 (topic->kids +1) * sizeof (TOPIC *));
11065 if (NULL == children) {
11066 FREE (newt->title);
11067 FREE (newt);
11068 #if !defined(SUNLINT)
11069 FAIL (SCPE_MEM, No memory, NULL);
11070 #endif
11071 }
11072 topic->children = children;
11073 topic->children[topic->kids++] = newt;
11074 newt->level = n;
11075 newt->parent = topic;
11076 n = strlen (newt->title);
11077 if (n > topic->kidwid)
11078 topic->kidwid = n;
11079 (void)sprintf (nbuf, ".%u", topic->kids);
11080 n = strlen (topic->label) + strlen (nbuf) + 1;
11081 newt->label = (char *) malloc (n);
11082 if (NULL == newt->label) {
11083 FREE (newt->title);
11084 topic->children[topic->kids -1] = NULL;
11085 FREE (newt);
11086 #if !defined(SUNLINT)
11087 FAIL (SCPE_MEM, No memory, NULL);
11088 #endif
11089 }
11090 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11091 topic = newt;
11092 continue;
11093 }
11094 if (*htext == ';') {
11095 while (*htext && *htext != '\n')
11096 htext++;
11097 continue;
11098 }
11099 #if !defined(SUNLINT)
11100 FAIL (SCPE_ARG, Unknown line type, htext);
11101 #endif
11102 }
11103 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11104 vsnum = 0;
11105 }
11106
11107 return topic;
11108 }
11109
11110
11111
11112
11113
11114 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
11115 {
11116 char *prefix;
11117 char *newp, *newt;
11118
11119 if (topic->level == 0) {
11120 prefix = (char *) calloc (2,1);
11121 if (!prefix) {
11122 #if !defined(SUNLINT)
11123 FAIL (SCPE_MEM, No memory, NULL);
11124 #endif
11125 }
11126 prefix[0] = '\n';
11127 }
11128 else
11129 prefix = helpPrompt (topic->parent, "", oneword);
11130
11131 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11132 strlen (pstring) +1);
11133 if (!newp) {
11134 FREE (prefix);
11135 #if !defined(SUNLINT)
11136 FAIL (SCPE_MEM, No memory, NULL);
11137 #endif
11138 }
11139 strcpy (newp, prefix);
11140 if (topic->children) {
11141 if (topic->level != 0)
11142 strcat (newp, " ");
11143 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11144 topic->title+1: topic->title;
11145 if (oneword) {
11146 char *np = newp + strlen (newp);
11147 while (*newt) {
11148 *np++ = blankch (*newt)? '_' : *newt;
11149 newt++;
11150 }
11151 *np = '\0';
11152 }
11153 else
11154 strcat (newp, newt);
11155 if (*pstring && *pstring != '?')
11156 strcat (newp, " ");
11157 }
11158 strcat (newp, pstring);
11159 FREE (prefix);
11160 return newp;
11161 }
11162
11163 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11164 {
11165 char tbuf[CBUFSIZE];
11166 size_t i, skiplines;
11167 #if defined(_WIN32)
11168 FILE *tmp;
11169 char *tmpnam;
11170
11171 do {
11172 int fd;
11173 tmpnam = _tempnam (NULL, "simh");
11174 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11175 if (fd != -1) {
11176 tmp = _fdopen (fd, "w+");
11177 break;
11178 }
11179 } while (1);
11180 #else
11181 FILE *tmp = tmpfile();
11182 #endif
11183
11184 if (!tmp) {
11185 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11186 xstrerror_l(errno), errno);
11187 return;
11188 }
11189
11190 if (topic->title)
11191 (void)fprintf (st, "%s\r\n", topic->title+1);
11192
11193 skiplines = 0;
11194 if (topic->title) {
11195 if (!strcmp (topic->title+1, "Registers")) {
11196 fprint_reg_help (tmp, dptr) ;
11197 skiplines = 1;
11198 }
11199 else
11200 if (!strcmp (topic->title+1, "Set commands")) {
11201 fprint_set_help (tmp, dptr);
11202 skiplines = 3;
11203 }
11204 else
11205 if (!strcmp (topic->title+1, "Show commands")) {
11206 fprint_show_help (tmp, dptr);
11207 skiplines = 3;
11208 }
11209 }
11210 rewind (tmp);
11211 if (errno) {
11212 (void)fprintf (st, "rewind: error %d\r\n", errno);
11213 }
11214
11215
11216
11217 for (i =0; i < skiplines; i++)
11218 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11219
11220 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11221 if (tbuf[0] != '\n')
11222 fputs (" ", st);
11223 fputs (tbuf, st);
11224 }
11225 fclose (tmp);
11226 #if defined(_WIN32)
11227 remove (tmpnam);
11228 FREE (tmpnam);
11229 #endif
11230 return;
11231 }
11232
11233
11234 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11235 UNIT *uptr, int32 flag,
11236 TOPIC *topic, va_list ap )
11237 {
11238 size_t i;
11239
11240 if (topic->flags & HLP_MAGIC_TOPIC) {
11241 (void)fprintf (st, "\r\n%s ", topic->label);
11242 displayMagicTopic (st, dptr, topic);
11243 }
11244 else
11245 (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11246
11247
11248
11249
11250
11251
11252 if (topic->text)
11253 fputs (topic->text, st);
11254
11255 for (i = 0; i < topic->kids; i++)
11256 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11257
11258 return SCPE_OK;
11259 }
11260
11261 #define HLP_MATCH_AMBIGUOUS (~0u)
11262 #define HLP_MATCH_WILDCARD (~1U)
11263 #define HLP_MATCH_NONE 0
11264 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11265 {
11266 size_t i, match;
11267 char cbuf[CBUFSIZE], *cptr;
11268
11269 if (!strcmp (token, "*"))
11270 return HLP_MATCH_WILDCARD;
11271
11272 match = 0;
11273 for (i = 0; i < topic->kids; i++) {
11274 strcpy (cbuf,topic->children[i]->title +
11275 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11276 cptr = cbuf;
11277 while (*cptr) {
11278 if (blankch (*cptr)) {
11279 *cptr++ = '_';
11280 }
11281 else {
11282 *cptr = (char)toupper (*cptr);
11283 cptr++;
11284 }
11285 }
11286 if (!strcmp (cbuf, token))
11287 return i+1;
11288 if (!strncmp (cbuf, token, strlen (token))) {
11289 if (match)
11290 return HLP_MATCH_AMBIGUOUS;
11291 match = i+1;
11292 }
11293 }
11294 return match;
11295 }
11296
11297
11298
11299 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11300 UNIT *uptr, int32 flag,
11301 const char *help, const char *cptr, va_list ap)
11302 {
11303 TOPIC top;
11304 TOPIC *topic = ⊤
11305 int failed;
11306 size_t match;
11307 size_t i;
11308 const char *p;
11309 t_bool flat_help = FALSE;
11310 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11311
11312 static const char attach_help[] = { " ATTACH" };
11313 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\r\n" };
11314 static const char onecmd_help[] = { "%s help.\r\n" };
11315 static const char help_help[] = {
11316
11317 " To see more HELP information, type the listed subtopic name. To move\r\n"
11318 " up a level, just type <CR>. To review the current subtopic, type \"?\".\r\n"
11319 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11320 };
11321
11322 (void)memset (&top, 0, sizeof(top));
11323 top.parent = ⊤
11324 if ((failed = setjmp (help_env)) != 0) {
11325 (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11326 "Error in block %u line %u: %s\r\n"
11327 "%s%*.*s%s\r\n",
11328 (int)help_where.block, (int)help_where.line, help_where.error,
11329 help_where.prox ? "Near '" : "",
11330 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11331 help_where.prox ? help_where.prox : "",
11332 help_where.prox ? "'" : "");
11333 cleanHelp (&top);
11334 return failed;
11335 }
11336
11337
11338
11339
11340
11341 if (dptr) {
11342 p = dptr->name;
11343 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11344 }
11345 else
11346 p = sim_name;
11347 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11348 if (!top.title)
11349 {
11350 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11351 __func__, __FILE__, __LINE__);
11352 #if defined(USE_BACKTRACE)
11353 # if defined(SIGUSR2)
11354 (void)raise(SIGUSR2);
11355
11356 # endif
11357 #endif
11358 abort();
11359 }
11360 for (i = 0; p[i]; i++ )
11361 top.title[i] = (char)toupper (p[i]);
11362 top.title[i] = '\0';
11363 if (flag & SCP_HELP_ATTACH)
11364 strcpy (top.title+i, attach_help);
11365
11366 top.label = (char *) malloc (sizeof ("1"));
11367 if (!top.label)
11368 {
11369 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11370 __func__, __FILE__, __LINE__);
11371 #if defined(USE_BACKTRACE)
11372 # if defined(SIGUSR2)
11373 (void)raise(SIGUSR2);
11374
11375 # endif
11376 #endif
11377 abort();
11378 }
11379 strcpy (top.label, "1");
11380
11381 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11382
11383 if (flat_help) {
11384 flag |= SCP_HELP_FLAT;
11385 if (sim_ttisatty())
11386 (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11387 else
11388 (void)fprintf (st, "%s help.\r\n", top.title);
11389 }
11390 else
11391 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11392
11393
11394
11395 (void) buildHelp (&top, dptr, uptr, help, ap);
11396
11397
11398
11399 while (cptr && *cptr) {
11400 cptr = get_glyph (cptr, gbuf, 0);
11401 if (!gbuf[0])
11402 break;
11403 if (!strcmp (gbuf, "HELP")) {
11404 (void)fprintf (st, "\r\n");
11405 fputs (help_help, st);
11406 break;
11407 }
11408 match = matchHelpTopicName (topic, gbuf);
11409 if (match == HLP_MATCH_WILDCARD) {
11410 if (dptr)
11411 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11412 cleanHelp (&top);
11413 return SCPE_OK;
11414 }
11415 if (match == HLP_MATCH_AMBIGUOUS) {
11416 (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11417 break;
11418 }
11419 if (match == HLP_MATCH_NONE) {
11420 (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11421 break;
11422 }
11423 topic = topic->children[match-1];
11424 }
11425 cptr = NULL;
11426
11427 if (flat_help) {
11428 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11429 cleanHelp (&top);
11430 return SCPE_OK;
11431 }
11432
11433
11434
11435 while (TRUE) {
11436 char *pstring;
11437 const char *prompt[2] = {"? ", "Subtopic? "};
11438
11439
11440
11441 if (topic->flags & HLP_MAGIC_TOPIC) {
11442 fputc ('\n', st);
11443 displayMagicTopic (st, dptr, topic);
11444 }
11445 else
11446 (void)fprintf (st, "\r\n%s\r\n", topic->title);
11447
11448
11449
11450
11451
11452 if (topic->text)
11453 fputs (topic->text, st);
11454
11455 if (topic->kids) {
11456 size_t w = 0;
11457 char *p;
11458 char tbuf[CBUFSIZE];
11459
11460 (void)fprintf (st, "\r\n Additional information available:\r\n\r\n");
11461 for (i = 0; i < topic->kids; i++) {
11462 strcpy (tbuf, topic->children[i]->title +
11463 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11464 for (p = tbuf; *p; p++) {
11465 if (blankch (*p))
11466 *p = '_';
11467 }
11468 w += 4 + topic->kidwid;
11469 if (w > 80) {
11470 w = 4 + topic->kidwid;
11471 fputc ('\r', st);
11472 fputc ('\n', st);
11473 }
11474 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11475 }
11476 (void)fprintf (st, "\r\n\r\n");
11477 if (flag & SCP_HELP_ONECMD) {
11478 pstring = helpPrompt (topic, "", TRUE);
11479 (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11480 FREE (pstring);
11481 break;
11482 }
11483 }
11484
11485 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11486 break;
11487
11488 reprompt:
11489 if (NULL == cptr || !*cptr) {
11490 if (topic->kids == 0)
11491 topic = topic->parent;
11492 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11493
11494 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11495 FREE (pstring);
11496 if ((cptr != NULL) &&
11497 ((0 == strcmp (cptr, "\x04")) ||
11498 (0 == strcmp (cptr, "\x1A"))))
11499 cptr = NULL;
11500 }
11501
11502 if (NULL == cptr)
11503 break;
11504
11505 cptr = get_glyph (cptr, gbuf, 0);
11506 if (!strcmp (gbuf, "*")) {
11507 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11508 gbuf[0] = '\0';
11509 }
11510 if (!gbuf[0]) {
11511 if (topic->level == 0)
11512 break;
11513 topic = topic->parent;
11514 continue;
11515 }
11516 if (!strcmp (gbuf, "?"))
11517 continue;
11518 if (!strcmp (gbuf, "HELP")) {
11519 fputs (help_help, st);
11520 goto reprompt;
11521 }
11522 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11523 break;
11524
11525
11526
11527 if (!topic->kids) {
11528 (void)fprintf (st, "No additional help at this level.\r\n");
11529 cptr = NULL;
11530 goto reprompt;
11531 }
11532 match = matchHelpTopicName (topic, gbuf);
11533 if (match == HLP_MATCH_AMBIGUOUS) {
11534 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11535 cptr = NULL;
11536 goto reprompt;
11537 }
11538
11539 if (match == HLP_MATCH_NONE) {
11540 (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11541 cptr = NULL;
11542 goto reprompt;
11543 }
11544
11545
11546 topic = topic->children[match-1];
11547 }
11548
11549
11550
11551 cleanHelp (&top);
11552
11553 return SCPE_OK;
11554 }
11555
11556
11557
11558 t_stat scp_help (FILE *st, DEVICE *dptr,
11559 UNIT *uptr, int32 flag,
11560 const char *help, const char *cptr, ...)
11561 {
11562 t_stat r;
11563 va_list ap;
11564
11565 va_start (ap, cptr);
11566 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11567 va_end (ap);
11568
11569 return r;
11570 }
11571
11572 #if defined(_MSC_VER)
11573 # pragma warning(pop)
11574 #endif