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
- removehex
- 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 # if !defined(__FILC__)
184 static unsigned int dl_iterate_phdr_callback_called = 0;
185 # endif
186 # endif
187 # endif
188 # endif
189 # endif
190 # endif
191 # endif
192 # endif
193 # endif
194 # endif
195 #endif
196
197 #if defined(MAX)
198 # undef MAX
199 #endif
200 #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
201
202 #if defined(FREE)
203 # undef FREE
204 #endif
205 #define FREE(p) do \
206 { \
207 free((p)); \
208 (p) = NULL; \
209 } while(0)
210
211
212
213 #define SCH_OR 0
214 #define SCH_AND 1
215 #define SCH_XOR 2
216 #define SCH_E 0
217 #define SCH_N 1
218 #define SCH_G 2
219 #define SCH_L 3
220 #define SCH_EE 4
221 #define SCH_NE 5
222 #define SCH_GE 6
223 #define SCH_LE 7
224
225 #define MAX_DO_NEST_LVL 20
226 #define SRBSIZ 1024
227 #define SIM_BRK_INILNT 4096
228 #define SIM_BRK_ALLTYP 0xFFFFFFFB
229
230 #define UPDATE_SIM_TIME \
231 if (1) { \
232 int32 _x; \
233 if (sim_clock_queue == QUEUE_LIST_END) \
234 _x = noqueue_time; \
235 else \
236 _x = sim_clock_queue->time; \
237 sim_time = sim_time + (_x - sim_interval); \
238 sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
239 if (sim_clock_queue == QUEUE_LIST_END) \
240 noqueue_time = sim_interval; \
241 else \
242 sim_clock_queue->time = sim_interval; \
243 } \
244 else \
245 (void)0
246
247 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
248
249 #define SZ_R(rp) \
250 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
251
252 #define SZ_LOAD(sz,v,mb,j) \
253 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
254 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
255 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
256 else v = *(((t_uint64 *) mb) + ((uint32) j));
257
258 #define SZ_STORE(sz,v,mb,j) \
259 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
260 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
261 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
262 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
263
264 #define GET_SWITCHES(cp) \
265 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
266
267 #define GET_RADIX(val,dft) \
268 if (sim_switches & SWMASK ('O')) val = 8; \
269 else if (sim_switches & SWMASK ('D')) val = 10; \
270 else if (sim_switches & SWMASK ('H')) val = 16; \
271 else val = dft;
272
273
274
275
276
277
278 t_bool sim_asynch_enabled = FALSE;
279 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
280 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
281 extern void (*sim_vm_init) (void);
282 extern void (*sim_vm_exit) (void);
283 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
284 void (*sim_vm_post) (t_bool from_scp) = NULL;
285 CTAB *sim_vm_cmd = NULL;
286 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
287 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
288 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
289 t_value (*sim_vm_pc_value) (void) = NULL;
290 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
291 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
292 unsigned int nprocs;
293 unsigned int ncores;
294 bool mlock_failure = false;
295 char* sim_appfilename;
296
297
298
299
300
301 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
302 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
303 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
304 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
305 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
306 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
307 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
308 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
309 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
310 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
311 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
312 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
313 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
314 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
315 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
316 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
317 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
318 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
319 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
320 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
321 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
322 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
323 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
324 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
325 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
326 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
327 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
328 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
329 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
330 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
331 t_stat sim_save (FILE *sfile);
332 t_stat sim_rest (FILE *rfile);
333
334
335
336 t_stat sim_brk_init (void);
337 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
338 t_stat sim_brk_clr (t_addr loc, int32 sw);
339 t_stat sim_brk_clrall (int32 sw);
340 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
341 t_stat sim_brk_showall (FILE *st, uint32 sw);
342 CONST char *sim_brk_getact (char *buf, int32 size);
343 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
344 char *sim_brk_clract (void);
345
346 FILE *stdnul;
347
348
349
350 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
351 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
352 int32 test_search (t_value *val, SCHTAB *schptr);
353 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
354 int32 get_switches (const char *cptr);
355 CONST char *get_sim_sw (CONST char *cptr);
356 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
357 t_value get_rval (REG *rptr, uint32 idx);
358 void put_rval (REG *rptr, uint32 idx, t_value val);
359 void fprint_help (FILE *st);
360 void fprint_stopped (FILE *st, t_stat r);
361 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
362 void fprint_sep (FILE *st, int32 *tokens);
363 char *read_line (char *ptr, int32 size, FILE *stream);
364 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
365 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
366 char *sim_trim_endspc (char *cptr);
367
368
369
370 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
371 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
372 t_bool qdisable (DEVICE *dptr);
373 t_stat attach_err (UNIT *uptr, t_stat stat);
374 t_stat detach_all (int32 start_device, t_bool shutdown);
375 t_stat assign_device (DEVICE *dptr, const char *cptr);
376 t_stat deassign_device (DEVICE *dptr);
377 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
378 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
379 REG *lowr, REG *highr, uint32 lows, uint32 highs);
380 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
381 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
382 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
383 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
384 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
385 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
386 UNIT *uptr, int32 dfltinc);
387 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
388 t_stat step_svc (UNIT *ptr);
389 t_stat expect_svc (UNIT *ptr);
390 t_stat set_on (int32 flag, CONST char *cptr);
391 t_stat set_verify (int32 flag, CONST char *cptr);
392 t_stat set_message (int32 flag, CONST char *cptr);
393 t_stat set_quiet (int32 flag, CONST char *cptr);
394 t_stat set_localopc (int32 flag, CONST char *cptr);
395 t_stat set_asynch (int32 flag, CONST char *cptr);
396 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
397 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
398 void int_handler (int signal);
399 t_stat set_prompt (int32 flag, CONST char *cptr);
400 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
401 t_stat sim_set_environment (int32 flag, CONST char *cptr);
402 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
403
404
405
406 DEVICE *sim_dflt_dev = NULL;
407 UNIT *sim_clock_queue = QUEUE_LIST_END;
408 int32 sim_interval = 0;
409 int32 sim_switches = 0;
410 FILE *sim_ofile = NULL;
411 SCHTAB *sim_schrptr = NULL;
412 SCHTAB *sim_schaptr = NULL;
413 DEVICE *sim_dfdev = NULL;
414 UNIT *sim_dfunit = NULL;
415 DEVICE **sim_internal_devices = NULL;
416 uint32 sim_internal_device_count = 0;
417 int32 sim_opt_out = 0;
418 int32 sim_is_running = 0;
419 t_bool sim_processing_event = FALSE;
420 uint32 sim_brk_summ = 0;
421 uint32 sim_brk_types = 0;
422 BRKTYPTAB *sim_brk_type_desc = NULL;
423 uint32 sim_brk_dflt = 0;
424 uint32 sim_brk_match_type;
425 t_addr sim_brk_match_addr;
426 char *sim_brk_act[MAX_DO_NEST_LVL];
427 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
428 BRKTAB **sim_brk_tab = NULL;
429 int32 sim_brk_ent = 0;
430 int32 sim_brk_lnt = 0;
431 int32 sim_brk_ins = 0;
432 int32 sim_iglock = 0;
433 int32 sim_nolock = 0;
434 int32 sim_quiet = 0;
435 int32 sim_localopc = 1;
436 int32 sim_randompst = 0;
437 int32 sim_randstate = 0;
438 int32 sim_step = 0;
439 int nodist = 0;
440 #if defined(PERF_STRIP)
441 int32 sim_nostate = 1;
442 #else
443 int32 sim_nostate = 0;
444 #endif
445 static double sim_time;
446 static uint32 sim_rtime;
447 static int32 noqueue_time;
448 volatile int32 stop_cpu = 0;
449 t_value *sim_eval = NULL;
450 static t_value sim_last_val;
451 static t_addr sim_last_addr;
452 FILE *sim_log = NULL;
453 FILEREF *sim_log_ref = NULL;
454 FILE *sim_deb = NULL;
455 FILEREF *sim_deb_ref = NULL;
456 int32 sim_deb_switches = 0;
457 struct timespec sim_deb_basetime;
458 char *sim_prompt = NULL;
459 static FILE *sim_gotofile;
460 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];
461 static int32 sim_do_echo = 0;
462 static int32 sim_show_message = 1;
463 static int32 sim_on_inherit = 0;
464 #if !defined(PERF_STRIP)
465 static int32 sim_realtime = 0;
466 #endif
467 static int32 sim_do_depth = 0;
468 uint64_t sim_free_memory = 0;
469
470 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
471 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
472 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
473 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
474 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
475
476 t_stat sim_last_cmd_stat;
477
478 static SCHTAB sim_stabr;
479 static SCHTAB sim_staba;
480
481 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };
482 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) };
483
484 pthread_t main_thread_id;
485
486
487
488 const char save_vercur[] = "V4.1";
489 const char save_ver40[] = "V4.0";
490 const char save_ver35[] = "V3.5";
491 const char save_ver32[] = "V3.2";
492 const char save_ver30[] = "V3.0";
493 const struct scp_error {
494 const char *code;
495 const char *message;
496 } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
497 {{"NXM", "Address space exceeded"},
498 {"UNATT", "Unit not attached"},
499 {"IOERR", "I/O error"},
500 {"CSUM", "Checksum error"},
501 {"FMT", "Format error"},
502 {"NOATT", "Unit not attachable"},
503 {"OPENERR", "File open error"},
504 {"MEM", "Memory exhausted"},
505 {"ARG", "Invalid argument"},
506 {"STEP", "Step expired"},
507 {"UNK", "Unknown command"},
508 {"RO", "Read only argument"},
509 {"INCOMP", "Command not completed"},
510 {"STOP", "Simulation stopped"},
511 {"EXIT", "Goodbye"},
512 {"TTIERR", "Console input I/O error"},
513 {"TTOERR", "Console output I/O error"},
514 {"EOF", "End of file"},
515 {"REL", "Relocation error"},
516 {"NOPARAM", "No settable parameters"},
517 {"ALATT", "Unit already attached"},
518 {"TIMER", "Hardware timer error"},
519 {"SIGERR", "Signal handler setup error"},
520 {"TTYERR", "Console terminal setup error"},
521 {"SUB", "Subscript out of range"},
522 {"NOFNC", "Command not allowed"},
523 {"UDIS", "Unit disabled"},
524 {"NORO", "Read only operation not allowed"},
525 {"INVSW", "Invalid switch"},
526 {"MISVAL", "Missing value"},
527 {"2FARG", "Too few arguments"},
528 {"2MARG", "Too many arguments"},
529 {"NXDEV", "Non-existent device"},
530 {"NXUN", "Non-existent unit"},
531 {"NXREG", "Non-existent register"},
532 {"NXPAR", "Non-existent parameter"},
533 {"NEST", "Nested DO command limit exceeded"},
534 {"IERR", "Internal error"},
535 {"MTRLNT", "Invalid magtape record length"},
536 {"LOST", "Console Telnet connection lost"},
537 {"TTMO", "Console Telnet connection timed out"},
538 {"STALL", "Console Telnet output stall"},
539 {"AFAIL", "Assertion failed"},
540 {"INVREM", "Invalid remote console command"},
541 {"NOTATT", "Not attached"},
542 {"EXPECT", "Expect matched"},
543 {"REMOTE", "Remote console command"},
544 };
545
546 const size_t size_map[] = { sizeof (int8),
547 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
548 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
549 };
550
551 const t_value width_mask[] = { 0,
552 0x1, 0x3, 0x7, 0xF,
553 0x1F, 0x3F, 0x7F, 0xFF,
554 0x1FF, 0x3FF, 0x7FF, 0xFFF,
555 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
556 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
557 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
558 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
559 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
560 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
561 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
562 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
563 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
564 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
565 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
566 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
567 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
568 };
569
570 static const char simh_help[] =
571
572 "1Commands\n"
573 #define HLP_RESET "*Commands Resetting Devices"
574
575 "2Resetting Devices\n"
576 " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\r\n"
577 " simulator to a predefined condition. If the switch \"`-p`\" is specified,\r\n"
578 " the device is reset to its initial power-on state:\r\n\r\n"
579 "++RESET resets all devices\r\n"
580 "++RESET -p power-cycle all devices\r\n"
581 "++RESET ALL resets all devices\r\n"
582 "++RESET <device> resets the specified <device>\r\n\r\n"
583 " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\r\n"
584 " interrupt requests, and returns the device to a quiescent state.\r\n\r\n"
585 " * It does **NOT** clear the main memory or affect associated I/O\r\n"
586 " connections.\r\n"
587 #define HLP_EXAMINE "*Commands Examining_and_Changing_State"
588 #define HLP_IEXAMINE "*Commands Examining_and_Changing_State"
589 #define HLP_DEPOSIT "*Commands Examining_and_Changing_State"
590 #define HLP_IDEPOSIT "*Commands Examining_and_Changing_State"
591
592 "2Examining and Changing State\n"
593 " There are four commands to examine and change state:\r\n\r\n"
594 " * `EXAMINE` (*abbreviated* `E`) examines state\r\n"
595 " * `DEPOSIT` (*abbreviated* `D`) changes state\r\n"
596 " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\r\n"
597 " and allows the user to interactively change it\r\n"
598 " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\r\n"
599 " interactively change state\r\n\r\n"
600 " All four commands take the form:\r\n\r\n"
601 "++command {modifiers} <object list>\r\n\r\n"
602 " The `DEPOSIT` command requires the deposit value at the end of the command.\r\n\r\n"
603 " There are four kinds of modifiers: **switches**, **device/unit name**,\r\n"
604 " **search specifier**, and for `EXAMINE`, **output file**.\r\n\r\n"
605 " * **Switches** have been described previously.\r\n"
606 " * A **device/unit name** identifies the device and unit whose address\r\n"
607 " space is to be examined or modified. If no device is specified, the CPU\r\n"
608 " main memory is selected. If a device but no unit is specified, unit `0`\r\n"
609 " of the specified device is selected automatically.\r\n"
610 " * The **search specifier** provides criteria for testing addresses or\r\n"
611 " registers to see if they should be processed. The search specifier\r\n"
612 " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\r\n"
613 " both, optionally separated by spaces:\r\n\r\n"
614 "++{ < logical op > < value > } < relational op > < value >\r\n\r\n"
615
616 " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\r\n"
617 " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\r\n"
618 " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\r\n"
619 " equal*), \">=\" (*greater than or equal*), \">\" (*greater\r\n"
620 " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\r\n"
621 " * * If any \"<`logical operator`>\" is specified without\r\n"
622 " a \"<`relational operator`>\", it is ignored.\r\n"
623 " * * If any \"<`relational operator`>\" is specified without\r\n"
624 " a \"<`logical operator`>\", no logical operation is performed.\r\n"
625 " * * All comparisons are unsigned.\r\n\r\n"
626 " * The **output file** modifier redirects the command output to a file\r\n"
627 " instead of the console. The **output file** modifier is specified with\r\n"
628 " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\r\n\r\n"
629 " **NOTE**: Modifiers may be specified in any order. If multiple\r\n"
630 " modifiers of the same type are specified, later modifiers override earlier\r\n"
631 " modifiers. If the **device/unit name** comes *after* the search specifier,\r\n"
632 " the search values will interpreted in the *radix of the CPU*, rather than\r\n"
633 " of the device/unit.\r\n\r\n"
634 " The \"<`object list`>\" argument consists of one or more of the following,\r\n"
635 " separated by commas:\r\n\r\n"
636
637 "++register the specified register\r\n"
638 "++register[sub1-sub2] the specified register array locations,\r\n"
639 "++++++++ starting at location sub1 up to and\r\n"
640 "++++++++ including location sub2\r\n"
641 "++register[sub1/length] the specified register array locations,\r\n"
642 "++++++++ starting at location sub1 up to but\r\n"
643 "++++++++ not including sub1+length\r\n"
644 "++register[ALL] all locations in the specified register\r\n"
645 "++++++++ array\r\n"
646 "++register1-register2 all the registers starting at register1\r\n"
647 "++++++++ up to and including register2\r\n"
648 "++address the specified location\r\n"
649 "++address1-address2 all locations starting at address1 up to\r\n"
650 "++++++++ and including address2\r\n"
651 "++address/length all location starting at address up to\r\n"
652 "++++++++ but not including address+length\r\n"
653 "++STATE all registers in the device\r\n"
654 "++ALL all locations in the unit\r\n"
655 "++$ the last value displayed by an EXAMINE\r\n"
656 "++++++++ command interpreted as an address\r\n"
657 "3Switches\n"
658 "4Formatting Control\n"
659 " Switches can be used to control the format of the displayed information:\r\n\r\n"
660
661 "5`-a`\n"
662 " display as ASCII\r\n"
663 "5`-c`\n"
664 " display as character string\r\n"
665 "5`-m`\n"
666 " display as instruction mnemonics\r\n"
667 "5`-o`\n"
668 " display as octal\r\n"
669 "5`-d`\n"
670 " display as decimal\r\n"
671 "5`-h`\n"
672 " display as hexadecimal\r\n\r\n"
673 "3Examples\n"
674 "++ex 1000-1100 examine 1000 to 1100\r\n"
675 "++de PC 1040 set PC to 1040\r\n"
676 "++ie 40-50 interactively examine 40:50\r\n"
677 "++ie >1000 40-50 interactively examine the subset\r\n"
678 "+++++++++ of locations 40:50 that are >1000\r\n"
679 "++ex rx0 50060 examine 50060, RX unit 0\r\n"
680 "++ex rx sbuf[3-6] examine SBUF[3] to SBUF[6] in RX\r\n"
681 "++de all 0 set main memory to 0\r\n"
682 "++de &77>0 0 set all addresses whose low order\r\n"
683 "+++++++++ bits are non-zero to 0\r\n"
684 "++ex -m @memdump.txt 0-7777 dump memory to file\r\n\r\n"
685 " * **NOTE**: To terminate an interactive command, simply type any bad value\r\n"
686 " (*e.g.* `XYZ`) when input is requested.\r\n"
687 #define HLP_EVALUATE "*Commands Evaluating_Instructions"
688
689 "2Evaluating Instructions\n"
690 " The `EVAL` command evaluates a symbolic expression and returns the\r\n"
691 " equivalent numeric value.\r\n\r\n"
692
693 "2Running A Simulated Program\n"
694 #define HLP_RUN "*Commands Running_A_Simulated_Program RUN"
695 "3RUN\n"
696 " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\r\n"
697 " argument, if given, in the PC (program counter), and starts execution.\r\n"
698 " If no argument is given execution starts at the current PC.\r\n"
699 #define HLP_GO "*Commands Running_A_Simulated_Program GO"
700 "3GO\n"
701 " The `GO` command does *not* reset devices, deposits its argument (if\r\n"
702 " given) in the PC, and starts execution. If no argument is given,\r\n"
703 " execution starts at the current PC (program counter).\r\n"
704 #define HLP_CONTINUE "*Commands Running_A_Simulated_Program Continuing_Execution"
705 "3Continuing Execution\n"
706 " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\r\n"
707 " (if execution was stopped, possibly due to hitting a breakpoint) at the\r\n"
708 " current program counter without resetting any devices.\r\n"
709 #define HLP_STEP "*Commands Running_A_Simulated_Program Step_Execution"
710 "3Step Execution\n"
711 " The `STEP` command (*abbreviated* `S`) resumes execution at the current\r\n"
712 " PC for the number of instructions given by its argument. If no argument\r\n"
713 " is supplied, one instruction is executed.\r\n"
714 "4Switches\n"
715 "5`-T`\n"
716 " If the `STEP` command is invoked with the \"`-T`\" switch, the step\r\n"
717 " command will cause execution to run for *microseconds* rather than\r\n"
718 " instructions.\r\n"
719 #define HLP_NEXT "*Commands Running_A_Simulated_Program NEXT"
720 "3NEXT\n"
721 " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\r\n"
722 " for one instruction, attempting to execute *through* subroutine calls.\r\n"
723 " If the next instruction to be executed is *not* a subroutine call, then\r\n"
724 " one instruction is executed.\r\n"
725 #define HLP_BOOT "*Commands Running_A_Simulated_Program Booting_the_system"
726 "3Booting the system\n"
727 " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\r\n"
728 " the device and unit given by its argument. If no unit is supplied,\r\n"
729 " unit `0` is bootstrapped. The specified unit must be `ATTACH`'ed.\r\n\r\n"
730 " When booting Multics, the boot device should always be `iom0`.\r\n"
731 " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\r\n"
732 " into memory and the system will transfer control to the boot record.\r\n\r\n"
733 " **Example**\r\n\r\n"
734 "++; Boot Multics using iom0\r\n"
735 "++boot iom0\r\n\r\n"
736
737 "2Stopping The Simulator\n"
738 " The simulator runs until the simulated hardware encounters an error, or\r\n"
739 " until the user forces a stop condition.\r\n"
740 "3Simulator Detected Stop Conditions\n"
741 " These simulator-detected conditions stop simulation:\r\n\r\n"
742 "++- HALT instruction. If a HALT instruction is decoded, simulation stops.\r\n\r\n"
743 "++- I/O error. If an I/O error occurs during simulation of an I/O\r\n"
744 "+++operation, and the device stop-on-I/O-error flag is set, simulation\r\n"
745 "+++usually stops.\r\n\r\n"
746 "++- Processor condition. Certain processor conditions can stop\r\n"
747 "+++the simulation.\r\n"
748 "3User Specified Stop Conditions\n"
749 " Typing the interrupt character stops simulation. The interrupt character\r\n"
750 " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\r\n"
751 " set to `005` (`^E`).\r\n\r\n"
752
753 #define HLP_BREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
754 #define HLP_NOBREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
755 "4Breakpoints\n"
756 " The simulator offers breakpoint capability for debugging. Users may define\r\n"
757 " breakpoints of different types, identified by letter (for example, `E`\r\n"
758 " for *execution*, `R` for *read*, `W` for *write*, etc).\r\n\r\n"
759 " Associated with each breakpoint is a count and, optionally, one or more\r\n"
760 " actions. Each time a breakpoint occurs, the associated count\r\n"
761 " is *decremented*. If the count is less than or equal to `0`, the breakpoint\r\n"
762 " occurs; otherwise, it is deferred. When the breakpoint occurs, any\r\n"
763 " optional actions are automatically executed.\r\n\r\n"
764 " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\r\n\r\n"
765 "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\r\n\r\n"
766 " If no type is specified, the default breakpoint type (`E`, *execution*) is\r\n"
767 " used. If no address range is specified, the current PC is used. As\r\n"
768 " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\r\n"
769 " range of addresses low-high, or a relative range of address/length.\r\n"
770
771 "5Displaying Breakpoints\n"
772 " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\r\n\r\n"
773 "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\r\n\r\n"
774 " Locations with breakpoints of the specified type are displayed.\r\n\r\n"
775 " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\r\n"
776 " commands which may be subsequently used to establish the same\r\n"
777 " breakpoint(s).\r\n\r\n"
778 "5Removing Breakpoints\n"
779 " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\r\n"
780 "5Examples\n"
781 " The following examples illustrate breakpoint usage:\r\n\r\n"
782 "++BREAK set E break at current PC\r\n"
783 "++BREAK -e 200 set E break at 200\r\n"
784 "++BREAK 2000/2[2] set E breaks at 2000,2001 with count = 2\r\n"
785 "++BREAK 100;EX AC;D MQ 0 set E break at 100 with actions EX AC and\r\n"
786 "+++++++++D MQ 0\r\n"
787 "++BREAK 100; delete action on break at 100\r\n\r\n"
788
789 "2Connecting and Disconnecting Devices\n"
790 " Units are simulated as files on the host file system. Before using any\r\n"
791 " simulated unit, the user must specify the file to be accessed by that unit.\r\n"
792 #define HLP_ATTACH "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
793 "3Attaching devices\n"
794 " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\r\n\r\n"
795 "++ATTACH <unit> <filename>\r\n\r\n"
796 " Some devices have more detailed or specific help available with:\r\n\r\n"
797 "++HELP <device> ATTACH\r\n\r\n"
798 "4Switches\n"
799 "5`-n`\n"
800 " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\r\n"
801 " file will be created when the filename specified does not exist, or an\r\n"
802 " existing file will have it's size truncated to zero, and an appropriate\r\n"
803 " message is printed.\r\n"
804 "5`-e`\n"
805 " If the file does not exist, and the \"`-e`\" switch *was not* specified,\r\n"
806 " a new file is created, and an appropriate message is printed. If\r\n"
807 " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\r\n"
808 " error message is printed.\r\n"
809 "5`-r`\n"
810 " If the \"`-r`\" switch is specified, or the file is write protected by\r\n"
811 " host operating system, `ATTACH` tries to open the file in read only mode.\r\n"
812 " If the file does not exist, or the unit does not support read only\r\n"
813 " operation, an error occurs. Input-only devices, such as card readers, or\r\n"
814 " storage devices with write locking switches, such as disks or tapes,\r\n"
815 " support read only operation - other devices do not. If a file is\r\n"
816 " attached read only, its contents can be examined but not modified.\r\n"
817 "5`-q`\n"
818 " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\r\n"
819 " or opening one read only (\"`-r`\"), the message announcing this fact\r\n"
820 " is suppressed.\r\n"
821 "5`-f`\n"
822 " For simulated magnetic tapes, the `ATTACH` command can specify the format\r\n"
823 " of the attached tape image file:\r\n\r\n"
824 "++ATTACH -f <tape_unit> <format> <filename>\r\n\r\n"
825 " * The currently supported magnetic tape image file formats are:\r\n\r\n"
826 " | | |\r\n"
827 " | ----------------:|:---------------------------------------------------- |\r\n"
828 " | \"**`SIMH`**\" | The **SIMH** / **DPS8M** native portable tape format |\r\n"
829 " | \"**`E11`**\" | The *D Bit* **Ersatz-11** simulator format |\r\n"
830 " | \"**`TPC`**\" | The **TPC** format (*used by _SIMH_ prior to V2.3*) |\r\n"
831 " | \"**`P7B`**\" | The **Paul Pierce** `7`-track tape archive format |\r\n\r\n"
832
833 " * The default tape format can also be specified with the `SET` command\r\n"
834 " prior to using the `ATTACH` command:\r\n\r\n"
835 "++SET <tape_unit> FORMAT=<format>\r\n"
836 "++ATTACH <tape_unit> <filename>\r\n\r\n"
837 " * The format of a currently attached tape image can be displayed with\r\n"
838 " the `SHOW FORMAT` command:\r\n\r\n"
839 "++SHOW <unit> FORMAT\r\n\r\n"
840 " **Examples**\r\n\r\n"
841 " The following example illustrates common `ATTACH` usage:\r\n"
842 "++; Associate the tape image file \"12.8MULTICS.tap\" with the tape0 unit\r\n"
843 "++; in read-only mode, where tape0 corresponds to the first tape device.\r\n"
844 "++ATTACH -r tape0 12.8MULTICS.tap\r\n\r\n"
845 "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\r\n"
846 "++; The disk0 unit corresponds to the first disk device.\r\n"
847 "++ATTACH disk0 root.dsk\r\n\r\n"
848
849 #define HLP_DETACH "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
850 "3Detaching devices\n"
851 " The `DETACH` (*abbreviation* `DET`) command breaks the association between\r\n"
852 " a unit and its backing file or device:\r\n\r\n"
853 "++DETACH ALL Detach all units\r\n"
854 "++DETACH <unit> Detach specified unit\r\n\r\n"
855 " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\r\n"
856 #define HLP_SET "*Commands SET"
857 "2SET\n"
858
859 #define HLP_SET_LOG "*Commands SET Logging"
860 "3Logging\n"
861 " Interactions with the simulator session can be recorded to a log file.\r\n\r\n"
862 "+SET LOG log_file Specify the log destination\r\n"
863 "++++++++ (STDOUT, DEBUG, or filename)\r\n"
864 "+SET NOLOG Disables any currently active logging\r\n"
865 "4Switches\n"
866 "5`-N`\n"
867 " By default, log output is written at the *end* of the specified log file.\r\n"
868 " A new log file can created if the \"`-N`\" switch is used on the command\r\n"
869 " line.\r\n\r\n"
870 "5`-B`\n"
871 " By default, log output is written in *text* mode. The log file can be\r\n"
872 " opened for *binary* mode writing if the \"`-B`\" switch is used on the\r\n"
873 " command line.\r\n"
874 #define HLP_SET_DEBUG "*Commands SET Debug_Messages"
875
876 "3Debug Messages\n"
877 "+SET DEBUG debug_file Specify the debug destination\r\n"
878 "++++++++ (STDOUT, STDERR, LOG, or filename)\r\n"
879 "+SET NODEBUG Disables any currently active debug output\r\n"
880 "4Switches\n"
881 " Debug message output contains a timestamp which indicates the number of\r\n"
882 " simulated instructions which have been executed prior to the debug event.\r\n\r\n"
883 " Debug message output can be enhanced to contain additional, potentially\r\n"
884 " useful information.\r\n\r\n\r\n"
885 " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\r\n"
886 "5`-T`\n"
887 " The \"`-T`\" switch causes debug output to contain a time of day displayed\r\n"
888 " as `hh:mm:ss.msec`.\r\n"
889 "5`-A`\n"
890 " The \"`-A`\" switch causes debug output to contain a time of day displayed\r\n"
891 " as `seconds.msec`.\r\n"
892 "5`-R`\n"
893 " The \"`-R`\" switch causes timing to be relative to the start of debugging.\r\n"
894 "5`-P`\n"
895 " The \"`-P`\" switch adds the output of the PC (program counter) to each\r\n"
896 " debug message.\r\n"
897 "5`-N`\n"
898 " The \"`-N`\" switch causes a new (empty) file to be written to.\r\n"
899 " (The default is to append to an existing debug log file).\r\n"
900 "5`-D`\n"
901 " The \"`-D`\" switch causes data blob output to also display the data\r\n"
902 " as **`RADIX-50`** characters.\r\n"
903 "5`-E`\n"
904 " The \"`-E`\" switch causes data blob output to also display the data\r\n"
905 " as \"**EBCDIC**\" characters.\r\n"
906
907 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
908 "3Environment Variables\n"
909 "+SET ENVIRONMENT NAME=val Set environment variable\r\n"
910 "+SET ENVIRONMENT NAME Clear environment variable\r\n"
911 #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
912 "3Command Status Trap Dispatching\n"
913 "+SET ON Enables error checking command execution\r\n"
914 "+SET NOON Disables error checking command execution\r\n"
915 "+SET ON INHERIT Enables inheritance of ON state and actions\r\n"
916 "+SET ON NOINHERIT Disables inheritance of ON state and actions\r\n"
917 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
918 "3Command Execution Display\n"
919 "+SET VERIFY Enables display of processed script commands\r\n"
920 "+SET VERBOSE Enables display of processed script commands\r\n"
921 "+SET NOVERIFY Disables display of processed script commands\r\n"
922 "+SET NOVERBOSE Disables display of processed script commands\r\n"
923 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
924 "3Command Error Status Display\n"
925 "+SET MESSAGE Re-enables display of script error messages\r\n"
926 "+SET NOMESSAGE Disables display of script error messages\r\n"
927 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
928 "3Command Output Display\n"
929 "+SET QUIET Disables suppression of some messages\r\n"
930 "+SET NOQUIET Re-enables suppression of some messages\r\n"
931 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
932 "3Local Operator Console\n"
933 "+SET LOCALOPC Enables local operator console\r\n"
934 "+SET NOLOCALOPC Disables local operator console\r\n"
935 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
936 "3Command Prompt\n"
937 "+SET PROMPT \"string\" Sets an alternate simulator prompt string\r\n"
938 "3Device and Unit Settings\n"
939 "+SET <dev> OCT|DEC|HEX Set device display radix\r\n"
940 "+SET <dev> ENABLED Enable device\r\n"
941 "+SET <dev> DISABLED Disable device\r\n"
942 "+SET <dev> DEBUG{=arg} Set device debug flags\r\n"
943 "+SET <dev> NODEBUG={arg} Clear device debug flags\r\n"
944 "+SET <dev> arg{,arg...} Set device parameters\r\n"
945 "+SET <unit> ENABLED Enable unit\r\n"
946 "+SET <unit> DISABLED Disable unit\r\n"
947 "+SET <unit> arg{,arg...} Set unit parameters\r\n"
948 "+HELP <dev> SET Displays any device specific SET commands\r\n"
949 " \r\n\r\n"
950 " See the Omnibus documentation for a complete SET command reference.\r\n"
951
952 #define HLP_SHOW "*Commands SHOW"
953 "2SHOW\n"
954 "+SH{OW} B{UILDINFO} Show build-time compilation information\r\n"
955 "+SH{OW} CL{OCKS} Show wall clock and timer information\r\n"
956 "+SH{OW} C{ONFIGURATION} Show simulator configuration\r\n"
957 "+SH{OW} D{EFAULT_BASE_SYSTEM} Show default base system script\r\n"
958 "+SH{OW} DEV{ICES} Show devices\r\n"
959 "+SH{OW} H{INTS} Show configuration hints\r\n"
960 "+SH{OW} M{ODIFIERS} Show SET commands for all devices\r\n"
961 "+SH{OW} O{N} Show ON condition actions\r\n"
962 "+SH{OW} P{ROM} Show CPU ID PROM initialization data\r\n"
963 "+SH{OW} Q{UEUE} Show event queue\r\n"
964 "+SH{OW} S{HOW} Show SHOW commands for all devices\r\n"
965 "+SH{OW} T{IME} Show simulated timer\r\n"
966 "+SH{OW} VE{RSION} Show simulator version\r\n"
967 "+H{ELP} <dev> SHOW Show device-specific SHOW commands\r\n"
968 "+SH{OW} <dev> {arg,...} Show device parameters\r\n"
969 "+SH{OW} <dev> DEBUG Show device debug flags\r\n"
970 "+SH{OW} <dev> MODIFIERS Show device modifiers\r\n"
971 "+SH{OW} <dev> RADIX Show device display radix\r\n"
972 "+SH{OW} <dev> SHOW Show device SHOW commands\r\n"
973 "+SH{OW} <unit> {arg,...} Show unit parameters\r\n\r\n"
974 " See the Omnibus documentation for a complete SHOW command reference.\r\n\r\n"
975 #define HLP_SHOW_CONFIG "*Commands SHOW"
976 #define HLP_SHOW_DEVICES "*Commands SHOW"
977 #define HLP_SHOW_FEATURES "*Commands SHOW"
978 #define HLP_SHOW_QUEUE "*Commands SHOW"
979 #define HLP_SHOW_TIME "*Commands SHOW"
980 #define HLP_SHOW_MODIFIERS "*Commands SHOW"
981 #define HLP_SHOW_NAMES "*Commands SHOW"
982 #define HLP_SHOW_SHOW "*Commands SHOW"
983 #define HLP_SHOW_VERSION "*Commands SHOW"
984 #define HLP_SHOW_BUILDINFO "*Commands SHOW"
985 #define HLP_SHOW_PROM "*Commands SHOW"
986 #define HLP_SHOW_HINTS "*Commands SHOW"
987 #define HLP_SHOW_DBS "*Commands SHOW"
988 #define HLP_SHOW_DEFAULT "*Commands SHOW"
989 #define HLP_SHOW_CONSOLE "*Commands SHOW"
990 #define HLP_SHOW_REMOTE "*Commands SHOW"
991 #define HLP_SHOW_BREAK "*Commands SHOW"
992 #define HLP_SHOW_LOG "*Commands SHOW"
993 #define HLP_SHOW_DEBUG "*Commands SHOW"
994 #define HLP_SHOW_CLOCKS "*Commands SHOW"
995 #define HLP_SHOW_ON "*Commands SHOW"
996 #define HLP_SHOW_SEND "*Commands SHOW"
997 #define HLP_SHOW_EXPECT "*Commands SHOW"
998 #define HLP_HELP "*Commands HELP"
999
1000 "2HELP\n"
1001 "+H{ELP} Show this message\r\n"
1002 "+H{ELP} <command> Show help for command\r\n"
1003 "+H{ELP} <dev> Show help for device\r\n"
1004 "+H{ELP} <dev> REGISTERS Show help for device register variables\r\n"
1005 "+H{ELP} <dev> ATTACH Show help for device specific ATTACH command\r\n"
1006 "+H{ELP} <dev> SET Show help for device specific SET commands\r\n"
1007 "+H{ELP} <dev> SHOW Show help for device specific SHOW commands\r\n"
1008 "+H{ELP} <dev> <command> Show help for device specific <command> command\r\n"
1009
1010 "2Altering The Simulated Configuration\n"
1011 " The \"SET <device> DISABLED\" command removes a device from the configuration.\r\n"
1012 " A `DISABLED` device is invisible to running programs. The device can still\r\n"
1013 " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\r\n\r\n"
1014 " The \"SET <device> ENABLED\" command restores a disabled device to a\r\n"
1015 " configuration.\r\n\r\n"
1016 " Most multi-unit devices allow units to be enabled or disabled:\r\n\r\n"
1017 "++SET <unit> ENABLED\r\n"
1018 "++SET <unit> DISABLED\r\n\r\n"
1019 " When a unit is disabled, it will not be displayed by SHOW DEVICE.\r\n\r\n"
1020
1021 #define HLP_DO "*Commands Executing_Command_Files Processing_Command_Files"
1022 "2Executing Command Files\n"
1023 "3Processing Command Files\n"
1024 " The simulator can invoke another script file with the \"`DO`\" command:\r\n\r\n"
1025 "++DO <filename> {arguments...} execute commands in specified file\r\n\r\n"
1026 " The \"`DO`\" command allows command files to contain substitutable\r\n"
1027 " arguments. The string \"`%%n`\", where \"`n`\" is a number\r\n"
1028 " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\r\n"
1029 " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\r\n"
1030 " The string \"`%%0`\" is replaced with \"<`filename`>\"\r\n"
1031 " The sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\r\n"
1032 " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\r\n"
1033 " be enclosed in matching single or double quotation marks.\r\n\r\n"
1034 " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\r\n"
1035 " deep.\r\n\r\n"
1036 "4Switches\n"
1037 "5`-v`\n\n"
1038 " If the switch \"`-v`\" is specified, commands in the command file are\r\n"
1039 " echoed *before* they are executed.\r\n\r\n"
1040 "5`-e`\n\n"
1041 " If the switch \"`-e`\" is specified, command processing (including nested\r\n"
1042 " command invocations) will be aborted if any command error is encountered.\r\n"
1043 " (A simulation stop **never** aborts processing; use `ASSERT` to catch\r\n"
1044 " unexpected stops.) Without this switch, all errors except `ASSERT` failures\r\n"
1045 " will be ignored, and command processing will continue.\r\n\r\n"
1046 "5`-o`\n\n"
1047 " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\r\n"
1048 " the calling command file will be inherited by the command file being\r\n"
1049 " invoked.\r\n"
1050 "5`-q`\n\n"
1051 " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\r\n"
1052 " enabled for the called command file, otherwise the *quiet mode* setting\r\n"
1053 " is inherited from the calling context.\r\n"
1054
1055 #define HLP_GOTO "*Commands Executing_Command_Files GOTO"
1056 "3GOTO\n"
1057 " Commands in a command file execute in sequence until either an error\r\n"
1058 " trap occurs (when a command completes with an error status), or when an\r\n"
1059 " explicit request is made to start command execution elsewhere with\r\n"
1060 " the `GOTO` command:\r\n\r\n"
1061 "++GOTO <label>\r\n\r\n"
1062 " * Labels are lines in a command file which the first non-whitespace\r\n"
1063 " character is a \"`:`\".\r\n"
1064 " * The target of a `GOTO` is the first matching label in the current `DO`\r\n"
1065 " command file which is encountered.\r\n\r\n"
1066 " **Example**\r\n\r\n"
1067 " The following example illustrates usage of the `GOTO` command (by\r\n"
1068 " creating an infinite loop):\r\n\r\n"
1069 "++:Label\r\n"
1070 "++:: This is a loop.\r\n"
1071 "++GOTO Label\r\n\r\n"
1072 #define HLP_RETURN "*Commands Executing_Command_Files RETURN"
1073
1074 "3RETURN\n"
1075 " The `RETURN` command causes the current procedure call to be restored to\r\n"
1076 " the calling context, possibly returning a specific return status.\r\n"
1077 " If no return status is specified, the return status from the last command\r\n"
1078 " executed will be returned. The calling context may have `ON` traps defined\r\n"
1079 " which may redirect command flow in that context.\r\n\r\n"
1080 "++RETURN return from command file with last command status\r\n"
1081 "++RETURN {-Q} <status> return from command file with specific status\r\n\r\n"
1082 " * The status return can be any numeric value or one of the standard SCPE_\r\n"
1083 " condition names.\r\n\r\n"
1084 " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\r\n"
1085 " status to be returned, but normal error status message printing to be\r\n"
1086 " suppressed.\r\n\r\n"
1087 " **Condition Names**\r\n\r\n"
1088 " The available standard SCPE_ condition names and their meanings are:\r\n\r\n"
1089 " | Name | Meaning | Name | Meaning |\r\n"
1090 " | ------- | --------------------------------| ------- | ----------------------------------- |\r\n"
1091 " | NXM | Address space exceeded | UNATT | Unit not attached |\r\n"
1092 " | IOERR | I/O error | CSUM | Checksum error |\r\n"
1093 " | FMT | Format error | NOATT | Unit not attachable |\r\n"
1094 " | OPENERR | File open error | MEM | Memory exhausted |\r\n"
1095 " | ARG | Invalid argument | STEP | Step expired |\r\n"
1096 " | UNK | Unknown command | RO | Read only argument |\r\n"
1097 " | INCOMP | Command not completed | STOP | Simulation stopped |\r\n"
1098 " | EXIT | Goodbye | TTIERR | Console input I/O error |\r\n"
1099 " | TTOERR | Console output I/O error | EOF | End of file |\r\n"
1100 " | REL | Relocation error | NOPARAM | No settable parameters |\r\n"
1101 " | ALATT | Unit already attached | TIMER | Hardware timer error |\r\n"
1102 " | SIGERR | Signal handler setup error | TTYERR | Console terminal setup error |\r\n"
1103 " | NOFNC | Command not allowed | UDIS | Unit disabled |\r\n"
1104 " | NORO | Read only operation not allowed | INVSW | Invalid switch |\r\n"
1105 " | MISVAL | Missing value | 2FARG | Too few arguments |\r\n"
1106 " | 2MARG | Too many arguments | NXDEV | Non-existent device |\r\n"
1107 " | NXUN | Non-existent unit | NXREG | Non-existent register |\r\n"
1108 " | NXPAR | Non-existent parameter | NEST | Nested DO command limit exceeded |\r\n"
1109 " | IERR | Internal error | MTRLNT | Invalid magtape record length |\r\n"
1110 " | LOST | Console Telnet connection lost | TTMO | Console Telnet connection timed out |\r\n"
1111 " | STALL | Console Telnet output stall | AFAIL | Assertion failed |\r\n"
1112 " | INVREM | Invalid remote console command | | |\r\n"
1113 "\r\n\r\n"
1114 #define HLP_SHIFT "*Commands Executing_Command_Files Shift_Parameters"
1115 "3Shift Parameters\n"
1116 " Shift the command files positional parameters\r\n"
1117 #define HLP_CALL "*Commands Executing_Command_Files Call_a_subroutine"
1118 "3Call a subroutine\n"
1119 " Control can be transferred to a labeled subroutine using `CALL`.\r\n\r\n"
1120 " **Example**\r\n\r\n"
1121 "++CALL routine\r\n"
1122 "++BYE\r\n"
1123 "++\r\n"
1124 "++:routine\r\n"
1125 "++ECHO routine called\r\n"
1126 "++RETURN\r\n\r\n"
1127 #define HLP_ON "*Commands Executing_Command_Files ON"
1128 "3ON\n"
1129 " The `ON` command performs actions after a condition, or clears a condition.\r\n"
1130 "++ON <condition> <action> Perform action after condition\r\n"
1131 "++ON <condition> Clears action of specified condition\r\n"
1132 #define HLP_PROCEED "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1133 #define HLP_IGNORE "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1134
1135 "3PROCEED or IGNORE\n"
1136 " The `PROCEED` (or `IGNORE`) command does nothing. It is potentially\r\n"
1137 " useful as a placeholder for any `ON` action condition that should be\r\n"
1138 " explicitly ignored, allowing command file execution to continue without\r\n"
1139 " taking any specific action.\r\n"
1140 #define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1141
1142 "3Displaying Arbitrary Text\n"
1143 " The `ECHO` command is a useful way of annotating command files. `ECHO`\r\n"
1144 " prints out its arguments to the console (and to any applicable log file):\r\n\r\n"
1145 "++ECHO <string> Output string to console\r\n\r\n"
1146 " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\r\n"
1147 " This may be used to provide spacing for console messages or log file\r\n"
1148 " output.\r\n"
1149
1150 #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Assertions"
1151 "3Testing Assertions\n"
1152 " The `ASSERT` command tests a simulator state condition and halts command\r\n"
1153 " file execution if the condition is false:\r\n\r\n"
1154 "++ASSERT <Simulator State Expressions>\r\n\r\n"
1155 " * If the indicated expression evaluates to false, the command completes\r\n"
1156 " with an `AFAIL` condition. By default, when a command file encounters a\r\n"
1157 " command which returns the `AFAIL` condition, it will exit the running\r\n"
1158 " command file with the `AFAIL` status to the calling command file. This\r\n"
1159 " behavior can be changed with the `ON` command as well as switches to the\r\n"
1160 " invoking `DO` command.\r\n\r\n"
1161 " **Examples**\r\n\r\n"
1162 " The command file below might be used to bootstrap a hypothetical system\r\n"
1163 " that halts after the initial load from disk. The `ASSERT` command can then\r\n"
1164 " be used to confirm that the load completed successfully by examining the\r\n"
1165 " CPU's \"`A`\" register for the expected value:`\r\n\r\n"
1166 "++; Example INI file\r\n"
1167 "++BOOT\r\n"
1168 "++; A register contains error code; 0 = good boot\r\n"
1169 "++ASSERT A=0\r\n"
1170 "++RUN\r\n\r\n"
1171
1172 " * In the above example, if the \"`A`\" register is *not* `0`,\r\n"
1173 " the \"`ASSERT A=0`\" command will be displayed to the user, and the\r\n"
1174 " command file will be aborted with an \"`Assertion failed`\" message.\r\n"
1175 " Otherwise, the command file will continue to bring up the system.\r\n\r\n"
1176 " * See the **`IF`** command documentation for more information and details\r\n"
1177 " regarding simulator state expressions.\r\n\r\n"
1178 #define HLP_IF "*Commands Executing_Command_Files Testing_Conditions"
1179 "3Testing Conditions\n"
1180 " The `IF` command tests a simulator state condition and executes additional\r\n"
1181 " commands if the condition is true:\r\n\r\n"
1182 "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\r\n\r\n"
1183 " **Examples**\r\n\r\n"
1184 " The command file below might be used to bootstrap a hypothetical system\r\n"
1185 " that halts after the initial load from disk. The `IF` command can then\r\n"
1186 " be used to confirm that the load completed successfully by examining the\r\n"
1187 " CPU's \"`A`\" register for an expected value:\r\n\r\n"
1188 "++; Example INI file\r\n"
1189 "++BOOT\r\n"
1190 "++; A register contains error code; 0 = good boot\r\n"
1191 "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\r\n"
1192 "++RUN\r\n\r\n"
1193
1194 " * In the above example, if the \"`A`\" register is *not* `0`, the\r\n"
1195 " message \"`Boot failed - Failure Code `\" will be displayed, the contents\r\n"
1196 " of the \"`A`\" register will be displayed, and the command file will be\r\n"
1197 " aborted with an \"`Assertion failed`\" message. Otherwise, the command\r\n"
1198 " file will continue to bring up the system.\r\n"
1199 "4Conditional Expressions\n"
1200 " The `IF` and `ASSERT` commands evaluate the following two different forms\r\n"
1201 " of conditional expressions.\r\n\r\n"
1202 "5Simulator State Expressions\n"
1203 " \r\n \r\n"
1204 " The values of simulator registers can be evaluated with:\r\n\r\n"
1205 "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\r\n\r\n"
1206 " * If \"<`dev`>\" is not specified, `CPU` is assumed. \"<`reg`>\" is a\r\n"
1207 " register belonging to the indicated device.\r\n"
1208 " * The \"<`addr`>\" is an address in the address space of the indicated\r\n"
1209 " device.\r\n"
1210 " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\r\n"
1211 " the same as those used for \"search specifiers\" by the `EXAMINE` and\r\n"
1212 " `DEPOSIT` commands.\r\n"
1213 " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\r\n"
1214 " not in the radix for the device when referencing a register; when an\r\n"
1215 " address is referenced the device radix is used as the default.\r\n\r\n"
1216 " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\r\n"
1217 " register value is first altered as indicated. The result is then compared\r\n"
1218 " to the \"<`value`>\" via the \"<`conditional-op`>\".\r\n"
1219 " * * If the result is *true*, the command(s) are executed before proceeding\r\n"
1220 " to the next line in the command file.\r\n"
1221 " * * If the result is *false*, the next command in the command file is\r\n"
1222 " processed.\r\n\r\n"
1223 "5String Comparison Expressions\n"
1224 " \r\n \r\n"
1225 " String Values can be compared with:\r\n\r\n"
1226 "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\r\n\r\n"
1227 " * The \"`-i`\" switch, if present, causes a comparison to be case\r\n"
1228 " insensitive.\r\n"
1229 " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\r\n"
1230 " values which may have environment variables substituted as desired.\r\n"
1231 " * The \"<`compare-op`>\" may be one of:\r\n\r\n"
1232 " | | |\r\n"
1233 " | --------------:|:---------------------- |\r\n"
1234 " | \"**`==`**\" | equal |\r\n"
1235 " | \"**`EQU`**\" | equal |\r\n"
1236 " | \"**`!=`**\" | not equal |\r\n"
1237 " | \"**`NEQ`**\" | not equal |\r\n"
1238 " | \"**<**\" | less than |\r\n"
1239 " | \"**`LSS`**\" | less than |\r\n"
1240 " | \"**<=**\" | less than or equal |\r\n"
1241 " | \"**`LEQ`**\" | less than or equal |\r\n"
1242 " | \"**>**\" | greater than |\r\n"
1243 " | \"**`GTR`**\" | greater than |\r\n"
1244 " | \"**>=**\" | greater than or equal |\r\n"
1245 " | \"**`GEQ`**\" | greater than or equal |\r\n"
1246 " * **NOTE**: Comparisons are *generic*. This means that if\r\n"
1247 " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\r\n"
1248 " digits, then the strings are converted to numbers and a numeric\r\n"
1249 " comparison is performed. For example, the comparison\r\n"
1250 " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\r\n"
1251
1252 #define HLP_EXIT "*Commands Exiting_the_Simulator"
1253 "2Exiting the Simulator\n"
1254 " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\r\n"
1255 " returning control to the host operating system.\r\n"
1256
1257 #define HLP_SPAWN "*Commands Executing_System_Commands"
1258 "2Executing System Commands\n"
1259 " * The simulator can execute host operating system commands with\r\n"
1260 " the \"`!`\" (*spawn*) command.\r\n\r\n"
1261 " | | |\r\n"
1262 " |:----------------------- |:------------------------------------------- |\r\n"
1263 " | \"**`!`**\" | Spawn the hosts default command interpreter |\r\n"
1264 " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\r\n\r\n"
1265 " * **NOTE**: The *exit status* from the command which was executed is set\r\n"
1266 " as the *command completion status* for the \"`!`\" command. This may\r\n"
1267 " influence any enabled `ON` condition traps.\r\n" ;
1268
1269
1270 static CTAB cmd_table[] = {
1271 { "RESET", &reset_cmd, 0, HLP_RESET },
1272 { "EXAMINE", &exdep_cmd, EX_E, HLP_EXAMINE },
1273 { "IEXAMINE", &exdep_cmd, EX_E+EX_I, HLP_IEXAMINE },
1274 { "DEPOSIT", &exdep_cmd, EX_D, HLP_DEPOSIT },
1275 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, HLP_IDEPOSIT },
1276 { "EVALUATE", &eval_cmd, 0, HLP_EVALUATE },
1277 { "RUN", &run_cmd, RU_RUN, HLP_RUN, NULL, &run_cmd_message },
1278 { "GO", &run_cmd, RU_GO, HLP_GO, NULL, &run_cmd_message },
1279 { "STEP", &run_cmd, RU_STEP, HLP_STEP, NULL, &run_cmd_message },
1280 { "NEXT", &run_cmd, RU_NEXT, HLP_NEXT, NULL, &run_cmd_message },
1281 { "CONTINUE", &run_cmd, RU_CONT, HLP_CONTINUE, NULL, &run_cmd_message },
1282 { "BOOT", &run_cmd, RU_BOOT, HLP_BOOT, NULL, &run_cmd_message },
1283 { "BREAK", &brk_cmd, SSH_ST, HLP_BREAK },
1284 { "NOBREAK", &brk_cmd, SSH_CL, HLP_NOBREAK },
1285 { "ATTACH", &attach_cmd, 0, HLP_ATTACH },
1286 { "DETACH", &detach_cmd, 0, HLP_DETACH },
1287 { "EXIT", &exit_cmd, 0, HLP_EXIT },
1288 { "QUIT", &exit_cmd, 0, NULL },
1289 { "BYE", &exit_cmd, 0, NULL },
1290 { "SET", &set_cmd, 0, HLP_SET },
1291 { "SHOW", &show_cmd, 0, HLP_SHOW },
1292 { "DO", &do_cmd, 1, HLP_DO },
1293 { "GOTO", &goto_cmd, 1, HLP_GOTO },
1294 { "RETURN", &return_cmd, 0, HLP_RETURN },
1295 { "SHIFT", &shift_cmd, 0, HLP_SHIFT },
1296 { "CALL", &call_cmd, 0, HLP_CALL },
1297 { "ON", &on_cmd, 0, HLP_ON },
1298 { "IF", &assert_cmd, 0, HLP_IF },
1299 { "PROCEED", &noop_cmd, 0, HLP_PROCEED },
1300 { "IGNORE", &noop_cmd, 0, HLP_IGNORE },
1301 { "ECHO", &echo_cmd, 0, HLP_ECHO },
1302 { "ASSERT", &assert_cmd, 1, HLP_ASSERT },
1303 { "SEND", &send_cmd, 0 },
1304 { "EXPECT", &expect_cmd, 1 },
1305 { "NOEXPECT", &expect_cmd, 0 },
1306 { "!", &spawn_cmd, 0, HLP_SPAWN },
1307 { "HELP", &help_cmd, 0, HLP_HELP },
1308 { NULL, NULL, 0 }
1309 };
1310
1311 static CTAB set_glob_tab[] = {
1312 { "CONSOLE", &sim_set_console, 0 },
1313 { "REMOTE", &sim_set_remote_console, 0 },
1314 { "BREAK", &brk_cmd, SSH_ST },
1315 { "NOBREAK", &brk_cmd, SSH_CL },
1316 { "TELNET", &sim_set_telnet, 0 },
1317 { "NOTELNET", &sim_set_notelnet, 0 },
1318 { "LOG", &sim_set_logon, 0, HLP_SET_LOG },
1319 { "NOLOG", &sim_set_logoff, 0, HLP_SET_LOG },
1320 { "DEBUG", &sim_set_debon, 0, HLP_SET_DEBUG },
1321 { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
1322 { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
1323 { "ON", &set_on, 1, HLP_SET_ON },
1324 { "NOON", &set_on, 0, HLP_SET_ON },
1325 { "VERIFY", &set_verify, 1, HLP_SET_VERIFY },
1326 { "VERBOSE", &set_verify, 1, HLP_SET_VERIFY },
1327 { "NOVERIFY", &set_verify, 0, HLP_SET_VERIFY },
1328 { "NOVERBOSE", &set_verify, 0, HLP_SET_VERIFY },
1329 { "MESSAGE", &set_message, 1, HLP_SET_MESSAGE },
1330 { "NOMESSAGE", &set_message, 0, HLP_SET_MESSAGE },
1331 { "QUIET", &set_quiet, 1, HLP_SET_QUIET },
1332 { "NOQUIET", &set_quiet, 0, HLP_SET_QUIET },
1333 { "LOCALOPC", &set_localopc, 1, HLP_SET_LOCALOPC },
1334 { "NOLOCALOPC", &set_localopc, 0, HLP_SET_LOCALOPC },
1335 { "PROMPT", &set_prompt, 0, HLP_SET_PROMPT },
1336 { NULL, NULL, 0 }
1337 };
1338
1339 static C1TAB set_dev_tab[] = {
1340 { "OCTAL", &set_dev_radix, 8 },
1341 { "DECIMAL", &set_dev_radix, 10 },
1342 { "HEX", &set_dev_radix, 16 },
1343 { "ENABLED", &set_dev_enbdis, 1 },
1344 { "DISABLED", &set_dev_enbdis, 0 },
1345 { "DEBUG", &set_dev_debug, 1 },
1346 { "NODEBUG", &set_dev_debug, 0 },
1347 { NULL, NULL, 0 }
1348 };
1349
1350 static C1TAB set_unit_tab[] = {
1351 { "ENABLED", &set_unit_enbdis, 1 },
1352 { "DISABLED", &set_unit_enbdis, 0 },
1353 { NULL, NULL, 0 }
1354 };
1355
1356 static SHTAB show_glob_tab[] = {
1357 { "CONFIGURATION", &show_config, 0, HLP_SHOW_CONFIG },
1358 { "DEFAULT_BASE_SYSTEM_SCRIPT",
1359 &show_default_base_system_script, 0, HLP_SHOW_DBS },
1360 { "DEVICES", &show_config, 1, HLP_SHOW_DEVICES },
1361 { "FEATURES", &show_config, 2, HLP_SHOW_FEATURES },
1362 { "QUEUE", &show_queue, 0, HLP_SHOW_QUEUE },
1363 { "TIME", &show_time, 0, HLP_SHOW_TIME },
1364 { "MODIFIERS", &show_mod_names, 0, HLP_SHOW_MODIFIERS },
1365 { "NAMES", &show_log_names, 0, HLP_SHOW_NAMES },
1366 { "SHOW", &show_show_commands, 0, HLP_SHOW_SHOW },
1367 { "VERSION", &show_version, 1, HLP_SHOW_VERSION },
1368 { "BUILDINFO", &show_buildinfo, 1, HLP_SHOW_BUILDINFO },
1369 { "PROM", &show_prom, 0, HLP_SHOW_PROM },
1370 { "HINTS", &show_hints, 0, HLP_SHOW_HINTS },
1371 { "CONSOLE", &sim_show_console, 0, HLP_SHOW_CONSOLE },
1372 { "REMOTE", &sim_show_remote_console, 0, HLP_SHOW_REMOTE },
1373 { "BREAK", &show_break, 0, HLP_SHOW_BREAK },
1374 { "LOG", &sim_show_log, 0, HLP_SHOW_LOG },
1375 { "TELNET", &sim_show_telnet, 0 },
1376 { "DEBUG", &sim_show_debug, 0, HLP_SHOW_DEBUG },
1377 { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS },
1378 { "SEND", &sim_show_send, 0, HLP_SHOW_SEND },
1379 { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT },
1380 { "ON", &show_on, 0, HLP_SHOW_ON },
1381 { NULL, NULL, 0 }
1382 };
1383
1384 static SHTAB show_dev_tab[] = {
1385 { "RADIX", &show_dev_radix, 0 },
1386 { "DEBUG", &show_dev_debug, 0 },
1387 { "MODIFIERS", &show_dev_modifiers, 0 },
1388 { "NAMES", &show_dev_logicals, 0 },
1389 { "SHOW", &show_dev_show_commands, 0 },
1390 { NULL, NULL, 0 }
1391 };
1392
1393 static SHTAB show_unit_tab[] = {
1394 { NULL, NULL, 0 }
1395 };
1396
1397 #if defined(_WIN32)
1398 static
1399 int setenv(const char *envname, const char *envval, int overwrite)
1400 {
1401 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1402 int r;
1403
1404 (void)sprintf(envstr, "%s=%s", envname, envval);
1405 r = _putenv(envstr);
1406 FREE(envstr);
1407 return r;
1408 }
1409
1410 static
1411 int unsetenv(const char *envname)
1412 {
1413 setenv(envname, "", 1);
1414 return 0;
1415 }
1416 #endif
1417
1418 #if !defined(NO_LOCALE)
1419 # define XSTR_EMAXLEN 32767
1420
1421 const char
1422 *xstrerror_l(int errnum)
1423 {
1424 int saved = errno;
1425 const char *ret = NULL;
1426 static __thread char buf[XSTR_EMAXLEN];
1427
1428 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1429 defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1430 # if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1431 if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf;
1432 # else
1433 if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf;
1434 # endif
1435 # else
1436 # if defined(__NetBSD__)
1437 locale_t loc = LC_GLOBAL_LOCALE;
1438 # else
1439 locale_t loc = uselocale((locale_t)0);
1440 # endif
1441 locale_t copy = loc;
1442 if (copy == LC_GLOBAL_LOCALE)
1443 copy = duplocale(copy);
1444
1445 if (copy != (locale_t)0)
1446 {
1447 ret = strerror_l(errnum, copy);
1448 if (loc == LC_GLOBAL_LOCALE)
1449 {
1450 freelocale(copy);
1451 }
1452 }
1453 # endif
1454
1455 if (!ret)
1456 {
1457 (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1458 ret = buf;
1459 }
1460
1461 errno = saved;
1462 return ret;
1463 }
1464 #else
1465 # define xstrerror_l strerror
1466 #endif
1467
1468 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1469
1470
1471
1472 char *strremove(char *str, const char *sub)
1473 {
1474 char *p, *q, *r;
1475 if (*sub && (q = r = strstr(str, sub)) != NULL) {
1476 size_t len = strlen(sub);
1477 while ((r = strstr(p = r + len, sub)) != NULL) {
1478 while (p < r)
1479 *q++ = *p++;
1480 }
1481 while ((*q++ = *p++) != '\0')
1482 continue;
1483 }
1484 return str;
1485 }
1486
1487
1488
1489 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
1490 {
1491 while (*str_untrimmed != '\0') {
1492 if(!isspace((unsigned char)*str_untrimmed)) {
1493 *str_trimmed = (char)*str_untrimmed;
1494 str_trimmed++;
1495 }
1496 str_untrimmed++;
1497 }
1498 *str_trimmed = '\0';
1499 }
1500
1501 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1502 void allowCores(void)
1503 {
1504 int ret;
1505 struct rlimit limit;
1506 # if defined(RLIMIT_CORE)
1507 ret = getrlimit(RLIMIT_CORE, &limit);
1508 (void)ret;
1509 # if defined(TESTING)
1510 if (ret != 0)
1511 {
1512 sim_warn ("Failed to query core dump configuration.");
1513 return;
1514 }
1515 # endif
1516 limit.rlim_cur = limit.rlim_max;
1517 ret = setrlimit(RLIMIT_CORE, &limit);
1518 # if defined(TESTING)
1519 if (ret != 0)
1520 {
1521 sim_warn ("Failed to enable unlimited core dumps.");
1522 return;
1523 }
1524 # endif
1525 # else
1526 # if defined(TESTING)
1527 sim_warn ("Unable to query core dump configuration.");
1528 # endif
1529 # endif
1530 return;
1531 }
1532 #endif
1533
1534 #if defined(USE_DUMA)
1535 void CleanDUMA(void)
1536 {
1537 (void)fflush(stdout);
1538 DUMA_CHECKALL();
1539 (void)fflush(stderr);
1540 }
1541 # undef USE_DUMA
1542 # define USE_DUMA 1
1543 #endif
1544
1545 #if !defined(SIG_SETMASK)
1546 # undef USE_BACKTRACE
1547 #endif
1548
1549 #if defined(PERF_STRIP)
1550 # undef USE_BACKTRACE
1551 #endif
1552
1553 #if defined(USE_BACKTRACE)
1554 # include <backtrace.h>
1555 # include <backtrace-supported.h>
1556 # define BACKTRACE_SKIP 1
1557 # define BACKTRACE_MAIN "main"
1558 # undef USE_BACKTRACE
1559 # define USE_BACKTRACE 1
1560 #endif
1561
1562 #if defined(BACKTRACE_SUPPORTED)
1563 # if defined(BACKTRACE_SUPPORTS_THREADS)
1564 # if !(BACKTRACE_SUPPORTED)
1565 # undef USE_BACKTRACE
1566 # endif
1567 # else
1568 # undef USE_BACKTRACE
1569 # endif
1570 #else
1571 # undef USE_BACKTRACE
1572 #endif
1573
1574 #if defined(USE_BACKTRACE)
1575 # if defined(BACKTRACE_SUPPORTED)
1576 # include "backtrace_func.c"
1577 # endif
1578 #endif
1579
1580 #if !defined(__CYGWIN__)
1581 # if !defined(__APPLE__)
1582 # if !defined(_AIX)
1583 # if !defined(__MINGW32__)
1584 # if !defined(__MINGW64__)
1585 # if !defined(CROSS_MINGW32)
1586 # if !defined(CROSS_MINGW64)
1587 # if !defined(_WIN32)
1588 # if !defined(__HAIKU__)
1589 # if !defined(__QNX__)
1590 # if !defined(__FILC__)
1591 static int
1592 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
1593 {
1594 (void)size;
1595 (void)data;
1596
1597 if (strlen(info->dlpi_name) >= 2) {
1598 if (!dl_iterate_phdr_callback_called)
1599 (void)printf ("\r\n Loaded shared objects: ");
1600
1601 dl_iterate_phdr_callback_called++;
1602 (void)printf ("%s ", info->dlpi_name);
1603 }
1604
1605 return 0;
1606 }
1607 # endif
1608 # endif
1609 # endif
1610 # endif
1611 # endif
1612 # endif
1613 # endif
1614 # endif
1615 # endif
1616 # endif
1617 #endif
1618
1619 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1620 # if defined(_UCRT)
1621 # define MINGW_CRT "UCRT"
1622 # else
1623 # define MINGW_CRT "MSVCRT"
1624 # endif
1625 #endif
1626
1627 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1628 struct UCRTVersion
1629 {
1630 uint16_t ProductVersion[4];
1631 };
1632
1633 int
1634 GetUCRTVersion (struct UCRTVersion *ucrtversion)
1635 {
1636 # ifdef _DEBUG
1637 static const wchar_t *DllName = L"ucrtbased.dll";
1638 # else
1639 static const wchar_t *DllName = L"ucrtbase.dll";
1640 # endif
1641
1642 HMODULE ucrt = GetModuleHandleW (DllName);
1643 if (!ucrt)
1644 return GetLastError ();
1645
1646 wchar_t path[SIR_MAXPATH];
1647 if (!GetModuleFileNameW (ucrt, path, SIR_MAXPATH))
1648 return GetLastError ();
1649
1650 DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1651 if (!versionInfoSize)
1652 return GetLastError ();
1653
1654 uint8_t versionInfo[versionInfoSize];
1655
1656 if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1657 return GetLastError ();
1658
1659 VS_FIXEDFILEINFO *fixedFileInfo;
1660 UINT fixedFileInfoSize;
1661 if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1662 return GetLastError ();
1663
1664 memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1665
1666 return 0;
1667 }
1668 #endif
1669
1670
1671
1672 #if !defined(PERF_STRIP)
1673 static int dps8_sir_report_error(void)
1674 {
1675 char message[SIR_MAXERROR] = {0};
1676 (void)sir_geterror(message);
1677 (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1678 return EXIT_FAILURE;
1679 }
1680
1681
1682
1683 int main (int argc, char *argv[])
1684 {
1685 char *cptr, *cptr2;
1686 char nbuf[PATH_MAX + 7];
1687 char cbuf[4*CBUFSIZE];
1688 char **targv = NULL;
1689 int32 i, sw;
1690 t_bool lookswitch;
1691 t_stat stat;
1692
1693
1694 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1695 uid_t real_uid = getuid();
1696 uid_t eff_uid = geteuid();
1697 if (0 == eff_uid && 0 != real_uid) {
1698 (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1699 exit(EXIT_FAILURE);
1700 }
1701 # endif
1702
1703 sunos_obtain_realtime_privileges();
1704
1705 sim_free_memory = sim_memory_available();
1706
1707 sim_appfilename = _sir_getappfilename();
1708 if (sim_appfilename == NULL) {
1709 sim_appfilename = "dps8";
1710 }
1711
1712
1713
1714 sirinit si;
1715 if (!sir_makeinit(&si))
1716 return dps8_sir_report_error();
1717
1718
1719 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1720
1721
1722 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1723
1724
1725 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1726
1727
1728 si.d_stderr.opts = SIRO_NOHOST;
1729
1730
1731 si.d_syslog.levels = SIRL_NONE;
1732
1733
1734 si.d_syslog.opts = SIRO_DEFAULT;
1735
1736
1737 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1738
1739
1740 if (!sir_init(&si))
1741 return dps8_sir_report_error();
1742
1743 # if defined(_AIX)
1744 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1745 if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1746 (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1747 __func__, __FILE__, __LINE__);
1748 abort();
1749 }
1750
1751 if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1752 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1753 }
1754
1755 if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1756 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1757 }
1758
1759 if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1760 (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1761 }
1762
1763 # if !defined(__PASE__)
1764 if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1765 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1766 }
1767 # else
1768 # if !defined(TESTING)
1769 if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1770 (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1771 }
1772 # endif
1773 # endif
1774
1775 if (execvp(argv[0], argv) == -1) {
1776 (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1777 __func__, __FILE__, __LINE__);
1778 abort();
1779 }
1780 }
1781 # endif
1782
1783 # if defined(USE_BACKTRACE)
1784 # if defined(BACKTRACE_SUPPORTED)
1785 # if defined(_INC_BACKTRACE_FUNC)
1786 bt_pid = (long)_sir_getpid();
1787 (void)bt_pid;
1788 # endif
1789 # endif
1790 # endif
1791
1792 # if defined(__MINGW32__)
1793 # undef IS_WINDOWS
1794 # define IS_WINDOWS 1
1795 # if !defined(NEED_CONSOLE_SETUP)
1796 # define NEED_CONSOLE_SETUP
1797 # endif
1798 # endif
1799
1800 # if defined(CROSS_MINGW32)
1801 # undef IS_WINDOWS
1802 # define IS_WINDOWS 1
1803 # if !defined(NEED_CONSOLE_SETUP)
1804 # define NEED_CONSOLE_SETUP
1805 # endif
1806 # endif
1807
1808 # if defined(__MINGW64__)
1809 # undef IS_WINDOWS
1810 # define IS_WINDOWS 1
1811 # if !defined(NEED_CONSOLE_SETUP)
1812 # define NEED_CONSOLE_SETUP
1813 # endif
1814 # endif
1815
1816 # if defined(CROSS_MINGW64)
1817 # undef IS_WINDOWS
1818 # define IS_WINDOWS 1
1819 # if !defined(NEED_CONSOLE_SETUP)
1820 # define NEED_CONSOLE_SETUP
1821 # endif
1822 # endif
1823
1824 # if defined(__CYGWIN__)
1825 # if defined(IS_WINDOWS)
1826 # undef IS_WINDOWS
1827 # endif
1828 # endif
1829
1830 # if defined(USE_DUMA)
1831 # if defined(DUMA_EXPLICIT_INIT)
1832 duma_init();
1833 (void)fflush(stderr);
1834 # endif
1835 # if defined(DUMA_MIN_ALIGNMENT)
1836 # if DUMA_MIN_ALIGNMENT > 0
1837 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1838 # endif
1839 # endif
1840 DUMA_SET_FILL(0x2E);
1841 (void)fflush(stderr);
1842 (void)atexit(CleanDUMA);
1843 # endif
1844
1845 # if defined(USE_BACKTRACE)
1846 # if defined(BACKTRACE_SUPPORTED)
1847 # include "backtrace_main.c"
1848 # endif
1849 # endif
1850
1851 # if !defined(NO_LOCALE)
1852 (void)setlocale(LC_ALL, "");
1853 # endif
1854
1855 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1856 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1857 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1858 # endif
1859 # endif
1860
1861 # if defined(NEED_CONSOLE_SETUP)
1862 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1863 if (handle != INVALID_HANDLE_VALUE)
1864 {
1865 DWORD mode = 0;
1866 if (GetConsoleMode(handle, &mode))
1867 {
1868 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1869 SetConsoleMode(handle, mode);
1870 }
1871 }
1872 puts ("\e[0m");
1873 # endif
1874
1875 # if defined(__HAIKU__)
1876 (void)disable_debugger(1);
1877 # endif
1878
1879 running_perf_test = false;
1880
1881
1882 char thread_name[SIR_MAXPID] = {0};
1883 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1884 (void)_sir_setthreadname(thread_name);
1885
1886
1887
1888 # if defined(__clang_analyzer__)
1889 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1890 return 1;
1891 # endif
1892
1893 if (argc == 0) {
1894 (void)fprintf (stderr, "Error: main() called directly!\r\n");
1895 return 1;
1896 }
1897
1898
1899 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1900 allowCores();
1901 # endif
1902
1903 int testEndian = decContextTestEndian();
1904 if (testEndian != 0) {
1905 if (testEndian == 1) {
1906 (void)fprintf (stderr,
1907 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1908 return 1;
1909 }
1910 if (testEndian == -1) {
1911 (void)fprintf (stderr,
1912 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1913 return 1;
1914 }
1915 (void)fprintf (stderr,
1916 "Error: Unable to determine system byte order; aborting.\r\n");
1917 return 1;
1918 }
1919 # if defined(NEED_128)
1920 test_math128();
1921 # endif
1922
1923 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1924
1925 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1926
1927
1928
1929
1930 nprocs = (unsigned int)uv_available_parallelism();
1931 # else
1932 nprocs = (unsigned int)_sir_nprocs();
1933 # endif
1934 ncores = (unsigned int)get_core_count();
1935
1936
1937 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1938 if (!targv)
1939 {
1940 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1941 __func__, __FILE__, __LINE__);
1942 # if defined(USE_BACKTRACE)
1943 # if defined(SIGUSR2)
1944 (void)raise(SIGUSR2);
1945
1946 # endif
1947 # endif
1948 abort();
1949 }
1950 for (i=0; i<argc; i++)
1951 targv[i] = argv[i];
1952 argv = targv;
1953
1954
1955 set_prompt (0, "sim>");
1956 *cbuf = 0;
1957 sim_switches = 0;
1958 lookswitch = TRUE;
1959 stdnul = fopen(NULL_DEVICE,"wb");
1960
1961
1962 for (i = 1; i < argc; i++) {
1963 if (argv[i] == NULL)
1964 continue;
1965
1966 # if defined(THREADZ) || defined(LOCKLESS)
1967
1968 int perftestflag = strcmp(argv[i], "--perftest");
1969 if (perftestflag == 0) {
1970 char * testName = NULL;
1971 if (i + 1 < argc)
1972 testName = argv[i + 1];
1973 perfTest (testName);
1974 return 0;
1975 }
1976 # endif
1977
1978
1979 int onlyvers = strcmp(argv[i], "--version");
1980 if (onlyvers == 0) {
1981 # if defined(VER_H_GIT_VERSION)
1982 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1983 # if VER_H_GIT_PATCH_INT < 1
1984 (void)fprintf (stdout, "%s simulator %s\r\n",
1985 sim_name, VER_H_GIT_VERSION);
1986 # else
1987 (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1988 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1989 # endif
1990 # else
1991 (void)fprintf (stdout, "%s simulator %s\r\n",
1992 sim_name, VER_H_GIT_VERSION);
1993 # endif
1994 # else
1995 (void)fprintf (stdout, "%s simulator\r\n", sim_name);
1996 # endif
1997 FREE (targv);
1998 return 0;
1999 }
2000
2001
2002 int longhelp = strcmp(argv[i], "--help");
2003 int shorthelp = strcmp(argv[i], "-h");
2004 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2005 if (longhelp == 0 || shorthelp == 0) {
2006 # if defined(VER_H_GIT_VERSION)
2007 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2008 # if VER_H_GIT_PATCH_INT < 1
2009 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2010 # else
2011 (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2012 # endif
2013 # else
2014 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2015 # endif
2016 # else
2017 (void)fprintf (stdout, "%s simulator", sim_name);
2018 # endif
2019 (void)fprintf (stdout, "\r\n");
2020 (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2021 (void)fprintf (stdout, "\r\n");
2022 (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2023 (void)fprintf (stdout, "\r\n");
2024 (void)fprintf (stdout, "\r\n Switches:");
2025 (void)fprintf (stdout, "\r\n -e, -E Aborts script processing immediately upon any error");
2026 (void)fprintf (stdout, "\r\n -h, -H, --help Prints only this informational help text and exits");
2027 (void)fprintf (stdout, "\r\n -k, -K Disables all support for exclusive file locking");
2028 (void)fprintf (stdout, "\r\n -l, -L Reports but ignores all exclusive file locking errors");
2029 (void)fprintf (stdout, "\r\n -o, -O Makes scripting ON conditions and actions inheritable");
2030 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2031 (void)fprintf (stdout, "\r\n -p, -P Enables real-time scheduling (may require privileges)");
2032 # endif
2033 (void)fprintf (stdout, "\r\n -q, -Q Disables printing of non-fatal informational messages");
2034 (void)fprintf (stdout, "\r\n -r, -R Enables an unlinked ephemeral system state file");
2035 (void)fprintf (stdout, "\r\n -s, -S Enables a randomized persistent system state file");
2036 (void)fprintf (stdout, "\r\n -t, -T Disables fsync and creation/usage of system state file");
2037 (void)fprintf (stdout, "\r\n -v, -V Prints commands read from script file before execution");
2038 (void)fprintf (stdout, "\r\n --version Prints only the simulator identification text and exits");
2039 (void)fprintf (stdout, "\r\n");
2040 # if defined(USE_DUMA)
2041 nodist++;
2042 # endif
2043 if (!nodist) {
2044 (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2045 (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2046 (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2047 }
2048 else
2049 {
2050 (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2051 }
2052 (void)fprintf (stdout, "\r\n");
2053 FREE(argv);
2054 return 0;
2055 }
2056
2057 if ((*argv[i] == '-') && lookswitch) {
2058 if ((sw = get_switches (argv[i])) < 0) {
2059 (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2060 FREE(argv);
2061 return 1;
2062 }
2063 sim_switches = sim_switches | sw;
2064 }
2065
2066 else {
2067 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2068 (void)fprintf (stderr, "Argument string too long\r\n");
2069 FREE(argv);
2070 return 1;
2071 }
2072 if (*cbuf)
2073 strcat (cbuf, " ");
2074 (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s",
2075 strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
2076 lookswitch = FALSE;
2077 }
2078 }
2079 sim_nolock = sim_switches & SWMASK ('K');
2080 sim_iglock = sim_switches & SWMASK ('L');
2081 sim_randompst = sim_switches & SWMASK ('S');
2082 sim_quiet = sim_switches & SWMASK ('Q');
2083 sim_randstate = sim_switches & SWMASK ('R');
2084 if (sim_randompst) sim_randstate = 1;
2085 sim_nostate = sim_switches & SWMASK ('T');
2086 if (sim_nostate)
2087 {
2088 sim_randompst = 0;
2089 sim_randstate = 0;
2090 }
2091 sim_on_inherit = sim_switches & SWMASK ('O');
2092
2093 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2094 !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2095 sim_realtime = sim_switches & SWMASK ('P');
2096 # endif
2097
2098 sim_init_sock ();
2099 if (sim_dflt_dev == NULL)
2100 sim_dflt_dev = sim_devices[0];
2101 if (sim_vm_init != NULL)
2102 (*sim_vm_init)();
2103 sim_finit ();
2104 for (i = 0; cmd_table[i].name; i++) {
2105 size_t alias_len = strlen (cmd_table[i].name);
2106 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2107 if (!cmd_name)
2108 {
2109 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2110 __func__, __FILE__, __LINE__);
2111 # if defined(USE_BACKTRACE)
2112 # if defined(SIGUSR2)
2113 (void)raise(SIGUSR2);
2114
2115 # endif
2116 # endif
2117 abort();
2118 }
2119
2120 strcpy (cmd_name, cmd_table[i].name);
2121 while (alias_len > 1) {
2122 cmd_name[alias_len] = '\0';
2123 --alias_len;
2124 if (getenv (cmd_name))
2125 unsetenv (cmd_name);
2126 }
2127 FREE (cmd_name);
2128 }
2129 stop_cpu = 0;
2130 sim_interval = 0;
2131 sim_time = sim_rtime = 0;
2132 noqueue_time = 0;
2133 sim_clock_queue = QUEUE_LIST_END;
2134 sim_is_running = 0;
2135 sim_log = NULL;
2136 if (sim_emax <= 0)
2137 sim_emax = 1;
2138
2139
2140 main_thread_id = pthread_self();
2141
2142
2143 save_thread_sched(pthread_self());
2144
2145
2146 if (sim_realtime) {
2147 if (nprocs < 2) {
2148 sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2149 exit(EXIT_FAILURE);
2150 } else {
2151 watchdog_startup();
2152 }
2153 }
2154
2155
2156 if (realtime_ok) {
2157 set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2158 check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2159 } else {
2160 # if !defined(__QNX__)
2161 (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2162 # endif
2163 }
2164
2165 sim_timer_init ();
2166
2167 if ((stat = sim_ttinit ()) != SCPE_OK) {
2168 (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2169 sim_error_text (stat));
2170 FREE(argv);
2171 return 1;
2172 }
2173 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2174 (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2175 FREE(argv);
2176 return 1;
2177 };
2178 if ((stat = reset_all_p (0)) != SCPE_OK) {
2179 (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2180 sim_error_text (stat));
2181 FREE(argv);
2182 return 1;
2183 }
2184 if ((stat = sim_brk_init ()) != SCPE_OK) {
2185 (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2186 sim_error_text (stat));
2187 FREE(argv);
2188 return 1;
2189 }
2190 if (!sim_quiet) {
2191 (void)printf ("\r\n");
2192 show_version (stdout, NULL, NULL, 0, NULL);
2193 }
2194
2195 cptr = getenv("HOME");
2196 if (cptr == NULL) {
2197 cptr = getenv("HOMEPATH");
2198 cptr2 = getenv("HOMEDRIVE");
2199 }
2200 else
2201 cptr2 = NULL;
2202 (void)cptr2;
2203 if ( (*cbuf) && (strcmp(cbuf, "")) )
2204 stat = do_cmd (0, cbuf);
2205 else if (*argv[0]) {
2206 char *np;
2207 nbuf[0] = '"';
2208 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
2209 if (stat == SCPE_OPENERR) {
2210 np = strrchr (nbuf, '/');
2211 if (np == NULL)
2212 np = strrchr (nbuf, '\\');
2213 if (np != NULL) {
2214 *np = '"';
2215 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
2216 }
2217 }
2218 }
2219
2220 argv = uv_setup_args(argc, argv);
2221
2222
2223 if (getenv("DPS8M_NO_HINTS") == NULL)
2224 if (!sim_quiet && 0 == strcmp(cbuf, ""))
2225 (void)show_hints(0, 0, 0, 1, 0);
2226
2227 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2228
2229 if (sim_vm_exit != NULL)
2230 (*sim_vm_exit)();
2231
2232 detach_all (0, TRUE);
2233 sim_set_deboff (0, NULL);
2234 sim_set_logoff (0, NULL);
2235 sim_set_notelnet (0, NULL);
2236 sim_ttclose ();
2237 sim_cleanup_sock ();
2238 fclose (stdnul);
2239 FREE (targv);
2240 FREE (sim_prompt);
2241 FREE (sim_eval);
2242 FREE (sim_internal_devices);
2243 FREE (sim_brk_tab);
2244 FREE (sim_staba.comp);
2245 FREE (sim_staba.mask);
2246 FREE (sim_stabr.comp);
2247 FREE (sim_stabr.mask);
2248 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2249 }
2250 #endif
2251
2252 t_stat process_stdin_commands (t_stat stat, char *argv[])
2253 {
2254 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2255 CONST char *cptr;
2256 t_stat stat_nomessage;
2257 CTAB *cmdp = NULL;
2258
2259 stat = SCPE_BARE_STATUS(stat);
2260 while (stat != SCPE_EXIT) {
2261 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
2262 (void)printf ("%s%s\r\n", sim_prompt, cptr);
2263 else if (sim_vm_read != NULL) {
2264 (void)printf ("%s", sim_prompt);
2265 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2266 }
2267 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
2268 if (cptr == NULL) {
2269 if (sim_ttisatty()) continue;
2270 else break;
2271 }
2272 if (*cptr == 0)
2273 continue;
2274 sim_sub_args (cbuf, sizeof(cbuf), argv);
2275 if (sim_log)
2276 (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2277 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2278 (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2279 cptr = get_glyph_cmd (cptr, gbuf);
2280 sim_switches = 0;
2281 if ((cmdp = find_cmd (gbuf)))
2282 stat = cmdp->action (cmdp->arg, cptr);
2283 else
2284 stat = SCPE_UNK;
2285 stat_nomessage = stat & SCPE_NOMESSAGE;
2286 stat_nomessage = stat_nomessage || (!sim_show_message);
2287 stat = SCPE_BARE_STATUS(stat);
2288 sim_last_cmd_stat = stat;
2289 if (!stat_nomessage) {
2290 if (cmdp && (cmdp->message))
2291 cmdp->message (NULL, stat);
2292 else
2293 if (stat >= SCPE_BASE)
2294 sim_printf ("%s\r\n", sim_error_text (stat));
2295 }
2296 if (sim_vm_post != NULL)
2297 (*sim_vm_post) (TRUE);
2298 }
2299 return stat;
2300 }
2301
2302
2303
2304 t_stat set_prompt (int32 flag, CONST char *cptr)
2305 {
2306 char gbuf[CBUFSIZE], *gptr;
2307
2308 if ((NULL == cptr) || (*cptr == '\0'))
2309 return SCPE_ARG;
2310
2311 cptr = get_glyph_nc (cptr, gbuf, '"');
2312 if (gbuf[0] == '\0') {
2313 gbuf[sizeof (gbuf)-1] = '\0';
2314 strncpy (gbuf, cptr, sizeof (gbuf)-1);
2315 gptr = strchr (gbuf, '"');
2316 if (NULL != gptr)
2317 *gptr = '\0';
2318 }
2319 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
2320 if (!sim_prompt)
2321 {
2322 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2323 __func__, __FILE__, __LINE__);
2324 #if defined(USE_BACKTRACE)
2325 # if defined(SIGUSR2)
2326 (void)raise(SIGUSR2);
2327
2328 # endif
2329 #endif
2330 abort();
2331 }
2332 (void)sprintf (sim_prompt, "%s ", gbuf);
2333 return SCPE_OK;
2334 }
2335
2336
2337
2338 CTAB *find_cmd (const char *gbuf)
2339 {
2340 CTAB *cmdp = NULL;
2341
2342 if (sim_vm_cmd)
2343 cmdp = find_ctab (sim_vm_cmd, gbuf);
2344 if (cmdp == NULL)
2345 cmdp = find_ctab (cmd_table, gbuf);
2346 return cmdp;
2347 }
2348
2349
2350
2351 t_stat exit_cmd (int32 flag, CONST char *cptr)
2352 {
2353 return SCPE_EXIT;
2354 }
2355
2356
2357
2358
2359 static int _cmd_name_compare (const void *pa, const void *pb)
2360 {
2361 CTAB * const *a = (CTAB * const *)pa;
2362 CTAB * const *b = (CTAB * const *)pb;
2363
2364 return strcmp((*a)->name, (*b)->name);
2365 }
2366
2367 void fprint_help (FILE *st)
2368 {
2369 CTAB *cmdp;
2370 CTAB **hlp_cmdp = NULL;
2371 size_t cmd_cnt = 0;
2372 size_t cmd_size = 0;
2373 size_t max_cmdname_size = 0;
2374 size_t i, line_offset;
2375
2376 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2377 if (cmdp->help) {
2378 if (cmd_cnt >= cmd_size) {
2379 cmd_size += 20;
2380 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2381 if (!hlp_cmdp)
2382 {
2383 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2384 __func__, __FILE__, __LINE__);
2385 #if defined(USE_BACKTRACE)
2386 # if defined(SIGUSR2)
2387 (void)raise(SIGUSR2);
2388
2389 # endif
2390 #endif
2391 abort();
2392 }
2393 }
2394 hlp_cmdp[cmd_cnt] = cmdp;
2395 ++cmd_cnt;
2396 if (strlen(cmdp->name) > max_cmdname_size)
2397 max_cmdname_size = strlen(cmdp->name);
2398 }
2399 }
2400 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2401 if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2402 if (cmd_cnt >= cmd_size) {
2403 cmd_size += 20;
2404 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2405 if (!hlp_cmdp)
2406 {
2407 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2408 __func__, __FILE__, __LINE__);
2409 #if defined(USE_BACKTRACE)
2410 # if defined(SIGUSR2)
2411 (void)raise(SIGUSR2);
2412
2413 # endif
2414 #endif
2415 abort();
2416 }
2417 }
2418 hlp_cmdp[cmd_cnt] = cmdp;
2419 ++cmd_cnt;
2420 if (strlen (cmdp->name) > max_cmdname_size)
2421 max_cmdname_size = strlen(cmdp->name);
2422 }
2423 }
2424 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n ");
2425 if (hlp_cmdp)
2426 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2427 line_offset = 4;
2428 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2429 fputs (hlp_cmdp[i]->name, st);
2430 line_offset += 5 + max_cmdname_size;
2431 if (line_offset + max_cmdname_size > 79) {
2432 line_offset = 4;
2433 (void)fprintf (st, "\r\n ");
2434 }
2435 else
2436 (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2437 }
2438 FREE (hlp_cmdp);
2439 (void)fprintf (st, "\r\n");
2440 return;
2441 }
2442
2443 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2444 {
2445 if (!*pdone)
2446 (void)fprintf (st, "%s", context);
2447 *pdone = TRUE;
2448 }
2449
2450 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2451 {
2452 REG *rptr, *trptr;
2453 t_bool found = FALSE;
2454 t_bool all_unique = TRUE;
2455 size_t max_namelen = 0;
2456 DEVICE *tdptr;
2457 CONST char *tptr;
2458 char *namebuf;
2459 char rangebuf[32];
2460
2461 if (dptr->registers)
2462 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2463 if (rptr->flags & REG_HIDDEN)
2464 continue;
2465 if (rptr->depth > 1)
2466 (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2467 else
2468 strcpy (rangebuf, "");
2469 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2470 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2471 found = TRUE;
2472 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2473 if ((trptr == NULL) || (tdptr != dptr))
2474 all_unique = FALSE;
2475 }
2476 if (!found) {
2477 if (!silent)
2478 (void)fprintf (st, "No register HELP available for the %s device\r\n",
2479 dptr->name);
2480 }
2481 else {
2482 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2483 if (!namebuf)
2484 {
2485 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2486 __func__, __FILE__, __LINE__);
2487 #if defined(USE_BACKTRACE)
2488 # if defined(SIGUSR2)
2489 (void)raise(SIGUSR2);
2490
2491 # endif
2492 #endif
2493 abort();
2494 }
2495 (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2496 dptr->name);
2497 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2498 if (rptr->flags & REG_HIDDEN)
2499 continue;
2500 if (rptr->depth <= 1)
2501 (void)sprintf (namebuf, "%*s",
2502 -((int)max_namelen),
2503 rptr->name);
2504 else {
2505 (void)sprintf (rangebuf, "[%d:%d]",
2506 0,
2507 rptr->depth-1);
2508 (void)sprintf (namebuf, "%s%*s",
2509 rptr->name,
2510 (int)(strlen(rptr->name))-((int)max_namelen),
2511 rangebuf);
2512 }
2513 if (all_unique) {
2514 (void)fprintf (st, " %s %4d %s\r\n",
2515 namebuf,
2516 rptr->width,
2517 rptr->desc ? rptr->desc : "");
2518 continue;
2519 }
2520 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2521 if ((trptr == NULL) || (tdptr != dptr))
2522 (void)fprintf (st, " %s %s %4d %s\r\n",
2523 dptr->name,
2524 namebuf,
2525 rptr->width,
2526 rptr->desc ? rptr->desc : "");
2527 else
2528 (void)fprintf (st, " %*s %s %4d %s\r\n",
2529 (int)strlen(dptr->name), "",
2530 namebuf,
2531 rptr->width,
2532 rptr->desc ? rptr->desc : "");
2533 }
2534 FREE (namebuf);
2535 }
2536 }
2537
2538 void fprint_reg_help (FILE *st, DEVICE *dptr)
2539 {
2540 fprint_reg_help_ex (st, dptr, TRUE);
2541 }
2542
2543 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2544 {
2545 if (dptr->attach_help) {
2546 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2547 dptr->attach_help (st, dptr, NULL, 0, NULL);
2548 return;
2549 }
2550 if (DEV_TYPE(dptr) == DEV_DISK) {
2551 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2552 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2553 return;
2554 }
2555 if (DEV_TYPE(dptr) == DEV_TAPE) {
2556 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2557 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2558 return;
2559 }
2560 if (!silent) {
2561 (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2562 if (dptr->help)
2563 dptr->help (st, dptr, NULL, 0, NULL);
2564 }
2565 }
2566
2567 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2568 {
2569 MTAB *mptr;
2570 DEBTAB *dep;
2571 t_bool found = FALSE;
2572 char buf[CBUFSIZE], header[CBUFSIZE];
2573 uint32 enabled_units = dptr->numunits;
2574 uint32 unit;
2575
2576 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2577 for (unit=0; unit < dptr->numunits; unit++)
2578 if (dptr->units[unit].flags & UNIT_DIS)
2579 --enabled_units;
2580 if (dptr->modifiers) {
2581 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2582 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2583 continue;
2584 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2585 continue;
2586 if (mptr->mstring) {
2587 fprint_header (st, &found, header);
2588 (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2589 mptr->mstring,
2590 (strchr(mptr->mstring, '=')) \
2591 ? "" : (MODMASK(mptr,MTAB_VALR) \
2592 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2593 ? "{=val}" : "")));
2594 if ((strlen (buf) < 30) || (NULL == mptr->help))
2595 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2596 else
2597 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2598 }
2599 }
2600 }
2601 if (dptr->flags & DEV_DISABLE) {
2602 fprint_header (st, &found, header);
2603 (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2604 (void)fprintf (st, "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2605 (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2606 (void)fprintf (st, "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2607 }
2608 if (dptr->flags & DEV_DEBUG) {
2609 fprint_header (st, &found, header);
2610 (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2611 (void)fprintf (st, "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2612 (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2613 (void)fprintf (st, "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2614 if (dptr->debflags) {
2615 t_bool desc_available = FALSE;
2616 strcpy (buf, "");
2617 (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2618 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2619 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2620 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2621 }
2622 (void)fprintf (st, "\r\n");
2623 (void)fprintf (st, "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2624 (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2625 for (dep = dptr->debflags; dep->name != NULL; dep++)
2626 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2627 (void)fprintf (st, "\r\n");
2628 (void)fprintf (st, "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2629 if (desc_available) {
2630 (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2631 for (dep = dptr->debflags; dep->name != NULL; dep++)
2632 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2633 }
2634 }
2635 }
2636 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2637 if (dptr->units->flags & UNIT_DISABLE) {
2638 fprint_header (st, &found, header);
2639 (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2640 (void)fprintf (st, "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2641 (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2642 (void)fprintf (st, "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2643 }
2644 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2645 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2646 continue;
2647 if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2648 continue;
2649 if (mptr->mstring) {
2650 fprint_header (st, &found, header);
2651 (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2652 (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2653 (strchr(mptr->mstring, '=')) \
2654 ? "" : (MODMASK(mptr,MTAB_VALR) \
2655 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2656 ? "{=val}" : "")));
2657 (void)fprintf (st, "%-30s\t%s\r\n", buf,
2658 (strchr(mptr->mstring, '=')) \
2659 ? "" : (mptr->help ? mptr->help : ""));
2660 }
2661 }
2662 }
2663 if (!found && !silent)
2664 (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2665 }
2666
2667 void fprint_set_help (FILE *st, DEVICE *dptr)
2668 {
2669 fprint_set_help_ex (st, dptr, TRUE);
2670 }
2671
2672 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2673 {
2674 MTAB *mptr;
2675 t_bool found = FALSE;
2676 char buf[CBUFSIZE], header[CBUFSIZE];
2677 uint32 enabled_units = dptr->numunits;
2678 uint32 unit;
2679
2680 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2681 for (unit=0; unit < dptr->numunits; unit++)
2682 if (dptr->units[unit].flags & UNIT_DIS)
2683 --enabled_units;
2684 if (dptr->modifiers) {
2685 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2686 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2687 continue;
2688 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2689 continue;
2690 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2691 continue;
2692 fprint_header (st, &found, header);
2693 (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2694 mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2695 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2696 }
2697 }
2698 if (dptr->flags & DEV_DEBUG) {
2699 fprint_header (st, &found, header);
2700 (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2701 (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2702 }
2703 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2704 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2705 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2706 continue;
2707 if ((!mptr->disp) || (!mptr->pstring))
2708 continue;
2709 fprint_header (st, &found, header);
2710 (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2711 (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2712 MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2713 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2714 }
2715 }
2716 if (!found && !silent)
2717 (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2718 }
2719
2720 void fprint_show_help (FILE *st, DEVICE *dptr)
2721 {
2722 fprint_show_help_ex (st, dptr, TRUE);
2723 }
2724
2725 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2726 {
2727 BRKTYPTAB *brkt = dptr->brk_types;
2728 char gbuf[CBUFSIZE];
2729
2730 if (sim_brk_types == 0) {
2731 if ((dptr != sim_dflt_dev) && (!silent)) {
2732 (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2733 if (dptr->help)
2734 dptr->help (st, dptr, NULL, 0, NULL);
2735 }
2736 return;
2737 }
2738 if (brkt == NULL) {
2739 int i;
2740
2741 if (dptr == sim_dflt_dev) {
2742 if (sim_brk_types & ~sim_brk_dflt) {
2743 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2744 for (i=0; i<26; i++) {
2745 if (sim_brk_types & (1<<i))
2746 (void)fprintf (st, " -%c\r\n", 'A'+i);
2747 }
2748 }
2749 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2750 }
2751 return;
2752 }
2753 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2754 while (brkt->btyp) {
2755 (void)fprintf (st, " %s %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2756 ++brkt;
2757 }
2758 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2759 }
2760
2761 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2762 {
2763 char gbuf[CBUFSIZE];
2764 CTAB *cmdp;
2765
2766 if (*cptr) {
2767 (void)get_glyph (cptr, gbuf, 0);
2768 if ((cmdp = find_cmd (gbuf))) {
2769 if (cmdp->action == &exdep_cmd) {
2770 if (dptr->help)
2771 return dptr->help (st, dptr, uptr, flag, cptr);
2772 else
2773 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2774 return SCPE_OK;
2775 }
2776 if (cmdp->action == &set_cmd) {
2777 fprint_set_help_ex (st, dptr, FALSE);
2778 return SCPE_OK;
2779 }
2780 if (cmdp->action == &show_cmd) {
2781 fprint_show_help_ex (st, dptr, FALSE);
2782 return SCPE_OK;
2783 }
2784 if (cmdp->action == &attach_cmd) {
2785 fprint_attach_help_ex (st, dptr, FALSE);
2786 return SCPE_OK;
2787 }
2788 if (cmdp->action == &brk_cmd) {
2789 fprint_brk_help_ex (st, dptr, FALSE);
2790 return SCPE_OK;
2791 }
2792 if (dptr->help)
2793 return dptr->help (st, dptr, uptr, flag, cptr);
2794 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2795 return SCPE_OK;
2796 }
2797 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2798 fprint_reg_help_ex (st, dptr, FALSE);
2799 return SCPE_OK;
2800 }
2801 if (dptr->help)
2802 return dptr->help (st, dptr, uptr, flag, cptr);
2803 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2804 return SCPE_OK;
2805 }
2806 if (dptr->help) {
2807 return dptr->help (st, dptr, uptr, flag, cptr);
2808 }
2809 if (dptr->description)
2810 (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2811 else
2812 (void)fprintf (st, "%s HELP\r\n", dptr->name);
2813 fprint_set_help_ex (st, dptr, TRUE);
2814 fprint_show_help_ex (st, dptr, TRUE);
2815 fprint_attach_help_ex (st, dptr, TRUE);
2816 fprint_reg_help_ex (st, dptr, TRUE);
2817 fprint_brk_help_ex (st, dptr, TRUE);
2818 return SCPE_OK;
2819 }
2820
2821 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2822 {
2823 switch (help[0]) {
2824 case '*':
2825 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2826 if (sim_log)
2827 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2828 break;
2829 default:
2830 fputs (help, stdout);
2831 if (sim_log)
2832 fputs (help, sim_log);
2833 break;
2834 }
2835 return SCPE_OK;
2836 }
2837
2838 t_stat help_cmd (int32 flag, CONST char *cptr)
2839 {
2840 char gbuf[CBUFSIZE];
2841 CTAB *cmdp;
2842
2843 GET_SWITCHES (cptr);
2844 if (sim_switches & SWMASK ('F'))
2845 flag = flag | SCP_HELP_FLAT;
2846 if (*cptr) {
2847 cptr = get_glyph (cptr, gbuf, 0);
2848 if ((cmdp = find_cmd (gbuf))) {
2849 if (*cptr) {
2850 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2851 DEVICE *dptr;
2852 UNIT *uptr;
2853 t_stat r;
2854 cptr = get_glyph (cptr, gbuf, 0);
2855 dptr = find_unit (gbuf, &uptr);
2856 if (dptr == NULL)
2857 dptr = find_dev (gbuf);
2858 if (dptr != NULL) {
2859 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2860 if (sim_log)
2861 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2862 return r;
2863 }
2864 if (cmdp->action == &set_cmd) {
2865
2866 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2867 (cmdp->help))
2868 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2869 }
2870 else {
2871 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2872 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2873 return SCPE_ARG;
2874 return help_cmd_output (flag, shptr->help, NULL);
2875 }
2876 return SCPE_ARG;
2877 }
2878 else
2879 return SCPE_2MARG;
2880 }
2881 if (cmdp->help) {
2882 if (strcmp (cmdp->name, "HELP") == 0) {
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
2915
2916
2917 }
2918 else {
2919 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2920 sim_dflt_dev && sim_dflt_dev->help) {
2921 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2922 if (sim_log)
2923 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2924 }
2925 }
2926 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2927 }
2928 else {
2929 CTAB *cmdpa;
2930 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2931 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2932 sim_printf ("%s is an alias for the %s command:\r\n%s",
2933 cmdp->name, cmdpa->name, cmdpa->help);
2934 break;
2935 }
2936 if (cmdpa->name == NULL)
2937 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2938 }
2939 }
2940 else {
2941 DEVICE *dptr;
2942 UNIT *uptr;
2943 t_stat r;
2944 dptr = find_unit (gbuf, &uptr);
2945 if (dptr == NULL) {
2946 dptr = find_dev (gbuf);
2947 if (dptr == NULL)
2948 return SCPE_ARG;
2949 if (dptr->flags & DEV_DIS)
2950 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2951 }
2952 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2953 if (sim_log)
2954 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2955 return r;
2956 }
2957 }
2958 else {
2959 fprint_help (stdout);
2960 if (sim_log)
2961 fprint_help (sim_log);
2962 }
2963 return SCPE_OK;
2964 }
2965
2966
2967
2968 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2969 {
2970 t_stat status;
2971 if ((cptr == NULL) || (strlen (cptr) == 0))
2972 cptr = getenv("SHELL");
2973 if ((cptr == NULL) || (strlen (cptr) == 0))
2974 cptr = getenv("ComSpec");
2975 (void)fflush(stdout);
2976 if (sim_log)
2977 (void)fflush (sim_log);
2978 if (sim_deb)
2979 (void)fflush (sim_deb);
2980 status = system (cptr);
2981
2982 return status;
2983 }
2984
2985
2986
2987 t_stat echo_cmd (int32 flag, CONST char *cptr)
2988 {
2989 sim_printf ("%s\r\n", cptr);
2990 return SCPE_OK;
2991 }
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013 t_stat do_cmd (int32 flag, CONST char *fcptr)
3014 {
3015 return do_cmd_label (flag, fcptr, NULL);
3016 }
3017
3018 static char *do_position(void)
3019 {
3020 static char cbuf[4*CBUFSIZE];
3021
3022 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3023 sim_do_label[sim_do_depth] ? "::" : "",
3024 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3025 sim_goto_line[sim_do_depth]);
3026 return cbuf;
3027 }
3028
3029 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
3030 {
3031 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3032 CONST char *cptr;
3033 FILE *fpin;
3034 CTAB *cmdp = NULL;
3035 int32 echo, nargs, errabort, i;
3036 int32 saved_sim_do_echo = sim_do_echo,
3037 saved_sim_show_message = sim_show_message,
3038 saved_sim_on_inherit = sim_on_inherit,
3039 saved_sim_quiet = sim_quiet;
3040 t_bool staying;
3041 t_stat stat, stat_nomessage;
3042
3043 stat = SCPE_OK;
3044 staying = TRUE;
3045 if (flag > 0)
3046 GET_SWITCHES (fcptr);
3047 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
3048 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
3049 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
3050 errabort = sim_switches & SWMASK ('E');
3051
3052 abuf[sizeof(abuf)-1] = '\0';
3053 strncpy (abuf, fcptr, sizeof(abuf)-1);
3054 c = abuf;
3055 do_arg[10] = NULL;
3056 for (nargs = 0; nargs < 10; ) {
3057 while (sim_isspace (*c))
3058 c++;
3059 if (*c == 0)
3060 do_arg [nargs++] = NULL;
3061 else {
3062 if (*c == '\'' || *c == '"')
3063 quote = *c++;
3064 else quote = 0;
3065 do_arg[nargs++] = c;
3066 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3067 c++;
3068 if (*c)
3069 *c++ = 0;
3070 }
3071 }
3072
3073 if (do_arg [0] == NULL)
3074 return SCPE_2FARG;
3075 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
3076 strcat (strcpy (cbuf, do_arg[0]), ".ini");
3077 if ((fpin = fopen (cbuf, "r")) == NULL) {
3078 if (flag == 0)
3079 (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3080 return SCPE_OPENERR;
3081 }
3082 }
3083 if (flag >= 0) {
3084 ++sim_do_depth;
3085 if (sim_on_inherit) {
3086 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
3087 for (i=0; i<SCPE_MAX_ERR; i++) {
3088 if (sim_on_actions[sim_do_depth-1][i]) {
3089 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3090 if (NULL == sim_on_actions[sim_do_depth][i]) {
3091 while (--i >= 0) {
3092 FREE(sim_on_actions[sim_do_depth][i]);
3093 sim_on_actions[sim_do_depth][i] = NULL;
3094 }
3095 sim_on_check[sim_do_depth] = 0;
3096 sim_brk_clract ();
3097 --sim_do_depth;
3098 fclose(fpin);
3099 return SCPE_MEM;
3100 }
3101 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3102 }
3103 }
3104 }
3105 }
3106
3107 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
3108 sim_do_label[sim_do_depth] = label;
3109 sim_goto_line[sim_do_depth] = 0;
3110 if (label) {
3111 sim_gotofile = fpin;
3112 sim_do_echo = echo;
3113 stat = goto_cmd (0, label);
3114 if (stat != SCPE_OK) {
3115 strcpy(cbuf, "RETURN SCPE_ARG");
3116 cptr = get_glyph (cbuf, gbuf, 0);
3117 cmdp = find_cmd (gbuf);
3118 goto Cleanup_Return;
3119 }
3120 }
3121 if (errabort)
3122 set_on (1, NULL);
3123
3124 do {
3125 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
3126 if (!sim_do_ocptr[sim_do_depth]) {
3127 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
3128 sim_goto_line[sim_do_depth] += 1;
3129 }
3130 if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {
3131 sim_sub_args(cbuf, sizeof(cbuf), do_arg);
3132 }
3133 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
3134 if (cptr == NULL) {
3135 stat = SCPE_OK;
3136 break;
3137 }
3138 if (*cptr == 0)
3139 continue;
3140 if (echo)
3141 sim_printf("%s> %s\r\n", do_position(), cptr);
3142 if (*cptr == ':')
3143 continue;
3144 cptr = get_glyph_cmd (cptr, gbuf);
3145 sim_switches = 0;
3146 sim_gotofile = fpin;
3147 sim_do_echo = echo;
3148 if ((cmdp = find_cmd (gbuf))) {
3149 if (cmdp->action == &return_cmd)
3150 break;
3151 if (cmdp->action == &do_cmd) {
3152 if (sim_do_depth >= MAX_DO_NEST_LVL)
3153 stat = SCPE_NEST;
3154 else
3155 stat = do_cmd (sim_do_depth+1, cptr);
3156 }
3157 else
3158 stat = cmdp->action (cmdp->arg, cptr);
3159 }
3160 else stat = SCPE_UNK;
3161 echo = sim_do_echo;
3162 stat_nomessage = stat & SCPE_NOMESSAGE;
3163 stat_nomessage = stat_nomessage || (!sim_show_message);
3164 stat = SCPE_BARE_STATUS(stat);
3165 if (cmdp)
3166 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3167 ((cmdp->action != &return_cmd) &&
3168 (cmdp->action != &goto_cmd) &&
3169 (cmdp->action != &on_cmd) &&
3170 (cmdp->action != &echo_cmd)))
3171 sim_last_cmd_stat = stat;
3172 switch (stat) {
3173 case SCPE_AFAIL:
3174 staying = (sim_on_check[sim_do_depth] &&
3175 sim_on_actions[sim_do_depth][stat]);
3176 break;
3177 case SCPE_EXIT:
3178 staying = FALSE;
3179 break;
3180 case SCPE_OK:
3181 case SCPE_STEP:
3182 break;
3183 default:
3184 break;
3185 }
3186 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
3187 (stat != SCPE_STEP)) {
3188 if (!echo && !sim_quiet &&
3189 !stat_nomessage &&
3190 !(cmdp && cmdp->message)) {
3191 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3192 }
3193 }
3194 if (!stat_nomessage) {
3195 if (cmdp && cmdp->message)
3196 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3197 else
3198 if (stat >= SCPE_BASE)
3199 sim_printf ("%s\r\n", sim_error_text (stat));
3200 }
3201 if (stat == SCPE_EXPECT)
3202 stat = SCPE_OK;
3203 if (staying &&
3204 (sim_on_check[sim_do_depth]) &&
3205 (stat != SCPE_OK) &&
3206 (stat != SCPE_STEP)) {
3207 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3208 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3209 else
3210 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3211 }
3212 if (sim_vm_post != NULL)
3213 (*sim_vm_post) (TRUE);
3214 } while (staying);
3215 Cleanup_Return:
3216 if (fpin)
3217 fclose (fpin);
3218 sim_gotofile = NULL;
3219 if (flag >= 0) {
3220 sim_do_echo = saved_sim_do_echo;
3221 sim_show_message = saved_sim_show_message;
3222 sim_on_inherit = saved_sim_on_inherit;
3223 }
3224 sim_quiet = saved_sim_quiet;
3225 if ((flag >= 0) || (!sim_on_inherit)) {
3226 for (i=0; i<SCPE_MAX_ERR; i++) {
3227 FREE (sim_on_actions[sim_do_depth][i]);
3228 sim_on_actions[sim_do_depth][i] = NULL;
3229 }
3230 sim_on_check[sim_do_depth] = 0;
3231 }
3232 if (flag >= 0)
3233 --sim_do_depth;
3234 sim_brk_clract ();
3235 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
3236 sim_string_to_stat (cptr, &stat);
3237 sim_last_cmd_stat = stat;
3238 if (sim_switches & SWMASK ('Q'))
3239 stat |= SCPE_NOMESSAGE;
3240 return stat;
3241 }
3242 return stat | SCPE_NOMESSAGE;
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
3284
3285
3286
3287 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
3288 {
3289 char gbuf[CBUFSIZE];
3290 char *ip = instr, *op, *oend, *tmpbuf;
3291 const char *ap;
3292 char rbuf[CBUFSIZE];
3293 int i;
3294 time_t now;
3295 struct tm *tmnow;
3296
3297 time(&now);
3298 tmnow = localtime(&now);
3299 tmpbuf = (char *)malloc(instr_size);
3300 if (!tmpbuf)
3301 {
3302 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3303 __func__, __FILE__, __LINE__);
3304 #if defined(USE_BACKTRACE)
3305 # if defined(SIGUSR2)
3306 (void)raise(SIGUSR2);
3307
3308 # endif
3309 #endif
3310 abort();
3311 }
3312 op = tmpbuf;
3313 oend = tmpbuf + instr_size - 2;
3314 while (sim_isspace (*ip))
3315 *op++ = *ip++;
3316 for (; *ip && (op < oend); ) {
3317 if ((ip [0] == '\\') &&
3318 ((ip [1] == '%') || (ip [1] == '\\'))) {
3319 ip++;
3320 *op++ = *ip++;
3321 }
3322 else
3323 if ((*ip == '%') &&
3324 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
3325 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
3326 ap = do_arg[ip[1] - '0'];
3327 for (i=0; i<ip[1] - '0'; ++i)
3328 if (do_arg[i] == NULL) {
3329 ap = NULL;
3330 break;
3331 }
3332 ip = ip + 2;
3333 }
3334 else if (ip[1] == '*') {
3335 (void)memset (rbuf, '\0', sizeof(rbuf));
3336 ap = rbuf;
3337 for (i=1; i<=9; ++i)
3338 if (do_arg[i] == NULL)
3339 break;
3340 else
3341 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3342 if (strchr(do_arg[i], ' ')) {
3343 char quote = '"';
3344 if (strchr(do_arg[i], quote))
3345 quote = '\'';
3346 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3347 (i != 1) ? " " : "", quote,
3348 do_arg[i], quote);
3349 }
3350 else
3351 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3352 (i != 1) ? " " : "", do_arg[i]);
3353 }
3354 else
3355 break;
3356 ip = ip + 2;
3357 }
3358 else {
3359 ap = NULL;
3360 (void)get_glyph_nc (ip+1, gbuf, '%');
3361 ap = getenv(gbuf);
3362 if (!ap) {
3363 (void)get_glyph (ip+1, gbuf, '%');
3364 ap = getenv(gbuf);
3365 }
3366 ip += 1 + strlen (gbuf);
3367 if (*ip == '%') ++ip;
3368 if (!ap) {
3369
3370 if (!strcmp ("DATE", gbuf)) {
3371 (void)sprintf (rbuf, "%4d-%02d-%02d",
3372 tmnow->tm_year + 1900,
3373 tmnow->tm_mon + 1,
3374 tmnow->tm_mday);
3375 ap = rbuf;
3376 }
3377 else if (!strcmp ("TIME", gbuf)) {
3378 (void)sprintf (rbuf, "%02d:%02d:%02d",
3379 tmnow->tm_hour,
3380 tmnow->tm_min,
3381 tmnow->tm_sec);
3382 ap = rbuf;
3383 }
3384 else if (!strcmp ("DATETIME", gbuf)) {
3385 (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3386 tmnow->tm_year + 1900,
3387 tmnow->tm_mon + 1,
3388 tmnow->tm_mday,
3389 tmnow->tm_hour,
3390 tmnow->tm_min,
3391 tmnow->tm_sec);
3392 ap = rbuf;
3393 }
3394
3395 if (!strcmp ("LDATE", gbuf)) {
3396 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3397 ap = rbuf;
3398 }
3399 else if (!strcmp ("LTIME", gbuf)) {
3400 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3401 ap = rbuf;
3402 }
3403 else if (!strcmp ("CTIME", gbuf)) {
3404 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3405 ap = rbuf;
3406 }
3407
3408 else if (!strcmp ("DATE_YYYY", gbuf)) {
3409 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3410 ap = rbuf;
3411 }
3412 else if (!strcmp ("DATE_YY", gbuf)) {
3413 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3414 ap = rbuf;
3415 }
3416 else if (!strcmp ("DATE_YC", gbuf)) {
3417 (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3418 ap = rbuf;
3419 }
3420 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3421 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3422 int year = tmnow->tm_year + 1900;
3423 int days = year - 2001;
3424 int leaps = days/4 - days/100 + days/400;
3425 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3426 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3427 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3428 96, 80, 92, 76, 88, 72, 84};
3429 int cal_year = years[selector];
3430
3431 if (!strcmp ("DATE_19XX_YY", gbuf))
3432 (void)sprintf (rbuf, "%d", cal_year);
3433 else
3434 (void)sprintf (rbuf, "%d", cal_year + 1900);
3435 ap = rbuf;
3436 }
3437 else if (!strcmp ("DATE_MM", gbuf)) {
3438 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3439 ap = rbuf;
3440 }
3441 else if (!strcmp ("DATE_MMM", gbuf)) {
3442 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3443 ap = rbuf;
3444 }
3445 else if (!strcmp ("DATE_DD", gbuf)) {
3446 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3447 ap = rbuf;
3448 }
3449 else if (!strcmp ("DATE_D", gbuf)) {
3450 (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3451 ap = rbuf;
3452 }
3453 else if ((!strcmp ("DATE_WW", gbuf)) ||
3454 (!strcmp ("DATE_WYYYY", gbuf))) {
3455 int iso_yr = tmnow->tm_year + 1900;
3456 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3457
3458 if (iso_wk == 0) {
3459 iso_yr = iso_yr - 1;
3460 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3461 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3462 }
3463 else
3464 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3465 ++iso_yr;
3466 iso_wk = 1;
3467 }
3468 if (!strcmp ("DATE_WW", gbuf))
3469 (void)sprintf (rbuf, "%02d", iso_wk);
3470 else
3471 (void)sprintf (rbuf, "%04d", iso_yr);
3472 ap = rbuf;
3473 }
3474 else if (!strcmp ("DATE_JJJ", gbuf)) {
3475 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3476 ap = rbuf;
3477 }
3478 else if (!strcmp ("TIME_HH", gbuf)) {
3479 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3480 ap = rbuf;
3481 }
3482 else if (!strcmp ("TIME_MM", gbuf)) {
3483 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3484 ap = rbuf;
3485 }
3486 else if (!strcmp ("TIME_SS", gbuf)) {
3487 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3488 ap = rbuf;
3489 }
3490 else if (!strcmp ("STATUS", gbuf)) {
3491 (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3492 ap = rbuf;
3493 }
3494 else if (!strcmp ("TSTATUS", gbuf)) {
3495 (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3496 ap = rbuf;
3497 }
3498 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3499 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3500 ap = rbuf;
3501 }
3502 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3503 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3504 ap = rbuf;
3505 }
3506 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3507 (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3508 ap = rbuf;
3509 }
3510 else if (!strcmp ("SIM_QUIET", gbuf)) {
3511 (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3512 ap = rbuf;
3513 }
3514 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3515 (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3516 ap = rbuf;
3517 }
3518 else if (!strcmp ("HOSTID", gbuf)) {
3519 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3520 (void)sprintf (rbuf, "%ld", (long)gethostid());
3521 #else
3522 (void)sprintf (rbuf, "00000000");
3523 #endif
3524 ap = rbuf;
3525 }
3526 else if (!strcmp ("UID", gbuf)) {
3527 #if defined(HAVE_UNISTD)
3528 (void)sprintf (rbuf, "%ld", (long)getuid());
3529 #else
3530 (void)sprintf (rbuf, "0");
3531 #endif
3532 ap = rbuf;
3533 }
3534 else if (!strcmp ("GID", gbuf)) {
3535 #if defined(HAVE_UNISTD)
3536 (void)sprintf (rbuf, "%ld", (long)getgid());
3537 #else
3538 (void)sprintf (rbuf, "0");
3539 #endif
3540 ap = rbuf;
3541 }
3542 else if (!strcmp ("EUID", gbuf)) {
3543 #if defined(HAVE_UNISTD)
3544 (void)sprintf (rbuf, "%ld", (long)geteuid());
3545 #else
3546 (void)sprintf (rbuf, "0");
3547 #endif
3548 ap = rbuf;
3549 }
3550 else if (!strcmp ("EGID", gbuf)) {
3551 #if defined(HAVE_UNISTD)
3552 (void)sprintf (rbuf, "%ld", (long)getegid());
3553 #else
3554 (void)sprintf (rbuf, "0");
3555 #endif
3556 ap = rbuf;
3557 }
3558 else if (!strcmp ("PID", gbuf)) {
3559 #if defined(HAVE_UNISTD)
3560 (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3561 #else
3562 (void)sprintf (rbuf, "0");
3563 #endif
3564 ap = rbuf;
3565 }
3566 else if (!strcmp ("PPID", gbuf)) {
3567 #if defined(HAVE_UNISTD)
3568 (void)sprintf (rbuf, "%ld", (long)getppid());
3569 #else
3570 (void)sprintf (rbuf, "0");
3571 #endif
3572 ap = rbuf;
3573 }
3574 else if (!strcmp ("PGID", gbuf)) {
3575 #if defined(HAVE_UNISTD)
3576 (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3577 #else
3578 (void)sprintf (rbuf, "0");
3579 #endif
3580 ap = rbuf;
3581 }
3582 else if (!strcmp ("SID", gbuf)) {
3583 #if defined(HAVE_UNISTD)
3584 (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3585 #else
3586 (void)sprintf (rbuf, "0");
3587 #endif
3588 ap = rbuf;
3589 }
3590 else if (!strcmp ("ENDIAN", gbuf)) {
3591 #if ( defined(DECLITEND) && DECLITEND == 1 )
3592 (void)sprintf (rbuf, "LITTLE");
3593 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3594 (void)sprintf (rbuf, "BIG");
3595 #else
3596 (void)sprintf (rbuf, "UNKNOWN");
3597 #endif
3598 ap = rbuf;
3599 }
3600 else if (!strcmp("SIM_NAME", gbuf)) {
3601 (void)sprintf (rbuf, "%s", sim_name);
3602 ap = rbuf;
3603 }
3604 else if (!strcmp("SIM_VERSION", gbuf)) {
3605 #if defined(VER_H_GIT_VERSION)
3606 (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3607 #else
3608 (void)sprintf (rbuf, "UNKNOWN");
3609 #endif
3610 ap = rbuf;
3611 }
3612 else if (!strcmp("SIM_HASH", gbuf)) {
3613 #if defined(VER_H_GIT_HASH)
3614 (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3615 #else
3616 (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3617 #endif
3618 ap = rbuf;
3619 }
3620 else if (!strcmp("SIM_RELT", gbuf)) {
3621 #if defined(VER_H_GIT_RELT)
3622 (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3623 #else
3624 (void)sprintf (rbuf, "X");
3625 #endif
3626 ap = rbuf;
3627 }
3628 else if (!strcmp("SIM_DATE", gbuf)) {
3629 #if defined(VER_H_GIT_DATE)
3630 (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3631 #else
3632 (void)sprintf (rbuf, "UNKNOWN");
3633 #endif
3634 ap = rbuf;
3635 }
3636 else if ((!strcmp("CORES", gbuf)) ||
3637 (!strcmp("SIM_CORES", gbuf))) {
3638 (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3639 ap = rbuf;
3640 }
3641 else if ((!strcmp("CPUS", gbuf)) ||
3642 (!strcmp("SIM_PROCESSORS", gbuf))) {
3643 (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3644 ap = rbuf;
3645 }
3646 }
3647 }
3648 if (ap) {
3649 while (*ap && (op < oend))
3650 *op++ = *ap++;
3651 }
3652 }
3653 else
3654 *op++ = *ip++;
3655 }
3656 *op = 0;
3657 strcpy (instr, tmpbuf);
3658 FREE (tmpbuf);
3659 return;
3660 }
3661
3662 static
3663 int sim_cmp_string (const char *s1, const char *s2)
3664 {
3665 long int v1, v2;
3666 char *ep1, *ep2;
3667
3668 v1 = strtol(s1+1, &ep1, 0);
3669 v2 = strtol(s2+1, &ep2, 0);
3670 if ((ep1 != s1 + strlen (s1) - 1) ||
3671 (ep2 != s2 + strlen (s2) - 1))
3672 return strcmp (s1, s2);
3673 if (v1 == v2)
3674 return 0;
3675 if (v1 < v2)
3676 return -1;
3677 return 1;
3678 }
3679
3680
3681
3682 t_stat assert_cmd (int32 flag, CONST char *cptr)
3683 {
3684 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3685 CONST char *tptr, *gptr;
3686 REG *rptr;
3687 uint32 idx = 0;
3688 t_value val;
3689 t_stat r;
3690 t_bool Not = FALSE;
3691 t_bool result;
3692 t_addr addr = 0;
3693 t_stat reason = SCPE_AFAIL;
3694
3695 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3696
3697 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3698 # pragma diagnostic push
3699 # pragma diag_suppress = integer_sign_change
3700 #endif
3701 sim_stabr.boolop = sim_staba.boolop = -1;
3702 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3703 # pragma diagnostic pop
3704 #endif
3705 if (*cptr == 0)
3706 return SCPE_2FARG;
3707 tptr = get_glyph (cptr, gbuf, 0);
3708 if (!strcmp (gbuf, "NOT")) {
3709 Not = TRUE;
3710 cptr = (CONST char *)tptr;
3711 }
3712 if (*cptr == '"') {
3713 char op[CBUFSIZE];
3714 static struct {
3715 const char *op;
3716 int aval;
3717 int bval;
3718 t_bool invert;
3719 } *optr, compare_ops[] =
3720 {
3721 { "==", 0, 0, FALSE },
3722 { "EQU", 0, 0, FALSE },
3723 { "!=", 0, 0, TRUE },
3724 { "NEQ", 0, 0, TRUE },
3725 { "<", -1, -1, FALSE },
3726 { "LSS", -1, -1, FALSE },
3727 { "<=", 0, -1, FALSE },
3728 { "LEQ", 0, -1, FALSE },
3729 { ">", 1, 1, FALSE },
3730 { "GTR", 1, 1, FALSE },
3731 { ">=", 0, 1, FALSE },
3732 { "GEQ", 0, 1, FALSE },
3733 { NULL }
3734 };
3735
3736 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3737
3738 if (!*tptr)
3739 return SCPE_2FARG;
3740 cptr += strlen (gbuf);
3741 while (sim_isspace (*cptr))
3742 ++cptr;
3743 (void)get_glyph (cptr, op, '"');
3744 for (optr = compare_ops; optr->op; optr++)
3745 if (0 == strcmp (op, optr->op))
3746 break;
3747 if (!optr->op)
3748 return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3749 cptr += strlen (op);
3750 while (sim_isspace (*cptr))
3751 ++cptr;
3752 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3753
3754 if (*cptr) {
3755 if (flag)
3756 return SCPE_2MARG;
3757 }
3758 else {
3759 if (!flag)
3760 return SCPE_2FARG;
3761 }
3762 result = sim_cmp_string (gbuf, gbuf2);
3763 result = ((result == optr->aval) || (result == optr->bval));
3764 if (optr->invert)
3765 result = !result;
3766 }
3767 else {
3768 cptr = get_glyph (cptr, gbuf, 0);
3769 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3770 if (rptr) {
3771 if (*gptr == '[') {
3772 if (rptr->depth <= 1)
3773 return SCPE_ARG;
3774 idx = (uint32) strtotv (++gptr, &tptr, 10);
3775 if ((gptr == tptr) || (*tptr++ != ']'))
3776 return SCPE_ARG;
3777 gptr = tptr;
3778 }
3779 else idx = 0;
3780 if (idx >= rptr->depth)
3781 return SCPE_SUB;
3782 }
3783 else {
3784 if (sim_dfdev && sim_vm_parse_addr)
3785 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3786 else if (sim_dfdev)
3787 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3788 if (gbuf == gptr)
3789 return SCPE_NXREG;
3790 }
3791 if (*gptr != 0)
3792 (void)get_glyph (gptr, gbuf, 0);
3793 else {
3794 if (*cptr == 0)
3795 return SCPE_2FARG;
3796 cptr = get_glyph (cptr, gbuf, 0);
3797 }
3798 if (*cptr) {
3799 if (flag)
3800 return SCPE_2MARG;
3801 }
3802 else {
3803 if (!flag)
3804 return SCPE_2FARG;
3805 }
3806 if (rptr) {
3807 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3808 # pragma diagnostic push
3809 # pragma diag_suppress = integer_sign_change
3810 #endif
3811 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3812 (sim_stabr.boolop == -1))
3813 return SCPE_MISVAL;
3814 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3815 # pragma diagnostic pop
3816 #endif
3817 val = get_rval (rptr, idx);
3818 result = test_search (&val, &sim_stabr);
3819 }
3820 else {
3821 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3822 # pragma diagnostic push
3823 # pragma diag_suppress = integer_sign_change
3824 #endif
3825 if (sim_dfdev)
3826 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3827 (sim_staba.boolop == -1))
3828 return SCPE_MISVAL;
3829 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3830 # pragma diagnostic pop
3831 #endif
3832 if (sim_dfdev)
3833 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3834 if (reason != SCPE_OK)
3835 return reason;
3836 result = test_search (sim_eval, &sim_staba);
3837 }
3838 }
3839 if (Not ^ result) {
3840 if (!flag)
3841 sim_brk_setact (cptr);
3842 }
3843 else
3844 if (flag)
3845 return SCPE_AFAIL;
3846 return SCPE_OK;
3847 }
3848
3849
3850
3851 t_stat send_cmd (int32 flag, CONST char *cptr)
3852 {
3853 char gbuf[CBUFSIZE];
3854 CONST char *tptr;
3855 uint8 dbuf[CBUFSIZE];
3856 uint32 dsize = 0;
3857 uint32 delay = 0;
3858 uint32 after = 0;
3859 t_stat r;
3860 SEND *snd = NULL;
3861
3862 GET_SWITCHES (cptr);
3863 tptr = get_glyph (cptr, gbuf, ',');
3864 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3865 r = tmxr_locate_line_send (gbuf, &snd);
3866 if (r != SCPE_OK)
3867 return r;
3868 cptr = tptr;
3869 tptr = get_glyph (tptr, gbuf, ',');
3870 }
3871 else
3872 snd = sim_cons_get_send ();
3873
3874 while (*cptr) {
3875 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3876 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3877 if (r != SCPE_OK)
3878 return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3879 cptr = tptr;
3880 tptr = get_glyph (cptr, gbuf, ',');
3881 continue;
3882 }
3883 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3884 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3885 if (r != SCPE_OK)
3886 return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3887 cptr = tptr;
3888 tptr = get_glyph (cptr, gbuf, ',');
3889 continue;
3890 }
3891 if ((*cptr == '"') || (*cptr == '\''))
3892 break;
3893 return SCPE_ARG;
3894 }
3895 if (*cptr) {
3896 if ((*cptr != '"') && (*cptr != '\''))
3897 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3898 cptr = get_glyph_quoted (cptr, gbuf, 0);
3899 if (*cptr != '\0')
3900 return SCPE_2MARG;
3901
3902 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3903 return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3904 }
3905 if ((dsize == 0) && (delay == 0) && (after == 0))
3906 return SCPE_2FARG;
3907 return sim_send_input (snd, dbuf, dsize, after, delay);
3908 }
3909
3910 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3911 {
3912 char gbuf[CBUFSIZE];
3913 CONST char *tptr;
3914 t_stat r;
3915 SEND *snd = NULL;
3916
3917 tptr = get_glyph (cptr, gbuf, ',');
3918 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3919 r = tmxr_locate_line_send (gbuf, &snd);
3920 if (r != SCPE_OK)
3921 return r;
3922 cptr = tptr;
3923 }
3924 else
3925 snd = sim_cons_get_send ();
3926 if (*cptr)
3927 return SCPE_2MARG;
3928 return sim_show_send_input (st, snd);
3929 }
3930
3931 t_stat expect_cmd (int32 flag, CONST char *cptr)
3932 {
3933 char gbuf[CBUFSIZE];
3934 CONST char *tptr;
3935 EXPECT *exp = NULL;
3936
3937 GET_SWITCHES (cptr);
3938 tptr = get_glyph (cptr, gbuf, ',');
3939 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3940 cptr = tptr;
3941 } else {
3942 exp = sim_cons_get_expect ();
3943 }
3944
3945 if (flag) {
3946 return sim_set_expect (exp, cptr);
3947 } else {
3948 if (exp == NULL) {
3949 exp = sim_cons_get_expect();
3950 }
3951 return sim_set_noexpect (exp, cptr);
3952 }
3953 }
3954
3955 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3956 {
3957 char gbuf[CBUFSIZE];
3958 CONST char *tptr;
3959 EXPECT *exp = NULL;
3960 t_stat r;
3961
3962 tptr = get_glyph (cptr, gbuf, ',');
3963 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3964 r = tmxr_locate_line_expect (gbuf, &exp);
3965 if (r != SCPE_OK)
3966 return r;
3967 cptr = tptr;
3968 }
3969 else
3970 exp = sim_cons_get_expect ();
3971 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3972 return SCPE_ARG;
3973 tptr = get_glyph_quoted (cptr, gbuf, 0);
3974 if (*tptr != '\0')
3975 return SCPE_2MARG;
3976 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3977 return SCPE_ARG;
3978 return sim_exp_show (st, exp, gbuf);
3979 }
3980
3981
3982
3983 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3984 {
3985 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3986 const char *cptr;
3987 long fpos;
3988 int32 saved_do_echo = sim_do_echo;
3989 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3990
3991 if (NULL == sim_gotofile) return SCPE_UNK;
3992 (void)get_glyph (fcptr, gbuf1, 0);
3993 if ('\0' == gbuf1[0]) return SCPE_ARG;
3994 fpos = ftell(sim_gotofile);
3995 rewind(sim_gotofile);
3996 sim_goto_line[sim_do_depth] = 0;
3997 sim_do_echo = 0;
3998 while (1) {
3999 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
4000 if (cptr == NULL) break;
4001 sim_goto_line[sim_do_depth] += 1;
4002 if (*cptr == 0) continue;
4003 if (*cptr != ':') continue;
4004 ++cptr;
4005 while (sim_isspace (*cptr)) ++cptr;
4006 cptr = get_glyph (cptr, gbuf, 0);
4007 if (0 == strcmp(gbuf, gbuf1)) {
4008 sim_brk_clract ();
4009 sim_do_echo = saved_do_echo;
4010 if (sim_do_echo)
4011 sim_printf("%s> %s\r\n", do_position(), cbuf);
4012 return SCPE_OK;
4013 }
4014 }
4015 sim_do_echo = saved_do_echo;
4016 fseek(sim_gotofile, fpos, SEEK_SET);
4017 sim_goto_line[sim_do_depth] = saved_goto_line;
4018 return SCPE_ARG;
4019 }
4020
4021
4022
4023
4024
4025
4026
4027
4028 t_stat return_cmd (int32 flag, CONST char *fcptr)
4029 {
4030 return SCPE_UNK;
4031 }
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041 t_stat shift_cmd (int32 flag, CONST char *fcptr)
4042 {
4043 return SCPE_UNK;
4044 }
4045
4046
4047
4048
4049
4050
4051
4052
4053 t_stat call_cmd (int32 flag, CONST char *fcptr)
4054 {
4055 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4056 const char *cptr;
4057
4058 if (NULL == sim_gotofile) return SCPE_UNK;
4059 cptr = get_glyph (fcptr, gbuf, 0);
4060 if ('\0' == gbuf[0]) return SCPE_ARG;
4061 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4062 sim_switches |= SWMASK ('O');
4063 return do_cmd_label (flag, cbuf, gbuf);
4064 }
4065
4066
4067
4068 t_stat on_cmd (int32 flag, CONST char *cptr)
4069 {
4070 char gbuf[CBUFSIZE];
4071 t_stat cond;
4072
4073 cptr = get_glyph (cptr, gbuf, 0);
4074 if ('\0' == gbuf[0]) return SCPE_ARG;
4075 if (0 == strcmp("ERROR", gbuf))
4076 cond = 0;
4077 else
4078 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4079 return SCPE_ARG;
4080 if ((NULL == cptr) || ('\0' == *cptr)) {
4081 FREE(sim_on_actions[sim_do_depth][cond]);
4082 sim_on_actions[sim_do_depth][cond] = NULL; }
4083 else {
4084 sim_on_actions[sim_do_depth][cond] =
4085 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4086 if (!sim_on_actions[sim_do_depth][cond])
4087 {
4088 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4089 __func__, __FILE__, __LINE__);
4090 #if defined(USE_BACKTRACE)
4091 # if defined(SIGUSR2)
4092 (void)raise(SIGUSR2);
4093
4094 # endif
4095 #endif
4096 abort();
4097 }
4098 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4099 }
4100 return SCPE_OK;
4101 }
4102
4103
4104
4105 t_stat noop_cmd (int32 flag, CONST char *cptr)
4106 {
4107 if (cptr && (*cptr != 0))
4108 return SCPE_2MARG;
4109 return SCPE_OK;
4110 }
4111
4112
4113
4114 t_stat set_on (int32 flag, CONST char *cptr)
4115 {
4116 if ((flag) && (cptr) && (*cptr)) {
4117 char gbuf[CBUFSIZE];
4118
4119 cptr = get_glyph (cptr, gbuf, 0);
4120 if (((MATCH_CMD(gbuf,"INHERIT")) &&
4121 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
4122 (*cptr))
4123 return SCPE_2MARG;
4124 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
4125 sim_on_inherit = 1;
4126 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
4127 sim_on_inherit = 0;
4128 return SCPE_OK;
4129 }
4130 if (cptr && (*cptr != 0))
4131 return SCPE_2MARG;
4132 sim_on_check[sim_do_depth] = flag;
4133 if ((sim_do_depth != 0) &&
4134 (NULL == sim_on_actions[sim_do_depth][0])) {
4135 sim_on_actions[sim_do_depth][0] =
4136 (char *)malloc(1+strlen("RETURN"));
4137 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4138 }
4139 if ((sim_do_depth != 0) &&
4140 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
4141 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
4142 (char *)malloc(1+strlen("RETURN"));
4143 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4144 }
4145 return SCPE_OK;
4146 }
4147
4148
4149
4150 t_stat set_verify (int32 flag, CONST char *cptr)
4151 {
4152 if (cptr && (*cptr != 0))
4153 return SCPE_2MARG;
4154 if (flag == sim_do_echo)
4155 return SCPE_OK;
4156 sim_do_echo = flag;
4157 return SCPE_OK;
4158 }
4159
4160
4161
4162 t_stat set_message (int32 flag, CONST char *cptr)
4163 {
4164 if (cptr && (*cptr != 0))
4165 return SCPE_2MARG;
4166 if (flag == sim_show_message)
4167 return SCPE_OK;
4168 sim_show_message = flag;
4169 return SCPE_OK;
4170 }
4171
4172
4173
4174 t_stat set_localopc (int32 flag, CONST char *cptr)
4175 {
4176 if (cptr && (*cptr != 0))
4177 return SCPE_2MARG;
4178 if (flag == sim_localopc)
4179 return SCPE_OK;
4180 sim_localopc = flag;
4181 return SCPE_OK;
4182 }
4183
4184
4185 t_stat set_quiet (int32 flag, CONST char *cptr)
4186 {
4187 if (cptr && (*cptr != 0))
4188 return SCPE_2MARG;
4189 if (flag == sim_quiet)
4190 return SCPE_OK;
4191 sim_quiet = flag;
4192 return SCPE_OK;
4193 }
4194
4195
4196
4197 t_stat sim_set_environment (int32 flag, CONST char *cptr)
4198 {
4199 char varname[CBUFSIZE];
4200
4201 if ((NULL == cptr) || (*cptr == 0))
4202 return SCPE_2FARG;
4203 cptr = get_glyph (cptr, varname, '=');
4204 setenv(varname, cptr, 1);
4205 return SCPE_OK;
4206 }
4207
4208
4209
4210 t_stat set_cmd (int32 flag, CONST char *cptr)
4211 {
4212 uint32 lvl = 0;
4213 t_stat r;
4214 char gbuf[CBUFSIZE], *cvptr;
4215 CONST char *svptr;
4216 DEVICE *dptr;
4217 UNIT *uptr;
4218 MTAB *mptr;
4219 CTAB *gcmdp;
4220 C1TAB *ctbr = NULL, *glbr;
4221
4222 GET_SWITCHES (cptr);
4223 if ((NULL == cptr) || (*cptr == 0))
4224 return SCPE_2FARG;
4225 cptr = get_glyph (svptr = cptr, gbuf, 0);
4226
4227 if ((dptr = find_dev (gbuf))) {
4228 uptr = dptr->units;
4229 ctbr = set_dev_tab;
4230 lvl = MTAB_VDV;
4231 GET_SWITCHES (cptr);
4232 }
4233 else if ((dptr = find_unit (gbuf, &uptr))) {
4234 if (uptr == NULL)
4235 return SCPE_NXUN;
4236 ctbr = set_unit_tab;
4237 lvl = MTAB_VUN;
4238 GET_SWITCHES (cptr);
4239 }
4240 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
4241 GET_SWITCHES (cptr);
4242 return gcmdp->action (gcmdp->arg, cptr);
4243 }
4244 else {
4245 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4246 if ((cvptr = strchr (gbuf, '=')))
4247 *cvptr++ = 0;
4248 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4249 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4250 dptr = sim_dflt_dev;
4251 cptr = svptr;
4252 while (sim_isspace(*cptr))
4253 ++cptr;
4254 break;
4255 }
4256 }
4257 }
4258 if (!dptr)
4259 return SCPE_NXDEV;
4260 lvl = MTAB_VDV;
4261 uptr = dptr->units;
4262 }
4263 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4264 return SCPE_2FARG;
4265 GET_SWITCHES (cptr);
4266
4267 while (*cptr != 0) {
4268 cptr = get_glyph (svptr = cptr, gbuf, ',');
4269 if (0 == strcmp (gbuf, ";"))
4270 break;
4271 if ((cvptr = strchr (gbuf, '=')))
4272 *cvptr++ = 0;
4273 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4274 if ((mptr->mstring) &&
4275 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4276 if (mptr->mask & MTAB_XTD) {
4277 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4278 return SCPE_ARG;
4279 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4280 return SCPE_UDIS;
4281 if (mptr->valid) {
4282 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4283 svptr = get_glyph_quoted (svptr, gbuf, ',');
4284 if ((cvptr = strchr (gbuf, '='))) {
4285 *cvptr++ = 0;
4286 cptr = svptr;
4287 }
4288 }
4289 else {
4290 if (cvptr && MODMASK(mptr,MTAB_NC)) {
4291 (void)get_glyph_nc (svptr, gbuf, ',');
4292 if ((cvptr = strchr (gbuf, '=')))
4293 *cvptr++ = 0;
4294 }
4295 }
4296 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4297 if (r != SCPE_OK)
4298 return r;
4299 }
4300 else if (!mptr->desc)
4301 break;
4302 else if (cvptr)
4303 return SCPE_ARG;
4304 else *((int32 *) mptr->desc) = mptr->match;
4305 }
4306 else {
4307 if (cvptr)
4308 return SCPE_ARG;
4309 if (uptr->flags & UNIT_DIS)
4310 return SCPE_UDIS;
4311 if ((mptr->valid) &&
4312 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4313 return r;
4314 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4315 (mptr->match & mptr->mask);
4316 }
4317 break;
4318 }
4319 }
4320 if (!mptr || (mptr->mask == 0)) {
4321 if ((glbr = find_c1tab (ctbr, gbuf))) {
4322 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
4323 if (r != SCPE_OK)
4324 return r;
4325 }
4326 else if (!dptr->modifiers)
4327 return SCPE_NOPARAM;
4328 else return SCPE_NXPAR;
4329 }
4330 }
4331 return SCPE_OK;
4332 }
4333
4334
4335
4336 CTAB *find_ctab (CTAB *tab, const char *gbuf)
4337 {
4338 if (!tab)
4339 return NULL;
4340 for (; tab->name != NULL; tab++) {
4341 if (MATCH_CMD (gbuf, tab->name) == 0)
4342 return tab;
4343 }
4344 return NULL;
4345 }
4346
4347 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
4348 {
4349 if (!tab)
4350 return NULL;
4351 for (; tab->name != NULL; tab++) {
4352 if (MATCH_CMD (gbuf, tab->name) == 0)
4353 return tab;
4354 }
4355 return NULL;
4356 }
4357
4358
4359
4360 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4361 {
4362 if (cptr)
4363 return SCPE_ARG;
4364 dptr->dradix = flag & 037;
4365 return SCPE_OK;
4366 }
4367
4368
4369
4370 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4371 {
4372 UNIT *up;
4373 uint32 i;
4374
4375 if (cptr)
4376 return SCPE_ARG;
4377 if ((dptr->flags & DEV_DISABLE) == 0)
4378 return SCPE_NOFNC;
4379 if (flag) {
4380 if ((dptr->flags & DEV_DIS) == 0)
4381 return SCPE_OK;
4382 dptr->flags = dptr->flags & ~DEV_DIS;
4383 }
4384 else {
4385 if (dptr->flags & DEV_DIS)
4386 return SCPE_OK;
4387 for (i = 0; i < dptr->numunits; i++) {
4388 up = (dptr->units) + i;
4389 if ((up->flags & UNIT_ATT) || sim_is_active (up))
4390 return SCPE_NOFNC;
4391 }
4392 dptr->flags = dptr->flags | DEV_DIS;
4393 }
4394 if (dptr->reset)
4395 return dptr->reset (dptr);
4396 else return SCPE_OK;
4397 }
4398
4399
4400
4401 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4402 {
4403 if (cptr)
4404 return SCPE_ARG;
4405 if (!(uptr->flags & UNIT_DISABLE))
4406 return SCPE_NOFNC;
4407 if (flag)
4408 uptr->flags = uptr->flags & ~UNIT_DIS;
4409 else {
4410 if ((uptr->flags & UNIT_ATT) ||
4411 sim_is_active (uptr))
4412 return SCPE_NOFNC;
4413 uptr->flags = uptr->flags | UNIT_DIS;
4414 }
4415 return SCPE_OK;
4416 }
4417
4418
4419
4420 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4421 {
4422 char gbuf[CBUFSIZE];
4423 DEBTAB *dep;
4424
4425 if ((dptr->flags & DEV_DEBUG) == 0)
4426 return SCPE_NOFNC;
4427 if (cptr == NULL) {
4428 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4429 if (flag && dptr->debflags) {
4430 for (dep = dptr->debflags; dep->name != NULL; dep++)
4431 dptr->dctrl = dptr->dctrl | dep->mask;
4432 }
4433 return SCPE_OK;
4434 }
4435 if (dptr->debflags == NULL)
4436 return SCPE_ARG;
4437 while (*cptr) {
4438 cptr = get_glyph (cptr, gbuf, ';');
4439 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4440 if (strcmp (dep->name, gbuf) == 0) {
4441 if (flag)
4442 dptr->dctrl = dptr->dctrl | dep->mask;
4443 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4444 break;
4445 }
4446 }
4447 if (dep->mask == 0)
4448 return SCPE_ARG;
4449 }
4450 return SCPE_OK;
4451 }
4452
4453
4454
4455 t_stat show_cmd (int32 flag, CONST char *cptr)
4456 {
4457 t_stat r = SCPE_IERR;
4458
4459 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4460
4461 if (NULL == cptr)
4462 return r;
4463 if (sim_ofile) {
4464 r = show_cmd_fi (sim_ofile, flag, cptr);
4465 fclose (sim_ofile);
4466 }
4467 else {
4468 r = show_cmd_fi (stdout, flag, cptr);
4469 if (sim_log && (sim_log != stdout))
4470 show_cmd_fi (sim_log, flag, cptr);
4471 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4472 show_cmd_fi (sim_deb, flag, cptr);
4473 }
4474 return r;
4475 }
4476
4477 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4478 {
4479 uint32 lvl = 0xFFFFFFFF;
4480 char gbuf[CBUFSIZE], *cvptr;
4481 CONST char *svptr;
4482 DEVICE *dptr;
4483 UNIT *uptr;
4484 MTAB *mptr;
4485 SHTAB *shtb = NULL, *shptr;
4486
4487 GET_SWITCHES (cptr);
4488 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4489 return SCPE_2FARG;
4490 cptr = get_glyph (svptr = cptr, gbuf, 0);
4491
4492 if ((dptr = find_dev (gbuf))) {
4493 uptr = dptr->units;
4494 shtb = show_dev_tab;
4495 lvl = MTAB_VDV;
4496 GET_SWITCHES (cptr);
4497 }
4498 else if ((dptr = find_unit (gbuf, &uptr))) {
4499 if (uptr == NULL)
4500 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4501 if (uptr->flags & UNIT_DIS)
4502 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4503 shtb = show_unit_tab;
4504 lvl = MTAB_VUN;
4505 GET_SWITCHES (cptr);
4506 }
4507 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4508 GET_SWITCHES (cptr);
4509 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4510 }
4511 else {
4512 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4513 if ((cvptr = strchr (gbuf, '=')))
4514 *cvptr++ = 0;
4515 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4516 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4517 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4518 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4519 dptr = sim_dflt_dev;
4520 lvl = MTAB_VDV;
4521 cptr = svptr;
4522 while (sim_isspace(*cptr))
4523 ++cptr;
4524 break;
4525 }
4526 }
4527 }
4528 if (!dptr) {
4529 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4530 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4531 else
4532 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);
4533 }
4534 }
4535
4536 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4537 return (lvl == MTAB_VDV)?
4538 show_device (ofile, dptr, 0):
4539 show_unit (ofile, dptr, uptr, -1);
4540 }
4541 GET_SWITCHES (cptr);
4542
4543 while (*cptr != 0) {
4544 cptr = get_glyph (cptr, gbuf, ',');
4545 if ((cvptr = strchr (gbuf, '=')))
4546 *cvptr++ = 0;
4547 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4548 if (((mptr->mask & MTAB_XTD)?
4549 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4550 ((mptr->disp && mptr->pstring &&
4551 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4552 )) {
4553 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4554 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4555 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4556 break;
4557 }
4558 }
4559 if (!mptr || (mptr->mask == 0)) {
4560 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4561 t_stat r;
4562
4563 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4564 if (r != SCPE_OK)
4565 return r;
4566 }
4567 else {
4568 if (!dptr->modifiers)
4569 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4570 else
4571 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4572 }
4573 }
4574 }
4575 return SCPE_OK;
4576 }
4577
4578 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4579 {
4580 if (!tab)
4581 return NULL;
4582 for (; tab->name != NULL; tab++) {
4583 if (MATCH_CMD (gbuf, tab->name) == 0)
4584 return tab;
4585 }
4586 return NULL;
4587 }
4588
4589
4590
4591 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4592 {
4593 uint32 j, udbl, ucnt;
4594 UNIT *uptr;
4595 int32 toks = 0;
4596
4597 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4598 (void)fprintf (st, "%s", sim_dname (dptr));
4599 if ((flag == 2) && dptr->description) {
4600 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4601 }
4602 else {
4603 if ((sim_switches & SWMASK ('D')) && dptr->description)
4604 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4605 }
4606 if (qdisable (dptr)) {
4607 (void)fprintf (st, "\tdisabled\r\n");
4608 return SCPE_OK;
4609 }
4610 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4611 uptr = dptr->units + j;
4612 if (!(uptr->flags & UNIT_DIS))
4613 ucnt++;
4614 else if (uptr->flags & UNIT_DISABLE)
4615 udbl++;
4616 }
4617
4618 if (dptr->numunits == 0) {
4619
4620
4621 }
4622 else
4623 {
4624 if (ucnt == 0) {
4625 fprint_sep (st, &toks);
4626 (void)fprintf (st, "all units disabled\r\n");
4627 }
4628 else if ((ucnt + udbl) == 1) {
4629 fprint_sep (st, &toks);
4630 (void)fprintf (st, " 1 unit\r\n");
4631 }
4632 else if ((ucnt > 1) || (udbl > 0)) {
4633 fprint_sep (st, &toks);
4634 (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4635 }
4636 else
4637 if ((flag != 2) || !dptr->description || toks)
4638 (void)fprintf (st, "\r\n");
4639 toks = 0;
4640 }
4641 if (flag)
4642 return SCPE_OK;
4643 for (j = 0; j < dptr->numunits; j++) {
4644 uptr = dptr->units + j;
4645 if ((uptr->flags & UNIT_DIS) == 0)
4646 show_unit (st, dptr, uptr, ucnt + udbl);
4647 }
4648 }
4649 return SCPE_OK;
4650 }
4651
4652 void fprint_sep (FILE *st, int32 *tokens)
4653 {
4654 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4655 *tokens += 1;
4656 }
4657
4658 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4659 {
4660 int32 u = (int32)(uptr - dptr->units);
4661 int32 toks = 0;
4662
4663 if (flag > 1)
4664 (void)fprintf (st, " %s%d\r\n", sim_dname (dptr), u);
4665 else if (flag < 0)
4666 (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4667 if (uptr->flags & UNIT_ATT) {
4668 fprint_sep (st, &toks);
4669 (void)fprintf (st, "status : attached to %s", uptr->filename);
4670 if (uptr->flags & UNIT_RO)
4671 (void)fprintf (st, ", read only");
4672 }
4673 else {
4674 if (uptr->flags & UNIT_ATTABLE) {
4675 fprint_sep (st, &toks);
4676 (void)fprintf (st, "status : not attached");
4677 }
4678 }
4679 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4680 fprint_sep (st, &toks);
4681 fprint_capac (st, dptr, uptr);
4682 }
4683 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4684 if (toks || (flag < 0) || (flag > 1))
4685 (void)fprintf (st, "\r\n");
4686 return SCPE_OK;
4687 }
4688
4689 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4690 {
4691 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4692 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4693 t_offset mval;
4694 t_offset psize = (t_offset)uptr->capac;
4695 char *scale, *width;
4696
4697 if (sim_switches & SWMASK ('B'))
4698 kval = 1024;
4699 mval = kval * kval;
4700 if (dptr->flags & DEV_SECTORS) {
4701 kval = kval / 512;
4702 mval = mval / 512;
4703 }
4704 if ((dptr->dwidth / dptr->aincr) > 8)
4705 width = "W";
4706 else
4707 width = "B";
4708 if ((psize < (kval * 10)) &&
4709 (0 != (psize % kval))) {
4710 scale = "";
4711 }
4712 else if ((psize < (mval * 10)) &&
4713 (0 != (psize % mval))){
4714 scale = "K";
4715 psize = psize / kval;
4716 }
4717 else {
4718 scale = "M";
4719 psize = psize / mval;
4720 }
4721 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4722 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4723 return capac_buf;
4724 }
4725
4726 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4727 {
4728 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4729 }
4730
4731
4732
4733 extern void print_default_base_system_script (void);
4734 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4735 {
4736 #if !defined(PERF_STRIP)
4737 print_default_base_system_script();
4738 #endif
4739 return 0;
4740 }
4741
4742 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4743 sim_printf (" %s ", label);
4744 sim_printf (" %2d %3o(8) '", length, offset);
4745 for (int l = 0; l < length; l ++)
4746 {
4747 unsigned int byte = PROM[offset + l];
4748 if (byte == 255)
4749 {
4750 byte = ' ';
4751 }
4752 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4753 }
4754 sim_printf ("'\r\n");
4755 }
4756
4757 static void strip_spaces(char* str) {
4758 int i, x;
4759 for (i=x=0; str[i]; ++i)
4760 {
4761 if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)])))
4762 {
4763 str[x++] = str[i];
4764 }
4765 }
4766 str[x] = '\0';
4767 i = -1;
4768 x = 0;
4769 while (str[x] != '\0')
4770 {
4771 if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4772 {
4773 i=x;
4774 }
4775 x++;
4776 }
4777 str[i+1] = '\0';
4778 }
4779
4780 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
4781 char sx[1024];
4782 sx[1023] = '\0';
4783 unsigned int lastbyte = 0;
4784 for (int l = 0; l < length; l ++)
4785 {
4786 unsigned int byte = PROM[offset + l];
4787 if (byte == 255)
4788 {
4789 byte = 20;
4790 }
4791 if ((lastbyte != 20) && (byte != 20))
4792 {
4793 (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4794 }
4795 lastbyte = byte;
4796 }
4797 strip_spaces(sx);
4798 (void)fprintf (st, "%s", sx);
4799 }
4800
4801 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4802 {
4803 unsigned char PROM[1024];
4804 setupPROM (0, PROM);
4805
4806 sim_printf (" PROM size: %llu bytes\r\n",
4807 (long long unsigned)sizeof(PROM));
4808 sim_printf (" PROM initialization data:\r\n\r\n");
4809
4810 sim_printf (" Field Description Length Offset Contents\r\n");
4811 sim_printf (" ========================= ======== ======== ==================================\r\n");
4812 sim_printf ("\r\n");
4813
4814
4815
4816 printp (PROM, "CPU Model ", 0, 11);
4817 printp (PROM, "CPU Serial ", 11, 11);
4818 printp (PROM, "Ship Date ", 22, 6);
4819 printp (PROM, "PROM Layout Version ", 60, 1);
4820 printp (PROM, "Release Git Commit Date ", 70, 10);
4821 printp (PROM, "Release Major ", 80, 3);
4822 printp (PROM, "Release Minor ", 83, 3);
4823 printp (PROM, "Release Patch ", 86, 3);
4824 printp (PROM, "Release Iteration ", 89, 3);
4825 printp (PROM, "Release Build Number ", 92, 8);
4826 printp (PROM, "Release Type ", 100, 1);
4827 printp (PROM, "Release Version Text ", 101, 29);
4828 printp (PROM, "Build Architecture ", 130, 20);
4829 printp (PROM, "Build Operating System ", 150, 20);
4830 printp (PROM, "Target Architecture ", 170, 20);
4831 printp (PROM, "Target Operating System ", 190, 20);
4832
4833 sim_printf("\r\n");
4834 return 0;
4835 }
4836
4837 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4838 {
4839 (void)fprintf (st, "\r Build Information:\r\n");
4840 #if defined(BUILDINFO_scp)
4841 (void)fprintf (st, "\r\n Compilation info: %s\r\n", BUILDINFO_scp );
4842 #else
4843 (void)fprintf (st, "\r\n Compilation info: Not available\r\n" );
4844 #endif
4845 #if !defined(__CYGWIN__)
4846 # if !defined(__APPLE__)
4847 # if !defined(_AIX)
4848 # if !defined(__MINGW32__)
4849 # if !defined(__MINGW64__)
4850 # if !defined(CROSS_MINGW32)
4851 # if !defined(CROSS_MINGW64)
4852 # if !defined(_WIN32)
4853 # if !defined(__HAIKU__)
4854 # if !defined(__QNX__)
4855 # if !defined(__FILC__)
4856 (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4857 if (dl_iterate_phdr_callback_called)
4858 (void)fprintf (st, "\r\n");
4859 dl_iterate_phdr_callback_called = 0;
4860 # endif
4861 # endif
4862 # endif
4863 # endif
4864 # endif
4865 # endif
4866 # endif
4867 # endif
4868 # endif
4869 # endif
4870 #endif
4871 #if defined(UV_VERSION_MAJOR) && \
4872 defined(UV_VERSION_MINOR) && \
4873 defined(UV_VERSION_PATCH)
4874 # if defined(UV_VERSION_MAJOR)
4875 # if !defined(UV_VERSION_MINOR) && \
4876 !defined(UV_VERSION_PATCH) && \
4877 !defined(UV_VERSION_SUFFIX)
4878 (void)fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4879 # endif
4880 # if defined(UV_VERSION_MINOR)
4881 # if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4882 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4883 UV_VERSION_MINOR);
4884 # endif
4885 # if defined(UV_VERSION_PATCH)
4886 # if !defined(UV_VERSION_SUFFIX)
4887 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4888 UV_VERSION_MINOR, UV_VERSION_PATCH);
4889 # endif
4890 # if defined(UV_VERSION_SUFFIX)
4891 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4892 UV_VERSION_MINOR, UV_VERSION_PATCH);
4893 # if defined(UV_VERSION_IS_RELEASE)
4894 # if UV_VERSION_IS_RELEASE == 1
4895 # define UV_RELEASE_TYPE " (release)"
4896 # endif
4897 # if UV_VERSION_IS_RELEASE == 0
4898 # define UV_RELEASE_TYPE "-dev"
4899 # endif
4900 # if !defined(UV_RELEASE_TYPE)
4901 # define UV_RELEASE_TYPE ""
4902 # endif
4903 # if defined(UV_RELEASE_TYPE)
4904 (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4905 # endif
4906 # endif
4907 # endif
4908 # endif
4909 # endif
4910 unsigned int CurrentUvVersion = uv_version();
4911 if (CurrentUvVersion > 0)
4912 if (uv_version_string() != NULL)
4913 (void)fprintf (st, "; %s in use", uv_version_string());
4914 # endif
4915 #else
4916 (void)fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4917 #endif
4918
4919
4920
4921 (void)fprintf (st, "\r\n Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4922 SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4923 SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4924 sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4925 #if defined(DECNUMBERLOC)
4926 # if defined(DECVERSION)
4927 # if defined(DECVERSEXT)
4928 (void)fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4929 # else
4930 # if defined(DECNLAUTHOR)
4931 (void)fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4932 # else
4933 (void)fprintf (st, "\r\n Math library: %s", DECVERSION);
4934 # endif
4935 # endif
4936 # else
4937 (void)fprintf (st, "\r\n Math library: decNumber, unknown version");
4938 # endif
4939 #endif
4940 #if defined(LOCKLESS)
4941 (void)fprintf (st, "\r\n Atomic operations: ");
4942 # if defined(AIX_ATOMICS)
4943 (void)fprintf (st, "C11 and IBM AIX-style");
4944 # elif defined(BSD_ATOMICS)
4945 (void)fprintf (st, "C11 and FreeBSD-style");
4946 # elif defined(GNU_ATOMICS)
4947 (void)fprintf (st, "C11 and GNU-style");
4948 # elif defined(SYNC_ATOMICS)
4949 (void)fprintf (st, "C11 and GNU sync-style");
4950 # elif defined(ISO_ATOMICS)
4951 (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4952 # elif defined(NT_ATOMICS)
4953 (void)fprintf (st, "C11 and Windows NT interlocked operations");
4954 # endif
4955 #endif
4956 (void)fprintf (st, "\r\n File locking: ");
4957 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4958 (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4959 #endif
4960 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4961 (void)fprintf (st, "POSIX-style fcntl() locking");
4962 #endif
4963 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4964 (void)fprintf (st, "BSD-style flock() locking");
4965 #endif
4966 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4967 (void)fprintf (st, "No file locking available");
4968 #endif
4969 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
4970 (void)fprintf (st, "\r\n Windows support: ");
4971 #endif
4972 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4973 # if defined(__MINGW64_VERSION_STR)
4974 (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4975 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4976 (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4977 # else
4978 (void)fprintf (st, "Built with MinGW");
4979 # endif
4980
4981 # if defined(MINGW_CRT)
4982 (void)fprintf (st, "; %s", MINGW_CRT);
4983 # if !defined(_UCRT)
4984 # if defined(__MSVCRT_VERSION__)
4985 # if __MSVCRT_VERSION__ > 0x00
4986 (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4987 # endif
4988 # endif
4989 # else
4990
4991 struct UCRTVersion ucrtversion;
4992 int result = GetUCRTVersion (&ucrtversion);
4993
4994 if (result == 0)
4995 (void)fprintf (st, " %u.%u.%u.%u",
4996 ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4997 ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4998 # endif
4999 (void)fprintf (st, " in use");
5000 # endif
5001 #elif defined(__CYGWIN__)
5002 struct utsname utsname;
5003 (void)fprintf (st, "Built with Cygwin %d.%d.%d",
5004 CYGWIN_VERSION_DLL_MAJOR / 1000,
5005 CYGWIN_VERSION_DLL_MAJOR % 1000,
5006 CYGWIN_VERSION_DLL_MINOR);
5007 if (uname(&utsname) == 0)
5008 fprintf (st, "; %s in use", utsname.release);
5009 #endif
5010
5011 (void)fprintf (st, "\r\n");
5012 return 0;
5013 }
5014
5015 static void
5016 removehex(char *s)
5017 {
5018 if (!s) return;
5019
5020 size_t len = strlen(s);
5021 for (size_t i = 0; i < len; i++) {
5022 if (s[i] != ' ')
5023 continue;
5024
5025 if ((len - i) < 41)
5026 continue;
5027
5028 size_t j;
5029 for (j = 1; j <= 40; j++) {
5030 unsigned char uc = (unsigned char)s[i + j];
5031 if (!isxdigit(uc))
5032 break;
5033 }
5034
5035 if (j == 41) {
5036 memmove(&s[i], &s[i + 41], strlen(&s[i + 41]) + 1);
5037 return;
5038 }
5039 }
5040 }
5041
5042 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5043 {
5044 const char *arch = "";
5045 char *whydirty = " ";
5046 int dirty = 0;
5047
5048 if (cptr && (*cptr != 0))
5049 return SCPE_2MARG;
5050 if (flag) {
5051 (void)fprintf (st, " %s Simulator:", sim_name);
5052 #if defined(USE_DUMA)
5053 # undef NO_SUPPORT_VERSION
5054 # define NO_SUPPORT_VERSION 1
5055 nodist++;
5056 #endif
5057 #if defined(NO_SUPPORT_VERSION) || \
5058 defined(WITH_SOCKET_DEV) || \
5059 defined(WITH_ABSI_DEV) || \
5060 defined(WITH_MGP_DEV) || \
5061 defined(TESTING) || \
5062 defined(ISOLTS) || \
5063 defined(USE_DUMA)
5064 # if !defined(NO_SUPPORT_VERSION)
5065 # define NO_SUPPORT_VERSION 1
5066 # endif
5067 #endif
5068 #if defined(NO_SUPPORT_VERSION)
5069 dirty++;
5070 #endif
5071 #if defined(GENERATED_MAKE_VER_H)
5072 # if defined(VER_H_GIT_VERSION)
5073
5074
5075 if (strstr(VER_H_GIT_VERSION, "*"))
5076 {
5077 dirty++;
5078 }
5079
5080
5081 if ((strstr(VER_H_GIT_VERSION, "X")) || \
5082 (strstr(VER_H_GIT_VERSION, "D")) || \
5083 (strstr(VER_H_GIT_VERSION, "A")) || \
5084 (strstr(VER_H_GIT_VERSION, "B")))
5085 {
5086 dirty++;
5087 }
5088
5089
5090 if (dirty)
5091 {
5092 if ((strstr(VER_H_GIT_VERSION, "X")))
5093 {
5094 whydirty = " ";
5095 }
5096 else if ((strstr(VER_H_GIT_VERSION, "D")))
5097 {
5098 whydirty = " DEV ";
5099 }
5100 else if ((strstr(VER_H_GIT_VERSION, "A")))
5101 {
5102 whydirty = " ALPHA ";
5103 }
5104 else if ((strstr(VER_H_GIT_VERSION, "B")))
5105 {
5106 whydirty = " BETA ";
5107 }
5108 }
5109
5110 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5111 # if defined(VER_H_GIT_HASH)
5112 # if VER_H_GIT_PATCH_INT < 1
5113 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5114 VER_H_GIT_VERSION,
5115 (long)(CHAR_BIT*sizeof(void *)),
5116 VER_H_GIT_HASH);
5117 # else
5118 # define NO_SUPPORT_VERSION 1
5119 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)\r\n Commit: %s",
5120 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5121 (long)(CHAR_BIT*sizeof(void *)),
5122 VER_H_GIT_HASH);
5123 # endif
5124 # else
5125 # if VER_H_GIT_PATCH_INT < 1
5126 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5127 VER_H_GIT_VERSION,
5128 (long)(CHAR_BIT*sizeof(void *)));
5129 # else
5130 # define NO_SUPPORT_VERSION 1
5131 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)",
5132 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5133 (long)(CHAR_BIT*sizeof(void *)));
5134 # endif
5135 # endif
5136 # else
5137 # if defined(VER_H_GIT_HASH)
5138 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5139 VER_H_GIT_VERSION,
5140 (long)(CHAR_BIT*sizeof(void *)),
5141 VER_H_GIT_HASH);
5142 # else
5143 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5144 VER_H_GIT_VERSION,
5145 (long)(CHAR_BIT*sizeof(void *)));
5146 # endif
5147 # endif
5148 # endif
5149 #endif
5150
5151
5152 #if defined(TESTING)
5153 (void)fprintf (st, "\r\n Options: ");
5154 # if !defined(HAVE_DPSOPT)
5155 # define HAVE_DPSOPT 1
5156 # endif
5157 (void)fprintf (st, "TESTING");
5158 #endif
5159
5160
5161 #if defined(ISOLTS)
5162 # if defined(HAVE_DPSOPT)
5163 (void)fprintf (st, ", ");
5164 # else
5165 (void)fprintf (st, "\r\n Options: ");
5166 # endif
5167 # if !defined(HAVE_DPSOPT)
5168 # define HAVE_DPSOPT 1
5169 # endif
5170 (void)fprintf (st, "ISOLTS");
5171 #endif
5172
5173
5174 #if defined(NEED_128)
5175 # if defined(HAVE_DPSOPT)
5176 (void)fprintf (st, ", ");
5177 # else
5178 (void)fprintf (st, "\r\n Options: ");
5179 # endif
5180 # if !defined(HAVE_DPSOPT)
5181 # define HAVE_DPSOPT 1
5182 # endif
5183 (void)fprintf (st, "NEED_128");
5184 #endif
5185
5186
5187 #if !defined(LOCKLESS)
5188 # if defined(HAVE_DPSOPT)
5189 (void)fprintf (st, ", ");
5190 # else
5191 (void)fprintf (st, "\r\n Options: ");
5192 # endif
5193 # if !defined(HAVE_DPSOPT)
5194 # define HAVE_DPSOPT 1
5195 # endif
5196 (void)fprintf (st, "NO_LOCKLESS");
5197 #endif
5198
5199
5200 #if defined(PANEL68)
5201 # if defined(HAVE_DPSOPT)
5202 (void)fprintf (st, ", ");
5203 # else
5204 (void)fprintf (st, "\r\n Options: ");
5205 # endif
5206 # if !defined(HAVE_DPSOPT)
5207 # define HAVE_DPSOPT 1
5208 # endif
5209 (void)fprintf (st, "PANEL68");
5210 #endif
5211
5212
5213 #if defined(WITH_ABSI_DEV)
5214 # if defined(HAVE_DPSOPT)
5215 (void)fprintf (st, ", ");
5216 # else
5217 (void)fprintf (st, "\r\n Options: ");
5218 # endif
5219 # if !defined(HAVE_DPSOPT)
5220 # define HAVE_DPSOPT 1
5221 # endif
5222 (void)fprintf (st, "ABSI");
5223 #endif
5224
5225
5226 #if defined(WITH_SOCKET_DEV)
5227 # if defined(HAVE_DPSOPT)
5228 (void)fprintf (st, ", ");
5229 # else
5230 (void)fprintf (st, "\r\n Options: ");
5231 # endif
5232 # if !defined(HAVE_DPSOPT)
5233 # define HAVE_DPSOPT 1
5234 # endif
5235 (void)fprintf (st, "SOCKET");
5236 #endif
5237
5238
5239 #if defined(WITH_MGP_DEV)
5240 # if defined(HAVE_DPSOPT)
5241 (void)fprintf (st, ", ");
5242 # else
5243 (void)fprintf (st, "\r\n Options: ");
5244 # endif
5245 # if !defined(HAVE_DPSOPT)
5246 # define HAVE_DPSOPT 1
5247 # endif
5248 (void)fprintf (st, "CHAOSNET");
5249 # if USE_SOCKET_DEV_APPROACH
5250 (void)fprintf (st, "-S");
5251 # endif
5252 #endif
5253
5254
5255 #if defined(USE_DUMA)
5256 # if defined(HAVE_DPSOPT)
5257 (void)fprintf (st, ", ");
5258 # else
5259 (void)fprintf (st, "\r\n Options: ");
5260 # endif
5261 # if !defined(HAVE_DPSOPT)
5262 # define HAVE_DPSOPT 1
5263 # endif
5264 (void)fprintf (st, "DUMA");
5265 #endif
5266
5267 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5268 # if defined(NO_SUPPORT_VERSION)
5269 (void)fprintf (st, "\r\n Modified: %s", VER_H_GIT_DATE);
5270 # else
5271 (void)fprintf (st, "\r\n Released: %s", VER_H_GIT_DATE);
5272 # endif
5273 #endif
5274 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5275 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5276 #endif
5277 #if defined(VER_CURRENT_TIME)
5278 (void)fprintf (st, "\r\n Compiled: %s", VER_CURRENT_TIME);
5279 #endif
5280 if (dirty)
5281 {
5282 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5283 }
5284 (void)fprintf (st, "\r\n\r\n Build Information:");
5285 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5286 char build_os_version_raw[255];
5287 char build_os_arch_raw[255];
5288 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5289 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5290 char *build_os_version = strdup(build_os_version_raw);
5291 if (!build_os_version)
5292 {
5293 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5294 __func__, __FILE__, __LINE__);
5295 # if defined(USE_BACKTRACE)
5296 # if defined(SIGUSR2)
5297 (void)raise(SIGUSR2);
5298
5299 # endif
5300 # endif
5301 abort();
5302 }
5303 char *build_os_arch = strdup(build_os_arch_raw);
5304 if (!build_os_arch)
5305 {
5306 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5307 __func__, __FILE__, __LINE__);
5308 # if defined(USE_BACKTRACE)
5309 # if defined(SIGUSR2)
5310 (void)raise(SIGUSR2);
5311
5312 # endif
5313 # endif
5314 abort();
5315 }
5316 unsigned char SPROM[1024];
5317 setupPROM (0, SPROM);
5318 (void)fprintf (st, "\r\n Target: ");
5319 printpq (SPROM, st, 190, 20);
5320 if (SPROM[170] != 20)
5321 {
5322 if (SPROM[170] != 255)
5323 {
5324 (void)fprintf (st, " on ");
5325 printpq (SPROM, st, 170, 20);
5326 }
5327 }
5328 strtrimspace(build_os_version, build_os_version_raw);
5329 strtrimspace(build_os_arch, build_os_arch_raw);
5330 (void)fprintf (st, "\r\n Build OS: %s %s", build_os_version, build_os_arch);
5331 FREE(build_os_version);
5332 FREE(build_os_arch);
5333 #endif
5334 #if defined(__VERSION__)
5335 char gnumver[2];
5336 char postver[1024];
5337 (void)sprintf(gnumver, "%.1s", __VERSION__);
5338 (void)sprintf(postver, "%.1023s", __VERSION__);
5339 strremove(postver, "(TM)");
5340 strremove(postver, "(R)");
5341 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5342 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5343 strremove(postver, " gcc 4.9 mode");
5344 strremove(postver, "4.2.1 Compatible ");
5345 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5346 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5347 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5348 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5349 strremove(postver, "(experimental) ");
5350 strremove(postver, ".module+el8.7.0+20823+214a699d");
5351 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5352 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5353 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5354 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5355 strremove(postver, "llvmorg-16.0.6-0-");
5356 strremove(postver, " Clang 15.0.0 (build 760095e)");
5357 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5358 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5359 strremove(postver, " Clang 15.0.0 (build 232543c)");
5360 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5361 strremove(postver, "CLANG: ");
5362 removehex(postver);
5363 strremove(postver, " (git@github.com:pizlonator/llvm-project-deluge.git)");
5364 #endif
5365 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5366 # if !defined(__clang_version__)
5367 if (isdigit((unsigned char)gnumver[0])) {
5368 (void)fprintf (st, "\r\n Compiler: GCC %s", postver);
5369 } else {
5370 (void)fprintf (st, "\r\n Compiler: %s", postver);
5371 }
5372 # endif
5373 # if defined(__clang_analyzer__ )
5374 (void)fprintf (st, "\r\n Compiler: Clang C/C++ Static Analyzer");
5375 # elif defined(__clang_version__) && defined(__VERSION__)
5376 char clangllvmver[1024];
5377 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5378 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5379 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5380 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5381 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5382 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5383 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5384 strremove(clangllvmver, " ( )");
5385 strremove(clangllvmver, " ()");
5386 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5387 (void)fprintf (st, "\r\n Compiler: Clang %s", clangllvmver);
5388 } else {
5389 (void)fprintf (st, "\r\n Compiler: %s", postver);
5390 }
5391 # elif defined(__clang_version__)
5392 (void)fprintf (st, "\r\n Compiler: %s", postver);
5393 # endif
5394 #elif defined(__PGI) && !defined(__NVCOMPILER)
5395 (void)fprintf (st, "\r\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5396 # if defined(__PGIC__)
5397 (void)fprintf (st, "%d", __PGIC__);
5398 # if defined(__PGIC_MINOR__)
5399 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5400 # if defined(__PGIC_PATCHLEVEL__)
5401 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5402 # endif
5403 # endif
5404 # endif
5405 #elif defined(__NVCOMPILER)
5406 (void)fprintf (st, "\r\n Compiler: NVIDIA HPC SDK C Compiler ");
5407 # if defined(__NVCOMPILER_MAJOR__)
5408 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5409 # if defined(__NVCOMPILER_MINOR__)
5410 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5411 # if defined(__NVCOMPILER_PATCHLEVEL__)
5412 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5413 # endif
5414 # endif
5415 # endif
5416 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5417 (void)fprintf (st, "\r\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5418 _MSC_FULL_VER/10000000,
5419 (_MSC_FULL_VER/100000)%100,
5420 _MSC_FULL_VER%100000,
5421 _MSC_BUILD);
5422 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5423 # if defined(_AIX) && defined(__PASE__)
5424 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5425 # endif
5426 # if defined(_AIX) && !defined(__PASE__)
5427 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5428 # endif
5429 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5430 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5431 # endif
5432 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5433 # if defined(__PPC__) && defined(__APPLE__)
5434 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5435 # else
5436 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s", __xlc__);
5437 # endif
5438 # endif
5439 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5440 # define VER_ENC(maj, min, rev) \
5441 (((maj) * 1000000) + ((min) * 1000) + (rev))
5442 # define VER_DEC_MAJ(ver) \
5443 ((ver) / 1000000)
5444 # define VER_DEC_MIN(ver) \
5445 (((ver) % 1000000) / 1000)
5446 # define VER_DEC_REV(ver) \
5447 ((ver) % 1000)
5448 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5449 # define COMP_VER VER_ENC( \
5450 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5451 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5452 (__SUNPRO_C & 0xf) * 10)
5453 # elif defined(__SUNPRO_C)
5454 # define COMP_VER VER_ENC( \
5455 (__SUNPRO_C >> 8) & 0xf, \
5456 (__SUNPRO_C >> 4) & 0xf, \
5457 (__SUNPRO_C) & 0xf)
5458 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5459 # define COMP_VER VER_ENC( \
5460 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5461 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5462 (__SUNPRO_CC & 0xf) * 10)
5463 # elif defined(__SUNPRO_CC)
5464 # define COMP_VER VER_ENC( \
5465 (__SUNPRO_CC >> 8) & 0xf, \
5466 (__SUNPRO_CC >> 4) & 0xf, \
5467 (__SUNPRO_CC) & 0xf)
5468 # endif
5469 # if !defined(COMP_VER)
5470 # define COMP_VER 0
5471 # endif
5472 (void)fprintf (st, "\r\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5473 VER_DEC_MAJ(COMP_VER),
5474 VER_DEC_MIN(COMP_VER),
5475 VER_DEC_REV(COMP_VER));
5476 #elif defined(__DMC__)
5477 (void)fprintf (st, "\r\n Compiler: Digital Mars C/C++");
5478 #elif defined(__PCC__)
5479 (void)fprintf (st, "\r\n Compiler: Portable C Compiler");
5480 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5481 (void)fprintf (st, "\r\n Compiler: Plan 9 Compiler Suite");
5482 #elif defined(__ACK__)
5483 (void)fprintf (st, "\r\n Compiler: Amsterdam Compiler Kit");
5484 #elif defined(__COMO__)
5485 (void)fprintf (st, "\r\n Compiler: Comeau C++");
5486 #elif defined(__COMPCERT__)
5487 (void)fprintf (st, "\r\n Compiler: CompCert C");
5488 #elif defined(__COVERITY__)
5489 (void)fprintf (st, "\r\n Compiler: Coverity C/C++ Static Analyzer");
5490 #elif defined(__LCC__)
5491 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5492 (void)fprintf (st, "\r\n Compiler: MCST Elbrus C Compiler");
5493 # if __LCC__ > 99
5494 (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5495 # if defined(__LCC_MINOR__)
5496 # if __LCC_MINOR__ > 0
5497 (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5498 # endif
5499 # endif
5500 # endif
5501 # if defined(__EDG__) && defined(__EDG_VERSION__)
5502 # if __EDG_VERSION__ > 99
5503 (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5504 (int)(((__EDG_VERSION__) % 100) % 10));
5505 # endif
5506 # endif
5507 # else
5508 (void)fprintf (st, "\r\n Compiler: Local/Little C Compiler (lcc)");
5509 # endif
5510 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5511 (void)fprintf (st, "\r\n Compiler: SGI MIPSpro");
5512 #elif defined(__OPEN64__)
5513 (void)fprintf (st, "\r\n Compiler: Open64 %s", __OPEN64__);
5514 #elif defined(__PGI) || defined(__PGIC__)
5515 (void)fprintf (st, "\r\n Compiler: Portland Group/PGI C/C++");
5516 #elif defined(__VBCC__)
5517 (void)fprintf (st, "\r\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5518 #elif defined(__WATCOMC__)
5519 (void)fprintf (st, "\r\n Compiler: Watcom C/C++ %d.%d",
5520 __WATCOMC__ / 100,
5521 __WATCOMC__ % 100);
5522 #elif defined(__xlC__)
5523 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++");
5524 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5525 # if defined(__INTEL_COMPILER_UPDATE)
5526 # if defined(__INTEL_COMPILER_BUILD_DATE)
5527 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d (%d)",
5528 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5529 __INTEL_COMPILER_BUILD_DATE);
5530 # else
5531 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d",
5532 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5533 # endif
5534 # else
5535 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d",
5536 __INTEL_COMPILER);
5537 # endif
5538 #elif defined(SIM_COMPILER)
5539 # define S_xstr(a) S_str(a)
5540 # define S_str(a) #a
5541 (void)fprintf (st, "\r\n Compiler: %s", S_xstr(SIM_COMPILER));
5542 # undef S_str
5543 # undef S_xstr
5544 #else
5545 (void)fprintf (st, "\r\n Compiler: Unknown");
5546 #endif
5547
5548 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5549 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5550 # define SC_IS_PPC64 1
5551 #else
5552 # define SC_IS_PPC64 0
5553 #endif
5554
5555 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5556 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5557 defined(__PPC32)
5558 # define SC_IS_PPC32 1
5559 #else
5560 # define SC_IS_PPC32 0
5561 #endif
5562
5563 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5564 arch = " x86_64";
5565 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5566 arch = " x86";
5567 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5568 arch = " arm64";
5569 #elif defined(_M_ARM) || defined(__arm__)
5570 arch = " arm";
5571 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5572 arch = " ia64";
5573 #elif SC_IS_PPC64
5574 arch = " powerpc64";
5575 #elif SC_IS_PPC32
5576 arch = " powerpc";
5577 #elif defined(__s390x__)
5578 arch = " s390x";
5579 #elif defined(__s390__)
5580 arch = " s390";
5581 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5582 arch = " j2";
5583 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5584 arch = " sh4";
5585 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5586 arch = " sh2";
5587 #elif defined(__alpha__)
5588 arch = " alpha";
5589 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5590 arch = " hppa";
5591 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5592 arch = " ice9";
5593 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5594 arch = " mips64";
5595 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5596 arch = " mips";
5597 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5598 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5599 arch = " openrisc";
5600 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5601 arch = " sparc64";
5602 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5603 arch = " sparc";
5604 #elif defined(__riscv) || defined(__riscv__)
5605 arch = " riscv";
5606 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5607 arch = " e2k";
5608 #elif defined(__myriad2__)
5609 arch = " myriad2";
5610 #elif defined(__loongarch64) || defined(__loongarch__)
5611 arch = " loongarch";
5612 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5613 arch = " m68k";
5614 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5615 arch = " m88k";
5616 #elif defined(__VAX__) || defined(__vax__)
5617 arch = " vax";
5618 #elif defined(__NIOS2__) || defined(__nios2__)
5619 arch = " nios2";
5620 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5621 arch = " microblaze";
5622 #else
5623 arch = " ";
5624 #endif
5625 (void)fprintf (st, "%s", arch);
5626 #if defined(BUILD_BY_USER)
5627 (void)fprintf (st, "\r\n Built by: %s", BUILD_BY_USER);
5628 #else
5629 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5630 (void)fprintf (st, "\r\n Built by: %s", VER_H_PREP_USER);
5631 # endif
5632 #endif
5633 (void)fprintf (st, "\r\n\r\n Host System Information:");
5634 #if defined(_WIN32)
5635 if (1) {
5636 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5637 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5638 char osversion[PATH_MAX+1] = "";
5639 FILE *f;
5640
5641 if ((f = _popen ("ver", "r"))) {
5642 (void)memset (osversion, 0, sizeof(osversion));
5643 do {
5644 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5645 break;
5646 sim_trim_endspc (osversion);
5647 } while (osversion[0] == '\0');
5648 _pclose (f);
5649 }
5650 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5651 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5652 }
5653 #else
5654 if (1) {
5655 char osversion[2*PATH_MAX+1] = "";
5656 FILE *f;
5657 # if !defined(_AIX)
5658 if ((f = popen \
5659 ("uname -mrs 2> /dev/null", "r"))) {
5660 # else
5661 if ((f = popen \
5662 ("sh -c 'echo \"$(command -p env uname -v \
5663 2> /dev/null).$(command -p env uname -r \
5664 2> /dev/null) $(command -p env uname -p \
5665 2> /dev/null)\"' 2> /dev/null", "r"))) {
5666 # endif
5667 (void)memset (osversion, 0, sizeof(osversion));
5668 do {
5669 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5670 break;
5671 }
5672 sim_trim_endspc (osversion);
5673 } while (osversion[0] == '\0');
5674 pclose (f);
5675 strremove(osversion, "0000000000000000 ");
5676 strremove(osversion, " 0000000000000000");
5677 strremove(osversion, "000000000000 ");
5678 strremove(osversion, " 000000000000");
5679 strremove(osversion, "IBM ");
5680 strremove(osversion, " (emulated by qemu)");
5681 strremove(osversion, " (emulated by QEMU)");
5682 }
5683 # if !defined(_AIX)
5684 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5685 # else
5686 strremove(osversion, "AIX ");
5687 # if !defined(__PASE__)
5688 (void)fprintf (st, "\r\n Host OS: IBM AIX %s", osversion);
5689 # else
5690 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE) %s", osversion);
5691 # endif
5692 # endif
5693 } else {
5694 # if !defined(_AIX)
5695 (void)fprintf (st, "\r\n Host OS: Unknown");
5696 # else
5697 # if !defined(__PASE__)
5698 (void)fprintf (st, "\r\n Host OS: IBM AIX");
5699 # else
5700 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE)");
5701 # endif
5702 # endif
5703 }
5704 #endif
5705 if (nodist)
5706 {
5707 sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5708 }
5709 else
5710 {
5711 (void)fprintf (st, "\r\n");
5712 (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5713 (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5714 (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5715 }
5716 (void)fprintf (st, "\r\n");
5717 }
5718 return SCPE_OK;
5719 }
5720
5721 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5722 {
5723 size_t i;
5724 DEVICE *dptr;
5725 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5726
5727 if (cptr && (*cptr != 0))
5728 return SCPE_2MARG;
5729 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5730 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5731 if (!only_enabled || !qdisable (dptr))
5732 show_device (st, dptr, flag);
5733 return SCPE_OK;
5734 }
5735
5736 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5737 {
5738 int32 i;
5739 DEVICE *dptr;
5740
5741 if (cptr && (*cptr != 0))
5742 return SCPE_2MARG;
5743 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5744 show_dev_logicals (st, dptr, NULL, 1, cptr);
5745 return SCPE_OK;
5746 }
5747
5748 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5749 {
5750 if (dptr->lname)
5751 (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5752 else if (!flag)
5753 fputs ("no logical name assigned\r\n", st);
5754 return SCPE_OK;
5755 }
5756
5757 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5758 {
5759 DEVICE *dptr;
5760 UNIT *uptr;
5761 int32 accum;
5762
5763 if (cptr && (*cptr != 0))
5764 return SCPE_2MARG;
5765 if (sim_clock_queue == QUEUE_LIST_END)
5766 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5767 sim_name, sim_time, sim_timer_inst_per_sec ());
5768 else {
5769 const char *tim;
5770
5771 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5772 sim_name, sim_time, sim_timer_inst_per_sec ());
5773 accum = 0;
5774 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5775 if (uptr == &sim_step_unit)
5776 (void)fprintf (st, " Step timer");
5777 else
5778 if (uptr == &sim_expect_unit)
5779 (void)fprintf (st, " Expect fired");
5780 else
5781 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5782 (void)fprintf (st, " %s", sim_dname (dptr));
5783 if (dptr->numunits > 1)
5784 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5785 }
5786 else
5787 (void)fprintf (st, " Unknown");
5788 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5789 (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5790 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5791 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5792 accum = accum + uptr->time;
5793 }
5794 }
5795 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5796 return SCPE_OK;
5797 }
5798
5799 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5800 {
5801 if (cptr && (*cptr != 0))
5802 return SCPE_2MARG;
5803 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5804 return SCPE_OK;
5805 }
5806
5807 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5808 {
5809 t_stat r;
5810
5811 if (cptr && (*cptr != 0))
5812 r = ssh_break (st, cptr, 1);
5813 else
5814 r = sim_brk_showall (st, (uint32)sim_switches);
5815 return r;
5816 }
5817
5818 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5819 {
5820 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5821 return SCPE_OK;
5822 }
5823
5824 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5825 {
5826 int32 any = 0;
5827 DEBTAB *dep;
5828
5829 if (dptr->flags & DEV_DEBUG) {
5830 if (dptr->dctrl == 0)
5831 fputs ("Debugging disabled", st);
5832 else if (dptr->debflags == NULL)
5833 fputs ("Debugging enabled", st);
5834 else {
5835 uint32 dctrl = dptr->dctrl;
5836
5837 fputs ("Debug=", st);
5838 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5839 if ((dctrl & dep->mask) == dep->mask) {
5840 dctrl &= ~dep->mask;
5841 if (any)
5842 fputc (';', st);
5843 fputs (dep->name, st);
5844 any = 1;
5845 }
5846 }
5847 }
5848 fputc ('\n', st);
5849 return SCPE_OK;
5850 }
5851 else return SCPE_NOFNC;
5852 }
5853
5854
5855
5856 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5857 {
5858 int32 lvl, i;
5859
5860 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5861 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5862 if (lvl > 0)
5863 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5864 else
5865 (void)fprintf(st, "On Processing for input commands");
5866 (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5867 for (i=1; i<SCPE_BASE; ++i) {
5868 if (sim_on_actions[lvl][i])
5869 (void)fprintf(st, " on %5d %s\r\n", i, sim_on_actions[lvl][i]); }
5870 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5871 if (sim_on_actions[lvl][i])
5872 (void)fprintf(st, " on %-5s %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5873 if (sim_on_actions[lvl][0])
5874 (void)fprintf(st, " on ERROR %s\r\n", sim_on_actions[lvl][0]);
5875 (void)fprintf(st, "\r\n");
5876 }
5877 if (sim_on_inherit)
5878 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5879 return SCPE_OK;
5880 }
5881
5882
5883
5884 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5885 {
5886 int32 i;
5887 DEVICE *dptr;
5888
5889 if (cptr && (*cptr != 0))
5890 return SCPE_2MARG;
5891 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5892 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5893 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5894 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5895 return SCPE_OK;
5896 }
5897
5898 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5899 {
5900 fprint_set_help (st, dptr);
5901 return SCPE_OK;
5902 }
5903
5904 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5905 {
5906 MTAB *mptr;
5907 t_stat r = SCPE_OK;
5908
5909 if (dptr->modifiers == NULL)
5910 return SCPE_OK;
5911 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5912 if (mptr->pstring &&
5913 ((mptr->mask & MTAB_XTD)?
5914 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5915 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5916 if (*toks > 0) {
5917 (void)fprintf (st, "\r\n");
5918 *toks = 0;
5919 }
5920 if (r == SCPE_OK)
5921 fprint_sep (st, toks);
5922 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5923 }
5924 }
5925 return SCPE_OK;
5926 }
5927
5928 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5929 CONST char *cptr, int32 flag)
5930 {
5931 t_stat r = SCPE_OK;
5932
5933 if (mptr->disp)
5934 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5935 else
5936 fputs (mptr->pstring, st);
5937 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5938 fputc ('\n', st);
5939 return r;
5940 }
5941
5942
5943
5944 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5945 {
5946 int32 i;
5947 DEVICE *dptr;
5948
5949 if (cptr && (*cptr != 0))
5950 return SCPE_2MARG;
5951 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5952 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5953 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5954 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5955 return SCPE_OK;
5956 }
5957
5958 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5959 {
5960 fprint_show_help (st, dptr);
5961 return SCPE_OK;
5962 }
5963
5964
5965
5966 t_stat brk_cmd (int32 flg, CONST char *cptr)
5967 {
5968 GET_SWITCHES (cptr);
5969 return ssh_break (NULL, cptr, flg);
5970 }
5971
5972 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
5973 {
5974 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5975 CONST char *tptr, *t1ptr;
5976 DEVICE *dptr = sim_dflt_dev;
5977 UNIT *uptr;
5978 t_stat r;
5979 t_addr lo, hi, max;
5980 int32 cnt;
5981
5982 if (sim_brk_types == 0)
5983 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
5984 if (dptr == NULL)
5985 return SCPE_IERR;
5986 uptr = dptr->units;
5987 if (uptr == NULL)
5988 return SCPE_IERR;
5989 max = uptr->capac - 1;
5990 abuf[sizeof(abuf)-1] = '\0';
5991 strncpy (abuf, cptr, sizeof(abuf)-1);
5992 cptr = abuf;
5993 if ((aptr = strchr (abuf, ';'))) {
5994 if (flg != SSH_ST)
5995 return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
5996 *aptr++ = 0;
5997 }
5998 if (*cptr == 0) {
5999 lo = (t_addr) get_rval (sim_PC, 0);
6000 return ssh_break_one (st, flg, lo, 0, aptr);
6001 }
6002 while (*cptr) {
6003 cptr = get_glyph (cptr, gbuf, ',');
6004 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
6005 if (tptr == NULL)
6006 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
6007 if (*tptr == '[') {
6008 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
6009 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
6010 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
6011 tptr = t1ptr + 1;
6012 }
6013 else cnt = 0;
6014 if (*tptr != 0)
6015 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
6016 if ((lo == 0) && (hi == max)) {
6017 if (flg == SSH_CL)
6018 sim_brk_clrall (sim_switches);
6019 else
6020 if (flg == SSH_SH)
6021 sim_brk_showall (st, (uint32)sim_switches);
6022 else
6023 return SCPE_ARG;
6024 }
6025 else {
6026 for ( ; lo <= hi; lo = lo + 1) {
6027 r = ssh_break_one (st, flg, lo, cnt, aptr);
6028 if (r != SCPE_OK)
6029 return r;
6030 }
6031 }
6032 }
6033 return SCPE_OK;
6034 }
6035
6036 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
6037 {
6038 if (!sim_brk_types)
6039 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6040 switch (flg) {
6041 case SSH_ST:
6042 return sim_brk_set (lo, sim_switches, cnt, aptr);
6043
6044 break;
6045
6046 case SSH_CL:
6047 return sim_brk_clr (lo, sim_switches);
6048
6049 break;
6050
6051 case SSH_SH:
6052 return sim_brk_show (st, lo, sim_switches);
6053
6054 break;
6055
6056 default:
6057 return SCPE_ARG;
6058 }
6059 }
6060
6061
6062
6063 static t_bool run_cmd_did_reset = FALSE;
6064
6065 t_stat reset_cmd (int32 flag, CONST char *cptr)
6066 {
6067 char gbuf[CBUFSIZE];
6068 DEVICE *dptr;
6069
6070 GET_SWITCHES (cptr);
6071 run_cmd_did_reset = FALSE;
6072 if (*cptr == 0)
6073 return (reset_all (0));
6074 cptr = get_glyph (cptr, gbuf, 0);
6075 if (*cptr != 0)
6076 return SCPE_2MARG;
6077 if (strcmp (gbuf, "ALL") == 0)
6078 return (reset_all (0));
6079 dptr = find_dev (gbuf);
6080 if (dptr == NULL)
6081 return SCPE_NXDEV;
6082 if (dptr->reset != NULL)
6083 return dptr->reset (dptr);
6084 else return SCPE_OK;
6085 }
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095 t_stat reset_all (uint32 start)
6096 {
6097 DEVICE *dptr;
6098 uint32 i;
6099 t_stat reason;
6100
6101 for (i = 0; i < start; i++) {
6102 if (sim_devices[i] == NULL)
6103 return SCPE_IERR;
6104 }
6105 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6106 if (dptr->reset != NULL) {
6107 reason = dptr->reset (dptr);
6108 if (reason != SCPE_OK)
6109 return reason;
6110 }
6111 }
6112 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6113 if (dptr->reset != NULL) {
6114 reason = dptr->reset (dptr);
6115 if (reason != SCPE_OK)
6116 return reason;
6117 }
6118 }
6119 return SCPE_OK;
6120 }
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130 t_stat reset_all_p (uint32 start)
6131 {
6132 t_stat r;
6133 int32 old_sw = sim_switches;
6134
6135 sim_switches = SWMASK ('P');
6136 r = reset_all (start);
6137 sim_switches = old_sw;
6138 return r;
6139 }
6140
6141
6142
6143 t_stat attach_cmd (int32 flag, CONST char *cptr)
6144 {
6145 char gbuf[4*CBUFSIZE];
6146 DEVICE *dptr;
6147 UNIT *uptr;
6148 t_stat r;
6149
6150 GET_SWITCHES (cptr);
6151 if ((NULL == cptr) || (*cptr == 0))
6152 return SCPE_2FARG;
6153 cptr = get_glyph (cptr, gbuf, 0);
6154 GET_SWITCHES (cptr);
6155 if ((NULL == cptr) || (*cptr == 0))
6156 return SCPE_2FARG;
6157 dptr = find_unit (gbuf, &uptr);
6158 if (dptr == NULL)
6159 return SCPE_NXDEV;
6160 if (uptr == NULL)
6161 return SCPE_NXUN;
6162 if (uptr->flags & UNIT_ATT) {
6163 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6164 !(dptr->flags & DEV_DONTAUTO)) {
6165 r = scp_detach_unit (dptr, uptr);
6166 if (r != SCPE_OK)
6167 return r; }
6168 else {
6169 if (!(uptr->dynflags & UNIT_ATTMULT))
6170 return SCPE_ALATT;
6171 }
6172 }
6173 gbuf[sizeof(gbuf)-1] = '\0';
6174 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6175 sim_trim_endspc (gbuf);
6176 return scp_attach_unit (dptr, uptr, gbuf);
6177 }
6178
6179
6180
6181 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6182 {
6183 if (dptr->attach != NULL)
6184 return dptr->attach (uptr, (CONST char *)cptr);
6185 return attach_unit (uptr, (CONST char *)cptr);
6186 }
6187
6188
6189
6190 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6191 {
6192 DEVICE *dptr;
6193
6194 if (uptr->flags & UNIT_DIS)
6195 return SCPE_UDIS;
6196 if (!(uptr->flags & UNIT_ATTABLE))
6197 return SCPE_NOATT;
6198 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6199 return SCPE_NOATT;
6200 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6201 if (uptr->filename == NULL)
6202 return SCPE_MEM;
6203 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6204 if ((sim_switches & SWMASK ('R')) ||
6205 ((uptr->flags & UNIT_RO) != 0)) {
6206 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6207 ((uptr->flags & UNIT_RO) == 0))
6208 return attach_err (uptr, SCPE_NORO);
6209 uptr->fileref = sim_fopen (cptr, "rb");
6210 if (uptr->fileref == NULL)
6211 return attach_err (uptr, SCPE_OPENERR);
6212 uptr->flags = uptr->flags | UNIT_RO;
6213 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6214 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6215 }
6216 }
6217 else {
6218 if (sim_switches & SWMASK ('N')) {
6219 uptr->fileref = sim_fopen (cptr, "wb+");
6220 if (uptr->fileref == NULL)
6221 return attach_err (uptr, SCPE_OPENERR);
6222 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6223 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6224 }
6225 }
6226 else {
6227 uptr->fileref = sim_fopen (cptr, "rb+");
6228 if (uptr->fileref == NULL) {
6229 #if defined(EWOULDBLOCK)
6230 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6231 #else
6232 if ((errno == EAGAIN))
6233 #endif
6234 return attach_err (uptr, SCPE_OPENERR);
6235
6236 #if defined(EPERM)
6237 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6238 #else
6239 if ((errno == EROFS) || (errno == EACCES)) {
6240 #endif
6241 if ((uptr->flags & UNIT_ROABLE) == 0)
6242 return attach_err (uptr, SCPE_NORO);
6243 uptr->fileref = sim_fopen (cptr, "rb");
6244 if (uptr->fileref == NULL)
6245 return attach_err (uptr, SCPE_OPENERR);
6246 uptr->flags = uptr->flags | UNIT_RO;
6247 if (!sim_quiet) {
6248 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6249 }
6250 }
6251 else {
6252 if (sim_switches & SWMASK ('E'))
6253 return attach_err (uptr, SCPE_OPENERR);
6254 uptr->fileref = sim_fopen (cptr, "wb+");
6255 if (uptr->fileref == NULL)
6256 return attach_err (uptr, SCPE_OPENERR);
6257 if (!sim_quiet) {
6258 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6259 }
6260 }
6261 }
6262 }
6263 }
6264 if (uptr->flags & UNIT_BUFABLE) {
6265 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6266 if (uptr->flags & UNIT_MUSTBUF)
6267 uptr->filebuf = calloc (cap, SZ_D (dptr));
6268 if (uptr->filebuf == NULL)
6269 return attach_err (uptr, SCPE_MEM);
6270 if (!sim_quiet) {
6271 sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6272 }
6273 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6274 SZ_D (dptr), cap, uptr->fileref);
6275 uptr->flags = uptr->flags | UNIT_BUF;
6276 }
6277 uptr->flags = uptr->flags | UNIT_ATT;
6278 uptr->pos = 0;
6279 return SCPE_OK;
6280 }
6281
6282 t_stat attach_err (UNIT *uptr, t_stat stat)
6283 {
6284 FREE (uptr->filename);
6285 uptr->filename = NULL;
6286 return stat;
6287 }
6288
6289
6290
6291 t_stat detach_cmd (int32 flag, CONST char *cptr)
6292 {
6293 char gbuf[CBUFSIZE];
6294 DEVICE *dptr;
6295 UNIT *uptr;
6296
6297 GET_SWITCHES (cptr);
6298 if ((NULL == cptr) || (*cptr == 0))
6299 return SCPE_2FARG;
6300 cptr = get_glyph (cptr, gbuf, 0);
6301 if (*cptr != 0)
6302 return SCPE_2MARG;
6303 if (strcmp (gbuf, "ALL") == 0)
6304 return (detach_all (0, FALSE));
6305 dptr = find_unit (gbuf, &uptr);
6306 if (dptr == NULL)
6307 return SCPE_NXDEV;
6308 if (uptr == NULL)
6309 return SCPE_NXUN;
6310 return scp_detach_unit (dptr, uptr);
6311 }
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326 t_stat detach_all (int32 start, t_bool shutdown)
6327 {
6328 uint32 i, j;
6329 DEVICE *dptr;
6330 UNIT *uptr;
6331 t_stat r;
6332
6333 if ((start < 0) || (start > 1))
6334 return SCPE_IERR;
6335 if (shutdown)
6336 sim_switches = sim_switches | SIM_SW_SHUT;
6337 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6338 for (j = 0; j < dptr->numunits; j++) {
6339 uptr = (dptr->units) + j;
6340 if ((uptr->flags & UNIT_ATT) ||
6341 (shutdown && dptr->detach &&
6342 !(uptr->flags & UNIT_ATTABLE))) {
6343 r = scp_detach_unit (dptr, uptr);
6344
6345 if ((r != SCPE_OK) && !shutdown)
6346 return r;
6347 }
6348 }
6349 }
6350 return SCPE_OK;
6351 }
6352
6353
6354
6355 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6356 {
6357 if (dptr->detach != NULL)
6358 return dptr->detach (uptr);
6359 return detach_unit (uptr);
6360 }
6361
6362
6363
6364 t_stat detach_unit (UNIT *uptr)
6365 {
6366 DEVICE *dptr;
6367
6368 if (uptr == NULL)
6369 return SCPE_IERR;
6370 if (!(uptr->flags & UNIT_ATTABLE))
6371 return SCPE_NOATT;
6372 if (!(uptr->flags & UNIT_ATT)) {
6373 if (sim_switches & SIM_SW_REST)
6374 return SCPE_OK;
6375 else
6376 return SCPE_NOTATT;
6377 }
6378 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6379 return SCPE_OK;
6380 if (uptr->flags & UNIT_BUF) {
6381 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6382 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6383 if (!sim_quiet) {
6384 sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6385 }
6386 rewind (uptr->fileref);
6387 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6388 if (ferror (uptr->fileref))
6389 sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6390 sim_dname (dptr), xstrerror_l(errno), errno);
6391 }
6392 if (uptr->flags & UNIT_MUSTBUF) {
6393 FREE (uptr->filebuf);
6394 uptr->filebuf = NULL;
6395 }
6396 uptr->flags = uptr->flags & ~UNIT_BUF;
6397 }
6398 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6399 FREE (uptr->filename);
6400 uptr->filename = NULL;
6401 if (fclose (uptr->fileref) == EOF)
6402 return SCPE_IOERR;
6403 return SCPE_OK;
6404 }
6405
6406
6407
6408 const char *sim_dname (DEVICE *dptr)
6409 {
6410 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6411 }
6412
6413
6414
6415 const char *sim_uname (UNIT *uptr)
6416 {
6417 DEVICE *d = find_dev_from_unit(uptr);
6418 static char uname[CBUFSIZE];
6419
6420 if (!d)
6421 return "";
6422 if (d->numunits == 1)
6423 return sim_dname (d);
6424 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6425 return uname;
6426 }
6427
6428
6429
6430 t_stat run_cmd (int32 flag, CONST char *cptr)
6431 {
6432 char gbuf[CBUFSIZE] = "";
6433 CONST char *tptr;
6434 uint32 i, j;
6435 int32 sim_next = 0;
6436 int32 unitno;
6437 t_value pcv, orig_pcv;
6438 t_stat r;
6439 DEVICE *dptr;
6440 UNIT *uptr;
6441
6442 GET_SWITCHES (cptr);
6443 sim_step = 0;
6444 if ((flag == RU_RUN) || (flag == RU_GO)) {
6445 orig_pcv = get_rval (sim_PC, 0);
6446 if (*cptr != 0) {
6447 cptr = get_glyph (cptr, gbuf, 0);
6448 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6449 if (sim_dflt_dev && sim_vm_parse_addr)
6450 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6451 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6452 if ((tptr == gbuf) || (*tptr != 0) ||
6453 (pcv > width_mask[sim_PC->width]))
6454 return SCPE_ARG;
6455 put_rval (sim_PC, 0, pcv);
6456 }
6457 }
6458 if ((flag == RU_RUN) &&
6459 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6460 put_rval (sim_PC, 0, orig_pcv);
6461 return r;
6462 }
6463 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6464 int32 saved_switches = sim_switches;
6465
6466 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6467 cptr = get_glyph (cptr, gbuf, 0);
6468 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6469 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6470 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6471 sim_switches = 0;
6472 GET_SWITCHES (cptr);
6473 if ((*cptr == '\'') || (*cptr == '"')) {
6474 r = expect_cmd (1, cptr);
6475 if (r != SCPE_OK)
6476 return r;
6477 }
6478 else {
6479 if (sim_switches == 0)
6480 sim_switches = sim_brk_dflt;
6481 sim_switches |= BRK_TYP_TEMP;
6482 sim_brk_types |= BRK_TYP_TEMP;
6483 r = ssh_break (NULL, cptr, SSH_ST);
6484 if (r != SCPE_OK)
6485 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6486 }
6487 sim_switches = saved_switches;
6488 }
6489 }
6490
6491 else if ((flag == RU_STEP) ||
6492 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6493 static t_bool not_implemented_message = FALSE;
6494
6495 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6496 not_implemented_message = TRUE;
6497 flag = RU_STEP;
6498 }
6499 if (*cptr != 0) {
6500 cptr = get_glyph (cptr, gbuf, 0);
6501 if (*cptr != 0)
6502 return SCPE_2MARG;
6503 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6504 if ((r != SCPE_OK) || (sim_step <= 0))
6505 return SCPE_ARG;
6506 }
6507 else sim_step = 1;
6508 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6509 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6510 }
6511 else if (flag == RU_NEXT) {
6512 t_addr *addrs;
6513
6514 if (*cptr != 0) {
6515 cptr = get_glyph (cptr, gbuf, 0);
6516 if (*cptr != 0)
6517 return SCPE_2MARG;
6518 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6519 if ((r != SCPE_OK) || (sim_next <= 0))
6520 return SCPE_ARG;
6521 }
6522 else sim_next = 1;
6523 if (sim_vm_is_subroutine_call(&addrs)) {
6524 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6525 for (i=0; addrs[i]; i++)
6526 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6527 }
6528 else
6529 sim_step = 1;
6530 }
6531 else if (flag == RU_BOOT) {
6532 if (*cptr == 0)
6533 return SCPE_2FARG;
6534 cptr = get_glyph (cptr, gbuf, 0);
6535 if (*cptr != 0)
6536 return SCPE_2MARG;
6537 dptr = find_unit (gbuf, &uptr);
6538 if (dptr == NULL)
6539 return SCPE_NXDEV;
6540 if (uptr == NULL)
6541 return SCPE_NXUN;
6542 if (dptr->boot == NULL)
6543 return SCPE_NOFNC;
6544 if (uptr->flags & UNIT_DIS)
6545 return SCPE_UDIS;
6546 if ((uptr->flags & UNIT_ATTABLE) &&
6547 !(uptr->flags & UNIT_ATT))
6548 return SCPE_UNATT;
6549 unitno = (int32) (uptr - dptr->units);
6550 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6551 return r;
6552 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6553 return r;
6554 }
6555
6556 else
6557 if (flag != RU_CONT)
6558 return SCPE_IERR;
6559 else
6560 if (*cptr != 0)
6561 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6562
6563 if (sim_switches & SIM_SW_HIDE)
6564 return SCPE_OK;
6565
6566 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6567 for (j = 0; j < dptr->numunits; j++) {
6568 uptr = dptr->units + j;
6569 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6570 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6571 }
6572 }
6573 stop_cpu = 0;
6574 sim_is_running = 1;
6575 if (sim_ttrun () != SCPE_OK) {
6576 sim_is_running = 0;
6577 sim_ttcmd ();
6578 return SCPE_TTYERR;
6579 }
6580 if ((r = sim_check_console (30)) != SCPE_OK) {
6581 sim_is_running = 0;
6582 sim_ttcmd ();
6583 return r;
6584 }
6585 #if !defined(IS_WINDOWS)
6586 # if defined(SIGINT)
6587 if (signal (SIGINT, int_handler) == SIG_ERR) {
6588 sim_is_running = 0;
6589 sim_ttcmd ();
6590 return SCPE_SIGERR;
6591 }
6592 # endif
6593 #endif
6594 #if !defined(IS_WINDOWS)
6595 # if defined(SIGHUP)
6596 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6597 sim_is_running = 0;
6598 sim_ttcmd ();
6599 return SCPE_SIGERR;
6600 }
6601 # endif
6602 #endif
6603 #if !defined(IS_WINDOWS)
6604 # if defined(SIGTERM)
6605 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6606 sim_is_running = 0;
6607 sim_ttcmd ();
6608 return SCPE_SIGERR;
6609 }
6610 # endif
6611 #endif
6612 if (sim_step)
6613 sim_activate (&sim_step_unit, sim_step);
6614 (void)fflush(stdout);
6615 if (sim_log)
6616 (void)fflush (sim_log);
6617 sim_rtcn_init_all ();
6618 sim_start_timer_services ();
6619
6620 do {
6621 t_addr *addrs;
6622
6623 while (1) {
6624 r = sim_instr();
6625 if (r != SCPE_REMOTE)
6626 break;
6627 sim_remote_process_command ();
6628 }
6629 if ((flag != RU_NEXT) ||
6630 (--sim_next <=0))
6631 break;
6632 if (sim_step == 0) {
6633 t_addr val;
6634 BRKTAB *bp;
6635
6636 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6637 break;
6638 if (sim_vm_pc_value)
6639 val = (t_addr)(*sim_vm_pc_value)();
6640 else
6641 val = (t_addr)get_rval (sim_PC, 0);
6642 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6643 break;
6644 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6645 }
6646 else {
6647 if (r != SCPE_STEP)
6648 break;
6649 }
6650
6651 sim_step = 0;
6652 if (sim_vm_is_subroutine_call(&addrs)) {
6653 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6654 for (i=0; addrs[i]; i++)
6655 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6656 }
6657 else
6658 sim_step = 1;
6659 if (sim_step)
6660 sim_activate (&sim_step_unit, sim_step);
6661 } while (1);
6662
6663 sim_is_running = 0;
6664 sim_stop_timer_services ();
6665 sim_ttcmd ();
6666 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6667 signal (SIGINT, SIG_DFL);
6668 #if defined(SIGHUP)
6669 signal (SIGHUP, SIG_DFL);
6670 #endif
6671 signal (SIGTERM, SIG_DFL);
6672 if (sim_log)
6673 (void)fflush (sim_log);
6674 if (sim_deb)
6675 sim_debug_flush ();
6676 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6677 for (j = 0; j < dptr->numunits; j++) {
6678 uptr = dptr->units + j;
6679 if (uptr->flags & UNIT_ATT) {
6680 if (uptr->io_flush)
6681 uptr->io_flush (uptr);
6682 else {
6683 if (!(uptr->flags & UNIT_BUF) &&
6684 (uptr->fileref) &&
6685 !(uptr->dynflags & UNIT_NO_FIO) &&
6686 !(uptr->flags & UNIT_RO))
6687 (void)fflush (uptr->fileref);
6688 }
6689 }
6690 }
6691 }
6692 sim_cancel (&sim_step_unit);
6693 UPDATE_SIM_TIME;
6694 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6695 }
6696
6697
6698
6699 void
6700 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6701 {
6702 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6703 sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6704 #if defined(WIN_STDIO)
6705 (void)fflush(stderr);
6706 (void)fflush(stdout);
6707 #endif
6708 fprint_stopped (stdout, r);
6709 if (sim_log && (sim_log != stdout))
6710 fprint_stopped (sim_log, r);
6711 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6712 fprint_stopped (sim_deb, r);
6713 #if defined(WIN_STDIO)
6714 (void)fflush(stderr);
6715 (void)fflush(stdout);
6716 #endif
6717 }
6718
6719
6720
6721 t_stat sim_run_boot_prep (int32 flag)
6722 {
6723 UNIT *uptr;
6724 t_stat r;
6725
6726 sim_interval = 0;
6727 sim_time = sim_rtime = 0;
6728 noqueue_time = 0;
6729 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6730 sim_clock_queue = uptr->next;
6731 uptr->next = NULL;
6732 }
6733 r = reset_all (0);
6734 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6735 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6736 sim_printf ("Resetting all devices... This may not have been your intention.\r\n");
6737 sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6738 }
6739 run_cmd_did_reset = TRUE;
6740 }
6741 return r;
6742 }
6743
6744
6745
6746
6747
6748
6749
6750
6751 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6752 {
6753 int32 i;
6754 t_stat r = 0;
6755 t_addr k;
6756 t_value pcval;
6757
6758 fputc ('\n', st);
6759
6760 if (v >= SCPE_BASE)
6761 fputs (sim_error_text (v), st);
6762 else {
6763 fputs (sim_stop_messages [v], st);
6764
6765 if ((sim_vm_fprint_stopped != NULL) &&
6766 (!sim_vm_fprint_stopped (st, v)))
6767 return;
6768 }
6769
6770 (void)fprintf (st, ", %s: ", pc->name);
6771
6772 pcval = get_rval (pc, 0);
6773 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6774 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6775 else fprint_val (st, pcval, pc->radix, pc->width,
6776 pc->flags & REG_FMT);
6777 if ((dptr != NULL) && (dptr->examine != NULL)) {
6778 for (i = 0; i < sim_emax; i++)
6779 sim_eval[i] = 0;
6780 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6781 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6782 break;
6783 }
6784 if ((r == SCPE_OK) || (i > 0)) {
6785 (void)fprintf (st, " (");
6786 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6787 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6788 (void)fprintf (st, ")");
6789 }
6790 }
6791 (void)fprintf (st, "\r\n");
6792 return;
6793 }
6794
6795 void fprint_stopped (FILE *st, t_stat v)
6796 {
6797 #if defined(WIN_STDIO)
6798 (void)fflush(stderr);
6799 (void)fflush(stdout);
6800 #endif
6801 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6802 return;
6803 }
6804
6805
6806
6807
6808 t_stat step_svc (UNIT *uptr)
6809 {
6810 return SCPE_STEP;
6811 }
6812
6813
6814
6815
6816 t_stat expect_svc (UNIT *uptr)
6817 {
6818 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6819 }
6820
6821
6822
6823 void int_handler (int sig)
6824 {
6825 stop_cpu = 1;
6826 return;
6827 }
6828
6829
6830
6831 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6832 {
6833 char gbuf[CBUFSIZE];
6834 CONST char *gptr;
6835 CONST char *tptr = NULL;
6836 int32 opt;
6837 t_addr low, high;
6838 t_stat reason = SCPE_IERR;
6839 DEVICE *tdptr;
6840 REG *lowr, *highr;
6841 FILE *ofile;
6842
6843 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6844 if (flag == EX_E)
6845 opt = opt | CMD_OPT_OF;
6846 cptr = get_sim_opt (opt, cptr, &reason);
6847 if (NULL == cptr)
6848 return reason;
6849 if (*cptr == 0)
6850 return SCPE_2FARG;
6851 if (sim_dfunit == NULL)
6852 return SCPE_NXUN;
6853 cptr = get_glyph (cptr, gbuf, 0);
6854 if ((flag == EX_D) && (*cptr == 0))
6855
6856 return SCPE_2FARG;
6857 ofile = sim_ofile? sim_ofile: stdout;
6858
6859 for (gptr = gbuf, reason = SCPE_OK;
6860 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6861 tdptr = sim_dfdev;
6862 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6863 tptr = gptr + strlen ("STATE");
6864 if (*tptr && (*tptr++ != ','))
6865 return SCPE_ARG;
6866 if ((lowr = sim_dfdev->registers) == NULL)
6867 return SCPE_NXREG;
6868 for (highr = lowr; highr->name != NULL; highr++) ;
6869 sim_switches = sim_switches | SIM_SW_HIDE;
6870 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6871 lowr, --highr, 0, 0);
6872 continue;
6873 }
6874
6875
6876 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6877 (!(sim_opt_out & CMD_OPT_DFT) &&
6878 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6879 low = high = 0;
6880 if ((*tptr == '-') || (*tptr == ':')) {
6881 highr = find_reg (tptr + 1, &tptr, tdptr);
6882 if (highr == NULL)
6883 return SCPE_NXREG;
6884 }
6885 else {
6886 highr = lowr;
6887 if (*tptr == '[') {
6888 if (lowr->depth <= 1)
6889 return SCPE_ARG;
6890 tptr = get_range (NULL, tptr + 1, &low, &high,
6891 10, lowr->depth - 1, ']');
6892 if (tptr == NULL)
6893 return SCPE_ARG;
6894 }
6895 }
6896 if (*tptr && (*tptr++ != ','))
6897 return SCPE_ARG;
6898 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6899 lowr, highr, (uint32) low, (uint32) high);
6900 continue;
6901 }
6902
6903 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6904 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6905 sim_dfunit->capac - sim_dfdev->aincr), 0);
6906 if (tptr == NULL)
6907 return SCPE_ARG;
6908 if (*tptr && (*tptr++ != ','))
6909 return SCPE_ARG;
6910 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6911 sim_dfdev, sim_dfunit);
6912 }
6913 if (sim_ofile)
6914 fclose (sim_ofile);
6915 return reason;
6916 }
6917
6918
6919
6920
6921
6922
6923
6924 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6925 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6926 {
6927 t_stat reason;
6928 uint32 idx, val_start=lows;
6929 t_value val, last_val;
6930 REG *rptr;
6931
6932 if ((lowr == NULL) || (highr == NULL))
6933 return SCPE_IERR;
6934 if (lowr > highr)
6935 return SCPE_ARG;
6936 for (rptr = lowr; rptr <= highr; rptr++) {
6937 if ((sim_switches & SIM_SW_HIDE) &&
6938 (rptr->flags & REG_HIDDEN))
6939 continue;
6940 val = last_val = 0;
6941 for (idx = lows; idx <= highs; idx++) {
6942 if (idx >= rptr->depth)
6943 return SCPE_SUB;
6944 val = get_rval (rptr, idx);
6945 if (schptr && !test_search (&val, schptr))
6946 continue;
6947 if (flag == EX_E) {
6948 if ((idx > lows) && (val == last_val))
6949 continue;
6950 if (idx > val_start+1) {
6951 if (idx-1 == val_start+1) {
6952 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6953 if (reason != SCPE_OK)
6954 return reason;
6955 if (sim_log && (ofile == stdout))
6956 ex_reg (sim_log, val, flag, rptr, idx-1);
6957 }
6958 else {
6959 if (val_start+1 != idx-1) {
6960 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6961 if (sim_log && (ofile == stdout))
6962 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6963 }
6964 else {
6965 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6966 if (sim_log && (ofile == stdout))
6967 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6968 }
6969 }
6970 }
6971 sim_last_val = last_val = val;
6972 val_start = idx;
6973 reason = ex_reg (ofile, val, flag, rptr, idx);
6974 if (reason != SCPE_OK)
6975 return reason;
6976 if (sim_log && (ofile == stdout))
6977 ex_reg (sim_log, val, flag, rptr, idx);
6978 }
6979 if (flag != EX_E) {
6980 reason = dep_reg (flag, cptr, rptr, idx);
6981 if (reason != SCPE_OK)
6982 return reason;
6983 }
6984 }
6985 if ((flag == EX_E) && (val_start != highs)) {
6986 if (highs == val_start+1) {
6987 reason = ex_reg (ofile, val, flag, rptr, highs);
6988 if (reason != SCPE_OK)
6989 return reason;
6990 if (sim_log && (ofile == stdout))
6991 ex_reg (sim_log, val, flag, rptr, highs);
6992 }
6993 else {
6994 if (val_start+1 != highs) {
6995 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6996 if (sim_log && (ofile == stdout))
6997 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6998 }
6999 else {
7000 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7001 if (sim_log && (ofile == stdout))
7002 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7003 }
7004 }
7005 }
7006 }
7007 return SCPE_OK;
7008 }
7009
7010 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
7011 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
7012 {
7013 t_addr i, mask;
7014 t_stat reason;
7015
7016 if (uptr->flags & UNIT_DIS)
7017 return SCPE_UDIS;
7018 mask = (t_addr) width_mask[dptr->awidth];
7019 if ((low > mask) || (high > mask) || (low > high))
7020 return SCPE_ARG;
7021 for (i = low; i <= high; ) {
7022 reason = get_aval (i, dptr, uptr);
7023 if (reason != SCPE_OK)
7024 return reason;
7025 if (schptr && !test_search (sim_eval, schptr))
7026 i = i + dptr->aincr;
7027 else {
7028 if (flag != EX_D) {
7029 reason = ex_addr (ofile, flag, i, dptr, uptr);
7030 if (reason > SCPE_OK)
7031 return reason;
7032 if (sim_log && (ofile == stdout))
7033 ex_addr (sim_log, flag, i, dptr, uptr);
7034 }
7035 else reason = 1 - dptr->aincr;
7036 if (flag != EX_E) {
7037 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7038 if (reason > SCPE_OK)
7039 return reason;
7040 }
7041 i = i + (1 - reason);
7042 }
7043 }
7044 return SCPE_OK;
7045 }
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
7060 {
7061 int32 rdx;
7062
7063 if (rptr == NULL)
7064 return SCPE_IERR;
7065 if (rptr->depth > 1)
7066 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7067 else
7068 (void)Fprintf (ofile, "%s:\t", rptr->name);
7069 if (!(flag & EX_E))
7070 return SCPE_OK;
7071 GET_RADIX (rdx, rptr->radix);
7072 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7073 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7074 else if (!(rptr->flags & REG_VMFLAGS) ||
7075 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7076 NULL, sim_switches | SIM_SW_REG) > 0)) {
7077 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7078 if (rptr->fields) {
7079 (void)Fprintf (ofile, "\t");
7080 fprint_fields (ofile, val, val, rptr->fields);
7081 }
7082 }
7083 if (flag & EX_I)
7084 (void)Fprintf (ofile, "\t");
7085 else
7086 (void)Fprintf (ofile, "\r\n");
7087 return SCPE_OK;
7088 }
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099 t_value get_rval (REG *rptr, uint32 idx)
7100 {
7101 size_t sz;
7102 t_value val;
7103 uint32 *ptr;
7104
7105 sz = SZ_R (rptr);
7106 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7107 idx = idx + rptr->qptr;
7108 if (idx >= rptr->depth) idx = idx - rptr->depth;
7109 }
7110 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7111 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7112 if (sz <= sizeof (uint32))
7113 val = *ptr;
7114 else val = *((t_uint64 *) ptr);
7115 }
7116 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7117 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7118 if (sz <= sizeof (uint32))
7119 val = *ptr;
7120 else val = *((t_uint64 *) ptr);
7121 }
7122 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7123 (sz == sizeof (uint8)))
7124 val = *(((uint8 *) rptr->loc) + idx);
7125 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7126 (sz == sizeof (uint16)))
7127 val = *(((uint16 *) rptr->loc) + idx);
7128 else if (sz <= sizeof (uint32))
7129 val = *(((uint32 *) rptr->loc) + idx);
7130 else val = *(((t_uint64 *) rptr->loc) + idx);
7131 val = (val >> rptr->offset) & width_mask[rptr->width];
7132 return val;
7133 }
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7147 {
7148 t_stat r;
7149 t_value val, mask;
7150 int32 rdx;
7151 CONST char *tptr;
7152 char gbuf[CBUFSIZE];
7153
7154 if ((cptr == NULL) || (rptr == NULL))
7155 return SCPE_IERR;
7156 if (rptr->flags & REG_RO)
7157 return SCPE_RO;
7158 if (flag & EX_I) {
7159 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7160 if (sim_log)
7161 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7162 if (cptr == NULL)
7163 return 1;
7164 if (*cptr == 0)
7165 return SCPE_OK;
7166 }
7167 mask = width_mask[rptr->width];
7168 GET_RADIX (rdx, rptr->radix);
7169 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7170 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7171 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7172 return SCPE_ARG;
7173 }
7174 else
7175 if (!(rptr->flags & REG_VMFLAGS) ||
7176 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7177 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7178 val = get_uint (cptr, rdx, mask, &r);
7179 if (r != SCPE_OK)
7180 return SCPE_ARG;
7181 }
7182 if ((rptr->flags & REG_NZ) && (val == 0))
7183 return SCPE_ARG;
7184 put_rval (rptr, idx, val);
7185 return SCPE_OK;
7186 }
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199 void put_rval (REG *rptr, uint32 idx, t_value val)
7200 {
7201 size_t sz;
7202 t_value mask;
7203 uint32 *ptr;
7204
7205 #define PUT_RVAL(sz,rp,id,v,m) \
7206 *(((sz *) rp->loc) + id) = \
7207 (sz)((*(((sz *) rp->loc) + id) & \
7208 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7209
7210 if (rptr == sim_PC)
7211 sim_brk_npc (0);
7212 sz = SZ_R (rptr);
7213 mask = width_mask[rptr->width];
7214 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7215 idx = idx + rptr->qptr;
7216 if (idx >= rptr->depth)
7217 idx = idx - rptr->depth;
7218 }
7219 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7220 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7221 if (sz <= sizeof (uint32))
7222 *ptr = (*ptr &
7223 ~(((uint32) mask) << rptr->offset)) |
7224 (((uint32) val) << rptr->offset);
7225 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7226 & ~(mask << rptr->offset)) | (val << rptr->offset);
7227 }
7228 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7229 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7230 if (sz <= sizeof (uint32))
7231 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7232 ~(((uint32) mask) << rptr->offset)) |
7233 (((uint32) val) << rptr->offset);
7234 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7235 & ~(mask << rptr->offset)) | (val << rptr->offset);
7236 }
7237 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7238 (sz == sizeof (uint8)))
7239 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7240 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7241 (sz == sizeof (uint16)))
7242 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7243 else if (sz <= sizeof (uint32))
7244 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7245 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7246 return;
7247 }
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7263 {
7264 t_stat reason;
7265 int32 rdx;
7266
7267 if (sim_vm_fprint_addr)
7268 sim_vm_fprint_addr (ofile, dptr, addr);
7269 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7270 (void)Fprintf (ofile, ":\t");
7271 if (!(flag & EX_E))
7272 return (1 - dptr->aincr);
7273
7274 GET_RADIX (rdx, dptr->dradix);
7275 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7276 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7277 reason = 1 - dptr->aincr;
7278 }
7279 if (flag & EX_I)
7280 (void)Fprintf (ofile, "\t");
7281 else
7282 (void)Fprintf (ofile, "\r\n");
7283 return reason;
7284 }
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7298 {
7299 int32 i;
7300 t_value mask;
7301 t_addr j, loc;
7302 size_t sz;
7303 t_stat reason = SCPE_OK;
7304
7305 if ((dptr == NULL) || (uptr == NULL))
7306 return SCPE_IERR;
7307 mask = width_mask[dptr->dwidth];
7308 for (i = 0; i < sim_emax; i++)
7309 sim_eval[i] = 0;
7310 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7311 if (dptr->examine != NULL) {
7312 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7313 if (reason != SCPE_OK)
7314 break;
7315 }
7316 else {
7317 if (!(uptr->flags & UNIT_ATT))
7318 return SCPE_UNATT;
7319 if (uptr->dynflags & UNIT_NO_FIO)
7320 return SCPE_NOFNC;
7321 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7322 reason = SCPE_NXM;
7323 break;
7324 }
7325 sz = SZ_D (dptr);
7326 loc = j / dptr->aincr;
7327 if (uptr->flags & UNIT_BUF) {
7328 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7329 }
7330 else {
7331 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7332 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7333 if ((feof (uptr->fileref)) &&
7334 !(uptr->flags & UNIT_FIX)) {
7335 reason = SCPE_EOF;
7336 break;
7337 }
7338 else if (ferror (uptr->fileref)) {
7339 clearerr (uptr->fileref);
7340 reason = SCPE_IOERR;
7341 break;
7342 }
7343 }
7344 }
7345 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7346 }
7347 if ((reason != SCPE_OK) && (i == 0))
7348 return reason;
7349 return SCPE_OK;
7350 }
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7367 UNIT *uptr, int32 dfltinc)
7368 {
7369 int32 i, count, rdx;
7370 t_addr j, loc;
7371 t_stat r, reason;
7372 t_value mask;
7373 size_t sz;
7374 char gbuf[CBUFSIZE];
7375
7376 if (dptr == NULL)
7377 return SCPE_IERR;
7378 if (flag & EX_I) {
7379 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7380 if (sim_log)
7381 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7382 if (cptr == NULL)
7383 return 1;
7384 if (*cptr == 0)
7385 return dfltinc;
7386 }
7387 if (uptr->flags & UNIT_RO)
7388 return SCPE_RO;
7389 mask = width_mask[dptr->dwidth];
7390
7391 GET_RADIX (rdx, dptr->dradix);
7392 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7393 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7394 if (reason != SCPE_OK)
7395 return reason;
7396 reason = dfltinc;
7397 }
7398 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7399
7400 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7401 sim_eval[i] = sim_eval[i] & mask;
7402 if (dptr->deposit != NULL) {
7403 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7404 if (r != SCPE_OK)
7405 return r;
7406 }
7407 else {
7408 if (!(uptr->flags & UNIT_ATT))
7409 return SCPE_UNATT;
7410 if (uptr->dynflags & UNIT_NO_FIO)
7411 return SCPE_NOFNC;
7412 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7413 return SCPE_NXM;
7414 sz = SZ_D (dptr);
7415 loc = j / dptr->aincr;
7416 if (uptr->flags & UNIT_BUF) {
7417 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7418 if (loc >= uptr->hwmark)
7419 uptr->hwmark = (uint32) loc + 1;
7420 }
7421 else {
7422 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7423 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7424 if (ferror (uptr->fileref)) {
7425 clearerr (uptr->fileref);
7426 return SCPE_IOERR;
7427 }
7428 }
7429 }
7430 }
7431 return reason;
7432 }
7433
7434
7435
7436 t_stat eval_cmd (int32 flg, CONST char *cptr)
7437 {
7438 if (!sim_dflt_dev)
7439 return SCPE_ARG;
7440 DEVICE *dptr = sim_dflt_dev;
7441 int32 i, rdx, a, lim;
7442 t_stat r;
7443
7444 GET_SWITCHES (cptr);
7445 GET_RADIX (rdx, dptr->dradix);
7446 for (i = 0; i < sim_emax; i++)
7447 sim_eval[i] = 0;
7448 if (*cptr == 0)
7449 return SCPE_2FARG;
7450 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7451 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7452 if (r != SCPE_OK)
7453 return r;
7454 }
7455 lim = 1 - r;
7456 for (i = a = 0; a < lim; ) {
7457 sim_printf ("%d:\t", a);
7458 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7459 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7460 if (sim_log) {
7461 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7462 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7463 }
7464 sim_printf ("\r\n");
7465 if (r < 0)
7466 a = a + 1 - r;
7467 else a = a + dptr->aincr;
7468 i = a / dptr->aincr;
7469 }
7470 return SCPE_OK;
7471 }
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486 char *read_line (char *cptr, int32 size, FILE *stream)
7487 {
7488 return read_line_p (NULL, cptr, size, stream);
7489 }
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7504 {
7505 char *tptr;
7506
7507 if (prompt) {
7508 #if defined(HAVE_LINEHISTORY)
7509 char *tmpc = linenoise (prompt);
7510 if (tmpc == NULL)
7511 cptr = NULL;
7512 else {
7513 strncpy (cptr, tmpc, size-1);
7514 linenoiseHistoryAdd (tmpc);
7515 FREE (tmpc);
7516 }
7517 }
7518 #else
7519 (void)fflush (stdout);
7520 (void)printf ("%s", prompt);
7521 (void)fflush (stdout);
7522 cptr = fgets (cptr, size, stream);
7523 }
7524 #endif
7525 else cptr = fgets (cptr, size, stream);
7526
7527 if (cptr == NULL) {
7528 clearerr (stream);
7529 return NULL;
7530 }
7531 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7532 if ((*tptr == '\n') || (*tptr == '\r') ||
7533 (tptr == (cptr + size - 1))) {
7534 *tptr = 0;
7535 break;
7536 }
7537 }
7538 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7539 memmove (cptr, cptr + 3, strlen (cptr + 3));
7540 while (sim_isspace (*cptr))
7541 cptr++;
7542 if ((*cptr == ';') || (*cptr == '#')) {
7543 if (sim_do_echo)
7544 sim_printf("%s> %s\r\n", do_position(), cptr);
7545 *cptr = 0;
7546 }
7547
7548 return cptr;
7549 }
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7570 {
7571 t_bool quoting = FALSE;
7572 t_bool escaping = FALSE;
7573 char quote_char = 0;
7574
7575 while ((*iptr != 0) &&
7576 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7577 if (quote) {
7578 if (quoting) {
7579 if (!escaping) {
7580 if (*iptr == escape_char)
7581 escaping = TRUE;
7582 else
7583 if (*iptr == quote_char)
7584 quoting = FALSE;
7585 }
7586 else
7587 escaping = FALSE;
7588 }
7589 else {
7590 if ((*iptr == '"') || (*iptr == '\'')) {
7591 quoting = TRUE;
7592 quote_char = *iptr;
7593 }
7594 }
7595 }
7596 if (sim_islower (*iptr) && uc)
7597 *optr = (char)toupper (*iptr);
7598 else *optr = *iptr;
7599 iptr++; optr++;
7600 }
7601 if (mchar && (*iptr == mchar))
7602 iptr++;
7603 *optr = 0;
7604 while (sim_isspace (*iptr))
7605 iptr++;
7606 return iptr;
7607 }
7608
7609 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7610 {
7611 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7612 }
7613
7614 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7615 {
7616 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7617 }
7618
7619 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7620 {
7621 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7622 }
7623
7624 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7625 {
7626
7627 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7628 strcpy (optr, "!");
7629 return (CONST char *)(iptr + 1);
7630 }
7631 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7632 }
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642 char *sim_trim_endspc (char *cptr)
7643 {
7644 char *tptr;
7645
7646 tptr = cptr + strlen (cptr);
7647 while ((--tptr >= cptr) && sim_isspace (*tptr))
7648 *tptr = 0;
7649 return cptr;
7650 }
7651
7652 int sim_isspace (char c)
7653 {
7654 return (c & 0x80) ? 0 : isspace (c);
7655 }
7656
7657 int sim_islower (char c)
7658 {
7659 return (c & 0x80) ? 0 : islower (c);
7660 }
7661
7662 int sim_isalpha (char c)
7663 {
7664 return (c & 0x80) ? 0 : isalpha (c);
7665 }
7666
7667 int sim_isprint (char c)
7668 {
7669 return (c & 0x80) ? 0 : isprint (c);
7670 }
7671
7672 int sim_isdigit (char c)
7673 {
7674 return (c & 0x80) ? 0 : isdigit (c);
7675 }
7676
7677 int sim_isgraph (char c)
7678 {
7679 return (c & 0x80) ? 0 : isgraph (c);
7680 }
7681
7682 int sim_isalnum (char c)
7683 {
7684 return (c & 0x80) ? 0 : isalnum (c);
7685 }
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7699 {
7700 t_value val;
7701 CONST char *tptr;
7702
7703 *status = SCPE_OK;
7704 val = strtotv ((CONST char *)cptr, &tptr, radix);
7705 if ((cptr == tptr) || (val > max))
7706 *status = SCPE_ARG;
7707 else {
7708 while (sim_isspace (*tptr)) tptr++;
7709 if (*tptr != 0)
7710 *status = SCPE_ARG;
7711 }
7712 return val;
7713 }
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7731 uint32 rdx, t_addr max, char term)
7732 {
7733 CONST char *tptr;
7734
7735 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7736 tptr = cptr + strlen ("ALL");
7737 *lo = 0;
7738 *hi = max;
7739 }
7740 else {
7741 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7742 ((cptr[1] == '\0') ||
7743 (cptr[1] == '-') ||
7744 (cptr[1] == ':') ||
7745 (cptr[1] == '/'))) {
7746 tptr = cptr + strlen (".");
7747 *lo = *hi = sim_last_addr;
7748 }
7749 else {
7750 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7751 tptr = cptr + strlen ("$");
7752 *hi = *lo = (t_addr)sim_last_val;
7753 }
7754 else {
7755 if (dptr && sim_vm_parse_addr)
7756 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7757 else
7758 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7759 if (cptr == tptr)
7760 return NULL;
7761 }
7762 }
7763 if ((*tptr == '-') || (*tptr == ':')) {
7764 cptr = tptr + 1;
7765 if (dptr && sim_vm_parse_addr)
7766 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7767 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7768 if (cptr == tptr)
7769 return NULL;
7770 if (*lo > *hi)
7771 return NULL;
7772 }
7773 else if (*tptr == '/') {
7774 cptr = tptr + 1;
7775 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7776 if ((cptr == tptr) || (*hi == 0))
7777 return NULL;
7778 *hi = *lo + *hi - 1;
7779 }
7780 else *hi = *lo;
7781 }
7782 sim_last_addr = *hi;
7783 if (term && (*tptr++ != term))
7784 return NULL;
7785 return tptr;
7786 }
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
7805
7806 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7807 {
7808 char quote_char;
7809 uint8 *ostart = optr;
7810
7811 *osize = 0;
7812 if ((strlen(iptr) == 1) ||
7813 (iptr[0] != iptr[strlen(iptr)-1]) ||
7814 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7815 return SCPE_ARG;
7816 quote_char = *iptr++;
7817 while (iptr[1]) {
7818 if (*iptr != '\\') {
7819 if (*iptr == quote_char)
7820 return SCPE_ARG;
7821 *(optr++) = (uint8)(*(iptr++));
7822 continue;
7823 }
7824 ++iptr;
7825 switch (*iptr) {
7826 case 'r':
7827 *(optr++) = 13; ++iptr;
7828 break;
7829 case 'n':
7830 *(optr++) = 10; ++iptr;
7831 break;
7832 case 'f':
7833 *(optr++) = 12; ++iptr;
7834 break;
7835 case 't':
7836 *(optr++) = 9; ++iptr;
7837 break;
7838 case 'v':
7839 *(optr++) = 11; ++iptr;
7840 break;
7841 case 'b':
7842 *(optr++) = 8; ++iptr;
7843 break;
7844 case '\\':
7845 *(optr++) = 92; ++iptr;
7846 break;
7847 case 'e':
7848 *(optr++) = 27; ++iptr;
7849 break;
7850 case '\'':
7851 *(optr++) = 39; ++iptr;
7852 break;
7853 case '"':
7854 *(optr++) = 34; ++iptr;
7855 break;
7856 case '?':
7857 *(optr++) = 63; ++iptr;
7858 break;
7859 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7860 *optr = *(iptr++) - '0';
7861 if ((*iptr >= '0') && (*iptr <= '7'))
7862 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7863 if ((*iptr >= '0') && (*iptr <= '7'))
7864 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7865 ++optr;
7866 break;
7867 case 'x':
7868 if (1) {
7869 static const char *hex_digits = "0123456789ABCDEF";
7870 const char *c;
7871
7872 ++iptr;
7873 *optr = 0;
7874 c = strchr (hex_digits, toupper(*iptr));
7875 if (c) {
7876 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7877 ++iptr;
7878 }
7879 c = strchr (hex_digits, toupper(*iptr));
7880 if (c) {
7881 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7882 ++iptr;
7883 }
7884 ++optr;
7885 }
7886 break;
7887 default:
7888 return SCPE_ARG;
7889 }
7890 }
7891 *optr = '\0';
7892 *osize = (uint32)(optr-ostart);
7893 return SCPE_OK;
7894 }
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7910 {
7911 size_t i;
7912 t_bool double_quote_found = FALSE;
7913 t_bool single_quote_found = FALSE;
7914 char quote = '"';
7915 char *tptr, *optr;
7916
7917 optr = (char *)malloc (4*size + 3);
7918 if (optr == NULL)
7919 return NULL;
7920 tptr = optr;
7921 for (i=0; i<size; i++)
7922 switch ((char)iptr[i]) {
7923 case '"':
7924 double_quote_found = TRUE;
7925 break;
7926 case '\'':
7927 single_quote_found = TRUE;
7928 break;
7929 }
7930 if (double_quote_found && (!single_quote_found))
7931 quote = '\'';
7932 *tptr++ = quote;
7933 while (size--) {
7934 switch (*iptr) {
7935 case '\r':
7936 *tptr++ = '\\'; *tptr++ = 'r'; break;
7937 case '\n':
7938 *tptr++ = '\\'; *tptr++ = 'n'; break;
7939 case '\f':
7940 *tptr++ = '\\'; *tptr++ = 'f'; break;
7941 case '\t':
7942 *tptr++ = '\\'; *tptr++ = 't'; break;
7943 case '\v':
7944 *tptr++ = '\\'; *tptr++ = 'v'; break;
7945 case '\b':
7946 *tptr++ = '\\'; *tptr++ = 'b'; break;
7947 case '\\':
7948 *tptr++ = '\\'; *tptr++ = '\\'; break;
7949 case '"':
7950 case '\'':
7951 if (quote == *iptr)
7952 *tptr++ = '\\';
7953
7954 default:
7955 if (sim_isprint (*iptr))
7956 *tptr++ = *iptr;
7957 else {
7958 (void)sprintf (tptr, "\\%03o", *iptr);
7959 tptr += 4;
7960 }
7961 break;
7962 }
7963 ++iptr;
7964 }
7965 *tptr++ = quote;
7966 *tptr++ = '\0';
7967 return optr;
7968 }
7969
7970 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
7971 {
7972 char *string;
7973
7974 string = sim_encode_quoted_string (buf, size);
7975 (void)fprintf (st, "%s", string);
7976 FREE (string);
7977 }
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987 DEVICE *find_dev (const char *cptr)
7988 {
7989 int32 i;
7990 DEVICE *dptr;
7991
7992 if (cptr == NULL)
7993 return NULL;
7994 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7995 if ((strcmp (cptr, dptr->name) == 0) ||
7996 (dptr->lname &&
7997 (strcmp (cptr, dptr->lname) == 0)))
7998 return dptr;
7999 }
8000 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
8001 if ((strcmp (cptr, dptr->name) == 0) ||
8002 (dptr->lname &&
8003 (strcmp (cptr, dptr->lname) == 0)))
8004 return dptr;
8005 }
8006 return NULL;
8007 }
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020 DEVICE *find_unit (const char *cptr, UNIT **uptr)
8021 {
8022 uint32 i, u;
8023 const char *nptr;
8024 const char *tptr;
8025 t_stat r;
8026 DEVICE *dptr;
8027
8028 if (uptr == NULL)
8029 return NULL;
8030 *uptr = NULL;
8031 if ((dptr = find_dev (cptr))) {
8032 if (qdisable (dptr))
8033 return NULL;
8034 *uptr = dptr->units;
8035 return dptr;
8036 }
8037
8038 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8039 if (qdisable (dptr))
8040 continue;
8041 if (dptr->numunits &&
8042 (((nptr = dptr->name) &&
8043 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
8044 ((nptr = dptr->lname) &&
8045 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8046 tptr = cptr + strlen (nptr);
8047 if (sim_isdigit (*tptr)) {
8048 if (qdisable (dptr))
8049 return NULL;
8050 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8051 if (r != SCPE_OK)
8052 *uptr = NULL;
8053 else
8054 *uptr = dptr->units + u;
8055 return dptr;
8056 }
8057 }
8058 for (u = 0; u < dptr->numunits; u++) {
8059 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8060 *uptr = &dptr->units[u];
8061 return dptr;
8062 }
8063 }
8064 }
8065 return NULL;
8066 }
8067
8068
8069
8070
8071
8072
8073
8074 t_stat sim_register_internal_device (DEVICE *dptr)
8075 {
8076 uint32 i;
8077
8078 for (i = 0; (sim_devices[i] != NULL); i++)
8079 if (sim_devices[i] == dptr)
8080 return SCPE_OK;
8081 for (i = 0; i < sim_internal_device_count; i++)
8082 if (sim_internal_devices[i] == dptr)
8083 return SCPE_OK;
8084 ++sim_internal_device_count;
8085 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8086 if (!sim_internal_devices)
8087 {
8088 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8089 __func__, __FILE__, __LINE__);
8090 #if defined(USE_BACKTRACE)
8091 # if defined(SIGUSR2)
8092 (void)raise(SIGUSR2);
8093
8094 # endif
8095 #endif
8096 abort();
8097 }
8098 sim_internal_devices[sim_internal_device_count-1] = dptr;
8099 sim_internal_devices[sim_internal_device_count] = NULL;
8100 return SCPE_OK;
8101 }
8102
8103
8104
8105
8106
8107
8108
8109
8110
8111 DEVICE *find_dev_from_unit (UNIT *uptr)
8112 {
8113 DEVICE *dptr;
8114 uint32 i, j;
8115
8116 if (uptr == NULL)
8117 return NULL;
8118 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8119 for (j = 0; j < dptr->numunits; j++) {
8120 if (uptr == (dptr->units + j))
8121 return dptr;
8122 }
8123 }
8124 for (i = 0; i<sim_internal_device_count; i++) {
8125 dptr = sim_internal_devices[i];
8126 for (j = 0; j < dptr->numunits; j++) {
8127 if (uptr == (dptr->units + j))
8128 return dptr;
8129 }
8130 }
8131 return NULL;
8132 }
8133
8134
8135
8136 t_bool qdisable (DEVICE *dptr)
8137 {
8138 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8139 }
8140
8141
8142
8143
8144
8145
8146
8147
8148
8149
8150
8151
8152
8153 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8154 {
8155 int32 i;
8156 DEVICE *dptr;
8157 REG *rptr, *srptr = NULL;
8158
8159 *gdptr = NULL;
8160 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8161 if (dptr->flags & DEV_DIS)
8162 continue;
8163 if ((rptr = find_reg (cptr, optr, dptr))) {
8164 if (srptr)
8165 return NULL;
8166 srptr = rptr;
8167 *gdptr = dptr;
8168 }
8169 }
8170 return srptr;
8171 }
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8185 {
8186 CONST char *tptr;
8187 REG *rptr;
8188 size_t slnt;
8189
8190 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8191 return NULL;
8192 tptr = cptr;
8193 do {
8194 tptr++;
8195 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8196 slnt = tptr - cptr;
8197 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8198 if ((slnt == strlen (rptr->name)) &&
8199 (strncmp (cptr, rptr->name, slnt) == 0)) {
8200 if (optr != NULL)
8201 *optr = tptr;
8202 return rptr;
8203 }
8204 }
8205 return NULL;
8206 }
8207
8208
8209
8210
8211
8212
8213
8214
8215
8216
8217 int32 get_switches (const char *cptr)
8218 {
8219 int32 sw;
8220
8221 if (*cptr != '-')
8222 return 0;
8223 sw = 0;
8224 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8225 if (sim_isalpha (*cptr) == 0)
8226 return -1;
8227 sw = sw | SWMASK (toupper (*cptr));
8228 }
8229 return sw;
8230 }
8231
8232
8233
8234
8235
8236
8237
8238
8239
8240
8241 CONST char *get_sim_sw (CONST char *cptr)
8242 {
8243 int32 lsw;
8244 char gbuf[CBUFSIZE];
8245
8246 while (*cptr == '-') {
8247 cptr = get_glyph (cptr, gbuf, 0);
8248 lsw = get_switches (gbuf);
8249 if (lsw <= 0)
8250 return NULL;
8251 sim_switches = sim_switches | lsw;
8252 }
8253 return cptr;
8254 }
8255
8256
8257
8258
8259
8260
8261
8262
8263
8264
8265
8266 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8267 {
8268 int32 t;
8269 char gbuf[CBUFSIZE];
8270 CONST char *svptr;
8271 DEVICE *tdptr;
8272 UNIT *tuptr;
8273
8274 sim_switches = 0;
8275 sim_ofile = NULL;
8276 sim_schrptr = NULL;
8277 sim_schaptr = NULL;
8278 sim_stabr.logic = sim_staba.logic = SCH_OR;
8279 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8280 sim_stabr.count = 1;
8281 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8282 if (!sim_stabr.mask)
8283 {
8284 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8285 __func__, __FILE__, __LINE__);
8286 #if defined(USE_BACKTRACE)
8287 # if defined(SIGUSR2)
8288 (void)raise(SIGUSR2);
8289
8290 # endif
8291 #endif
8292 abort();
8293 }
8294 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8295 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8296 if (!sim_stabr.comp)
8297 {
8298 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8299 __func__, __FILE__, __LINE__);
8300 #if defined(USE_BACKTRACE)
8301 # if defined(SIGUSR2)
8302 (void)raise(SIGUSR2);
8303
8304 # endif
8305 #endif
8306 abort();
8307 }
8308 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8309 sim_staba.count = sim_emax;
8310 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8311 if (!sim_staba.mask)
8312 {
8313 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8314 __func__, __FILE__, __LINE__);
8315 #if defined(USE_BACKTRACE)
8316 # if defined(SIGUSR2)
8317 (void)raise(SIGUSR2);
8318
8319 # endif
8320 #endif
8321 abort();
8322 }
8323 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8324 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8325 if (!sim_staba.comp)
8326 {
8327 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8328 __func__, __FILE__, __LINE__);
8329 #if defined(USE_BACKTRACE)
8330 # if defined(SIGUSR2)
8331 (void)raise(SIGUSR2);
8332
8333 # endif
8334 #endif
8335 abort();
8336 }
8337 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8338 if (! sim_dflt_dev)
8339 return NULL;
8340 sim_dfdev = sim_dflt_dev;
8341 sim_dfunit = sim_dfdev->units;
8342 sim_opt_out = 0;
8343 *st = SCPE_OK;
8344 while (*cptr) {
8345 svptr = cptr;
8346 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8347 if (sim_ofile) {
8348 fclose (sim_ofile);
8349 *st = SCPE_ARG;
8350 return NULL;
8351 }
8352 cptr = get_glyph (cptr + 1, gbuf, 0);
8353 sim_ofile = sim_fopen (gbuf, "a");
8354 if (sim_ofile == NULL) {
8355 *st = SCPE_OPENERR;
8356 return NULL;
8357 }
8358 sim_opt_out |= CMD_OPT_OF;
8359 continue;
8360 }
8361 cptr = get_glyph (cptr, gbuf, 0);
8362 if ((t = get_switches (gbuf)) != 0) {
8363 if (t < 0) {
8364 *st = SCPE_INVSW;
8365 return NULL;
8366 }
8367 sim_switches = sim_switches | t;
8368 }
8369 else if ((opt & CMD_OPT_SCH) &&
8370 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8371 sim_schrptr = &sim_stabr;
8372 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8373 sim_opt_out |= CMD_OPT_SCH;
8374 }
8375 else if ((opt & CMD_OPT_DFT) &&
8376 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8377 (tdptr = find_unit (gbuf, &tuptr)) &&
8378 (tuptr != NULL)) {
8379 sim_dfdev = tdptr;
8380 sim_dfunit = tuptr;
8381 sim_opt_out |= CMD_OPT_DFT;
8382 }
8383 else return svptr;
8384 }
8385 return cptr;
8386 }
8387
8388
8389
8390
8391
8392
8393
8394
8395
8396
8397
8398 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8399 {
8400 char *optr = buf;
8401 int32 bit;
8402
8403 (void)memset (buf, 0, bufsize);
8404 if ((sw == 0) || (bufsize < 3))
8405 return buf;
8406 --bufsize;
8407 *optr++ = '-';
8408 for (bit=0; bit <= ('Z'-'A'); bit++)
8409 if (sw & (1 << bit))
8410 if ((size_t)(optr - buf) < bufsize)
8411 *optr++ = 'A' + bit;
8412 return buf;
8413 }
8414
8415
8416
8417
8418
8419
8420
8421
8422
8423
8424
8425
8426 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8427 {
8428 int32 c;
8429 size_t logop, cmpop;
8430 t_value logval, cmpval;
8431 const char *sptr;
8432 CONST char *tptr;
8433 const char logstr[] = "|&^", cmpstr[] = "=!><";
8434
8435 const size_t invalid_op = (size_t) -1;
8436
8437 logval = cmpval = 0;
8438 if (*cptr == 0)
8439 return NULL;
8440
8441 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8442 if ((sptr = strchr (logstr, c))) {
8443 logop = sptr - logstr;
8444 logval = strtotv (cptr, &tptr, radix);
8445 if (cptr == tptr)
8446 return NULL;
8447 cptr = tptr;
8448 }
8449 else if ((sptr = strchr (cmpstr, c))) {
8450 cmpop = sptr - cmpstr;
8451 if (*cptr == '=') {
8452 cmpop = cmpop + strlen (cmpstr);
8453 cptr++;
8454 }
8455 cmpval = strtotv (cptr, &tptr, radix);
8456 if (cptr == tptr)
8457 return NULL;
8458 cptr = tptr;
8459 }
8460 else return NULL;
8461 }
8462 if (schptr->count != 1) {
8463 FREE (schptr->mask);
8464 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8465 FREE (schptr->comp);
8466 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8467 }
8468 if (logop != invalid_op) {
8469 schptr->logic = logop;
8470 schptr->mask[0] = logval;
8471 }
8472 if (cmpop != invalid_op) {
8473 schptr->boolop = cmpop;
8474 schptr->comp[0] = cmpval;
8475 }
8476 schptr->count = 1;
8477 return schptr;
8478 }
8479
8480
8481
8482
8483
8484
8485
8486
8487
8488
8489
8490
8491 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8492 {
8493 int32 c;
8494 size_t logop, cmpop;
8495 t_value *logval, *cmpval;
8496 t_stat reason = SCPE_OK;
8497 CONST char *ocptr = cptr;
8498 const char *sptr;
8499 char gbuf[CBUFSIZE];
8500 const char logstr[] = "|&^", cmpstr[] = "=!><";
8501
8502 const size_t invalid_op = (size_t) -1;
8503
8504 if (*cptr == 0)
8505 return NULL;
8506 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8507 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8508
8509 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8510 if (NULL != (sptr = strchr (logstr, c))) {
8511 logop = sptr - logstr;
8512 cptr = get_glyph (cptr, gbuf, 0);
8513 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8514 if (reason > 0) {
8515 FREE (logval);
8516 FREE (cmpval);
8517 return get_rsearch (ocptr, radix, schptr);
8518 }
8519 }
8520 else if (NULL != (sptr = strchr (cmpstr, c))) {
8521 cmpop = sptr - cmpstr;
8522 if (*cptr == '=') {
8523 cmpop = cmpop + strlen (cmpstr);
8524 cptr++;
8525 }
8526 cptr = get_glyph (cptr, gbuf, 0);
8527 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8528 if (reason > 0) {
8529 FREE (logval);
8530 FREE (cmpval);
8531 return get_rsearch (ocptr, radix, schptr);
8532 }
8533 }
8534 else {
8535 FREE (logval);
8536 FREE (cmpval);
8537 return NULL;
8538 }
8539 }
8540 if (schptr->count != (uint32)(1 - reason)) {
8541 schptr->count = 1 - reason;
8542 FREE (schptr->mask);
8543 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8544 FREE (schptr->comp);
8545 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8546 }
8547 if (logop != invalid_op) {
8548 schptr->logic = logop;
8549 FREE (schptr->mask);
8550 schptr->mask = logval;
8551 }
8552 else {
8553 FREE (logval);
8554 }
8555 if (cmpop != invalid_op) {
8556 schptr->boolop = cmpop;
8557 FREE (schptr->comp);
8558 schptr->comp = cmpval;
8559 }
8560 else {
8561 FREE (cmpval);
8562 }
8563 return schptr;
8564 }
8565
8566
8567
8568
8569
8570
8571
8572
8573
8574
8575 int32 test_search (t_value *values, SCHTAB *schptr)
8576 {
8577 t_value *val = NULL;
8578 int32 i, updown;
8579 int32 ret = 0;
8580
8581 if (schptr == NULL)
8582 return ret;
8583
8584 val = (t_value *)malloc (schptr->count * sizeof (*values));
8585 if (!val)
8586 {
8587 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8588 __func__, __FILE__, __LINE__);
8589 #if defined(USE_BACKTRACE)
8590 # if defined(SIGUSR2)
8591 (void)raise(SIGUSR2);
8592
8593 # endif
8594 #endif
8595 abort();
8596 }
8597 for (i=0; i<(int32)schptr->count; i++) {
8598 val[i] = values[i];
8599 switch (schptr->logic) {
8600
8601 case SCH_OR:
8602 val[i] = val[i] | schptr->mask[i];
8603 break;
8604
8605 case SCH_AND:
8606 val[i] = val[i] & schptr->mask[i];
8607 break;
8608
8609 case SCH_XOR:
8610 val[i] = val[i] ^ schptr->mask[i];
8611 break;
8612 }
8613 }
8614
8615 ret = 1;
8616 if (1) {
8617 updown = -1;
8618 i=schptr->count-1;
8619 }
8620 else {
8621 updown = 1;
8622 i=0;
8623 }
8624 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8625 switch (schptr->boolop) {
8626
8627 case SCH_E: case SCH_EE:
8628 if (val[i] != schptr->comp[i])
8629 ret = 0;
8630 break;
8631
8632 case SCH_N: case SCH_NE:
8633 if (val[i] == schptr->comp[i])
8634 ret = 0;
8635 break;
8636
8637 case SCH_G:
8638 if (val[i] <= schptr->comp[i])
8639 ret = 0;
8640 break;
8641
8642 case SCH_GE:
8643 if (val[i] < schptr->comp[i])
8644 ret = 0;
8645 break;
8646
8647 case SCH_L:
8648 if (val[i] >= schptr->comp[i])
8649 ret = 0;
8650 break;
8651
8652 case SCH_LE:
8653 if (val[i] > schptr->comp[i])
8654 ret = 0;
8655 break;
8656 }
8657 }
8658 FREE (val);
8659 return ret;
8660 }
8661
8662
8663
8664
8665
8666
8667
8668
8669
8670
8671
8672
8673
8674
8675
8676 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8677 {
8678 int32 nodigit;
8679 t_value val;
8680 uint32 c, digit;
8681
8682 *endptr = inptr;
8683 if ((radix < 2) || (radix > 36))
8684 return 0;
8685 while (sim_isspace (*inptr))
8686 inptr++;
8687 val = 0;
8688 nodigit = 1;
8689 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8690 if (sim_islower (c))
8691 c = toupper (c);
8692 if (sim_isdigit (c))
8693 digit = c - (uint32) '0';
8694 else if (radix <= 10)
8695 break;
8696 else digit = c + 10 - (uint32) 'A';
8697 if (digit >= radix)
8698 return 0;
8699 val = (val * radix) + digit;
8700 nodigit = 0;
8701 }
8702 if (nodigit)
8703 return 0;
8704 *endptr = inptr;
8705 return val;
8706 }
8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
8722 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8723 size_t width, uint32 format)
8724 {
8725 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8726 t_value owtest, wtest;
8727 size_t d;
8728 size_t digit;
8729 size_t ndigits;
8730 size_t commas = 0;
8731 char dbuf[MAX_WIDTH + 1];
8732
8733 for (d = 0; d < MAX_WIDTH; d++)
8734 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8735 dbuf[MAX_WIDTH] = 0;
8736 d = MAX_WIDTH;
8737 do {
8738 d = d - 1;
8739 digit = val % radix;
8740 val = val / radix;
8741 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8742 } while ((d > 0) && (val != 0));
8743
8744 switch (format) {
8745 case PV_LEFT:
8746 break;
8747 case PV_RZRO:
8748 wtest = owtest = radix;
8749 ndigits = 1;
8750 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8751 owtest = wtest;
8752 wtest = wtest * radix;
8753 ndigits = ndigits + 1;
8754 }
8755 if ((MAX_WIDTH - (ndigits + commas)) < d)
8756 d = MAX_WIDTH - (ndigits + commas);
8757 break;
8758 }
8759 if (NULL == buffer)
8760 return ((t_stat) strlen(dbuf+d));
8761 *buffer = '\0';
8762 if (width < strlen(dbuf+d))
8763 return SCPE_IOERR;
8764 strcpy(buffer, dbuf+d);
8765 return SCPE_OK;
8766 }
8767
8768 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8769 uint32 width, uint32 format)
8770 {
8771 char dbuf[MAX_WIDTH + 1];
8772
8773 if (!stream)
8774 return sprint_val (NULL, val, radix, width, format);
8775 if (width > MAX_WIDTH)
8776 width = MAX_WIDTH;
8777 sprint_val (dbuf, val, radix, width, format);
8778 if (Fprintf (stream, "%s", dbuf) < 0)
8779 return SCPE_IOERR;
8780 return SCPE_OK;
8781 }
8782
8783 const char *sim_fmt_secs (double seconds)
8784 {
8785 static char buf[60];
8786 char frac[16] = "";
8787 const char *sign = "";
8788 double val = seconds;
8789 double days, hours, mins, secs, msecs, usecs;
8790
8791 if (val == 0.0)
8792 return "";
8793 if (val < 0.0) {
8794 sign = "-";
8795 val = -val;
8796 }
8797 days = floor (val / (24.0*60.0*60.0));
8798 val -= (days * 24.0*60.0*60.0);
8799 hours = floor (val / (60.0*60.0));
8800 val -= (hours * 60.0 * 60.0);
8801 mins = floor (val / 60.0);
8802 val -= (mins * 60.0);
8803 secs = floor (val);
8804 val -= secs;
8805 val *= 1000.0;
8806 msecs = floor (val);
8807 val -= msecs;
8808 val *= 1000.0;
8809 usecs = floor (val+0.5);
8810 if (usecs == 1000.0) {
8811 usecs = 0.0;
8812 msecs += 1;
8813 }
8814 if ((msecs > 0.0) || (usecs > 0.0)) {
8815 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8816 while (frac[strlen (frac) - 1] == '0')
8817 frac[strlen (frac) - 1] = '\0';
8818 if (strlen (frac) == 1)
8819 frac[0] = '\0';
8820 }
8821 if (days > 0)
8822 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8823 sign, days, (days != 1) ? "s" : "", hours, mins,
8824 secs, frac, (days == 1) ? "s" : "");
8825 else
8826 if (hours > 0)
8827 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8828 sign, hours, mins, secs, frac);
8829 else
8830 if (mins > 0)
8831 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8832 sign, mins, secs, frac);
8833 else
8834 if (secs > 0)
8835 (void)sprintf (buf, "%s%.0f%s second",
8836 sign, secs, frac);
8837 else
8838 if (msecs > 0) {
8839 if (usecs > 0)
8840 (void)sprintf (buf, "%s%.0f.%s msec",
8841 sign, msecs, frac+4);
8842 else
8843 (void)sprintf (buf, "%s%.0f msec",
8844 sign, msecs);
8845 }
8846 else
8847 (void)sprintf (buf, "%s%.0f usec",
8848 sign, usecs);
8849 if (0 != strncmp ("1 ", buf, 2))
8850 strcpy (&buf[strlen (buf)], "s");
8851 return buf;
8852 }
8853
8854
8855
8856
8857
8858
8859
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869 t_stat sim_process_event (void)
8870 {
8871 UNIT *uptr;
8872 t_stat reason;
8873 #if defined(TESTING)
8874 cpu_state_t * cpup = _cpup;
8875 #endif
8876
8877 if (stop_cpu)
8878 {
8879 #if defined(WIN_STDIO)
8880 (void)fflush(stdout);
8881 (void)fflush(stderr);
8882 #endif
8883 return SCPE_STOP;
8884 }
8885 UPDATE_SIM_TIME;
8886
8887 if (sim_clock_queue == QUEUE_LIST_END) {
8888 sim_interval = noqueue_time = NOQUEUE_WAIT;
8889 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8890 "Queue Empty New Interval = %d\r\n",
8891 sim_interval);
8892 return SCPE_OK;
8893 }
8894 sim_processing_event = TRUE;
8895 do {
8896 uptr = sim_clock_queue;
8897 sim_clock_queue = uptr->next;
8898 uptr->next = NULL;
8899 sim_interval -= uptr->time;
8900 uptr->time = 0;
8901 if (sim_clock_queue != QUEUE_LIST_END)
8902 sim_interval = sim_clock_queue->time;
8903 else
8904 sim_interval = noqueue_time = NOQUEUE_WAIT;
8905 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8906 "Processing Event for %s\r\n", sim_uname (uptr));
8907 if (uptr->action != NULL)
8908 reason = uptr->action (uptr);
8909 else
8910 reason = SCPE_OK;
8911 } while ((reason == SCPE_OK) &&
8912 (sim_interval <= 0) &&
8913 (sim_clock_queue != QUEUE_LIST_END) &&
8914 (!stop_cpu));
8915
8916 if (sim_clock_queue == QUEUE_LIST_END) {
8917 sim_interval = noqueue_time = NOQUEUE_WAIT;
8918 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8919 "Processing Queue Complete New Interval = %d\r\n",
8920 sim_interval);
8921 }
8922 else
8923 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8924 "Processing Queue Complete New Interval = %d(%s)\r\n",
8925 sim_interval, sim_uname(sim_clock_queue));
8926
8927 if ((reason == SCPE_OK) && stop_cpu)
8928 {
8929 #if defined(WIN_STDIO)
8930 (void)fflush(stdout);
8931 (void)fflush(stderr);
8932 #endif
8933 reason = SCPE_STOP;
8934 }
8935 sim_processing_event = FALSE;
8936 return reason;
8937 }
8938
8939
8940
8941
8942
8943
8944
8945
8946
8947
8948 t_stat sim_activate (UNIT *uptr, int32 event_time)
8949 {
8950 if (uptr->dynflags & UNIT_TMR_UNIT)
8951 return sim_timer_activate (uptr, event_time);
8952 return _sim_activate (uptr, event_time);
8953 }
8954
8955 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8956 {
8957 UNIT *cptr, *prvptr;
8958 int32 accum;
8959 #if defined(TESTING)
8960 cpu_state_t * cpup = _cpup;
8961 #endif
8962
8963 if (sim_is_active (uptr))
8964 return SCPE_OK;
8965 UPDATE_SIM_TIME;
8966
8967 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
8968
8969 prvptr = NULL;
8970 accum = 0;
8971 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8972 if (event_time < (accum + cptr->time))
8973 break;
8974 accum = accum + cptr->time;
8975 prvptr = cptr;
8976 }
8977 if (prvptr == NULL) {
8978 cptr = uptr->next = sim_clock_queue;
8979 sim_clock_queue = uptr;
8980 }
8981 else {
8982 cptr = uptr->next = prvptr->next;
8983 prvptr->next = uptr;
8984 }
8985 uptr->time = event_time - accum;
8986 if (cptr != QUEUE_LIST_END)
8987 cptr->time = cptr->time - uptr->time;
8988 sim_interval = sim_clock_queue->time;
8989 return SCPE_OK;
8990 }
8991
8992
8993
8994
8995
8996
8997
8998
8999
9000
9001 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
9002 {
9003 sim_cancel (uptr);
9004 return _sim_activate (uptr, event_time);
9005 }
9006
9007
9008
9009
9010
9011
9012
9013
9014
9015
9016 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
9017 {
9018 return _sim_activate_after (uptr, usec_delay);
9019 }
9020
9021 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
9022 {
9023 if (sim_is_active (uptr))
9024 return SCPE_OK;
9025 return sim_timer_activate_after (uptr, usec_delay);
9026 }
9027
9028
9029
9030
9031
9032
9033
9034
9035
9036
9037 t_stat sim_cancel (UNIT *uptr)
9038 {
9039 UNIT *cptr, *nptr;
9040 #if defined(TESTING)
9041 cpu_state_t * cpup = _cpup;
9042 #endif
9043
9044 if (sim_clock_queue == QUEUE_LIST_END)
9045 return SCPE_OK;
9046 if (!sim_is_active (uptr))
9047 return SCPE_OK;
9048 UPDATE_SIM_TIME;
9049 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9050 nptr = QUEUE_LIST_END;
9051
9052 if (sim_clock_queue == uptr) {
9053 nptr = sim_clock_queue = uptr->next;
9054 uptr->next = NULL;
9055 }
9056 else {
9057 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9058 if (cptr->next == uptr) {
9059 nptr = cptr->next = uptr->next;
9060 uptr->next = NULL;
9061 break;
9062 }
9063 }
9064 }
9065 if (nptr != QUEUE_LIST_END)
9066 nptr->time += (uptr->next) ? 0 : uptr->time;
9067 if (!uptr->next)
9068 uptr->time = 0;
9069 if (sim_clock_queue != QUEUE_LIST_END)
9070 sim_interval = sim_clock_queue->time;
9071 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9072 if (uptr->next) {
9073 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9074 if (sim_deb)
9075 fclose(sim_deb);
9076 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9077 __func__, __FILE__, __LINE__);
9078 abort ();
9079 }
9080 return SCPE_OK;
9081 }
9082
9083
9084
9085
9086
9087
9088
9089
9090
9091 t_bool sim_is_active (UNIT *uptr)
9092 {
9093 if (uptr->next == NULL)
9094 return FALSE;
9095 else
9096 return TRUE;
9097 }
9098
9099
9100
9101
9102
9103
9104
9105
9106
9107 int32 sim_activate_time (UNIT *uptr)
9108 {
9109 UNIT *cptr;
9110 int32 accum = 0;
9111
9112 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9113 if (cptr == sim_clock_queue) {
9114 if (sim_interval > 0)
9115 accum = accum + sim_interval;
9116 }
9117 else
9118 accum = accum + cptr->time;
9119 if (cptr == uptr)
9120 return accum + 1;
9121 }
9122 return 0;
9123 }
9124
9125
9126
9127
9128
9129
9130
9131
9132 double sim_gtime (void)
9133 {
9134 return sim_time;
9135 }
9136
9137
9138
9139
9140
9141
9142
9143
9144 int32 sim_qcount (void)
9145 {
9146 int32 cnt;
9147 UNIT *uptr;
9148
9149 cnt = 0;
9150 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9151 cnt++;
9152 return cnt;
9153 }
9154
9155
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
9166
9167
9168
9169
9170
9171
9172
9173
9174
9175
9176
9177
9178
9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190 t_stat sim_brk_init (void)
9191 {
9192 int32 i;
9193
9194 for (i=0; i<sim_brk_lnt; i++) {
9195 BRKTAB *bp;
9196 if (sim_brk_tab)
9197 {
9198 bp = sim_brk_tab[i];
9199
9200 while (bp)
9201 {
9202 BRKTAB *bpt = bp->next;
9203
9204 FREE (bp->act);
9205 FREE (bp);
9206 bp = bpt;
9207 }
9208 }
9209 }
9210 if (sim_brk_tab != NULL)
9211 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9212 sim_brk_lnt = SIM_BRK_INILNT;
9213 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9214 if (sim_brk_tab == NULL)
9215 return SCPE_MEM;
9216 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9217 sim_brk_ent = sim_brk_ins = 0;
9218 sim_brk_clract ();
9219 sim_brk_npc (0);
9220 return SCPE_OK;
9221 }
9222
9223
9224
9225 BRKTAB *sim_brk_fnd (t_addr loc)
9226 {
9227 int32 lo, hi, p;
9228 BRKTAB *bp;
9229
9230 if (sim_brk_ent == 0) {
9231 sim_brk_ins = 0;
9232 return NULL;
9233 }
9234 lo = 0;
9235 hi = sim_brk_ent - 1;
9236 do {
9237 p = (lo + hi) >> 1;
9238 bp = sim_brk_tab[p];
9239 if (loc == bp->addr) {
9240 sim_brk_ins = p;
9241 return bp;
9242 }
9243 else if (loc < bp->addr)
9244 hi = p - 1;
9245 else lo = p + 1;
9246 } while (lo <= hi);
9247 if (loc < bp->addr)
9248 sim_brk_ins = p;
9249 else sim_brk_ins = p + 1;
9250 return NULL;
9251 }
9252
9253 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9254 {
9255 BRKTAB *bp = sim_brk_fnd (loc);
9256
9257 while (bp) {
9258 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9259 (bp->typ == btyp))
9260 return bp;
9261 bp = bp->next;
9262 }
9263 return bp;
9264 }
9265
9266
9267
9268 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9269 {
9270 int32 i, t;
9271 BRKTAB *bp, **newp;
9272
9273 if (sim_brk_ins < 0)
9274 return NULL;
9275 if (sim_brk_ent >= sim_brk_lnt) {
9276 t = sim_brk_lnt + SIM_BRK_INILNT;
9277 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9278 if (newp == NULL)
9279 return NULL;
9280 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9281 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9282 FREE (sim_brk_tab);
9283 sim_brk_tab = newp;
9284 sim_brk_lnt = t;
9285 }
9286 if ((sim_brk_ins == sim_brk_ent) ||
9287 ((sim_brk_ins != sim_brk_ent) &&
9288 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9289 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9290 sim_brk_tab[i] = sim_brk_tab[i - 1];
9291 sim_brk_tab[sim_brk_ins] = NULL;
9292 }
9293 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9294 if (!bp)
9295 {
9296 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9297 __func__, __FILE__, __LINE__);
9298 #if defined(USE_BACKTRACE)
9299 # if defined(SIGUSR2)
9300 (void)raise(SIGUSR2);
9301
9302 # endif
9303 #endif
9304 abort();
9305 }
9306 bp->next = sim_brk_tab[sim_brk_ins];
9307 sim_brk_tab[sim_brk_ins] = bp;
9308 if (bp->next == NULL)
9309 sim_brk_ent += 1;
9310 bp->addr = loc;
9311 bp->typ = btyp;
9312 bp->cnt = 0;
9313 bp->act = NULL;
9314 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9315 bp->time_fired[i] = -1.0;
9316 return bp;
9317 }
9318
9319
9320
9321 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9322 {
9323 BRKTAB *bp;
9324
9325 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9326 sw |= sim_brk_dflt;
9327 if (~sim_brk_types & sw) {
9328 char gbuf[CBUFSIZE];
9329
9330 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9331 }
9332 if ((sw & BRK_TYP_DYN_ALL) && act)
9333 return SCPE_ARG;
9334 bp = sim_brk_fnd (loc);
9335 if (!bp)
9336 bp = sim_brk_new (loc, sw);
9337 else {
9338 while (bp && (bp->typ != (uint32)sw))
9339 bp = bp->next;
9340 if (!bp)
9341 bp = sim_brk_new (loc, sw);
9342 }
9343 if (!bp)
9344 return SCPE_MEM;
9345 bp->cnt = ncnt;
9346 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9347 (bp->act != NULL) && (act != NULL)) {
9348 FREE (bp->act);
9349 bp->act = NULL;
9350 }
9351 if ((act != NULL) && (*act != 0)) {
9352 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9353 if (newp == NULL)
9354 return SCPE_MEM;
9355 strncpy (newp, act, CBUFSIZE);
9356 bp->act = newp;
9357 }
9358 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9359 return SCPE_OK;
9360 }
9361
9362
9363
9364 t_stat sim_brk_clr (t_addr loc, int32 sw)
9365 {
9366 BRKTAB *bpl = NULL;
9367 BRKTAB *bp = sim_brk_fnd (loc);
9368 int32 i;
9369
9370 if (!bp)
9371 return SCPE_OK;
9372 if (sw == 0)
9373 sw = SIM_BRK_ALLTYP;
9374
9375 #if !defined(__clang_analyzer__)
9376 while (bp) {
9377 if (bp->typ == (bp->typ & sw)) {
9378 FREE (bp->act);
9379 if (bp == sim_brk_tab[sim_brk_ins])
9380 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9381 else
9382 {
9383 if (bpl)
9384 bpl->next = bp->next;
9385 }
9386 FREE (bp);
9387 bp = bpl;
9388 }
9389 else {
9390 bpl = bp;
9391 bp = bp->next;
9392 }
9393 }
9394 #endif
9395 if (sim_brk_tab[sim_brk_ins] == NULL) {
9396 sim_brk_ent = sim_brk_ent - 1;
9397 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9398 sim_brk_tab[i] = sim_brk_tab[i+1];
9399 }
9400 sim_brk_summ = 0;
9401 for (i = 0; i < sim_brk_ent; i++) {
9402 bp = sim_brk_tab[i];
9403 while (bp) {
9404 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9405 bp = bp->next;
9406 }
9407 }
9408 return SCPE_OK;
9409 }
9410
9411
9412
9413 t_stat sim_brk_clrall (int32 sw)
9414 {
9415 int32 i;
9416
9417 if (sw == 0)
9418 sw = SIM_BRK_ALLTYP;
9419 for (i = 0; i < sim_brk_ent;) {
9420 t_addr loc = sim_brk_tab[i]->addr;
9421 sim_brk_clr (loc, sw);
9422 if ((i < sim_brk_ent) &&
9423 (loc == sim_brk_tab[i]->addr))
9424 ++i;
9425 }
9426 return SCPE_OK;
9427 }
9428
9429
9430
9431 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9432 {
9433 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9434 DEVICE *dptr;
9435 uint32 i, any;
9436
9437 if ((sw == 0) || (sw == SWMASK ('C'))) {
9438 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9439 if (!bp || (!(bp->typ & sw))) {
9440 return SCPE_OK; }
9441 dptr = sim_dflt_dev;
9442 if (dptr == NULL) {
9443 return SCPE_OK; }
9444 if (sw & SWMASK ('C')) {
9445 if (st != NULL) {
9446 (void)fprintf (st, "SET BREAK "); }
9447 } else {
9448 if (sim_vm_fprint_addr) {
9449 sim_vm_fprint_addr
9450 (st, dptr, loc);
9451 } else {
9452 fprint_val
9453 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9454 if (st != NULL) {
9455 (void)fprintf (st, ":\t"); }
9456 }
9457 for (i = any = 0; i < 26; i++) {
9458 if ((bp->typ >> i) & 1) {
9459 if ((sw & SWMASK ('C')) == 0) {
9460 if (any) {
9461 if (st != NULL) {
9462 (void)fprintf (st, ", "); } }
9463 if (st != NULL) {
9464 fputc (i + 'A', st); }
9465 }
9466 } else {
9467 if (st != NULL) {
9468 (void)fprintf (st, "-%c", i + 'A'); }
9469 any = 1;
9470 }
9471 }
9472 if (sw & SWMASK ('C')) {
9473 if (st != NULL) {
9474 (void)fprintf (st, " "); }
9475 if (sim_vm_fprint_addr) {
9476 if (st != NULL) {
9477 sim_vm_fprint_addr (st, dptr, loc); }
9478 } else {
9479 fprint_val
9480 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9481 }
9482 if (bp->cnt > 0) {
9483 if (st != NULL) {
9484 (void)fprintf (st, "[%d]", bp->cnt); } }
9485 if (bp->act != NULL) {
9486 if (st != NULL) {
9487 (void)fprintf (st, "; %s", bp->act); } }
9488 (void)fprintf (st, "\r\n");
9489 return SCPE_OK;
9490 }
9491
9492
9493
9494 t_stat sim_brk_showall (FILE *st, uint32 sw)
9495 {
9496 int32 bit, mask, types;
9497 BRKTAB **bpt;
9498
9499 if ((sw == 0) || (sw == SWMASK ('C')))
9500 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9501 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9502 if (sim_brk_types & (1 << bit))
9503 ++types;
9504 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9505 (void)fprintf (st, "Supported Breakpoint Types:");
9506 for (bit=0; bit <= ('Z'-'A'); bit++)
9507 if (sim_brk_types & (1 << bit))
9508 (void)fprintf (st, " -%c", 'A' + bit);
9509 (void)fprintf (st, "\r\n");
9510 }
9511 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9512 mask = (sw & sim_brk_types);
9513 (void)fprintf (st, "Displaying Breakpoint Types:");
9514 for (bit=0; bit <= ('Z'-'A'); bit++)
9515 if (mask & (1 << bit))
9516 (void)fprintf (st, " -%c", 'A' + bit);
9517 (void)fprintf (st, "\r\n");
9518 }
9519 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9520 BRKTAB *prev = NULL;
9521 BRKTAB *cur = *bpt;
9522 BRKTAB *next;
9523
9524 while (cur) {
9525 next = cur->next;
9526 cur->next = prev;
9527 prev = cur;
9528 cur = next;
9529 }
9530
9531 *bpt = prev;
9532
9533 cur = prev;
9534 while (cur) {
9535 if (cur->typ & sw)
9536 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9537 cur = cur->next;
9538 }
9539
9540 cur = prev;
9541 prev = NULL;
9542 while (cur) {
9543 next = cur->next;
9544 cur->next = prev;
9545 prev = cur;
9546 cur = next;
9547 }
9548
9549 *bpt = prev;
9550 }
9551 return SCPE_OK;
9552 }
9553
9554
9555
9556 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9557 {
9558 BRKTAB *bp;
9559 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9560
9561 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9562 btyp |= BRK_TYP_DYN_ALL;
9563
9564 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9565 double s_gtime = sim_gtime ();
9566
9567 if (bp->time_fired[spc] == s_gtime)
9568 return 0;
9569 bp->time_fired[spc] = s_gtime;
9570 if (--bp->cnt > 0)
9571 return 0;
9572 bp->cnt = 0;
9573 sim_brk_setact (bp->act);
9574 sim_brk_match_type = btyp & bp->typ;
9575 if (bp->typ & BRK_TYP_TEMP)
9576 sim_brk_clr (loc, bp->typ);
9577 sim_brk_match_addr = loc;
9578 return sim_brk_match_type;
9579 }
9580 return 0;
9581 }
9582
9583
9584
9585 CONST char *sim_brk_getact (char *buf, int32 size)
9586 {
9587 char *ep;
9588 size_t lnt;
9589
9590 if (sim_brk_act[sim_do_depth] == NULL)
9591 return NULL;
9592 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9593 sim_brk_act[sim_do_depth]++;
9594 if (*sim_brk_act[sim_do_depth] == 0) {
9595 return sim_brk_clract ();
9596 }
9597 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9598 lnt = ep - sim_brk_act[sim_do_depth];
9599 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9600 buf[lnt] = 0;
9601 sim_brk_act[sim_do_depth] += lnt + 1;
9602 }
9603 else {
9604 strncpy (buf, sim_brk_act[sim_do_depth], size);
9605 sim_brk_clract ();
9606 }
9607 return buf;
9608 }
9609
9610
9611
9612 char *sim_brk_clract (void)
9613 {
9614 FREE (sim_brk_act_buf[sim_do_depth]);
9615 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9616 }
9617
9618
9619
9620 void sim_brk_setact (const char *action)
9621 {
9622 if (action) {
9623 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9624 if (!sim_brk_act_buf[sim_do_depth])
9625 {
9626 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9627 __func__, __FILE__, __LINE__);
9628 #if defined(USE_BACKTRACE)
9629 # if defined(SIGUSR2)
9630 (void)raise(SIGUSR2);
9631
9632 # endif
9633 #endif
9634 abort();
9635 }
9636 strcpy (sim_brk_act_buf[sim_do_depth], action);
9637 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9638 }
9639 else
9640 sim_brk_clract ();
9641 }
9642
9643
9644
9645 void sim_brk_npc (uint32 cnt)
9646 {
9647 uint32 spc;
9648 BRKTAB **bpt, *bp;
9649
9650 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9651 cnt = SIM_BKPT_N_SPC;
9652 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9653 for (bp = *bpt; bp; bp = bp->next) {
9654 for (spc = 0; spc < cnt; spc++)
9655 bp->time_fired[spc] = -1.0;
9656 }
9657 }
9658 }
9659
9660
9661
9662 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9663 {
9664 BRKTAB **bpt, *bp;
9665
9666 if (spc < SIM_BKPT_N_SPC) {
9667 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9668 for (bp = *bpt; bp; bp = bp->next) {
9669 if (bp->typ & btyp)
9670 bp->time_fired[spc] = -1.0;
9671 }
9672 }
9673 }
9674 }
9675
9676 const char *sim_brk_message(void)
9677 {
9678 static char msg[256];
9679 char addr[65] = "";
9680 char buf[32];
9681
9682 msg[0] = '\0';
9683 if (sim_dflt_dev) {
9684 if (sim_vm_sprint_addr)
9685 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9686 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9687 }
9688 if (sim_brk_type_desc) {
9689 BRKTYPTAB *brk = sim_brk_type_desc;
9690
9691 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9692 if (brk->btyp == sim_brk_match_type) {
9693 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9694 break;
9695 }
9696 brk++;
9697 }
9698 }
9699 if (!msg[0])
9700 (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9701 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9702
9703 return msg;
9704 }
9705
9706
9707
9708
9709
9710
9711
9712
9713
9714
9715
9716
9717
9718
9719
9720
9721
9722
9723
9724
9725
9726
9727
9728
9729
9730
9731
9732
9733
9734
9735
9736
9737
9738
9739
9740
9741
9742 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9743 {
9744 char gbuf[CBUFSIZE];
9745 CONST char *tptr;
9746 CONST char *c1ptr;
9747 t_bool after_set = FALSE;
9748 uint32 after;
9749 int32 cnt = 0;
9750 t_stat r;
9751
9752 if (exp == NULL)
9753 return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9754 after = exp->after;
9755
9756 if ((cptr == NULL) || (*cptr == 0))
9757 return SCPE_2FARG;
9758 if (*cptr == '[') {
9759 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9760 if ((cptr == c1ptr) || (*c1ptr != ']'))
9761 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9762 cptr = c1ptr + 1;
9763 while (sim_isspace(*cptr))
9764 ++cptr;
9765 }
9766 tptr = get_glyph (cptr, gbuf, ',');
9767 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9768 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9769 if (r != SCPE_OK)
9770 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9771 after_set = TRUE;
9772 cptr = tptr;
9773 }
9774 if ((*cptr != '"') && (*cptr != '\''))
9775 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9776 cptr = get_glyph_quoted (cptr, gbuf, 0);
9777
9778 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9779 }
9780
9781
9782
9783 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9784 {
9785 char gbuf[CBUFSIZE];
9786
9787 if (NULL == cptr || !*cptr)
9788 return sim_exp_clrall (exp);
9789 if ((*cptr != '"') && (*cptr != '\''))
9790 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9791 cptr = get_glyph_quoted (cptr, gbuf, 0);
9792 if (*cptr != '\0')
9793 return SCPE_2MARG;
9794 return sim_exp_clr (exp, gbuf);
9795 }
9796
9797
9798
9799 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9800 {
9801 size_t i;
9802
9803 if (NULL == exp->rules)
9804 return NULL;
9805 for (i=start_rule; i<exp->size; i++)
9806 if (!strcmp (exp->rules[i].match_pattern, match))
9807 return &exp->rules[i];
9808 return NULL;
9809 }
9810
9811
9812
9813 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9814 {
9815 size_t i;
9816
9817 if (NULL == ep)
9818 return SCPE_OK;
9819 FREE (ep->match);
9820 FREE (ep->match_pattern);
9821 FREE (ep->act);
9822 exp->size -= 1;
9823 #if !defined(__clang_analyzer__)
9824 for (i=ep-exp->rules; i<exp->size; i++)
9825 exp->rules[i] = exp->rules[i+1];
9826 if (exp->size == 0) {
9827 FREE (exp->rules);
9828 exp->rules = NULL;
9829 }
9830 #endif
9831 return SCPE_OK;
9832 }
9833
9834 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9835 {
9836 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9837
9838 while (ep) {
9839 sim_exp_clr_tab (exp, ep);
9840 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9841 }
9842 return SCPE_OK;
9843 }
9844
9845
9846
9847 t_stat sim_exp_clrall (EXPECT *exp)
9848 {
9849 int32 i;
9850
9851 for (i=0; i<exp->size; i++) {
9852 FREE (exp->rules[i].match);
9853 FREE (exp->rules[i].match_pattern);
9854 FREE (exp->rules[i].act);
9855 }
9856 FREE (exp->rules);
9857 exp->rules = NULL;
9858 exp->size = 0;
9859 FREE (exp->buf);
9860 exp->buf = NULL;
9861 exp->buf_size = 0;
9862 exp->buf_ins = 0;
9863 return SCPE_OK;
9864 }
9865
9866
9867
9868 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9869 {
9870 EXPTAB *ep;
9871 uint8 *match_buf;
9872 uint32 match_size;
9873 size_t i;
9874
9875
9876 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9877 if (!match_buf)
9878 return SCPE_MEM;
9879 if (switches & EXP_TYP_REGEX) {
9880 FREE (match_buf);
9881 return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9882 }
9883 else {
9884 if (switches & EXP_TYP_REGEX_I) {
9885 FREE (match_buf);
9886 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9887 }
9888 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9889 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9890 FREE (match_buf);
9891 return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9892 }
9893 }
9894 FREE (match_buf);
9895 for (i=0; i<exp->size; i++) {
9896 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9897 (exp->rules[i].switches & EXP_TYP_PERSIST))
9898 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9899 }
9900 if (after && exp->size)
9901 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9902 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9903 if (!exp->rules)
9904 {
9905 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9906 __func__, __FILE__, __LINE__);
9907 #if defined(USE_BACKTRACE)
9908 # if defined(SIGUSR2)
9909 (void)raise(SIGUSR2);
9910
9911 # endif
9912 #endif
9913 abort();
9914 }
9915 ep = &exp->rules[exp->size];
9916 exp->size += 1;
9917 exp->after = after;
9918 (void)memset (ep, 0, sizeof(*ep));
9919 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9920 if (ep->match_pattern)
9921 strcpy (ep->match_pattern, match);
9922 ep->cnt = cnt;
9923 ep->switches = switches;
9924 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9925 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9926 sim_exp_clr_tab (exp, ep);
9927 FREE (match_buf);
9928 return SCPE_MEM;
9929 }
9930 if (switches & EXP_TYP_REGEX) {
9931 FREE (match_buf);
9932 match_buf = NULL;
9933 }
9934 else {
9935 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9936 sim_decode_quoted_string (match, match_buf, &match_size);
9937 ep->match = match_buf;
9938 ep->size = match_size;
9939 }
9940 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9941 if (!ep->match_pattern)
9942 {
9943 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9944 __func__, __FILE__, __LINE__);
9945 #if defined(USE_BACKTRACE)
9946 # if defined(SIGUSR2)
9947 (void)raise(SIGUSR2);
9948
9949 # endif
9950 #endif
9951 abort();
9952 }
9953 strcpy (ep->match_pattern, match);
9954 if (ep->act) {
9955 FREE (ep->act);
9956 ep->act = NULL;
9957 }
9958 if (act) while (sim_isspace(*act)) ++act;
9959 if ((act != NULL) && (*act != 0)) {
9960 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9961 if (newp == NULL)
9962 return SCPE_MEM;
9963 strcpy (newp, act);
9964 ep->act = newp;
9965 }
9966
9967 for (i=0; i<exp->size; i++) {
9968 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9969 if (compare_size >= exp->buf_size) {
9970 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
9971 exp->buf_size = compare_size + 1;
9972 }
9973 }
9974 return SCPE_OK;
9975 }
9976
9977
9978
9979 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
9980 {
9981 if (!ep)
9982 return SCPE_OK;
9983 (void)fprintf (st, "EXPECT");
9984 if (ep->switches & EXP_TYP_PERSIST)
9985 (void)fprintf (st, " -p");
9986 if (ep->switches & EXP_TYP_CLEARALL)
9987 (void)fprintf (st, " -c");
9988 if (ep->switches & EXP_TYP_REGEX)
9989 (void)fprintf (st, " -r");
9990 if (ep->switches & EXP_TYP_REGEX_I)
9991 (void)fprintf (st, " -i");
9992 (void)fprintf (st, " %s", ep->match_pattern);
9993 if (ep->cnt > 0)
9994 (void)fprintf (st, " [%d]", ep->cnt);
9995 if (ep->act)
9996 (void)fprintf (st, " %s", ep->act);
9997 (void)fprintf (st, "\r\n");
9998 return SCPE_OK;
9999 }
10000
10001 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
10002 {
10003 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
10004
10005 if (exp->buf_size) {
10006 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10007
10008 (void)fprintf (st, "Match Buffer Size: %lld\r\n",
10009 (long long)exp->buf_size);
10010 (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
10011 (long long)exp->buf_ins);
10012 (void)fprintf (st, "Buffer Contents: %s\r\n",
10013 bstr);
10014 FREE (bstr);
10015 }
10016 if (exp->after)
10017 (void)fprintf (st, "Halt After: %lld instructions\r\n",
10018 (long long)exp->after);
10019 if (exp->dptr && exp->dbit)
10020 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10021 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10022 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10023 (void)fprintf (st, "Match Rules:\r\n");
10024 if (!*match)
10025 return sim_exp_showall (st, exp);
10026 if (!ep) {
10027 (void)fprintf (st, "No Rules match '%s'\r\n", match);
10028 return SCPE_ARG;
10029 }
10030 do {
10031 sim_exp_show_tab (st, exp, ep);
10032 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10033 } while (ep);
10034 return SCPE_OK;
10035 }
10036
10037
10038
10039 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
10040 {
10041 size_t i;
10042
10043 for (i=0; i < exp->size; i++)
10044 sim_exp_show_tab (st, exp, &exp->rules[i]);
10045 return SCPE_OK;
10046 }
10047
10048
10049
10050 t_stat sim_exp_check (EXPECT *exp, uint8 data)
10051 {
10052 size_t i;
10053 EXPTAB *ep = NULL;
10054 char *tstr = NULL;
10055 #if defined(TESTING)
10056 cpu_state_t * cpup = _cpup;
10057 #endif
10058
10059 if ((!exp) || (!exp->rules))
10060 return SCPE_OK;
10061
10062 exp->buf[exp->buf_ins++] = data;
10063 exp->buf[exp->buf_ins] = '\0';
10064
10065 for (i=0; i < exp->size; i++) {
10066 ep = &exp->rules[i];
10067 if (ep == NULL)
10068 break;
10069 if (ep->switches & EXP_TYP_REGEX) {
10070 }
10071 else {
10072 if (exp->buf_ins < ep->size) {
10073
10074
10075
10076
10077 if (exp->buf_ins > 0) {
10078 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10079 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10080 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10081
10082 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10083 (long long)exp->buf_ins, estr);
10084 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10085 FREE (estr);
10086 FREE (mstr);
10087 }
10088 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10089 continue;
10090 }
10091 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10092 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10093 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10094
10095 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10096 (long long)exp->buf_size-(ep->size-exp->buf_ins),
10097 (long long)ep->size-exp->buf_ins, estr);
10098 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10099 FREE (estr);
10100 FREE (mstr);
10101 }
10102 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10103 continue;
10104 break;
10105 }
10106 else {
10107 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10108 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10109 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10110
10111 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10112 (long long)exp->buf_ins-ep->size,
10113 (long long)ep->size, estr);
10114 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10115 FREE (estr);
10116 FREE (mstr);
10117 }
10118 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10119 continue;
10120 break;
10121 }
10122 }
10123 }
10124 if (exp->buf_ins == exp->buf_size) {
10125 exp->buf_ins = 0;
10126 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10127 }
10128 if ((ep != NULL) && (i != exp->size)) {
10129 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10130 if (ep->cnt > 0) {
10131 ep->cnt -= 1;
10132 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10133 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10134 }
10135 else {
10136 uint32 after = exp->after;
10137 int32 switches = ep->switches;
10138 if (ep->act && *ep->act) {
10139 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10140 }
10141 else {
10142 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10143 }
10144 sim_brk_setact (ep->act);
10145 if (ep->switches & EXP_TYP_CLEARALL)
10146 sim_exp_clrall (exp);
10147 else {
10148 if (!(ep->switches & EXP_TYP_PERSIST))
10149 sim_exp_clr_tab (exp, ep);
10150 }
10151 sim_activate (&sim_expect_unit,
10152 (switches & EXP_TYP_TIME) ?
10153 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10154 after);
10155 }
10156
10157 exp->buf_ins = 0;
10158 }
10159 if (tstr)
10160 FREE (tstr);
10161 return SCPE_OK;
10162 }
10163
10164
10165
10166 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10167 {
10168 if (snd->extoff != 0) {
10169 if (snd->insoff > snd->extoff)
10170 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10171 snd->insoff -= snd->extoff;
10172 snd->extoff = 0;
10173 }
10174 if (snd->insoff+size > snd->bufsize) {
10175 snd->bufsize = snd->insoff+size;
10176 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10177 if (!snd->buffer)
10178 {
10179 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10180 __func__, __FILE__, __LINE__);
10181 #if defined(USE_BACKTRACE)
10182 # if defined(SIGUSR2)
10183 (void)raise(SIGUSR2);
10184
10185 # endif
10186 #endif
10187 abort();
10188 }
10189 }
10190 memcpy(snd->buffer+snd->insoff, data, size);
10191 snd->insoff += size;
10192 if (delay)
10193 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10194 if (after)
10195 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10196 if (snd->after == 0)
10197 snd->after = snd->delay;
10198 snd->next_time = sim_gtime() + snd->after;
10199 return SCPE_OK;
10200 }
10201
10202
10203 t_stat sim_send_clear (SEND *snd)
10204 {
10205 snd->insoff = 0;
10206 snd->extoff = 0;
10207 return SCPE_OK;
10208 }
10209
10210
10211
10212 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10213 {
10214 if (snd->extoff < snd->insoff) {
10215 (void)fprintf (st, "%lld bytes of pending input Data:\r\n ",
10216 (long long)snd->insoff-snd->extoff);
10217 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10218 (void)fprintf (st, "\r\n");
10219 }
10220 else
10221 (void)fprintf (st, "No Pending Input Data\r\n");
10222 if ((snd->next_time - sim_gtime()) > 0) {
10223 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10224 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10225 (int)(snd->next_time - sim_gtime()),
10226 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10227 else
10228 (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10229 (int)(snd->next_time - sim_gtime()));
10230 }
10231 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10232 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10233 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10234 else
10235 (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10236 (int)snd->delay);
10237 if (snd->dptr && snd->dbit)
10238 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10239 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10240 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10241 return SCPE_OK;
10242 }
10243
10244
10245
10246 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10247 {
10248 #if defined(TESTING)
10249 cpu_state_t * cpup = _cpup;
10250 #endif
10251 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10252 if (sim_gtime() < snd->next_time) {
10253 *stat = SCPE_OK;
10254 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10255 }
10256 else {
10257 char dstr[8] = "";
10258 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10259 snd->next_time = sim_gtime() + snd->delay;
10260 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10261 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10262 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10263 }
10264 return TRUE;
10265 }
10266 return FALSE;
10267 }
10268
10269
10270
10271 const char *sim_error_text (t_stat stat)
10272 {
10273 static char msgbuf[64];
10274
10275 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10276 if (stat == SCPE_OK)
10277 return "No Error";
10278 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10279 return scp_errors[stat-SCPE_BASE].message;
10280 (void)sprintf(msgbuf, "Error %d", stat);
10281 return msgbuf;
10282 }
10283
10284 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10285 {
10286 char gbuf[CBUFSIZE];
10287 size_t cond;
10288
10289 *stat = SCPE_ARG;
10290 cptr = get_glyph (cptr, gbuf, 0);
10291 if (0 == memcmp("SCPE_", gbuf, 5))
10292 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10293 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10294 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10295 cond += SCPE_BASE;
10296 break;
10297 }
10298 if (0 == strcmp(gbuf, "OK"))
10299 cond = SCPE_OK;
10300 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10301 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10302 if (0 == numeric_cond)
10303 return SCPE_ARG;
10304 cond = (t_stat) numeric_cond;
10305 }
10306 if (cond > SCPE_MAX_ERR)
10307 return SCPE_ARG;
10308 *stat = cond;
10309 return SCPE_OK;
10310 }
10311
10312
10313
10314 const char* debug_bstates = "01_^";
10315 char debug_line_prefix[256];
10316 int32 debug_unterm = 0;
10317
10318
10319
10320 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10321 {
10322 static const char *debtab_none = "DEBTAB_ISNULL";
10323 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10324 const char *some_match = NULL;
10325 int32 offset = 0;
10326
10327 if (dptr->debflags == 0)
10328 return debtab_none;
10329
10330 dbits &= dptr->dctrl;
10331
10332
10333
10334 while ((offset < 32) && dptr->debflags[offset].name) {
10335 if (dptr->debflags[offset].mask == dbits)
10336 return dptr->debflags[offset].name;
10337 if (dptr->debflags[offset].mask & dbits)
10338 some_match = dptr->debflags[offset].name;
10339 offset++;
10340 }
10341 return some_match ? some_match : debtab_nomatch;
10342 }
10343
10344
10345
10346 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10347 {
10348 const char* debug_type = get_dbg_verb (dbits, dptr);
10349 char tim_t[32] = "";
10350 char tim_a[32] = "";
10351 char pc_s[64] = "";
10352 struct timespec time_now;
10353
10354 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10355 clock_gettime(CLOCK_REALTIME, &time_now);
10356 if (sim_deb_switches & SWMASK ('R'))
10357 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10358 if (sim_deb_switches & SWMASK ('T')) {
10359 time_t tnow = (time_t)time_now.tv_sec;
10360 struct tm *now = gmtime(&tnow);
10361 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10362 (int)now->tm_hour,
10363 (int)now->tm_min,
10364 (int)now->tm_sec,
10365 (long)(time_now.tv_nsec / 1000000));
10366 }
10367 if (sim_deb_switches & SWMASK ('A')) {
10368 (void)sprintf(tim_t, "%d.%03ld ",
10369 (int)(time_now.tv_sec),
10370 (long)(time_now.tv_nsec / 1000000));
10371 }
10372 }
10373 if (sim_deb_switches & SWMASK ('P')) {
10374 t_value val;
10375
10376 if (sim_vm_pc_value)
10377 val = (*sim_vm_pc_value)();
10378 else
10379 val = get_rval (sim_PC, 0);
10380 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10381 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10382 }
10383 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10384 tim_t, tim_a, sim_gtime(), pc_s,
10385 "", dptr->name, debug_type);
10386 return debug_line_prefix;
10387 }
10388
10389 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10390 {
10391 int32 i, fields, offset;
10392 uint32 value, beforevalue, mask;
10393
10394 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10395 if (bitdefs[fields].offset == 0xffffffff)
10396 bitdefs[fields].offset = offset;
10397 offset += bitdefs[fields].width;
10398 }
10399 for (i = fields-1; i >= 0; i--) {
10400 if (bitdefs[i].name[0] == '\0')
10401 continue;
10402 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10403 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10404 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10405 }
10406 else {
10407 const char *delta = "";
10408 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10409 value = (uint32)((after >> bitdefs[i].offset) & mask);
10410 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10411 if (value < beforevalue)
10412 delta = "_";
10413 if (value > beforevalue)
10414 delta = "^";
10415 if (bitdefs[i].valuenames)
10416 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10417 else
10418 if (bitdefs[i].format) {
10419 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10420 (void)Fprintf(stream, bitdefs[i].format, value);
10421 (void)Fprintf(stream, " ");
10422 }
10423 else
10424 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10425 }
10426 }
10427 }
10428
10429
10430
10431
10432
10433 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10434 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10435 {
10436 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10437 if (!debug_unterm)
10438 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10439 if (header)
10440 (void)fprintf(sim_deb, "%s: ", header);
10441 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10442 if (terminate)
10443 (void)fprintf(sim_deb, "\r\n");
10444 debug_unterm = terminate ? 0 : 1;
10445 }
10446 }
10447 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10448 uint32 before, uint32 after, int terminate)
10449 {
10450 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10451 }
10452
10453
10454 void sim_printf (const char* fmt, ...)
10455 {
10456 char stackbuf[STACKBUFSIZE];
10457 int32 bufsize = sizeof(stackbuf);
10458 char *buf = stackbuf;
10459 int32 len;
10460 va_list arglist;
10461
10462 while (1) {
10463 va_start (arglist, fmt);
10464 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10465 va_end (arglist);
10466
10467
10468
10469 if ((len < 0) || (len >= bufsize-1)) {
10470 if (buf != stackbuf)
10471 FREE (buf);
10472 if (bufsize >= (INT_MAX / 2))
10473 return;
10474 bufsize = bufsize * 2;
10475 if (bufsize < len + 2)
10476 bufsize = len + 2;
10477 buf = (char *) malloc (bufsize);
10478 if (buf == NULL)
10479 return;
10480 buf[bufsize-1] = '\0';
10481 continue;
10482 }
10483 break;
10484 }
10485
10486 if (sim_is_running) {
10487 char *c, *remnant = buf;
10488 while ((c = strchr(remnant, '\n'))) {
10489 if ((c != buf) && (*(c - 1) != '\r'))
10490 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10491 else
10492 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10493 remnant = c + 1;
10494 }
10495 (void)printf("%s", remnant);
10496 }
10497 else
10498 (void)printf("%s", buf);
10499 if (sim_log && (sim_log != stdout))
10500 (void)fprintf (sim_log, "%s", buf);
10501 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10502 (void)fprintf (sim_deb, "%s", buf);
10503
10504 if (buf != stackbuf)
10505 FREE (buf);
10506 }
10507
10508
10509 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10510 {
10511 char stackbuf[STACKBUFSIZE];
10512 size_t bufsize = sizeof(stackbuf);
10513 char *buf = stackbuf;
10514 size_t len;
10515 va_list arglist;
10516 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10517
10518 while (1) {
10519 va_start (arglist, fmt);
10520 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10521 va_end (arglist);
10522
10523
10524
10525 if (len >= bufsize - 1) {
10526 if (buf != stackbuf)
10527 FREE (buf);
10528 bufsize = bufsize * 2;
10529 if (bufsize < len + 2)
10530 bufsize = len + 2;
10531 buf = (char *) malloc (bufsize);
10532 if (buf == NULL)
10533 return SCPE_MEM;
10534 buf[bufsize-1] = '\0';
10535 continue;
10536 }
10537 break;
10538 }
10539
10540 if (sim_do_ocptr[sim_do_depth]) {
10541 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10542 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10543 else {
10544 if (sim_deb)
10545 (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10546 }
10547 }
10548 if (sim_is_running && !inhibit_message) {
10549 char *c, *remnant = buf;
10550 while ((c = strchr(remnant, '\n'))) {
10551 if ((c != buf) && (*(c - 1) != '\r'))
10552 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10553 else
10554 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10555 remnant = c + 1;
10556 }
10557 (void)printf("%s", remnant);
10558 }
10559 else {
10560 if (!inhibit_message)
10561 (void)printf("%s", buf);
10562 }
10563 if (sim_log && (sim_log != stdout) && !inhibit_message)
10564 (void)fprintf (sim_log, "%s", buf);
10565 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10566 (void)fprintf (sim_deb, "%s", buf);
10567
10568 if (buf != stackbuf)
10569 FREE (buf);
10570 return stat | SCPE_NOMESSAGE;
10571 }
10572
10573
10574
10575
10576
10577
10578
10579
10580
10581 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10582 {
10583 DEVICE *dptr = (DEVICE *)vdptr;
10584 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10585 char stackbuf[STACKBUFSIZE];
10586 int32 bufsize = sizeof(stackbuf);
10587 char *buf = stackbuf;
10588 va_list arglist;
10589 int32 i, j, len;
10590 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10591
10592 buf[bufsize-1] = '\0';
10593 while (1) {
10594 va_start (arglist, fmt);
10595 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10596 va_end (arglist);
10597
10598
10599
10600 if ((len < 0) || (len >= bufsize-1)) {
10601 if (buf != stackbuf)
10602 FREE (buf);
10603 if (bufsize >= (INT_MAX / 2))
10604 return;
10605 bufsize = bufsize * 2;
10606 if (bufsize < len + 2)
10607 bufsize = len + 2;
10608 buf = (char *) malloc (bufsize);
10609 if (buf == NULL)
10610 return;
10611 buf[bufsize-1] = '\0';
10612 continue;
10613 }
10614 break;
10615 }
10616
10617
10618
10619 for (i = j = 0; i < len; ++i) {
10620 if ('\n' == buf[i]) {
10621 if (i >= j) {
10622 if ((i != j) || (i == 0)) {
10623 if (debug_unterm)
10624 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10625 else
10626 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10627 }
10628 debug_unterm = 0;
10629 }
10630 j = i + 1;
10631 }
10632 }
10633 if (i > j) {
10634 if (debug_unterm)
10635 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10636 else
10637 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10638 }
10639
10640
10641
10642 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10643 if (buf != stackbuf)
10644 FREE (buf);
10645 }
10646 return;
10647 }
10648
10649 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10650 {
10651 #if defined(TESTING)
10652 cpu_state_t * cpup = _cpup;
10653 #endif
10654 if (sim_deb && (dptr->dctrl & reason)) {
10655 sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10656 if (data && len) {
10657 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10658 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10659 static char hex[] = "0123456789ABCDEF";
10660 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10661 static unsigned char ebcdic2ascii[] = {
10662 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10663 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10664 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10665 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10666 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10667 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10668 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10669 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10670 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10671 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10672 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10673 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10674 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10675 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10676 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10677 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10678 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10679 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10680 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10681 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10682 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10683 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10684 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10685 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10686 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10687 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10688 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10689 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10690 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10691 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10692 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10693 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10694 };
10695
10696 for (i=same=0; i<len; i += 16) {
10697 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10698 ++same;
10699 continue;
10700 }
10701 if (same > 0) {
10702 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10703 (unsigned long int)(i - (16*same)),
10704 (unsigned long int)(i - 1));
10705 same = 0;
10706 }
10707 group = (((len - i) > 16) ? 16 : (len - i));
10708 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10709 eidx = strlen(ebcdicbuf);
10710 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10711 ridx = strlen(rad50buf);
10712 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10713 soff = strlen(strbuf);
10714 for (sidx=oidx=0; sidx<group; ++sidx) {
10715 outbuf[oidx++] = ' ';
10716 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10717 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10718 if (sim_isprint (data[i+sidx]))
10719 strbuf[soff+sidx] = data[i+sidx];
10720 else
10721 strbuf[soff+sidx] = '.';
10722 if (ridx && ((sidx&1) == 0)) {
10723 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10724
10725 if (word >= 64000) {
10726 rad50buf[ridx++] = '|';
10727 rad50buf[ridx++] = '|';
10728 rad50buf[ridx++] = '|';
10729 }
10730 else {
10731 rad50buf[ridx++] = rad50[word/1600];
10732 rad50buf[ridx++] = rad50[(word/40)%40];
10733 rad50buf[ridx++] = rad50[word%40];
10734 }
10735 }
10736 if (eidx) {
10737 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10738 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10739 else
10740 ebcdicbuf[eidx++] = '.';
10741 }
10742 }
10743 outbuf[oidx] = '\0';
10744 strbuf[soff+sidx] = '\0';
10745 ebcdicbuf[eidx] = '\0';
10746 rad50buf[ridx] = '\0';
10747 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10748 (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10749 }
10750 if (same > 0) {
10751 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10752 (unsigned long int)(i-(16*same)),
10753 (unsigned long int)(len-1));
10754 }
10755 }
10756 }
10757 }
10758
10759 int Fprintf (FILE *f, const char* fmt, ...)
10760 {
10761 int ret = 0;
10762 va_list args;
10763
10764 va_start (args, fmt);
10765 ret = vfprintf (f, fmt, args);
10766 va_end (args);
10767 return ret;
10768 }
10769
10770
10771
10772
10773
10774
10775
10776
10777
10778
10779
10780
10781
10782
10783
10784
10785
10786
10787
10788 #define blankch(x) ((x) == ' ' || (x) == '\t')
10789
10790 typedef struct topic {
10791 size_t level;
10792 char *title;
10793 char *label;
10794 struct topic *parent;
10795 struct topic **children;
10796 uint32 kids;
10797 char *text;
10798 size_t len;
10799 uint32 flags;
10800 size_t kidwid;
10801 #define HLP_MAGIC_TOPIC 1
10802 } TOPIC;
10803
10804 static volatile struct {
10805 const char *error;
10806 const char *prox;
10807 size_t block;
10808 size_t line;
10809 } help_where = { "", NULL, 0, 0 };
10810 jmp_buf help_env;
10811
10812 #define FAIL(why,text,here) \
10813 { \
10814 help_where.error = #text; \
10815 help_where.prox = here; \
10816 longjmp ( help_env, (why) ); \
10817 \
10818 }
10819
10820
10821
10822
10823
10824
10825 static void appendText (TOPIC *topic, const char *text, size_t len)
10826 {
10827 char *newt;
10828
10829 if (!len)
10830 return;
10831
10832 newt = (char *)realloc (topic->text, topic->len + len +1);
10833 if (!newt) {
10834 #if !defined(SUNLINT)
10835 FAIL (SCPE_MEM, No memory, NULL);
10836 #endif
10837 }
10838 topic->text = newt;
10839 memcpy (newt + topic->len, text, len);
10840 topic->len +=len;
10841 newt[topic->len] = '\0';
10842 return;
10843 }
10844
10845
10846
10847 static void cleanHelp (TOPIC *topic)
10848 {
10849 TOPIC *child;
10850 size_t i;
10851
10852 FREE (topic->title);
10853 FREE (topic->text);
10854 FREE (topic->label);
10855 for (i = 0; i < topic->kids; i++) {
10856 child = topic->children[i];
10857 cleanHelp (child);
10858 FREE (child);
10859 }
10860 FREE (topic->children);
10861 return;
10862 }
10863
10864
10865
10866
10867 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10868 UNIT *uptr, const char *htext, va_list ap)
10869 {
10870 char *end;
10871 size_t n, ilvl;
10872 #define VSMAX 100
10873 char *vstrings[VSMAX];
10874 size_t vsnum = 0;
10875 char * astrings[VSMAX+1];
10876 size_t asnum = 0;
10877 char *const *hblock;
10878 const char *ep;
10879 t_bool excluded = FALSE;
10880
10881
10882
10883
10884
10885
10886
10887 (void)memset (vstrings, 0, sizeof (vstrings));
10888 (void)memset (astrings, 0, sizeof (astrings));
10889 astrings[asnum++] = (char *) htext;
10890
10891 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10892 help_where.block = hblock - astrings;
10893 help_where.line = 0;
10894 while (*htext) {
10895 const char *start;
10896
10897 help_where.line++;
10898 if (sim_isspace (*htext) || *htext == '+') {
10899 if (excluded) {
10900 while (*htext && *htext != '\n')
10901 htext++;
10902 if (*htext)
10903 ++htext;
10904 continue;
10905 }
10906 ilvl = 1;
10907 appendText (topic, " ", 4);
10908 if (*htext == '+') {
10909 while (*htext == '+') {
10910 ilvl++;
10911 appendText (topic, " ", 4);
10912 htext++;
10913 }
10914 }
10915 while (*htext && *htext != '\n' && sim_isspace (*htext))
10916 htext++;
10917 if (!*htext)
10918 break;
10919 start = htext;
10920 while (*htext) {
10921 if (*htext == '%') {
10922 appendText (topic, start, htext - start);
10923 switch (*++htext) {
10924 case 'U':
10925 if (dptr) {
10926 char buf[129];
10927 n = uptr? uptr - dptr->units: 0;
10928 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10929 appendText (topic, buf, strlen (buf));
10930 }
10931 break;
10932 case 'D':
10933 if (dptr != NULL)
10934 appendText (topic, dptr->name, strlen (dptr->name));
10935 break;
10936 case 'S':
10937 appendText (topic, sim_name, strlen (sim_name));
10938 break;
10939 case '%':
10940 appendText (topic, "%", 1);
10941 break;
10942 case '+':
10943 appendText (topic, "+", 1);
10944 break;
10945 default:
10946 if (sim_isdigit (*htext)) {
10947 n = 0;
10948 while (sim_isdigit (*htext))
10949 n += (n * 10) + (*htext++ - '0');
10950 if (( *htext != 'H' && *htext != 's') ||
10951 n == 0 || n >= VSMAX) {
10952 #if !defined(SUNLINT)
10953 FAIL (SCPE_ARG, Invalid escape, htext);
10954 #endif
10955 }
10956 while (n > vsnum)
10957 vstrings[vsnum++] = va_arg (ap, char *);
10958 start = vstrings[n-1];
10959 if (*htext == 'H') {
10960 if (asnum >= VSMAX) {
10961 #if !defined(SUNLINT)
10962 FAIL (SCPE_ARG, Too many blocks, htext);
10963 #endif
10964 }
10965 astrings[asnum++] = (char *)start;
10966 break;
10967 }
10968 ep = start;
10969 while (*ep) {
10970 if (*ep == '\n') {
10971 ep++;
10972 appendText (topic, start, ep - start);
10973 if (*ep) {
10974 size_t i;
10975 for (i = 0; i < ilvl; i++)
10976 appendText (topic, " ", 4);
10977 }
10978 start = ep;
10979 }
10980 else
10981 ep++;
10982 }
10983 appendText (topic, start, ep-start);
10984 break;
10985 }
10986 #if !defined(SUNLINT)
10987 FAIL (SCPE_ARG, Invalid escape, htext);
10988 #endif
10989 }
10990 start = ++htext;
10991 continue;
10992 }
10993 if (*htext == '\n') {
10994 htext++;
10995 appendText (topic, start, htext - start);
10996 break;
10997 }
10998 htext++;
10999 }
11000 continue;
11001 }
11002 if (sim_isdigit (*htext)) {
11003 TOPIC **children;
11004 TOPIC *newt;
11005 char nbuf[100];
11006
11007 n = 0;
11008 start = htext;
11009 while (sim_isdigit (*htext))
11010 n += (n * 10) + (*htext++ - '0');
11011 if ((htext == start) || !n) {
11012 #if !defined(SUNLINT)
11013 FAIL (SCPE_ARG, Invalid topic heading, htext);
11014 #endif
11015 }
11016 if (n <= topic->level) {
11017 while (n <= topic->level)
11018 topic = topic->parent;
11019 }
11020 else {
11021 if (n > topic->level + 1) {
11022 #if !defined(SUNLINT)
11023 FAIL (SCPE_ARG, Level not contiguous, htext);
11024 #endif
11025 }
11026 }
11027 while (*htext && (*htext != '\n') && sim_isspace (*htext))
11028 htext++;
11029 if (!*htext || (*htext == '\n')) {
11030 #if !defined(SUNLINT)
11031 FAIL (SCPE_ARG, Missing topic name, htext);
11032 #endif
11033 }
11034 start = htext;
11035 while (*htext && (*htext != '\n'))
11036 htext++;
11037 if (start == htext) {
11038 #if !defined(SUNLINT)
11039 FAIL (SCPE_ARG, Null topic name, htext);
11040 #endif
11041 }
11042 excluded = FALSE;
11043 if (*start == '?') {
11044 size_t n = 0;
11045 start++;
11046 while (sim_isdigit (*start))
11047 n += (n * 10) + (*start++ - '0');
11048 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11049 #if !defined(SUNLINT)
11050 FAIL (SCPE_ARG, Invalid parameter number, start);
11051 #endif
11052 }
11053 while (n > vsnum)
11054 vstrings[vsnum++] = va_arg (ap, char *);
11055 end = vstrings[n-1];
11056 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11057 excluded = TRUE;
11058 if (*htext)
11059 htext++;
11060 continue;
11061 }
11062 }
11063 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11064 if (!newt) {
11065 #if !defined(SUNLINT)
11066 FAIL (SCPE_MEM, No memory, NULL);
11067 #endif
11068 }
11069 size_t len = (htext > start) ? (htext - start) : 0;
11070 newt->title = (char *) malloc(len + 1);
11071 if (!newt->title) {
11072 FREE (newt);
11073 #if !defined(SUNLINT)
11074 FAIL (SCPE_MEM, No memory, NULL);
11075 #endif
11076 }
11077 memcpy (newt->title, start, htext - start);
11078 newt->title[htext - start] = '\0';
11079 if (*htext)
11080 htext++;
11081
11082 if (newt->title[0] == '$')
11083 newt->flags |= HLP_MAGIC_TOPIC;
11084
11085 children = (TOPIC **) realloc (topic->children,
11086 (topic->kids +1) * sizeof (TOPIC *));
11087 if (NULL == children) {
11088 FREE (newt->title);
11089 FREE (newt);
11090 #if !defined(SUNLINT)
11091 FAIL (SCPE_MEM, No memory, NULL);
11092 #endif
11093 }
11094 topic->children = children;
11095 topic->children[topic->kids++] = newt;
11096 newt->level = n;
11097 newt->parent = topic;
11098 n = strlen (newt->title);
11099 if (n > topic->kidwid)
11100 topic->kidwid = n;
11101 (void)sprintf (nbuf, ".%u", topic->kids);
11102 n = strlen (topic->label) + strlen (nbuf) + 1;
11103 newt->label = (char *) malloc (n);
11104 if (NULL == newt->label) {
11105 FREE (newt->title);
11106 topic->children[topic->kids -1] = NULL;
11107 FREE (newt);
11108 #if !defined(SUNLINT)
11109 FAIL (SCPE_MEM, No memory, NULL);
11110 #endif
11111 }
11112 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11113 topic = newt;
11114 continue;
11115 }
11116 if (*htext == ';') {
11117 while (*htext && *htext != '\n')
11118 htext++;
11119 continue;
11120 }
11121 #if !defined(SUNLINT)
11122 FAIL (SCPE_ARG, Unknown line type, htext);
11123 #endif
11124 }
11125 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11126 vsnum = 0;
11127 }
11128
11129 return topic;
11130 }
11131
11132
11133
11134
11135
11136 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
11137 {
11138 char *prefix;
11139 char *newp, *newt;
11140
11141 if (topic->level == 0) {
11142 prefix = (char *) calloc (2,1);
11143 if (!prefix) {
11144 #if !defined(SUNLINT)
11145 FAIL (SCPE_MEM, No memory, NULL);
11146 #endif
11147 }
11148 prefix[0] = '\n';
11149 }
11150 else
11151 prefix = helpPrompt (topic->parent, "", oneword);
11152
11153 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11154 strlen (pstring) +1);
11155 if (!newp) {
11156 FREE (prefix);
11157 #if !defined(SUNLINT)
11158 FAIL (SCPE_MEM, No memory, NULL);
11159 #endif
11160 }
11161 strcpy (newp, prefix);
11162 if (topic->children) {
11163 if (topic->level != 0)
11164 strcat (newp, " ");
11165 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11166 topic->title+1: topic->title;
11167 if (oneword) {
11168 char *np = newp + strlen (newp);
11169 while (*newt) {
11170 *np++ = blankch (*newt)? '_' : *newt;
11171 newt++;
11172 }
11173 *np = '\0';
11174 }
11175 else
11176 strcat (newp, newt);
11177 if (*pstring && *pstring != '?')
11178 strcat (newp, " ");
11179 }
11180 strcat (newp, pstring);
11181 FREE (prefix);
11182 return newp;
11183 }
11184
11185 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11186 {
11187 char tbuf[CBUFSIZE];
11188 size_t i, skiplines;
11189 #if defined(_WIN32)
11190 FILE *tmp;
11191 char *tmpnam;
11192
11193 do {
11194 int fd;
11195 tmpnam = _tempnam (NULL, "simh");
11196 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11197 if (fd != -1) {
11198 tmp = _fdopen (fd, "w+");
11199 break;
11200 }
11201 } while (1);
11202 #else
11203 FILE *tmp = tmpfile();
11204 #endif
11205
11206 if (!tmp) {
11207 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11208 xstrerror_l(errno), errno);
11209 return;
11210 }
11211
11212 if (topic->title)
11213 (void)fprintf (st, "%s\r\n", topic->title+1);
11214
11215 skiplines = 0;
11216 if (topic->title) {
11217 if (!strcmp (topic->title+1, "Registers")) {
11218 fprint_reg_help (tmp, dptr) ;
11219 skiplines = 1;
11220 }
11221 else
11222 if (!strcmp (topic->title+1, "Set commands")) {
11223 fprint_set_help (tmp, dptr);
11224 skiplines = 3;
11225 }
11226 else
11227 if (!strcmp (topic->title+1, "Show commands")) {
11228 fprint_show_help (tmp, dptr);
11229 skiplines = 3;
11230 }
11231 }
11232 rewind (tmp);
11233 if (errno) {
11234 (void)fprintf (st, "rewind: error %d\r\n", errno);
11235 }
11236
11237
11238
11239 for (i =0; i < skiplines; i++)
11240 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11241
11242 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11243 if (tbuf[0] != '\n')
11244 fputs (" ", st);
11245 fputs (tbuf, st);
11246 }
11247 fclose (tmp);
11248 #if defined(_WIN32)
11249 remove (tmpnam);
11250 FREE (tmpnam);
11251 #endif
11252 return;
11253 }
11254
11255
11256 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11257 UNIT *uptr, int32 flag,
11258 TOPIC *topic, va_list ap )
11259 {
11260 size_t i;
11261
11262 if (topic->flags & HLP_MAGIC_TOPIC) {
11263 (void)fprintf (st, "\r\n%s ", topic->label);
11264 displayMagicTopic (st, dptr, topic);
11265 }
11266 else
11267 (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11268
11269
11270
11271
11272
11273
11274 if (topic->text)
11275 fputs (topic->text, st);
11276
11277 for (i = 0; i < topic->kids; i++)
11278 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11279
11280 return SCPE_OK;
11281 }
11282
11283 #define HLP_MATCH_AMBIGUOUS (~0u)
11284 #define HLP_MATCH_WILDCARD (~1U)
11285 #define HLP_MATCH_NONE 0
11286 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11287 {
11288 size_t i, match;
11289 char cbuf[CBUFSIZE], *cptr;
11290
11291 if (!strcmp (token, "*"))
11292 return HLP_MATCH_WILDCARD;
11293
11294 match = 0;
11295 for (i = 0; i < topic->kids; i++) {
11296 strcpy (cbuf,topic->children[i]->title +
11297 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11298 cptr = cbuf;
11299 while (*cptr) {
11300 if (blankch (*cptr)) {
11301 *cptr++ = '_';
11302 }
11303 else {
11304 *cptr = (char)toupper (*cptr);
11305 cptr++;
11306 }
11307 }
11308 if (!strcmp (cbuf, token))
11309 return i+1;
11310 if (!strncmp (cbuf, token, strlen (token))) {
11311 if (match)
11312 return HLP_MATCH_AMBIGUOUS;
11313 match = i+1;
11314 }
11315 }
11316 return match;
11317 }
11318
11319
11320
11321 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11322 UNIT *uptr, int32 flag,
11323 const char *help, const char *cptr, va_list ap)
11324 {
11325 TOPIC top;
11326 TOPIC *topic = ⊤
11327 int failed;
11328 size_t match;
11329 size_t i;
11330 const char *p;
11331 t_bool flat_help = FALSE;
11332 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11333
11334 static const char attach_help[] = { " ATTACH" };
11335 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\r\n" };
11336 static const char onecmd_help[] = { "%s help.\r\n" };
11337 static const char help_help[] = {
11338
11339 " To see more HELP information, type the listed subtopic name. To move\r\n"
11340 " up a level, just type <CR>. To review the current subtopic, type \"?\".\r\n"
11341 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11342 };
11343
11344 (void)memset (&top, 0, sizeof(top));
11345 top.parent = ⊤
11346 if ((failed = setjmp (help_env)) != 0) {
11347 (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11348 "Error in block %u line %u: %s\r\n"
11349 "%s%*.*s%s\r\n",
11350 (int)help_where.block, (int)help_where.line, help_where.error,
11351 help_where.prox ? "Near '" : "",
11352 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11353 help_where.prox ? help_where.prox : "",
11354 help_where.prox ? "'" : "");
11355 cleanHelp (&top);
11356 return failed;
11357 }
11358
11359
11360
11361
11362
11363 if (dptr) {
11364 p = dptr->name;
11365 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11366 }
11367 else
11368 p = sim_name;
11369 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11370 if (!top.title)
11371 {
11372 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11373 __func__, __FILE__, __LINE__);
11374 #if defined(USE_BACKTRACE)
11375 # if defined(SIGUSR2)
11376 (void)raise(SIGUSR2);
11377
11378 # endif
11379 #endif
11380 abort();
11381 }
11382 for (i = 0; p[i]; i++ )
11383 top.title[i] = (char)toupper (p[i]);
11384 top.title[i] = '\0';
11385 if (flag & SCP_HELP_ATTACH)
11386 strcpy (top.title+i, attach_help);
11387
11388 top.label = (char *) malloc (sizeof ("1"));
11389 if (!top.label)
11390 {
11391 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11392 __func__, __FILE__, __LINE__);
11393 #if defined(USE_BACKTRACE)
11394 # if defined(SIGUSR2)
11395 (void)raise(SIGUSR2);
11396
11397 # endif
11398 #endif
11399 abort();
11400 }
11401 strcpy (top.label, "1");
11402
11403 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11404
11405 if (flat_help) {
11406 flag |= SCP_HELP_FLAT;
11407 if (sim_ttisatty())
11408 (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11409 else
11410 (void)fprintf (st, "%s help.\r\n", top.title);
11411 }
11412 else
11413 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11414
11415
11416
11417 (void) buildHelp (&top, dptr, uptr, help, ap);
11418
11419
11420
11421 while (cptr && *cptr) {
11422 cptr = get_glyph (cptr, gbuf, 0);
11423 if (!gbuf[0])
11424 break;
11425 if (!strcmp (gbuf, "HELP")) {
11426 (void)fprintf (st, "\r\n");
11427 fputs (help_help, st);
11428 break;
11429 }
11430 match = matchHelpTopicName (topic, gbuf);
11431 if (match == HLP_MATCH_WILDCARD) {
11432 if (dptr)
11433 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11434 cleanHelp (&top);
11435 return SCPE_OK;
11436 }
11437 if (match == HLP_MATCH_AMBIGUOUS) {
11438 (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11439 break;
11440 }
11441 if (match == HLP_MATCH_NONE) {
11442 (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11443 break;
11444 }
11445 topic = topic->children[match-1];
11446 }
11447 cptr = NULL;
11448
11449 if (flat_help) {
11450 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11451 cleanHelp (&top);
11452 return SCPE_OK;
11453 }
11454
11455
11456
11457 while (TRUE) {
11458 char *pstring;
11459 const char *prompt[2] = {"? ", "Subtopic? "};
11460
11461
11462
11463 if (topic->flags & HLP_MAGIC_TOPIC) {
11464 fputc ('\n', st);
11465 displayMagicTopic (st, dptr, topic);
11466 }
11467 else
11468 (void)fprintf (st, "\r\n%s\r\n", topic->title);
11469
11470
11471
11472
11473
11474 if (topic->text)
11475 fputs (topic->text, st);
11476
11477 if (topic->kids) {
11478 size_t w = 0;
11479 char *p;
11480 char tbuf[CBUFSIZE];
11481
11482 (void)fprintf (st, "\r\n Additional information available:\r\n\r\n");
11483 for (i = 0; i < topic->kids; i++) {
11484 strcpy (tbuf, topic->children[i]->title +
11485 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11486 for (p = tbuf; *p; p++) {
11487 if (blankch (*p))
11488 *p = '_';
11489 }
11490 w += 4 + topic->kidwid;
11491 if (w > 80) {
11492 w = 4 + topic->kidwid;
11493 fputc ('\r', st);
11494 fputc ('\n', st);
11495 }
11496 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11497 }
11498 (void)fprintf (st, "\r\n\r\n");
11499 if (flag & SCP_HELP_ONECMD) {
11500 pstring = helpPrompt (topic, "", TRUE);
11501 (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11502 FREE (pstring);
11503 break;
11504 }
11505 }
11506
11507 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11508 break;
11509
11510 reprompt:
11511 if (NULL == cptr || !*cptr) {
11512 if (topic->kids == 0)
11513 topic = topic->parent;
11514 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11515
11516 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11517 FREE (pstring);
11518 if ((cptr != NULL) &&
11519 ((0 == strcmp (cptr, "\x04")) ||
11520 (0 == strcmp (cptr, "\x1A"))))
11521 cptr = NULL;
11522 }
11523
11524 if (NULL == cptr)
11525 break;
11526
11527 cptr = get_glyph (cptr, gbuf, 0);
11528 if (!strcmp (gbuf, "*")) {
11529 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11530 gbuf[0] = '\0';
11531 }
11532 if (!gbuf[0]) {
11533 if (topic->level == 0)
11534 break;
11535 topic = topic->parent;
11536 continue;
11537 }
11538 if (!strcmp (gbuf, "?"))
11539 continue;
11540 if (!strcmp (gbuf, "HELP")) {
11541 fputs (help_help, st);
11542 goto reprompt;
11543 }
11544 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11545 break;
11546
11547
11548
11549 if (!topic->kids) {
11550 (void)fprintf (st, "No additional help at this level.\r\n");
11551 cptr = NULL;
11552 goto reprompt;
11553 }
11554 match = matchHelpTopicName (topic, gbuf);
11555 if (match == HLP_MATCH_AMBIGUOUS) {
11556 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11557 cptr = NULL;
11558 goto reprompt;
11559 }
11560
11561 if (match == HLP_MATCH_NONE) {
11562 (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11563 cptr = NULL;
11564 goto reprompt;
11565 }
11566
11567
11568 topic = topic->children[match-1];
11569 }
11570
11571
11572
11573 cleanHelp (&top);
11574
11575 return SCPE_OK;
11576 }
11577
11578
11579
11580 t_stat scp_help (FILE *st, DEVICE *dptr,
11581 UNIT *uptr, int32 flag,
11582 const char *help, const char *cptr, ...)
11583 {
11584 t_stat r;
11585 va_list ap;
11586
11587 va_start (ap, cptr);
11588 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11589 va_end (ap);
11590
11591 return r;
11592 }
11593
11594 #if defined(_MSC_VER)
11595 # pragma warning(pop)
11596 #endif