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
43 #if !defined(__EXTENSIONS__)
44 # define __EXTENSIONS__
45 #endif
46
47 #if !defined(__STDC_WANT_LIB_EXT1__)
48 # define __STDC_WANT_LIB_EXT1__ 1
49 #endif
50
51 #if !defined(_GNU_SOURCE)
52 # define _GNU_SOURCE
53 #endif
54
55
56
57 #include "sim_defs.h"
58 #include "sim_disk.h"
59 #include "sim_hints.h"
60 #include "sim_tape.h"
61 #include "sim_sock.h"
62 #include "sim_os_mem.h"
63
64 #include <signal.h>
65 #include <ctype.h>
66 #include <time.h>
67 #include <math.h>
68 #include <stddef.h>
69 #if defined(_WIN32)
70 # if !defined(WIN32_LEAN_AND_MEAN)
71 # define WIN32_LEAN_AND_MEAN
72 # endif
73 # if defined(_MSC_VER)
74 # pragma warning(push, 3)
75 # endif
76 # include <direct.h>
77 # include <io.h>
78 # include <fcntl.h>
79 #else
80 # include <unistd.h>
81 # define HAVE_UNISTD 1
82 #endif
83 #include <sys/stat.h>
84 #include <sys/types.h>
85 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
86 # include <sys/resource.h>
87 #endif
88 #include <setjmp.h>
89 #include <stdint.h>
90 #include <limits.h>
91 #if defined(__APPLE__)
92 # include <xlocale.h>
93 #endif
94 #include <locale.h>
95
96 #include "linehistory.h"
97
98 #if defined(__APPLE__)
99 # include <sys/sysctl.h>
100 #endif
101
102 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) )
103 # include <sys/sysinfo.h>
104 # define LINUX_OS
105 #endif
106
107 #include <uv.h>
108
109 #if !defined(HAVE_UNISTD)
110 # undef USE_BACKTRACE
111 #endif
112
113 #if defined(USE_BACKTRACE)
114 # include <string.h>
115 # include <signal.h>
116 #endif
117
118 #if defined(__HAIKU__)
119 # include <OS.h>
120 #endif
121
122 #if !defined(__CYGWIN__)
123 # if !defined(__APPLE__)
124 # if !defined(_AIX)
125 # if !defined(__MINGW32__)
126 # if !defined(__MINGW64__)
127 # if !defined(CROSS_MINGW32)
128 # if !defined(CROSS_MINGW64)
129 # if !defined(_WIN32)
130 # if !defined(__HAIKU__)
131 # if !defined(__QNX__)
132 # include <link.h>
133 # endif
134 # endif
135 # endif
136 # endif
137 # endif
138 # endif
139 # endif
140 # endif
141 # endif
142 #endif
143
144 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
145 # include <windows.h>
146 #endif
147
148 #if defined(__CYGWIN__)
149 # include <windows.h>
150 # include <sys/utsname.h>
151 # include <sys/cygwin.h>
152 # include <cygwin/version.h>
153 #endif
154
155 #define DBG_CTR 0
156
157 #include "../dps8/dps8.h"
158 #include "../dps8/dps8_cpu.h"
159 #include "../dps8/dps8_rt.h"
160 #include "../dps8/dps8_priv.h"
161 #include "../dps8/dps8_topo.h"
162 #include "../dps8/ver.h"
163
164 #include "../dps8/dps8_iom.h"
165 #include "../dps8/dps8_fnp2.h"
166
167 #include "../decNumber/decContext.h"
168 #include "../decNumber/decNumberLocal.h"
169
170 #include "../dps8/dps8_math128.h"
171
172 #include "../dps8/dps8_sir.h"
173
174 #if !defined(__CYGWIN__)
175 # if !defined(__APPLE__)
176 # if !defined(_AIX)
177 # if !defined(__MINGW32__)
178 # if !defined(__MINGW64__)
179 # if !defined(CROSS_MINGW32)
180 # if !defined(CROSS_MINGW64)
181 # if !defined(_WIN32)
182 # if !defined(__HAIKU__)
183 # if !defined(__QNX__)
184 # if !defined(__FILC__)
185 static unsigned int dl_iterate_phdr_callback_called = 0;
186 # endif
187 # endif
188 # endif
189 # endif
190 # endif
191 # endif
192 # endif
193 # endif
194 # endif
195 # endif
196 #endif
197
198 #if defined(MAX)
199 # undef MAX
200 #endif
201 #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
202
203 #if defined(FREE)
204 # undef FREE
205 #endif
206 #define FREE(p) do \
207 { \
208 free((p)); \
209 (p) = NULL; \
210 } while(0)
211
212
213
214 #define SCH_OR 0
215 #define SCH_AND 1
216 #define SCH_XOR 2
217 #define SCH_E 0
218 #define SCH_N 1
219 #define SCH_G 2
220 #define SCH_L 3
221 #define SCH_EE 4
222 #define SCH_NE 5
223 #define SCH_GE 6
224 #define SCH_LE 7
225
226 #define MAX_DO_NEST_LVL 20
227 #define SRBSIZ 1024
228 #define SIM_BRK_INILNT 4096
229 #define SIM_BRK_ALLTYP 0xFFFFFFFB
230
231 #define UPDATE_SIM_TIME \
232 if (1) { \
233 int32 _x; \
234 if (sim_clock_queue == QUEUE_LIST_END) \
235 _x = noqueue_time; \
236 else \
237 _x = sim_clock_queue->time; \
238 sim_time = sim_time + (_x - sim_interval); \
239 sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
240 if (sim_clock_queue == QUEUE_LIST_END) \
241 noqueue_time = sim_interval; \
242 else \
243 sim_clock_queue->time = sim_interval; \
244 } \
245 else \
246 (void)0
247
248 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
249
250 #define SZ_R(rp) \
251 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
252
253 #define SZ_LOAD(sz,v,mb,j) \
254 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
255 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
256 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
257 else v = *(((t_uint64 *) mb) + ((uint32) j));
258
259 #define SZ_STORE(sz,v,mb,j) \
260 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
261 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
262 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
263 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
264
265 #define GET_SWITCHES(cp) \
266 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
267
268 #define GET_RADIX(val,dft) \
269 if (sim_switches & SWMASK ('O')) val = 8; \
270 else if (sim_switches & SWMASK ('D')) val = 10; \
271 else if (sim_switches & SWMASK ('H')) val = 16; \
272 else val = dft;
273
274
275
276
277
278
279 t_bool sim_asynch_enabled = FALSE;
280 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
281 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
282 extern void (*sim_vm_init) (void);
283 extern void (*sim_vm_exit) (void);
284 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
285 void (*sim_vm_post) (t_bool from_scp) = NULL;
286 CTAB *sim_vm_cmd = NULL;
287 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
288 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
289 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
290 t_value (*sim_vm_pc_value) (void) = NULL;
291 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
292 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
293 unsigned int nprocs;
294 unsigned int ncores;
295 bool mlock_failure = false;
296 char* sim_appfilename;
297
298
299
300
301
302 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
303 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
304 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
305 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
306 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
307 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
308 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
309 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
310 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
311 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
312 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
313 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
314 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
315 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
316 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
317 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
318 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
319 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
320 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
321 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
322 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
323 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
324 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
325 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
326 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
327 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
328 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
329 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
330 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
331 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
332 t_stat sim_save (FILE *sfile);
333 t_stat sim_rest (FILE *rfile);
334
335
336
337 t_stat sim_brk_init (void);
338 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
339 t_stat sim_brk_clr (t_addr loc, int32 sw);
340 t_stat sim_brk_clrall (int32 sw);
341 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
342 t_stat sim_brk_showall (FILE *st, uint32 sw);
343 CONST char *sim_brk_getact (char *buf, int32 size);
344 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
345 char *sim_brk_clract (void);
346
347 FILE *stdnul;
348
349
350
351 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
352 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
353 int32 test_search (t_value *val, SCHTAB *schptr);
354 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
355 int32 get_switches (const char *cptr);
356 CONST char *get_sim_sw (CONST char *cptr);
357 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
358 t_value get_rval (REG *rptr, uint32 idx);
359 void put_rval (REG *rptr, uint32 idx, t_value val);
360 void fprint_help (FILE *st);
361 void fprint_stopped (FILE *st, t_stat r);
362 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
363 void fprint_sep (FILE *st, int32 *tokens);
364 char *read_line (char *ptr, int32 size, FILE *stream);
365 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
366 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
367 char *sim_trim_endspc (char *cptr);
368
369
370
371 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
372 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
373 t_bool qdisable (DEVICE *dptr);
374 t_stat attach_err (UNIT *uptr, t_stat stat);
375 t_stat detach_all (int32 start_device, t_bool shutdown);
376 t_stat assign_device (DEVICE *dptr, const char *cptr);
377 t_stat deassign_device (DEVICE *dptr);
378 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
379 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
380 REG *lowr, REG *highr, uint32 lows, uint32 highs);
381 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
382 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
383 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
384 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
385 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
386 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
387 UNIT *uptr, int32 dfltinc);
388 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
389 t_stat step_svc (UNIT *ptr);
390 t_stat expect_svc (UNIT *ptr);
391 t_stat set_on (int32 flag, CONST char *cptr);
392 t_stat set_verify (int32 flag, CONST char *cptr);
393 t_stat set_message (int32 flag, CONST char *cptr);
394 t_stat set_quiet (int32 flag, CONST char *cptr);
395 t_stat set_localopc (int32 flag, CONST char *cptr);
396 t_stat set_asynch (int32 flag, CONST char *cptr);
397 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
398 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
399 void int_handler (int signal);
400 t_stat set_prompt (int32 flag, CONST char *cptr);
401 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
402 t_stat sim_set_environment (int32 flag, CONST char *cptr);
403 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
404
405
406
407 DEVICE *sim_dflt_dev = NULL;
408 UNIT *sim_clock_queue = QUEUE_LIST_END;
409 int32 sim_interval = 0;
410 int32 sim_switches = 0;
411 FILE *sim_ofile = NULL;
412 SCHTAB *sim_schrptr = NULL;
413 SCHTAB *sim_schaptr = NULL;
414 DEVICE *sim_dfdev = NULL;
415 UNIT *sim_dfunit = NULL;
416 DEVICE **sim_internal_devices = NULL;
417 uint32 sim_internal_device_count = 0;
418 int32 sim_opt_out = 0;
419 int32 sim_is_running = 0;
420 t_bool sim_processing_event = FALSE;
421 uint32 sim_brk_summ = 0;
422 uint32 sim_brk_types = 0;
423 BRKTYPTAB *sim_brk_type_desc = NULL;
424 uint32 sim_brk_dflt = 0;
425 uint32 sim_brk_match_type;
426 t_addr sim_brk_match_addr;
427 char *sim_brk_act[MAX_DO_NEST_LVL];
428 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
429 BRKTAB **sim_brk_tab = NULL;
430 int32 sim_brk_ent = 0;
431 int32 sim_brk_lnt = 0;
432 int32 sim_brk_ins = 0;
433 int32 sim_iglock = 0;
434 int32 sim_nolock = 0;
435 int32 sim_quiet = 0;
436 int32 sim_localopc = 1;
437 int32 sim_randompst = 0;
438 int32 sim_randstate = 0;
439 int32 sim_step = 0;
440 int nodist = 0;
441 #if defined(PERF_STRIP)
442 int32 sim_nostate = 1;
443 #else
444 int32 sim_nostate = 0;
445 #endif
446 static double sim_time;
447 static uint32 sim_rtime;
448 static int32 noqueue_time;
449 volatile int32 stop_cpu = 0;
450 t_value *sim_eval = NULL;
451 static t_value sim_last_val;
452 static t_addr sim_last_addr;
453 FILE *sim_log = NULL;
454 FILEREF *sim_log_ref = NULL;
455 FILE *sim_deb = NULL;
456 FILEREF *sim_deb_ref = NULL;
457 int32 sim_deb_switches = 0;
458 struct timespec sim_deb_basetime;
459 char *sim_prompt = NULL;
460 static FILE *sim_gotofile;
461 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];
462 static int32 sim_do_echo = 0;
463 static int32 sim_show_message = 1;
464 static int32 sim_on_inherit = 0;
465 #if !defined(PERF_STRIP)
466 static int32 sim_realtime = 0;
467 #endif
468 static int32 sim_do_depth = 0;
469 uint64_t sim_free_memory = 0;
470
471 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
472 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
473 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
474 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
475 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
476
477 t_stat sim_last_cmd_stat;
478
479 static SCHTAB sim_stabr;
480 static SCHTAB sim_staba;
481
482 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };
483 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) };
484
485 pthread_t main_thread_id;
486
487
488
489 const char save_vercur[] = "V4.1";
490 const char save_ver40[] = "V4.0";
491 const char save_ver35[] = "V3.5";
492 const char save_ver32[] = "V3.2";
493 const char save_ver30[] = "V3.0";
494 const struct scp_error {
495 const char *code;
496 const char *message;
497 } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
498 {{"NXM", "Address space exceeded"},
499 {"UNATT", "Unit not attached"},
500 {"IOERR", "I/O error"},
501 {"CSUM", "Checksum error"},
502 {"FMT", "Format error"},
503 {"NOATT", "Unit not attachable"},
504 {"OPENERR", "File open error"},
505 {"MEM", "Memory exhausted"},
506 {"ARG", "Invalid argument"},
507 {"STEP", "Step expired"},
508 {"UNK", "Unknown command"},
509 {"RO", "Read only argument"},
510 {"INCOMP", "Command not completed"},
511 {"STOP", "Simulation stopped"},
512 {"EXIT", "Goodbye"},
513 {"TTIERR", "Console input I/O error"},
514 {"TTOERR", "Console output I/O error"},
515 {"EOF", "End of file"},
516 {"REL", "Relocation error"},
517 {"NOPARAM", "No settable parameters"},
518 {"ALATT", "Unit already attached"},
519 {"TIMER", "Hardware timer error"},
520 {"SIGERR", "Signal handler setup error"},
521 {"TTYERR", "Console terminal setup error"},
522 {"SUB", "Subscript out of range"},
523 {"NOFNC", "Command not allowed"},
524 {"UDIS", "Unit disabled"},
525 {"NORO", "Read only operation not allowed"},
526 {"INVSW", "Invalid switch"},
527 {"MISVAL", "Missing value"},
528 {"2FARG", "Too few arguments"},
529 {"2MARG", "Too many arguments"},
530 {"NXDEV", "Non-existent device"},
531 {"NXUN", "Non-existent unit"},
532 {"NXREG", "Non-existent register"},
533 {"NXPAR", "Non-existent parameter"},
534 {"NEST", "Nested DO command limit exceeded"},
535 {"IERR", "Internal error"},
536 {"MTRLNT", "Invalid magtape record length"},
537 {"LOST", "Console Telnet connection lost"},
538 {"TTMO", "Console Telnet connection timed out"},
539 {"STALL", "Console Telnet output stall"},
540 {"AFAIL", "Assertion failed"},
541 {"INVREM", "Invalid remote console command"},
542 {"NOTATT", "Not attached"},
543 {"EXPECT", "Expect matched"},
544 {"REMOTE", "Remote console command"},
545 };
546
547 const size_t size_map[] = { sizeof (int8),
548 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
549 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
550 };
551
552 const t_value width_mask[] = { 0,
553 0x1, 0x3, 0x7, 0xF,
554 0x1F, 0x3F, 0x7F, 0xFF,
555 0x1FF, 0x3FF, 0x7FF, 0xFFF,
556 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
557 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
558 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
559 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
560 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
561 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
562 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
563 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
564 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
565 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
566 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
567 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
568 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
569 };
570
571 static const char simh_help[] =
572
573 "1Commands\n"
574 #define HLP_RESET "*Commands Resetting Devices"
575
576 "2Resetting Devices\n"
577 " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\r\n"
578 " simulator to a predefined condition. If the switch \"`-p`\" is specified,\r\n"
579 " the device is reset to its initial power-on state:\r\n\r\n"
580 "++RESET resets all devices\r\n"
581 "++RESET -p power-cycle all devices\r\n"
582 "++RESET ALL resets all devices\r\n"
583 "++RESET <device> resets the specified <device>\r\n\r\n"
584 " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\r\n"
585 " interrupt requests, and returns the device to a quiescent state.\r\n\r\n"
586 " * It does **NOT** clear the main memory or affect associated I/O\r\n"
587 " connections.\r\n"
588 #define HLP_EXAMINE "*Commands Examining_and_Changing_State"
589 #define HLP_IEXAMINE "*Commands Examining_and_Changing_State"
590 #define HLP_DEPOSIT "*Commands Examining_and_Changing_State"
591 #define HLP_IDEPOSIT "*Commands Examining_and_Changing_State"
592
593 "2Examining and Changing State\n"
594 " There are four commands to examine and change state:\r\n\r\n"
595 " * `EXAMINE` (*abbreviated* `E`) examines state\r\n"
596 " * `DEPOSIT` (*abbreviated* `D`) changes state\r\n"
597 " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\r\n"
598 " and allows the user to interactively change it\r\n"
599 " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\r\n"
600 " interactively change state\r\n\r\n"
601 " All four commands take the form:\r\n\r\n"
602 "++command {modifiers} <object list>\r\n\r\n"
603 " The `DEPOSIT` command requires the deposit value at the end of the command.\r\n\r\n"
604 " There are four kinds of modifiers: **switches**, **device/unit name**,\r\n"
605 " **search specifier**, and for `EXAMINE`, **output file**.\r\n\r\n"
606 " * **Switches** have been described previously.\r\n"
607 " * A **device/unit name** identifies the device and unit whose address\r\n"
608 " space is to be examined or modified. If no device is specified, the CPU\r\n"
609 " main memory is selected. If a device but no unit is specified, unit `0`\r\n"
610 " of the specified device is selected automatically.\r\n"
611 " * The **search specifier** provides criteria for testing addresses or\r\n"
612 " registers to see if they should be processed. The search specifier\r\n"
613 " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\r\n"
614 " both, optionally separated by spaces:\r\n\r\n"
615 "++{ < logical op > < value > } < relational op > < value >\r\n\r\n"
616
617 " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\r\n"
618 " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\r\n"
619 " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\r\n"
620 " equal*), \">=\" (*greater than or equal*), \">\" (*greater\r\n"
621 " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\r\n"
622 " * * If any \"<`logical operator`>\" is specified without\r\n"
623 " a \"<`relational operator`>\", it is ignored.\r\n"
624 " * * If any \"<`relational operator`>\" is specified without\r\n"
625 " a \"<`logical operator`>\", no logical operation is performed.\r\n"
626 " * * All comparisons are unsigned.\r\n\r\n"
627 " * The **output file** modifier redirects the command output to a file\r\n"
628 " instead of the console. The **output file** modifier is specified with\r\n"
629 " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\r\n\r\n"
630 " **NOTE**: Modifiers may be specified in any order. If multiple\r\n"
631 " modifiers of the same type are specified, later modifiers override earlier\r\n"
632 " modifiers. If the **device/unit name** comes *after* the search specifier,\r\n"
633 " the search values will interpreted in the *radix of the CPU*, rather than\r\n"
634 " of the device/unit.\r\n\r\n"
635 " The \"<`object list`>\" argument consists of one or more of the following,\r\n"
636 " separated by commas:\r\n\r\n"
637
638 "++register the specified register\r\n"
639 "++register[sub1-sub2] the specified register array locations,\r\n"
640 "++++++++ starting at location sub1 up to and\r\n"
641 "++++++++ including location sub2\r\n"
642 "++register[sub1/length] the specified register array locations,\r\n"
643 "++++++++ starting at location sub1 up to but\r\n"
644 "++++++++ not including sub1+length\r\n"
645 "++register[ALL] all locations in the specified register\r\n"
646 "++++++++ array\r\n"
647 "++register1-register2 all the registers starting at register1\r\n"
648 "++++++++ up to and including register2\r\n"
649 "++address the specified location\r\n"
650 "++address1-address2 all locations starting at address1 up to\r\n"
651 "++++++++ and including address2\r\n"
652 "++address/length all location starting at address up to\r\n"
653 "++++++++ but not including address+length\r\n"
654 "++STATE all registers in the device\r\n"
655 "++ALL all locations in the unit\r\n"
656 "++$ the last value displayed by an EXAMINE\r\n"
657 "++++++++ command interpreted as an address\r\n"
658 "3Switches\n"
659 "4Formatting Control\n"
660 " Switches can be used to control the format of the displayed information:\r\n\r\n"
661
662 "5`-a`\n"
663 " display as ASCII\r\n"
664 "5`-c`\n"
665 " display as character string\r\n"
666 "5`-m`\n"
667 " display as instruction mnemonics\r\n"
668 "5`-o`\n"
669 " display as octal\r\n"
670 "5`-d`\n"
671 " display as decimal\r\n"
672 "5`-h`\n"
673 " display as hexadecimal\r\n\r\n"
674 "3Examples\n"
675 "++ex 1000-1100 examine 1000 to 1100\r\n"
676 "++de PC 1040 set PC to 1040\r\n"
677 "++ie 40-50 interactively examine 40:50\r\n"
678 "++ie >1000 40-50 interactively examine the subset\r\n"
679 "+++++++++ of locations 40:50 that are >1000\r\n"
680 "++ex rx0 50060 examine 50060, RX unit 0\r\n"
681 "++ex rx sbuf[3-6] examine SBUF[3] to SBUF[6] in RX\r\n"
682 "++de all 0 set main memory to 0\r\n"
683 "++de &77>0 0 set all addresses whose low order\r\n"
684 "+++++++++ bits are non-zero to 0\r\n"
685 "++ex -m @memdump.txt 0-7777 dump memory to file\r\n\r\n"
686 " * **NOTE**: To terminate an interactive command, simply type any bad value\r\n"
687 " (*e.g.* `XYZ`) when input is requested.\r\n"
688 #define HLP_EVALUATE "*Commands Evaluating_Instructions"
689
690 "2Evaluating Instructions\n"
691 " The `EVAL` command evaluates a symbolic expression and returns the\r\n"
692 " equivalent numeric value.\r\n\r\n"
693
694 "2Running A Simulated Program\n"
695 #define HLP_RUN "*Commands Running_A_Simulated_Program RUN"
696 "3RUN\n"
697 " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\r\n"
698 " argument, if given, in the PC (program counter), and starts execution.\r\n"
699 " If no argument is given execution starts at the current PC.\r\n"
700 #define HLP_GO "*Commands Running_A_Simulated_Program GO"
701 "3GO\n"
702 " The `GO` command does *not* reset devices, deposits its argument (if\r\n"
703 " given) in the PC, and starts execution. If no argument is given,\r\n"
704 " execution starts at the current PC (program counter).\r\n"
705 #define HLP_CONTINUE "*Commands Running_A_Simulated_Program Continuing_Execution"
706 "3Continuing Execution\n"
707 " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\r\n"
708 " (if execution was stopped, possibly due to hitting a breakpoint) at the\r\n"
709 " current program counter without resetting any devices.\r\n"
710 #define HLP_STEP "*Commands Running_A_Simulated_Program Step_Execution"
711 "3Step Execution\n"
712 " The `STEP` command (*abbreviated* `S`) resumes execution at the current\r\n"
713 " PC for the number of instructions given by its argument. If no argument\r\n"
714 " is supplied, one instruction is executed.\r\n"
715 "4Switches\n"
716 "5`-T`\n"
717 " If the `STEP` command is invoked with the \"`-T`\" switch, the step\r\n"
718 " command will cause execution to run for *microseconds* rather than\r\n"
719 " instructions.\r\n"
720 #define HLP_NEXT "*Commands Running_A_Simulated_Program NEXT"
721 "3NEXT\n"
722 " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\r\n"
723 " for one instruction, attempting to execute *through* subroutine calls.\r\n"
724 " If the next instruction to be executed is *not* a subroutine call, then\r\n"
725 " one instruction is executed.\r\n"
726 #define HLP_BOOT "*Commands Running_A_Simulated_Program Booting_the_system"
727 "3Booting the system\n"
728 " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\r\n"
729 " the device and unit given by its argument. If no unit is supplied,\r\n"
730 " unit `0` is bootstrapped. The specified unit must be `ATTACH`'ed.\r\n\r\n"
731 " When booting Multics, the boot device should always be `iom0`.\r\n"
732 " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\r\n"
733 " into memory and the system will transfer control to the boot record.\r\n\r\n"
734 " **Example**\r\n\r\n"
735 "++; Boot Multics using iom0\r\n"
736 "++boot iom0\r\n\r\n"
737
738 "2Stopping The Simulator\n"
739 " The simulator runs until the simulated hardware encounters an error, or\r\n"
740 " until the user forces a stop condition.\r\n"
741 "3Simulator Detected Stop Conditions\n"
742 " These simulator-detected conditions stop simulation:\r\n\r\n"
743 "++- HALT instruction. If a HALT instruction is decoded, simulation stops.\r\n\r\n"
744 "++- I/O error. If an I/O error occurs during simulation of an I/O\r\n"
745 "+++operation, and the device stop-on-I/O-error flag is set, simulation\r\n"
746 "+++usually stops.\r\n\r\n"
747 "++- Processor condition. Certain processor conditions can stop\r\n"
748 "+++the simulation.\r\n"
749 "3User Specified Stop Conditions\n"
750 " Typing the interrupt character stops simulation. The interrupt character\r\n"
751 " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\r\n"
752 " set to `005` (`^E`).\r\n\r\n"
753
754 #define HLP_BREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
755 #define HLP_NOBREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
756 "4Breakpoints\n"
757 " The simulator offers breakpoint capability for debugging. Users may define\r\n"
758 " breakpoints of different types, identified by letter (for example, `E`\r\n"
759 " for *execution*, `R` for *read*, `W` for *write*, etc).\r\n\r\n"
760 " Associated with each breakpoint is a count and, optionally, one or more\r\n"
761 " actions. Each time a breakpoint occurs, the associated count\r\n"
762 " is *decremented*. If the count is less than or equal to `0`, the breakpoint\r\n"
763 " occurs; otherwise, it is deferred. When the breakpoint occurs, any\r\n"
764 " optional actions are automatically executed.\r\n\r\n"
765 " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\r\n\r\n"
766 "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\r\n\r\n"
767 " If no type is specified, the default breakpoint type (`E`, *execution*) is\r\n"
768 " used. If no address range is specified, the current PC is used. As\r\n"
769 " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\r\n"
770 " range of addresses low-high, or a relative range of address/length.\r\n"
771
772 "5Displaying Breakpoints\n"
773 " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\r\n\r\n"
774 "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\r\n\r\n"
775 " Locations with breakpoints of the specified type are displayed.\r\n\r\n"
776 " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\r\n"
777 " commands which may be subsequently used to establish the same\r\n"
778 " breakpoint(s).\r\n\r\n"
779 "5Removing Breakpoints\n"
780 " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\r\n"
781 "5Examples\n"
782 " The following examples illustrate breakpoint usage:\r\n\r\n"
783 "++BREAK set E break at current PC\r\n"
784 "++BREAK -e 200 set E break at 200\r\n"
785 "++BREAK 2000/2[2] set E breaks at 2000,2001 with count = 2\r\n"
786 "++BREAK 100;EX AC;D MQ 0 set E break at 100 with actions EX AC and\r\n"
787 "+++++++++D MQ 0\r\n"
788 "++BREAK 100; delete action on break at 100\r\n\r\n"
789
790 "2Connecting and Disconnecting Devices\n"
791 " Units are simulated as files on the host file system. Before using any\r\n"
792 " simulated unit, the user must specify the file to be accessed by that unit.\r\n"
793 #define HLP_ATTACH "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
794 "3Attaching devices\n"
795 " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\r\n\r\n"
796 "++ATTACH <unit> <filename>\r\n\r\n"
797 " Some devices have more detailed or specific help available with:\r\n\r\n"
798 "++HELP <device> ATTACH\r\n\r\n"
799 "4Switches\n"
800 "5`-n`\n"
801 " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\r\n"
802 " file will be created when the filename specified does not exist, or an\r\n"
803 " existing file will have it's size truncated to zero, and an appropriate\r\n"
804 " message is printed.\r\n"
805 "5`-e`\n"
806 " If the file does not exist, and the \"`-e`\" switch *was not* specified,\r\n"
807 " a new file is created, and an appropriate message is printed. If\r\n"
808 " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\r\n"
809 " error message is printed.\r\n"
810 "5`-r`\n"
811 " If the \"`-r`\" switch is specified, or the file is write protected by\r\n"
812 " host operating system, `ATTACH` tries to open the file in read only mode.\r\n"
813 " If the file does not exist, or the unit does not support read only\r\n"
814 " operation, an error occurs. Input-only devices, such as card readers, or\r\n"
815 " storage devices with write locking switches, such as disks or tapes,\r\n"
816 " support read only operation - other devices do not. If a file is\r\n"
817 " attached read only, its contents can be examined but not modified.\r\n"
818 "5`-q`\n"
819 " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\r\n"
820 " or opening one read only (\"`-r`\"), the message announcing this fact\r\n"
821 " is suppressed.\r\n"
822 "5`-f`\n"
823 " For simulated magnetic tapes, the `ATTACH` command can specify the format\r\n"
824 " of the attached tape image file:\r\n\r\n"
825 "++ATTACH -f <tape_unit> <format> <filename>\r\n\r\n"
826 " * The currently supported magnetic tape image file formats are:\r\n\r\n"
827 " | | |\r\n"
828 " | ----------------:|:---------------------------------------------------- |\r\n"
829 " | \"**`SIMH`**\" | The **SIMH** / **DPS8M** native portable tape format |\r\n"
830 " | \"**`E11`**\" | The *D Bit* **Ersatz-11** simulator format |\r\n"
831 " | \"**`TPC`**\" | The **TPC** format (*used by _SIMH_ prior to V2.3*) |\r\n"
832 " | \"**`P7B`**\" | The **Paul Pierce** `7`-track tape archive format |\r\n\r\n"
833
834 " * The default tape format can also be specified with the `SET` command\r\n"
835 " prior to using the `ATTACH` command:\r\n\r\n"
836 "++SET <tape_unit> FORMAT=<format>\r\n"
837 "++ATTACH <tape_unit> <filename>\r\n\r\n"
838 " * The format of a currently attached tape image can be displayed with\r\n"
839 " the `SHOW FORMAT` command:\r\n\r\n"
840 "++SHOW <unit> FORMAT\r\n\r\n"
841 " **Examples**\r\n\r\n"
842 " The following example illustrates common `ATTACH` usage:\r\n"
843 "++; Associate the tape image file \"12.8MULTICS.tap\" with the tape0 unit\r\n"
844 "++; in read-only mode, where tape0 corresponds to the first tape device.\r\n"
845 "++ATTACH -r tape0 12.8MULTICS.tap\r\n\r\n"
846 "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\r\n"
847 "++; The disk0 unit corresponds to the first disk device.\r\n"
848 "++ATTACH disk0 root.dsk\r\n\r\n"
849
850 #define HLP_DETACH "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
851 "3Detaching devices\n"
852 " The `DETACH` (*abbreviation* `DET`) command breaks the association between\r\n"
853 " a unit and its backing file or device:\r\n\r\n"
854 "++DETACH ALL Detach all units\r\n"
855 "++DETACH <unit> Detach specified unit\r\n\r\n"
856 " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\r\n"
857 #define HLP_SET "*Commands SET"
858 "2SET\n"
859
860 #define HLP_SET_LOG "*Commands SET Logging"
861 "3Logging\n"
862 " Interactions with the simulator session can be recorded to a log file.\r\n\r\n"
863 "+SET LOG log_file Specify the log destination\r\n"
864 "++++++++ (STDOUT, DEBUG, or filename)\r\n"
865 "+SET NOLOG Disables any currently active logging\r\n"
866 "4Switches\n"
867 "5`-N`\n"
868 " By default, log output is written at the *end* of the specified log file.\r\n"
869 " A new log file can created if the \"`-N`\" switch is used on the command\r\n"
870 " line.\r\n\r\n"
871 "5`-B`\n"
872 " By default, log output is written in *text* mode. The log file can be\r\n"
873 " opened for *binary* mode writing if the \"`-B`\" switch is used on the\r\n"
874 " command line.\r\n"
875 #define HLP_SET_DEBUG "*Commands SET Debug_Messages"
876
877 "3Debug Messages\n"
878 "+SET DEBUG debug_file Specify the debug destination\r\n"
879 "++++++++ (STDOUT, STDERR, LOG, or filename)\r\n"
880 "+SET NODEBUG Disables any currently active debug output\r\n"
881 "4Switches\n"
882 " Debug message output contains a timestamp which indicates the number of\r\n"
883 " simulated instructions which have been executed prior to the debug event.\r\n\r\n"
884 " Debug message output can be enhanced to contain additional, potentially\r\n"
885 " useful information.\r\n\r\n\r\n"
886 " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\r\n"
887 "5`-T`\n"
888 " The \"`-T`\" switch causes debug output to contain a time of day displayed\r\n"
889 " as `hh:mm:ss.msec`.\r\n"
890 "5`-A`\n"
891 " The \"`-A`\" switch causes debug output to contain a time of day displayed\r\n"
892 " as `seconds.msec`.\r\n"
893 "5`-R`\n"
894 " The \"`-R`\" switch causes timing to be relative to the start of debugging.\r\n"
895 "5`-P`\n"
896 " The \"`-P`\" switch adds the output of the PC (program counter) to each\r\n"
897 " debug message.\r\n"
898 "5`-N`\n"
899 " The \"`-N`\" switch causes a new (empty) file to be written to.\r\n"
900 " (The default is to append to an existing debug log file).\r\n"
901 "5`-D`\n"
902 " The \"`-D`\" switch causes data blob output to also display the data\r\n"
903 " as **`RADIX-50`** characters.\r\n"
904 "5`-E`\n"
905 " The \"`-E`\" switch causes data blob output to also display the data\r\n"
906 " as \"**EBCDIC**\" characters.\r\n"
907
908 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
909 "3Environment Variables\n"
910 "+SET ENVIRONMENT NAME=val Set environment variable\r\n"
911 "+SET ENVIRONMENT NAME Clear environment variable\r\n"
912 #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
913 "3Command Status Trap Dispatching\n"
914 "+SET ON Enables error checking command execution\r\n"
915 "+SET NOON Disables error checking command execution\r\n"
916 "+SET ON INHERIT Enables inheritance of ON state and actions\r\n"
917 "+SET ON NOINHERIT Disables inheritance of ON state and actions\r\n"
918 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
919 "3Command Execution Display\n"
920 "+SET VERIFY Enables display of processed script commands\r\n"
921 "+SET VERBOSE Enables display of processed script commands\r\n"
922 "+SET NOVERIFY Disables display of processed script commands\r\n"
923 "+SET NOVERBOSE Disables display of processed script commands\r\n"
924 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
925 "3Command Error Status Display\n"
926 "+SET MESSAGE Re-enables display of script error messages\r\n"
927 "+SET NOMESSAGE Disables display of script error messages\r\n"
928 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
929 "3Command Output Display\n"
930 "+SET QUIET Disables suppression of some messages\r\n"
931 "+SET NOQUIET Re-enables suppression of some messages\r\n"
932 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
933 "3Local Operator Console\n"
934 "+SET LOCALOPC Enables local operator console\r\n"
935 "+SET NOLOCALOPC Disables local operator console\r\n"
936 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
937 "3Command Prompt\n"
938 "+SET PROMPT \"string\" Sets an alternate simulator prompt string\r\n"
939 "3Device and Unit Settings\n"
940 "+SET <dev> OCT|DEC|HEX Set device display radix\r\n"
941 "+SET <dev> ENABLED Enable device\r\n"
942 "+SET <dev> DISABLED Disable device\r\n"
943 "+SET <dev> DEBUG{=arg} Set device debug flags\r\n"
944 "+SET <dev> NODEBUG={arg} Clear device debug flags\r\n"
945 "+SET <dev> arg{,arg...} Set device parameters\r\n"
946 "+SET <unit> ENABLED Enable unit\r\n"
947 "+SET <unit> DISABLED Disable unit\r\n"
948 "+SET <unit> arg{,arg...} Set unit parameters\r\n"
949 "+HELP <dev> SET Displays any device specific SET commands\r\n"
950 " \r\n\r\n"
951 " See the Omnibus documentation for a complete SET command reference.\r\n"
952
953 #define HLP_SHOW "*Commands SHOW"
954 "2SHOW\n"
955 "+SH{OW} B{UILDINFO} Show build-time compilation information\r\n"
956 "+SH{OW} CL{OCKS} Show wall clock and timer information\r\n"
957 "+SH{OW} C{ONFIGURATION} Show simulator configuration\r\n"
958 "+SH{OW} D{EFAULT_BASE_SYSTEM} Show default base system script\r\n"
959 "+SH{OW} DEV{ICES} Show devices\r\n"
960 "+SH{OW} H{INTS} Show configuration hints\r\n"
961 "+SH{OW} M{ODIFIERS} Show SET commands for all devices\r\n"
962 "+SH{OW} O{N} Show ON condition actions\r\n"
963 "+SH{OW} P{ROM} Show CPU ID PROM initialization data\r\n"
964 "+SH{OW} Q{UEUE} Show event queue\r\n"
965 "+SH{OW} S{HOW} Show SHOW commands for all devices\r\n"
966 "+SH{OW} T{IME} Show simulated timer\r\n"
967 "+SH{OW} VE{RSION} Show simulator version\r\n"
968 "+H{ELP} <dev> SHOW Show device-specific SHOW commands\r\n"
969 "+SH{OW} <dev> {arg,...} Show device parameters\r\n"
970 "+SH{OW} <dev> DEBUG Show device debug flags\r\n"
971 "+SH{OW} <dev> MODIFIERS Show device modifiers\r\n"
972 "+SH{OW} <dev> RADIX Show device display radix\r\n"
973 "+SH{OW} <dev> SHOW Show device SHOW commands\r\n"
974 "+SH{OW} <unit> {arg,...} Show unit parameters\r\n\r\n"
975 " See the Omnibus documentation for a complete SHOW command reference.\r\n\r\n"
976 #define HLP_SHOW_CONFIG "*Commands SHOW"
977 #define HLP_SHOW_DEVICES "*Commands SHOW"
978 #define HLP_SHOW_FEATURES "*Commands SHOW"
979 #define HLP_SHOW_QUEUE "*Commands SHOW"
980 #define HLP_SHOW_TIME "*Commands SHOW"
981 #define HLP_SHOW_MODIFIERS "*Commands SHOW"
982 #define HLP_SHOW_NAMES "*Commands SHOW"
983 #define HLP_SHOW_SHOW "*Commands SHOW"
984 #define HLP_SHOW_VERSION "*Commands SHOW"
985 #define HLP_SHOW_BUILDINFO "*Commands SHOW"
986 #define HLP_SHOW_PROM "*Commands SHOW"
987 #define HLP_SHOW_HINTS "*Commands SHOW"
988 #define HLP_SHOW_DBS "*Commands SHOW"
989 #define HLP_SHOW_DEFAULT "*Commands SHOW"
990 #define HLP_SHOW_CONSOLE "*Commands SHOW"
991 #define HLP_SHOW_REMOTE "*Commands SHOW"
992 #define HLP_SHOW_BREAK "*Commands SHOW"
993 #define HLP_SHOW_LOG "*Commands SHOW"
994 #define HLP_SHOW_DEBUG "*Commands SHOW"
995 #define HLP_SHOW_CLOCKS "*Commands SHOW"
996 #define HLP_SHOW_ON "*Commands SHOW"
997 #define HLP_SHOW_SEND "*Commands SHOW"
998 #define HLP_SHOW_EXPECT "*Commands SHOW"
999 #define HLP_HELP "*Commands HELP"
1000
1001 "2HELP\n"
1002 "+H{ELP} Show this message\r\n"
1003 "+H{ELP} <command> Show help for command\r\n"
1004 "+H{ELP} <dev> Show help for device\r\n"
1005 "+H{ELP} <dev> REGISTERS Show help for device register variables\r\n"
1006 "+H{ELP} <dev> ATTACH Show help for device specific ATTACH command\r\n"
1007 "+H{ELP} <dev> SET Show help for device specific SET commands\r\n"
1008 "+H{ELP} <dev> SHOW Show help for device specific SHOW commands\r\n"
1009 "+H{ELP} <dev> <command> Show help for device specific <command> command\r\n"
1010
1011 "2Altering The Simulated Configuration\n"
1012 " The \"SET <device> DISABLED\" command removes a device from the configuration.\r\n"
1013 " A `DISABLED` device is invisible to running programs. The device can still\r\n"
1014 " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\r\n\r\n"
1015 " The \"SET <device> ENABLED\" command restores a disabled device to a\r\n"
1016 " configuration.\r\n\r\n"
1017 " Most multi-unit devices allow units to be enabled or disabled:\r\n\r\n"
1018 "++SET <unit> ENABLED\r\n"
1019 "++SET <unit> DISABLED\r\n\r\n"
1020 " When a unit is disabled, it will not be displayed by SHOW DEVICE.\r\n\r\n"
1021
1022 #define HLP_DO "*Commands Executing_Command_Files Processing_Command_Files"
1023 "2Executing Command Files\n"
1024 "3Processing Command Files\n"
1025 " The simulator can invoke another script file with the \"`DO`\" command:\r\n\r\n"
1026 "++DO <filename> {arguments...} execute commands in specified file\r\n\r\n"
1027 " The \"`DO`\" command allows command files to contain substitutable\r\n"
1028 " arguments. The string \"`%%n`\", where \"`n`\" is a number\r\n"
1029 " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\r\n"
1030 " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\r\n"
1031 " The string \"`%%0`\" is replaced with \"<`filename`>\"\r\n"
1032 " The sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\r\n"
1033 " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\r\n"
1034 " be enclosed in matching single or double quotation marks.\r\n\r\n"
1035 " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\r\n"
1036 " deep.\r\n\r\n"
1037 "4Switches\n"
1038 "5`-v`\n\n"
1039 " If the switch \"`-v`\" is specified, commands in the command file are\r\n"
1040 " echoed *before* they are executed.\r\n\r\n"
1041 "5`-e`\n\n"
1042 " If the switch \"`-e`\" is specified, command processing (including nested\r\n"
1043 " command invocations) will be aborted if any command error is encountered.\r\n"
1044 " (A simulation stop **never** aborts processing; use `ASSERT` to catch\r\n"
1045 " unexpected stops.) Without this switch, all errors except `ASSERT` failures\r\n"
1046 " will be ignored, and command processing will continue.\r\n\r\n"
1047 "5`-o`\n\n"
1048 " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\r\n"
1049 " the calling command file will be inherited by the command file being\r\n"
1050 " invoked.\r\n"
1051 "5`-q`\n\n"
1052 " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\r\n"
1053 " enabled for the called command file, otherwise the *quiet mode* setting\r\n"
1054 " is inherited from the calling context.\r\n"
1055
1056 #define HLP_GOTO "*Commands Executing_Command_Files GOTO"
1057 "3GOTO\n"
1058 " Commands in a command file execute in sequence until either an error\r\n"
1059 " trap occurs (when a command completes with an error status), or when an\r\n"
1060 " explicit request is made to start command execution elsewhere with\r\n"
1061 " the `GOTO` command:\r\n\r\n"
1062 "++GOTO <label>\r\n\r\n"
1063 " * Labels are lines in a command file which the first non-whitespace\r\n"
1064 " character is a \"`:`\".\r\n"
1065 " * The target of a `GOTO` is the first matching label in the current `DO`\r\n"
1066 " command file which is encountered.\r\n\r\n"
1067 " **Example**\r\n\r\n"
1068 " The following example illustrates usage of the `GOTO` command (by\r\n"
1069 " creating an infinite loop):\r\n\r\n"
1070 "++:Label\r\n"
1071 "++:: This is a loop.\r\n"
1072 "++GOTO Label\r\n\r\n"
1073 #define HLP_RETURN "*Commands Executing_Command_Files RETURN"
1074
1075 "3RETURN\n"
1076 " The `RETURN` command causes the current procedure call to be restored to\r\n"
1077 " the calling context, possibly returning a specific return status.\r\n"
1078 " If no return status is specified, the return status from the last command\r\n"
1079 " executed will be returned. The calling context may have `ON` traps defined\r\n"
1080 " which may redirect command flow in that context.\r\n\r\n"
1081 "++RETURN return from command file with last command status\r\n"
1082 "++RETURN {-Q} <status> return from command file with specific status\r\n\r\n"
1083 " * The status return can be any numeric value or one of the standard SCPE_\r\n"
1084 " condition names.\r\n\r\n"
1085 " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\r\n"
1086 " status to be returned, but normal error status message printing to be\r\n"
1087 " suppressed.\r\n\r\n"
1088 " **Condition Names**\r\n\r\n"
1089 " The available standard SCPE_ condition names and their meanings are:\r\n\r\n"
1090 " | Name | Meaning | Name | Meaning |\r\n"
1091 " | ------- | --------------------------------| ------- | ----------------------------------- |\r\n"
1092 " | NXM | Address space exceeded | UNATT | Unit not attached |\r\n"
1093 " | IOERR | I/O error | CSUM | Checksum error |\r\n"
1094 " | FMT | Format error | NOATT | Unit not attachable |\r\n"
1095 " | OPENERR | File open error | MEM | Memory exhausted |\r\n"
1096 " | ARG | Invalid argument | STEP | Step expired |\r\n"
1097 " | UNK | Unknown command | RO | Read only argument |\r\n"
1098 " | INCOMP | Command not completed | STOP | Simulation stopped |\r\n"
1099 " | EXIT | Goodbye | TTIERR | Console input I/O error |\r\n"
1100 " | TTOERR | Console output I/O error | EOF | End of file |\r\n"
1101 " | REL | Relocation error | NOPARAM | No settable parameters |\r\n"
1102 " | ALATT | Unit already attached | TIMER | Hardware timer error |\r\n"
1103 " | SIGERR | Signal handler setup error | TTYERR | Console terminal setup error |\r\n"
1104 " | NOFNC | Command not allowed | UDIS | Unit disabled |\r\n"
1105 " | NORO | Read only operation not allowed | INVSW | Invalid switch |\r\n"
1106 " | MISVAL | Missing value | 2FARG | Too few arguments |\r\n"
1107 " | 2MARG | Too many arguments | NXDEV | Non-existent device |\r\n"
1108 " | NXUN | Non-existent unit | NXREG | Non-existent register |\r\n"
1109 " | NXPAR | Non-existent parameter | NEST | Nested DO command limit exceeded |\r\n"
1110 " | IERR | Internal error | MTRLNT | Invalid magtape record length |\r\n"
1111 " | LOST | Console Telnet connection lost | TTMO | Console Telnet connection timed out |\r\n"
1112 " | STALL | Console Telnet output stall | AFAIL | Assertion failed |\r\n"
1113 " | INVREM | Invalid remote console command | | |\r\n"
1114 "\r\n\r\n"
1115 #define HLP_SHIFT "*Commands Executing_Command_Files Shift_Parameters"
1116 "3Shift Parameters\n"
1117 " Shift the command files positional parameters\r\n"
1118 #define HLP_CALL "*Commands Executing_Command_Files Call_a_subroutine"
1119 "3Call a subroutine\n"
1120 " Control can be transferred to a labeled subroutine using `CALL`.\r\n\r\n"
1121 " **Example**\r\n\r\n"
1122 "++CALL routine\r\n"
1123 "++BYE\r\n"
1124 "++\r\n"
1125 "++:routine\r\n"
1126 "++ECHO routine called\r\n"
1127 "++RETURN\r\n\r\n"
1128 #define HLP_ON "*Commands Executing_Command_Files ON"
1129 "3ON\n"
1130 " The `ON` command performs actions after a condition, or clears a condition.\r\n"
1131 "++ON <condition> <action> Perform action after condition\r\n"
1132 "++ON <condition> Clears action of specified condition\r\n"
1133 #define HLP_PROCEED "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1134 #define HLP_IGNORE "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1135
1136 "3PROCEED or IGNORE\n"
1137 " The `PROCEED` (or `IGNORE`) command does nothing. It is potentially\r\n"
1138 " useful as a placeholder for any `ON` action condition that should be\r\n"
1139 " explicitly ignored, allowing command file execution to continue without\r\n"
1140 " taking any specific action.\r\n"
1141 #define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1142
1143 "3Displaying Arbitrary Text\n"
1144 " The `ECHO` command is a useful way of annotating command files. `ECHO`\r\n"
1145 " prints out its arguments to the console (and to any applicable log file):\r\n\r\n"
1146 "++ECHO <string> Output string to console\r\n\r\n"
1147 " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\r\n"
1148 " This may be used to provide spacing for console messages or log file\r\n"
1149 " output.\r\n"
1150
1151 #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Assertions"
1152 "3Testing Assertions\n"
1153 " The `ASSERT` command tests a simulator state condition and halts command\r\n"
1154 " file execution if the condition is false:\r\n\r\n"
1155 "++ASSERT <Simulator State Expressions>\r\n\r\n"
1156 " * If the indicated expression evaluates to false, the command completes\r\n"
1157 " with an `AFAIL` condition. By default, when a command file encounters a\r\n"
1158 " command which returns the `AFAIL` condition, it will exit the running\r\n"
1159 " command file with the `AFAIL` status to the calling command file. This\r\n"
1160 " behavior can be changed with the `ON` command as well as switches to the\r\n"
1161 " invoking `DO` command.\r\n\r\n"
1162 " **Examples**\r\n\r\n"
1163 " The command file below might be used to bootstrap a hypothetical system\r\n"
1164 " that halts after the initial load from disk. The `ASSERT` command can then\r\n"
1165 " be used to confirm that the load completed successfully by examining the\r\n"
1166 " CPU's \"`A`\" register for the expected value:`\r\n\r\n"
1167 "++; Example INI file\r\n"
1168 "++BOOT\r\n"
1169 "++; A register contains error code; 0 = good boot\r\n"
1170 "++ASSERT A=0\r\n"
1171 "++RUN\r\n\r\n"
1172
1173 " * In the above example, if the \"`A`\" register is *not* `0`,\r\n"
1174 " the \"`ASSERT A=0`\" command will be displayed to the user, and the\r\n"
1175 " command file will be aborted with an \"`Assertion failed`\" message.\r\n"
1176 " Otherwise, the command file will continue to bring up the system.\r\n\r\n"
1177 " * See the **`IF`** command documentation for more information and details\r\n"
1178 " regarding simulator state expressions.\r\n\r\n"
1179 #define HLP_IF "*Commands Executing_Command_Files Testing_Conditions"
1180 "3Testing Conditions\n"
1181 " The `IF` command tests a simulator state condition and executes additional\r\n"
1182 " commands if the condition is true:\r\n\r\n"
1183 "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\r\n\r\n"
1184 " **Examples**\r\n\r\n"
1185 " The command file below might be used to bootstrap a hypothetical system\r\n"
1186 " that halts after the initial load from disk. The `IF` command can then\r\n"
1187 " be used to confirm that the load completed successfully by examining the\r\n"
1188 " CPU's \"`A`\" register for an expected value:\r\n\r\n"
1189 "++; Example INI file\r\n"
1190 "++BOOT\r\n"
1191 "++; A register contains error code; 0 = good boot\r\n"
1192 "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\r\n"
1193 "++RUN\r\n\r\n"
1194
1195 " * In the above example, if the \"`A`\" register is *not* `0`, the\r\n"
1196 " message \"`Boot failed - Failure Code `\" will be displayed, the contents\r\n"
1197 " of the \"`A`\" register will be displayed, and the command file will be\r\n"
1198 " aborted with an \"`Assertion failed`\" message. Otherwise, the command\r\n"
1199 " file will continue to bring up the system.\r\n"
1200 "4Conditional Expressions\n"
1201 " The `IF` and `ASSERT` commands evaluate the following two different forms\r\n"
1202 " of conditional expressions.\r\n\r\n"
1203 "5Simulator State Expressions\n"
1204 " \r\n \r\n"
1205 " The values of simulator registers can be evaluated with:\r\n\r\n"
1206 "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\r\n\r\n"
1207 " * If \"<`dev`>\" is not specified, `CPU` is assumed. \"<`reg`>\" is a\r\n"
1208 " register belonging to the indicated device.\r\n"
1209 " * The \"<`addr`>\" is an address in the address space of the indicated\r\n"
1210 " device.\r\n"
1211 " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\r\n"
1212 " the same as those used for \"search specifiers\" by the `EXAMINE` and\r\n"
1213 " `DEPOSIT` commands.\r\n"
1214 " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\r\n"
1215 " not in the radix for the device when referencing a register; when an\r\n"
1216 " address is referenced the device radix is used as the default.\r\n\r\n"
1217 " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\r\n"
1218 " register value is first altered as indicated. The result is then compared\r\n"
1219 " to the \"<`value`>\" via the \"<`conditional-op`>\".\r\n"
1220 " * * If the result is *true*, the command(s) are executed before proceeding\r\n"
1221 " to the next line in the command file.\r\n"
1222 " * * If the result is *false*, the next command in the command file is\r\n"
1223 " processed.\r\n\r\n"
1224 "5String Comparison Expressions\n"
1225 " \r\n \r\n"
1226 " String Values can be compared with:\r\n\r\n"
1227 "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\r\n\r\n"
1228 " * The \"`-i`\" switch, if present, causes a comparison to be case\r\n"
1229 " insensitive.\r\n"
1230 " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\r\n"
1231 " values which may have environment variables substituted as desired.\r\n"
1232 " * The \"<`compare-op`>\" may be one of:\r\n\r\n"
1233 " | | |\r\n"
1234 " | --------------:|:---------------------- |\r\n"
1235 " | \"**`==`**\" | equal |\r\n"
1236 " | \"**`EQU`**\" | equal |\r\n"
1237 " | \"**`!=`**\" | not equal |\r\n"
1238 " | \"**`NEQ`**\" | not equal |\r\n"
1239 " | \"**<**\" | less than |\r\n"
1240 " | \"**`LSS`**\" | less than |\r\n"
1241 " | \"**<=**\" | less than or equal |\r\n"
1242 " | \"**`LEQ`**\" | less than or equal |\r\n"
1243 " | \"**>**\" | greater than |\r\n"
1244 " | \"**`GTR`**\" | greater than |\r\n"
1245 " | \"**>=**\" | greater than or equal |\r\n"
1246 " | \"**`GEQ`**\" | greater than or equal |\r\n"
1247 " * **NOTE**: Comparisons are *generic*. This means that if\r\n"
1248 " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\r\n"
1249 " digits, then the strings are converted to numbers and a numeric\r\n"
1250 " comparison is performed. For example, the comparison\r\n"
1251 " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\r\n"
1252
1253 #define HLP_EXIT "*Commands Exiting_the_Simulator"
1254 "2Exiting the Simulator\n"
1255 " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\r\n"
1256 " returning control to the host operating system.\r\n"
1257
1258 #define HLP_SPAWN "*Commands Executing_System_Commands"
1259 "2Executing System Commands\n"
1260 " * The simulator can execute host operating system commands with\r\n"
1261 " the \"`!`\" (*spawn*) command.\r\n\r\n"
1262 " | | |\r\n"
1263 " |:----------------------- |:------------------------------------------- |\r\n"
1264 " | \"**`!`**\" | Spawn the hosts default command interpreter |\r\n"
1265 " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\r\n\r\n"
1266 " * **NOTE**: The *exit status* from the command which was executed is set\r\n"
1267 " as the *command completion status* for the \"`!`\" command. This may\r\n"
1268 " influence any enabled `ON` condition traps.\r\n" ;
1269
1270
1271 static CTAB cmd_table[] = {
1272 { "RESET", &reset_cmd, 0, HLP_RESET },
1273 { "EXAMINE", &exdep_cmd, EX_E, HLP_EXAMINE },
1274 { "IEXAMINE", &exdep_cmd, EX_E+EX_I, HLP_IEXAMINE },
1275 { "DEPOSIT", &exdep_cmd, EX_D, HLP_DEPOSIT },
1276 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, HLP_IDEPOSIT },
1277 { "EVALUATE", &eval_cmd, 0, HLP_EVALUATE },
1278 { "RUN", &run_cmd, RU_RUN, HLP_RUN, NULL, &run_cmd_message },
1279 { "GO", &run_cmd, RU_GO, HLP_GO, NULL, &run_cmd_message },
1280 { "STEP", &run_cmd, RU_STEP, HLP_STEP, NULL, &run_cmd_message },
1281 { "NEXT", &run_cmd, RU_NEXT, HLP_NEXT, NULL, &run_cmd_message },
1282 { "CONTINUE", &run_cmd, RU_CONT, HLP_CONTINUE, NULL, &run_cmd_message },
1283 { "BOOT", &run_cmd, RU_BOOT, HLP_BOOT, NULL, &run_cmd_message },
1284 { "BREAK", &brk_cmd, SSH_ST, HLP_BREAK },
1285 { "NOBREAK", &brk_cmd, SSH_CL, HLP_NOBREAK },
1286 { "ATTACH", &attach_cmd, 0, HLP_ATTACH },
1287 { "DETACH", &detach_cmd, 0, HLP_DETACH },
1288 { "EXIT", &exit_cmd, 0, HLP_EXIT },
1289 { "QUIT", &exit_cmd, 0, NULL },
1290 { "BYE", &exit_cmd, 0, NULL },
1291 { "SET", &set_cmd, 0, HLP_SET },
1292 { "SHOW", &show_cmd, 0, HLP_SHOW },
1293 { "DO", &do_cmd, 1, HLP_DO },
1294 { "GOTO", &goto_cmd, 1, HLP_GOTO },
1295 { "RETURN", &return_cmd, 0, HLP_RETURN },
1296 { "SHIFT", &shift_cmd, 0, HLP_SHIFT },
1297 { "CALL", &call_cmd, 0, HLP_CALL },
1298 { "ON", &on_cmd, 0, HLP_ON },
1299 { "IF", &assert_cmd, 0, HLP_IF },
1300 { "PROCEED", &noop_cmd, 0, HLP_PROCEED },
1301 { "IGNORE", &noop_cmd, 0, HLP_IGNORE },
1302 { "ECHO", &echo_cmd, 0, HLP_ECHO },
1303 { "ASSERT", &assert_cmd, 1, HLP_ASSERT },
1304 { "SEND", &send_cmd, 0 },
1305 { "EXPECT", &expect_cmd, 1 },
1306 { "NOEXPECT", &expect_cmd, 0 },
1307 { "!", &spawn_cmd, 0, HLP_SPAWN },
1308 { "HELP", &help_cmd, 0, HLP_HELP },
1309 { NULL, NULL, 0 }
1310 };
1311
1312 static CTAB set_glob_tab[] = {
1313 { "CONSOLE", &sim_set_console, 0 },
1314 { "REMOTE", &sim_set_remote_console, 0 },
1315 { "BREAK", &brk_cmd, SSH_ST },
1316 { "NOBREAK", &brk_cmd, SSH_CL },
1317 { "TELNET", &sim_set_telnet, 0 },
1318 { "NOTELNET", &sim_set_notelnet, 0 },
1319 { "LOG", &sim_set_logon, 0, HLP_SET_LOG },
1320 { "NOLOG", &sim_set_logoff, 0, HLP_SET_LOG },
1321 { "DEBUG", &sim_set_debon, 0, HLP_SET_DEBUG },
1322 { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
1323 { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
1324 { "ON", &set_on, 1, HLP_SET_ON },
1325 { "NOON", &set_on, 0, HLP_SET_ON },
1326 { "VERIFY", &set_verify, 1, HLP_SET_VERIFY },
1327 { "VERBOSE", &set_verify, 1, HLP_SET_VERIFY },
1328 { "NOVERIFY", &set_verify, 0, HLP_SET_VERIFY },
1329 { "NOVERBOSE", &set_verify, 0, HLP_SET_VERIFY },
1330 { "MESSAGE", &set_message, 1, HLP_SET_MESSAGE },
1331 { "NOMESSAGE", &set_message, 0, HLP_SET_MESSAGE },
1332 { "QUIET", &set_quiet, 1, HLP_SET_QUIET },
1333 { "NOQUIET", &set_quiet, 0, HLP_SET_QUIET },
1334 { "LOCALOPC", &set_localopc, 1, HLP_SET_LOCALOPC },
1335 { "NOLOCALOPC", &set_localopc, 0, HLP_SET_LOCALOPC },
1336 { "PROMPT", &set_prompt, 0, HLP_SET_PROMPT },
1337 { NULL, NULL, 0 }
1338 };
1339
1340 static C1TAB set_dev_tab[] = {
1341 { "OCTAL", &set_dev_radix, 8 },
1342 { "DECIMAL", &set_dev_radix, 10 },
1343 { "HEX", &set_dev_radix, 16 },
1344 { "ENABLED", &set_dev_enbdis, 1 },
1345 { "DISABLED", &set_dev_enbdis, 0 },
1346 { "DEBUG", &set_dev_debug, 1 },
1347 { "NODEBUG", &set_dev_debug, 0 },
1348 { NULL, NULL, 0 }
1349 };
1350
1351 static C1TAB set_unit_tab[] = {
1352 { "ENABLED", &set_unit_enbdis, 1 },
1353 { "DISABLED", &set_unit_enbdis, 0 },
1354 { NULL, NULL, 0 }
1355 };
1356
1357 static SHTAB show_glob_tab[] = {
1358 { "CONFIGURATION", &show_config, 0, HLP_SHOW_CONFIG },
1359 { "DEFAULT_BASE_SYSTEM_SCRIPT",
1360 &show_default_base_system_script, 0, HLP_SHOW_DBS },
1361 { "DEVICES", &show_config, 1, HLP_SHOW_DEVICES },
1362 { "FEATURES", &show_config, 2, HLP_SHOW_FEATURES },
1363 { "QUEUE", &show_queue, 0, HLP_SHOW_QUEUE },
1364 { "TIME", &show_time, 0, HLP_SHOW_TIME },
1365 { "MODIFIERS", &show_mod_names, 0, HLP_SHOW_MODIFIERS },
1366 { "NAMES", &show_log_names, 0, HLP_SHOW_NAMES },
1367 { "SHOW", &show_show_commands, 0, HLP_SHOW_SHOW },
1368 { "VERSION", &show_version, 1, HLP_SHOW_VERSION },
1369 { "BUILDINFO", &show_buildinfo, 1, HLP_SHOW_BUILDINFO },
1370 { "PROM", &show_prom, 0, HLP_SHOW_PROM },
1371 { "HINTS", &show_hints, 0, HLP_SHOW_HINTS },
1372 { "CONSOLE", &sim_show_console, 0, HLP_SHOW_CONSOLE },
1373 { "REMOTE", &sim_show_remote_console, 0, HLP_SHOW_REMOTE },
1374 { "BREAK", &show_break, 0, HLP_SHOW_BREAK },
1375 { "LOG", &sim_show_log, 0, HLP_SHOW_LOG },
1376 { "TELNET", &sim_show_telnet, 0 },
1377 { "DEBUG", &sim_show_debug, 0, HLP_SHOW_DEBUG },
1378 { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS },
1379 { "SEND", &sim_show_send, 0, HLP_SHOW_SEND },
1380 { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT },
1381 { "ON", &show_on, 0, HLP_SHOW_ON },
1382 { NULL, NULL, 0 }
1383 };
1384
1385 static SHTAB show_dev_tab[] = {
1386 { "RADIX", &show_dev_radix, 0 },
1387 { "DEBUG", &show_dev_debug, 0 },
1388 { "MODIFIERS", &show_dev_modifiers, 0 },
1389 { "NAMES", &show_dev_logicals, 0 },
1390 { "SHOW", &show_dev_show_commands, 0 },
1391 { NULL, NULL, 0 }
1392 };
1393
1394 static SHTAB show_unit_tab[] = {
1395 { NULL, NULL, 0 }
1396 };
1397
1398 #if defined(_WIN32)
1399 static
1400 int setenv(const char *envname, const char *envval, int overwrite)
1401 {
1402 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1403 int r;
1404
1405 (void)sprintf(envstr, "%s=%s", envname, envval);
1406 r = _putenv(envstr);
1407 FREE(envstr);
1408 return r;
1409 }
1410
1411 static
1412 int unsetenv(const char *envname)
1413 {
1414 setenv(envname, "", 1);
1415 return 0;
1416 }
1417 #endif
1418
1419 #if !defined(NO_LOCALE)
1420 # define XSTR_EMAXLEN 32767
1421
1422 const char
1423 *xstrerror_l(int errnum)
1424 {
1425 int saved = errno;
1426 const char *ret = NULL;
1427 static __thread char buf[XSTR_EMAXLEN];
1428
1429 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1430 defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1431 # if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1432 if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf;
1433 # else
1434 if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf;
1435 # endif
1436 # else
1437 # if defined(__NetBSD__)
1438 locale_t loc = LC_GLOBAL_LOCALE;
1439 # else
1440 locale_t loc = uselocale((locale_t)0);
1441 # endif
1442 locale_t copy = loc;
1443 if (copy == LC_GLOBAL_LOCALE)
1444 copy = duplocale(copy);
1445
1446 if (copy != (locale_t)0)
1447 {
1448 ret = strerror_l(errnum, copy);
1449 if (loc == LC_GLOBAL_LOCALE)
1450 {
1451 freelocale(copy);
1452 }
1453 }
1454 # endif
1455
1456 if (!ret)
1457 {
1458 (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1459 ret = buf;
1460 }
1461
1462 errno = saved;
1463 return ret;
1464 }
1465 #else
1466 # define xstrerror_l strerror
1467 #endif
1468
1469 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1470
1471
1472
1473 char *strremove(char *str, const char *sub)
1474 {
1475 char *p, *q, *r;
1476 if (*sub && (q = r = strstr(str, sub)) != NULL) {
1477 size_t len = strlen(sub);
1478 while ((r = strstr(p = r + len, sub)) != NULL) {
1479 while (p < r)
1480 *q++ = *p++;
1481 }
1482 while ((*q++ = *p++) != '\0')
1483 continue;
1484 }
1485 return str;
1486 }
1487
1488
1489
1490 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
1491 {
1492 while (*str_untrimmed != '\0') {
1493 if(!isspace((unsigned char)*str_untrimmed)) {
1494 *str_trimmed = (char)*str_untrimmed;
1495 str_trimmed++;
1496 }
1497 str_untrimmed++;
1498 }
1499 *str_trimmed = '\0';
1500 }
1501
1502 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1503 void allowCores(void)
1504 {
1505 int ret;
1506 struct rlimit limit;
1507 # if defined(RLIMIT_CORE)
1508 ret = getrlimit(RLIMIT_CORE, &limit);
1509 (void)ret;
1510 # if defined(TESTING)
1511 if (ret != 0)
1512 {
1513 sim_warn ("Failed to query core dump configuration.");
1514 return;
1515 }
1516 # endif
1517 limit.rlim_cur = limit.rlim_max;
1518 ret = setrlimit(RLIMIT_CORE, &limit);
1519 # if defined(TESTING)
1520 if (ret != 0)
1521 {
1522 sim_warn ("Failed to enable unlimited core dumps.");
1523 return;
1524 }
1525 # endif
1526 # else
1527 # if defined(TESTING)
1528 sim_warn ("Unable to query core dump configuration.");
1529 # endif
1530 # endif
1531 return;
1532 }
1533 #endif
1534
1535 #if defined(USE_DUMA)
1536 void CleanDUMA(void)
1537 {
1538 (void)fflush(stdout);
1539 DUMA_CHECKALL();
1540 (void)fflush(stderr);
1541 }
1542 # undef USE_DUMA
1543 # define USE_DUMA 1
1544 #endif
1545
1546 #if !defined(SIG_SETMASK)
1547 # undef USE_BACKTRACE
1548 #endif
1549
1550 #if defined(PERF_STRIP)
1551 # undef USE_BACKTRACE
1552 #endif
1553
1554 #if defined(USE_BACKTRACE)
1555 # include <backtrace.h>
1556 # include <backtrace-supported.h>
1557 # define BACKTRACE_SKIP 1
1558 # define BACKTRACE_MAIN "main"
1559 # undef USE_BACKTRACE
1560 # define USE_BACKTRACE 1
1561 #endif
1562
1563 #if defined(BACKTRACE_SUPPORTED)
1564 # if defined(BACKTRACE_SUPPORTS_THREADS)
1565 # if !(BACKTRACE_SUPPORTED)
1566 # undef USE_BACKTRACE
1567 # endif
1568 # else
1569 # undef USE_BACKTRACE
1570 # endif
1571 #else
1572 # undef USE_BACKTRACE
1573 #endif
1574
1575 #if defined(USE_BACKTRACE)
1576 # if defined(BACKTRACE_SUPPORTED)
1577 # include "backtrace_func.c"
1578 # endif
1579 #endif
1580
1581 #if !defined(__CYGWIN__)
1582 # if !defined(__APPLE__)
1583 # if !defined(_AIX)
1584 # if !defined(__MINGW32__)
1585 # if !defined(__MINGW64__)
1586 # if !defined(CROSS_MINGW32)
1587 # if !defined(CROSS_MINGW64)
1588 # if !defined(_WIN32)
1589 # if !defined(__HAIKU__)
1590 # if !defined(__QNX__)
1591 # if !defined(__FILC__)
1592 static int
1593 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
1594 {
1595 (void)size;
1596 (void)data;
1597
1598 if (strlen(info->dlpi_name) >= 2) {
1599 if (!dl_iterate_phdr_callback_called)
1600 (void)printf ("\r\n Loaded shared objects: ");
1601
1602 dl_iterate_phdr_callback_called++;
1603 (void)printf ("%s ", info->dlpi_name);
1604 }
1605
1606 return 0;
1607 }
1608 # endif
1609 # endif
1610 # endif
1611 # endif
1612 # endif
1613 # endif
1614 # endif
1615 # endif
1616 # endif
1617 # endif
1618 #endif
1619
1620 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1621 # if defined(_UCRT)
1622 # define MINGW_CRT "UCRT"
1623 # else
1624 # define MINGW_CRT "MSVCRT"
1625 # endif
1626 #endif
1627
1628 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1629 struct UCRTVersion
1630 {
1631 uint16_t ProductVersion[4];
1632 };
1633
1634 int
1635 GetUCRTVersion (struct UCRTVersion *ucrtversion)
1636 {
1637 # ifdef _DEBUG
1638 static const wchar_t *DllName = L"ucrtbased.dll";
1639 # else
1640 static const wchar_t *DllName = L"ucrtbase.dll";
1641 # endif
1642
1643 HMODULE ucrt = GetModuleHandleW (DllName);
1644 if (!ucrt)
1645 return GetLastError ();
1646
1647 wchar_t path[SIR_MAXPATH];
1648 if (!GetModuleFileNameW (ucrt, path, SIR_MAXPATH))
1649 return GetLastError ();
1650
1651 DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1652 if (!versionInfoSize)
1653 return GetLastError ();
1654
1655 uint8_t versionInfo[versionInfoSize];
1656
1657 if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1658 return GetLastError ();
1659
1660 VS_FIXEDFILEINFO *fixedFileInfo;
1661 UINT fixedFileInfoSize;
1662 if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1663 return GetLastError ();
1664
1665 memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1666
1667 return 0;
1668 }
1669 #endif
1670
1671
1672
1673 #if !defined(PERF_STRIP)
1674 static int dps8_sir_report_error(void)
1675 {
1676 char message[SIR_MAXERROR] = {0};
1677 (void)sir_geterror(message);
1678 (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1679 return EXIT_FAILURE;
1680 }
1681
1682
1683
1684 int main (int argc, char *argv[])
1685 {
1686 char *cptr, *cptr2;
1687 char nbuf[PATH_MAX + 7];
1688 char cbuf[4*CBUFSIZE];
1689 char **targv = NULL;
1690 int32 i, sw;
1691 t_bool lookswitch;
1692 t_stat stat;
1693
1694
1695 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1696 uid_t real_uid = getuid();
1697 uid_t eff_uid = geteuid();
1698 if (0 == eff_uid && 0 != real_uid) {
1699 (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1700 exit(EXIT_FAILURE);
1701 }
1702 # endif
1703
1704 sunos_obtain_realtime_privileges();
1705
1706 sim_free_memory = sim_memory_available();
1707
1708 sim_appfilename = _sir_getappfilename();
1709 if (sim_appfilename == NULL) {
1710 sim_appfilename = "dps8";
1711 }
1712
1713
1714
1715 sirinit si;
1716 if (!sir_makeinit(&si))
1717 return dps8_sir_report_error();
1718
1719
1720 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1721
1722
1723 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1724
1725
1726 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1727
1728
1729 si.d_stderr.opts = SIRO_NOHOST;
1730
1731
1732 si.d_syslog.levels = SIRL_NONE;
1733
1734
1735 si.d_syslog.opts = SIRO_DEFAULT;
1736
1737
1738 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1739
1740
1741 if (!sir_init(&si))
1742 return dps8_sir_report_error();
1743
1744 # if defined(_AIX)
1745 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1746 if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1747 (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1748 __func__, __FILE__, __LINE__);
1749 abort();
1750 }
1751
1752 if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1753 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1754 }
1755
1756 if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1757 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1758 }
1759
1760 if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1761 (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1762 }
1763
1764 # if !defined(__PASE__)
1765 if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1766 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1767 }
1768 # else
1769 # if !defined(TESTING)
1770 if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1771 (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1772 }
1773 # endif
1774 # endif
1775
1776 if (execvp(argv[0], argv) == -1) {
1777 (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1778 __func__, __FILE__, __LINE__);
1779 abort();
1780 }
1781 }
1782 # endif
1783
1784 # if defined(USE_BACKTRACE)
1785 # if defined(BACKTRACE_SUPPORTED)
1786 # if defined(_INC_BACKTRACE_FUNC)
1787 bt_pid = (long)_sir_getpid();
1788 (void)bt_pid;
1789 # endif
1790 # endif
1791 # endif
1792
1793 # if defined(__MINGW32__)
1794 # undef IS_WINDOWS
1795 # define IS_WINDOWS 1
1796 # if !defined(NEED_CONSOLE_SETUP)
1797 # define NEED_CONSOLE_SETUP
1798 # endif
1799 # endif
1800
1801 # if defined(CROSS_MINGW32)
1802 # undef IS_WINDOWS
1803 # define IS_WINDOWS 1
1804 # if !defined(NEED_CONSOLE_SETUP)
1805 # define NEED_CONSOLE_SETUP
1806 # endif
1807 # endif
1808
1809 # if defined(__MINGW64__)
1810 # undef IS_WINDOWS
1811 # define IS_WINDOWS 1
1812 # if !defined(NEED_CONSOLE_SETUP)
1813 # define NEED_CONSOLE_SETUP
1814 # endif
1815 # endif
1816
1817 # if defined(CROSS_MINGW64)
1818 # undef IS_WINDOWS
1819 # define IS_WINDOWS 1
1820 # if !defined(NEED_CONSOLE_SETUP)
1821 # define NEED_CONSOLE_SETUP
1822 # endif
1823 # endif
1824
1825 # if defined(__CYGWIN__)
1826 # if defined(IS_WINDOWS)
1827 # undef IS_WINDOWS
1828 # endif
1829 # endif
1830
1831 # if defined(USE_DUMA)
1832 # if defined(DUMA_EXPLICIT_INIT)
1833 duma_init();
1834 (void)fflush(stderr);
1835 # endif
1836 # if defined(DUMA_MIN_ALIGNMENT)
1837 # if DUMA_MIN_ALIGNMENT > 0
1838 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1839 # endif
1840 # endif
1841 DUMA_SET_FILL(0x2E);
1842 (void)fflush(stderr);
1843 (void)atexit(CleanDUMA);
1844 # endif
1845
1846 # if defined(USE_BACKTRACE)
1847 # if defined(BACKTRACE_SUPPORTED)
1848 # include "backtrace_main.c"
1849 # endif
1850 # endif
1851
1852 # if !defined(NO_LOCALE)
1853 (void)setlocale(LC_ALL, "");
1854 # endif
1855
1856 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1857 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1858 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1859 # endif
1860 # endif
1861
1862 # if defined(NEED_CONSOLE_SETUP)
1863 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1864 if (handle != INVALID_HANDLE_VALUE)
1865 {
1866 DWORD mode = 0;
1867 if (GetConsoleMode(handle, &mode))
1868 {
1869 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1870 SetConsoleMode(handle, mode);
1871 }
1872 }
1873 puts ("\e[0m");
1874 # endif
1875
1876 # if defined(__HAIKU__)
1877 (void)disable_debugger(1);
1878 # endif
1879
1880 running_perf_test = false;
1881
1882
1883 char thread_name[SIR_MAXPID] = {0};
1884 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1885 (void)_sir_setthreadname(thread_name);
1886
1887
1888
1889 # if defined(__clang_analyzer__)
1890 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1891 return 1;
1892 # endif
1893
1894 if (argc == 0) {
1895 (void)fprintf (stderr, "Error: main() called directly!\r\n");
1896 return 1;
1897 }
1898
1899
1900 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1901 allowCores();
1902 # endif
1903
1904 int testEndian = decContextTestEndian();
1905 if (testEndian != 0) {
1906 if (testEndian == 1) {
1907 (void)fprintf (stderr,
1908 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1909 return 1;
1910 }
1911 if (testEndian == -1) {
1912 (void)fprintf (stderr,
1913 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1914 return 1;
1915 }
1916 (void)fprintf (stderr,
1917 "Error: Unable to determine system byte order; aborting.\r\n");
1918 return 1;
1919 }
1920 # if defined(NEED_128)
1921 test_math128();
1922 # endif
1923
1924 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1925
1926 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1927
1928
1929
1930
1931 nprocs = (unsigned int)uv_available_parallelism();
1932 # else
1933 nprocs = (unsigned int)_sir_nprocs();
1934 # endif
1935 ncores = (unsigned int)get_core_count();
1936
1937
1938 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1939 if (!targv)
1940 {
1941 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1942 __func__, __FILE__, __LINE__);
1943 # if defined(USE_BACKTRACE)
1944 # if defined(SIGUSR2)
1945 (void)raise(SIGUSR2);
1946
1947 # endif
1948 # endif
1949 abort();
1950 }
1951 for (i=0; i<argc; i++)
1952 targv[i] = argv[i];
1953 argv = targv;
1954
1955
1956 set_prompt (0, "sim>");
1957 *cbuf = 0;
1958 sim_switches = 0;
1959 lookswitch = TRUE;
1960 stdnul = fopen(NULL_DEVICE,"wb");
1961
1962
1963 for (i = 1; i < argc; i++) {
1964 if (argv[i] == NULL)
1965 continue;
1966
1967 # if defined(THREADZ) || defined(LOCKLESS)
1968
1969 int perftestflag = strcmp(argv[i], "--perftest");
1970 if (perftestflag == 0) {
1971 char * testName = NULL;
1972 if (i + 1 < argc)
1973 testName = argv[i + 1];
1974 perfTest (testName);
1975 return 0;
1976 }
1977 # endif
1978
1979
1980 int onlyvers = strcmp(argv[i], "--version");
1981 if (onlyvers == 0) {
1982 # if defined(VER_H_GIT_VERSION)
1983 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1984 # if VER_H_GIT_PATCH_INT < 1
1985 (void)fprintf (stdout, "%s simulator %s\r\n",
1986 sim_name, VER_H_GIT_VERSION);
1987 # else
1988 (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1989 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1990 # endif
1991 # else
1992 (void)fprintf (stdout, "%s simulator %s\r\n",
1993 sim_name, VER_H_GIT_VERSION);
1994 # endif
1995 # else
1996 (void)fprintf (stdout, "%s simulator\r\n", sim_name);
1997 # endif
1998 FREE (targv);
1999 return 0;
2000 }
2001
2002
2003 int longhelp = strcmp(argv[i], "--help");
2004 int shorthelp = strcmp(argv[i], "-h");
2005 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2006 if (longhelp == 0 || shorthelp == 0) {
2007 # if defined(VER_H_GIT_VERSION)
2008 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2009 # if VER_H_GIT_PATCH_INT < 1
2010 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2011 # else
2012 (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2013 # endif
2014 # else
2015 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2016 # endif
2017 # else
2018 (void)fprintf (stdout, "%s simulator", sim_name);
2019 # endif
2020 (void)fprintf (stdout, "\r\n");
2021 (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2022 (void)fprintf (stdout, "\r\n");
2023 (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2024 (void)fprintf (stdout, "\r\n");
2025 (void)fprintf (stdout, "\r\n Switches:");
2026 (void)fprintf (stdout, "\r\n -e, -E Aborts script processing immediately upon any error");
2027 (void)fprintf (stdout, "\r\n -h, -H, --help Prints only this informational help text and exits");
2028 (void)fprintf (stdout, "\r\n -k, -K Disables all support for exclusive file locking");
2029 (void)fprintf (stdout, "\r\n -l, -L Reports but ignores all exclusive file locking errors");
2030 (void)fprintf (stdout, "\r\n -o, -O Makes scripting ON conditions and actions inheritable");
2031 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2032 (void)fprintf (stdout, "\r\n -p, -P Enables real-time scheduling (may require privileges)");
2033 # endif
2034 (void)fprintf (stdout, "\r\n -q, -Q Disables printing of non-fatal informational messages");
2035 (void)fprintf (stdout, "\r\n -r, -R Enables an unlinked ephemeral system state file");
2036 (void)fprintf (stdout, "\r\n -s, -S Enables a randomized persistent system state file");
2037 (void)fprintf (stdout, "\r\n -t, -T Disables fsync and creation/usage of system state file");
2038 (void)fprintf (stdout, "\r\n -v, -V Prints commands read from script file before execution");
2039 (void)fprintf (stdout, "\r\n --version Prints only the simulator identification text and exits");
2040 (void)fprintf (stdout, "\r\n");
2041 # if defined(USE_DUMA)
2042 nodist++;
2043 # endif
2044 if (!nodist) {
2045 (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2046 (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2047 (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2048 }
2049 else
2050 {
2051 (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2052 }
2053 (void)fprintf (stdout, "\r\n");
2054 FREE(argv);
2055 return 0;
2056 }
2057
2058 if ((*argv[i] == '-') && lookswitch) {
2059 if ((sw = get_switches (argv[i])) < 0) {
2060 (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2061 FREE(argv);
2062 return 1;
2063 }
2064 sim_switches = sim_switches | sw;
2065 }
2066
2067 else {
2068 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2069 (void)fprintf (stderr, "Argument string too long\r\n");
2070 FREE(argv);
2071 return 1;
2072 }
2073 if (*cbuf)
2074 strcat (cbuf, " ");
2075 (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s",
2076 strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
2077 lookswitch = FALSE;
2078 }
2079 }
2080 sim_nolock = sim_switches & SWMASK ('K');
2081 sim_iglock = sim_switches & SWMASK ('L');
2082 sim_randompst = sim_switches & SWMASK ('S');
2083 sim_quiet = sim_switches & SWMASK ('Q');
2084 sim_randstate = sim_switches & SWMASK ('R');
2085 if (sim_randompst) sim_randstate = 1;
2086 sim_nostate = sim_switches & SWMASK ('T');
2087 if (sim_nostate)
2088 {
2089 sim_randompst = 0;
2090 sim_randstate = 0;
2091 }
2092 sim_on_inherit = sim_switches & SWMASK ('O');
2093
2094 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2095 !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2096 sim_realtime = sim_switches & SWMASK ('P');
2097 # endif
2098
2099 sim_init_sock ();
2100 if (sim_dflt_dev == NULL)
2101 sim_dflt_dev = sim_devices[0];
2102 if (sim_vm_init != NULL)
2103 (*sim_vm_init)();
2104 sim_finit ();
2105 for (i = 0; cmd_table[i].name; i++) {
2106 size_t alias_len = strlen (cmd_table[i].name);
2107 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2108 if (!cmd_name)
2109 {
2110 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2111 __func__, __FILE__, __LINE__);
2112 # if defined(USE_BACKTRACE)
2113 # if defined(SIGUSR2)
2114 (void)raise(SIGUSR2);
2115
2116 # endif
2117 # endif
2118 abort();
2119 }
2120
2121 strcpy (cmd_name, cmd_table[i].name);
2122 while (alias_len > 1) {
2123 cmd_name[alias_len] = '\0';
2124 --alias_len;
2125 if (getenv (cmd_name))
2126 unsetenv (cmd_name);
2127 }
2128 FREE (cmd_name);
2129 }
2130 stop_cpu = 0;
2131 sim_interval = 0;
2132 sim_time = sim_rtime = 0;
2133 noqueue_time = 0;
2134 sim_clock_queue = QUEUE_LIST_END;
2135 sim_is_running = 0;
2136 sim_log = NULL;
2137 if (sim_emax <= 0)
2138 sim_emax = 1;
2139
2140
2141 main_thread_id = pthread_self();
2142
2143
2144 save_thread_sched(pthread_self());
2145
2146
2147 if (sim_realtime) {
2148 if (nprocs < 2) {
2149 sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2150 exit(EXIT_FAILURE);
2151 } else {
2152 watchdog_startup();
2153 }
2154 }
2155
2156
2157 if (realtime_ok) {
2158 set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2159 check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2160 } else {
2161 # if !defined(__QNX__)
2162 (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2163 # endif
2164 }
2165
2166 sim_timer_init ();
2167
2168 if ((stat = sim_ttinit ()) != SCPE_OK) {
2169 (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2170 sim_error_text (stat));
2171 FREE(argv);
2172 return 1;
2173 }
2174 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2175 (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2176 FREE(argv);
2177 return 1;
2178 };
2179 if ((stat = reset_all_p (0)) != SCPE_OK) {
2180 (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2181 sim_error_text (stat));
2182 FREE(argv);
2183 return 1;
2184 }
2185 if ((stat = sim_brk_init ()) != SCPE_OK) {
2186 (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2187 sim_error_text (stat));
2188 FREE(argv);
2189 return 1;
2190 }
2191 if (!sim_quiet) {
2192 (void)printf ("\r\n");
2193 show_version (stdout, NULL, NULL, 0, NULL);
2194 }
2195
2196 cptr = getenv("HOME");
2197 if (cptr == NULL) {
2198 cptr = getenv("HOMEPATH");
2199 cptr2 = getenv("HOMEDRIVE");
2200 }
2201 else
2202 cptr2 = NULL;
2203 (void)cptr2;
2204 if ( (*cbuf) && (strcmp(cbuf, "")) )
2205 stat = do_cmd (0, cbuf);
2206 else if (*argv[0]) {
2207 char *np;
2208 nbuf[0] = '"';
2209 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
2210 if (stat == SCPE_OPENERR) {
2211 np = strrchr (nbuf, '/');
2212 if (np == NULL)
2213 np = strrchr (nbuf, '\\');
2214 if (np != NULL) {
2215 *np = '"';
2216 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
2217 }
2218 }
2219 }
2220
2221 argv = uv_setup_args(argc, argv);
2222
2223
2224 if (getenv("DPS8M_NO_HINTS") == NULL)
2225 if (!sim_quiet && 0 == strcmp(cbuf, ""))
2226 (void)show_hints(0, 0, 0, 1, 0);
2227
2228 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2229
2230 if (sim_vm_exit != NULL)
2231 (*sim_vm_exit)();
2232
2233 detach_all (0, TRUE);
2234 sim_set_deboff (0, NULL);
2235 sim_set_logoff (0, NULL);
2236 sim_set_notelnet (0, NULL);
2237 sim_ttclose ();
2238 sim_cleanup_sock ();
2239 fclose (stdnul);
2240 FREE (targv);
2241 FREE (sim_prompt);
2242 FREE (sim_eval);
2243 FREE (sim_internal_devices);
2244 FREE (sim_brk_tab);
2245 FREE (sim_staba.comp);
2246 FREE (sim_staba.mask);
2247 FREE (sim_stabr.comp);
2248 FREE (sim_stabr.mask);
2249 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2250 }
2251 #endif
2252
2253 t_stat process_stdin_commands (t_stat stat, char *argv[])
2254 {
2255 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2256 CONST char *cptr;
2257 t_stat stat_nomessage;
2258 CTAB *cmdp = NULL;
2259
2260 stat = SCPE_BARE_STATUS(stat);
2261 while (stat != SCPE_EXIT) {
2262 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
2263 (void)printf ("%s%s\r\n", sim_prompt, cptr);
2264 else if (sim_vm_read != NULL) {
2265 (void)printf ("%s", sim_prompt);
2266 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2267 }
2268 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
2269 if (cptr == NULL) {
2270 if (sim_ttisatty()) continue;
2271 else break;
2272 }
2273 if (*cptr == 0)
2274 continue;
2275 sim_sub_args (cbuf, sizeof(cbuf), argv);
2276 if (sim_log)
2277 (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2278 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2279 (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2280 cptr = get_glyph_cmd (cptr, gbuf);
2281 sim_switches = 0;
2282 if ((cmdp = find_cmd (gbuf)))
2283 stat = cmdp->action (cmdp->arg, cptr);
2284 else
2285 stat = SCPE_UNK;
2286 stat_nomessage = stat & SCPE_NOMESSAGE;
2287 stat_nomessage = stat_nomessage || (!sim_show_message);
2288 stat = SCPE_BARE_STATUS(stat);
2289 sim_last_cmd_stat = stat;
2290 if (!stat_nomessage) {
2291 if (cmdp && (cmdp->message))
2292 cmdp->message (NULL, stat);
2293 else
2294 if (stat >= SCPE_BASE)
2295 sim_printf ("%s\r\n", sim_error_text (stat));
2296 }
2297 if (sim_vm_post != NULL)
2298 (*sim_vm_post) (TRUE);
2299 }
2300 return stat;
2301 }
2302
2303
2304
2305 t_stat set_prompt (int32 flag, CONST char *cptr)
2306 {
2307 char gbuf[CBUFSIZE], *gptr;
2308
2309 if ((NULL == cptr) || (*cptr == '\0'))
2310 return SCPE_ARG;
2311
2312 cptr = get_glyph_nc (cptr, gbuf, '"');
2313 if (gbuf[0] == '\0') {
2314 gbuf[sizeof (gbuf)-1] = '\0';
2315 strncpy (gbuf, cptr, sizeof (gbuf)-1);
2316 gptr = strchr (gbuf, '"');
2317 if (NULL != gptr)
2318 *gptr = '\0';
2319 }
2320 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
2321 if (!sim_prompt)
2322 {
2323 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2324 __func__, __FILE__, __LINE__);
2325 #if defined(USE_BACKTRACE)
2326 # if defined(SIGUSR2)
2327 (void)raise(SIGUSR2);
2328
2329 # endif
2330 #endif
2331 abort();
2332 }
2333 (void)sprintf (sim_prompt, "%s ", gbuf);
2334 return SCPE_OK;
2335 }
2336
2337
2338
2339 CTAB *find_cmd (const char *gbuf)
2340 {
2341 CTAB *cmdp = NULL;
2342
2343 if (sim_vm_cmd)
2344 cmdp = find_ctab (sim_vm_cmd, gbuf);
2345 if (cmdp == NULL)
2346 cmdp = find_ctab (cmd_table, gbuf);
2347 return cmdp;
2348 }
2349
2350
2351
2352 t_stat exit_cmd (int32 flag, CONST char *cptr)
2353 {
2354 return SCPE_EXIT;
2355 }
2356
2357
2358
2359
2360 static int _cmd_name_compare (const void *pa, const void *pb)
2361 {
2362 CTAB * const *a = (CTAB * const *)pa;
2363 CTAB * const *b = (CTAB * const *)pb;
2364
2365 return strcmp((*a)->name, (*b)->name);
2366 }
2367
2368 void fprint_help (FILE *st)
2369 {
2370 CTAB *cmdp;
2371 CTAB **hlp_cmdp = NULL;
2372 size_t cmd_cnt = 0;
2373 size_t cmd_size = 0;
2374 size_t max_cmdname_size = 0;
2375 size_t i, line_offset;
2376
2377 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2378 if (cmdp->help) {
2379 if (cmd_cnt >= cmd_size) {
2380 cmd_size += 20;
2381 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2382 if (!hlp_cmdp)
2383 {
2384 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2385 __func__, __FILE__, __LINE__);
2386 #if defined(USE_BACKTRACE)
2387 # if defined(SIGUSR2)
2388 (void)raise(SIGUSR2);
2389
2390 # endif
2391 #endif
2392 abort();
2393 }
2394 }
2395 hlp_cmdp[cmd_cnt] = cmdp;
2396 ++cmd_cnt;
2397 if (strlen(cmdp->name) > max_cmdname_size)
2398 max_cmdname_size = strlen(cmdp->name);
2399 }
2400 }
2401 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2402 if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2403 if (cmd_cnt >= cmd_size) {
2404 cmd_size += 20;
2405 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2406 if (!hlp_cmdp)
2407 {
2408 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2409 __func__, __FILE__, __LINE__);
2410 #if defined(USE_BACKTRACE)
2411 # if defined(SIGUSR2)
2412 (void)raise(SIGUSR2);
2413
2414 # endif
2415 #endif
2416 abort();
2417 }
2418 }
2419 hlp_cmdp[cmd_cnt] = cmdp;
2420 ++cmd_cnt;
2421 if (strlen (cmdp->name) > max_cmdname_size)
2422 max_cmdname_size = strlen(cmdp->name);
2423 }
2424 }
2425 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n ");
2426 if (hlp_cmdp)
2427 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2428 line_offset = 4;
2429 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2430 fputs (hlp_cmdp[i]->name, st);
2431 line_offset += 5 + max_cmdname_size;
2432 if (line_offset + max_cmdname_size > 79) {
2433 line_offset = 4;
2434 (void)fprintf (st, "\r\n ");
2435 }
2436 else
2437 (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2438 }
2439 FREE (hlp_cmdp);
2440 (void)fprintf (st, "\r\n");
2441 return;
2442 }
2443
2444 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2445 {
2446 if (!*pdone)
2447 (void)fprintf (st, "%s", context);
2448 *pdone = TRUE;
2449 }
2450
2451 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2452 {
2453 REG *rptr, *trptr;
2454 t_bool found = FALSE;
2455 t_bool all_unique = TRUE;
2456 size_t max_namelen = 0;
2457 DEVICE *tdptr;
2458 CONST char *tptr;
2459 char *namebuf;
2460 char rangebuf[32];
2461
2462 if (dptr->registers)
2463 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2464 if (rptr->flags & REG_HIDDEN)
2465 continue;
2466 if (rptr->depth > 1)
2467 (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2468 else
2469 strcpy (rangebuf, "");
2470 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2471 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2472 found = TRUE;
2473 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2474 if ((trptr == NULL) || (tdptr != dptr))
2475 all_unique = FALSE;
2476 }
2477 if (!found) {
2478 if (!silent)
2479 (void)fprintf (st, "No register HELP available for the %s device\r\n",
2480 dptr->name);
2481 }
2482 else {
2483 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2484 if (!namebuf)
2485 {
2486 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2487 __func__, __FILE__, __LINE__);
2488 #if defined(USE_BACKTRACE)
2489 # if defined(SIGUSR2)
2490 (void)raise(SIGUSR2);
2491
2492 # endif
2493 #endif
2494 abort();
2495 }
2496 (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2497 dptr->name);
2498 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2499 if (rptr->flags & REG_HIDDEN)
2500 continue;
2501 if (rptr->depth <= 1)
2502 (void)sprintf (namebuf, "%*s",
2503 -((int)max_namelen),
2504 rptr->name);
2505 else {
2506 (void)sprintf (rangebuf, "[%d:%d]",
2507 0,
2508 rptr->depth-1);
2509 (void)sprintf (namebuf, "%s%*s",
2510 rptr->name,
2511 (int)(strlen(rptr->name))-((int)max_namelen),
2512 rangebuf);
2513 }
2514 if (all_unique) {
2515 (void)fprintf (st, " %s %4d %s\r\n",
2516 namebuf,
2517 rptr->width,
2518 rptr->desc ? rptr->desc : "");
2519 continue;
2520 }
2521 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2522 if ((trptr == NULL) || (tdptr != dptr))
2523 (void)fprintf (st, " %s %s %4d %s\r\n",
2524 dptr->name,
2525 namebuf,
2526 rptr->width,
2527 rptr->desc ? rptr->desc : "");
2528 else
2529 (void)fprintf (st, " %*s %s %4d %s\r\n",
2530 (int)strlen(dptr->name), "",
2531 namebuf,
2532 rptr->width,
2533 rptr->desc ? rptr->desc : "");
2534 }
2535 FREE (namebuf);
2536 }
2537 }
2538
2539 void fprint_reg_help (FILE *st, DEVICE *dptr)
2540 {
2541 fprint_reg_help_ex (st, dptr, TRUE);
2542 }
2543
2544 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2545 {
2546 if (dptr->attach_help) {
2547 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2548 dptr->attach_help (st, dptr, NULL, 0, NULL);
2549 return;
2550 }
2551 if (DEV_TYPE(dptr) == DEV_DISK) {
2552 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2553 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2554 return;
2555 }
2556 if (DEV_TYPE(dptr) == DEV_TAPE) {
2557 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2558 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2559 return;
2560 }
2561 if (!silent) {
2562 (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2563 if (dptr->help)
2564 dptr->help (st, dptr, NULL, 0, NULL);
2565 }
2566 }
2567
2568 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2569 {
2570 MTAB *mptr;
2571 DEBTAB *dep;
2572 t_bool found = FALSE;
2573 char buf[CBUFSIZE], header[CBUFSIZE];
2574 uint32 enabled_units = dptr->numunits;
2575 uint32 unit;
2576
2577 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2578 for (unit=0; unit < dptr->numunits; unit++)
2579 if (dptr->units[unit].flags & UNIT_DIS)
2580 --enabled_units;
2581 if (dptr->modifiers) {
2582 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2583 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2584 continue;
2585 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2586 continue;
2587 if (mptr->mstring) {
2588 fprint_header (st, &found, header);
2589 (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2590 mptr->mstring,
2591 (strchr(mptr->mstring, '=')) \
2592 ? "" : (MODMASK(mptr,MTAB_VALR) \
2593 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2594 ? "{=val}" : "")));
2595 if ((strlen (buf) < 30) || (NULL == mptr->help))
2596 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2597 else
2598 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2599 }
2600 }
2601 }
2602 if (dptr->flags & DEV_DISABLE) {
2603 fprint_header (st, &found, header);
2604 (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2605 (void)fprintf (st, "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2606 (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2607 (void)fprintf (st, "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2608 }
2609 if (dptr->flags & DEV_DEBUG) {
2610 fprint_header (st, &found, header);
2611 (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2612 (void)fprintf (st, "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2613 (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2614 (void)fprintf (st, "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2615 if (dptr->debflags) {
2616 t_bool desc_available = FALSE;
2617 strcpy (buf, "");
2618 (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2619 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2620 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2621 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2622 }
2623 (void)fprintf (st, "\r\n");
2624 (void)fprintf (st, "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2625 (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2626 for (dep = dptr->debflags; dep->name != NULL; dep++)
2627 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2628 (void)fprintf (st, "\r\n");
2629 (void)fprintf (st, "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2630 if (desc_available) {
2631 (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2632 for (dep = dptr->debflags; dep->name != NULL; dep++)
2633 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2634 }
2635 }
2636 }
2637 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2638 if (dptr->units->flags & UNIT_DISABLE) {
2639 fprint_header (st, &found, header);
2640 (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2641 (void)fprintf (st, "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2642 (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2643 (void)fprintf (st, "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2644 }
2645 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2646 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2647 continue;
2648 if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2649 continue;
2650 if (mptr->mstring) {
2651 fprint_header (st, &found, header);
2652 (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2653 (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2654 (strchr(mptr->mstring, '=')) \
2655 ? "" : (MODMASK(mptr,MTAB_VALR) \
2656 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2657 ? "{=val}" : "")));
2658 (void)fprintf (st, "%-30s\t%s\r\n", buf,
2659 (strchr(mptr->mstring, '=')) \
2660 ? "" : (mptr->help ? mptr->help : ""));
2661 }
2662 }
2663 }
2664 if (!found && !silent)
2665 (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2666 }
2667
2668 void fprint_set_help (FILE *st, DEVICE *dptr)
2669 {
2670 fprint_set_help_ex (st, dptr, TRUE);
2671 }
2672
2673 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2674 {
2675 MTAB *mptr;
2676 t_bool found = FALSE;
2677 char buf[CBUFSIZE], header[CBUFSIZE];
2678 uint32 enabled_units = dptr->numunits;
2679 uint32 unit;
2680
2681 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2682 for (unit=0; unit < dptr->numunits; unit++)
2683 if (dptr->units[unit].flags & UNIT_DIS)
2684 --enabled_units;
2685 if (dptr->modifiers) {
2686 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2687 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2688 continue;
2689 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2690 continue;
2691 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2692 continue;
2693 fprint_header (st, &found, header);
2694 (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2695 mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2696 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2697 }
2698 }
2699 if (dptr->flags & DEV_DEBUG) {
2700 fprint_header (st, &found, header);
2701 (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2702 (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2703 }
2704 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2705 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2706 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2707 continue;
2708 if ((!mptr->disp) || (!mptr->pstring))
2709 continue;
2710 fprint_header (st, &found, header);
2711 (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2712 (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2713 MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2714 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2715 }
2716 }
2717 if (!found && !silent)
2718 (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2719 }
2720
2721 void fprint_show_help (FILE *st, DEVICE *dptr)
2722 {
2723 fprint_show_help_ex (st, dptr, TRUE);
2724 }
2725
2726 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2727 {
2728 BRKTYPTAB *brkt = dptr->brk_types;
2729 char gbuf[CBUFSIZE];
2730
2731 if (sim_brk_types == 0) {
2732 if ((dptr != sim_dflt_dev) && (!silent)) {
2733 (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2734 if (dptr->help)
2735 dptr->help (st, dptr, NULL, 0, NULL);
2736 }
2737 return;
2738 }
2739 if (brkt == NULL) {
2740 int i;
2741
2742 if (dptr == sim_dflt_dev) {
2743 if (sim_brk_types & ~sim_brk_dflt) {
2744 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2745 for (i=0; i<26; i++) {
2746 if (sim_brk_types & (1<<i))
2747 (void)fprintf (st, " -%c\r\n", 'A'+i);
2748 }
2749 }
2750 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2751 }
2752 return;
2753 }
2754 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2755 while (brkt->btyp) {
2756 (void)fprintf (st, " %s %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2757 ++brkt;
2758 }
2759 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2760 }
2761
2762 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2763 {
2764 char gbuf[CBUFSIZE];
2765 CTAB *cmdp;
2766
2767 if (*cptr) {
2768 (void)get_glyph (cptr, gbuf, 0);
2769 if ((cmdp = find_cmd (gbuf))) {
2770 if (cmdp->action == &exdep_cmd) {
2771 if (dptr->help)
2772 return dptr->help (st, dptr, uptr, flag, cptr);
2773 else
2774 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2775 return SCPE_OK;
2776 }
2777 if (cmdp->action == &set_cmd) {
2778 fprint_set_help_ex (st, dptr, FALSE);
2779 return SCPE_OK;
2780 }
2781 if (cmdp->action == &show_cmd) {
2782 fprint_show_help_ex (st, dptr, FALSE);
2783 return SCPE_OK;
2784 }
2785 if (cmdp->action == &attach_cmd) {
2786 fprint_attach_help_ex (st, dptr, FALSE);
2787 return SCPE_OK;
2788 }
2789 if (cmdp->action == &brk_cmd) {
2790 fprint_brk_help_ex (st, dptr, FALSE);
2791 return SCPE_OK;
2792 }
2793 if (dptr->help)
2794 return dptr->help (st, dptr, uptr, flag, cptr);
2795 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2796 return SCPE_OK;
2797 }
2798 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2799 fprint_reg_help_ex (st, dptr, FALSE);
2800 return SCPE_OK;
2801 }
2802 if (dptr->help)
2803 return dptr->help (st, dptr, uptr, flag, cptr);
2804 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2805 return SCPE_OK;
2806 }
2807 if (dptr->help) {
2808 return dptr->help (st, dptr, uptr, flag, cptr);
2809 }
2810 if (dptr->description)
2811 (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2812 else
2813 (void)fprintf (st, "%s HELP\r\n", dptr->name);
2814 fprint_set_help_ex (st, dptr, TRUE);
2815 fprint_show_help_ex (st, dptr, TRUE);
2816 fprint_attach_help_ex (st, dptr, TRUE);
2817 fprint_reg_help_ex (st, dptr, TRUE);
2818 fprint_brk_help_ex (st, dptr, TRUE);
2819 return SCPE_OK;
2820 }
2821
2822 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2823 {
2824 switch (help[0]) {
2825 case '*':
2826 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2827 if (sim_log)
2828 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2829 break;
2830 default:
2831 fputs (help, stdout);
2832 if (sim_log)
2833 fputs (help, sim_log);
2834 break;
2835 }
2836 return SCPE_OK;
2837 }
2838
2839 t_stat help_cmd (int32 flag, CONST char *cptr)
2840 {
2841 char gbuf[CBUFSIZE];
2842 CTAB *cmdp;
2843
2844 GET_SWITCHES (cptr);
2845 if (sim_switches & SWMASK ('F'))
2846 flag = flag | SCP_HELP_FLAT;
2847 if (*cptr) {
2848 cptr = get_glyph (cptr, gbuf, 0);
2849 if ((cmdp = find_cmd (gbuf))) {
2850 if (*cptr) {
2851 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2852 DEVICE *dptr;
2853 UNIT *uptr;
2854 t_stat r;
2855 cptr = get_glyph (cptr, gbuf, 0);
2856 dptr = find_unit (gbuf, &uptr);
2857 if (dptr == NULL)
2858 dptr = find_dev (gbuf);
2859 if (dptr != NULL) {
2860 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2861 if (sim_log)
2862 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2863 return r;
2864 }
2865 if (cmdp->action == &set_cmd) {
2866
2867 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2868 (cmdp->help))
2869 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2870 }
2871 else {
2872 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2873 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2874 return SCPE_ARG;
2875 return help_cmd_output (flag, shptr->help, NULL);
2876 }
2877 return SCPE_ARG;
2878 }
2879 else
2880 return SCPE_2MARG;
2881 }
2882 if (cmdp->help) {
2883 if (strcmp (cmdp->name, "HELP") == 0) {
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 }
2919 else {
2920 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2921 sim_dflt_dev && sim_dflt_dev->help) {
2922 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2923 if (sim_log)
2924 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2925 }
2926 }
2927 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2928 }
2929 else {
2930 CTAB *cmdpa;
2931 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2932 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2933 sim_printf ("%s is an alias for the %s command:\r\n%s",
2934 cmdp->name, cmdpa->name, cmdpa->help);
2935 break;
2936 }
2937 if (cmdpa->name == NULL)
2938 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2939 }
2940 }
2941 else {
2942 DEVICE *dptr;
2943 UNIT *uptr;
2944 t_stat r;
2945 dptr = find_unit (gbuf, &uptr);
2946 if (dptr == NULL) {
2947 dptr = find_dev (gbuf);
2948 if (dptr == NULL)
2949 return SCPE_ARG;
2950 if (dptr->flags & DEV_DIS)
2951 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2952 }
2953 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2954 if (sim_log)
2955 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2956 return r;
2957 }
2958 }
2959 else {
2960 fprint_help (stdout);
2961 if (sim_log)
2962 fprint_help (sim_log);
2963 }
2964 return SCPE_OK;
2965 }
2966
2967
2968
2969 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2970 {
2971 t_stat status;
2972 if ((cptr == NULL) || (strlen (cptr) == 0))
2973 cptr = getenv("SHELL");
2974 if ((cptr == NULL) || (strlen (cptr) == 0))
2975 cptr = getenv("ComSpec");
2976 (void)fflush(stdout);
2977 if (sim_log)
2978 (void)fflush (sim_log);
2979 if (sim_deb)
2980 (void)fflush (sim_deb);
2981 status = system (cptr);
2982
2983 return status;
2984 }
2985
2986
2987
2988 t_stat echo_cmd (int32 flag, CONST char *cptr)
2989 {
2990 sim_printf ("%s\r\n", cptr);
2991 return SCPE_OK;
2992 }
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014 t_stat do_cmd (int32 flag, CONST char *fcptr)
3015 {
3016 return do_cmd_label (flag, fcptr, NULL);
3017 }
3018
3019 static char *do_position(void)
3020 {
3021 static char cbuf[4*CBUFSIZE];
3022
3023 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3024 sim_do_label[sim_do_depth] ? "::" : "",
3025 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3026 sim_goto_line[sim_do_depth]);
3027 return cbuf;
3028 }
3029
3030 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
3031 {
3032 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3033 CONST char *cptr;
3034 FILE *fpin;
3035 CTAB *cmdp = NULL;
3036 int32 echo, nargs, errabort, i;
3037 int32 saved_sim_do_echo = sim_do_echo,
3038 saved_sim_show_message = sim_show_message,
3039 saved_sim_on_inherit = sim_on_inherit,
3040 saved_sim_quiet = sim_quiet;
3041 t_bool staying;
3042 t_stat stat, stat_nomessage;
3043
3044 stat = SCPE_OK;
3045 staying = TRUE;
3046 if (flag > 0)
3047 GET_SWITCHES (fcptr);
3048 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
3049 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
3050 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
3051 errabort = sim_switches & SWMASK ('E');
3052
3053 abuf[sizeof(abuf)-1] = '\0';
3054 strncpy (abuf, fcptr, sizeof(abuf)-1);
3055 c = abuf;
3056 do_arg[10] = NULL;
3057 for (nargs = 0; nargs < 10; ) {
3058 while (sim_isspace (*c))
3059 c++;
3060 if (*c == 0)
3061 do_arg [nargs++] = NULL;
3062 else {
3063 if (*c == '\'' || *c == '"')
3064 quote = *c++;
3065 else quote = 0;
3066 do_arg[nargs++] = c;
3067 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3068 c++;
3069 if (*c)
3070 *c++ = 0;
3071 }
3072 }
3073
3074 if (do_arg [0] == NULL)
3075 return SCPE_2FARG;
3076 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
3077 strcat (strcpy (cbuf, do_arg[0]), ".ini");
3078 if ((fpin = fopen (cbuf, "r")) == NULL) {
3079 if (flag == 0)
3080 (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3081 return SCPE_OPENERR;
3082 }
3083 }
3084 if (flag >= 0) {
3085 ++sim_do_depth;
3086 if (sim_on_inherit) {
3087 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
3088 for (i=0; i<SCPE_MAX_ERR; i++) {
3089 if (sim_on_actions[sim_do_depth-1][i]) {
3090 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3091 if (NULL == sim_on_actions[sim_do_depth][i]) {
3092 while (--i >= 0) {
3093 FREE(sim_on_actions[sim_do_depth][i]);
3094 sim_on_actions[sim_do_depth][i] = NULL;
3095 }
3096 sim_on_check[sim_do_depth] = 0;
3097 sim_brk_clract ();
3098 --sim_do_depth;
3099 fclose(fpin);
3100 return SCPE_MEM;
3101 }
3102 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3103 }
3104 }
3105 }
3106 }
3107
3108 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
3109 sim_do_label[sim_do_depth] = label;
3110 sim_goto_line[sim_do_depth] = 0;
3111 if (label) {
3112 sim_gotofile = fpin;
3113 sim_do_echo = echo;
3114 stat = goto_cmd (0, label);
3115 if (stat != SCPE_OK) {
3116 strcpy(cbuf, "RETURN SCPE_ARG");
3117 cptr = get_glyph (cbuf, gbuf, 0);
3118 cmdp = find_cmd (gbuf);
3119 goto Cleanup_Return;
3120 }
3121 }
3122 if (errabort)
3123 set_on (1, NULL);
3124
3125 do {
3126 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
3127 if (!sim_do_ocptr[sim_do_depth]) {
3128 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
3129 sim_goto_line[sim_do_depth] += 1;
3130 }
3131 if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {
3132 sim_sub_args(cbuf, sizeof(cbuf), do_arg);
3133 }
3134 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
3135 if (cptr == NULL) {
3136 stat = SCPE_OK;
3137 break;
3138 }
3139 if (*cptr == 0)
3140 continue;
3141 if (echo)
3142 sim_printf("%s> %s\r\n", do_position(), cptr);
3143 if (*cptr == ':')
3144 continue;
3145 cptr = get_glyph_cmd (cptr, gbuf);
3146 sim_switches = 0;
3147 sim_gotofile = fpin;
3148 sim_do_echo = echo;
3149 if ((cmdp = find_cmd (gbuf))) {
3150 if (cmdp->action == &return_cmd)
3151 break;
3152 if (cmdp->action == &do_cmd) {
3153 if (sim_do_depth >= MAX_DO_NEST_LVL)
3154 stat = SCPE_NEST;
3155 else
3156 stat = do_cmd (sim_do_depth+1, cptr);
3157 }
3158 else
3159 stat = cmdp->action (cmdp->arg, cptr);
3160 }
3161 else stat = SCPE_UNK;
3162 echo = sim_do_echo;
3163 stat_nomessage = stat & SCPE_NOMESSAGE;
3164 stat_nomessage = stat_nomessage || (!sim_show_message);
3165 stat = SCPE_BARE_STATUS(stat);
3166 if (cmdp)
3167 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3168 ((cmdp->action != &return_cmd) &&
3169 (cmdp->action != &goto_cmd) &&
3170 (cmdp->action != &on_cmd) &&
3171 (cmdp->action != &echo_cmd)))
3172 sim_last_cmd_stat = stat;
3173 switch (stat) {
3174 case SCPE_AFAIL:
3175 staying = (sim_on_check[sim_do_depth] &&
3176 sim_on_actions[sim_do_depth][stat]);
3177 break;
3178 case SCPE_EXIT:
3179 staying = FALSE;
3180 break;
3181 case SCPE_OK:
3182 case SCPE_STEP:
3183 break;
3184 default:
3185 break;
3186 }
3187 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
3188 (stat != SCPE_STEP)) {
3189 if (!echo && !sim_quiet &&
3190 !stat_nomessage &&
3191 !(cmdp && cmdp->message)) {
3192 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3193 }
3194 }
3195 if (!stat_nomessage) {
3196 if (cmdp && cmdp->message)
3197 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3198 else
3199 if (stat >= SCPE_BASE)
3200 sim_printf ("%s\r\n", sim_error_text (stat));
3201 }
3202 if (stat == SCPE_EXPECT)
3203 stat = SCPE_OK;
3204 if (staying &&
3205 (sim_on_check[sim_do_depth]) &&
3206 (stat != SCPE_OK) &&
3207 (stat != SCPE_STEP)) {
3208 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3209 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3210 else
3211 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3212 }
3213 if (sim_vm_post != NULL)
3214 (*sim_vm_post) (TRUE);
3215 } while (staying);
3216 Cleanup_Return:
3217 if (fpin)
3218 fclose (fpin);
3219 sim_gotofile = NULL;
3220 if (flag >= 0) {
3221 sim_do_echo = saved_sim_do_echo;
3222 sim_show_message = saved_sim_show_message;
3223 sim_on_inherit = saved_sim_on_inherit;
3224 }
3225 sim_quiet = saved_sim_quiet;
3226 if ((flag >= 0) || (!sim_on_inherit)) {
3227 for (i=0; i<SCPE_MAX_ERR; i++) {
3228 FREE (sim_on_actions[sim_do_depth][i]);
3229 sim_on_actions[sim_do_depth][i] = NULL;
3230 }
3231 sim_on_check[sim_do_depth] = 0;
3232 }
3233 if (flag >= 0)
3234 --sim_do_depth;
3235 sim_brk_clract ();
3236 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
3237 sim_string_to_stat (cptr, &stat);
3238 sim_last_cmd_stat = stat;
3239 if (sim_switches & SWMASK ('Q'))
3240 stat |= SCPE_NOMESSAGE;
3241 return stat;
3242 }
3243 return stat | SCPE_NOMESSAGE;
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
3288 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
3289 {
3290 char gbuf[CBUFSIZE];
3291 char *ip = instr, *op, *oend, *tmpbuf;
3292 const char *ap;
3293 char rbuf[CBUFSIZE];
3294 int i;
3295 time_t now;
3296 struct tm *tmnow;
3297
3298 time(&now);
3299 tmnow = localtime(&now);
3300 tmpbuf = (char *)malloc(instr_size);
3301 if (!tmpbuf)
3302 {
3303 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3304 __func__, __FILE__, __LINE__);
3305 #if defined(USE_BACKTRACE)
3306 # if defined(SIGUSR2)
3307 (void)raise(SIGUSR2);
3308
3309 # endif
3310 #endif
3311 abort();
3312 }
3313 op = tmpbuf;
3314 oend = tmpbuf + instr_size - 2;
3315 while (sim_isspace (*ip))
3316 *op++ = *ip++;
3317 for (; *ip && (op < oend); ) {
3318 if ((ip [0] == '\\') &&
3319 ((ip [1] == '%') || (ip [1] == '\\'))) {
3320 ip++;
3321 *op++ = *ip++;
3322 }
3323 else
3324 if ((*ip == '%') &&
3325 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
3326 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
3327 ap = do_arg[ip[1] - '0'];
3328 for (i=0; i<ip[1] - '0'; ++i)
3329 if (do_arg[i] == NULL) {
3330 ap = NULL;
3331 break;
3332 }
3333 ip = ip + 2;
3334 }
3335 else if (ip[1] == '*') {
3336 (void)memset (rbuf, '\0', sizeof(rbuf));
3337 ap = rbuf;
3338 for (i=1; i<=9; ++i)
3339 if (do_arg[i] == NULL)
3340 break;
3341 else
3342 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3343 if (strchr(do_arg[i], ' ')) {
3344 char quote = '"';
3345 if (strchr(do_arg[i], quote))
3346 quote = '\'';
3347 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3348 (i != 1) ? " " : "", quote,
3349 do_arg[i], quote);
3350 }
3351 else
3352 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3353 (i != 1) ? " " : "", do_arg[i]);
3354 }
3355 else
3356 break;
3357 ip = ip + 2;
3358 }
3359 else {
3360 ap = NULL;
3361 (void)get_glyph_nc (ip+1, gbuf, '%');
3362 ap = getenv(gbuf);
3363 if (!ap) {
3364 (void)get_glyph (ip+1, gbuf, '%');
3365 ap = getenv(gbuf);
3366 }
3367 ip += 1 + strlen (gbuf);
3368 if (*ip == '%') ++ip;
3369 if (!ap) {
3370
3371 if (!strcmp ("DATE", gbuf)) {
3372 (void)sprintf (rbuf, "%4d-%02d-%02d",
3373 tmnow->tm_year + 1900,
3374 tmnow->tm_mon + 1,
3375 tmnow->tm_mday);
3376 ap = rbuf;
3377 }
3378 else if (!strcmp ("TIME", gbuf)) {
3379 (void)sprintf (rbuf, "%02d:%02d:%02d",
3380 tmnow->tm_hour,
3381 tmnow->tm_min,
3382 tmnow->tm_sec);
3383 ap = rbuf;
3384 }
3385 else if (!strcmp ("DATETIME", gbuf)) {
3386 (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3387 tmnow->tm_year + 1900,
3388 tmnow->tm_mon + 1,
3389 tmnow->tm_mday,
3390 tmnow->tm_hour,
3391 tmnow->tm_min,
3392 tmnow->tm_sec);
3393 ap = rbuf;
3394 }
3395
3396 if (!strcmp ("LDATE", gbuf)) {
3397 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3398 ap = rbuf;
3399 }
3400 else if (!strcmp ("LTIME", gbuf)) {
3401 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3402 ap = rbuf;
3403 }
3404 else if (!strcmp ("CTIME", gbuf)) {
3405 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3406 ap = rbuf;
3407 }
3408
3409 else if (!strcmp ("DATE_YYYY", gbuf)) {
3410 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3411 ap = rbuf;
3412 }
3413 else if (!strcmp ("DATE_YY", gbuf)) {
3414 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3415 ap = rbuf;
3416 }
3417 else if (!strcmp ("DATE_YC", gbuf)) {
3418 (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3419 ap = rbuf;
3420 }
3421 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3422 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3423 int year = tmnow->tm_year + 1900;
3424 int days = year - 2001;
3425 int leaps = days/4 - days/100 + days/400;
3426 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3427 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3428 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3429 96, 80, 92, 76, 88, 72, 84};
3430 int cal_year = years[selector];
3431
3432 if (!strcmp ("DATE_19XX_YY", gbuf))
3433 (void)sprintf (rbuf, "%d", cal_year);
3434 else
3435 (void)sprintf (rbuf, "%d", cal_year + 1900);
3436 ap = rbuf;
3437 }
3438 else if (!strcmp ("DATE_MM", gbuf)) {
3439 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3440 ap = rbuf;
3441 }
3442 else if (!strcmp ("DATE_MMM", gbuf)) {
3443 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3444 ap = rbuf;
3445 }
3446 else if (!strcmp ("DATE_DD", gbuf)) {
3447 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3448 ap = rbuf;
3449 }
3450 else if (!strcmp ("DATE_D", gbuf)) {
3451 (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3452 ap = rbuf;
3453 }
3454 else if ((!strcmp ("DATE_WW", gbuf)) ||
3455 (!strcmp ("DATE_WYYYY", gbuf))) {
3456 int iso_yr = tmnow->tm_year + 1900;
3457 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3458
3459 if (iso_wk == 0) {
3460 iso_yr = iso_yr - 1;
3461 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3462 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3463 }
3464 else
3465 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3466 ++iso_yr;
3467 iso_wk = 1;
3468 }
3469 if (!strcmp ("DATE_WW", gbuf))
3470 (void)sprintf (rbuf, "%02d", iso_wk);
3471 else
3472 (void)sprintf (rbuf, "%04d", iso_yr);
3473 ap = rbuf;
3474 }
3475 else if (!strcmp ("DATE_JJJ", gbuf)) {
3476 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3477 ap = rbuf;
3478 }
3479 else if (!strcmp ("TIME_HH", gbuf)) {
3480 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3481 ap = rbuf;
3482 }
3483 else if (!strcmp ("TIME_MM", gbuf)) {
3484 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3485 ap = rbuf;
3486 }
3487 else if (!strcmp ("TIME_SS", gbuf)) {
3488 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3489 ap = rbuf;
3490 }
3491 else if (!strcmp ("STATUS", gbuf)) {
3492 (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3493 ap = rbuf;
3494 }
3495 else if (!strcmp ("TSTATUS", gbuf)) {
3496 (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3497 ap = rbuf;
3498 }
3499 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3500 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3501 ap = rbuf;
3502 }
3503 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3504 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3505 ap = rbuf;
3506 }
3507 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3508 (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3509 ap = rbuf;
3510 }
3511 else if (!strcmp ("SIM_QUIET", gbuf)) {
3512 (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3513 ap = rbuf;
3514 }
3515 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3516 (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3517 ap = rbuf;
3518 }
3519 else if (!strcmp ("HOSTID", gbuf)) {
3520 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3521 (void)sprintf (rbuf, "%ld", (long)gethostid());
3522 #else
3523 (void)sprintf (rbuf, "00000000");
3524 #endif
3525 ap = rbuf;
3526 }
3527 else if (!strcmp ("UID", gbuf)) {
3528 #if defined(HAVE_UNISTD)
3529 (void)sprintf (rbuf, "%ld", (long)getuid());
3530 #else
3531 (void)sprintf (rbuf, "0");
3532 #endif
3533 ap = rbuf;
3534 }
3535 else if (!strcmp ("GID", gbuf)) {
3536 #if defined(HAVE_UNISTD)
3537 (void)sprintf (rbuf, "%ld", (long)getgid());
3538 #else
3539 (void)sprintf (rbuf, "0");
3540 #endif
3541 ap = rbuf;
3542 }
3543 else if (!strcmp ("EUID", gbuf)) {
3544 #if defined(HAVE_UNISTD)
3545 (void)sprintf (rbuf, "%ld", (long)geteuid());
3546 #else
3547 (void)sprintf (rbuf, "0");
3548 #endif
3549 ap = rbuf;
3550 }
3551 else if (!strcmp ("EGID", gbuf)) {
3552 #if defined(HAVE_UNISTD)
3553 (void)sprintf (rbuf, "%ld", (long)getegid());
3554 #else
3555 (void)sprintf (rbuf, "0");
3556 #endif
3557 ap = rbuf;
3558 }
3559 else if (!strcmp ("PID", gbuf)) {
3560 #if defined(HAVE_UNISTD)
3561 (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3562 #else
3563 (void)sprintf (rbuf, "0");
3564 #endif
3565 ap = rbuf;
3566 }
3567 else if (!strcmp ("PPID", gbuf)) {
3568 #if defined(HAVE_UNISTD)
3569 (void)sprintf (rbuf, "%ld", (long)getppid());
3570 #else
3571 (void)sprintf (rbuf, "0");
3572 #endif
3573 ap = rbuf;
3574 }
3575 else if (!strcmp ("PGID", gbuf)) {
3576 #if defined(HAVE_UNISTD)
3577 (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3578 #else
3579 (void)sprintf (rbuf, "0");
3580 #endif
3581 ap = rbuf;
3582 }
3583 else if (!strcmp ("SID", gbuf)) {
3584 #if defined(HAVE_UNISTD)
3585 (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3586 #else
3587 (void)sprintf (rbuf, "0");
3588 #endif
3589 ap = rbuf;
3590 }
3591 else if (!strcmp ("ENDIAN", gbuf)) {
3592 #if ( defined(DECLITEND) && DECLITEND == 1 )
3593 (void)sprintf (rbuf, "LITTLE");
3594 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3595 (void)sprintf (rbuf, "BIG");
3596 #else
3597 (void)sprintf (rbuf, "UNKNOWN");
3598 #endif
3599 ap = rbuf;
3600 }
3601 else if (!strcmp("SIM_NAME", gbuf)) {
3602 (void)sprintf (rbuf, "%s", sim_name);
3603 ap = rbuf;
3604 }
3605 else if (!strcmp("SIM_VERSION", gbuf)) {
3606 #if defined(VER_H_GIT_VERSION)
3607 (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3608 #else
3609 (void)sprintf (rbuf, "UNKNOWN");
3610 #endif
3611 ap = rbuf;
3612 }
3613 else if (!strcmp("SIM_HASH", gbuf)) {
3614 #if defined(VER_H_GIT_HASH)
3615 (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3616 #else
3617 (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3618 #endif
3619 ap = rbuf;
3620 }
3621 else if (!strcmp("SIM_RELT", gbuf)) {
3622 #if defined(VER_H_GIT_RELT)
3623 (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3624 #else
3625 (void)sprintf (rbuf, "X");
3626 #endif
3627 ap = rbuf;
3628 }
3629 else if (!strcmp("SIM_DATE", gbuf)) {
3630 #if defined(VER_H_GIT_DATE)
3631 (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3632 #else
3633 (void)sprintf (rbuf, "UNKNOWN");
3634 #endif
3635 ap = rbuf;
3636 }
3637 else if ((!strcmp("CORES", gbuf)) ||
3638 (!strcmp("SIM_CORES", gbuf))) {
3639 (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3640 ap = rbuf;
3641 }
3642 else if ((!strcmp("CPUS", gbuf)) ||
3643 (!strcmp("SIM_PROCESSORS", gbuf))) {
3644 (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3645 ap = rbuf;
3646 }
3647 }
3648 }
3649 if (ap) {
3650 while (*ap && (op < oend))
3651 *op++ = *ap++;
3652 }
3653 }
3654 else
3655 *op++ = *ip++;
3656 }
3657 *op = 0;
3658 strcpy (instr, tmpbuf);
3659 FREE (tmpbuf);
3660 return;
3661 }
3662
3663 static
3664 int sim_cmp_string (const char *s1, const char *s2)
3665 {
3666 long int v1, v2;
3667 char *ep1, *ep2;
3668
3669 v1 = strtol(s1+1, &ep1, 0);
3670 v2 = strtol(s2+1, &ep2, 0);
3671 if ((ep1 != s1 + strlen (s1) - 1) ||
3672 (ep2 != s2 + strlen (s2) - 1))
3673 return strcmp (s1, s2);
3674 if (v1 == v2)
3675 return 0;
3676 if (v1 < v2)
3677 return -1;
3678 return 1;
3679 }
3680
3681
3682
3683 t_stat assert_cmd (int32 flag, CONST char *cptr)
3684 {
3685 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3686 CONST char *tptr, *gptr;
3687 REG *rptr;
3688 uint32 idx = 0;
3689 t_value val;
3690 t_stat r;
3691 t_bool Not = FALSE;
3692 t_bool result;
3693 t_addr addr = 0;
3694 t_stat reason = SCPE_AFAIL;
3695
3696 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3697
3698 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3699 # pragma diagnostic push
3700 # pragma diag_suppress = integer_sign_change
3701 #endif
3702 sim_stabr.boolop = sim_staba.boolop = -1;
3703 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3704 # pragma diagnostic pop
3705 #endif
3706 if (*cptr == 0)
3707 return SCPE_2FARG;
3708 tptr = get_glyph (cptr, gbuf, 0);
3709 if (!strcmp (gbuf, "NOT")) {
3710 Not = TRUE;
3711 cptr = (CONST char *)tptr;
3712 }
3713 if (*cptr == '"') {
3714 char op[CBUFSIZE];
3715 static struct {
3716 const char *op;
3717 int aval;
3718 int bval;
3719 t_bool invert;
3720 } *optr, compare_ops[] =
3721 {
3722 { "==", 0, 0, FALSE },
3723 { "EQU", 0, 0, FALSE },
3724 { "!=", 0, 0, TRUE },
3725 { "NEQ", 0, 0, TRUE },
3726 { "<", -1, -1, FALSE },
3727 { "LSS", -1, -1, FALSE },
3728 { "<=", 0, -1, FALSE },
3729 { "LEQ", 0, -1, FALSE },
3730 { ">", 1, 1, FALSE },
3731 { "GTR", 1, 1, FALSE },
3732 { ">=", 0, 1, FALSE },
3733 { "GEQ", 0, 1, FALSE },
3734 { NULL }
3735 };
3736
3737 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3738
3739 if (!*tptr)
3740 return SCPE_2FARG;
3741 cptr += strlen (gbuf);
3742 while (sim_isspace (*cptr))
3743 ++cptr;
3744 (void)get_glyph (cptr, op, '"');
3745 for (optr = compare_ops; optr->op; optr++)
3746 if (0 == strcmp (op, optr->op))
3747 break;
3748 if (!optr->op)
3749 return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3750 cptr += strlen (op);
3751 while (sim_isspace (*cptr))
3752 ++cptr;
3753 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3754
3755 if (*cptr) {
3756 if (flag)
3757 return SCPE_2MARG;
3758 }
3759 else {
3760 if (!flag)
3761 return SCPE_2FARG;
3762 }
3763 result = sim_cmp_string (gbuf, gbuf2);
3764 result = ((result == optr->aval) || (result == optr->bval));
3765 if (optr->invert)
3766 result = !result;
3767 }
3768 else {
3769 cptr = get_glyph (cptr, gbuf, 0);
3770 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3771 if (rptr) {
3772 if (*gptr == '[') {
3773 if (rptr->depth <= 1)
3774 return SCPE_ARG;
3775 idx = (uint32) strtotv (++gptr, &tptr, 10);
3776 if ((gptr == tptr) || (*tptr++ != ']'))
3777 return SCPE_ARG;
3778 gptr = tptr;
3779 }
3780 else idx = 0;
3781 if (idx >= rptr->depth)
3782 return SCPE_SUB;
3783 }
3784 else {
3785 if (sim_dfdev && sim_vm_parse_addr)
3786 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3787 else if (sim_dfdev)
3788 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3789 if (gbuf == gptr)
3790 return SCPE_NXREG;
3791 }
3792 if (*gptr != 0)
3793 (void)get_glyph (gptr, gbuf, 0);
3794 else {
3795 if (*cptr == 0)
3796 return SCPE_2FARG;
3797 cptr = get_glyph (cptr, gbuf, 0);
3798 }
3799 if (*cptr) {
3800 if (flag)
3801 return SCPE_2MARG;
3802 }
3803 else {
3804 if (!flag)
3805 return SCPE_2FARG;
3806 }
3807 if (rptr) {
3808 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3809 # pragma diagnostic push
3810 # pragma diag_suppress = integer_sign_change
3811 #endif
3812 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3813 (sim_stabr.boolop == -1))
3814 return SCPE_MISVAL;
3815 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3816 # pragma diagnostic pop
3817 #endif
3818 val = get_rval (rptr, idx);
3819 result = test_search (&val, &sim_stabr);
3820 }
3821 else {
3822 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3823 # pragma diagnostic push
3824 # pragma diag_suppress = integer_sign_change
3825 #endif
3826 if (sim_dfdev)
3827 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3828 (sim_staba.boolop == -1))
3829 return SCPE_MISVAL;
3830 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3831 # pragma diagnostic pop
3832 #endif
3833 if (sim_dfdev)
3834 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3835 if (reason != SCPE_OK)
3836 return reason;
3837 result = test_search (sim_eval, &sim_staba);
3838 }
3839 }
3840 if (Not ^ result) {
3841 if (!flag)
3842 sim_brk_setact (cptr);
3843 }
3844 else
3845 if (flag)
3846 return SCPE_AFAIL;
3847 return SCPE_OK;
3848 }
3849
3850
3851
3852 t_stat send_cmd (int32 flag, CONST char *cptr)
3853 {
3854 char gbuf[CBUFSIZE];
3855 CONST char *tptr;
3856 uint8 dbuf[CBUFSIZE];
3857 uint32 dsize = 0;
3858 uint32 delay = 0;
3859 uint32 after = 0;
3860 t_stat r;
3861 SEND *snd = NULL;
3862
3863 GET_SWITCHES (cptr);
3864 tptr = get_glyph (cptr, gbuf, ',');
3865 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3866 r = tmxr_locate_line_send (gbuf, &snd);
3867 if (r != SCPE_OK)
3868 return r;
3869 cptr = tptr;
3870 tptr = get_glyph (tptr, gbuf, ',');
3871 }
3872 else
3873 snd = sim_cons_get_send ();
3874
3875 while (*cptr) {
3876 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3877 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3878 if (r != SCPE_OK)
3879 return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3880 cptr = tptr;
3881 tptr = get_glyph (cptr, gbuf, ',');
3882 continue;
3883 }
3884 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3885 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3886 if (r != SCPE_OK)
3887 return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3888 cptr = tptr;
3889 tptr = get_glyph (cptr, gbuf, ',');
3890 continue;
3891 }
3892 if ((*cptr == '"') || (*cptr == '\''))
3893 break;
3894 return SCPE_ARG;
3895 }
3896 if (*cptr) {
3897 if ((*cptr != '"') && (*cptr != '\''))
3898 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3899 cptr = get_glyph_quoted (cptr, gbuf, 0);
3900 if (*cptr != '\0')
3901 return SCPE_2MARG;
3902
3903 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3904 return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3905 }
3906 if ((dsize == 0) && (delay == 0) && (after == 0))
3907 return SCPE_2FARG;
3908 return sim_send_input (snd, dbuf, dsize, after, delay);
3909 }
3910
3911 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3912 {
3913 char gbuf[CBUFSIZE];
3914 CONST char *tptr;
3915 t_stat r;
3916 SEND *snd = NULL;
3917
3918 tptr = get_glyph (cptr, gbuf, ',');
3919 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3920 r = tmxr_locate_line_send (gbuf, &snd);
3921 if (r != SCPE_OK)
3922 return r;
3923 cptr = tptr;
3924 }
3925 else
3926 snd = sim_cons_get_send ();
3927 if (*cptr)
3928 return SCPE_2MARG;
3929 return sim_show_send_input (st, snd);
3930 }
3931
3932 t_stat expect_cmd (int32 flag, CONST char *cptr)
3933 {
3934 char gbuf[CBUFSIZE];
3935 CONST char *tptr;
3936 EXPECT *exp = NULL;
3937
3938 GET_SWITCHES (cptr);
3939 tptr = get_glyph (cptr, gbuf, ',');
3940 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3941 cptr = tptr;
3942 } else {
3943 exp = sim_cons_get_expect ();
3944 }
3945
3946 if (flag) {
3947 return sim_set_expect (exp, cptr);
3948 } else {
3949 if (exp == NULL) {
3950 exp = sim_cons_get_expect();
3951 }
3952 return sim_set_noexpect (exp, cptr);
3953 }
3954 }
3955
3956 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3957 {
3958 char gbuf[CBUFSIZE];
3959 CONST char *tptr;
3960 EXPECT *exp = NULL;
3961 t_stat r;
3962
3963 tptr = get_glyph (cptr, gbuf, ',');
3964 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3965 r = tmxr_locate_line_expect (gbuf, &exp);
3966 if (r != SCPE_OK)
3967 return r;
3968 cptr = tptr;
3969 }
3970 else
3971 exp = sim_cons_get_expect ();
3972 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3973 return SCPE_ARG;
3974 tptr = get_glyph_quoted (cptr, gbuf, 0);
3975 if (*tptr != '\0')
3976 return SCPE_2MARG;
3977 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3978 return SCPE_ARG;
3979 return sim_exp_show (st, exp, gbuf);
3980 }
3981
3982
3983
3984 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3985 {
3986 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3987 const char *cptr;
3988 long fpos;
3989 int32 saved_do_echo = sim_do_echo;
3990 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3991
3992 if (NULL == sim_gotofile) return SCPE_UNK;
3993 (void)get_glyph (fcptr, gbuf1, 0);
3994 if ('\0' == gbuf1[0]) return SCPE_ARG;
3995 fpos = ftell(sim_gotofile);
3996 rewind(sim_gotofile);
3997 sim_goto_line[sim_do_depth] = 0;
3998 sim_do_echo = 0;
3999 while (1) {
4000 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
4001 if (cptr == NULL) break;
4002 sim_goto_line[sim_do_depth] += 1;
4003 if (*cptr == 0) continue;
4004 if (*cptr != ':') continue;
4005 ++cptr;
4006 while (sim_isspace (*cptr)) ++cptr;
4007 cptr = get_glyph (cptr, gbuf, 0);
4008 if (0 == strcmp(gbuf, gbuf1)) {
4009 sim_brk_clract ();
4010 sim_do_echo = saved_do_echo;
4011 if (sim_do_echo)
4012 sim_printf("%s> %s\r\n", do_position(), cbuf);
4013 return SCPE_OK;
4014 }
4015 }
4016 sim_do_echo = saved_do_echo;
4017 fseek(sim_gotofile, fpos, SEEK_SET);
4018 sim_goto_line[sim_do_depth] = saved_goto_line;
4019 return SCPE_ARG;
4020 }
4021
4022
4023
4024
4025
4026
4027
4028
4029 t_stat return_cmd (int32 flag, CONST char *fcptr)
4030 {
4031 return SCPE_UNK;
4032 }
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042 t_stat shift_cmd (int32 flag, CONST char *fcptr)
4043 {
4044 return SCPE_UNK;
4045 }
4046
4047
4048
4049
4050
4051
4052
4053
4054 t_stat call_cmd (int32 flag, CONST char *fcptr)
4055 {
4056 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4057 const char *cptr;
4058
4059 if (NULL == sim_gotofile) return SCPE_UNK;
4060 cptr = get_glyph (fcptr, gbuf, 0);
4061 if ('\0' == gbuf[0]) return SCPE_ARG;
4062 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4063 sim_switches |= SWMASK ('O');
4064 return do_cmd_label (flag, cbuf, gbuf);
4065 }
4066
4067
4068
4069 t_stat on_cmd (int32 flag, CONST char *cptr)
4070 {
4071 char gbuf[CBUFSIZE];
4072 t_stat cond;
4073
4074 cptr = get_glyph (cptr, gbuf, 0);
4075 if ('\0' == gbuf[0]) return SCPE_ARG;
4076 if (0 == strcmp("ERROR", gbuf))
4077 cond = 0;
4078 else
4079 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4080 return SCPE_ARG;
4081 if ((NULL == cptr) || ('\0' == *cptr)) {
4082 FREE(sim_on_actions[sim_do_depth][cond]);
4083 sim_on_actions[sim_do_depth][cond] = NULL; }
4084 else {
4085 sim_on_actions[sim_do_depth][cond] =
4086 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4087 if (!sim_on_actions[sim_do_depth][cond])
4088 {
4089 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4090 __func__, __FILE__, __LINE__);
4091 #if defined(USE_BACKTRACE)
4092 # if defined(SIGUSR2)
4093 (void)raise(SIGUSR2);
4094
4095 # endif
4096 #endif
4097 abort();
4098 }
4099 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4100 }
4101 return SCPE_OK;
4102 }
4103
4104
4105
4106 t_stat noop_cmd (int32 flag, CONST char *cptr)
4107 {
4108 if (cptr && (*cptr != 0))
4109 return SCPE_2MARG;
4110 return SCPE_OK;
4111 }
4112
4113
4114
4115 t_stat set_on (int32 flag, CONST char *cptr)
4116 {
4117 if ((flag) && (cptr) && (*cptr)) {
4118 char gbuf[CBUFSIZE];
4119
4120 cptr = get_glyph (cptr, gbuf, 0);
4121 if (((MATCH_CMD(gbuf,"INHERIT")) &&
4122 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
4123 (*cptr))
4124 return SCPE_2MARG;
4125 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
4126 sim_on_inherit = 1;
4127 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
4128 sim_on_inherit = 0;
4129 return SCPE_OK;
4130 }
4131 if (cptr && (*cptr != 0))
4132 return SCPE_2MARG;
4133 sim_on_check[sim_do_depth] = flag;
4134 if ((sim_do_depth != 0) &&
4135 (NULL == sim_on_actions[sim_do_depth][0])) {
4136 sim_on_actions[sim_do_depth][0] =
4137 (char *)malloc(1+strlen("RETURN"));
4138 if (sim_on_actions[sim_do_depth][0] == NULL)
4139 {
4140 (void)sir_emerg ("FATAL: Out of memory! Aborting at %s[%s:%d]",
4141 __func__, __FILE__, __LINE__);
4142 #if defined(USE_BACKTRACE)
4143 # if defined(SIGUSR2)
4144 (void)raise(SIGUSR2);
4145
4146 # endif
4147 #endif
4148 abort();
4149 }
4150 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4151 }
4152 if ((sim_do_depth != 0) &&
4153 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
4154 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
4155 (char *)malloc(1+strlen("RETURN"));
4156 if (sim_on_actions[sim_do_depth][SCPE_AFAIL] == NULL)
4157 {
4158 (void)sir_emerg ("FATAL: Out of memory! Aborting at %s[%s:%d]",
4159 __func__, __FILE__, __LINE__);
4160 #if defined(USE_BACKTRACE)
4161 # if defined(SIGUSR2)
4162 (void)raise(SIGUSR2);
4163
4164 # endif
4165 #endif
4166 abort();
4167 }
4168 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4169 }
4170 return SCPE_OK;
4171 }
4172
4173
4174
4175 t_stat set_verify (int32 flag, CONST char *cptr)
4176 {
4177 if (cptr && (*cptr != 0))
4178 return SCPE_2MARG;
4179 if (flag == sim_do_echo)
4180 return SCPE_OK;
4181 sim_do_echo = flag;
4182 return SCPE_OK;
4183 }
4184
4185
4186
4187 t_stat set_message (int32 flag, CONST char *cptr)
4188 {
4189 if (cptr && (*cptr != 0))
4190 return SCPE_2MARG;
4191 if (flag == sim_show_message)
4192 return SCPE_OK;
4193 sim_show_message = flag;
4194 return SCPE_OK;
4195 }
4196
4197
4198
4199 t_stat set_localopc (int32 flag, CONST char *cptr)
4200 {
4201 if (cptr && (*cptr != 0))
4202 return SCPE_2MARG;
4203 if (flag == sim_localopc)
4204 return SCPE_OK;
4205 sim_localopc = flag;
4206 return SCPE_OK;
4207 }
4208
4209
4210 t_stat set_quiet (int32 flag, CONST char *cptr)
4211 {
4212 if (cptr && (*cptr != 0))
4213 return SCPE_2MARG;
4214 if (flag == sim_quiet)
4215 return SCPE_OK;
4216 sim_quiet = flag;
4217 return SCPE_OK;
4218 }
4219
4220
4221
4222 t_stat sim_set_environment (int32 flag, CONST char *cptr)
4223 {
4224 char varname[CBUFSIZE];
4225
4226 if ((NULL == cptr) || (*cptr == 0))
4227 return SCPE_2FARG;
4228 cptr = get_glyph (cptr, varname, '=');
4229 setenv(varname, cptr, 1);
4230 return SCPE_OK;
4231 }
4232
4233
4234
4235 t_stat set_cmd (int32 flag, CONST char *cptr)
4236 {
4237 uint32 lvl = 0;
4238 t_stat r;
4239 char gbuf[CBUFSIZE], *cvptr;
4240 CONST char *svptr;
4241 DEVICE *dptr;
4242 UNIT *uptr;
4243 MTAB *mptr;
4244 CTAB *gcmdp;
4245 C1TAB *ctbr = NULL, *glbr;
4246
4247 GET_SWITCHES (cptr);
4248 if ((NULL == cptr) || (*cptr == 0))
4249 return SCPE_2FARG;
4250 cptr = get_glyph (svptr = cptr, gbuf, 0);
4251
4252 if ((dptr = find_dev (gbuf))) {
4253 uptr = dptr->units;
4254 ctbr = set_dev_tab;
4255 lvl = MTAB_VDV;
4256 GET_SWITCHES (cptr);
4257 }
4258 else if ((dptr = find_unit (gbuf, &uptr))) {
4259 if (uptr == NULL)
4260 return SCPE_NXUN;
4261 ctbr = set_unit_tab;
4262 lvl = MTAB_VUN;
4263 GET_SWITCHES (cptr);
4264 }
4265 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
4266 GET_SWITCHES (cptr);
4267 return gcmdp->action (gcmdp->arg, cptr);
4268 }
4269 else {
4270 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4271 if ((cvptr = strchr (gbuf, '=')))
4272 *cvptr++ = 0;
4273 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4274 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4275 dptr = sim_dflt_dev;
4276 cptr = svptr;
4277 while (sim_isspace(*cptr))
4278 ++cptr;
4279 break;
4280 }
4281 }
4282 }
4283 if (!dptr)
4284 return SCPE_NXDEV;
4285 lvl = MTAB_VDV;
4286 uptr = dptr->units;
4287 }
4288 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4289 return SCPE_2FARG;
4290 GET_SWITCHES (cptr);
4291
4292 while (*cptr != 0) {
4293 cptr = get_glyph (svptr = cptr, gbuf, ',');
4294 if (0 == strcmp (gbuf, ";"))
4295 break;
4296 if ((cvptr = strchr (gbuf, '=')))
4297 *cvptr++ = 0;
4298 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4299 if ((mptr->mstring) &&
4300 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4301 if (mptr->mask & MTAB_XTD) {
4302 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4303 return SCPE_ARG;
4304 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4305 return SCPE_UDIS;
4306 if (mptr->valid) {
4307 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4308 svptr = get_glyph_quoted (svptr, gbuf, ',');
4309 if ((cvptr = strchr (gbuf, '='))) {
4310 *cvptr++ = 0;
4311 cptr = svptr;
4312 }
4313 }
4314 else {
4315 if (cvptr && MODMASK(mptr,MTAB_NC)) {
4316 (void)get_glyph_nc (svptr, gbuf, ',');
4317 if ((cvptr = strchr (gbuf, '=')))
4318 *cvptr++ = 0;
4319 }
4320 }
4321 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4322 if (r != SCPE_OK)
4323 return r;
4324 }
4325 else if (!mptr->desc)
4326 break;
4327 else if (cvptr)
4328 return SCPE_ARG;
4329 else *((int32 *) mptr->desc) = mptr->match;
4330 }
4331 else {
4332 if (cvptr)
4333 return SCPE_ARG;
4334 if (uptr->flags & UNIT_DIS)
4335 return SCPE_UDIS;
4336 if ((mptr->valid) &&
4337 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4338 return r;
4339 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4340 (mptr->match & mptr->mask);
4341 }
4342 break;
4343 }
4344 }
4345 if (!mptr || (mptr->mask == 0)) {
4346 if ((glbr = find_c1tab (ctbr, gbuf))) {
4347 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
4348 if (r != SCPE_OK)
4349 return r;
4350 }
4351 else if (!dptr->modifiers)
4352 return SCPE_NOPARAM;
4353 else return SCPE_NXPAR;
4354 }
4355 }
4356 return SCPE_OK;
4357 }
4358
4359
4360
4361 CTAB *find_ctab (CTAB *tab, const char *gbuf)
4362 {
4363 if (!tab)
4364 return NULL;
4365 for (; tab->name != NULL; tab++) {
4366 if (MATCH_CMD (gbuf, tab->name) == 0)
4367 return tab;
4368 }
4369 return NULL;
4370 }
4371
4372 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
4373 {
4374 if (!tab)
4375 return NULL;
4376 for (; tab->name != NULL; tab++) {
4377 if (MATCH_CMD (gbuf, tab->name) == 0)
4378 return tab;
4379 }
4380 return NULL;
4381 }
4382
4383
4384
4385 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4386 {
4387 if (cptr)
4388 return SCPE_ARG;
4389 dptr->dradix = flag & 037;
4390 return SCPE_OK;
4391 }
4392
4393
4394
4395 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4396 {
4397 UNIT *up;
4398 uint32 i;
4399
4400 if (cptr)
4401 return SCPE_ARG;
4402 if ((dptr->flags & DEV_DISABLE) == 0)
4403 return SCPE_NOFNC;
4404 if (flag) {
4405 if ((dptr->flags & DEV_DIS) == 0)
4406 return SCPE_OK;
4407 dptr->flags = dptr->flags & ~DEV_DIS;
4408 }
4409 else {
4410 if (dptr->flags & DEV_DIS)
4411 return SCPE_OK;
4412 for (i = 0; i < dptr->numunits; i++) {
4413 up = (dptr->units) + i;
4414 if ((up->flags & UNIT_ATT) || sim_is_active (up))
4415 return SCPE_NOFNC;
4416 }
4417 dptr->flags = dptr->flags | DEV_DIS;
4418 }
4419 if (dptr->reset)
4420 return dptr->reset (dptr);
4421 else return SCPE_OK;
4422 }
4423
4424
4425
4426 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4427 {
4428 if (cptr)
4429 return SCPE_ARG;
4430 if (!(uptr->flags & UNIT_DISABLE))
4431 return SCPE_NOFNC;
4432 if (flag)
4433 uptr->flags = uptr->flags & ~UNIT_DIS;
4434 else {
4435 if ((uptr->flags & UNIT_ATT) ||
4436 sim_is_active (uptr))
4437 return SCPE_NOFNC;
4438 uptr->flags = uptr->flags | UNIT_DIS;
4439 }
4440 return SCPE_OK;
4441 }
4442
4443
4444
4445 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4446 {
4447 char gbuf[CBUFSIZE];
4448 DEBTAB *dep;
4449
4450 if ((dptr->flags & DEV_DEBUG) == 0)
4451 return SCPE_NOFNC;
4452 if (cptr == NULL) {
4453 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4454 if (flag && dptr->debflags) {
4455 for (dep = dptr->debflags; dep->name != NULL; dep++)
4456 dptr->dctrl = dptr->dctrl | dep->mask;
4457 }
4458 return SCPE_OK;
4459 }
4460 if (dptr->debflags == NULL)
4461 return SCPE_ARG;
4462 while (*cptr) {
4463 cptr = get_glyph (cptr, gbuf, ';');
4464 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4465 if (strcmp (dep->name, gbuf) == 0) {
4466 if (flag)
4467 dptr->dctrl = dptr->dctrl | dep->mask;
4468 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4469 break;
4470 }
4471 }
4472 if (dep->mask == 0)
4473 return SCPE_ARG;
4474 }
4475 return SCPE_OK;
4476 }
4477
4478
4479
4480 t_stat show_cmd (int32 flag, CONST char *cptr)
4481 {
4482 t_stat r = SCPE_IERR;
4483
4484 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4485
4486 if (NULL == cptr)
4487 return r;
4488 if (sim_ofile) {
4489 r = show_cmd_fi (sim_ofile, flag, cptr);
4490 fclose (sim_ofile);
4491 }
4492 else {
4493 r = show_cmd_fi (stdout, flag, cptr);
4494 if (sim_log && (sim_log != stdout))
4495 show_cmd_fi (sim_log, flag, cptr);
4496 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4497 show_cmd_fi (sim_deb, flag, cptr);
4498 }
4499 return r;
4500 }
4501
4502 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4503 {
4504 uint32 lvl = 0xFFFFFFFF;
4505 char gbuf[CBUFSIZE], *cvptr;
4506 CONST char *svptr;
4507 DEVICE *dptr;
4508 UNIT *uptr;
4509 MTAB *mptr;
4510 SHTAB *shtb = NULL, *shptr;
4511
4512 GET_SWITCHES (cptr);
4513 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4514 return SCPE_2FARG;
4515 cptr = get_glyph (svptr = cptr, gbuf, 0);
4516
4517 if ((dptr = find_dev (gbuf))) {
4518 uptr = dptr->units;
4519 shtb = show_dev_tab;
4520 lvl = MTAB_VDV;
4521 GET_SWITCHES (cptr);
4522 }
4523 else if ((dptr = find_unit (gbuf, &uptr))) {
4524 if (uptr == NULL)
4525 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4526 if (uptr->flags & UNIT_DIS)
4527 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4528 shtb = show_unit_tab;
4529 lvl = MTAB_VUN;
4530 GET_SWITCHES (cptr);
4531 }
4532 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4533 GET_SWITCHES (cptr);
4534 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4535 }
4536 else {
4537 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4538 if ((cvptr = strchr (gbuf, '=')))
4539 *cvptr++ = 0;
4540 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4541 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4542 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4543 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4544 dptr = sim_dflt_dev;
4545 lvl = MTAB_VDV;
4546 cptr = svptr;
4547 while (sim_isspace(*cptr))
4548 ++cptr;
4549 break;
4550 }
4551 }
4552 }
4553 if (!dptr) {
4554 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4555 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4556 else
4557 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);
4558 }
4559 }
4560
4561 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4562 return (lvl == MTAB_VDV)?
4563 show_device (ofile, dptr, 0):
4564 show_unit (ofile, dptr, uptr, -1);
4565 }
4566 GET_SWITCHES (cptr);
4567
4568 while (*cptr != 0) {
4569 cptr = get_glyph (cptr, gbuf, ',');
4570 if ((cvptr = strchr (gbuf, '=')))
4571 *cvptr++ = 0;
4572 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4573 if (((mptr->mask & MTAB_XTD)?
4574 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4575 ((mptr->disp && mptr->pstring &&
4576 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4577 )) {
4578 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4579 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4580 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4581 break;
4582 }
4583 }
4584 if (!mptr || (mptr->mask == 0)) {
4585 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4586 t_stat r;
4587
4588 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4589 if (r != SCPE_OK)
4590 return r;
4591 }
4592 else {
4593 if (!dptr->modifiers)
4594 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4595 else
4596 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4597 }
4598 }
4599 }
4600 return SCPE_OK;
4601 }
4602
4603 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4604 {
4605 if (!tab)
4606 return NULL;
4607 for (; tab->name != NULL; tab++) {
4608 if (MATCH_CMD (gbuf, tab->name) == 0)
4609 return tab;
4610 }
4611 return NULL;
4612 }
4613
4614
4615
4616 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4617 {
4618 uint32 j, udbl, ucnt;
4619 UNIT *uptr;
4620 int32 toks = 0;
4621
4622 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4623 (void)fprintf (st, "%s", sim_dname (dptr));
4624 if ((flag == 2) && dptr->description) {
4625 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4626 }
4627 else {
4628 if ((sim_switches & SWMASK ('D')) && dptr->description)
4629 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4630 }
4631 if (qdisable (dptr)) {
4632 (void)fprintf (st, "\tdisabled\r\n");
4633 return SCPE_OK;
4634 }
4635 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4636 uptr = dptr->units + j;
4637 if (!(uptr->flags & UNIT_DIS))
4638 ucnt++;
4639 else if (uptr->flags & UNIT_DISABLE)
4640 udbl++;
4641 }
4642
4643 if (dptr->numunits == 0) {
4644
4645
4646 }
4647 else
4648 {
4649 if (ucnt == 0) {
4650 fprint_sep (st, &toks);
4651 (void)fprintf (st, "all units disabled\r\n");
4652 }
4653 else if ((ucnt + udbl) == 1) {
4654 fprint_sep (st, &toks);
4655 (void)fprintf (st, " 1 unit\r\n");
4656 }
4657 else if ((ucnt > 1) || (udbl > 0)) {
4658 fprint_sep (st, &toks);
4659 (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4660 }
4661 else
4662 if ((flag != 2) || !dptr->description || toks)
4663 (void)fprintf (st, "\r\n");
4664 toks = 0;
4665 }
4666 if (flag)
4667 return SCPE_OK;
4668 for (j = 0; j < dptr->numunits; j++) {
4669 uptr = dptr->units + j;
4670 if ((uptr->flags & UNIT_DIS) == 0)
4671 show_unit (st, dptr, uptr, ucnt + udbl);
4672 }
4673 }
4674 return SCPE_OK;
4675 }
4676
4677 void fprint_sep (FILE *st, int32 *tokens)
4678 {
4679 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4680 *tokens += 1;
4681 }
4682
4683 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4684 {
4685 int32 u = (int32)(uptr - dptr->units);
4686 int32 toks = 0;
4687
4688 if (flag > 1)
4689 (void)fprintf (st, " %s%d\r\n", sim_dname (dptr), u);
4690 else if (flag < 0)
4691 (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4692 if (uptr->flags & UNIT_ATT) {
4693 fprint_sep (st, &toks);
4694 (void)fprintf (st, "status : attached to %s", uptr->filename);
4695 if (uptr->flags & UNIT_RO)
4696 (void)fprintf (st, ", read only");
4697 }
4698 else {
4699 if (uptr->flags & UNIT_ATTABLE) {
4700 fprint_sep (st, &toks);
4701 (void)fprintf (st, "status : not attached");
4702 }
4703 }
4704 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4705 fprint_sep (st, &toks);
4706 fprint_capac (st, dptr, uptr);
4707 }
4708 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4709 if (toks || (flag < 0) || (flag > 1))
4710 (void)fprintf (st, "\r\n");
4711 return SCPE_OK;
4712 }
4713
4714 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4715 {
4716 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4717 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4718 t_offset mval;
4719 t_offset psize = (t_offset)uptr->capac;
4720 char *scale, *width;
4721
4722 if (sim_switches & SWMASK ('B'))
4723 kval = 1024;
4724 mval = kval * kval;
4725 if (dptr->flags & DEV_SECTORS) {
4726 kval = kval / 512;
4727 mval = mval / 512;
4728 }
4729 if ((dptr->dwidth / dptr->aincr) > 8)
4730 width = "W";
4731 else
4732 width = "B";
4733 if ((psize < (kval * 10)) &&
4734 (0 != (psize % kval))) {
4735 scale = "";
4736 }
4737 else if ((psize < (mval * 10)) &&
4738 (0 != (psize % mval))){
4739 scale = "K";
4740 psize = psize / kval;
4741 }
4742 else {
4743 scale = "M";
4744 psize = psize / mval;
4745 }
4746 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4747 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4748 return capac_buf;
4749 }
4750
4751 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4752 {
4753 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4754 }
4755
4756
4757
4758 extern void print_default_base_system_script (void);
4759 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4760 {
4761 #if !defined(PERF_STRIP)
4762 print_default_base_system_script();
4763 #endif
4764 return 0;
4765 }
4766
4767 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4768 sim_printf (" %s ", label);
4769 sim_printf (" %2d %3o(8) '", length, offset);
4770 for (int l = 0; l < length; l ++)
4771 {
4772 unsigned int byte = PROM[offset + l];
4773 if (byte == 255)
4774 {
4775 byte = ' ';
4776 }
4777 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4778 }
4779 sim_printf ("'\r\n");
4780 }
4781
4782 static void strip_spaces(char* str) {
4783 int i, x;
4784 for (i=x=0; str[i]; ++i)
4785 {
4786 if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)])))
4787 {
4788 str[x++] = str[i];
4789 }
4790 }
4791 str[x] = '\0';
4792 i = -1;
4793 x = 0;
4794 while (str[x] != '\0')
4795 {
4796 if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4797 {
4798 i=x;
4799 }
4800 x++;
4801 }
4802 str[i+1] = '\0';
4803 }
4804
4805 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
4806 char sx[1024];
4807 sx[1023] = '\0';
4808 unsigned int lastbyte = 0;
4809 for (int l = 0; l < length; l ++)
4810 {
4811 unsigned int byte = PROM[offset + l];
4812 if (byte == 255)
4813 {
4814 byte = 20;
4815 }
4816 if ((lastbyte != 20) && (byte != 20))
4817 {
4818 (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4819 }
4820 lastbyte = byte;
4821 }
4822 strip_spaces(sx);
4823 (void)fprintf (st, "%s", sx);
4824 }
4825
4826 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4827 {
4828 unsigned char PROM[1024];
4829 setupPROM (0, PROM);
4830
4831 sim_printf (" PROM size: %llu bytes\r\n",
4832 (long long unsigned)sizeof(PROM));
4833 sim_printf (" PROM initialization data:\r\n\r\n");
4834
4835 sim_printf (" Field Description Length Offset Contents\r\n");
4836 sim_printf (" ========================= ======== ======== ==================================\r\n");
4837 sim_printf ("\r\n");
4838
4839
4840
4841 printp (PROM, "CPU Model ", 0, 11);
4842 printp (PROM, "CPU Serial ", 11, 11);
4843 printp (PROM, "Ship Date ", 22, 6);
4844 printp (PROM, "PROM Layout Version ", 60, 1);
4845 printp (PROM, "Release Git Commit Date ", 70, 10);
4846 printp (PROM, "Release Major ", 80, 3);
4847 printp (PROM, "Release Minor ", 83, 3);
4848 printp (PROM, "Release Patch ", 86, 3);
4849 printp (PROM, "Release Iteration ", 89, 3);
4850 printp (PROM, "Release Build Number ", 92, 8);
4851 printp (PROM, "Release Type ", 100, 1);
4852 printp (PROM, "Release Version Text ", 101, 29);
4853 printp (PROM, "Build Architecture ", 130, 20);
4854 printp (PROM, "Build Operating System ", 150, 20);
4855 printp (PROM, "Target Architecture ", 170, 20);
4856 printp (PROM, "Target Operating System ", 190, 20);
4857
4858 sim_printf("\r\n");
4859 return 0;
4860 }
4861
4862 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4863 {
4864 (void)fprintf (st, "\r Build Information:\r\n");
4865 #if defined(BUILDINFO_scp)
4866 (void)fprintf (st, "\r\n Compilation info: %s\r\n", BUILDINFO_scp );
4867 #else
4868 (void)fprintf (st, "\r\n Compilation info: Not available\r\n" );
4869 #endif
4870 #if !defined(__CYGWIN__)
4871 # if !defined(__APPLE__)
4872 # if !defined(_AIX)
4873 # if !defined(__MINGW32__)
4874 # if !defined(__MINGW64__)
4875 # if !defined(CROSS_MINGW32)
4876 # if !defined(CROSS_MINGW64)
4877 # if !defined(_WIN32)
4878 # if !defined(__HAIKU__)
4879 # if !defined(__QNX__)
4880 # if !defined(__FILC__)
4881 (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4882 if (dl_iterate_phdr_callback_called)
4883 (void)fprintf (st, "\r\n");
4884 dl_iterate_phdr_callback_called = 0;
4885 # endif
4886 # endif
4887 # endif
4888 # endif
4889 # endif
4890 # endif
4891 # endif
4892 # endif
4893 # endif
4894 # endif
4895 #endif
4896 #if defined(UV_VERSION_MAJOR) && \
4897 defined(UV_VERSION_MINOR) && \
4898 defined(UV_VERSION_PATCH)
4899 # if defined(UV_VERSION_MAJOR)
4900 # if !defined(UV_VERSION_MINOR) && \
4901 !defined(UV_VERSION_PATCH) && \
4902 !defined(UV_VERSION_SUFFIX)
4903 (void)fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4904 # endif
4905 # if defined(UV_VERSION_MINOR)
4906 # if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4907 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4908 UV_VERSION_MINOR);
4909 # endif
4910 # if defined(UV_VERSION_PATCH)
4911 # if !defined(UV_VERSION_SUFFIX)
4912 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4913 UV_VERSION_MINOR, UV_VERSION_PATCH);
4914 # endif
4915 # if defined(UV_VERSION_SUFFIX)
4916 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4917 UV_VERSION_MINOR, UV_VERSION_PATCH);
4918 # if defined(UV_VERSION_IS_RELEASE)
4919 # if UV_VERSION_IS_RELEASE == 1
4920 # define UV_RELEASE_TYPE " (release)"
4921 # endif
4922 # if UV_VERSION_IS_RELEASE == 0
4923 # define UV_RELEASE_TYPE "-dev"
4924 # endif
4925 # if !defined(UV_RELEASE_TYPE)
4926 # define UV_RELEASE_TYPE ""
4927 # endif
4928 # if defined(UV_RELEASE_TYPE)
4929 (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4930 # endif
4931 # endif
4932 # endif
4933 # endif
4934 # endif
4935 unsigned int CurrentUvVersion = uv_version();
4936 if (CurrentUvVersion > 0)
4937 if (uv_version_string() != NULL)
4938 (void)fprintf (st, "; %s in use", uv_version_string());
4939 # endif
4940 #else
4941 (void)fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4942 #endif
4943
4944
4945
4946 (void)fprintf (st, "\r\n Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4947 SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4948 SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4949 sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4950 #if defined(DECNUMBERLOC)
4951 # if defined(DECVERSION)
4952 # if defined(DECVERSEXT)
4953 (void)fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4954 # else
4955 # if defined(DECNLAUTHOR)
4956 (void)fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4957 # else
4958 (void)fprintf (st, "\r\n Math library: %s", DECVERSION);
4959 # endif
4960 # endif
4961 # else
4962 (void)fprintf (st, "\r\n Math library: decNumber, unknown version");
4963 # endif
4964 #endif
4965 #if defined(LOCKLESS)
4966 (void)fprintf (st, "\r\n Atomic operations: ");
4967 # if defined(AIX_ATOMICS)
4968 (void)fprintf (st, "C11 and IBM AIX-style");
4969 # elif defined(BSD_ATOMICS)
4970 (void)fprintf (st, "C11 and FreeBSD-style");
4971 # elif defined(GNU_ATOMICS)
4972 (void)fprintf (st, "C11 and GNU-style");
4973 # elif defined(SYNC_ATOMICS)
4974 (void)fprintf (st, "C11 and GNU sync-style");
4975 # elif defined(ISO_ATOMICS)
4976 (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4977 # elif defined(NT_ATOMICS)
4978 (void)fprintf (st, "C11 and Windows NT interlocked operations");
4979 # endif
4980 #endif
4981 (void)fprintf (st, "\r\n File locking: ");
4982 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4983 (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4984 #endif
4985 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4986 (void)fprintf (st, "POSIX-style fcntl() locking");
4987 #endif
4988 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4989 (void)fprintf (st, "BSD-style flock() locking");
4990 #endif
4991 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4992 (void)fprintf (st, "No file locking available");
4993 #endif
4994 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
4995 (void)fprintf (st, "\r\n Windows support: ");
4996 #endif
4997 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4998 # if defined(__MINGW64_VERSION_STR)
4999 (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
5000 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
5001 (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
5002 # else
5003 (void)fprintf (st, "Built with MinGW");
5004 # endif
5005
5006 # if defined(MINGW_CRT)
5007 (void)fprintf (st, "; %s", MINGW_CRT);
5008 # if !defined(_UCRT)
5009 # if defined(__MSVCRT_VERSION__)
5010 # if __MSVCRT_VERSION__ > 0x00
5011 (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
5012 # endif
5013 # endif
5014 # else
5015
5016 struct UCRTVersion ucrtversion;
5017 int result = GetUCRTVersion (&ucrtversion);
5018
5019 if (result == 0)
5020 (void)fprintf (st, " %u.%u.%u.%u",
5021 ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
5022 ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
5023 # endif
5024 (void)fprintf (st, " in use");
5025 # endif
5026 #elif defined(__CYGWIN__)
5027 struct utsname utsname;
5028 (void)fprintf (st, "Built with Cygwin %d.%d.%d",
5029 CYGWIN_VERSION_DLL_MAJOR / 1000,
5030 CYGWIN_VERSION_DLL_MAJOR % 1000,
5031 CYGWIN_VERSION_DLL_MINOR);
5032 if (uname(&utsname) == 0)
5033 fprintf (st, "; %s in use", utsname.release);
5034 #endif
5035
5036 (void)fprintf (st, "\r\n");
5037 return 0;
5038 }
5039
5040 static void
5041 removehex(char *s)
5042 {
5043 if (!s) return;
5044
5045 size_t len = strlen(s);
5046 for (size_t i = 0; i < len; i++) {
5047 if (s[i] != ' ')
5048 continue;
5049
5050 if ((len - i) < 41)
5051 continue;
5052
5053 size_t j;
5054 for (j = 1; j <= 40; j++) {
5055 unsigned char uc = (unsigned char)s[i + j];
5056 if (!isxdigit(uc))
5057 break;
5058 }
5059
5060 if (j == 41) {
5061 memmove(&s[i], &s[i + 41], strlen(&s[i + 41]) + 1);
5062 return;
5063 }
5064 }
5065 }
5066
5067 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5068 {
5069 const char *arch = "";
5070 char *whydirty = " ";
5071 int dirty = 0;
5072
5073 if (cptr && (*cptr != 0))
5074 return SCPE_2MARG;
5075 if (flag) {
5076 (void)fprintf (st, " %s Simulator:", sim_name);
5077 #if defined(USE_DUMA)
5078 # undef NO_SUPPORT_VERSION
5079 # define NO_SUPPORT_VERSION 1
5080 nodist++;
5081 #endif
5082 #if defined(NO_SUPPORT_VERSION) || \
5083 defined(WITH_SOCKET_DEV) || \
5084 defined(WITH_ABSI_DEV) || \
5085 defined(TESTING) || \
5086 defined(ISOLTS) || \
5087 defined(USE_DUMA)
5088 # if !defined(NO_SUPPORT_VERSION)
5089 # define NO_SUPPORT_VERSION 1
5090 # endif
5091 #endif
5092 #if defined(NO_SUPPORT_VERSION)
5093 dirty++;
5094 #endif
5095 #if defined(GENERATED_MAKE_VER_H)
5096 # if defined(VER_H_GIT_VERSION)
5097
5098
5099 if (strstr(VER_H_GIT_VERSION, "*"))
5100 {
5101 dirty++;
5102 }
5103
5104
5105 if ((strstr(VER_H_GIT_VERSION, "X")) || \
5106 (strstr(VER_H_GIT_VERSION, "D")) || \
5107 (strstr(VER_H_GIT_VERSION, "A")) || \
5108 (strstr(VER_H_GIT_VERSION, "B")))
5109 {
5110 dirty++;
5111 }
5112
5113
5114 if (dirty)
5115 {
5116 if ((strstr(VER_H_GIT_VERSION, "X")))
5117 {
5118 whydirty = " ";
5119 }
5120 else if ((strstr(VER_H_GIT_VERSION, "D")))
5121 {
5122 whydirty = " DEV ";
5123 }
5124 else if ((strstr(VER_H_GIT_VERSION, "A")))
5125 {
5126 whydirty = " ALPHA ";
5127 }
5128 else if ((strstr(VER_H_GIT_VERSION, "B")))
5129 {
5130 whydirty = " BETA ";
5131 }
5132 }
5133
5134 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5135 # if defined(VER_H_GIT_HASH)
5136 # if VER_H_GIT_PATCH_INT < 1
5137 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5138 VER_H_GIT_VERSION,
5139 (long)(CHAR_BIT*sizeof(void *)),
5140 VER_H_GIT_HASH);
5141 # else
5142 # define NO_SUPPORT_VERSION 1
5143 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)\r\n Commit: %s",
5144 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5145 (long)(CHAR_BIT*sizeof(void *)),
5146 VER_H_GIT_HASH);
5147 # endif
5148 # else
5149 # if VER_H_GIT_PATCH_INT < 1
5150 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5151 VER_H_GIT_VERSION,
5152 (long)(CHAR_BIT*sizeof(void *)));
5153 # else
5154 # define NO_SUPPORT_VERSION 1
5155 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)",
5156 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5157 (long)(CHAR_BIT*sizeof(void *)));
5158 # endif
5159 # endif
5160 # else
5161 # if defined(VER_H_GIT_HASH)
5162 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5163 VER_H_GIT_VERSION,
5164 (long)(CHAR_BIT*sizeof(void *)),
5165 VER_H_GIT_HASH);
5166 # else
5167 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5168 VER_H_GIT_VERSION,
5169 (long)(CHAR_BIT*sizeof(void *)));
5170 # endif
5171 # endif
5172 # endif
5173 #endif
5174
5175
5176 #if defined(TESTING)
5177 (void)fprintf (st, "\r\n Options: ");
5178 # if !defined(HAVE_DPSOPT)
5179 # define HAVE_DPSOPT 1
5180 # endif
5181 (void)fprintf (st, "TESTING");
5182 #endif
5183
5184
5185 #if defined(ISOLTS)
5186 # if defined(HAVE_DPSOPT)
5187 (void)fprintf (st, ", ");
5188 # else
5189 (void)fprintf (st, "\r\n Options: ");
5190 # endif
5191 # if !defined(HAVE_DPSOPT)
5192 # define HAVE_DPSOPT 1
5193 # endif
5194 (void)fprintf (st, "ISOLTS");
5195 #endif
5196
5197
5198 #if defined(NEED_128)
5199 # if defined(HAVE_DPSOPT)
5200 (void)fprintf (st, ", ");
5201 # else
5202 (void)fprintf (st, "\r\n Options: ");
5203 # endif
5204 # if !defined(HAVE_DPSOPT)
5205 # define HAVE_DPSOPT 1
5206 # endif
5207 (void)fprintf (st, "NEED_128");
5208 #endif
5209
5210
5211 #if !defined(LOCKLESS)
5212 # if defined(HAVE_DPSOPT)
5213 (void)fprintf (st, ", ");
5214 # else
5215 (void)fprintf (st, "\r\n Options: ");
5216 # endif
5217 # if !defined(HAVE_DPSOPT)
5218 # define HAVE_DPSOPT 1
5219 # endif
5220 (void)fprintf (st, "NO_LOCKLESS");
5221 #endif
5222
5223
5224 #if defined(PANEL68)
5225 # if defined(HAVE_DPSOPT)
5226 (void)fprintf (st, ", ");
5227 # else
5228 (void)fprintf (st, "\r\n Options: ");
5229 # endif
5230 # if !defined(HAVE_DPSOPT)
5231 # define HAVE_DPSOPT 1
5232 # endif
5233 (void)fprintf (st, "PANEL68");
5234 #endif
5235
5236
5237 #if defined(WITH_ABSI_DEV)
5238 # if defined(HAVE_DPSOPT)
5239 (void)fprintf (st, ", ");
5240 # else
5241 (void)fprintf (st, "\r\n Options: ");
5242 # endif
5243 # if !defined(HAVE_DPSOPT)
5244 # define HAVE_DPSOPT 1
5245 # endif
5246 (void)fprintf (st, "ABSI");
5247 #endif
5248
5249
5250 #if defined(WITH_SOCKET_DEV)
5251 # if defined(HAVE_DPSOPT)
5252 (void)fprintf (st, ", ");
5253 # else
5254 (void)fprintf (st, "\r\n Options: ");
5255 # endif
5256 # if !defined(HAVE_DPSOPT)
5257 # define HAVE_DPSOPT 1
5258 # endif
5259 (void)fprintf (st, "SOCKET");
5260 #endif
5261
5262
5263 #if !defined(WITH_MGP_DEV)
5264 # if defined(HAVE_DPSOPT)
5265 (void)fprintf (st, ", ");
5266 # else
5267 (void)fprintf (st, "\r\n Options: ");
5268 # endif
5269 # if !defined(HAVE_DPSOPT)
5270 # define HAVE_DPSOPT 1
5271 # endif
5272 (void)fprintf (st, "NO_CHAOSNET");
5273 #endif
5274
5275
5276 #if !defined(WITH_NET_DEV)
5277 # if defined(HAVE_DPSOPT)
5278 (void)fprintf (st, ", ");
5279 # else
5280 (void)fprintf (st, "\r\n Options: ");
5281 # endif
5282 # if !defined(HAVE_DPSOPT)
5283 # define HAVE_DPSOPT 1
5284 # endif
5285 (void)fprintf (st, "NO_INTERNET");
5286 #endif
5287
5288
5289 #if defined(USE_DUMA)
5290 # if defined(HAVE_DPSOPT)
5291 (void)fprintf (st, ", ");
5292 # else
5293 (void)fprintf (st, "\r\n Options: ");
5294 # endif
5295 # if !defined(HAVE_DPSOPT)
5296 # define HAVE_DPSOPT 1
5297 # endif
5298 (void)fprintf (st, "DUMA");
5299 #endif
5300
5301 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5302 # if defined(NO_SUPPORT_VERSION)
5303 (void)fprintf (st, "\r\n Modified: %s", VER_H_GIT_DATE);
5304 # else
5305 (void)fprintf (st, "\r\n Released: %s", VER_H_GIT_DATE);
5306 # endif
5307 #endif
5308 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5309 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5310 #endif
5311 #if defined(VER_CURRENT_TIME)
5312 (void)fprintf (st, "\r\n Compiled: %s", VER_CURRENT_TIME);
5313 #endif
5314 if (dirty)
5315 {
5316 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5317 }
5318 (void)fprintf (st, "\r\n\r\n Build Information:");
5319 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5320 char build_os_version_raw[255];
5321 char build_os_arch_raw[255];
5322 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5323 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5324 char *build_os_version = strdup(build_os_version_raw);
5325 if (!build_os_version)
5326 {
5327 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5328 __func__, __FILE__, __LINE__);
5329 # if defined(USE_BACKTRACE)
5330 # if defined(SIGUSR2)
5331 (void)raise(SIGUSR2);
5332
5333 # endif
5334 # endif
5335 abort();
5336 }
5337 char *build_os_arch = strdup(build_os_arch_raw);
5338 if (!build_os_arch)
5339 {
5340 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5341 __func__, __FILE__, __LINE__);
5342 # if defined(USE_BACKTRACE)
5343 # if defined(SIGUSR2)
5344 (void)raise(SIGUSR2);
5345
5346 # endif
5347 # endif
5348 abort();
5349 }
5350 unsigned char SPROM[1024];
5351 setupPROM (0, SPROM);
5352 (void)fprintf (st, "\r\n Target: ");
5353 printpq (SPROM, st, 190, 20);
5354 if (SPROM[170] != 20)
5355 {
5356 if (SPROM[170] != 255)
5357 {
5358 (void)fprintf (st, " on ");
5359 printpq (SPROM, st, 170, 20);
5360 }
5361 }
5362 strtrimspace(build_os_version, build_os_version_raw);
5363 strtrimspace(build_os_arch, build_os_arch_raw);
5364 (void)fprintf (st, "\r\n Build OS: %s %s", build_os_version, build_os_arch);
5365 FREE(build_os_version);
5366 FREE(build_os_arch);
5367 #endif
5368 #if defined(__VERSION__)
5369 char gnumver[2];
5370 char postver[1024];
5371 (void)sprintf(gnumver, "%.1s", __VERSION__);
5372 (void)sprintf(postver, "%.1023s", __VERSION__);
5373 strremove(postver, "(TM)");
5374 strremove(postver, "(R)");
5375 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5376 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5377 strremove(postver, " gcc 4.9 mode");
5378 strremove(postver, "4.2.1 Compatible ");
5379 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5380 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5381 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5382 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5383 strremove(postver, "(experimental) ");
5384 strremove(postver, ".module+el8.7.0+20823+214a699d");
5385 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5386 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5387 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5388 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5389 strremove(postver, "llvmorg-16.0.6-0-");
5390 strremove(postver, " Clang 15.0.0 (build 760095e)");
5391 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5392 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5393 strremove(postver, " Clang 15.0.0 (build 232543c)");
5394 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5395 strremove(postver, "CLANG: ");
5396 removehex(postver);
5397 strremove(postver, " (git@github.com:pizlonator/llvm-project-deluge.git)");
5398 #endif
5399 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5400 # if !defined(__clang_version__)
5401 if (isdigit((unsigned char)gnumver[0])) {
5402 (void)fprintf (st, "\r\n Compiler: GCC %s", postver);
5403 } else {
5404 (void)fprintf (st, "\r\n Compiler: %s", postver);
5405 }
5406 # endif
5407 # if defined(__clang_analyzer__ )
5408 (void)fprintf (st, "\r\n Compiler: Clang C/C++ Static Analyzer");
5409 # elif defined(__clang_version__) && defined(__VERSION__)
5410 char clangllvmver[1024];
5411 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5412 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5413 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5414 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5415 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5416 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5417 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5418 strremove(clangllvmver, " ( )");
5419 strremove(clangllvmver, " ()");
5420 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5421 (void)fprintf (st, "\r\n Compiler: Clang %s", clangllvmver);
5422 } else {
5423 (void)fprintf (st, "\r\n Compiler: %s", postver);
5424 }
5425 # elif defined(__clang_version__)
5426 (void)fprintf (st, "\r\n Compiler: %s", postver);
5427 # endif
5428 #elif defined(__PGI) && !defined(__NVCOMPILER)
5429 (void)fprintf (st, "\r\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5430 # if defined(__PGIC__)
5431 (void)fprintf (st, "%d", __PGIC__);
5432 # if defined(__PGIC_MINOR__)
5433 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5434 # if defined(__PGIC_PATCHLEVEL__)
5435 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5436 # endif
5437 # endif
5438 # endif
5439 #elif defined(__NVCOMPILER)
5440 (void)fprintf (st, "\r\n Compiler: NVIDIA HPC SDK C Compiler ");
5441 # if defined(__NVCOMPILER_MAJOR__)
5442 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5443 # if defined(__NVCOMPILER_MINOR__)
5444 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5445 # if defined(__NVCOMPILER_PATCHLEVEL__)
5446 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5447 # endif
5448 # endif
5449 # endif
5450 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5451 (void)fprintf (st, "\r\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5452 _MSC_FULL_VER/10000000,
5453 (_MSC_FULL_VER/100000)%100,
5454 _MSC_FULL_VER%100000,
5455 _MSC_BUILD);
5456 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5457 # if defined(_AIX) && defined(__PASE__)
5458 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5459 # endif
5460 # if defined(_AIX) && !defined(__PASE__)
5461 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5462 # endif
5463 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5464 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5465 # endif
5466 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5467 # if defined(__PPC__) && defined(__APPLE__)
5468 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5469 # else
5470 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s", __xlc__);
5471 # endif
5472 # endif
5473 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5474 # define VER_ENC(maj, min, rev) \
5475 (((maj) * 1000000) + ((min) * 1000) + (rev))
5476 # define VER_DEC_MAJ(ver) \
5477 ((ver) / 1000000)
5478 # define VER_DEC_MIN(ver) \
5479 (((ver) % 1000000) / 1000)
5480 # define VER_DEC_REV(ver) \
5481 ((ver) % 1000)
5482 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5483 # define COMP_VER VER_ENC( \
5484 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5485 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5486 (__SUNPRO_C & 0xf) * 10)
5487 # elif defined(__SUNPRO_C)
5488 # define COMP_VER VER_ENC( \
5489 (__SUNPRO_C >> 8) & 0xf, \
5490 (__SUNPRO_C >> 4) & 0xf, \
5491 (__SUNPRO_C) & 0xf)
5492 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5493 # define COMP_VER VER_ENC( \
5494 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5495 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5496 (__SUNPRO_CC & 0xf) * 10)
5497 # elif defined(__SUNPRO_CC)
5498 # define COMP_VER VER_ENC( \
5499 (__SUNPRO_CC >> 8) & 0xf, \
5500 (__SUNPRO_CC >> 4) & 0xf, \
5501 (__SUNPRO_CC) & 0xf)
5502 # endif
5503 # if !defined(COMP_VER)
5504 # define COMP_VER 0
5505 # endif
5506 (void)fprintf (st, "\r\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5507 VER_DEC_MAJ(COMP_VER),
5508 VER_DEC_MIN(COMP_VER),
5509 VER_DEC_REV(COMP_VER));
5510 #elif defined(__DMC__)
5511 (void)fprintf (st, "\r\n Compiler: Digital Mars C/C++");
5512 #elif defined(__PCC__)
5513 (void)fprintf (st, "\r\n Compiler: Portable C Compiler");
5514 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5515 (void)fprintf (st, "\r\n Compiler: Plan 9 Compiler Suite");
5516 #elif defined(__ACK__)
5517 (void)fprintf (st, "\r\n Compiler: Amsterdam Compiler Kit");
5518 #elif defined(__COMO__)
5519 (void)fprintf (st, "\r\n Compiler: Comeau C++");
5520 #elif defined(__COMPCERT__)
5521 (void)fprintf (st, "\r\n Compiler: CompCert C");
5522 #elif defined(__COVERITY__)
5523 (void)fprintf (st, "\r\n Compiler: Coverity C/C++ Static Analyzer");
5524 #elif defined(__LCC__)
5525 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5526 (void)fprintf (st, "\r\n Compiler: MCST Elbrus C Compiler");
5527 # if __LCC__ > 99
5528 (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5529 # if defined(__LCC_MINOR__)
5530 # if __LCC_MINOR__ > 0
5531 (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5532 # endif
5533 # endif
5534 # endif
5535 # if defined(__EDG__) && defined(__EDG_VERSION__)
5536 # if __EDG_VERSION__ > 99
5537 (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5538 (int)(((__EDG_VERSION__) % 100) % 10));
5539 # endif
5540 # endif
5541 # else
5542 (void)fprintf (st, "\r\n Compiler: Local/Little C Compiler (lcc)");
5543 # endif
5544 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5545 (void)fprintf (st, "\r\n Compiler: SGI MIPSpro");
5546 #elif defined(__OPEN64__)
5547 (void)fprintf (st, "\r\n Compiler: Open64 %s", __OPEN64__);
5548 #elif defined(__PGI) || defined(__PGIC__)
5549 (void)fprintf (st, "\r\n Compiler: Portland Group/PGI C/C++");
5550 #elif defined(__VBCC__)
5551 (void)fprintf (st, "\r\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5552 #elif defined(__WATCOMC__)
5553 (void)fprintf (st, "\r\n Compiler: Watcom C/C++ %d.%d",
5554 __WATCOMC__ / 100,
5555 __WATCOMC__ % 100);
5556 #elif defined(__xlC__)
5557 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++");
5558 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5559 # if defined(__INTEL_COMPILER_UPDATE)
5560 # if defined(__INTEL_COMPILER_BUILD_DATE)
5561 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d (%d)",
5562 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5563 __INTEL_COMPILER_BUILD_DATE);
5564 # else
5565 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d",
5566 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5567 # endif
5568 # else
5569 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d",
5570 __INTEL_COMPILER);
5571 # endif
5572 #elif defined(SIM_COMPILER)
5573 # define S_xstr(a) S_str(a)
5574 # define S_str(a) #a
5575 (void)fprintf (st, "\r\n Compiler: %s", S_xstr(SIM_COMPILER));
5576 # undef S_str
5577 # undef S_xstr
5578 #else
5579 (void)fprintf (st, "\r\n Compiler: Unknown");
5580 #endif
5581
5582 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5583 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5584 # define SC_IS_PPC64 1
5585 #else
5586 # define SC_IS_PPC64 0
5587 #endif
5588
5589 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5590 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5591 defined(__PPC32)
5592 # define SC_IS_PPC32 1
5593 #else
5594 # define SC_IS_PPC32 0
5595 #endif
5596
5597 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5598 arch = " x86_64";
5599 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5600 arch = " x86";
5601 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5602 arch = " arm64";
5603 #elif defined(_M_ARM) || defined(__arm__)
5604 arch = " arm";
5605 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5606 arch = " ia64";
5607 #elif SC_IS_PPC64
5608 arch = " powerpc64";
5609 #elif SC_IS_PPC32
5610 arch = " powerpc";
5611 #elif defined(__s390x__)
5612 arch = " s390x";
5613 #elif defined(__s390__)
5614 arch = " s390";
5615 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5616 arch = " j2";
5617 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5618 arch = " sh4";
5619 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5620 arch = " sh2";
5621 #elif defined(__alpha__)
5622 arch = " alpha";
5623 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5624 arch = " hppa";
5625 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5626 arch = " ice9";
5627 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5628 arch = " mips64";
5629 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5630 arch = " mips";
5631 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5632 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5633 arch = " openrisc";
5634 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5635 arch = " sparc64";
5636 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5637 arch = " sparc";
5638 #elif defined(__riscv) || defined(__riscv__)
5639 arch = " riscv";
5640 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5641 arch = " e2k";
5642 #elif defined(__myriad2__)
5643 arch = " myriad2";
5644 #elif defined(__loongarch64) || defined(__loongarch__)
5645 arch = " loongarch";
5646 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5647 arch = " m68k";
5648 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5649 arch = " m88k";
5650 #elif defined(__VAX__) || defined(__vax__)
5651 arch = " vax";
5652 #elif defined(__NIOS2__) || defined(__nios2__)
5653 arch = " nios2";
5654 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5655 arch = " microblaze";
5656 #else
5657 arch = " ";
5658 #endif
5659 (void)fprintf (st, "%s", arch);
5660 #if defined(BUILD_BY_USER)
5661 (void)fprintf (st, "\r\n Built by: %s", BUILD_BY_USER);
5662 #else
5663 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5664 (void)fprintf (st, "\r\n Built by: %s", VER_H_PREP_USER);
5665 # endif
5666 #endif
5667 (void)fprintf (st, "\r\n\r\n Host System Information:");
5668 #if defined(_WIN32)
5669 if (1) {
5670 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5671 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5672 char osversion[PATH_MAX+1] = "";
5673 FILE *f;
5674
5675 if ((f = _popen ("ver", "r"))) {
5676 (void)memset (osversion, 0, sizeof(osversion));
5677 do {
5678 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5679 break;
5680 sim_trim_endspc (osversion);
5681 } while (osversion[0] == '\0');
5682 _pclose (f);
5683 }
5684 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5685 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5686 }
5687 #else
5688 if (1) {
5689 char osversion[2*PATH_MAX+1] = "";
5690 FILE *f;
5691 # if !defined(_AIX)
5692 if ((f = popen \
5693 ("uname -mrs 2> /dev/null", "r"))) {
5694 # else
5695 if ((f = popen \
5696 ("sh -c 'echo \"$(command -p env uname -v \
5697 2> /dev/null).$(command -p env uname -r \
5698 2> /dev/null) $(command -p env uname -p \
5699 2> /dev/null)\"' 2> /dev/null", "r"))) {
5700 # endif
5701 (void)memset (osversion, 0, sizeof(osversion));
5702 do {
5703 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5704 break;
5705 }
5706 sim_trim_endspc (osversion);
5707 } while (osversion[0] == '\0');
5708 pclose (f);
5709 strremove(osversion, "0000000000000000 ");
5710 strremove(osversion, " 0000000000000000");
5711 strremove(osversion, "000000000000 ");
5712 strremove(osversion, " 000000000000");
5713 strremove(osversion, "IBM ");
5714 strremove(osversion, " (emulated by qemu)");
5715 strremove(osversion, " (emulated by QEMU)");
5716 }
5717 # if !defined(_AIX)
5718 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5719 # else
5720 strremove(osversion, "AIX ");
5721 # if !defined(__PASE__)
5722 (void)fprintf (st, "\r\n Host OS: IBM AIX %s", osversion);
5723 # else
5724 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE) %s", osversion);
5725 # endif
5726 # endif
5727 } else {
5728 # if !defined(_AIX)
5729 (void)fprintf (st, "\r\n Host OS: Unknown");
5730 # else
5731 # if !defined(__PASE__)
5732 (void)fprintf (st, "\r\n Host OS: IBM AIX");
5733 # else
5734 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE)");
5735 # endif
5736 # endif
5737 }
5738 #endif
5739 if (nodist)
5740 {
5741 sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5742 }
5743 else
5744 {
5745 (void)fprintf (st, "\r\n");
5746 (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5747 (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5748 (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5749 }
5750 (void)fprintf (st, "\r\n");
5751 }
5752 return SCPE_OK;
5753 }
5754
5755 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5756 {
5757 size_t i;
5758 DEVICE *dptr;
5759 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5760
5761 if (cptr && (*cptr != 0))
5762 return SCPE_2MARG;
5763 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5764 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5765 if (!only_enabled || !qdisable (dptr))
5766 show_device (st, dptr, flag);
5767 return SCPE_OK;
5768 }
5769
5770 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5771 {
5772 int32 i;
5773 DEVICE *dptr;
5774
5775 if (cptr && (*cptr != 0))
5776 return SCPE_2MARG;
5777 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5778 show_dev_logicals (st, dptr, NULL, 1, cptr);
5779 return SCPE_OK;
5780 }
5781
5782 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5783 {
5784 if (dptr->lname)
5785 (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5786 else if (!flag)
5787 fputs ("no logical name assigned\r\n", st);
5788 return SCPE_OK;
5789 }
5790
5791 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5792 {
5793 DEVICE *dptr;
5794 UNIT *uptr;
5795 int32 accum;
5796
5797 if (cptr && (*cptr != 0))
5798 return SCPE_2MARG;
5799 if (sim_clock_queue == QUEUE_LIST_END)
5800 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5801 sim_name, sim_time, sim_timer_inst_per_sec ());
5802 else {
5803 const char *tim;
5804
5805 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5806 sim_name, sim_time, sim_timer_inst_per_sec ());
5807 accum = 0;
5808 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5809 if (uptr == &sim_step_unit)
5810 (void)fprintf (st, " Step timer");
5811 else
5812 if (uptr == &sim_expect_unit)
5813 (void)fprintf (st, " Expect fired");
5814 else
5815 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5816 (void)fprintf (st, " %s", sim_dname (dptr));
5817 if (dptr->numunits > 1)
5818 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5819 }
5820 else
5821 (void)fprintf (st, " Unknown");
5822 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5823 (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5824 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5825 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5826 accum = accum + uptr->time;
5827 }
5828 }
5829 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5830 return SCPE_OK;
5831 }
5832
5833 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5834 {
5835 if (cptr && (*cptr != 0))
5836 return SCPE_2MARG;
5837 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5838 return SCPE_OK;
5839 }
5840
5841 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5842 {
5843 t_stat r;
5844
5845 if (cptr && (*cptr != 0))
5846 r = ssh_break (st, cptr, 1);
5847 else
5848 r = sim_brk_showall (st, (uint32)sim_switches);
5849 return r;
5850 }
5851
5852 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5853 {
5854 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5855 return SCPE_OK;
5856 }
5857
5858 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5859 {
5860 int32 any = 0;
5861 DEBTAB *dep;
5862
5863 if (dptr->flags & DEV_DEBUG) {
5864 if (dptr->dctrl == 0)
5865 fputs ("Debugging disabled", st);
5866 else if (dptr->debflags == NULL)
5867 fputs ("Debugging enabled", st);
5868 else {
5869 uint32 dctrl = dptr->dctrl;
5870
5871 fputs ("Debug=", st);
5872 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5873 if ((dctrl & dep->mask) == dep->mask) {
5874 dctrl &= ~dep->mask;
5875 if (any)
5876 fputc (';', st);
5877 fputs (dep->name, st);
5878 any = 1;
5879 }
5880 }
5881 }
5882 fputc ('\n', st);
5883 return SCPE_OK;
5884 }
5885 else return SCPE_NOFNC;
5886 }
5887
5888
5889
5890 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5891 {
5892 int32 lvl, i;
5893
5894 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5895 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5896 if (lvl > 0)
5897 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5898 else
5899 (void)fprintf(st, "On Processing for input commands");
5900 (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5901 for (i=1; i<SCPE_BASE; ++i) {
5902 if (sim_on_actions[lvl][i])
5903 (void)fprintf(st, " on %5d %s\r\n", i, sim_on_actions[lvl][i]); }
5904 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5905 if (sim_on_actions[lvl][i])
5906 (void)fprintf(st, " on %-5s %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5907 if (sim_on_actions[lvl][0])
5908 (void)fprintf(st, " on ERROR %s\r\n", sim_on_actions[lvl][0]);
5909 (void)fprintf(st, "\r\n");
5910 }
5911 if (sim_on_inherit)
5912 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5913 return SCPE_OK;
5914 }
5915
5916
5917
5918 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5919 {
5920 int32 i;
5921 DEVICE *dptr;
5922
5923 if (cptr && (*cptr != 0))
5924 return SCPE_2MARG;
5925 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5926 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5927 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5928 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5929 return SCPE_OK;
5930 }
5931
5932 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5933 {
5934 fprint_set_help (st, dptr);
5935 return SCPE_OK;
5936 }
5937
5938 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5939 {
5940 MTAB *mptr;
5941 t_stat r = SCPE_OK;
5942
5943 if (dptr->modifiers == NULL)
5944 return SCPE_OK;
5945 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5946 if (mptr->pstring &&
5947 ((mptr->mask & MTAB_XTD)?
5948 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5949 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5950 if (*toks > 0) {
5951 (void)fprintf (st, "\r\n");
5952 *toks = 0;
5953 }
5954 if (r == SCPE_OK)
5955 fprint_sep (st, toks);
5956 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5957 }
5958 }
5959 return SCPE_OK;
5960 }
5961
5962 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5963 CONST char *cptr, int32 flag)
5964 {
5965 t_stat r = SCPE_OK;
5966
5967 if (mptr->disp)
5968 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5969 else
5970 fputs (mptr->pstring, st);
5971 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5972 fputc ('\n', st);
5973 return r;
5974 }
5975
5976
5977
5978 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5979 {
5980 int32 i;
5981 DEVICE *dptr;
5982
5983 if (cptr && (*cptr != 0))
5984 return SCPE_2MARG;
5985 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5986 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5987 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5988 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5989 return SCPE_OK;
5990 }
5991
5992 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5993 {
5994 fprint_show_help (st, dptr);
5995 return SCPE_OK;
5996 }
5997
5998
5999
6000 t_stat brk_cmd (int32 flg, CONST char *cptr)
6001 {
6002 GET_SWITCHES (cptr);
6003 return ssh_break (NULL, cptr, flg);
6004 }
6005
6006 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
6007 {
6008 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
6009 CONST char *tptr, *t1ptr;
6010 DEVICE *dptr = sim_dflt_dev;
6011 UNIT *uptr;
6012 t_stat r;
6013 t_addr lo, hi, max;
6014 int32 cnt;
6015
6016 if (sim_brk_types == 0)
6017 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6018 if (dptr == NULL)
6019 return SCPE_IERR;
6020 uptr = dptr->units;
6021 if (uptr == NULL)
6022 return SCPE_IERR;
6023 max = uptr->capac - 1;
6024 abuf[sizeof(abuf)-1] = '\0';
6025 strncpy (abuf, cptr, sizeof(abuf)-1);
6026 cptr = abuf;
6027 if ((aptr = strchr (abuf, ';'))) {
6028 if (flg != SSH_ST)
6029 return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
6030 *aptr++ = 0;
6031 }
6032 if (*cptr == 0) {
6033 lo = (t_addr) get_rval (sim_PC, 0);
6034 return ssh_break_one (st, flg, lo, 0, aptr);
6035 }
6036 while (*cptr) {
6037 cptr = get_glyph (cptr, gbuf, ',');
6038 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
6039 if (tptr == NULL)
6040 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
6041 if (*tptr == '[') {
6042 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
6043 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
6044 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
6045 tptr = t1ptr + 1;
6046 }
6047 else cnt = 0;
6048 if (*tptr != 0)
6049 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
6050 if ((lo == 0) && (hi == max)) {
6051 if (flg == SSH_CL)
6052 sim_brk_clrall (sim_switches);
6053 else
6054 if (flg == SSH_SH)
6055 sim_brk_showall (st, (uint32)sim_switches);
6056 else
6057 return SCPE_ARG;
6058 }
6059 else {
6060 for ( ; lo <= hi; lo = lo + 1) {
6061 r = ssh_break_one (st, flg, lo, cnt, aptr);
6062 if (r != SCPE_OK)
6063 return r;
6064 }
6065 }
6066 }
6067 return SCPE_OK;
6068 }
6069
6070 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
6071 {
6072 if (!sim_brk_types)
6073 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6074 switch (flg) {
6075 case SSH_ST:
6076 return sim_brk_set (lo, sim_switches, cnt, aptr);
6077
6078 break;
6079
6080 case SSH_CL:
6081 return sim_brk_clr (lo, sim_switches);
6082
6083 break;
6084
6085 case SSH_SH:
6086 return sim_brk_show (st, lo, sim_switches);
6087
6088 break;
6089
6090 default:
6091 return SCPE_ARG;
6092 }
6093 }
6094
6095
6096
6097 static t_bool run_cmd_did_reset = FALSE;
6098
6099 t_stat reset_cmd (int32 flag, CONST char *cptr)
6100 {
6101 char gbuf[CBUFSIZE];
6102 DEVICE *dptr;
6103
6104 GET_SWITCHES (cptr);
6105 run_cmd_did_reset = FALSE;
6106 if (*cptr == 0)
6107 return (reset_all (0));
6108 cptr = get_glyph (cptr, gbuf, 0);
6109 if (*cptr != 0)
6110 return SCPE_2MARG;
6111 if (strcmp (gbuf, "ALL") == 0)
6112 return (reset_all (0));
6113 dptr = find_dev (gbuf);
6114 if (dptr == NULL)
6115 return SCPE_NXDEV;
6116 if (dptr->reset != NULL)
6117 return dptr->reset (dptr);
6118 else return SCPE_OK;
6119 }
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129 t_stat reset_all (uint32 start)
6130 {
6131 DEVICE *dptr;
6132 uint32 i;
6133 t_stat reason;
6134
6135 for (i = 0; i < start; i++) {
6136 if (sim_devices[i] == NULL)
6137 return SCPE_IERR;
6138 }
6139 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6140 if (dptr->reset != NULL) {
6141 reason = dptr->reset (dptr);
6142 if (reason != SCPE_OK)
6143 return reason;
6144 }
6145 }
6146 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6147 if (dptr->reset != NULL) {
6148 reason = dptr->reset (dptr);
6149 if (reason != SCPE_OK)
6150 return reason;
6151 }
6152 }
6153 return SCPE_OK;
6154 }
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164 t_stat reset_all_p (uint32 start)
6165 {
6166 t_stat r;
6167 int32 old_sw = sim_switches;
6168
6169 sim_switches = SWMASK ('P');
6170 r = reset_all (start);
6171 sim_switches = old_sw;
6172 return r;
6173 }
6174
6175
6176
6177 t_stat attach_cmd (int32 flag, CONST char *cptr)
6178 {
6179 char gbuf[4*CBUFSIZE];
6180 DEVICE *dptr;
6181 UNIT *uptr;
6182 t_stat r;
6183
6184 GET_SWITCHES (cptr);
6185 if ((NULL == cptr) || (*cptr == 0))
6186 return SCPE_2FARG;
6187 cptr = get_glyph (cptr, gbuf, 0);
6188 GET_SWITCHES (cptr);
6189 if ((NULL == cptr) || (*cptr == 0))
6190 return SCPE_2FARG;
6191 dptr = find_unit (gbuf, &uptr);
6192 if (dptr == NULL)
6193 return SCPE_NXDEV;
6194 if (uptr == NULL)
6195 return SCPE_NXUN;
6196 if (uptr->flags & UNIT_ATT) {
6197 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6198 !(dptr->flags & DEV_DONTAUTO)) {
6199 r = scp_detach_unit (dptr, uptr);
6200 if (r != SCPE_OK)
6201 return r; }
6202 else {
6203 if (!(uptr->dynflags & UNIT_ATTMULT))
6204 return SCPE_ALATT;
6205 }
6206 }
6207 gbuf[sizeof(gbuf)-1] = '\0';
6208 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6209 sim_trim_endspc (gbuf);
6210 return scp_attach_unit (dptr, uptr, gbuf);
6211 }
6212
6213
6214
6215 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6216 {
6217 if (dptr->attach != NULL)
6218 return dptr->attach (uptr, (CONST char *)cptr);
6219 return attach_unit (uptr, (CONST char *)cptr);
6220 }
6221
6222
6223
6224 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6225 {
6226 DEVICE *dptr;
6227
6228 if (uptr->flags & UNIT_DIS)
6229 return SCPE_UDIS;
6230 if (!(uptr->flags & UNIT_ATTABLE))
6231 return SCPE_NOATT;
6232 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6233 return SCPE_NOATT;
6234 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6235 if (uptr->filename == NULL)
6236 return SCPE_MEM;
6237 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6238 if ((sim_switches & SWMASK ('R')) ||
6239 ((uptr->flags & UNIT_RO) != 0)) {
6240 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6241 ((uptr->flags & UNIT_RO) == 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 && !(sim_switches & SWMASK ('Q'))) {
6248 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6249 }
6250 }
6251 else {
6252 if (sim_switches & SWMASK ('N')) {
6253 uptr->fileref = sim_fopen (cptr, "wb+");
6254 if (uptr->fileref == NULL)
6255 return attach_err (uptr, SCPE_OPENERR);
6256 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6257 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6258 }
6259 }
6260 else {
6261 uptr->fileref = sim_fopen (cptr, "rb+");
6262 if (uptr->fileref == NULL) {
6263 #if defined(EWOULDBLOCK)
6264 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6265 #else
6266 if ((errno == EAGAIN))
6267 #endif
6268 return attach_err (uptr, SCPE_OPENERR);
6269
6270 #if defined(EPERM)
6271 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6272 #else
6273 if ((errno == EROFS) || (errno == EACCES)) {
6274 #endif
6275 if ((uptr->flags & UNIT_ROABLE) == 0)
6276 return attach_err (uptr, SCPE_NORO);
6277 uptr->fileref = sim_fopen (cptr, "rb");
6278 if (uptr->fileref == NULL)
6279 return attach_err (uptr, SCPE_OPENERR);
6280 uptr->flags = uptr->flags | UNIT_RO;
6281 if (!sim_quiet) {
6282 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6283 }
6284 }
6285 else {
6286 if (sim_switches & SWMASK ('E'))
6287 return attach_err (uptr, SCPE_OPENERR);
6288 uptr->fileref = sim_fopen (cptr, "wb+");
6289 if (uptr->fileref == NULL)
6290 return attach_err (uptr, SCPE_OPENERR);
6291 if (!sim_quiet) {
6292 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6293 }
6294 }
6295 }
6296 }
6297 }
6298 if (uptr->flags & UNIT_BUFABLE) {
6299 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6300 if (uptr->flags & UNIT_MUSTBUF)
6301 uptr->filebuf = calloc (cap, SZ_D (dptr));
6302 if (uptr->filebuf == NULL)
6303 return attach_err (uptr, SCPE_MEM);
6304 if (!sim_quiet) {
6305 sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6306 }
6307 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6308 SZ_D (dptr), cap, uptr->fileref);
6309 uptr->flags = uptr->flags | UNIT_BUF;
6310 }
6311 uptr->flags = uptr->flags | UNIT_ATT;
6312 uptr->pos = 0;
6313 return SCPE_OK;
6314 }
6315
6316 t_stat attach_err (UNIT *uptr, t_stat stat)
6317 {
6318 FREE (uptr->filename);
6319 uptr->filename = NULL;
6320 return stat;
6321 }
6322
6323
6324
6325 t_stat detach_cmd (int32 flag, CONST char *cptr)
6326 {
6327 char gbuf[CBUFSIZE];
6328 DEVICE *dptr;
6329 UNIT *uptr;
6330
6331 GET_SWITCHES (cptr);
6332 if ((NULL == cptr) || (*cptr == 0))
6333 return SCPE_2FARG;
6334 cptr = get_glyph (cptr, gbuf, 0);
6335 if (*cptr != 0)
6336 return SCPE_2MARG;
6337 if (strcmp (gbuf, "ALL") == 0)
6338 return (detach_all (0, FALSE));
6339 dptr = find_unit (gbuf, &uptr);
6340 if (dptr == NULL)
6341 return SCPE_NXDEV;
6342 if (uptr == NULL)
6343 return SCPE_NXUN;
6344 return scp_detach_unit (dptr, uptr);
6345 }
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360 t_stat detach_all (int32 start, t_bool shutdown)
6361 {
6362 uint32 i, j;
6363 DEVICE *dptr;
6364 UNIT *uptr;
6365 t_stat r;
6366
6367 if ((start < 0) || (start > 1))
6368 return SCPE_IERR;
6369 if (shutdown)
6370 sim_switches = sim_switches | SIM_SW_SHUT;
6371 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6372 for (j = 0; j < dptr->numunits; j++) {
6373 uptr = (dptr->units) + j;
6374 if ((uptr->flags & UNIT_ATT) ||
6375 (shutdown && dptr->detach &&
6376 !(uptr->flags & UNIT_ATTABLE))) {
6377 r = scp_detach_unit (dptr, uptr);
6378
6379 if ((r != SCPE_OK) && !shutdown)
6380 return r;
6381 }
6382 }
6383 }
6384 return SCPE_OK;
6385 }
6386
6387
6388
6389 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6390 {
6391 if (dptr->detach != NULL)
6392 return dptr->detach (uptr);
6393 return detach_unit (uptr);
6394 }
6395
6396
6397
6398 t_stat detach_unit (UNIT *uptr)
6399 {
6400 DEVICE *dptr;
6401
6402 if (uptr == NULL)
6403 return SCPE_IERR;
6404 if (!(uptr->flags & UNIT_ATTABLE))
6405 return SCPE_NOATT;
6406 if (!(uptr->flags & UNIT_ATT)) {
6407 if (sim_switches & SIM_SW_REST)
6408 return SCPE_OK;
6409 else
6410 return SCPE_NOTATT;
6411 }
6412 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6413 return SCPE_OK;
6414 if (uptr->flags & UNIT_BUF) {
6415 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6416 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6417 if (!sim_quiet) {
6418 sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6419 }
6420 rewind (uptr->fileref);
6421 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6422 if (ferror (uptr->fileref))
6423 sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6424 sim_dname (dptr), xstrerror_l(errno), errno);
6425 }
6426 if (uptr->flags & UNIT_MUSTBUF) {
6427 FREE (uptr->filebuf);
6428 uptr->filebuf = NULL;
6429 }
6430 uptr->flags = uptr->flags & ~UNIT_BUF;
6431 }
6432 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6433 FREE (uptr->filename);
6434 uptr->filename = NULL;
6435 if (fclose (uptr->fileref) == EOF)
6436 return SCPE_IOERR;
6437 return SCPE_OK;
6438 }
6439
6440
6441
6442 const char *sim_dname (DEVICE *dptr)
6443 {
6444 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6445 }
6446
6447
6448
6449 const char *sim_uname (UNIT *uptr)
6450 {
6451 DEVICE *d = find_dev_from_unit(uptr);
6452 static char uname[CBUFSIZE];
6453
6454 if (!d)
6455 return "";
6456 if (d->numunits == 1)
6457 return sim_dname (d);
6458 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6459 return uname;
6460 }
6461
6462
6463
6464 t_stat run_cmd (int32 flag, CONST char *cptr)
6465 {
6466 char gbuf[CBUFSIZE] = "";
6467 CONST char *tptr;
6468 uint32 i, j;
6469 int32 sim_next = 0;
6470 int32 unitno;
6471 t_value pcv, orig_pcv;
6472 t_stat r;
6473 DEVICE *dptr;
6474 UNIT *uptr;
6475
6476 GET_SWITCHES (cptr);
6477 sim_step = 0;
6478 if ((flag == RU_RUN) || (flag == RU_GO)) {
6479 orig_pcv = get_rval (sim_PC, 0);
6480 if (*cptr != 0) {
6481 cptr = get_glyph (cptr, gbuf, 0);
6482 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6483 if (sim_dflt_dev && sim_vm_parse_addr)
6484 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6485 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6486 if ((tptr == gbuf) || (*tptr != 0) ||
6487 (pcv > width_mask[sim_PC->width]))
6488 return SCPE_ARG;
6489 put_rval (sim_PC, 0, pcv);
6490 }
6491 }
6492 if ((flag == RU_RUN) &&
6493 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6494 put_rval (sim_PC, 0, orig_pcv);
6495 return r;
6496 }
6497 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6498 int32 saved_switches = sim_switches;
6499
6500 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6501 cptr = get_glyph (cptr, gbuf, 0);
6502 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6503 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6504 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6505 sim_switches = 0;
6506 GET_SWITCHES (cptr);
6507 if ((*cptr == '\'') || (*cptr == '"')) {
6508 r = expect_cmd (1, cptr);
6509 if (r != SCPE_OK)
6510 return r;
6511 }
6512 else {
6513 if (sim_switches == 0)
6514 sim_switches = sim_brk_dflt;
6515 sim_switches |= BRK_TYP_TEMP;
6516 sim_brk_types |= BRK_TYP_TEMP;
6517 r = ssh_break (NULL, cptr, SSH_ST);
6518 if (r != SCPE_OK)
6519 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6520 }
6521 sim_switches = saved_switches;
6522 }
6523 }
6524
6525 else if ((flag == RU_STEP) ||
6526 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6527 static t_bool not_implemented_message = FALSE;
6528
6529 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6530 not_implemented_message = TRUE;
6531 flag = RU_STEP;
6532 }
6533 if (*cptr != 0) {
6534 cptr = get_glyph (cptr, gbuf, 0);
6535 if (*cptr != 0)
6536 return SCPE_2MARG;
6537 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6538 if ((r != SCPE_OK) || (sim_step <= 0))
6539 return SCPE_ARG;
6540 }
6541 else sim_step = 1;
6542 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6543 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6544 }
6545 else if (flag == RU_NEXT) {
6546 t_addr *addrs;
6547
6548 if (*cptr != 0) {
6549 cptr = get_glyph (cptr, gbuf, 0);
6550 if (*cptr != 0)
6551 return SCPE_2MARG;
6552 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6553 if ((r != SCPE_OK) || (sim_next <= 0))
6554 return SCPE_ARG;
6555 }
6556 else sim_next = 1;
6557 if (sim_vm_is_subroutine_call(&addrs)) {
6558 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6559 for (i=0; addrs[i]; i++)
6560 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6561 }
6562 else
6563 sim_step = 1;
6564 }
6565 else if (flag == RU_BOOT) {
6566 if (*cptr == 0)
6567 return SCPE_2FARG;
6568 cptr = get_glyph (cptr, gbuf, 0);
6569 if (*cptr != 0)
6570 return SCPE_2MARG;
6571 dptr = find_unit (gbuf, &uptr);
6572 if (dptr == NULL)
6573 return SCPE_NXDEV;
6574 if (uptr == NULL)
6575 return SCPE_NXUN;
6576 if (dptr->boot == NULL)
6577 return SCPE_NOFNC;
6578 if (uptr->flags & UNIT_DIS)
6579 return SCPE_UDIS;
6580 if ((uptr->flags & UNIT_ATTABLE) &&
6581 !(uptr->flags & UNIT_ATT))
6582 return SCPE_UNATT;
6583 unitno = (int32) (uptr - dptr->units);
6584 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6585 return r;
6586 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6587 return r;
6588 }
6589
6590 else
6591 if (flag != RU_CONT)
6592 return SCPE_IERR;
6593 else
6594 if (*cptr != 0)
6595 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6596
6597 if (sim_switches & SIM_SW_HIDE)
6598 return SCPE_OK;
6599
6600 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6601 for (j = 0; j < dptr->numunits; j++) {
6602 uptr = dptr->units + j;
6603 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6604 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6605 }
6606 }
6607 stop_cpu = 0;
6608 sim_is_running = 1;
6609 if (sim_ttrun () != SCPE_OK) {
6610 sim_is_running = 0;
6611 sim_ttcmd ();
6612 return SCPE_TTYERR;
6613 }
6614 if ((r = sim_check_console (30)) != SCPE_OK) {
6615 sim_is_running = 0;
6616 sim_ttcmd ();
6617 return r;
6618 }
6619 #if !defined(IS_WINDOWS)
6620 # if defined(SIGINT)
6621 if (signal (SIGINT, int_handler) == SIG_ERR) {
6622 sim_is_running = 0;
6623 sim_ttcmd ();
6624 return SCPE_SIGERR;
6625 }
6626 # endif
6627 #endif
6628 #if !defined(IS_WINDOWS)
6629 # if defined(SIGHUP)
6630 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6631 sim_is_running = 0;
6632 sim_ttcmd ();
6633 return SCPE_SIGERR;
6634 }
6635 # endif
6636 #endif
6637 #if !defined(IS_WINDOWS)
6638 # if defined(SIGTERM)
6639 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6640 sim_is_running = 0;
6641 sim_ttcmd ();
6642 return SCPE_SIGERR;
6643 }
6644 # endif
6645 #endif
6646 if (sim_step)
6647 sim_activate (&sim_step_unit, sim_step);
6648 (void)fflush(stdout);
6649 if (sim_log)
6650 (void)fflush (sim_log);
6651 sim_rtcn_init_all ();
6652 sim_start_timer_services ();
6653
6654 do {
6655 t_addr *addrs;
6656
6657 while (1) {
6658 r = sim_instr();
6659 if (r != SCPE_REMOTE)
6660 break;
6661 sim_remote_process_command ();
6662 }
6663 if ((flag != RU_NEXT) ||
6664 (--sim_next <=0))
6665 break;
6666 if (sim_step == 0) {
6667 t_addr val;
6668 BRKTAB *bp;
6669
6670 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6671 break;
6672 if (sim_vm_pc_value)
6673 val = (t_addr)(*sim_vm_pc_value)();
6674 else
6675 val = (t_addr)get_rval (sim_PC, 0);
6676 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6677 break;
6678 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6679 }
6680 else {
6681 if (r != SCPE_STEP)
6682 break;
6683 }
6684
6685 sim_step = 0;
6686 if (sim_vm_is_subroutine_call(&addrs)) {
6687 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6688 for (i=0; addrs[i]; i++)
6689 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6690 }
6691 else
6692 sim_step = 1;
6693 if (sim_step)
6694 sim_activate (&sim_step_unit, sim_step);
6695 } while (1);
6696
6697 sim_is_running = 0;
6698 sim_stop_timer_services ();
6699 sim_ttcmd ();
6700 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6701 signal (SIGINT, SIG_DFL);
6702 #if defined(SIGHUP)
6703 signal (SIGHUP, SIG_DFL);
6704 #endif
6705 signal (SIGTERM, SIG_DFL);
6706 if (sim_log)
6707 (void)fflush (sim_log);
6708 if (sim_deb)
6709 sim_debug_flush ();
6710 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6711 for (j = 0; j < dptr->numunits; j++) {
6712 uptr = dptr->units + j;
6713 if (uptr->flags & UNIT_ATT) {
6714 if (uptr->io_flush)
6715 uptr->io_flush (uptr);
6716 else {
6717 if (!(uptr->flags & UNIT_BUF) &&
6718 (uptr->fileref) &&
6719 !(uptr->dynflags & UNIT_NO_FIO) &&
6720 !(uptr->flags & UNIT_RO))
6721 (void)fflush (uptr->fileref);
6722 }
6723 }
6724 }
6725 }
6726 sim_cancel (&sim_step_unit);
6727 UPDATE_SIM_TIME;
6728 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6729 }
6730
6731
6732
6733 void
6734 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6735 {
6736 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6737 sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6738 #if defined(WIN_STDIO)
6739 (void)fflush(stderr);
6740 (void)fflush(stdout);
6741 #endif
6742 fprint_stopped (stdout, r);
6743 if (sim_log && (sim_log != stdout))
6744 fprint_stopped (sim_log, r);
6745 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6746 fprint_stopped (sim_deb, r);
6747 #if defined(WIN_STDIO)
6748 (void)fflush(stderr);
6749 (void)fflush(stdout);
6750 #endif
6751 }
6752
6753
6754
6755 t_stat sim_run_boot_prep (int32 flag)
6756 {
6757 UNIT *uptr;
6758 t_stat r;
6759
6760 sim_interval = 0;
6761 sim_time = sim_rtime = 0;
6762 noqueue_time = 0;
6763 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6764 sim_clock_queue = uptr->next;
6765 uptr->next = NULL;
6766 }
6767 r = reset_all (0);
6768 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6769 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6770 sim_printf ("Resetting all devices... This may not have been your intention.\r\n");
6771 sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6772 }
6773 run_cmd_did_reset = TRUE;
6774 }
6775 return r;
6776 }
6777
6778
6779
6780
6781
6782
6783
6784
6785 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6786 {
6787 int32 i;
6788 t_stat r = 0;
6789 t_addr k;
6790 t_value pcval;
6791
6792 fputc ('\n', st);
6793
6794 if (v >= SCPE_BASE)
6795 fputs (sim_error_text (v), st);
6796 else {
6797 fputs (sim_stop_messages [v], st);
6798
6799 if ((sim_vm_fprint_stopped != NULL) &&
6800 (!sim_vm_fprint_stopped (st, v)))
6801 return;
6802 }
6803
6804 (void)fprintf (st, ", %s: ", pc->name);
6805
6806 pcval = get_rval (pc, 0);
6807 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6808 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6809 else fprint_val (st, pcval, pc->radix, pc->width,
6810 pc->flags & REG_FMT);
6811 if ((dptr != NULL) && (dptr->examine != NULL)) {
6812 for (i = 0; i < sim_emax; i++)
6813 sim_eval[i] = 0;
6814 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6815 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6816 break;
6817 }
6818 if ((r == SCPE_OK) || (i > 0)) {
6819 (void)fprintf (st, " (");
6820 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6821 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6822 (void)fprintf (st, ")");
6823 }
6824 }
6825 (void)fprintf (st, "\r\n");
6826 return;
6827 }
6828
6829 void fprint_stopped (FILE *st, t_stat v)
6830 {
6831 #if defined(WIN_STDIO)
6832 (void)fflush(stderr);
6833 (void)fflush(stdout);
6834 #endif
6835 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6836 return;
6837 }
6838
6839
6840
6841
6842 t_stat step_svc (UNIT *uptr)
6843 {
6844 return SCPE_STEP;
6845 }
6846
6847
6848
6849
6850 t_stat expect_svc (UNIT *uptr)
6851 {
6852 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6853 }
6854
6855
6856
6857 void int_handler (int sig)
6858 {
6859 stop_cpu = 1;
6860 return;
6861 }
6862
6863
6864
6865 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6866 {
6867 char gbuf[CBUFSIZE];
6868 CONST char *gptr;
6869 CONST char *tptr = NULL;
6870 int32 opt;
6871 t_addr low, high;
6872 t_stat reason = SCPE_IERR;
6873 DEVICE *tdptr;
6874 REG *lowr, *highr;
6875 FILE *ofile;
6876
6877 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6878 if (flag == EX_E)
6879 opt = opt | CMD_OPT_OF;
6880 cptr = get_sim_opt (opt, cptr, &reason);
6881 if (NULL == cptr)
6882 return reason;
6883 if (*cptr == 0)
6884 return SCPE_2FARG;
6885 if (sim_dfunit == NULL)
6886 return SCPE_NXUN;
6887 cptr = get_glyph (cptr, gbuf, 0);
6888 if ((flag == EX_D) && (*cptr == 0))
6889
6890 return SCPE_2FARG;
6891 ofile = sim_ofile? sim_ofile: stdout;
6892
6893 for (gptr = gbuf, reason = SCPE_OK;
6894 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6895 tdptr = sim_dfdev;
6896 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6897 tptr = gptr + strlen ("STATE");
6898 if (*tptr && (*tptr++ != ','))
6899 return SCPE_ARG;
6900 if ((lowr = sim_dfdev->registers) == NULL)
6901 return SCPE_NXREG;
6902 for (highr = lowr; highr->name != NULL; highr++) ;
6903 sim_switches = sim_switches | SIM_SW_HIDE;
6904 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6905 lowr, --highr, 0, 0);
6906 continue;
6907 }
6908
6909
6910 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6911 (!(sim_opt_out & CMD_OPT_DFT) &&
6912 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6913 low = high = 0;
6914 if ((*tptr == '-') || (*tptr == ':')) {
6915 highr = find_reg (tptr + 1, &tptr, tdptr);
6916 if (highr == NULL)
6917 return SCPE_NXREG;
6918 }
6919 else {
6920 highr = lowr;
6921 if (*tptr == '[') {
6922 if (lowr->depth <= 1)
6923 return SCPE_ARG;
6924 tptr = get_range (NULL, tptr + 1, &low, &high,
6925 10, lowr->depth - 1, ']');
6926 if (tptr == NULL)
6927 return SCPE_ARG;
6928 }
6929 }
6930 if (*tptr && (*tptr++ != ','))
6931 return SCPE_ARG;
6932 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6933 lowr, highr, (uint32) low, (uint32) high);
6934 continue;
6935 }
6936
6937 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6938 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6939 sim_dfunit->capac - sim_dfdev->aincr), 0);
6940 if (tptr == NULL)
6941 return SCPE_ARG;
6942 if (*tptr && (*tptr++ != ','))
6943 return SCPE_ARG;
6944 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6945 sim_dfdev, sim_dfunit);
6946 }
6947 if (sim_ofile)
6948 fclose (sim_ofile);
6949 return reason;
6950 }
6951
6952
6953
6954
6955
6956
6957
6958 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6959 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6960 {
6961 t_stat reason;
6962 uint32 idx, val_start=lows;
6963 t_value val, last_val;
6964 REG *rptr;
6965
6966 if ((lowr == NULL) || (highr == NULL))
6967 return SCPE_IERR;
6968 if (lowr > highr)
6969 return SCPE_ARG;
6970 for (rptr = lowr; rptr <= highr; rptr++) {
6971 if ((sim_switches & SIM_SW_HIDE) &&
6972 (rptr->flags & REG_HIDDEN))
6973 continue;
6974 val = last_val = 0;
6975 for (idx = lows; idx <= highs; idx++) {
6976 if (idx >= rptr->depth)
6977 return SCPE_SUB;
6978 val = get_rval (rptr, idx);
6979 if (schptr && !test_search (&val, schptr))
6980 continue;
6981 if (flag == EX_E) {
6982 if ((idx > lows) && (val == last_val))
6983 continue;
6984 if (idx > val_start+1) {
6985 if (idx-1 == val_start+1) {
6986 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6987 if (reason != SCPE_OK)
6988 return reason;
6989 if (sim_log && (ofile == stdout))
6990 ex_reg (sim_log, val, flag, rptr, idx-1);
6991 }
6992 else {
6993 if (val_start+1 != idx-1) {
6994 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6995 if (sim_log && (ofile == stdout))
6996 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6997 }
6998 else {
6999 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7000 if (sim_log && (ofile == stdout))
7001 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7002 }
7003 }
7004 }
7005 sim_last_val = last_val = val;
7006 val_start = idx;
7007 reason = ex_reg (ofile, val, flag, rptr, idx);
7008 if (reason != SCPE_OK)
7009 return reason;
7010 if (sim_log && (ofile == stdout))
7011 ex_reg (sim_log, val, flag, rptr, idx);
7012 }
7013 if (flag != EX_E) {
7014 reason = dep_reg (flag, cptr, rptr, idx);
7015 if (reason != SCPE_OK)
7016 return reason;
7017 }
7018 }
7019 if ((flag == EX_E) && (val_start != highs)) {
7020 if (highs == val_start+1) {
7021 reason = ex_reg (ofile, val, flag, rptr, highs);
7022 if (reason != SCPE_OK)
7023 return reason;
7024 if (sim_log && (ofile == stdout))
7025 ex_reg (sim_log, val, flag, rptr, highs);
7026 }
7027 else {
7028 if (val_start+1 != highs) {
7029 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
7030 if (sim_log && (ofile == stdout))
7031 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
7032 }
7033 else {
7034 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7035 if (sim_log && (ofile == stdout))
7036 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7037 }
7038 }
7039 }
7040 }
7041 return SCPE_OK;
7042 }
7043
7044 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
7045 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
7046 {
7047 t_addr i, mask;
7048 t_stat reason;
7049
7050 if (uptr->flags & UNIT_DIS)
7051 return SCPE_UDIS;
7052 mask = (t_addr) width_mask[dptr->awidth];
7053 if ((low > mask) || (high > mask) || (low > high))
7054 return SCPE_ARG;
7055 for (i = low; i <= high; ) {
7056 reason = get_aval (i, dptr, uptr);
7057 if (reason != SCPE_OK)
7058 return reason;
7059 if (schptr && !test_search (sim_eval, schptr))
7060 i = i + dptr->aincr;
7061 else {
7062 if (flag != EX_D) {
7063 reason = ex_addr (ofile, flag, i, dptr, uptr);
7064 if (reason > SCPE_OK)
7065 return reason;
7066 if (sim_log && (ofile == stdout))
7067 ex_addr (sim_log, flag, i, dptr, uptr);
7068 }
7069 else reason = 1 - dptr->aincr;
7070 if (flag != EX_E) {
7071 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7072 if (reason > SCPE_OK)
7073 return reason;
7074 }
7075 i = i + (1 - reason);
7076 }
7077 }
7078 return SCPE_OK;
7079 }
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
7094 {
7095 int32 rdx;
7096
7097 if (rptr == NULL)
7098 return SCPE_IERR;
7099 if (rptr->depth > 1)
7100 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7101 else
7102 (void)Fprintf (ofile, "%s:\t", rptr->name);
7103 if (!(flag & EX_E))
7104 return SCPE_OK;
7105 GET_RADIX (rdx, rptr->radix);
7106 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7107 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7108 else if (!(rptr->flags & REG_VMFLAGS) ||
7109 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7110 NULL, sim_switches | SIM_SW_REG) > 0)) {
7111 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7112 if (rptr->fields) {
7113 (void)Fprintf (ofile, "\t");
7114 fprint_fields (ofile, val, val, rptr->fields);
7115 }
7116 }
7117 if (flag & EX_I)
7118 (void)Fprintf (ofile, "\t");
7119 else
7120 (void)Fprintf (ofile, "\r\n");
7121 return SCPE_OK;
7122 }
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133 t_value get_rval (REG *rptr, uint32 idx)
7134 {
7135 size_t sz;
7136 t_value val;
7137 uint32 *ptr;
7138
7139 sz = SZ_R (rptr);
7140 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7141 idx = idx + rptr->qptr;
7142 if (idx >= rptr->depth) idx = idx - rptr->depth;
7143 }
7144 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7145 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7146 if (sz <= sizeof (uint32))
7147 val = *ptr;
7148 else val = *((t_uint64 *) ptr);
7149 }
7150 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7151 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7152 if (sz <= sizeof (uint32))
7153 val = *ptr;
7154 else val = *((t_uint64 *) ptr);
7155 }
7156 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7157 (sz == sizeof (uint8)))
7158 val = *(((uint8 *) rptr->loc) + idx);
7159 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7160 (sz == sizeof (uint16)))
7161 val = *(((uint16 *) rptr->loc) + idx);
7162 else if (sz <= sizeof (uint32))
7163 val = *(((uint32 *) rptr->loc) + idx);
7164 else val = *(((t_uint64 *) rptr->loc) + idx);
7165 val = (val >> rptr->offset) & width_mask[rptr->width];
7166 return val;
7167 }
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7181 {
7182 t_stat r;
7183 t_value val, mask;
7184 int32 rdx;
7185 CONST char *tptr;
7186 char gbuf[CBUFSIZE];
7187
7188 if ((cptr == NULL) || (rptr == NULL))
7189 return SCPE_IERR;
7190 if (rptr->flags & REG_RO)
7191 return SCPE_RO;
7192 if (flag & EX_I) {
7193 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7194 if (sim_log)
7195 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7196 if (cptr == NULL)
7197 return 1;
7198 if (*cptr == 0)
7199 return SCPE_OK;
7200 }
7201 mask = width_mask[rptr->width];
7202 GET_RADIX (rdx, rptr->radix);
7203 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7204 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7205 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7206 return SCPE_ARG;
7207 }
7208 else
7209 if (!(rptr->flags & REG_VMFLAGS) ||
7210 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7211 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7212 val = get_uint (cptr, rdx, mask, &r);
7213 if (r != SCPE_OK)
7214 return SCPE_ARG;
7215 }
7216 if ((rptr->flags & REG_NZ) && (val == 0))
7217 return SCPE_ARG;
7218 put_rval (rptr, idx, val);
7219 return SCPE_OK;
7220 }
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233 void put_rval (REG *rptr, uint32 idx, t_value val)
7234 {
7235 size_t sz;
7236 t_value mask;
7237 uint32 *ptr;
7238
7239 #define PUT_RVAL(sz,rp,id,v,m) \
7240 *(((sz *) rp->loc) + id) = \
7241 (sz)((*(((sz *) rp->loc) + id) & \
7242 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7243
7244 if (rptr == sim_PC)
7245 sim_brk_npc (0);
7246 sz = SZ_R (rptr);
7247 mask = width_mask[rptr->width];
7248 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7249 idx = idx + rptr->qptr;
7250 if (idx >= rptr->depth)
7251 idx = idx - rptr->depth;
7252 }
7253 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7254 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7255 if (sz <= sizeof (uint32))
7256 *ptr = (*ptr &
7257 ~(((uint32) mask) << rptr->offset)) |
7258 (((uint32) val) << rptr->offset);
7259 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7260 & ~(mask << rptr->offset)) | (val << rptr->offset);
7261 }
7262 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7263 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7264 if (sz <= sizeof (uint32))
7265 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7266 ~(((uint32) mask) << rptr->offset)) |
7267 (((uint32) val) << rptr->offset);
7268 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7269 & ~(mask << rptr->offset)) | (val << rptr->offset);
7270 }
7271 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7272 (sz == sizeof (uint8)))
7273 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7274 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7275 (sz == sizeof (uint16)))
7276 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7277 else if (sz <= sizeof (uint32))
7278 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7279 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7280 return;
7281 }
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7297 {
7298 t_stat reason;
7299 int32 rdx;
7300
7301 if (sim_vm_fprint_addr)
7302 sim_vm_fprint_addr (ofile, dptr, addr);
7303 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7304 (void)Fprintf (ofile, ":\t");
7305 if (!(flag & EX_E))
7306 return (1 - dptr->aincr);
7307
7308 GET_RADIX (rdx, dptr->dradix);
7309 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7310 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7311 reason = 1 - dptr->aincr;
7312 }
7313 if (flag & EX_I)
7314 (void)Fprintf (ofile, "\t");
7315 else
7316 (void)Fprintf (ofile, "\r\n");
7317 return reason;
7318 }
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7332 {
7333 int32 i;
7334 t_value mask;
7335 t_addr j, loc;
7336 size_t sz;
7337 t_stat reason = SCPE_OK;
7338
7339 if ((dptr == NULL) || (uptr == NULL))
7340 return SCPE_IERR;
7341 mask = width_mask[dptr->dwidth];
7342 for (i = 0; i < sim_emax; i++)
7343 sim_eval[i] = 0;
7344 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7345 if (dptr->examine != NULL) {
7346 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7347 if (reason != SCPE_OK)
7348 break;
7349 }
7350 else {
7351 if (!(uptr->flags & UNIT_ATT))
7352 return SCPE_UNATT;
7353 if (uptr->dynflags & UNIT_NO_FIO)
7354 return SCPE_NOFNC;
7355 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7356 reason = SCPE_NXM;
7357 break;
7358 }
7359 sz = SZ_D (dptr);
7360 loc = j / dptr->aincr;
7361 if (uptr->flags & UNIT_BUF) {
7362 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7363 }
7364 else {
7365 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7366 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7367 if ((feof (uptr->fileref)) &&
7368 !(uptr->flags & UNIT_FIX)) {
7369 reason = SCPE_EOF;
7370 break;
7371 }
7372 else if (ferror (uptr->fileref)) {
7373 clearerr (uptr->fileref);
7374 reason = SCPE_IOERR;
7375 break;
7376 }
7377 }
7378 }
7379 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7380 }
7381 if ((reason != SCPE_OK) && (i == 0))
7382 return reason;
7383 return SCPE_OK;
7384 }
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7401 UNIT *uptr, int32 dfltinc)
7402 {
7403 int32 i, count, rdx;
7404 t_addr j, loc;
7405 t_stat r, reason;
7406 t_value mask;
7407 size_t sz;
7408 char gbuf[CBUFSIZE];
7409
7410 if (dptr == NULL)
7411 return SCPE_IERR;
7412 if (flag & EX_I) {
7413 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7414 if (sim_log)
7415 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7416 if (cptr == NULL)
7417 return 1;
7418 if (*cptr == 0)
7419 return dfltinc;
7420 }
7421 if (uptr->flags & UNIT_RO)
7422 return SCPE_RO;
7423 mask = width_mask[dptr->dwidth];
7424
7425 GET_RADIX (rdx, dptr->dradix);
7426 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7427 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7428 if (reason != SCPE_OK)
7429 return reason;
7430 reason = dfltinc;
7431 }
7432 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7433
7434 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7435 sim_eval[i] = sim_eval[i] & mask;
7436 if (dptr->deposit != NULL) {
7437 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7438 if (r != SCPE_OK)
7439 return r;
7440 }
7441 else {
7442 if (!(uptr->flags & UNIT_ATT))
7443 return SCPE_UNATT;
7444 if (uptr->dynflags & UNIT_NO_FIO)
7445 return SCPE_NOFNC;
7446 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7447 return SCPE_NXM;
7448 sz = SZ_D (dptr);
7449 loc = j / dptr->aincr;
7450 if (uptr->flags & UNIT_BUF) {
7451 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7452 if (loc >= uptr->hwmark)
7453 uptr->hwmark = (uint32) loc + 1;
7454 }
7455 else {
7456 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7457 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7458 if (ferror (uptr->fileref)) {
7459 clearerr (uptr->fileref);
7460 return SCPE_IOERR;
7461 }
7462 }
7463 }
7464 }
7465 return reason;
7466 }
7467
7468
7469
7470 t_stat eval_cmd (int32 flg, CONST char *cptr)
7471 {
7472 if (!sim_dflt_dev)
7473 return SCPE_ARG;
7474 DEVICE *dptr = sim_dflt_dev;
7475 int32 i, rdx, a, lim;
7476 t_stat r;
7477
7478 GET_SWITCHES (cptr);
7479 GET_RADIX (rdx, dptr->dradix);
7480 for (i = 0; i < sim_emax; i++)
7481 sim_eval[i] = 0;
7482 if (*cptr == 0)
7483 return SCPE_2FARG;
7484 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7485 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7486 if (r != SCPE_OK)
7487 return r;
7488 }
7489 lim = 1 - r;
7490 for (i = a = 0; a < lim; ) {
7491 sim_printf ("%d:\t", a);
7492 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7493 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7494 if (sim_log) {
7495 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7496 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7497 }
7498 sim_printf ("\r\n");
7499 if (r < 0)
7500 a = a + 1 - r;
7501 else a = a + dptr->aincr;
7502 i = a / dptr->aincr;
7503 }
7504 return SCPE_OK;
7505 }
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520 char *read_line (char *cptr, int32 size, FILE *stream)
7521 {
7522 return read_line_p (NULL, cptr, size, stream);
7523 }
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7538 {
7539 char *tptr;
7540
7541 if (prompt) {
7542 #if defined(HAVE_LINEHISTORY)
7543 char *tmpc = linenoise (prompt);
7544 if (tmpc == NULL)
7545 cptr = NULL;
7546 else {
7547 strncpy (cptr, tmpc, size-1);
7548 linenoiseHistoryAdd (tmpc);
7549 FREE (tmpc);
7550 }
7551 }
7552 #else
7553 (void)fflush (stdout);
7554 (void)printf ("%s", prompt);
7555 (void)fflush (stdout);
7556 cptr = fgets (cptr, size, stream);
7557 }
7558 #endif
7559 else cptr = fgets (cptr, size, stream);
7560
7561 if (cptr == NULL) {
7562 clearerr (stream);
7563 return NULL;
7564 }
7565 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7566 if ((*tptr == '\n') || (*tptr == '\r') ||
7567 (tptr == (cptr + size - 1))) {
7568 *tptr = 0;
7569 break;
7570 }
7571 }
7572 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7573 memmove (cptr, cptr + 3, strlen (cptr + 3));
7574 while (sim_isspace (*cptr))
7575 cptr++;
7576 if ((*cptr == ';') || (*cptr == '#')) {
7577 if (sim_do_echo)
7578 sim_printf("%s> %s\r\n", do_position(), cptr);
7579 *cptr = 0;
7580 }
7581
7582 return cptr;
7583 }
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7604 {
7605 t_bool quoting = FALSE;
7606 t_bool escaping = FALSE;
7607 char quote_char = 0;
7608
7609 while ((*iptr != 0) &&
7610 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7611 if (quote) {
7612 if (quoting) {
7613 if (!escaping) {
7614 if (*iptr == escape_char)
7615 escaping = TRUE;
7616 else
7617 if (*iptr == quote_char)
7618 quoting = FALSE;
7619 }
7620 else
7621 escaping = FALSE;
7622 }
7623 else {
7624 if ((*iptr == '"') || (*iptr == '\'')) {
7625 quoting = TRUE;
7626 quote_char = *iptr;
7627 }
7628 }
7629 }
7630 if (sim_islower (*iptr) && uc)
7631 *optr = (char)toupper (*iptr);
7632 else *optr = *iptr;
7633 iptr++; optr++;
7634 }
7635 if (mchar && (*iptr == mchar))
7636 iptr++;
7637 *optr = 0;
7638 while (sim_isspace (*iptr))
7639 iptr++;
7640 return iptr;
7641 }
7642
7643 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7644 {
7645 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7646 }
7647
7648 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7649 {
7650 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7651 }
7652
7653 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7654 {
7655 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7656 }
7657
7658 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7659 {
7660
7661 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7662 strcpy (optr, "!");
7663 return (CONST char *)(iptr + 1);
7664 }
7665 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7666 }
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676 char *sim_trim_endspc (char *cptr)
7677 {
7678 char *tptr;
7679
7680 tptr = cptr + strlen (cptr);
7681 while ((--tptr >= cptr) && sim_isspace (*tptr))
7682 *tptr = 0;
7683 return cptr;
7684 }
7685
7686 int sim_isspace (char c)
7687 {
7688 return (c & 0x80) ? 0 : isspace (c);
7689 }
7690
7691 int sim_islower (char c)
7692 {
7693 return (c & 0x80) ? 0 : islower (c);
7694 }
7695
7696 int sim_isalpha (char c)
7697 {
7698 return (c & 0x80) ? 0 : isalpha (c);
7699 }
7700
7701 int sim_isprint (char c)
7702 {
7703 return (c & 0x80) ? 0 : isprint (c);
7704 }
7705
7706 int sim_isdigit (char c)
7707 {
7708 return (c & 0x80) ? 0 : isdigit (c);
7709 }
7710
7711 int sim_isgraph (char c)
7712 {
7713 return (c & 0x80) ? 0 : isgraph (c);
7714 }
7715
7716 int sim_isalnum (char c)
7717 {
7718 return (c & 0x80) ? 0 : isalnum (c);
7719 }
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7733 {
7734 t_value val;
7735 CONST char *tptr;
7736
7737 *status = SCPE_OK;
7738 val = strtotv ((CONST char *)cptr, &tptr, radix);
7739 if ((cptr == tptr) || (val > max))
7740 *status = SCPE_ARG;
7741 else {
7742 while (sim_isspace (*tptr)) tptr++;
7743 if (*tptr != 0)
7744 *status = SCPE_ARG;
7745 }
7746 return val;
7747 }
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7765 uint32 rdx, t_addr max, char term)
7766 {
7767 CONST char *tptr;
7768
7769 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7770 tptr = cptr + strlen ("ALL");
7771 *lo = 0;
7772 *hi = max;
7773 }
7774 else {
7775 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7776 ((cptr[1] == '\0') ||
7777 (cptr[1] == '-') ||
7778 (cptr[1] == ':') ||
7779 (cptr[1] == '/'))) {
7780 tptr = cptr + strlen (".");
7781 *lo = *hi = sim_last_addr;
7782 }
7783 else {
7784 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7785 tptr = cptr + strlen ("$");
7786 *hi = *lo = (t_addr)sim_last_val;
7787 }
7788 else {
7789 if (dptr && sim_vm_parse_addr)
7790 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7791 else
7792 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7793 if (cptr == tptr)
7794 return NULL;
7795 }
7796 }
7797 if ((*tptr == '-') || (*tptr == ':')) {
7798 cptr = tptr + 1;
7799 if (dptr && sim_vm_parse_addr)
7800 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7801 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7802 if (cptr == tptr)
7803 return NULL;
7804 if (*lo > *hi)
7805 return NULL;
7806 }
7807 else if (*tptr == '/') {
7808 cptr = tptr + 1;
7809 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7810 if ((cptr == tptr) || (*hi == 0))
7811 return NULL;
7812 *hi = *lo + *hi - 1;
7813 }
7814 else *hi = *lo;
7815 }
7816 sim_last_addr = *hi;
7817 if (term && (*tptr++ != term))
7818 return NULL;
7819 return tptr;
7820 }
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7841 {
7842 char quote_char;
7843 uint8 *ostart = optr;
7844
7845 *osize = 0;
7846 if ((strlen(iptr) == 1) ||
7847 (iptr[0] != iptr[strlen(iptr)-1]) ||
7848 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7849 return SCPE_ARG;
7850 quote_char = *iptr++;
7851 while (iptr[1]) {
7852 if (*iptr != '\\') {
7853 if (*iptr == quote_char)
7854 return SCPE_ARG;
7855 *(optr++) = (uint8)(*(iptr++));
7856 continue;
7857 }
7858 ++iptr;
7859 switch (*iptr) {
7860 case 'r':
7861 *(optr++) = 13; ++iptr;
7862 break;
7863 case 'n':
7864 *(optr++) = 10; ++iptr;
7865 break;
7866 case 'f':
7867 *(optr++) = 12; ++iptr;
7868 break;
7869 case 't':
7870 *(optr++) = 9; ++iptr;
7871 break;
7872 case 'v':
7873 *(optr++) = 11; ++iptr;
7874 break;
7875 case 'b':
7876 *(optr++) = 8; ++iptr;
7877 break;
7878 case '\\':
7879 *(optr++) = 92; ++iptr;
7880 break;
7881 case 'e':
7882 *(optr++) = 27; ++iptr;
7883 break;
7884 case '\'':
7885 *(optr++) = 39; ++iptr;
7886 break;
7887 case '"':
7888 *(optr++) = 34; ++iptr;
7889 break;
7890 case '?':
7891 *(optr++) = 63; ++iptr;
7892 break;
7893 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7894 *optr = *(iptr++) - '0';
7895 if ((*iptr >= '0') && (*iptr <= '7'))
7896 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7897 if ((*iptr >= '0') && (*iptr <= '7'))
7898 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7899 ++optr;
7900 break;
7901 case 'x':
7902 if (1) {
7903 static const char *hex_digits = "0123456789ABCDEF";
7904 const char *c;
7905
7906 ++iptr;
7907 *optr = 0;
7908 c = strchr (hex_digits, toupper(*iptr));
7909 if (c) {
7910 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7911 ++iptr;
7912 }
7913 c = strchr (hex_digits, toupper(*iptr));
7914 if (c) {
7915 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7916 ++iptr;
7917 }
7918 ++optr;
7919 }
7920 break;
7921 default:
7922 return SCPE_ARG;
7923 }
7924 }
7925 *optr = '\0';
7926 *osize = (uint32)(optr-ostart);
7927 return SCPE_OK;
7928 }
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7944 {
7945 size_t i;
7946 t_bool double_quote_found = FALSE;
7947 t_bool single_quote_found = FALSE;
7948 char quote = '"';
7949 char *tptr, *optr;
7950
7951 optr = (char *)malloc (4*size + 3);
7952 if (optr == NULL)
7953 return NULL;
7954 tptr = optr;
7955 for (i=0; i<size; i++)
7956 switch ((char)iptr[i]) {
7957 case '"':
7958 double_quote_found = TRUE;
7959 break;
7960 case '\'':
7961 single_quote_found = TRUE;
7962 break;
7963 }
7964 if (double_quote_found && (!single_quote_found))
7965 quote = '\'';
7966 *tptr++ = quote;
7967 while (size--) {
7968 switch (*iptr) {
7969 case '\r':
7970 *tptr++ = '\\'; *tptr++ = 'r'; break;
7971 case '\n':
7972 *tptr++ = '\\'; *tptr++ = 'n'; break;
7973 case '\f':
7974 *tptr++ = '\\'; *tptr++ = 'f'; break;
7975 case '\t':
7976 *tptr++ = '\\'; *tptr++ = 't'; break;
7977 case '\v':
7978 *tptr++ = '\\'; *tptr++ = 'v'; break;
7979 case '\b':
7980 *tptr++ = '\\'; *tptr++ = 'b'; break;
7981 case '\\':
7982 *tptr++ = '\\'; *tptr++ = '\\'; break;
7983 case '"':
7984 case '\'':
7985 if (quote == *iptr)
7986 *tptr++ = '\\';
7987
7988 default:
7989 if (sim_isprint (*iptr))
7990 *tptr++ = *iptr;
7991 else {
7992 (void)sprintf (tptr, "\\%03o", *iptr);
7993 tptr += 4;
7994 }
7995 break;
7996 }
7997 ++iptr;
7998 }
7999 *tptr++ = quote;
8000 *tptr++ = '\0';
8001 return optr;
8002 }
8003
8004 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
8005 {
8006 char *string;
8007
8008 string = sim_encode_quoted_string (buf, size);
8009 (void)fprintf (st, "%s", string);
8010 FREE (string);
8011 }
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021 DEVICE *find_dev (const char *cptr)
8022 {
8023 int32 i;
8024 DEVICE *dptr;
8025
8026 if (cptr == NULL)
8027 return NULL;
8028 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8029 if ((strcmp (cptr, dptr->name) == 0) ||
8030 (dptr->lname &&
8031 (strcmp (cptr, dptr->lname) == 0)))
8032 return dptr;
8033 }
8034 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
8035 if ((strcmp (cptr, dptr->name) == 0) ||
8036 (dptr->lname &&
8037 (strcmp (cptr, dptr->lname) == 0)))
8038 return dptr;
8039 }
8040 return NULL;
8041 }
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054 DEVICE *find_unit (const char *cptr, UNIT **uptr)
8055 {
8056 uint32 i, u;
8057 const char *nptr;
8058 const char *tptr;
8059 t_stat r;
8060 DEVICE *dptr;
8061
8062 if (uptr == NULL)
8063 return NULL;
8064 *uptr = NULL;
8065 if ((dptr = find_dev (cptr))) {
8066 if (qdisable (dptr))
8067 return NULL;
8068 *uptr = dptr->units;
8069 return dptr;
8070 }
8071
8072 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8073 if (qdisable (dptr))
8074 continue;
8075 if (dptr->numunits &&
8076 (((nptr = dptr->name) &&
8077 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
8078 ((nptr = dptr->lname) &&
8079 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8080 tptr = cptr + strlen (nptr);
8081 if (sim_isdigit (*tptr)) {
8082 if (qdisable (dptr))
8083 return NULL;
8084 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8085 if (r != SCPE_OK)
8086 *uptr = NULL;
8087 else
8088 *uptr = dptr->units + u;
8089 return dptr;
8090 }
8091 }
8092 for (u = 0; u < dptr->numunits; u++) {
8093 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8094 *uptr = &dptr->units[u];
8095 return dptr;
8096 }
8097 }
8098 }
8099 return NULL;
8100 }
8101
8102
8103
8104
8105
8106
8107
8108 t_stat sim_register_internal_device (DEVICE *dptr)
8109 {
8110 uint32 i;
8111
8112 for (i = 0; (sim_devices[i] != NULL); i++)
8113 if (sim_devices[i] == dptr)
8114 return SCPE_OK;
8115 for (i = 0; i < sim_internal_device_count; i++)
8116 if (sim_internal_devices[i] == dptr)
8117 return SCPE_OK;
8118 ++sim_internal_device_count;
8119 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8120 if (!sim_internal_devices)
8121 {
8122 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8123 __func__, __FILE__, __LINE__);
8124 #if defined(USE_BACKTRACE)
8125 # if defined(SIGUSR2)
8126 (void)raise(SIGUSR2);
8127
8128 # endif
8129 #endif
8130 abort();
8131 }
8132 sim_internal_devices[sim_internal_device_count-1] = dptr;
8133 sim_internal_devices[sim_internal_device_count] = NULL;
8134 return SCPE_OK;
8135 }
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145 DEVICE *find_dev_from_unit (UNIT *uptr)
8146 {
8147 DEVICE *dptr;
8148 uint32 i, j;
8149
8150 if (uptr == NULL)
8151 return NULL;
8152 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8153 for (j = 0; j < dptr->numunits; j++) {
8154 if (uptr == (dptr->units + j))
8155 return dptr;
8156 }
8157 }
8158 for (i = 0; i<sim_internal_device_count; i++) {
8159 dptr = sim_internal_devices[i];
8160 for (j = 0; j < dptr->numunits; j++) {
8161 if (uptr == (dptr->units + j))
8162 return dptr;
8163 }
8164 }
8165 return NULL;
8166 }
8167
8168
8169
8170 t_bool qdisable (DEVICE *dptr)
8171 {
8172 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8173 }
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8188 {
8189 int32 i;
8190 DEVICE *dptr;
8191 REG *rptr, *srptr = NULL;
8192
8193 *gdptr = NULL;
8194 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8195 if (dptr->flags & DEV_DIS)
8196 continue;
8197 if ((rptr = find_reg (cptr, optr, dptr))) {
8198 if (srptr)
8199 return NULL;
8200 srptr = rptr;
8201 *gdptr = dptr;
8202 }
8203 }
8204 return srptr;
8205 }
8206
8207
8208
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8219 {
8220 CONST char *tptr;
8221 REG *rptr;
8222 size_t slnt;
8223
8224 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8225 return NULL;
8226 tptr = cptr;
8227 do {
8228 tptr++;
8229 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8230 slnt = tptr - cptr;
8231 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8232 if ((slnt == strlen (rptr->name)) &&
8233 (strncmp (cptr, rptr->name, slnt) == 0)) {
8234 if (optr != NULL)
8235 *optr = tptr;
8236 return rptr;
8237 }
8238 }
8239 return NULL;
8240 }
8241
8242
8243
8244
8245
8246
8247
8248
8249
8250
8251 int32 get_switches (const char *cptr)
8252 {
8253 int32 sw;
8254
8255 if (*cptr != '-')
8256 return 0;
8257 sw = 0;
8258 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8259 if (sim_isalpha (*cptr) == 0)
8260 return -1;
8261 sw = sw | SWMASK (toupper (*cptr));
8262 }
8263 return sw;
8264 }
8265
8266
8267
8268
8269
8270
8271
8272
8273
8274
8275 CONST char *get_sim_sw (CONST char *cptr)
8276 {
8277 int32 lsw;
8278 char gbuf[CBUFSIZE];
8279
8280 while (*cptr == '-') {
8281 cptr = get_glyph (cptr, gbuf, 0);
8282 lsw = get_switches (gbuf);
8283 if (lsw <= 0)
8284 return NULL;
8285 sim_switches = sim_switches | lsw;
8286 }
8287 return cptr;
8288 }
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8301 {
8302 int32 t;
8303 char gbuf[CBUFSIZE];
8304 CONST char *svptr;
8305 DEVICE *tdptr;
8306 UNIT *tuptr;
8307
8308 sim_switches = 0;
8309 sim_ofile = NULL;
8310 sim_schrptr = NULL;
8311 sim_schaptr = NULL;
8312 sim_stabr.logic = sim_staba.logic = SCH_OR;
8313 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8314 sim_stabr.count = 1;
8315 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8316 if (!sim_stabr.mask)
8317 {
8318 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8319 __func__, __FILE__, __LINE__);
8320 #if defined(USE_BACKTRACE)
8321 # if defined(SIGUSR2)
8322 (void)raise(SIGUSR2);
8323
8324 # endif
8325 #endif
8326 abort();
8327 }
8328 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8329 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8330 if (!sim_stabr.comp)
8331 {
8332 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8333 __func__, __FILE__, __LINE__);
8334 #if defined(USE_BACKTRACE)
8335 # if defined(SIGUSR2)
8336 (void)raise(SIGUSR2);
8337
8338 # endif
8339 #endif
8340 abort();
8341 }
8342 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8343 sim_staba.count = sim_emax;
8344 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8345 if (!sim_staba.mask)
8346 {
8347 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8348 __func__, __FILE__, __LINE__);
8349 #if defined(USE_BACKTRACE)
8350 # if defined(SIGUSR2)
8351 (void)raise(SIGUSR2);
8352
8353 # endif
8354 #endif
8355 abort();
8356 }
8357 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8358 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8359 if (!sim_staba.comp)
8360 {
8361 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8362 __func__, __FILE__, __LINE__);
8363 #if defined(USE_BACKTRACE)
8364 # if defined(SIGUSR2)
8365 (void)raise(SIGUSR2);
8366
8367 # endif
8368 #endif
8369 abort();
8370 }
8371 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8372 if (! sim_dflt_dev)
8373 return NULL;
8374 sim_dfdev = sim_dflt_dev;
8375 sim_dfunit = sim_dfdev->units;
8376 sim_opt_out = 0;
8377 *st = SCPE_OK;
8378 while (*cptr) {
8379 svptr = cptr;
8380 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8381 if (sim_ofile) {
8382 fclose (sim_ofile);
8383 *st = SCPE_ARG;
8384 return NULL;
8385 }
8386 cptr = get_glyph (cptr + 1, gbuf, 0);
8387 sim_ofile = sim_fopen (gbuf, "a");
8388 if (sim_ofile == NULL) {
8389 *st = SCPE_OPENERR;
8390 return NULL;
8391 }
8392 sim_opt_out |= CMD_OPT_OF;
8393 continue;
8394 }
8395 cptr = get_glyph (cptr, gbuf, 0);
8396 if ((t = get_switches (gbuf)) != 0) {
8397 if (t < 0) {
8398 *st = SCPE_INVSW;
8399 return NULL;
8400 }
8401 sim_switches = sim_switches | t;
8402 }
8403 else if ((opt & CMD_OPT_SCH) &&
8404 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8405 sim_schrptr = &sim_stabr;
8406 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8407 sim_opt_out |= CMD_OPT_SCH;
8408 }
8409 else if ((opt & CMD_OPT_DFT) &&
8410 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8411 (tdptr = find_unit (gbuf, &tuptr)) &&
8412 (tuptr != NULL)) {
8413 sim_dfdev = tdptr;
8414 sim_dfunit = tuptr;
8415 sim_opt_out |= CMD_OPT_DFT;
8416 }
8417 else return svptr;
8418 }
8419 return cptr;
8420 }
8421
8422
8423
8424
8425
8426
8427
8428
8429
8430
8431
8432 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8433 {
8434 char *optr = buf;
8435 int32 bit;
8436
8437 (void)memset (buf, 0, bufsize);
8438 if ((sw == 0) || (bufsize < 3))
8439 return buf;
8440 --bufsize;
8441 *optr++ = '-';
8442 for (bit=0; bit <= ('Z'-'A'); bit++)
8443 if (sw & (1 << bit))
8444 if ((size_t)(optr - buf) < bufsize)
8445 *optr++ = 'A' + bit;
8446 return buf;
8447 }
8448
8449
8450
8451
8452
8453
8454
8455
8456
8457
8458
8459
8460 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8461 {
8462 int32 c;
8463 size_t logop, cmpop;
8464 t_value logval, cmpval;
8465 const char *sptr;
8466 CONST char *tptr;
8467 const char logstr[] = "|&^", cmpstr[] = "=!><";
8468
8469 const size_t invalid_op = (size_t) -1;
8470
8471 logval = cmpval = 0;
8472 if (*cptr == 0)
8473 return NULL;
8474
8475 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8476 if ((sptr = strchr (logstr, c))) {
8477 logop = sptr - logstr;
8478 logval = strtotv (cptr, &tptr, radix);
8479 if (cptr == tptr)
8480 return NULL;
8481 cptr = tptr;
8482 }
8483 else if ((sptr = strchr (cmpstr, c))) {
8484 cmpop = sptr - cmpstr;
8485 if (*cptr == '=') {
8486 cmpop = cmpop + strlen (cmpstr);
8487 cptr++;
8488 }
8489 cmpval = strtotv (cptr, &tptr, radix);
8490 if (cptr == tptr)
8491 return NULL;
8492 cptr = tptr;
8493 }
8494 else return NULL;
8495 }
8496 if (schptr->count != 1) {
8497 FREE (schptr->mask);
8498 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8499 FREE (schptr->comp);
8500 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8501 }
8502 if (logop != invalid_op) {
8503 schptr->logic = logop;
8504 schptr->mask[0] = logval;
8505 }
8506 if (cmpop != invalid_op) {
8507 schptr->boolop = cmpop;
8508 schptr->comp[0] = cmpval;
8509 }
8510 schptr->count = 1;
8511 return schptr;
8512 }
8513
8514
8515
8516
8517
8518
8519
8520
8521
8522
8523
8524
8525 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8526 {
8527 int32 c;
8528 size_t logop, cmpop;
8529 t_value *logval, *cmpval;
8530 t_stat reason = SCPE_OK;
8531 CONST char *ocptr = cptr;
8532 const char *sptr;
8533 char gbuf[CBUFSIZE];
8534 const char logstr[] = "|&^", cmpstr[] = "=!><";
8535
8536 const size_t invalid_op = (size_t) -1;
8537
8538 if (*cptr == 0)
8539 return NULL;
8540 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8541 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8542
8543 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8544 if (NULL != (sptr = strchr (logstr, c))) {
8545 logop = sptr - logstr;
8546 cptr = get_glyph (cptr, gbuf, 0);
8547 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8548 if (reason > 0) {
8549 FREE (logval);
8550 FREE (cmpval);
8551 return get_rsearch (ocptr, radix, schptr);
8552 }
8553 }
8554 else if (NULL != (sptr = strchr (cmpstr, c))) {
8555 cmpop = sptr - cmpstr;
8556 if (*cptr == '=') {
8557 cmpop = cmpop + strlen (cmpstr);
8558 cptr++;
8559 }
8560 cptr = get_glyph (cptr, gbuf, 0);
8561 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8562 if (reason > 0) {
8563 FREE (logval);
8564 FREE (cmpval);
8565 return get_rsearch (ocptr, radix, schptr);
8566 }
8567 }
8568 else {
8569 FREE (logval);
8570 FREE (cmpval);
8571 return NULL;
8572 }
8573 }
8574 if (schptr->count != (uint32)(1 - reason)) {
8575 schptr->count = 1 - reason;
8576 FREE (schptr->mask);
8577 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8578 FREE (schptr->comp);
8579 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8580 }
8581 if (logop != invalid_op) {
8582 schptr->logic = logop;
8583 FREE (schptr->mask);
8584 schptr->mask = logval;
8585 }
8586 else {
8587 FREE (logval);
8588 }
8589 if (cmpop != invalid_op) {
8590 schptr->boolop = cmpop;
8591 FREE (schptr->comp);
8592 schptr->comp = cmpval;
8593 }
8594 else {
8595 FREE (cmpval);
8596 }
8597 return schptr;
8598 }
8599
8600
8601
8602
8603
8604
8605
8606
8607
8608
8609 int32 test_search (t_value *values, SCHTAB *schptr)
8610 {
8611 t_value *val = NULL;
8612 int32 i, updown;
8613 int32 ret = 0;
8614
8615 if (schptr == NULL)
8616 return ret;
8617
8618 val = (t_value *)malloc (schptr->count * sizeof (*values));
8619 if (!val)
8620 {
8621 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8622 __func__, __FILE__, __LINE__);
8623 #if defined(USE_BACKTRACE)
8624 # if defined(SIGUSR2)
8625 (void)raise(SIGUSR2);
8626
8627 # endif
8628 #endif
8629 abort();
8630 }
8631 for (i=0; i<(int32)schptr->count; i++) {
8632 val[i] = values[i];
8633 switch (schptr->logic) {
8634
8635 case SCH_OR:
8636 val[i] = val[i] | schptr->mask[i];
8637 break;
8638
8639 case SCH_AND:
8640 val[i] = val[i] & schptr->mask[i];
8641 break;
8642
8643 case SCH_XOR:
8644 val[i] = val[i] ^ schptr->mask[i];
8645 break;
8646 }
8647 }
8648
8649 ret = 1;
8650 if (1) {
8651 updown = -1;
8652 i=schptr->count-1;
8653 }
8654 else {
8655 updown = 1;
8656 i=0;
8657 }
8658 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8659 switch (schptr->boolop) {
8660
8661 case SCH_E: case SCH_EE:
8662 if (val[i] != schptr->comp[i])
8663 ret = 0;
8664 break;
8665
8666 case SCH_N: case SCH_NE:
8667 if (val[i] == schptr->comp[i])
8668 ret = 0;
8669 break;
8670
8671 case SCH_G:
8672 if (val[i] <= schptr->comp[i])
8673 ret = 0;
8674 break;
8675
8676 case SCH_GE:
8677 if (val[i] < schptr->comp[i])
8678 ret = 0;
8679 break;
8680
8681 case SCH_L:
8682 if (val[i] >= schptr->comp[i])
8683 ret = 0;
8684 break;
8685
8686 case SCH_LE:
8687 if (val[i] > schptr->comp[i])
8688 ret = 0;
8689 break;
8690 }
8691 }
8692 FREE (val);
8693 return ret;
8694 }
8695
8696
8697
8698
8699
8700
8701
8702
8703
8704
8705
8706
8707
8708
8709
8710 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8711 {
8712 int32 nodigit;
8713 t_value val;
8714 uint32 c, digit;
8715
8716 *endptr = inptr;
8717 if ((radix < 2) || (radix > 36))
8718 return 0;
8719 while (sim_isspace (*inptr))
8720 inptr++;
8721 val = 0;
8722 nodigit = 1;
8723 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8724 if (sim_islower (c))
8725 c = toupper (c);
8726 if (sim_isdigit (c))
8727 digit = c - (uint32) '0';
8728 else if (radix <= 10)
8729 break;
8730 else digit = c + 10 - (uint32) 'A';
8731 if (digit >= radix)
8732 return 0;
8733 val = (val * radix) + digit;
8734 nodigit = 0;
8735 }
8736 if (nodigit)
8737 return 0;
8738 *endptr = inptr;
8739 return val;
8740 }
8741
8742
8743
8744
8745
8746
8747
8748
8749
8750
8751
8752
8753
8754
8755
8756 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8757 size_t width, uint32 format)
8758 {
8759 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8760 t_value owtest, wtest;
8761 size_t d;
8762 size_t digit;
8763 size_t ndigits;
8764 size_t commas = 0;
8765 char dbuf[MAX_WIDTH + 1];
8766
8767 for (d = 0; d < MAX_WIDTH; d++)
8768 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8769 dbuf[MAX_WIDTH] = 0;
8770 d = MAX_WIDTH;
8771 do {
8772 d = d - 1;
8773 digit = val % radix;
8774 val = val / radix;
8775 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8776 } while ((d > 0) && (val != 0));
8777
8778 switch (format) {
8779 case PV_LEFT:
8780 break;
8781 case PV_RZRO:
8782 wtest = owtest = radix;
8783 ndigits = 1;
8784 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8785 owtest = wtest;
8786 wtest = wtest * radix;
8787 ndigits = ndigits + 1;
8788 }
8789 if ((MAX_WIDTH - (ndigits + commas)) < d)
8790 d = MAX_WIDTH - (ndigits + commas);
8791 break;
8792 }
8793 if (NULL == buffer)
8794 return ((t_stat) strlen(dbuf+d));
8795 *buffer = '\0';
8796 if (width < strlen(dbuf+d))
8797 return SCPE_IOERR;
8798 strcpy(buffer, dbuf+d);
8799 return SCPE_OK;
8800 }
8801
8802 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8803 uint32 width, uint32 format)
8804 {
8805 char dbuf[MAX_WIDTH + 1];
8806
8807 if (!stream)
8808 return sprint_val (NULL, val, radix, width, format);
8809 if (width > MAX_WIDTH)
8810 width = MAX_WIDTH;
8811 sprint_val (dbuf, val, radix, width, format);
8812 if (Fprintf (stream, "%s", dbuf) < 0)
8813 return SCPE_IOERR;
8814 return SCPE_OK;
8815 }
8816
8817 const char *sim_fmt_secs (double seconds)
8818 {
8819 static char buf[60];
8820 char frac[16] = "";
8821 const char *sign = "";
8822 double val = seconds;
8823 double days, hours, mins, secs, msecs, usecs;
8824
8825 if (val == 0.0)
8826 return "";
8827 if (val < 0.0) {
8828 sign = "-";
8829 val = -val;
8830 }
8831 days = floor (val / (24.0*60.0*60.0));
8832 val -= (days * 24.0*60.0*60.0);
8833 hours = floor (val / (60.0*60.0));
8834 val -= (hours * 60.0 * 60.0);
8835 mins = floor (val / 60.0);
8836 val -= (mins * 60.0);
8837 secs = floor (val);
8838 val -= secs;
8839 val *= 1000.0;
8840 msecs = floor (val);
8841 val -= msecs;
8842 val *= 1000.0;
8843 usecs = floor (val+0.5);
8844 if (usecs == 1000.0) {
8845 usecs = 0.0;
8846 msecs += 1;
8847 }
8848 if ((msecs > 0.0) || (usecs > 0.0)) {
8849 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8850 while (frac[strlen (frac) - 1] == '0')
8851 frac[strlen (frac) - 1] = '\0';
8852 if (strlen (frac) == 1)
8853 frac[0] = '\0';
8854 }
8855 if (days > 0)
8856 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8857 sign, days, (days != 1) ? "s" : "", hours, mins,
8858 secs, frac, (days == 1) ? "s" : "");
8859 else
8860 if (hours > 0)
8861 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8862 sign, hours, mins, secs, frac);
8863 else
8864 if (mins > 0)
8865 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8866 sign, mins, secs, frac);
8867 else
8868 if (secs > 0)
8869 (void)sprintf (buf, "%s%.0f%s second",
8870 sign, secs, frac);
8871 else
8872 if (msecs > 0) {
8873 if (usecs > 0)
8874 (void)sprintf (buf, "%s%.0f.%s msec",
8875 sign, msecs, frac+4);
8876 else
8877 (void)sprintf (buf, "%s%.0f msec",
8878 sign, msecs);
8879 }
8880 else
8881 (void)sprintf (buf, "%s%.0f usec",
8882 sign, usecs);
8883 if (0 != strncmp ("1 ", buf, 2))
8884 strcpy (&buf[strlen (buf)], "s");
8885 return buf;
8886 }
8887
8888
8889
8890
8891
8892
8893
8894
8895
8896
8897
8898
8899
8900
8901
8902
8903 t_stat sim_process_event (void)
8904 {
8905 UNIT *uptr;
8906 t_stat reason;
8907 #if defined(TESTING)
8908 cpu_state_t * cpup = _cpup;
8909 #endif
8910
8911 if (stop_cpu)
8912 {
8913 #if defined(WIN_STDIO)
8914 (void)fflush(stdout);
8915 (void)fflush(stderr);
8916 #endif
8917 return SCPE_STOP;
8918 }
8919 UPDATE_SIM_TIME;
8920
8921 if (sim_clock_queue == QUEUE_LIST_END) {
8922 sim_interval = noqueue_time = NOQUEUE_WAIT;
8923 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8924 "Queue Empty New Interval = %d\r\n",
8925 sim_interval);
8926 return SCPE_OK;
8927 }
8928 sim_processing_event = TRUE;
8929 do {
8930 uptr = sim_clock_queue;
8931 sim_clock_queue = uptr->next;
8932 uptr->next = NULL;
8933 sim_interval -= uptr->time;
8934 uptr->time = 0;
8935 if (sim_clock_queue != QUEUE_LIST_END)
8936 sim_interval = sim_clock_queue->time;
8937 else
8938 sim_interval = noqueue_time = NOQUEUE_WAIT;
8939 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8940 "Processing Event for %s\r\n", sim_uname (uptr));
8941 if (uptr->action != NULL)
8942 reason = uptr->action (uptr);
8943 else
8944 reason = SCPE_OK;
8945 } while ((reason == SCPE_OK) &&
8946 (sim_interval <= 0) &&
8947 (sim_clock_queue != QUEUE_LIST_END) &&
8948 (!stop_cpu));
8949
8950 if (sim_clock_queue == QUEUE_LIST_END) {
8951 sim_interval = noqueue_time = NOQUEUE_WAIT;
8952 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8953 "Processing Queue Complete New Interval = %d\r\n",
8954 sim_interval);
8955 }
8956 else
8957 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8958 "Processing Queue Complete New Interval = %d(%s)\r\n",
8959 sim_interval, sim_uname(sim_clock_queue));
8960
8961 if ((reason == SCPE_OK) && stop_cpu)
8962 {
8963 #if defined(WIN_STDIO)
8964 (void)fflush(stdout);
8965 (void)fflush(stderr);
8966 #endif
8967 reason = SCPE_STOP;
8968 }
8969 sim_processing_event = FALSE;
8970 return reason;
8971 }
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982 t_stat sim_activate (UNIT *uptr, int32 event_time)
8983 {
8984 if (uptr->dynflags & UNIT_TMR_UNIT)
8985 return sim_timer_activate (uptr, event_time);
8986 return _sim_activate (uptr, event_time);
8987 }
8988
8989 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8990 {
8991 UNIT *cptr, *prvptr;
8992 int32 accum;
8993 #if defined(TESTING)
8994 cpu_state_t * cpup = _cpup;
8995 #endif
8996
8997 if (sim_is_active (uptr))
8998 return SCPE_OK;
8999 UPDATE_SIM_TIME;
9000
9001 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
9002
9003 prvptr = NULL;
9004 accum = 0;
9005 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9006 if (event_time < (accum + cptr->time))
9007 break;
9008 accum = accum + cptr->time;
9009 prvptr = cptr;
9010 }
9011 if (prvptr == NULL) {
9012 cptr = uptr->next = sim_clock_queue;
9013 sim_clock_queue = uptr;
9014 }
9015 else {
9016 cptr = uptr->next = prvptr->next;
9017 prvptr->next = uptr;
9018 }
9019 uptr->time = event_time - accum;
9020 if (cptr != QUEUE_LIST_END)
9021 cptr->time = cptr->time - uptr->time;
9022 sim_interval = sim_clock_queue->time;
9023 return SCPE_OK;
9024 }
9025
9026
9027
9028
9029
9030
9031
9032
9033
9034
9035 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
9036 {
9037 sim_cancel (uptr);
9038 return _sim_activate (uptr, event_time);
9039 }
9040
9041
9042
9043
9044
9045
9046
9047
9048
9049
9050 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
9051 {
9052 return _sim_activate_after (uptr, usec_delay);
9053 }
9054
9055 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
9056 {
9057 if (sim_is_active (uptr))
9058 return SCPE_OK;
9059 return sim_timer_activate_after (uptr, usec_delay);
9060 }
9061
9062
9063
9064
9065
9066
9067
9068
9069
9070
9071 t_stat sim_cancel (UNIT *uptr)
9072 {
9073 UNIT *cptr, *nptr;
9074 #if defined(TESTING)
9075 cpu_state_t * cpup = _cpup;
9076 #endif
9077
9078 if (sim_clock_queue == QUEUE_LIST_END)
9079 return SCPE_OK;
9080 if (!sim_is_active (uptr))
9081 return SCPE_OK;
9082 UPDATE_SIM_TIME;
9083 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9084 nptr = QUEUE_LIST_END;
9085
9086 if (sim_clock_queue == uptr) {
9087 nptr = sim_clock_queue = uptr->next;
9088 uptr->next = NULL;
9089 }
9090 else {
9091 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9092 if (cptr->next == uptr) {
9093 nptr = cptr->next = uptr->next;
9094 uptr->next = NULL;
9095 break;
9096 }
9097 }
9098 }
9099 if (nptr != QUEUE_LIST_END)
9100 nptr->time += (uptr->next) ? 0 : uptr->time;
9101 if (!uptr->next)
9102 uptr->time = 0;
9103 if (sim_clock_queue != QUEUE_LIST_END)
9104 sim_interval = sim_clock_queue->time;
9105 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9106 if (uptr->next) {
9107 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9108 if (sim_deb)
9109 fclose(sim_deb);
9110 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9111 __func__, __FILE__, __LINE__);
9112 abort ();
9113 }
9114 return SCPE_OK;
9115 }
9116
9117
9118
9119
9120
9121
9122
9123
9124
9125 t_bool sim_is_active (UNIT *uptr)
9126 {
9127 if (uptr->next == NULL)
9128 return FALSE;
9129 else
9130 return TRUE;
9131 }
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141 int32 sim_activate_time (UNIT *uptr)
9142 {
9143 UNIT *cptr;
9144 int32 accum = 0;
9145
9146 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9147 if (cptr == sim_clock_queue) {
9148 if (sim_interval > 0)
9149 accum = accum + sim_interval;
9150 }
9151 else
9152 accum = accum + cptr->time;
9153 if (cptr == uptr)
9154 return accum + 1;
9155 }
9156 return 0;
9157 }
9158
9159
9160
9161
9162
9163
9164
9165
9166 double sim_gtime (void)
9167 {
9168 return sim_time;
9169 }
9170
9171
9172
9173
9174
9175
9176
9177
9178 int32 sim_qcount (void)
9179 {
9180 int32 cnt;
9181 UNIT *uptr;
9182
9183 cnt = 0;
9184 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9185 cnt++;
9186 return cnt;
9187 }
9188
9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
9219
9220
9221
9222
9223
9224 t_stat sim_brk_init (void)
9225 {
9226 int32 i;
9227
9228 for (i=0; i<sim_brk_lnt; i++) {
9229 BRKTAB *bp;
9230 if (sim_brk_tab)
9231 {
9232 bp = sim_brk_tab[i];
9233
9234 while (bp)
9235 {
9236 BRKTAB *bpt = bp->next;
9237
9238 FREE (bp->act);
9239 FREE (bp);
9240 bp = bpt;
9241 }
9242 }
9243 }
9244 if (sim_brk_tab != NULL)
9245 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9246 sim_brk_lnt = SIM_BRK_INILNT;
9247 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9248 if (sim_brk_tab == NULL)
9249 return SCPE_MEM;
9250 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9251 sim_brk_ent = sim_brk_ins = 0;
9252 sim_brk_clract ();
9253 sim_brk_npc (0);
9254 return SCPE_OK;
9255 }
9256
9257
9258
9259 BRKTAB *sim_brk_fnd (t_addr loc)
9260 {
9261 int32 lo, hi, p;
9262 BRKTAB *bp;
9263
9264 if (sim_brk_ent == 0) {
9265 sim_brk_ins = 0;
9266 return NULL;
9267 }
9268 lo = 0;
9269 hi = sim_brk_ent - 1;
9270 do {
9271 p = (lo + hi) >> 1;
9272 bp = sim_brk_tab[p];
9273 if (loc == bp->addr) {
9274 sim_brk_ins = p;
9275 return bp;
9276 }
9277 else if (loc < bp->addr)
9278 hi = p - 1;
9279 else lo = p + 1;
9280 } while (lo <= hi);
9281 if (loc < bp->addr)
9282 sim_brk_ins = p;
9283 else sim_brk_ins = p + 1;
9284 return NULL;
9285 }
9286
9287 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9288 {
9289 BRKTAB *bp = sim_brk_fnd (loc);
9290
9291 while (bp) {
9292 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9293 (bp->typ == btyp))
9294 return bp;
9295 bp = bp->next;
9296 }
9297 return bp;
9298 }
9299
9300
9301
9302 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9303 {
9304 int32 i, t;
9305 BRKTAB *bp, **newp;
9306
9307 if (sim_brk_ins < 0)
9308 return NULL;
9309 if (sim_brk_ent >= sim_brk_lnt) {
9310 t = sim_brk_lnt + SIM_BRK_INILNT;
9311 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9312 if (newp == NULL)
9313 return NULL;
9314 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9315 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9316 FREE (sim_brk_tab);
9317 sim_brk_tab = newp;
9318 sim_brk_lnt = t;
9319 }
9320 if ((sim_brk_ins == sim_brk_ent) ||
9321 ((sim_brk_ins != sim_brk_ent) &&
9322 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9323 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9324 sim_brk_tab[i] = sim_brk_tab[i - 1];
9325 sim_brk_tab[sim_brk_ins] = NULL;
9326 }
9327 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9328 if (!bp)
9329 {
9330 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9331 __func__, __FILE__, __LINE__);
9332 #if defined(USE_BACKTRACE)
9333 # if defined(SIGUSR2)
9334 (void)raise(SIGUSR2);
9335
9336 # endif
9337 #endif
9338 abort();
9339 }
9340 bp->next = sim_brk_tab[sim_brk_ins];
9341 sim_brk_tab[sim_brk_ins] = bp;
9342 if (bp->next == NULL)
9343 sim_brk_ent += 1;
9344 bp->addr = loc;
9345 bp->typ = btyp;
9346 bp->cnt = 0;
9347 bp->act = NULL;
9348 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9349 bp->time_fired[i] = -1.0;
9350 return bp;
9351 }
9352
9353
9354
9355 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9356 {
9357 BRKTAB *bp;
9358
9359 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9360 sw |= sim_brk_dflt;
9361 if (~sim_brk_types & sw) {
9362 char gbuf[CBUFSIZE];
9363
9364 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9365 }
9366 if ((sw & BRK_TYP_DYN_ALL) && act)
9367 return SCPE_ARG;
9368 bp = sim_brk_fnd (loc);
9369 if (!bp)
9370 bp = sim_brk_new (loc, sw);
9371 else {
9372 while (bp && (bp->typ != (uint32)sw))
9373 bp = bp->next;
9374 if (!bp)
9375 bp = sim_brk_new (loc, sw);
9376 }
9377 if (!bp)
9378 return SCPE_MEM;
9379 bp->cnt = ncnt;
9380 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9381 (bp->act != NULL) && (act != NULL)) {
9382 FREE (bp->act);
9383 bp->act = NULL;
9384 }
9385 if ((act != NULL) && (*act != 0)) {
9386 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9387 if (newp == NULL)
9388 return SCPE_MEM;
9389 strncpy (newp, act, CBUFSIZE);
9390 bp->act = newp;
9391 }
9392 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9393 return SCPE_OK;
9394 }
9395
9396
9397
9398 t_stat sim_brk_clr (t_addr loc, int32 sw)
9399 {
9400 BRKTAB *bpl = NULL;
9401 BRKTAB *bp = sim_brk_fnd (loc);
9402 int32 i;
9403
9404 if (!bp)
9405 return SCPE_OK;
9406 if (sw == 0)
9407 sw = SIM_BRK_ALLTYP;
9408
9409 #if !defined(__clang_analyzer__)
9410 while (bp) {
9411 if (bp->typ == (bp->typ & sw)) {
9412 FREE (bp->act);
9413 if (bp == sim_brk_tab[sim_brk_ins])
9414 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9415 else
9416 {
9417 if (bpl)
9418 bpl->next = bp->next;
9419 }
9420 FREE (bp);
9421 bp = bpl;
9422 }
9423 else {
9424 bpl = bp;
9425 bp = bp->next;
9426 }
9427 }
9428 #endif
9429 if (sim_brk_tab[sim_brk_ins] == NULL) {
9430 sim_brk_ent = sim_brk_ent - 1;
9431 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9432 sim_brk_tab[i] = sim_brk_tab[i+1];
9433 }
9434 sim_brk_summ = 0;
9435 for (i = 0; i < sim_brk_ent; i++) {
9436 bp = sim_brk_tab[i];
9437 while (bp) {
9438 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9439 bp = bp->next;
9440 }
9441 }
9442 return SCPE_OK;
9443 }
9444
9445
9446
9447 t_stat sim_brk_clrall (int32 sw)
9448 {
9449 int32 i;
9450
9451 if (sw == 0)
9452 sw = SIM_BRK_ALLTYP;
9453 for (i = 0; i < sim_brk_ent;) {
9454 t_addr loc = sim_brk_tab[i]->addr;
9455 sim_brk_clr (loc, sw);
9456 if ((i < sim_brk_ent) &&
9457 (loc == sim_brk_tab[i]->addr))
9458 ++i;
9459 }
9460 return SCPE_OK;
9461 }
9462
9463
9464
9465 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9466 {
9467 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9468 DEVICE *dptr;
9469 uint32 i, any;
9470
9471 if ((sw == 0) || (sw == SWMASK ('C'))) {
9472 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9473 if (!bp || (!(bp->typ & sw))) {
9474 return SCPE_OK; }
9475 dptr = sim_dflt_dev;
9476 if (dptr == NULL) {
9477 return SCPE_OK; }
9478 if (sw & SWMASK ('C')) {
9479 if (st != NULL) {
9480 (void)fprintf (st, "SET BREAK "); }
9481 } else {
9482 if (sim_vm_fprint_addr) {
9483 sim_vm_fprint_addr
9484 (st, dptr, loc);
9485 } else {
9486 fprint_val
9487 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9488 if (st != NULL) {
9489 (void)fprintf (st, ":\t"); }
9490 }
9491 for (i = any = 0; i < 26; i++) {
9492 if ((bp->typ >> i) & 1) {
9493 if ((sw & SWMASK ('C')) == 0) {
9494 if (any) {
9495 if (st != NULL) {
9496 (void)fprintf (st, ", "); } }
9497 if (st != NULL) {
9498 fputc (i + 'A', st); }
9499 }
9500 } else {
9501 if (st != NULL) {
9502 (void)fprintf (st, "-%c", i + 'A'); }
9503 any = 1;
9504 }
9505 }
9506 if (sw & SWMASK ('C')) {
9507 if (st != NULL) {
9508 (void)fprintf (st, " "); }
9509 if (sim_vm_fprint_addr) {
9510 if (st != NULL) {
9511 sim_vm_fprint_addr (st, dptr, loc); }
9512 } else {
9513 fprint_val
9514 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9515 }
9516 if (bp->cnt > 0) {
9517 if (st != NULL) {
9518 (void)fprintf (st, "[%d]", bp->cnt); } }
9519 if (bp->act != NULL) {
9520 if (st != NULL) {
9521 (void)fprintf (st, "; %s", bp->act); } }
9522 (void)fprintf (st, "\r\n");
9523 return SCPE_OK;
9524 }
9525
9526
9527
9528 t_stat sim_brk_showall (FILE *st, uint32 sw)
9529 {
9530 int32 bit, mask, types;
9531 BRKTAB **bpt;
9532
9533 if ((sw == 0) || (sw == SWMASK ('C')))
9534 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9535 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9536 if (sim_brk_types & (1 << bit))
9537 ++types;
9538 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9539 (void)fprintf (st, "Supported Breakpoint Types:");
9540 for (bit=0; bit <= ('Z'-'A'); bit++)
9541 if (sim_brk_types & (1 << bit))
9542 (void)fprintf (st, " -%c", 'A' + bit);
9543 (void)fprintf (st, "\r\n");
9544 }
9545 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9546 mask = (sw & sim_brk_types);
9547 (void)fprintf (st, "Displaying Breakpoint Types:");
9548 for (bit=0; bit <= ('Z'-'A'); bit++)
9549 if (mask & (1 << bit))
9550 (void)fprintf (st, " -%c", 'A' + bit);
9551 (void)fprintf (st, "\r\n");
9552 }
9553 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9554 BRKTAB *prev = NULL;
9555 BRKTAB *cur = *bpt;
9556 BRKTAB *next;
9557
9558 while (cur) {
9559 next = cur->next;
9560 cur->next = prev;
9561 prev = cur;
9562 cur = next;
9563 }
9564
9565 *bpt = prev;
9566
9567 cur = prev;
9568 while (cur) {
9569 if (cur->typ & sw)
9570 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9571 cur = cur->next;
9572 }
9573
9574 cur = prev;
9575 prev = NULL;
9576 while (cur) {
9577 next = cur->next;
9578 cur->next = prev;
9579 prev = cur;
9580 cur = next;
9581 }
9582
9583 *bpt = prev;
9584 }
9585 return SCPE_OK;
9586 }
9587
9588
9589
9590 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9591 {
9592 BRKTAB *bp;
9593 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9594
9595 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9596 btyp |= BRK_TYP_DYN_ALL;
9597
9598 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9599 double s_gtime = sim_gtime ();
9600
9601 if (bp->time_fired[spc] == s_gtime)
9602 return 0;
9603 bp->time_fired[spc] = s_gtime;
9604 if (--bp->cnt > 0)
9605 return 0;
9606 bp->cnt = 0;
9607 sim_brk_setact (bp->act);
9608 sim_brk_match_type = btyp & bp->typ;
9609 if (bp->typ & BRK_TYP_TEMP)
9610 sim_brk_clr (loc, bp->typ);
9611 sim_brk_match_addr = loc;
9612 return sim_brk_match_type;
9613 }
9614 return 0;
9615 }
9616
9617
9618
9619 CONST char *sim_brk_getact (char *buf, int32 size)
9620 {
9621 char *ep;
9622 size_t lnt;
9623
9624 if (sim_brk_act[sim_do_depth] == NULL)
9625 return NULL;
9626 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9627 sim_brk_act[sim_do_depth]++;
9628 if (*sim_brk_act[sim_do_depth] == 0) {
9629 return sim_brk_clract ();
9630 }
9631 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9632 lnt = ep - sim_brk_act[sim_do_depth];
9633 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9634 buf[lnt] = 0;
9635 sim_brk_act[sim_do_depth] += lnt + 1;
9636 }
9637 else {
9638 strncpy (buf, sim_brk_act[sim_do_depth], size);
9639 sim_brk_clract ();
9640 }
9641 return buf;
9642 }
9643
9644
9645
9646 char *sim_brk_clract (void)
9647 {
9648 FREE (sim_brk_act_buf[sim_do_depth]);
9649 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9650 }
9651
9652
9653
9654 void sim_brk_setact (const char *action)
9655 {
9656 if (action) {
9657 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9658 if (!sim_brk_act_buf[sim_do_depth])
9659 {
9660 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9661 __func__, __FILE__, __LINE__);
9662 #if defined(USE_BACKTRACE)
9663 # if defined(SIGUSR2)
9664 (void)raise(SIGUSR2);
9665
9666 # endif
9667 #endif
9668 abort();
9669 }
9670 strcpy (sim_brk_act_buf[sim_do_depth], action);
9671 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9672 }
9673 else
9674 sim_brk_clract ();
9675 }
9676
9677
9678
9679 void sim_brk_npc (uint32 cnt)
9680 {
9681 uint32 spc;
9682 BRKTAB **bpt, *bp;
9683
9684 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9685 cnt = SIM_BKPT_N_SPC;
9686 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9687 for (bp = *bpt; bp; bp = bp->next) {
9688 for (spc = 0; spc < cnt; spc++)
9689 bp->time_fired[spc] = -1.0;
9690 }
9691 }
9692 }
9693
9694
9695
9696 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9697 {
9698 BRKTAB **bpt, *bp;
9699
9700 if (spc < SIM_BKPT_N_SPC) {
9701 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9702 for (bp = *bpt; bp; bp = bp->next) {
9703 if (bp->typ & btyp)
9704 bp->time_fired[spc] = -1.0;
9705 }
9706 }
9707 }
9708 }
9709
9710 const char *sim_brk_message(void)
9711 {
9712 static char msg[256];
9713 char addr[65] = "";
9714 char buf[32];
9715
9716 msg[0] = '\0';
9717 if (sim_dflt_dev) {
9718 if (sim_vm_sprint_addr)
9719 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9720 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9721 }
9722 if (sim_brk_type_desc) {
9723 BRKTYPTAB *brk = sim_brk_type_desc;
9724
9725 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9726 if (brk->btyp == sim_brk_match_type) {
9727 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9728 break;
9729 }
9730 brk++;
9731 }
9732 }
9733 if (!msg[0])
9734 (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9735 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9736
9737 return msg;
9738 }
9739
9740
9741
9742
9743
9744
9745
9746
9747
9748
9749
9750
9751
9752
9753
9754
9755
9756
9757
9758
9759
9760
9761
9762
9763
9764
9765
9766
9767
9768
9769
9770
9771
9772
9773
9774
9775
9776 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9777 {
9778 char gbuf[CBUFSIZE];
9779 CONST char *tptr;
9780 CONST char *c1ptr;
9781 t_bool after_set = FALSE;
9782 uint32 after;
9783 int32 cnt = 0;
9784 t_stat r;
9785
9786 if (exp == NULL)
9787 return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9788 after = exp->after;
9789
9790 if ((cptr == NULL) || (*cptr == 0))
9791 return SCPE_2FARG;
9792 if (*cptr == '[') {
9793 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9794 if ((cptr == c1ptr) || (*c1ptr != ']'))
9795 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9796 cptr = c1ptr + 1;
9797 while (sim_isspace(*cptr))
9798 ++cptr;
9799 }
9800 tptr = get_glyph (cptr, gbuf, ',');
9801 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9802 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9803 if (r != SCPE_OK)
9804 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9805 after_set = TRUE;
9806 cptr = tptr;
9807 }
9808 if ((*cptr != '"') && (*cptr != '\''))
9809 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9810 cptr = get_glyph_quoted (cptr, gbuf, 0);
9811
9812 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9813 }
9814
9815
9816
9817 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9818 {
9819 char gbuf[CBUFSIZE];
9820
9821 if (NULL == cptr || !*cptr)
9822 return sim_exp_clrall (exp);
9823 if ((*cptr != '"') && (*cptr != '\''))
9824 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9825 cptr = get_glyph_quoted (cptr, gbuf, 0);
9826 if (*cptr != '\0')
9827 return SCPE_2MARG;
9828 return sim_exp_clr (exp, gbuf);
9829 }
9830
9831
9832
9833 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9834 {
9835 size_t i;
9836
9837 if (NULL == exp->rules)
9838 return NULL;
9839 for (i=start_rule; i<exp->size; i++)
9840 if (!strcmp (exp->rules[i].match_pattern, match))
9841 return &exp->rules[i];
9842 return NULL;
9843 }
9844
9845
9846
9847 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9848 {
9849 size_t i;
9850
9851 if (NULL == ep)
9852 return SCPE_OK;
9853 FREE (ep->match);
9854 FREE (ep->match_pattern);
9855 FREE (ep->act);
9856 exp->size -= 1;
9857 #if !defined(__clang_analyzer__)
9858 for (i=ep-exp->rules; i<exp->size; i++)
9859 exp->rules[i] = exp->rules[i+1];
9860 if (exp->size == 0) {
9861 FREE (exp->rules);
9862 exp->rules = NULL;
9863 }
9864 #endif
9865 return SCPE_OK;
9866 }
9867
9868 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9869 {
9870 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9871
9872 while (ep) {
9873 sim_exp_clr_tab (exp, ep);
9874 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9875 }
9876 return SCPE_OK;
9877 }
9878
9879
9880
9881 t_stat sim_exp_clrall (EXPECT *exp)
9882 {
9883 int32 i;
9884
9885 for (i=0; i<exp->size; i++) {
9886 FREE (exp->rules[i].match);
9887 FREE (exp->rules[i].match_pattern);
9888 FREE (exp->rules[i].act);
9889 }
9890 FREE (exp->rules);
9891 exp->rules = NULL;
9892 exp->size = 0;
9893 FREE (exp->buf);
9894 exp->buf = NULL;
9895 exp->buf_size = 0;
9896 exp->buf_ins = 0;
9897 return SCPE_OK;
9898 }
9899
9900
9901
9902 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9903 {
9904 EXPTAB *ep;
9905 uint8 *match_buf;
9906 uint32 match_size;
9907 size_t i;
9908
9909
9910 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9911 if (!match_buf)
9912 return SCPE_MEM;
9913 if (switches & EXP_TYP_REGEX) {
9914 FREE (match_buf);
9915 return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9916 }
9917 else {
9918 if (switches & EXP_TYP_REGEX_I) {
9919 FREE (match_buf);
9920 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9921 }
9922 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9923 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9924 FREE (match_buf);
9925 return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9926 }
9927 }
9928 FREE (match_buf);
9929 for (i=0; i<exp->size; i++) {
9930 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9931 (exp->rules[i].switches & EXP_TYP_PERSIST))
9932 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9933 }
9934 if (after && exp->size)
9935 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9936 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9937 if (!exp->rules)
9938 {
9939 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9940 __func__, __FILE__, __LINE__);
9941 #if defined(USE_BACKTRACE)
9942 # if defined(SIGUSR2)
9943 (void)raise(SIGUSR2);
9944
9945 # endif
9946 #endif
9947 abort();
9948 }
9949 ep = &exp->rules[exp->size];
9950 exp->size += 1;
9951 exp->after = after;
9952 (void)memset (ep, 0, sizeof(*ep));
9953 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9954 if (ep->match_pattern)
9955 strcpy (ep->match_pattern, match);
9956 ep->cnt = cnt;
9957 ep->switches = switches;
9958 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9959 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9960 sim_exp_clr_tab (exp, ep);
9961 FREE (match_buf);
9962 return SCPE_MEM;
9963 }
9964 if (switches & EXP_TYP_REGEX) {
9965 FREE (match_buf);
9966 match_buf = NULL;
9967 }
9968 else {
9969 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9970 sim_decode_quoted_string (match, match_buf, &match_size);
9971 ep->match = match_buf;
9972 ep->size = match_size;
9973 }
9974 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9975 if (!ep->match_pattern)
9976 {
9977 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9978 __func__, __FILE__, __LINE__);
9979 #if defined(USE_BACKTRACE)
9980 # if defined(SIGUSR2)
9981 (void)raise(SIGUSR2);
9982
9983 # endif
9984 #endif
9985 abort();
9986 }
9987 strcpy (ep->match_pattern, match);
9988 if (ep->act) {
9989 FREE (ep->act);
9990 ep->act = NULL;
9991 }
9992 if (act) while (sim_isspace(*act)) ++act;
9993 if ((act != NULL) && (*act != 0)) {
9994 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9995 if (newp == NULL)
9996 return SCPE_MEM;
9997 strcpy (newp, act);
9998 ep->act = newp;
9999 }
10000
10001 for (i=0; i<exp->size; i++) {
10002 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
10003 if (compare_size >= exp->buf_size) {
10004 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
10005 exp->buf_size = compare_size + 1;
10006 }
10007 }
10008 return SCPE_OK;
10009 }
10010
10011
10012
10013 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
10014 {
10015 if (!ep)
10016 return SCPE_OK;
10017 (void)fprintf (st, "EXPECT");
10018 if (ep->switches & EXP_TYP_PERSIST)
10019 (void)fprintf (st, " -p");
10020 if (ep->switches & EXP_TYP_CLEARALL)
10021 (void)fprintf (st, " -c");
10022 if (ep->switches & EXP_TYP_REGEX)
10023 (void)fprintf (st, " -r");
10024 if (ep->switches & EXP_TYP_REGEX_I)
10025 (void)fprintf (st, " -i");
10026 (void)fprintf (st, " %s", ep->match_pattern);
10027 if (ep->cnt > 0)
10028 (void)fprintf (st, " [%d]", ep->cnt);
10029 if (ep->act)
10030 (void)fprintf (st, " %s", ep->act);
10031 (void)fprintf (st, "\r\n");
10032 return SCPE_OK;
10033 }
10034
10035 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
10036 {
10037 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
10038
10039 if (exp->buf_size) {
10040 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10041
10042 (void)fprintf (st, "Match Buffer Size: %lld\r\n",
10043 (long long)exp->buf_size);
10044 (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
10045 (long long)exp->buf_ins);
10046 (void)fprintf (st, "Buffer Contents: %s\r\n",
10047 bstr);
10048 FREE (bstr);
10049 }
10050 if (exp->after)
10051 (void)fprintf (st, "Halt After: %lld instructions\r\n",
10052 (long long)exp->after);
10053 if (exp->dptr && exp->dbit)
10054 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10055 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10056 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10057 (void)fprintf (st, "Match Rules:\r\n");
10058 if (!*match)
10059 return sim_exp_showall (st, exp);
10060 if (!ep) {
10061 (void)fprintf (st, "No Rules match '%s'\r\n", match);
10062 return SCPE_ARG;
10063 }
10064 do {
10065 sim_exp_show_tab (st, exp, ep);
10066 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10067 } while (ep);
10068 return SCPE_OK;
10069 }
10070
10071
10072
10073 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
10074 {
10075 size_t i;
10076
10077 for (i=0; i < exp->size; i++)
10078 sim_exp_show_tab (st, exp, &exp->rules[i]);
10079 return SCPE_OK;
10080 }
10081
10082
10083
10084 t_stat sim_exp_check (EXPECT *exp, uint8 data)
10085 {
10086 size_t i;
10087 EXPTAB *ep = NULL;
10088 char *tstr = NULL;
10089 #if defined(TESTING)
10090 cpu_state_t * cpup = _cpup;
10091 #endif
10092
10093 if ((!exp) || (!exp->rules))
10094 return SCPE_OK;
10095
10096 exp->buf[exp->buf_ins++] = data;
10097 exp->buf[exp->buf_ins] = '\0';
10098
10099 for (i=0; i < exp->size; i++) {
10100 ep = &exp->rules[i];
10101 if (ep == NULL)
10102 break;
10103 if (ep->switches & EXP_TYP_REGEX) {
10104 }
10105 else {
10106 if (exp->buf_ins < ep->size) {
10107
10108
10109
10110
10111 if (exp->buf_ins > 0) {
10112 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10113 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10114 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10115
10116 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10117 (long long)exp->buf_ins, estr);
10118 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10119 FREE (estr);
10120 FREE (mstr);
10121 }
10122 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10123 continue;
10124 }
10125 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10126 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10127 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10128
10129 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10130 (long long)exp->buf_size-(ep->size-exp->buf_ins),
10131 (long long)ep->size-exp->buf_ins, estr);
10132 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10133 FREE (estr);
10134 FREE (mstr);
10135 }
10136 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10137 continue;
10138 break;
10139 }
10140 else {
10141 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10142 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10143 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10144
10145 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10146 (long long)exp->buf_ins-ep->size,
10147 (long long)ep->size, estr);
10148 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10149 FREE (estr);
10150 FREE (mstr);
10151 }
10152 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10153 continue;
10154 break;
10155 }
10156 }
10157 }
10158 if (exp->buf_ins == exp->buf_size) {
10159 exp->buf_ins = 0;
10160 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10161 }
10162 if ((ep != NULL) && (i != exp->size)) {
10163 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10164 if (ep->cnt > 0) {
10165 ep->cnt -= 1;
10166 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10167 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10168 }
10169 else {
10170 uint32 after = exp->after;
10171 int32 switches = ep->switches;
10172 if (ep->act && *ep->act) {
10173 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10174 }
10175 else {
10176 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10177 }
10178 sim_brk_setact (ep->act);
10179 if (ep->switches & EXP_TYP_CLEARALL)
10180 sim_exp_clrall (exp);
10181 else {
10182 if (!(ep->switches & EXP_TYP_PERSIST))
10183 sim_exp_clr_tab (exp, ep);
10184 }
10185 sim_activate (&sim_expect_unit,
10186 (switches & EXP_TYP_TIME) ?
10187 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10188 after);
10189 }
10190
10191 exp->buf_ins = 0;
10192 }
10193 if (tstr)
10194 FREE (tstr);
10195 return SCPE_OK;
10196 }
10197
10198
10199
10200 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10201 {
10202 if (snd->extoff != 0) {
10203 if (snd->insoff > snd->extoff)
10204 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10205 snd->insoff -= snd->extoff;
10206 snd->extoff = 0;
10207 }
10208 if (snd->insoff+size > snd->bufsize) {
10209 snd->bufsize = snd->insoff+size;
10210 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10211 if (!snd->buffer)
10212 {
10213 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10214 __func__, __FILE__, __LINE__);
10215 #if defined(USE_BACKTRACE)
10216 # if defined(SIGUSR2)
10217 (void)raise(SIGUSR2);
10218
10219 # endif
10220 #endif
10221 abort();
10222 }
10223 }
10224 memcpy(snd->buffer+snd->insoff, data, size);
10225 snd->insoff += size;
10226 if (delay)
10227 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10228 if (after)
10229 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10230 if (snd->after == 0)
10231 snd->after = snd->delay;
10232 snd->next_time = sim_gtime() + snd->after;
10233 return SCPE_OK;
10234 }
10235
10236
10237 t_stat sim_send_clear (SEND *snd)
10238 {
10239 snd->insoff = 0;
10240 snd->extoff = 0;
10241 return SCPE_OK;
10242 }
10243
10244
10245
10246 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10247 {
10248 if (snd->extoff < snd->insoff) {
10249 (void)fprintf (st, "%lld bytes of pending input Data:\r\n ",
10250 (long long)snd->insoff-snd->extoff);
10251 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10252 (void)fprintf (st, "\r\n");
10253 }
10254 else
10255 (void)fprintf (st, "No Pending Input Data\r\n");
10256 if ((snd->next_time - sim_gtime()) > 0) {
10257 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10258 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10259 (int)(snd->next_time - sim_gtime()),
10260 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10261 else
10262 (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10263 (int)(snd->next_time - sim_gtime()));
10264 }
10265 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10266 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10267 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10268 else
10269 (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10270 (int)snd->delay);
10271 if (snd->dptr && snd->dbit)
10272 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10273 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10274 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10275 return SCPE_OK;
10276 }
10277
10278
10279
10280 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10281 {
10282 #if defined(TESTING)
10283 cpu_state_t * cpup = _cpup;
10284 #endif
10285 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10286 if (sim_gtime() < snd->next_time) {
10287 *stat = SCPE_OK;
10288 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10289 }
10290 else {
10291 char dstr[8] = "";
10292 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10293 snd->next_time = sim_gtime() + snd->delay;
10294 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10295 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10296 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10297 }
10298 return TRUE;
10299 }
10300 return FALSE;
10301 }
10302
10303
10304
10305 const char *sim_error_text (t_stat stat)
10306 {
10307 static char msgbuf[64];
10308
10309 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10310 if (stat == SCPE_OK)
10311 return "No Error";
10312 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10313 return scp_errors[stat-SCPE_BASE].message;
10314 (void)sprintf(msgbuf, "Error %d", stat);
10315 return msgbuf;
10316 }
10317
10318 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10319 {
10320 char gbuf[CBUFSIZE];
10321 size_t cond;
10322
10323 *stat = SCPE_ARG;
10324 cptr = get_glyph (cptr, gbuf, 0);
10325 if (0 == memcmp("SCPE_", gbuf, 5))
10326 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10327 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10328 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10329 cond += SCPE_BASE;
10330 break;
10331 }
10332 if (0 == strcmp(gbuf, "OK"))
10333 cond = SCPE_OK;
10334 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10335 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10336 if (0 == numeric_cond)
10337 return SCPE_ARG;
10338 cond = (t_stat) numeric_cond;
10339 }
10340 if (cond > SCPE_MAX_ERR)
10341 return SCPE_ARG;
10342 *stat = cond;
10343 return SCPE_OK;
10344 }
10345
10346
10347
10348 const char* debug_bstates = "01_^";
10349 char debug_line_prefix[256];
10350 int32 debug_unterm = 0;
10351
10352
10353
10354 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10355 {
10356 static const char *debtab_none = "DEBTAB_ISNULL";
10357 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10358 const char *some_match = NULL;
10359 int32 offset = 0;
10360
10361 if (dptr->debflags == 0)
10362 return debtab_none;
10363
10364 dbits &= dptr->dctrl;
10365
10366
10367
10368 while ((offset < 32) && dptr->debflags[offset].name) {
10369 if (dptr->debflags[offset].mask == dbits)
10370 return dptr->debflags[offset].name;
10371 if (dptr->debflags[offset].mask & dbits)
10372 some_match = dptr->debflags[offset].name;
10373 offset++;
10374 }
10375 return some_match ? some_match : debtab_nomatch;
10376 }
10377
10378
10379
10380 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10381 {
10382 const char* debug_type = get_dbg_verb (dbits, dptr);
10383 char tim_t[32] = "";
10384 char tim_a[32] = "";
10385 char pc_s[64] = "";
10386 struct timespec time_now;
10387
10388 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10389 clock_gettime(CLOCK_REALTIME, &time_now);
10390 if (sim_deb_switches & SWMASK ('R'))
10391 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10392 if (sim_deb_switches & SWMASK ('T')) {
10393 time_t tnow = (time_t)time_now.tv_sec;
10394 struct tm *now = gmtime(&tnow);
10395 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10396 (int)now->tm_hour,
10397 (int)now->tm_min,
10398 (int)now->tm_sec,
10399 (long)(time_now.tv_nsec / 1000000));
10400 }
10401 if (sim_deb_switches & SWMASK ('A')) {
10402 (void)sprintf(tim_t, "%d.%03ld ",
10403 (int)(time_now.tv_sec),
10404 (long)(time_now.tv_nsec / 1000000));
10405 }
10406 }
10407 if (sim_deb_switches & SWMASK ('P')) {
10408 t_value val;
10409
10410 if (sim_vm_pc_value)
10411 val = (*sim_vm_pc_value)();
10412 else
10413 val = get_rval (sim_PC, 0);
10414 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10415 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10416 }
10417 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10418 tim_t, tim_a, sim_gtime(), pc_s,
10419 "", dptr->name, debug_type);
10420 return debug_line_prefix;
10421 }
10422
10423 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10424 {
10425 int32 i, fields, offset;
10426 uint32 value, beforevalue, mask;
10427
10428 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10429 if (bitdefs[fields].offset == 0xffffffff)
10430 bitdefs[fields].offset = offset;
10431 offset += bitdefs[fields].width;
10432 }
10433 for (i = fields-1; i >= 0; i--) {
10434 if (bitdefs[i].name[0] == '\0')
10435 continue;
10436 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10437 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10438 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10439 }
10440 else {
10441 const char *delta = "";
10442 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10443 value = (uint32)((after >> bitdefs[i].offset) & mask);
10444 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10445 if (value < beforevalue)
10446 delta = "_";
10447 if (value > beforevalue)
10448 delta = "^";
10449 if (bitdefs[i].valuenames)
10450 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10451 else
10452 if (bitdefs[i].format) {
10453 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10454 (void)Fprintf(stream, bitdefs[i].format, value);
10455 (void)Fprintf(stream, " ");
10456 }
10457 else
10458 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10459 }
10460 }
10461 }
10462
10463
10464
10465
10466
10467 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10468 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10469 {
10470 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10471 if (!debug_unterm)
10472 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10473 if (header)
10474 (void)fprintf(sim_deb, "%s: ", header);
10475 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10476 if (terminate)
10477 (void)fprintf(sim_deb, "\r\n");
10478 debug_unterm = terminate ? 0 : 1;
10479 }
10480 }
10481 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10482 uint32 before, uint32 after, int terminate)
10483 {
10484 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10485 }
10486
10487
10488 void sim_printf (const char* fmt, ...)
10489 {
10490 char stackbuf[STACKBUFSIZE];
10491 int32 bufsize = sizeof(stackbuf);
10492 char *buf = stackbuf;
10493 int32 len;
10494 va_list arglist;
10495
10496 while (1) {
10497 va_start (arglist, fmt);
10498 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10499 va_end (arglist);
10500
10501
10502
10503 if ((len < 0) || (len >= bufsize-1)) {
10504 if (buf != stackbuf)
10505 FREE (buf);
10506 if (bufsize >= (INT_MAX / 2))
10507 return;
10508 bufsize = bufsize * 2;
10509 if (bufsize < len + 2)
10510 bufsize = len + 2;
10511 buf = (char *) malloc (bufsize);
10512 if (buf == NULL)
10513 return;
10514 buf[bufsize-1] = '\0';
10515 continue;
10516 }
10517 break;
10518 }
10519
10520 if (sim_is_running) {
10521 char *c, *remnant = buf;
10522 while ((c = strchr(remnant, '\n'))) {
10523 if ((c != buf) && (*(c - 1) != '\r'))
10524 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10525 else
10526 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10527 remnant = c + 1;
10528 }
10529 (void)printf("%s", remnant);
10530 }
10531 else
10532 (void)printf("%s", buf);
10533
10534
10535
10536
10537
10538
10539
10540 (void)fflush (stdout);
10541 if (sim_log && (sim_log != stdout)) {
10542 (void)fprintf (sim_log, "%s", buf);
10543 (void)fflush (sim_log);
10544 }
10545 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log)) {
10546 (void)fprintf (sim_deb, "%s", buf);
10547 (void)fflush (sim_deb);
10548 }
10549
10550 if (buf != stackbuf)
10551 FREE (buf);
10552 }
10553
10554
10555 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10556 {
10557 char stackbuf[STACKBUFSIZE];
10558 size_t bufsize = sizeof(stackbuf);
10559 char *buf = stackbuf;
10560 size_t len;
10561 va_list arglist;
10562 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10563
10564 while (1) {
10565 va_start (arglist, fmt);
10566 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10567 va_end (arglist);
10568
10569
10570
10571 if (len >= bufsize - 1) {
10572 if (buf != stackbuf)
10573 FREE (buf);
10574 bufsize = bufsize * 2;
10575 if (bufsize < len + 2)
10576 bufsize = len + 2;
10577 buf = (char *) malloc (bufsize);
10578 if (buf == NULL)
10579 return SCPE_MEM;
10580 buf[bufsize-1] = '\0';
10581 continue;
10582 }
10583 break;
10584 }
10585
10586 if (sim_do_ocptr[sim_do_depth]) {
10587 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10588 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10589 else {
10590 if (sim_deb)
10591 (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10592 }
10593 }
10594 if (sim_is_running && !inhibit_message) {
10595 char *c, *remnant = buf;
10596 while ((c = strchr(remnant, '\n'))) {
10597 if ((c != buf) && (*(c - 1) != '\r'))
10598 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10599 else
10600 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10601 remnant = c + 1;
10602 }
10603 (void)printf("%s", remnant);
10604 }
10605 else {
10606 if (!inhibit_message)
10607 (void)printf("%s", buf);
10608 }
10609 if (sim_log && (sim_log != stdout) && !inhibit_message)
10610 (void)fprintf (sim_log, "%s", buf);
10611 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10612 (void)fprintf (sim_deb, "%s", buf);
10613
10614 if (buf != stackbuf)
10615 FREE (buf);
10616 return stat | SCPE_NOMESSAGE;
10617 }
10618
10619
10620
10621
10622
10623
10624
10625
10626
10627 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10628 {
10629 DEVICE *dptr = (DEVICE *)vdptr;
10630 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10631 char stackbuf[STACKBUFSIZE];
10632 int32 bufsize = sizeof(stackbuf);
10633 char *buf = stackbuf;
10634 va_list arglist;
10635 int32 i, j, len;
10636 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10637
10638 buf[bufsize-1] = '\0';
10639 while (1) {
10640 va_start (arglist, fmt);
10641 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10642 va_end (arglist);
10643
10644
10645
10646 if ((len < 0) || (len >= bufsize-1)) {
10647 if (buf != stackbuf)
10648 FREE (buf);
10649 if (bufsize >= (INT_MAX / 2))
10650 return;
10651 bufsize = bufsize * 2;
10652 if (bufsize < len + 2)
10653 bufsize = len + 2;
10654 buf = (char *) malloc (bufsize);
10655 if (buf == NULL)
10656 return;
10657 buf[bufsize-1] = '\0';
10658 continue;
10659 }
10660 break;
10661 }
10662
10663
10664
10665 for (i = j = 0; i < len; ++i) {
10666 if ('\n' == buf[i]) {
10667 if (i >= j) {
10668 if ((i != j) || (i == 0)) {
10669 if (debug_unterm)
10670 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10671 else
10672 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10673 }
10674 debug_unterm = 0;
10675 }
10676 j = i + 1;
10677 }
10678 }
10679 if (i > j) {
10680 if (debug_unterm)
10681 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10682 else
10683 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10684 }
10685
10686
10687
10688 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10689 if (buf != stackbuf)
10690 FREE (buf);
10691 }
10692 return;
10693 }
10694
10695 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10696 {
10697 #if defined(TESTING)
10698 cpu_state_t * cpup = _cpup;
10699 #endif
10700 if (sim_deb && (dptr->dctrl & reason)) {
10701 sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10702 if (data && len) {
10703 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10704 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10705 static char hex[] = "0123456789ABCDEF";
10706 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10707 static unsigned char ebcdic2ascii[] = {
10708 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10709 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10710 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10711 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10712 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10713 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10714 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10715 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10716 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10717 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10718 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10719 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10720 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10721 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10722 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10723 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10724 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10725 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10726 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10727 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10728 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10729 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10730 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10731 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10732 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10733 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10734 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10735 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10736 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10737 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10738 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10739 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10740 };
10741
10742 for (i=same=0; i<len; i += 16) {
10743 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10744 ++same;
10745 continue;
10746 }
10747 if (same > 0) {
10748 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10749 (unsigned long int)(i - (16*same)),
10750 (unsigned long int)(i - 1));
10751 same = 0;
10752 }
10753 group = (((len - i) > 16) ? 16 : (len - i));
10754 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10755 eidx = strlen(ebcdicbuf);
10756 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10757 ridx = strlen(rad50buf);
10758 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10759 soff = strlen(strbuf);
10760 for (sidx=oidx=0; sidx<group; ++sidx) {
10761 outbuf[oidx++] = ' ';
10762 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10763 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10764 if (sim_isprint (data[i+sidx]))
10765 strbuf[soff+sidx] = data[i+sidx];
10766 else
10767 strbuf[soff+sidx] = '.';
10768 if (ridx && ((sidx&1) == 0)) {
10769 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10770
10771 if (word >= 64000) {
10772 rad50buf[ridx++] = '|';
10773 rad50buf[ridx++] = '|';
10774 rad50buf[ridx++] = '|';
10775 }
10776 else {
10777 rad50buf[ridx++] = rad50[word/1600];
10778 rad50buf[ridx++] = rad50[(word/40)%40];
10779 rad50buf[ridx++] = rad50[word%40];
10780 }
10781 }
10782 if (eidx) {
10783 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10784 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10785 else
10786 ebcdicbuf[eidx++] = '.';
10787 }
10788 }
10789 outbuf[oidx] = '\0';
10790 strbuf[soff+sidx] = '\0';
10791 ebcdicbuf[eidx] = '\0';
10792 rad50buf[ridx] = '\0';
10793 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10794 (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10795 }
10796 if (same > 0) {
10797 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10798 (unsigned long int)(i-(16*same)),
10799 (unsigned long int)(len-1));
10800 }
10801 }
10802 }
10803 }
10804
10805 int Fprintf (FILE *f, const char* fmt, ...)
10806 {
10807 int ret = 0;
10808 va_list args;
10809
10810 va_start (args, fmt);
10811 ret = vfprintf (f, fmt, args);
10812 va_end (args);
10813 return ret;
10814 }
10815
10816
10817
10818
10819
10820
10821
10822
10823
10824
10825
10826
10827
10828
10829
10830
10831
10832
10833
10834 #define blankch(x) ((x) == ' ' || (x) == '\t')
10835
10836 typedef struct topic {
10837 size_t level;
10838 char *title;
10839 char *label;
10840 struct topic *parent;
10841 struct topic **children;
10842 uint32 kids;
10843 char *text;
10844 size_t len;
10845 uint32 flags;
10846 size_t kidwid;
10847 #define HLP_MAGIC_TOPIC 1
10848 } TOPIC;
10849
10850 static volatile struct {
10851 const char *error;
10852 const char *prox;
10853 size_t block;
10854 size_t line;
10855 } help_where = { "", NULL, 0, 0 };
10856 jmp_buf help_env;
10857
10858 #define FAIL(why,text,here) \
10859 { \
10860 help_where.error = #text; \
10861 help_where.prox = here; \
10862 longjmp ( help_env, (why) ); \
10863 \
10864 }
10865
10866
10867
10868
10869
10870
10871 static void appendText (TOPIC *topic, const char *text, size_t len)
10872 {
10873 char *newt;
10874
10875 if (!len)
10876 return;
10877
10878 newt = (char *)realloc (topic->text, topic->len + len +1);
10879 if (!newt) {
10880 #if !defined(SUNLINT)
10881 FAIL (SCPE_MEM, No memory, NULL);
10882 #endif
10883 }
10884 topic->text = newt;
10885 memcpy (newt + topic->len, text, len);
10886 topic->len +=len;
10887 newt[topic->len] = '\0';
10888 return;
10889 }
10890
10891
10892
10893 static void cleanHelp (TOPIC *topic)
10894 {
10895 TOPIC *child;
10896 size_t i;
10897
10898 FREE (topic->title);
10899 FREE (topic->text);
10900 FREE (topic->label);
10901 for (i = 0; i < topic->kids; i++) {
10902 child = topic->children[i];
10903 cleanHelp (child);
10904 FREE (child);
10905 }
10906 FREE (topic->children);
10907 return;
10908 }
10909
10910
10911
10912
10913 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10914 UNIT *uptr, const char *htext, va_list ap)
10915 {
10916 char *end;
10917 size_t n, ilvl;
10918 #define VSMAX 100
10919 char *vstrings[VSMAX];
10920 size_t vsnum = 0;
10921 char * astrings[VSMAX+1];
10922 size_t asnum = 0;
10923 char *const *hblock;
10924 const char *ep;
10925 t_bool excluded = FALSE;
10926
10927
10928
10929
10930
10931
10932
10933 (void)memset (vstrings, 0, sizeof (vstrings));
10934 (void)memset (astrings, 0, sizeof (astrings));
10935 astrings[asnum++] = (char *) htext;
10936
10937 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10938 help_where.block = hblock - astrings;
10939 help_where.line = 0;
10940 while (*htext) {
10941 const char *start;
10942
10943 help_where.line++;
10944 if (sim_isspace (*htext) || *htext == '+') {
10945 if (excluded) {
10946 while (*htext && *htext != '\n')
10947 htext++;
10948 if (*htext)
10949 ++htext;
10950 continue;
10951 }
10952 ilvl = 1;
10953 appendText (topic, " ", 4);
10954 if (*htext == '+') {
10955 while (*htext == '+') {
10956 ilvl++;
10957 appendText (topic, " ", 4);
10958 htext++;
10959 }
10960 }
10961 while (*htext && *htext != '\n' && sim_isspace (*htext))
10962 htext++;
10963 if (!*htext)
10964 break;
10965 start = htext;
10966 while (*htext) {
10967 if (*htext == '%') {
10968 appendText (topic, start, htext - start);
10969 switch (*++htext) {
10970 case 'U':
10971 if (dptr) {
10972 char buf[129];
10973 n = uptr? uptr - dptr->units: 0;
10974 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10975 appendText (topic, buf, strlen (buf));
10976 }
10977 break;
10978 case 'D':
10979 if (dptr != NULL)
10980 appendText (topic, dptr->name, strlen (dptr->name));
10981 break;
10982 case 'S':
10983 appendText (topic, sim_name, strlen (sim_name));
10984 break;
10985 case '%':
10986 appendText (topic, "%", 1);
10987 break;
10988 case '+':
10989 appendText (topic, "+", 1);
10990 break;
10991 default:
10992 if (sim_isdigit (*htext)) {
10993 n = 0;
10994 while (sim_isdigit (*htext))
10995 n += (n * 10) + (*htext++ - '0');
10996 if (( *htext != 'H' && *htext != 's') ||
10997 n == 0 || n >= VSMAX) {
10998 #if !defined(SUNLINT)
10999 FAIL (SCPE_ARG, Invalid escape, htext);
11000 #endif
11001 }
11002 while (n > vsnum)
11003 vstrings[vsnum++] = va_arg (ap, char *);
11004 start = vstrings[n-1];
11005 if (*htext == 'H') {
11006 if (asnum >= VSMAX) {
11007 #if !defined(SUNLINT)
11008 FAIL (SCPE_ARG, Too many blocks, htext);
11009 #endif
11010 }
11011 astrings[asnum++] = (char *)start;
11012 break;
11013 }
11014 ep = start;
11015 while (*ep) {
11016 if (*ep == '\n') {
11017 ep++;
11018 appendText (topic, start, ep - start);
11019 if (*ep) {
11020 size_t i;
11021 for (i = 0; i < ilvl; i++)
11022 appendText (topic, " ", 4);
11023 }
11024 start = ep;
11025 }
11026 else
11027 ep++;
11028 }
11029 appendText (topic, start, ep-start);
11030 break;
11031 }
11032 #if !defined(SUNLINT)
11033 FAIL (SCPE_ARG, Invalid escape, htext);
11034 #endif
11035 }
11036 start = ++htext;
11037 continue;
11038 }
11039 if (*htext == '\n') {
11040 htext++;
11041 appendText (topic, start, htext - start);
11042 break;
11043 }
11044 htext++;
11045 }
11046 continue;
11047 }
11048 if (sim_isdigit (*htext)) {
11049 TOPIC **children;
11050 TOPIC *newt;
11051 char nbuf[100];
11052
11053 n = 0;
11054 start = htext;
11055 while (sim_isdigit (*htext))
11056 n += (n * 10) + (*htext++ - '0');
11057 if ((htext == start) || !n) {
11058 #if !defined(SUNLINT)
11059 FAIL (SCPE_ARG, Invalid topic heading, htext);
11060 #endif
11061 }
11062 if (n <= topic->level) {
11063 while (n <= topic->level)
11064 topic = topic->parent;
11065 }
11066 else {
11067 if (n > topic->level + 1) {
11068 #if !defined(SUNLINT)
11069 FAIL (SCPE_ARG, Level not contiguous, htext);
11070 #endif
11071 }
11072 }
11073 while (*htext && (*htext != '\n') && sim_isspace (*htext))
11074 htext++;
11075 if (!*htext || (*htext == '\n')) {
11076 #if !defined(SUNLINT)
11077 FAIL (SCPE_ARG, Missing topic name, htext);
11078 #endif
11079 }
11080 start = htext;
11081 while (*htext && (*htext != '\n'))
11082 htext++;
11083 if (start == htext) {
11084 #if !defined(SUNLINT)
11085 FAIL (SCPE_ARG, Null topic name, htext);
11086 #endif
11087 }
11088 excluded = FALSE;
11089 if (*start == '?') {
11090 size_t n = 0;
11091 start++;
11092 while (sim_isdigit (*start))
11093 n += (n * 10) + (*start++ - '0');
11094 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11095 #if !defined(SUNLINT)
11096 FAIL (SCPE_ARG, Invalid parameter number, start);
11097 #endif
11098 }
11099 while (n > vsnum)
11100 vstrings[vsnum++] = va_arg (ap, char *);
11101 end = vstrings[n-1];
11102 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11103 excluded = TRUE;
11104 if (*htext)
11105 htext++;
11106 continue;
11107 }
11108 }
11109 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11110 if (!newt) {
11111 #if !defined(SUNLINT)
11112 FAIL (SCPE_MEM, No memory, NULL);
11113 #endif
11114 }
11115 size_t len = (htext > start) ? (htext - start) : 0;
11116 newt->title = (char *) malloc(len + 1);
11117 if (!newt->title) {
11118 FREE (newt);
11119 #if !defined(SUNLINT)
11120 FAIL (SCPE_MEM, No memory, NULL);
11121 #endif
11122 }
11123 memcpy (newt->title, start, htext - start);
11124 newt->title[htext - start] = '\0';
11125 if (*htext)
11126 htext++;
11127
11128 if (newt->title[0] == '$')
11129 newt->flags |= HLP_MAGIC_TOPIC;
11130
11131 children = (TOPIC **) realloc (topic->children,
11132 (topic->kids +1) * sizeof (TOPIC *));
11133 if (NULL == children) {
11134 FREE (newt->title);
11135 FREE (newt);
11136 #if !defined(SUNLINT)
11137 FAIL (SCPE_MEM, No memory, NULL);
11138 #endif
11139 }
11140 topic->children = children;
11141 topic->children[topic->kids++] = newt;
11142 newt->level = n;
11143 newt->parent = topic;
11144 n = strlen (newt->title);
11145 if (n > topic->kidwid)
11146 topic->kidwid = n;
11147 (void)sprintf (nbuf, ".%u", topic->kids);
11148 n = strlen (topic->label) + strlen (nbuf) + 1;
11149 newt->label = (char *) malloc (n);
11150 if (NULL == newt->label) {
11151 FREE (newt->title);
11152 topic->children[topic->kids -1] = NULL;
11153 FREE (newt);
11154 #if !defined(SUNLINT)
11155 FAIL (SCPE_MEM, No memory, NULL);
11156 #endif
11157 }
11158 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11159 topic = newt;
11160 continue;
11161 }
11162 if (*htext == ';') {
11163 while (*htext && *htext != '\n')
11164 htext++;
11165 continue;
11166 }
11167 #if !defined(SUNLINT)
11168 FAIL (SCPE_ARG, Unknown line type, htext);
11169 #endif
11170 }
11171 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11172 vsnum = 0;
11173 }
11174
11175 return topic;
11176 }
11177
11178
11179
11180
11181
11182 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
11183 {
11184 char *prefix;
11185 char *newp, *newt;
11186
11187 if (topic->level == 0) {
11188 prefix = (char *) calloc (2,1);
11189 if (!prefix) {
11190 #if !defined(SUNLINT)
11191 FAIL (SCPE_MEM, No memory, NULL);
11192 #endif
11193 }
11194 prefix[0] = '\n';
11195 }
11196 else
11197 prefix = helpPrompt (topic->parent, "", oneword);
11198
11199 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11200 strlen (pstring) +1);
11201 if (!newp) {
11202 FREE (prefix);
11203 #if !defined(SUNLINT)
11204 FAIL (SCPE_MEM, No memory, NULL);
11205 #endif
11206 }
11207 strcpy (newp, prefix);
11208 if (topic->children) {
11209 if (topic->level != 0)
11210 strcat (newp, " ");
11211 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11212 topic->title+1: topic->title;
11213 if (oneword) {
11214 char *np = newp + strlen (newp);
11215 while (*newt) {
11216 *np++ = blankch (*newt)? '_' : *newt;
11217 newt++;
11218 }
11219 *np = '\0';
11220 }
11221 else
11222 strcat (newp, newt);
11223 if (*pstring && *pstring != '?')
11224 strcat (newp, " ");
11225 }
11226 strcat (newp, pstring);
11227 FREE (prefix);
11228 return newp;
11229 }
11230
11231 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11232 {
11233 char tbuf[CBUFSIZE];
11234 size_t i, skiplines;
11235 #if defined(_WIN32)
11236 FILE *tmp;
11237 char *tmpnam;
11238
11239 do {
11240 int fd;
11241 tmpnam = _tempnam (NULL, "simh");
11242 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11243 if (fd != -1) {
11244 tmp = _fdopen (fd, "w+");
11245 break;
11246 }
11247 } while (1);
11248 #else
11249 FILE *tmp = tmpfile();
11250 #endif
11251
11252 if (!tmp) {
11253 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11254 xstrerror_l(errno), errno);
11255 return;
11256 }
11257
11258 if (topic->title)
11259 (void)fprintf (st, "%s\r\n", topic->title+1);
11260
11261 skiplines = 0;
11262 if (topic->title) {
11263 if (!strcmp (topic->title+1, "Registers")) {
11264 fprint_reg_help (tmp, dptr) ;
11265 skiplines = 1;
11266 }
11267 else
11268 if (!strcmp (topic->title+1, "Set commands")) {
11269 fprint_set_help (tmp, dptr);
11270 skiplines = 3;
11271 }
11272 else
11273 if (!strcmp (topic->title+1, "Show commands")) {
11274 fprint_show_help (tmp, dptr);
11275 skiplines = 3;
11276 }
11277 }
11278 rewind (tmp);
11279 if (errno) {
11280 (void)fprintf (st, "rewind: error %d\r\n", errno);
11281 }
11282
11283
11284
11285 for (i =0; i < skiplines; i++)
11286 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11287
11288 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11289 if (tbuf[0] != '\n')
11290 fputs (" ", st);
11291 fputs (tbuf, st);
11292 }
11293 fclose (tmp);
11294 #if defined(_WIN32)
11295 remove (tmpnam);
11296 FREE (tmpnam);
11297 #endif
11298 return;
11299 }
11300
11301
11302 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11303 UNIT *uptr, int32 flag,
11304 TOPIC *topic, va_list ap )
11305 {
11306 size_t i;
11307
11308 if (topic->flags & HLP_MAGIC_TOPIC) {
11309 (void)fprintf (st, "\r\n%s ", topic->label);
11310 displayMagicTopic (st, dptr, topic);
11311 }
11312 else
11313 (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11314
11315
11316
11317
11318
11319
11320 if (topic->text)
11321 fputs (topic->text, st);
11322
11323 for (i = 0; i < topic->kids; i++)
11324 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11325
11326 return SCPE_OK;
11327 }
11328
11329 #define HLP_MATCH_AMBIGUOUS (~0u)
11330 #define HLP_MATCH_WILDCARD (~1U)
11331 #define HLP_MATCH_NONE 0
11332 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11333 {
11334 size_t i, match;
11335 char cbuf[CBUFSIZE], *cptr;
11336
11337 if (!strcmp (token, "*"))
11338 return HLP_MATCH_WILDCARD;
11339
11340 match = 0;
11341 for (i = 0; i < topic->kids; i++) {
11342 strcpy (cbuf,topic->children[i]->title +
11343 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11344 cptr = cbuf;
11345 while (*cptr) {
11346 if (blankch (*cptr)) {
11347 *cptr++ = '_';
11348 }
11349 else {
11350 *cptr = (char)toupper (*cptr);
11351 cptr++;
11352 }
11353 }
11354 if (!strcmp (cbuf, token))
11355 return i+1;
11356 if (!strncmp (cbuf, token, strlen (token))) {
11357 if (match)
11358 return HLP_MATCH_AMBIGUOUS;
11359 match = i+1;
11360 }
11361 }
11362 return match;
11363 }
11364
11365
11366
11367 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11368 UNIT *uptr, int32 flag,
11369 const char *help, const char *cptr, va_list ap)
11370 {
11371 TOPIC top;
11372 TOPIC *topic = ⊤
11373 int failed;
11374 size_t match;
11375 size_t i;
11376 const char *p;
11377 t_bool flat_help = FALSE;
11378 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11379
11380 static const char attach_help[] = { " ATTACH" };
11381 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\r\n" };
11382 static const char onecmd_help[] = { "%s help.\r\n" };
11383 static const char help_help[] = {
11384
11385 " To see more HELP information, type the listed subtopic name. To move\r\n"
11386 " up a level, just type <CR>. To review the current subtopic, type \"?\".\r\n"
11387 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11388 };
11389
11390 (void)memset (&top, 0, sizeof(top));
11391 top.parent = ⊤
11392 if ((failed = setjmp (help_env)) != 0) {
11393 (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11394 "Error in block %u line %u: %s\r\n"
11395 "%s%*.*s%s\r\n",
11396 (int)help_where.block, (int)help_where.line, help_where.error,
11397 help_where.prox ? "Near '" : "",
11398 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11399 help_where.prox ? help_where.prox : "",
11400 help_where.prox ? "'" : "");
11401 cleanHelp (&top);
11402 return failed;
11403 }
11404
11405
11406
11407
11408
11409 if (dptr) {
11410 p = dptr->name;
11411 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11412 }
11413 else
11414 p = sim_name;
11415 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11416 if (!top.title)
11417 {
11418 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11419 __func__, __FILE__, __LINE__);
11420 #if defined(USE_BACKTRACE)
11421 # if defined(SIGUSR2)
11422 (void)raise(SIGUSR2);
11423
11424 # endif
11425 #endif
11426 abort();
11427 }
11428 for (i = 0; p[i]; i++ )
11429 top.title[i] = (char)toupper (p[i]);
11430 top.title[i] = '\0';
11431 if (flag & SCP_HELP_ATTACH)
11432 strcpy (top.title+i, attach_help);
11433
11434 top.label = (char *) malloc (sizeof ("1"));
11435 if (!top.label)
11436 {
11437 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11438 __func__, __FILE__, __LINE__);
11439 #if defined(USE_BACKTRACE)
11440 # if defined(SIGUSR2)
11441 (void)raise(SIGUSR2);
11442
11443 # endif
11444 #endif
11445 abort();
11446 }
11447 strcpy (top.label, "1");
11448
11449 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11450
11451 if (flat_help) {
11452 flag |= SCP_HELP_FLAT;
11453 if (sim_ttisatty())
11454 (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11455 else
11456 (void)fprintf (st, "%s help.\r\n", top.title);
11457 }
11458 else
11459 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11460
11461
11462
11463 (void) buildHelp (&top, dptr, uptr, help, ap);
11464
11465
11466
11467 while (cptr && *cptr) {
11468 cptr = get_glyph (cptr, gbuf, 0);
11469 if (!gbuf[0])
11470 break;
11471 if (!strcmp (gbuf, "HELP")) {
11472 (void)fprintf (st, "\r\n");
11473 fputs (help_help, st);
11474 break;
11475 }
11476 match = matchHelpTopicName (topic, gbuf);
11477 if (match == HLP_MATCH_WILDCARD) {
11478 if (dptr)
11479 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11480 cleanHelp (&top);
11481 return SCPE_OK;
11482 }
11483 if (match == HLP_MATCH_AMBIGUOUS) {
11484 (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11485 break;
11486 }
11487 if (match == HLP_MATCH_NONE) {
11488 (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11489 break;
11490 }
11491 topic = topic->children[match-1];
11492 }
11493 cptr = NULL;
11494
11495 if (flat_help) {
11496 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11497 cleanHelp (&top);
11498 return SCPE_OK;
11499 }
11500
11501
11502
11503 while (TRUE) {
11504 char *pstring;
11505 const char *prompt[2] = {"? ", "Subtopic? "};
11506
11507
11508
11509 if (topic->flags & HLP_MAGIC_TOPIC) {
11510 fputc ('\n', st);
11511 displayMagicTopic (st, dptr, topic);
11512 }
11513 else
11514 (void)fprintf (st, "\r\n%s\r\n", topic->title);
11515
11516
11517
11518
11519
11520 if (topic->text)
11521 fputs (topic->text, st);
11522
11523 if (topic->kids) {
11524 size_t w = 0;
11525 char *p;
11526 char tbuf[CBUFSIZE];
11527
11528 (void)fprintf (st, "\r\n Additional information available:\r\n\r\n");
11529 for (i = 0; i < topic->kids; i++) {
11530 strcpy (tbuf, topic->children[i]->title +
11531 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11532 for (p = tbuf; *p; p++) {
11533 if (blankch (*p))
11534 *p = '_';
11535 }
11536 w += 4 + topic->kidwid;
11537 if (w > 80) {
11538 w = 4 + topic->kidwid;
11539 fputc ('\r', st);
11540 fputc ('\n', st);
11541 }
11542 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11543 }
11544 (void)fprintf (st, "\r\n\r\n");
11545 if (flag & SCP_HELP_ONECMD) {
11546 pstring = helpPrompt (topic, "", TRUE);
11547 (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11548 FREE (pstring);
11549 break;
11550 }
11551 }
11552
11553 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11554 break;
11555
11556 reprompt:
11557 if (NULL == cptr || !*cptr) {
11558 if (topic->kids == 0)
11559 topic = topic->parent;
11560 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11561
11562 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11563 FREE (pstring);
11564 if ((cptr != NULL) &&
11565 ((0 == strcmp (cptr, "\x04")) ||
11566 (0 == strcmp (cptr, "\x1A"))))
11567 cptr = NULL;
11568 }
11569
11570 if (NULL == cptr)
11571 break;
11572
11573 cptr = get_glyph (cptr, gbuf, 0);
11574 if (!strcmp (gbuf, "*")) {
11575 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11576 gbuf[0] = '\0';
11577 }
11578 if (!gbuf[0]) {
11579 if (topic->level == 0)
11580 break;
11581 topic = topic->parent;
11582 continue;
11583 }
11584 if (!strcmp (gbuf, "?"))
11585 continue;
11586 if (!strcmp (gbuf, "HELP")) {
11587 fputs (help_help, st);
11588 goto reprompt;
11589 }
11590 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11591 break;
11592
11593
11594
11595 if (!topic->kids) {
11596 (void)fprintf (st, "No additional help at this level.\r\n");
11597 cptr = NULL;
11598 goto reprompt;
11599 }
11600 match = matchHelpTopicName (topic, gbuf);
11601 if (match == HLP_MATCH_AMBIGUOUS) {
11602 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11603 cptr = NULL;
11604 goto reprompt;
11605 }
11606
11607 if (match == HLP_MATCH_NONE) {
11608 (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11609 cptr = NULL;
11610 goto reprompt;
11611 }
11612
11613
11614 topic = topic->children[match-1];
11615 }
11616
11617
11618
11619 cleanHelp (&top);
11620
11621 return SCPE_OK;
11622 }
11623
11624
11625
11626 t_stat scp_help (FILE *st, DEVICE *dptr,
11627 UNIT *uptr, int32 flag,
11628 const char *help, const char *cptr, ...)
11629 {
11630 t_stat r;
11631 va_list ap;
11632
11633 va_start (ap, cptr);
11634 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11635 va_end (ap);
11636
11637 return r;
11638 }
11639
11640 #if defined(_MSC_VER)
11641 # pragma warning(pop)
11642 #endif