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 = NULL, *cptr2 = NULL;
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 (void)memset (nbuf, 0, sizeof(nbuf));
1695 (void)memset (cbuf, 0, sizeof(cbuf));
1696
1697
1698 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1699 uid_t real_uid = getuid();
1700 uid_t eff_uid = geteuid();
1701 if (0 == eff_uid && 0 != real_uid) {
1702 (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1703 exit(EXIT_FAILURE);
1704 }
1705 # endif
1706
1707 sunos_obtain_realtime_privileges();
1708
1709 sim_free_memory = sim_memory_available();
1710
1711 sim_appfilename = _sir_getappfilename();
1712 if (sim_appfilename == NULL) {
1713 sim_appfilename = "dps8";
1714 }
1715
1716
1717
1718 sirinit si;
1719 if (!sir_makeinit(&si))
1720 return dps8_sir_report_error();
1721
1722
1723 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1724
1725
1726 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1727
1728
1729 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1730
1731
1732 si.d_stderr.opts = SIRO_NOHOST;
1733
1734
1735 si.d_syslog.levels = SIRL_NONE;
1736
1737
1738 si.d_syslog.opts = SIRO_DEFAULT;
1739
1740
1741 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1742
1743
1744 if (!sir_init(&si))
1745 return dps8_sir_report_error();
1746
1747 # if defined(_AIX)
1748 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1749 if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1750 (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1751 __func__, __FILE__, __LINE__);
1752 abort();
1753 }
1754
1755 if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1756 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1757 }
1758
1759 if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1760 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1761 }
1762
1763 if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1764 (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1765 }
1766
1767 # if !defined(__PASE__)
1768 if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1769 (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1770 }
1771 # else
1772 # if !defined(TESTING)
1773 if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1774 (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1775 }
1776 # endif
1777 # endif
1778
1779 if (execvp(argv[0], argv) == -1) {
1780 (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1781 __func__, __FILE__, __LINE__);
1782 abort();
1783 }
1784 }
1785 # endif
1786
1787 # if defined(USE_BACKTRACE)
1788 # if defined(BACKTRACE_SUPPORTED)
1789 # if defined(_INC_BACKTRACE_FUNC)
1790 bt_pid = (long)_sir_getpid();
1791 (void)bt_pid;
1792 # endif
1793 # endif
1794 # endif
1795
1796 # if defined(__MINGW32__)
1797 # undef IS_WINDOWS
1798 # define IS_WINDOWS 1
1799 # if !defined(NEED_CONSOLE_SETUP)
1800 # define NEED_CONSOLE_SETUP
1801 # endif
1802 # endif
1803
1804 # if defined(CROSS_MINGW32)
1805 # undef IS_WINDOWS
1806 # define IS_WINDOWS 1
1807 # if !defined(NEED_CONSOLE_SETUP)
1808 # define NEED_CONSOLE_SETUP
1809 # endif
1810 # endif
1811
1812 # if defined(__MINGW64__)
1813 # undef IS_WINDOWS
1814 # define IS_WINDOWS 1
1815 # if !defined(NEED_CONSOLE_SETUP)
1816 # define NEED_CONSOLE_SETUP
1817 # endif
1818 # endif
1819
1820 # if defined(CROSS_MINGW64)
1821 # undef IS_WINDOWS
1822 # define IS_WINDOWS 1
1823 # if !defined(NEED_CONSOLE_SETUP)
1824 # define NEED_CONSOLE_SETUP
1825 # endif
1826 # endif
1827
1828 # if defined(__CYGWIN__)
1829 # if defined(IS_WINDOWS)
1830 # undef IS_WINDOWS
1831 # endif
1832 # endif
1833
1834 # if defined(USE_DUMA)
1835 # if defined(DUMA_EXPLICIT_INIT)
1836 duma_init();
1837 (void)fflush(stderr);
1838 # endif
1839 # if defined(DUMA_MIN_ALIGNMENT)
1840 # if DUMA_MIN_ALIGNMENT > 0
1841 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1842 # endif
1843 # endif
1844 DUMA_SET_FILL(0x2E);
1845 (void)fflush(stderr);
1846 (void)atexit(CleanDUMA);
1847 # endif
1848
1849 # if defined(USE_BACKTRACE)
1850 # if defined(BACKTRACE_SUPPORTED)
1851 # include "backtrace_main.c"
1852 # endif
1853 # endif
1854
1855 # if !defined(NO_LOCALE)
1856 (void)setlocale(LC_ALL, "");
1857 # endif
1858
1859 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1860 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1861 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1862 # endif
1863 # endif
1864
1865 # if defined(NEED_CONSOLE_SETUP)
1866 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1867 if (handle != INVALID_HANDLE_VALUE)
1868 {
1869 DWORD mode = 0;
1870 if (GetConsoleMode(handle, &mode))
1871 {
1872 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1873 SetConsoleMode(handle, mode);
1874 }
1875 }
1876 puts ("\e[0m");
1877 # endif
1878
1879 # if defined(__HAIKU__)
1880 (void)disable_debugger(1);
1881 # endif
1882
1883 running_perf_test = false;
1884
1885
1886 char thread_name[SIR_MAXPID] = {0};
1887 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1888 (void)_sir_setthreadname(thread_name);
1889
1890
1891
1892 # if defined(__clang_analyzer__)
1893 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1894 return 1;
1895 # endif
1896
1897 if (argc == 0) {
1898 (void)fprintf (stderr, "Error: main() called directly!\r\n");
1899 return 1;
1900 }
1901
1902
1903 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1904 allowCores();
1905 # endif
1906
1907 int testEndian = decContextTestEndian();
1908 if (testEndian != 0) {
1909 if (testEndian == 1) {
1910 (void)fprintf (stderr,
1911 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1912 return 1;
1913 }
1914 if (testEndian == -1) {
1915 (void)fprintf (stderr,
1916 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1917 return 1;
1918 }
1919 (void)fprintf (stderr,
1920 "Error: Unable to determine system byte order; aborting.\r\n");
1921 return 1;
1922 }
1923 # if defined(NEED_128)
1924 test_math128();
1925 # endif
1926
1927 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1928
1929 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1930
1931
1932
1933
1934 nprocs = (unsigned int)uv_available_parallelism();
1935 # else
1936 nprocs = (unsigned int)_sir_nprocs();
1937 # endif
1938
1939 # if defined(FORCE_STATIC)
1940 ncores = 0;
1941 # else
1942 ncores = (unsigned int)get_core_count();
1943 # endif
1944
1945
1946 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1947 if (!targv)
1948 {
1949 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1950 __func__, __FILE__, __LINE__);
1951 # if defined(USE_BACKTRACE)
1952 # if defined(SIGUSR2)
1953 (void)raise(SIGUSR2);
1954
1955 # endif
1956 # endif
1957 abort();
1958 }
1959 for (i=0; i<argc; i++)
1960 targv[i] = argv[i];
1961 argv = targv;
1962
1963
1964 set_prompt (0, "sim>");
1965 *cbuf = 0;
1966 sim_switches = 0;
1967 lookswitch = TRUE;
1968 stdnul = fopen(NULL_DEVICE,"wb");
1969
1970
1971 for (i = 1; i < argc; i++) {
1972 if (argv[i] == NULL)
1973 continue;
1974
1975 # if defined(THREADZ) || defined(LOCKLESS)
1976
1977 int perftestflag = strcmp(argv[i], "--perftest");
1978 if (perftestflag == 0) {
1979 char * testName = NULL;
1980 if (i + 1 < argc)
1981 testName = argv[i + 1];
1982 perfTest (testName);
1983 return 0;
1984 }
1985 # endif
1986
1987
1988 int onlyvers = strcmp(argv[i], "--version");
1989 if (onlyvers == 0) {
1990 # if defined(VER_H_GIT_VERSION)
1991 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1992 # if VER_H_GIT_PATCH_INT < 1
1993 (void)fprintf (stdout, "%s simulator %s\r\n",
1994 sim_name, VER_H_GIT_VERSION);
1995 # else
1996 (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1997 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1998 # endif
1999 # else
2000 (void)fprintf (stdout, "%s simulator %s\r\n",
2001 sim_name, VER_H_GIT_VERSION);
2002 # endif
2003 # else
2004 (void)fprintf (stdout, "%s simulator\r\n", sim_name);
2005 # endif
2006 FREE (targv);
2007 return 0;
2008 }
2009
2010
2011 int longhelp = strcmp(argv[i], "--help");
2012 int shorthelp = strcmp(argv[i], "-h");
2013 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2014 if (longhelp == 0 || shorthelp == 0) {
2015 # if defined(VER_H_GIT_VERSION)
2016 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2017 # if VER_H_GIT_PATCH_INT < 1
2018 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2019 # else
2020 (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2021 # endif
2022 # else
2023 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2024 # endif
2025 # else
2026 (void)fprintf (stdout, "%s simulator", sim_name);
2027 # endif
2028 (void)fprintf (stdout, "\r\n");
2029 (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2030 (void)fprintf (stdout, "\r\n");
2031 (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2032 (void)fprintf (stdout, "\r\n");
2033 (void)fprintf (stdout, "\r\n Switches:");
2034 (void)fprintf (stdout, "\r\n -e, -E Aborts script processing immediately upon any error");
2035 (void)fprintf (stdout, "\r\n -h, -H, --help Prints only this informational help text and exits");
2036 (void)fprintf (stdout, "\r\n -k, -K Disables all support for exclusive file locking");
2037 (void)fprintf (stdout, "\r\n -l, -L Reports but ignores all exclusive file locking errors");
2038 (void)fprintf (stdout, "\r\n -o, -O Makes scripting ON conditions and actions inheritable");
2039 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2040 (void)fprintf (stdout, "\r\n -p, -P Enables real-time scheduling (may require privileges)");
2041 # endif
2042 (void)fprintf (stdout, "\r\n -q, -Q Disables printing of non-fatal informational messages");
2043 (void)fprintf (stdout, "\r\n -r, -R Enables an unlinked ephemeral system state file");
2044 (void)fprintf (stdout, "\r\n -s, -S Enables a randomized persistent system state file");
2045 (void)fprintf (stdout, "\r\n -t, -T Disables fsync and creation/usage of system state file");
2046 (void)fprintf (stdout, "\r\n -v, -V Prints commands read from script file before execution");
2047 (void)fprintf (stdout, "\r\n --version Prints only the simulator identification text and exits");
2048 (void)fprintf (stdout, "\r\n");
2049 # if defined(USE_DUMA)
2050 nodist++;
2051 # endif
2052 if (!nodist) {
2053 (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2054 (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2055 (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2056 }
2057 else
2058 {
2059 (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2060 }
2061 (void)fprintf (stdout, "\r\n");
2062 FREE(argv);
2063 return 0;
2064 }
2065
2066 if ((*argv[i] == '-') && lookswitch) {
2067 if ((sw = get_switches (argv[i])) < 0) {
2068 (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2069 FREE(argv);
2070 return 1;
2071 }
2072 sim_switches = sim_switches | sw;
2073 }
2074
2075 else {
2076 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2077 (void)fprintf (stderr, "Argument string too long\r\n");
2078 FREE(argv);
2079 return 1;
2080 }
2081 if (*cbuf)
2082 strcat (cbuf, " ");
2083 (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s",
2084 strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
2085 lookswitch = FALSE;
2086 }
2087 }
2088 sim_nolock = sim_switches & SWMASK ('K');
2089 sim_iglock = sim_switches & SWMASK ('L');
2090 sim_randompst = sim_switches & SWMASK ('S');
2091 sim_quiet = sim_switches & SWMASK ('Q');
2092 sim_randstate = sim_switches & SWMASK ('R');
2093 if (sim_randompst) sim_randstate = 1;
2094 sim_nostate = sim_switches & SWMASK ('T');
2095 if (sim_nostate)
2096 {
2097 sim_randompst = 0;
2098 sim_randstate = 0;
2099 }
2100 sim_on_inherit = sim_switches & SWMASK ('O');
2101
2102 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2103 !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2104 sim_realtime = sim_switches & SWMASK ('P');
2105 # endif
2106
2107 sim_init_sock ();
2108 if (sim_dflt_dev == NULL)
2109 sim_dflt_dev = sim_devices[0];
2110 if (sim_vm_init != NULL)
2111 (*sim_vm_init)();
2112 sim_finit ();
2113 for (i = 0; cmd_table[i].name; i++) {
2114 size_t alias_len = strlen (cmd_table[i].name);
2115 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2116 if (!cmd_name)
2117 {
2118 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2119 __func__, __FILE__, __LINE__);
2120 # if defined(USE_BACKTRACE)
2121 # if defined(SIGUSR2)
2122 (void)raise(SIGUSR2);
2123
2124 # endif
2125 # endif
2126 abort();
2127 }
2128
2129 strcpy (cmd_name, cmd_table[i].name);
2130 while (alias_len > 1) {
2131 cmd_name[alias_len] = '\0';
2132 --alias_len;
2133 if (getenv (cmd_name))
2134 unsetenv (cmd_name);
2135 }
2136 FREE (cmd_name);
2137 }
2138 stop_cpu = 0;
2139 sim_interval = 0;
2140 sim_time = sim_rtime = 0;
2141 noqueue_time = 0;
2142 sim_clock_queue = QUEUE_LIST_END;
2143 sim_is_running = 0;
2144 sim_log = NULL;
2145 if (sim_emax <= 0)
2146 sim_emax = 1;
2147
2148
2149 main_thread_id = pthread_self();
2150
2151
2152 save_thread_sched(pthread_self());
2153
2154
2155 if (sim_realtime) {
2156 if (nprocs < 2) {
2157 sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2158 exit(EXIT_FAILURE);
2159 } else {
2160 watchdog_startup();
2161 }
2162 }
2163
2164
2165 if (realtime_ok) {
2166 set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2167 check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2168 } else {
2169 # if !defined(__QNX__)
2170 (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2171 # endif
2172 }
2173
2174 sim_timer_init ();
2175
2176 if ((stat = sim_ttinit ()) != SCPE_OK) {
2177 (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2178 sim_error_text (stat));
2179 FREE(argv);
2180 return 1;
2181 }
2182 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2183 (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2184 FREE(argv);
2185 return 1;
2186 };
2187 if ((stat = reset_all_p (0)) != SCPE_OK) {
2188 (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2189 sim_error_text (stat));
2190 FREE(argv);
2191 return 1;
2192 }
2193 if ((stat = sim_brk_init ()) != SCPE_OK) {
2194 (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2195 sim_error_text (stat));
2196 FREE(argv);
2197 return 1;
2198 }
2199 if (!sim_quiet) {
2200 (void)printf ("\r\n");
2201 show_version (stdout, NULL, NULL, 0, NULL);
2202 }
2203
2204 cptr = getenv("HOME");
2205 if (cptr == NULL) {
2206 cptr = getenv("HOMEPATH");
2207 cptr2 = getenv("HOMEDRIVE");
2208 }
2209 else
2210 cptr2 = NULL;
2211 (void)cptr2;
2212 if ( (*cbuf) && (strcmp(cbuf, "")) )
2213 stat = do_cmd (0, cbuf);
2214 else if (*argv[0]) {
2215 char *np;
2216 nbuf[0] = '"';
2217 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
2218 if (stat == SCPE_OPENERR) {
2219 np = strrchr (nbuf, '/');
2220 if (np == NULL)
2221 np = strrchr (nbuf, '\\');
2222 if (np != NULL) {
2223 *np = '"';
2224 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
2225 }
2226 }
2227 }
2228
2229 argv = uv_setup_args(argc, argv);
2230
2231
2232 if (getenv("DPS8M_NO_HINTS") == NULL)
2233 if (!sim_quiet && 0 == strcmp(cbuf, ""))
2234 (void)show_hints(0, 0, 0, 1, 0);
2235
2236 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2237
2238 if (sim_vm_exit != NULL)
2239 (*sim_vm_exit)();
2240
2241 detach_all (0, TRUE);
2242 sim_set_deboff (0, NULL);
2243 sim_set_logoff (0, NULL);
2244 sim_set_notelnet (0, NULL);
2245 sim_ttclose ();
2246 sim_cleanup_sock ();
2247 fclose (stdnul);
2248 FREE (targv);
2249 FREE (sim_prompt);
2250 FREE (sim_eval);
2251 FREE (sim_internal_devices);
2252 FREE (sim_brk_tab);
2253 FREE (sim_staba.comp);
2254 FREE (sim_staba.mask);
2255 FREE (sim_stabr.comp);
2256 FREE (sim_stabr.mask);
2257 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2258 }
2259 #endif
2260
2261 t_stat process_stdin_commands (t_stat stat, char *argv[])
2262 {
2263 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2264 CONST char *cptr;
2265 t_stat stat_nomessage;
2266 CTAB *cmdp = NULL;
2267
2268 (void)memset (gbuf, 0, sizeof(gbuf));
2269 (void)memset (cbuf, 0, sizeof(cbuf));
2270
2271 stat = SCPE_BARE_STATUS(stat);
2272 while (stat != SCPE_EXIT) {
2273 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
2274 (void)printf ("%s%s\r\n", sim_prompt, cptr);
2275 else if (sim_vm_read != NULL) {
2276 (void)printf ("%s", sim_prompt);
2277 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2278 }
2279 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
2280 if (cptr == NULL) {
2281 if (sim_ttisatty()) continue;
2282 else break;
2283 }
2284 if (*cptr == 0)
2285 continue;
2286 sim_sub_args (cbuf, sizeof(cbuf), argv);
2287 if (sim_log)
2288 (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2289 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2290 (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2291 cptr = get_glyph_cmd (cptr, gbuf);
2292 sim_switches = 0;
2293 if ((cmdp = find_cmd (gbuf)))
2294 stat = cmdp->action (cmdp->arg, cptr);
2295 else
2296 stat = SCPE_UNK;
2297 stat_nomessage = stat & SCPE_NOMESSAGE;
2298 stat_nomessage = stat_nomessage || (!sim_show_message);
2299 stat = SCPE_BARE_STATUS(stat);
2300 sim_last_cmd_stat = stat;
2301 if (!stat_nomessage) {
2302 if (cmdp && (cmdp->message))
2303 cmdp->message (NULL, stat);
2304 else
2305 if (stat >= SCPE_BASE)
2306 sim_printf ("%s\r\n", sim_error_text (stat));
2307 }
2308 if (sim_vm_post != NULL)
2309 (*sim_vm_post) (TRUE);
2310 }
2311 return stat;
2312 }
2313
2314
2315
2316 t_stat set_prompt (int32 flag, CONST char *cptr)
2317 {
2318 char gbuf[CBUFSIZE], *gptr;
2319
2320 if ((NULL == cptr) || (*cptr == '\0'))
2321 return SCPE_ARG;
2322
2323 cptr = get_glyph_nc (cptr, gbuf, '"');
2324 if (gbuf[0] == '\0') {
2325 gbuf[sizeof (gbuf)-1] = '\0';
2326 strncpy (gbuf, cptr, sizeof (gbuf)-1);
2327 gptr = strchr (gbuf, '"');
2328 if (NULL != gptr)
2329 *gptr = '\0';
2330 }
2331 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
2332 if (!sim_prompt)
2333 {
2334 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2335 __func__, __FILE__, __LINE__);
2336 #if defined(USE_BACKTRACE)
2337 # if defined(SIGUSR2)
2338 (void)raise(SIGUSR2);
2339
2340 # endif
2341 #endif
2342 abort();
2343 }
2344 (void)sprintf (sim_prompt, "%s ", gbuf);
2345 return SCPE_OK;
2346 }
2347
2348
2349
2350 CTAB *find_cmd (const char *gbuf)
2351 {
2352 CTAB *cmdp = NULL;
2353
2354 if (sim_vm_cmd)
2355 cmdp = find_ctab (sim_vm_cmd, gbuf);
2356 if (cmdp == NULL)
2357 cmdp = find_ctab (cmd_table, gbuf);
2358 return cmdp;
2359 }
2360
2361
2362
2363 t_stat exit_cmd (int32 flag, CONST char *cptr)
2364 {
2365 return SCPE_EXIT;
2366 }
2367
2368
2369
2370
2371 static int _cmd_name_compare (const void *pa, const void *pb)
2372 {
2373 CTAB * const *a = (CTAB * const *)pa;
2374 CTAB * const *b = (CTAB * const *)pb;
2375
2376 return strcmp((*a)->name, (*b)->name);
2377 }
2378
2379 void fprint_help (FILE *st)
2380 {
2381 CTAB *cmdp;
2382 CTAB **hlp_cmdp = NULL;
2383 size_t cmd_cnt = 0;
2384 size_t cmd_size = 0;
2385 size_t max_cmdname_size = 0;
2386 size_t i, line_offset;
2387
2388 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2389 if (cmdp->help) {
2390 if (cmd_cnt >= cmd_size) {
2391 cmd_size += 20;
2392 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2393 if (!hlp_cmdp)
2394 {
2395 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2396 __func__, __FILE__, __LINE__);
2397 #if defined(USE_BACKTRACE)
2398 # if defined(SIGUSR2)
2399 (void)raise(SIGUSR2);
2400
2401 # endif
2402 #endif
2403 abort();
2404 }
2405 }
2406 hlp_cmdp[cmd_cnt] = cmdp;
2407 ++cmd_cnt;
2408 if (strlen(cmdp->name) > max_cmdname_size)
2409 max_cmdname_size = strlen(cmdp->name);
2410 }
2411 }
2412 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2413 if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2414 if (cmd_cnt >= cmd_size) {
2415 cmd_size += 20;
2416 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2417 if (!hlp_cmdp)
2418 {
2419 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2420 __func__, __FILE__, __LINE__);
2421 #if defined(USE_BACKTRACE)
2422 # if defined(SIGUSR2)
2423 (void)raise(SIGUSR2);
2424
2425 # endif
2426 #endif
2427 abort();
2428 }
2429 }
2430 hlp_cmdp[cmd_cnt] = cmdp;
2431 ++cmd_cnt;
2432 if (strlen (cmdp->name) > max_cmdname_size)
2433 max_cmdname_size = strlen(cmdp->name);
2434 }
2435 }
2436 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n ");
2437 if (hlp_cmdp)
2438 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2439 line_offset = 4;
2440 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2441 fputs (hlp_cmdp[i]->name, st);
2442 line_offset += 5 + max_cmdname_size;
2443 if (line_offset + max_cmdname_size > 79) {
2444 line_offset = 4;
2445 (void)fprintf (st, "\r\n ");
2446 }
2447 else
2448 (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2449 }
2450 FREE (hlp_cmdp);
2451 (void)fprintf (st, "\r\n");
2452 return;
2453 }
2454
2455 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2456 {
2457 if (!*pdone)
2458 (void)fprintf (st, "%s", context);
2459 *pdone = TRUE;
2460 }
2461
2462 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2463 {
2464 REG *rptr, *trptr;
2465 t_bool found = FALSE;
2466 t_bool all_unique = TRUE;
2467 size_t max_namelen = 0;
2468 DEVICE *tdptr;
2469 CONST char *tptr;
2470 char *namebuf;
2471 char rangebuf[32];
2472
2473 if (dptr->registers)
2474 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2475 if (rptr->flags & REG_HIDDEN)
2476 continue;
2477 if (rptr->depth > 1)
2478 (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2479 else
2480 strcpy (rangebuf, "");
2481 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2482 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2483 found = TRUE;
2484 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2485 if ((trptr == NULL) || (tdptr != dptr))
2486 all_unique = FALSE;
2487 }
2488 if (!found) {
2489 if (!silent)
2490 (void)fprintf (st, "No register HELP available for the %s device\r\n",
2491 dptr->name);
2492 }
2493 else {
2494 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2495 if (!namebuf)
2496 {
2497 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2498 __func__, __FILE__, __LINE__);
2499 #if defined(USE_BACKTRACE)
2500 # if defined(SIGUSR2)
2501 (void)raise(SIGUSR2);
2502
2503 # endif
2504 #endif
2505 abort();
2506 }
2507 (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2508 dptr->name);
2509 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2510 if (rptr->flags & REG_HIDDEN)
2511 continue;
2512 if (rptr->depth <= 1)
2513 (void)sprintf (namebuf, "%*s",
2514 -((int)max_namelen),
2515 rptr->name);
2516 else {
2517 (void)sprintf (rangebuf, "[%d:%d]",
2518 0,
2519 rptr->depth-1);
2520 (void)sprintf (namebuf, "%s%*s",
2521 rptr->name,
2522 (int)(strlen(rptr->name))-((int)max_namelen),
2523 rangebuf);
2524 }
2525 if (all_unique) {
2526 (void)fprintf (st, " %s %4d %s\r\n",
2527 namebuf,
2528 rptr->width,
2529 rptr->desc ? rptr->desc : "");
2530 continue;
2531 }
2532 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2533 if ((trptr == NULL) || (tdptr != dptr))
2534 (void)fprintf (st, " %s %s %4d %s\r\n",
2535 dptr->name,
2536 namebuf,
2537 rptr->width,
2538 rptr->desc ? rptr->desc : "");
2539 else
2540 (void)fprintf (st, " %*s %s %4d %s\r\n",
2541 (int)strlen(dptr->name), "",
2542 namebuf,
2543 rptr->width,
2544 rptr->desc ? rptr->desc : "");
2545 }
2546 FREE (namebuf);
2547 }
2548 }
2549
2550 void fprint_reg_help (FILE *st, DEVICE *dptr)
2551 {
2552 fprint_reg_help_ex (st, dptr, TRUE);
2553 }
2554
2555 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2556 {
2557 if (dptr->attach_help) {
2558 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2559 dptr->attach_help (st, dptr, NULL, 0, NULL);
2560 return;
2561 }
2562 if (DEV_TYPE(dptr) == DEV_DISK) {
2563 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2564 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2565 return;
2566 }
2567 if (DEV_TYPE(dptr) == DEV_TAPE) {
2568 (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2569 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2570 return;
2571 }
2572 if (!silent) {
2573 (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2574 if (dptr->help)
2575 dptr->help (st, dptr, NULL, 0, NULL);
2576 }
2577 }
2578
2579 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2580 {
2581 MTAB *mptr;
2582 DEBTAB *dep;
2583 t_bool found = FALSE;
2584 char buf[CBUFSIZE], header[CBUFSIZE];
2585 uint32 enabled_units = dptr->numunits;
2586 uint32 unit;
2587
2588 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2589 for (unit=0; unit < dptr->numunits; unit++)
2590 if (dptr->units[unit].flags & UNIT_DIS)
2591 --enabled_units;
2592 if (dptr->modifiers) {
2593 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2594 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2595 continue;
2596 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2597 continue;
2598 if (mptr->mstring) {
2599 fprint_header (st, &found, header);
2600 (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2601 mptr->mstring,
2602 (strchr(mptr->mstring, '=')) \
2603 ? "" : (MODMASK(mptr,MTAB_VALR) \
2604 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2605 ? "{=val}" : "")));
2606 if ((strlen (buf) < 30) || (NULL == mptr->help))
2607 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2608 else
2609 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2610 }
2611 }
2612 }
2613 if (dptr->flags & DEV_DISABLE) {
2614 fprint_header (st, &found, header);
2615 (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2616 (void)fprintf (st, "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2617 (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2618 (void)fprintf (st, "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2619 }
2620 if (dptr->flags & DEV_DEBUG) {
2621 fprint_header (st, &found, header);
2622 (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2623 (void)fprintf (st, "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2624 (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2625 (void)fprintf (st, "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2626 if (dptr->debflags) {
2627 t_bool desc_available = FALSE;
2628 strcpy (buf, "");
2629 (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2630 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2631 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2632 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2633 }
2634 (void)fprintf (st, "\r\n");
2635 (void)fprintf (st, "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2636 (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2637 for (dep = dptr->debflags; dep->name != NULL; dep++)
2638 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2639 (void)fprintf (st, "\r\n");
2640 (void)fprintf (st, "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2641 if (desc_available) {
2642 (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2643 for (dep = dptr->debflags; dep->name != NULL; dep++)
2644 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2645 }
2646 }
2647 }
2648 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2649 if (dptr->units->flags & UNIT_DISABLE) {
2650 fprint_header (st, &found, header);
2651 (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2652 (void)fprintf (st, "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2653 (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2654 (void)fprintf (st, "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2655 }
2656 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2657 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2658 continue;
2659 if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2660 continue;
2661 if (mptr->mstring) {
2662 fprint_header (st, &found, header);
2663 (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2664 (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2665 (strchr(mptr->mstring, '=')) \
2666 ? "" : (MODMASK(mptr,MTAB_VALR) \
2667 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2668 ? "{=val}" : "")));
2669 (void)fprintf (st, "%-30s\t%s\r\n", buf,
2670 (strchr(mptr->mstring, '=')) \
2671 ? "" : (mptr->help ? mptr->help : ""));
2672 }
2673 }
2674 }
2675 if (!found && !silent)
2676 (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2677 }
2678
2679 void fprint_set_help (FILE *st, DEVICE *dptr)
2680 {
2681 fprint_set_help_ex (st, dptr, TRUE);
2682 }
2683
2684 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2685 {
2686 MTAB *mptr;
2687 t_bool found = FALSE;
2688 char buf[CBUFSIZE], header[CBUFSIZE];
2689 uint32 enabled_units = dptr->numunits;
2690 uint32 unit;
2691
2692 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2693 for (unit=0; unit < dptr->numunits; unit++)
2694 if (dptr->units[unit].flags & UNIT_DIS)
2695 --enabled_units;
2696 if (dptr->modifiers) {
2697 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2698 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2699 continue;
2700 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2701 continue;
2702 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2703 continue;
2704 fprint_header (st, &found, header);
2705 (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2706 mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2707 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2708 }
2709 }
2710 if (dptr->flags & DEV_DEBUG) {
2711 fprint_header (st, &found, header);
2712 (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2713 (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2714 }
2715 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2716 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2717 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2718 continue;
2719 if ((!mptr->disp) || (!mptr->pstring))
2720 continue;
2721 fprint_header (st, &found, header);
2722 (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2723 (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2724 MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2725 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2726 }
2727 }
2728 if (!found && !silent)
2729 (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2730 }
2731
2732 void fprint_show_help (FILE *st, DEVICE *dptr)
2733 {
2734 fprint_show_help_ex (st, dptr, TRUE);
2735 }
2736
2737 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2738 {
2739 BRKTYPTAB *brkt = dptr->brk_types;
2740 char gbuf[CBUFSIZE];
2741
2742 if (sim_brk_types == 0) {
2743 if ((dptr != sim_dflt_dev) && (!silent)) {
2744 (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2745 if (dptr->help)
2746 dptr->help (st, dptr, NULL, 0, NULL);
2747 }
2748 return;
2749 }
2750 if (brkt == NULL) {
2751 int i;
2752
2753 if (dptr == sim_dflt_dev) {
2754 if (sim_brk_types & ~sim_brk_dflt) {
2755 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2756 for (i=0; i<26; i++) {
2757 if (sim_brk_types & (1<<i))
2758 (void)fprintf (st, " -%c\r\n", 'A'+i);
2759 }
2760 }
2761 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2762 }
2763 return;
2764 }
2765 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2766 while (brkt->btyp) {
2767 (void)fprintf (st, " %s %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2768 ++brkt;
2769 }
2770 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2771 }
2772
2773 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2774 {
2775 char gbuf[CBUFSIZE];
2776 CTAB *cmdp;
2777
2778 if (*cptr) {
2779 (void)get_glyph (cptr, gbuf, 0);
2780 if ((cmdp = find_cmd (gbuf))) {
2781 if (cmdp->action == &exdep_cmd) {
2782 if (dptr->help)
2783 return dptr->help (st, dptr, uptr, flag, cptr);
2784 else
2785 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2786 return SCPE_OK;
2787 }
2788 if (cmdp->action == &set_cmd) {
2789 fprint_set_help_ex (st, dptr, FALSE);
2790 return SCPE_OK;
2791 }
2792 if (cmdp->action == &show_cmd) {
2793 fprint_show_help_ex (st, dptr, FALSE);
2794 return SCPE_OK;
2795 }
2796 if (cmdp->action == &attach_cmd) {
2797 fprint_attach_help_ex (st, dptr, FALSE);
2798 return SCPE_OK;
2799 }
2800 if (cmdp->action == &brk_cmd) {
2801 fprint_brk_help_ex (st, dptr, FALSE);
2802 return SCPE_OK;
2803 }
2804 if (dptr->help)
2805 return dptr->help (st, dptr, uptr, flag, cptr);
2806 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2807 return SCPE_OK;
2808 }
2809 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2810 fprint_reg_help_ex (st, dptr, FALSE);
2811 return SCPE_OK;
2812 }
2813 if (dptr->help)
2814 return dptr->help (st, dptr, uptr, flag, cptr);
2815 (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2816 return SCPE_OK;
2817 }
2818 if (dptr->help) {
2819 return dptr->help (st, dptr, uptr, flag, cptr);
2820 }
2821 if (dptr->description)
2822 (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2823 else
2824 (void)fprintf (st, "%s HELP\r\n", dptr->name);
2825 fprint_set_help_ex (st, dptr, TRUE);
2826 fprint_show_help_ex (st, dptr, TRUE);
2827 fprint_attach_help_ex (st, dptr, TRUE);
2828 fprint_reg_help_ex (st, dptr, TRUE);
2829 fprint_brk_help_ex (st, dptr, TRUE);
2830 return SCPE_OK;
2831 }
2832
2833 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2834 {
2835 switch (help[0]) {
2836 case '*':
2837 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2838 if (sim_log)
2839 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2840 break;
2841 default:
2842 fputs (help, stdout);
2843 if (sim_log)
2844 fputs (help, sim_log);
2845 break;
2846 }
2847 return SCPE_OK;
2848 }
2849
2850 t_stat help_cmd (int32 flag, CONST char *cptr)
2851 {
2852 char gbuf[CBUFSIZE];
2853 CTAB *cmdp;
2854
2855 GET_SWITCHES (cptr);
2856 if (sim_switches & SWMASK ('F'))
2857 flag = flag | SCP_HELP_FLAT;
2858 if (*cptr) {
2859 cptr = get_glyph (cptr, gbuf, 0);
2860 if ((cmdp = find_cmd (gbuf))) {
2861 if (*cptr) {
2862 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2863 DEVICE *dptr;
2864 UNIT *uptr;
2865 t_stat r;
2866 cptr = get_glyph (cptr, gbuf, 0);
2867 dptr = find_unit (gbuf, &uptr);
2868 if (dptr == NULL)
2869 dptr = find_dev (gbuf);
2870 if (dptr != NULL) {
2871 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2872 if (sim_log)
2873 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2874 return r;
2875 }
2876 if (cmdp->action == &set_cmd) {
2877
2878 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2879 (cmdp->help))
2880 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2881 }
2882 else {
2883 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2884 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2885 return SCPE_ARG;
2886 return help_cmd_output (flag, shptr->help, NULL);
2887 }
2888 return SCPE_ARG;
2889 }
2890 else
2891 return SCPE_2MARG;
2892 }
2893 if (cmdp->help) {
2894 if (strcmp (cmdp->name, "HELP") == 0) {
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
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929 }
2930 else {
2931 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2932 sim_dflt_dev && sim_dflt_dev->help) {
2933 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2934 if (sim_log)
2935 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2936 }
2937 }
2938 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2939 }
2940 else {
2941 CTAB *cmdpa;
2942 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2943 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2944 sim_printf ("%s is an alias for the %s command:\r\n%s",
2945 cmdp->name, cmdpa->name, cmdpa->help);
2946 break;
2947 }
2948 if (cmdpa->name == NULL)
2949 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2950 }
2951 }
2952 else {
2953 DEVICE *dptr;
2954 UNIT *uptr;
2955 t_stat r;
2956 dptr = find_unit (gbuf, &uptr);
2957 if (dptr == NULL) {
2958 dptr = find_dev (gbuf);
2959 if (dptr == NULL)
2960 return SCPE_ARG;
2961 if (dptr->flags & DEV_DIS)
2962 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2963 }
2964 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2965 if (sim_log)
2966 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2967 return r;
2968 }
2969 }
2970 else {
2971 fprint_help (stdout);
2972 if (sim_log)
2973 fprint_help (sim_log);
2974 }
2975 return SCPE_OK;
2976 }
2977
2978
2979
2980 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2981 {
2982 t_stat status;
2983 if ((cptr == NULL) || (strlen (cptr) == 0))
2984 cptr = getenv("SHELL");
2985 if ((cptr == NULL) || (strlen (cptr) == 0))
2986 cptr = getenv("ComSpec");
2987 (void)fflush(stdout);
2988 if (sim_log)
2989 (void)fflush (sim_log);
2990 if (sim_deb)
2991 (void)fflush (sim_deb);
2992 status = system (cptr);
2993
2994 return status;
2995 }
2996
2997
2998
2999 t_stat echo_cmd (int32 flag, CONST char *cptr)
3000 {
3001 sim_printf ("%s\r\n", cptr);
3002 return SCPE_OK;
3003 }
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025 t_stat do_cmd (int32 flag, CONST char *fcptr)
3026 {
3027 return do_cmd_label (flag, fcptr, NULL);
3028 }
3029
3030 static char *do_position(void)
3031 {
3032 static char cbuf[4*CBUFSIZE];
3033
3034 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3035 sim_do_label[sim_do_depth] ? "::" : "",
3036 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3037 sim_goto_line[sim_do_depth]);
3038 return cbuf;
3039 }
3040
3041 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
3042 {
3043 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3044 CONST char *cptr;
3045 FILE *fpin;
3046 CTAB *cmdp = NULL;
3047 int32 echo, nargs, errabort, i;
3048 int32 saved_sim_do_echo = sim_do_echo,
3049 saved_sim_show_message = sim_show_message,
3050 saved_sim_on_inherit = sim_on_inherit,
3051 saved_sim_quiet = sim_quiet;
3052 t_bool staying;
3053 t_stat stat, stat_nomessage;
3054
3055 stat = SCPE_OK;
3056 staying = TRUE;
3057 if (flag > 0)
3058 GET_SWITCHES (fcptr);
3059 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
3060 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
3061 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
3062 errabort = sim_switches & SWMASK ('E');
3063
3064 abuf[sizeof(abuf)-1] = '\0';
3065 strncpy (abuf, fcptr, sizeof(abuf)-1);
3066 c = abuf;
3067 do_arg[10] = NULL;
3068 for (nargs = 0; nargs < 10; ) {
3069 while (sim_isspace (*c))
3070 c++;
3071 if (*c == 0)
3072 do_arg [nargs++] = NULL;
3073 else {
3074 if (*c == '\'' || *c == '"')
3075 quote = *c++;
3076 else quote = 0;
3077 do_arg[nargs++] = c;
3078 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3079 c++;
3080 if (*c)
3081 *c++ = 0;
3082 }
3083 }
3084
3085 if (do_arg [0] == NULL)
3086 return SCPE_2FARG;
3087 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
3088 strcat (strcpy (cbuf, do_arg[0]), ".ini");
3089 if ((fpin = fopen (cbuf, "r")) == NULL) {
3090 if (flag == 0)
3091 (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3092 return SCPE_OPENERR;
3093 }
3094 }
3095 if (flag >= 0) {
3096 ++sim_do_depth;
3097 if (sim_on_inherit) {
3098 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
3099 for (i=0; i<SCPE_MAX_ERR; i++) {
3100 if (sim_on_actions[sim_do_depth-1][i]) {
3101 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3102 if (NULL == sim_on_actions[sim_do_depth][i]) {
3103 while (--i >= 0) {
3104 FREE(sim_on_actions[sim_do_depth][i]);
3105 sim_on_actions[sim_do_depth][i] = NULL;
3106 }
3107 sim_on_check[sim_do_depth] = 0;
3108 sim_brk_clract ();
3109 --sim_do_depth;
3110 fclose(fpin);
3111 return SCPE_MEM;
3112 }
3113 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3114 }
3115 }
3116 }
3117 }
3118
3119 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
3120 sim_do_label[sim_do_depth] = label;
3121 sim_goto_line[sim_do_depth] = 0;
3122 if (label) {
3123 sim_gotofile = fpin;
3124 sim_do_echo = echo;
3125 stat = goto_cmd (0, label);
3126 if (stat != SCPE_OK) {
3127 strcpy(cbuf, "RETURN SCPE_ARG");
3128 cptr = get_glyph (cbuf, gbuf, 0);
3129 cmdp = find_cmd (gbuf);
3130 goto Cleanup_Return;
3131 }
3132 }
3133 if (errabort)
3134 set_on (1, NULL);
3135
3136 do {
3137 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
3138 if (!sim_do_ocptr[sim_do_depth]) {
3139 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
3140 sim_goto_line[sim_do_depth] += 1;
3141 }
3142 if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {
3143 sim_sub_args(cbuf, sizeof(cbuf), do_arg);
3144 }
3145 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
3146 if (cptr == NULL) {
3147 stat = SCPE_OK;
3148 break;
3149 }
3150 if (*cptr == 0)
3151 continue;
3152 if (echo)
3153 sim_printf("%s> %s\r\n", do_position(), cptr);
3154 if (*cptr == ':')
3155 continue;
3156 cptr = get_glyph_cmd (cptr, gbuf);
3157 sim_switches = 0;
3158 sim_gotofile = fpin;
3159 sim_do_echo = echo;
3160 if ((cmdp = find_cmd (gbuf))) {
3161 if (cmdp->action == &return_cmd)
3162 break;
3163 if (cmdp->action == &do_cmd) {
3164 if (sim_do_depth >= MAX_DO_NEST_LVL)
3165 stat = SCPE_NEST;
3166 else
3167 stat = do_cmd (sim_do_depth+1, cptr);
3168 }
3169 else
3170 stat = cmdp->action (cmdp->arg, cptr);
3171 }
3172 else stat = SCPE_UNK;
3173 echo = sim_do_echo;
3174 stat_nomessage = stat & SCPE_NOMESSAGE;
3175 stat_nomessage = stat_nomessage || (!sim_show_message);
3176 stat = SCPE_BARE_STATUS(stat);
3177 if (cmdp)
3178 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3179 ((cmdp->action != &return_cmd) &&
3180 (cmdp->action != &goto_cmd) &&
3181 (cmdp->action != &on_cmd) &&
3182 (cmdp->action != &echo_cmd)))
3183 sim_last_cmd_stat = stat;
3184 switch (stat) {
3185 case SCPE_AFAIL:
3186 staying = (sim_on_check[sim_do_depth] &&
3187 sim_on_actions[sim_do_depth][stat]);
3188 break;
3189 case SCPE_EXIT:
3190 staying = FALSE;
3191 break;
3192 case SCPE_OK:
3193 case SCPE_STEP:
3194 break;
3195 default:
3196 break;
3197 }
3198 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
3199 (stat != SCPE_STEP)) {
3200 if (!echo && !sim_quiet &&
3201 !stat_nomessage &&
3202 !(cmdp && cmdp->message)) {
3203 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3204 }
3205 }
3206 if (!stat_nomessage) {
3207 if (cmdp && cmdp->message)
3208 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3209 else
3210 if (stat >= SCPE_BASE)
3211 sim_printf ("%s\r\n", sim_error_text (stat));
3212 }
3213 if (stat == SCPE_EXPECT)
3214 stat = SCPE_OK;
3215 if (staying &&
3216 (sim_on_check[sim_do_depth]) &&
3217 (stat != SCPE_OK) &&
3218 (stat != SCPE_STEP)) {
3219 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3220 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3221 else
3222 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3223 }
3224 if (sim_vm_post != NULL)
3225 (*sim_vm_post) (TRUE);
3226 } while (staying);
3227 Cleanup_Return:
3228 if (fpin)
3229 fclose (fpin);
3230 sim_gotofile = NULL;
3231 if (flag >= 0) {
3232 sim_do_echo = saved_sim_do_echo;
3233 sim_show_message = saved_sim_show_message;
3234 sim_on_inherit = saved_sim_on_inherit;
3235 }
3236 sim_quiet = saved_sim_quiet;
3237 if ((flag >= 0) || (!sim_on_inherit)) {
3238 for (i=0; i<SCPE_MAX_ERR; i++) {
3239 FREE (sim_on_actions[sim_do_depth][i]);
3240 sim_on_actions[sim_do_depth][i] = NULL;
3241 }
3242 sim_on_check[sim_do_depth] = 0;
3243 }
3244 if (flag >= 0)
3245 --sim_do_depth;
3246 sim_brk_clract ();
3247 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
3248 sim_string_to_stat (cptr, &stat);
3249 sim_last_cmd_stat = stat;
3250 if (sim_switches & SWMASK ('Q'))
3251 stat |= SCPE_NOMESSAGE;
3252 return stat;
3253 }
3254 return stat | SCPE_NOMESSAGE;
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
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
3300 {
3301 char gbuf[CBUFSIZE];
3302 char *ip = instr, *op, *oend, *tmpbuf;
3303 const char *ap;
3304 char rbuf[CBUFSIZE];
3305 int i;
3306 time_t now;
3307 struct tm *tmnow;
3308
3309 time(&now);
3310 tmnow = localtime(&now);
3311 tmpbuf = (char *)malloc(instr_size);
3312 if (!tmpbuf)
3313 {
3314 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3315 __func__, __FILE__, __LINE__);
3316 #if defined(USE_BACKTRACE)
3317 # if defined(SIGUSR2)
3318 (void)raise(SIGUSR2);
3319
3320 # endif
3321 #endif
3322 abort();
3323 }
3324 op = tmpbuf;
3325 oend = tmpbuf + instr_size - 2;
3326 while (sim_isspace (*ip))
3327 *op++ = *ip++;
3328 for (; *ip && (op < oend); ) {
3329 if ((ip [0] == '\\') &&
3330 ((ip [1] == '%') || (ip [1] == '\\'))) {
3331 ip++;
3332 *op++ = *ip++;
3333 }
3334 else
3335 if ((*ip == '%') &&
3336 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
3337 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
3338 ap = do_arg[ip[1] - '0'];
3339 for (i=0; i<ip[1] - '0'; ++i)
3340 if (do_arg[i] == NULL) {
3341 ap = NULL;
3342 break;
3343 }
3344 ip = ip + 2;
3345 }
3346 else if (ip[1] == '*') {
3347 (void)memset (rbuf, '\0', sizeof(rbuf));
3348 ap = rbuf;
3349 for (i=1; i<=9; ++i)
3350 if (do_arg[i] == NULL)
3351 break;
3352 else
3353 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3354 if (strchr(do_arg[i], ' ')) {
3355 char quote = '"';
3356 if (strchr(do_arg[i], quote))
3357 quote = '\'';
3358 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3359 (i != 1) ? " " : "", quote,
3360 do_arg[i], quote);
3361 }
3362 else
3363 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3364 (i != 1) ? " " : "", do_arg[i]);
3365 }
3366 else
3367 break;
3368 ip = ip + 2;
3369 }
3370 else {
3371 ap = NULL;
3372 (void)get_glyph_nc (ip+1, gbuf, '%');
3373 ap = getenv(gbuf);
3374 if (!ap) {
3375 (void)get_glyph (ip+1, gbuf, '%');
3376 ap = getenv(gbuf);
3377 }
3378 ip += 1 + strlen (gbuf);
3379 if (*ip == '%') ++ip;
3380 if (!ap) {
3381
3382 if (!strcmp ("DATE", gbuf)) {
3383 (void)sprintf (rbuf, "%4d-%02d-%02d",
3384 tmnow->tm_year + 1900,
3385 tmnow->tm_mon + 1,
3386 tmnow->tm_mday);
3387 ap = rbuf;
3388 }
3389 else if (!strcmp ("TIME", gbuf)) {
3390 (void)sprintf (rbuf, "%02d:%02d:%02d",
3391 tmnow->tm_hour,
3392 tmnow->tm_min,
3393 tmnow->tm_sec);
3394 ap = rbuf;
3395 }
3396 else if (!strcmp ("DATETIME", gbuf)) {
3397 (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3398 tmnow->tm_year + 1900,
3399 tmnow->tm_mon + 1,
3400 tmnow->tm_mday,
3401 tmnow->tm_hour,
3402 tmnow->tm_min,
3403 tmnow->tm_sec);
3404 ap = rbuf;
3405 }
3406
3407 if (!strcmp ("LDATE", gbuf)) {
3408 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3409 ap = rbuf;
3410 }
3411 else if (!strcmp ("LTIME", gbuf)) {
3412 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3413 ap = rbuf;
3414 }
3415 else if (!strcmp ("CTIME", gbuf)) {
3416 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3417 ap = rbuf;
3418 }
3419
3420 else if (!strcmp ("DATE_YYYY", gbuf)) {
3421 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3422 ap = rbuf;
3423 }
3424 else if (!strcmp ("DATE_YY", gbuf)) {
3425 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3426 ap = rbuf;
3427 }
3428 else if (!strcmp ("DATE_YC", gbuf)) {
3429 (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3430 ap = rbuf;
3431 }
3432 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3433 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3434 int year = tmnow->tm_year + 1900;
3435 int days = year - 2001;
3436 int leaps = days/4 - days/100 + days/400;
3437 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3438 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3439 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3440 96, 80, 92, 76, 88, 72, 84};
3441 int cal_year = years[selector];
3442
3443 if (!strcmp ("DATE_19XX_YY", gbuf))
3444 (void)sprintf (rbuf, "%d", cal_year);
3445 else
3446 (void)sprintf (rbuf, "%d", cal_year + 1900);
3447 ap = rbuf;
3448 }
3449 else if (!strcmp ("DATE_MM", gbuf)) {
3450 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3451 ap = rbuf;
3452 }
3453 else if (!strcmp ("DATE_MMM", gbuf)) {
3454 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3455 ap = rbuf;
3456 }
3457 else if (!strcmp ("DATE_DD", gbuf)) {
3458 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3459 ap = rbuf;
3460 }
3461 else if (!strcmp ("DATE_D", gbuf)) {
3462 (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3463 ap = rbuf;
3464 }
3465 else if ((!strcmp ("DATE_WW", gbuf)) ||
3466 (!strcmp ("DATE_WYYYY", gbuf))) {
3467 int iso_yr = tmnow->tm_year + 1900;
3468 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3469
3470 if (iso_wk == 0) {
3471 iso_yr = iso_yr - 1;
3472 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3473 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3474 }
3475 else
3476 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3477 ++iso_yr;
3478 iso_wk = 1;
3479 }
3480 if (!strcmp ("DATE_WW", gbuf))
3481 (void)sprintf (rbuf, "%02d", iso_wk);
3482 else
3483 (void)sprintf (rbuf, "%04d", iso_yr);
3484 ap = rbuf;
3485 }
3486 else if (!strcmp ("DATE_JJJ", gbuf)) {
3487 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3488 ap = rbuf;
3489 }
3490 else if (!strcmp ("TIME_HH", gbuf)) {
3491 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3492 ap = rbuf;
3493 }
3494 else if (!strcmp ("TIME_MM", gbuf)) {
3495 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3496 ap = rbuf;
3497 }
3498 else if (!strcmp ("TIME_SS", gbuf)) {
3499 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3500 ap = rbuf;
3501 }
3502 else if (!strcmp ("STATUS", gbuf)) {
3503 (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3504 ap = rbuf;
3505 }
3506 else if (!strcmp ("TSTATUS", gbuf)) {
3507 (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3508 ap = rbuf;
3509 }
3510 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3511 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3512 ap = rbuf;
3513 }
3514 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3515 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3516 ap = rbuf;
3517 }
3518 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3519 (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3520 ap = rbuf;
3521 }
3522 else if (!strcmp ("SIM_QUIET", gbuf)) {
3523 (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3524 ap = rbuf;
3525 }
3526 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3527 (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3528 ap = rbuf;
3529 }
3530 else if (!strcmp ("HOSTID", gbuf)) {
3531 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3532 (void)sprintf (rbuf, "%ld", (long)gethostid());
3533 #else
3534 (void)sprintf (rbuf, "00000000");
3535 #endif
3536 ap = rbuf;
3537 }
3538 else if (!strcmp ("UID", gbuf)) {
3539 #if defined(HAVE_UNISTD)
3540 (void)sprintf (rbuf, "%ld", (long)getuid());
3541 #else
3542 (void)sprintf (rbuf, "0");
3543 #endif
3544 ap = rbuf;
3545 }
3546 else if (!strcmp ("GID", gbuf)) {
3547 #if defined(HAVE_UNISTD)
3548 (void)sprintf (rbuf, "%ld", (long)getgid());
3549 #else
3550 (void)sprintf (rbuf, "0");
3551 #endif
3552 ap = rbuf;
3553 }
3554 else if (!strcmp ("EUID", gbuf)) {
3555 #if defined(HAVE_UNISTD)
3556 (void)sprintf (rbuf, "%ld", (long)geteuid());
3557 #else
3558 (void)sprintf (rbuf, "0");
3559 #endif
3560 ap = rbuf;
3561 }
3562 else if (!strcmp ("EGID", gbuf)) {
3563 #if defined(HAVE_UNISTD)
3564 (void)sprintf (rbuf, "%ld", (long)getegid());
3565 #else
3566 (void)sprintf (rbuf, "0");
3567 #endif
3568 ap = rbuf;
3569 }
3570 else if (!strcmp ("PID", gbuf)) {
3571 #if defined(HAVE_UNISTD)
3572 (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3573 #else
3574 (void)sprintf (rbuf, "0");
3575 #endif
3576 ap = rbuf;
3577 }
3578 else if (!strcmp ("PPID", gbuf)) {
3579 #if defined(HAVE_UNISTD)
3580 (void)sprintf (rbuf, "%ld", (long)getppid());
3581 #else
3582 (void)sprintf (rbuf, "0");
3583 #endif
3584 ap = rbuf;
3585 }
3586 else if (!strcmp ("PGID", gbuf)) {
3587 #if defined(HAVE_UNISTD)
3588 (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3589 #else
3590 (void)sprintf (rbuf, "0");
3591 #endif
3592 ap = rbuf;
3593 }
3594 else if (!strcmp ("SID", gbuf)) {
3595 #if defined(HAVE_UNISTD)
3596 (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3597 #else
3598 (void)sprintf (rbuf, "0");
3599 #endif
3600 ap = rbuf;
3601 }
3602 else if (!strcmp ("ENDIAN", gbuf)) {
3603 #if ( defined(DECLITEND) && DECLITEND == 1 )
3604 (void)sprintf (rbuf, "LITTLE");
3605 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3606 (void)sprintf (rbuf, "BIG");
3607 #else
3608 (void)sprintf (rbuf, "UNKNOWN");
3609 #endif
3610 ap = rbuf;
3611 }
3612 else if (!strcmp("SIM_NAME", gbuf)) {
3613 (void)sprintf (rbuf, "%s", sim_name);
3614 ap = rbuf;
3615 }
3616 else if (!strcmp("SIM_VERSION", gbuf)) {
3617 #if defined(VER_H_GIT_VERSION)
3618 (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3619 #else
3620 (void)sprintf (rbuf, "UNKNOWN");
3621 #endif
3622 ap = rbuf;
3623 }
3624 else if (!strcmp("SIM_HASH", gbuf)) {
3625 #if defined(VER_H_GIT_HASH)
3626 (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3627 #else
3628 (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3629 #endif
3630 ap = rbuf;
3631 }
3632 else if (!strcmp("SIM_RELT", gbuf)) {
3633 #if defined(VER_H_GIT_RELT)
3634 (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3635 #else
3636 (void)sprintf (rbuf, "X");
3637 #endif
3638 ap = rbuf;
3639 }
3640 else if (!strcmp("SIM_DATE", gbuf)) {
3641 #if defined(VER_H_GIT_DATE)
3642 (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3643 #else
3644 (void)sprintf (rbuf, "UNKNOWN");
3645 #endif
3646 ap = rbuf;
3647 }
3648 else if ((!strcmp("CORES", gbuf)) ||
3649 (!strcmp("SIM_CORES", gbuf))) {
3650 (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3651 ap = rbuf;
3652 }
3653 else if ((!strcmp("CPUS", gbuf)) ||
3654 (!strcmp("SIM_PROCESSORS", gbuf))) {
3655 (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3656 ap = rbuf;
3657 }
3658 }
3659 }
3660 if (ap) {
3661 while (*ap && (op < oend))
3662 *op++ = *ap++;
3663 }
3664 }
3665 else
3666 *op++ = *ip++;
3667 }
3668 *op = 0;
3669 strcpy (instr, tmpbuf);
3670 FREE (tmpbuf);
3671 return;
3672 }
3673
3674 static
3675 int sim_cmp_string (const char *s1, const char *s2)
3676 {
3677 long int v1, v2;
3678 char *ep1, *ep2;
3679
3680 v1 = strtol(s1+1, &ep1, 0);
3681 v2 = strtol(s2+1, &ep2, 0);
3682 if ((ep1 != s1 + strlen (s1) - 1) ||
3683 (ep2 != s2 + strlen (s2) - 1))
3684 return strcmp (s1, s2);
3685 if (v1 == v2)
3686 return 0;
3687 if (v1 < v2)
3688 return -1;
3689 return 1;
3690 }
3691
3692
3693
3694 t_stat assert_cmd (int32 flag, CONST char *cptr)
3695 {
3696 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3697 CONST char *tptr, *gptr;
3698 REG *rptr;
3699 uint32 idx = 0;
3700 t_value val;
3701 t_stat r;
3702 t_bool Not = FALSE;
3703 t_bool result;
3704 t_addr addr = 0;
3705 t_stat reason = SCPE_AFAIL;
3706
3707 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3708
3709 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3710 # pragma diagnostic push
3711 # pragma diag_suppress = integer_sign_change
3712 #endif
3713 sim_stabr.boolop = sim_staba.boolop = -1;
3714 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3715 # pragma diagnostic pop
3716 #endif
3717 if (*cptr == 0)
3718 return SCPE_2FARG;
3719 tptr = get_glyph (cptr, gbuf, 0);
3720 if (!strcmp (gbuf, "NOT")) {
3721 Not = TRUE;
3722 cptr = (CONST char *)tptr;
3723 }
3724 if (*cptr == '"') {
3725 char op[CBUFSIZE];
3726 static struct {
3727 const char *op;
3728 int aval;
3729 int bval;
3730 t_bool invert;
3731 } *optr, compare_ops[] =
3732 {
3733 { "==", 0, 0, FALSE },
3734 { "EQU", 0, 0, FALSE },
3735 { "!=", 0, 0, TRUE },
3736 { "NEQ", 0, 0, TRUE },
3737 { "<", -1, -1, FALSE },
3738 { "LSS", -1, -1, FALSE },
3739 { "<=", 0, -1, FALSE },
3740 { "LEQ", 0, -1, FALSE },
3741 { ">", 1, 1, FALSE },
3742 { "GTR", 1, 1, FALSE },
3743 { ">=", 0, 1, FALSE },
3744 { "GEQ", 0, 1, FALSE },
3745 { NULL }
3746 };
3747
3748 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3749
3750 if (!*tptr)
3751 return SCPE_2FARG;
3752 cptr += strlen (gbuf);
3753 while (sim_isspace (*cptr))
3754 ++cptr;
3755 (void)get_glyph (cptr, op, '"');
3756 for (optr = compare_ops; optr->op; optr++)
3757 if (0 == strcmp (op, optr->op))
3758 break;
3759 if (!optr->op)
3760 return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3761 cptr += strlen (op);
3762 while (sim_isspace (*cptr))
3763 ++cptr;
3764 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3765
3766 if (*cptr) {
3767 if (flag)
3768 return SCPE_2MARG;
3769 }
3770 else {
3771 if (!flag)
3772 return SCPE_2FARG;
3773 }
3774 result = sim_cmp_string (gbuf, gbuf2);
3775 result = ((result == optr->aval) || (result == optr->bval));
3776 if (optr->invert)
3777 result = !result;
3778 }
3779 else {
3780 cptr = get_glyph (cptr, gbuf, 0);
3781 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3782 if (rptr) {
3783 if (*gptr == '[') {
3784 if (rptr->depth <= 1)
3785 return SCPE_ARG;
3786 idx = (uint32) strtotv (++gptr, &tptr, 10);
3787 if ((gptr == tptr) || (*tptr++ != ']'))
3788 return SCPE_ARG;
3789 gptr = tptr;
3790 }
3791 else idx = 0;
3792 if (idx >= rptr->depth)
3793 return SCPE_SUB;
3794 }
3795 else {
3796 if (sim_dfdev && sim_vm_parse_addr)
3797 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3798 else if (sim_dfdev)
3799 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3800 if (gbuf == gptr)
3801 return SCPE_NXREG;
3802 }
3803 if (*gptr != 0)
3804 (void)get_glyph (gptr, gbuf, 0);
3805 else {
3806 if (*cptr == 0)
3807 return SCPE_2FARG;
3808 cptr = get_glyph (cptr, gbuf, 0);
3809 }
3810 if (*cptr) {
3811 if (flag)
3812 return SCPE_2MARG;
3813 }
3814 else {
3815 if (!flag)
3816 return SCPE_2FARG;
3817 }
3818 if (rptr) {
3819 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3820 # pragma diagnostic push
3821 # pragma diag_suppress = integer_sign_change
3822 #endif
3823 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3824 (sim_stabr.boolop == -1))
3825 return SCPE_MISVAL;
3826 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3827 # pragma diagnostic pop
3828 #endif
3829 val = get_rval (rptr, idx);
3830 result = test_search (&val, &sim_stabr);
3831 }
3832 else {
3833 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3834 # pragma diagnostic push
3835 # pragma diag_suppress = integer_sign_change
3836 #endif
3837 if (sim_dfdev)
3838 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3839 (sim_staba.boolop == -1))
3840 return SCPE_MISVAL;
3841 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3842 # pragma diagnostic pop
3843 #endif
3844 if (sim_dfdev)
3845 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3846 if (reason != SCPE_OK)
3847 return reason;
3848 result = test_search (sim_eval, &sim_staba);
3849 }
3850 }
3851 if (Not ^ result) {
3852 if (!flag)
3853 sim_brk_setact (cptr);
3854 }
3855 else
3856 if (flag)
3857 return SCPE_AFAIL;
3858 return SCPE_OK;
3859 }
3860
3861
3862
3863 t_stat send_cmd (int32 flag, CONST char *cptr)
3864 {
3865 char gbuf[CBUFSIZE];
3866 CONST char *tptr;
3867 uint8 dbuf[CBUFSIZE];
3868 uint32 dsize = 0;
3869 uint32 delay = 0;
3870 uint32 after = 0;
3871 t_stat r;
3872 SEND *snd = NULL;
3873
3874 GET_SWITCHES (cptr);
3875 tptr = get_glyph (cptr, gbuf, ',');
3876 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3877 r = tmxr_locate_line_send (gbuf, &snd);
3878 if (r != SCPE_OK)
3879 return r;
3880 cptr = tptr;
3881 tptr = get_glyph (tptr, gbuf, ',');
3882 }
3883 else
3884 snd = sim_cons_get_send ();
3885
3886 while (*cptr) {
3887 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3888 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3889 if (r != SCPE_OK)
3890 return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3891 cptr = tptr;
3892 tptr = get_glyph (cptr, gbuf, ',');
3893 continue;
3894 }
3895 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3896 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3897 if (r != SCPE_OK)
3898 return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3899 cptr = tptr;
3900 tptr = get_glyph (cptr, gbuf, ',');
3901 continue;
3902 }
3903 if ((*cptr == '"') || (*cptr == '\''))
3904 break;
3905 return SCPE_ARG;
3906 }
3907 if (*cptr) {
3908 if ((*cptr != '"') && (*cptr != '\''))
3909 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3910 cptr = get_glyph_quoted (cptr, gbuf, 0);
3911 if (*cptr != '\0')
3912 return SCPE_2MARG;
3913
3914 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3915 return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3916 }
3917 if ((dsize == 0) && (delay == 0) && (after == 0))
3918 return SCPE_2FARG;
3919 return sim_send_input (snd, dbuf, dsize, after, delay);
3920 }
3921
3922 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3923 {
3924 char gbuf[CBUFSIZE];
3925 CONST char *tptr;
3926 t_stat r;
3927 SEND *snd = NULL;
3928
3929 tptr = get_glyph (cptr, gbuf, ',');
3930 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3931 r = tmxr_locate_line_send (gbuf, &snd);
3932 if (r != SCPE_OK)
3933 return r;
3934 cptr = tptr;
3935 }
3936 else
3937 snd = sim_cons_get_send ();
3938 if (*cptr)
3939 return SCPE_2MARG;
3940 return sim_show_send_input (st, snd);
3941 }
3942
3943 t_stat expect_cmd (int32 flag, CONST char *cptr)
3944 {
3945 char gbuf[CBUFSIZE];
3946 CONST char *tptr;
3947 EXPECT *exp = NULL;
3948
3949 GET_SWITCHES (cptr);
3950 tptr = get_glyph (cptr, gbuf, ',');
3951 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3952 cptr = tptr;
3953 } else {
3954 exp = sim_cons_get_expect ();
3955 }
3956
3957 if (flag) {
3958 return sim_set_expect (exp, cptr);
3959 } else {
3960 if (exp == NULL) {
3961 exp = sim_cons_get_expect();
3962 }
3963 return sim_set_noexpect (exp, cptr);
3964 }
3965 }
3966
3967 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3968 {
3969 char gbuf[CBUFSIZE];
3970 CONST char *tptr;
3971 EXPECT *exp = NULL;
3972 t_stat r;
3973
3974 tptr = get_glyph (cptr, gbuf, ',');
3975 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3976 r = tmxr_locate_line_expect (gbuf, &exp);
3977 if (r != SCPE_OK)
3978 return r;
3979 cptr = tptr;
3980 }
3981 else
3982 exp = sim_cons_get_expect ();
3983 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3984 return SCPE_ARG;
3985 tptr = get_glyph_quoted (cptr, gbuf, 0);
3986 if (*tptr != '\0')
3987 return SCPE_2MARG;
3988 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3989 return SCPE_ARG;
3990 return sim_exp_show (st, exp, gbuf);
3991 }
3992
3993
3994
3995 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3996 {
3997 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3998 const char *cptr;
3999 long fpos;
4000 int32 saved_do_echo = sim_do_echo;
4001 int32 saved_goto_line = sim_goto_line[sim_do_depth];
4002
4003 if (NULL == sim_gotofile) return SCPE_UNK;
4004 (void)get_glyph (fcptr, gbuf1, 0);
4005 if ('\0' == gbuf1[0]) return SCPE_ARG;
4006 fpos = ftell(sim_gotofile);
4007 rewind(sim_gotofile);
4008 sim_goto_line[sim_do_depth] = 0;
4009 sim_do_echo = 0;
4010 while (1) {
4011 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
4012 if (cptr == NULL) break;
4013 sim_goto_line[sim_do_depth] += 1;
4014 if (*cptr == 0) continue;
4015 if (*cptr != ':') continue;
4016 ++cptr;
4017 while (sim_isspace (*cptr)) ++cptr;
4018 cptr = get_glyph (cptr, gbuf, 0);
4019 if (0 == strcmp(gbuf, gbuf1)) {
4020 sim_brk_clract ();
4021 sim_do_echo = saved_do_echo;
4022 if (sim_do_echo)
4023 sim_printf("%s> %s\r\n", do_position(), cbuf);
4024 return SCPE_OK;
4025 }
4026 }
4027 sim_do_echo = saved_do_echo;
4028 fseek(sim_gotofile, fpos, SEEK_SET);
4029 sim_goto_line[sim_do_depth] = saved_goto_line;
4030 return SCPE_ARG;
4031 }
4032
4033
4034
4035
4036
4037
4038
4039
4040 t_stat return_cmd (int32 flag, CONST char *fcptr)
4041 {
4042 return SCPE_UNK;
4043 }
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053 t_stat shift_cmd (int32 flag, CONST char *fcptr)
4054 {
4055 return SCPE_UNK;
4056 }
4057
4058
4059
4060
4061
4062
4063
4064
4065 t_stat call_cmd (int32 flag, CONST char *fcptr)
4066 {
4067 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4068 const char *cptr;
4069
4070 if (NULL == sim_gotofile) return SCPE_UNK;
4071 cptr = get_glyph (fcptr, gbuf, 0);
4072 if ('\0' == gbuf[0]) return SCPE_ARG;
4073 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4074 sim_switches |= SWMASK ('O');
4075 return do_cmd_label (flag, cbuf, gbuf);
4076 }
4077
4078
4079
4080 t_stat on_cmd (int32 flag, CONST char *cptr)
4081 {
4082 char gbuf[CBUFSIZE];
4083 t_stat cond;
4084
4085 cptr = get_glyph (cptr, gbuf, 0);
4086 if ('\0' == gbuf[0]) return SCPE_ARG;
4087 if (0 == strcmp("ERROR", gbuf))
4088 cond = 0;
4089 else
4090 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4091 return SCPE_ARG;
4092 if ((NULL == cptr) || ('\0' == *cptr)) {
4093 FREE(sim_on_actions[sim_do_depth][cond]);
4094 sim_on_actions[sim_do_depth][cond] = NULL; }
4095 else {
4096 sim_on_actions[sim_do_depth][cond] =
4097 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4098 if (!sim_on_actions[sim_do_depth][cond])
4099 {
4100 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4101 __func__, __FILE__, __LINE__);
4102 #if defined(USE_BACKTRACE)
4103 # if defined(SIGUSR2)
4104 (void)raise(SIGUSR2);
4105
4106 # endif
4107 #endif
4108 abort();
4109 }
4110 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4111 }
4112 return SCPE_OK;
4113 }
4114
4115
4116
4117 t_stat noop_cmd (int32 flag, CONST char *cptr)
4118 {
4119 if (cptr && (*cptr != 0))
4120 return SCPE_2MARG;
4121 return SCPE_OK;
4122 }
4123
4124
4125
4126 t_stat set_on (int32 flag, CONST char *cptr)
4127 {
4128 if ((flag) && (cptr) && (*cptr)) {
4129 char gbuf[CBUFSIZE];
4130
4131 cptr = get_glyph (cptr, gbuf, 0);
4132 if (((MATCH_CMD(gbuf,"INHERIT")) &&
4133 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
4134 (*cptr))
4135 return SCPE_2MARG;
4136 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
4137 sim_on_inherit = 1;
4138 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
4139 sim_on_inherit = 0;
4140 return SCPE_OK;
4141 }
4142 if (cptr && (*cptr != 0))
4143 return SCPE_2MARG;
4144 sim_on_check[sim_do_depth] = flag;
4145 if ((sim_do_depth != 0) &&
4146 (NULL == sim_on_actions[sim_do_depth][0])) {
4147 sim_on_actions[sim_do_depth][0] =
4148 (char *)malloc(1+strlen("RETURN"));
4149 if (sim_on_actions[sim_do_depth][0] == NULL)
4150 {
4151 (void)sir_emerg ("FATAL: Out of memory! Aborting at %s[%s:%d]",
4152 __func__, __FILE__, __LINE__);
4153 #if defined(USE_BACKTRACE)
4154 # if defined(SIGUSR2)
4155 (void)raise(SIGUSR2);
4156
4157 # endif
4158 #endif
4159 abort();
4160 }
4161 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4162 }
4163 if ((sim_do_depth != 0) &&
4164 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
4165 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
4166 (char *)malloc(1+strlen("RETURN"));
4167 if (sim_on_actions[sim_do_depth][SCPE_AFAIL] == NULL)
4168 {
4169 (void)sir_emerg ("FATAL: Out of memory! Aborting at %s[%s:%d]",
4170 __func__, __FILE__, __LINE__);
4171 #if defined(USE_BACKTRACE)
4172 # if defined(SIGUSR2)
4173 (void)raise(SIGUSR2);
4174
4175 # endif
4176 #endif
4177 abort();
4178 }
4179 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4180 }
4181 return SCPE_OK;
4182 }
4183
4184
4185
4186 t_stat set_verify (int32 flag, CONST char *cptr)
4187 {
4188 if (cptr && (*cptr != 0))
4189 return SCPE_2MARG;
4190 if (flag == sim_do_echo)
4191 return SCPE_OK;
4192 sim_do_echo = flag;
4193 return SCPE_OK;
4194 }
4195
4196
4197
4198 t_stat set_message (int32 flag, CONST char *cptr)
4199 {
4200 if (cptr && (*cptr != 0))
4201 return SCPE_2MARG;
4202 if (flag == sim_show_message)
4203 return SCPE_OK;
4204 sim_show_message = flag;
4205 return SCPE_OK;
4206 }
4207
4208
4209
4210 t_stat set_localopc (int32 flag, CONST char *cptr)
4211 {
4212 if (cptr && (*cptr != 0))
4213 return SCPE_2MARG;
4214 if (flag == sim_localopc)
4215 return SCPE_OK;
4216 sim_localopc = flag;
4217 return SCPE_OK;
4218 }
4219
4220
4221 t_stat set_quiet (int32 flag, CONST char *cptr)
4222 {
4223 if (cptr && (*cptr != 0))
4224 return SCPE_2MARG;
4225 if (flag == sim_quiet)
4226 return SCPE_OK;
4227 sim_quiet = flag;
4228 return SCPE_OK;
4229 }
4230
4231
4232
4233 t_stat sim_set_environment (int32 flag, CONST char *cptr)
4234 {
4235 char varname[CBUFSIZE];
4236
4237 if ((NULL == cptr) || (*cptr == 0))
4238 return SCPE_2FARG;
4239 cptr = get_glyph (cptr, varname, '=');
4240 setenv(varname, cptr, 1);
4241 return SCPE_OK;
4242 }
4243
4244
4245
4246 t_stat set_cmd (int32 flag, CONST char *cptr)
4247 {
4248 uint32 lvl = 0;
4249 t_stat r;
4250 char gbuf[CBUFSIZE], *cvptr;
4251 CONST char *svptr;
4252 DEVICE *dptr;
4253 UNIT *uptr;
4254 MTAB *mptr;
4255 CTAB *gcmdp;
4256 C1TAB *ctbr = NULL, *glbr;
4257
4258 GET_SWITCHES (cptr);
4259 if ((NULL == cptr) || (*cptr == 0))
4260 return SCPE_2FARG;
4261 cptr = get_glyph (svptr = cptr, gbuf, 0);
4262
4263 if ((dptr = find_dev (gbuf))) {
4264 uptr = dptr->units;
4265 ctbr = set_dev_tab;
4266 lvl = MTAB_VDV;
4267 GET_SWITCHES (cptr);
4268 }
4269 else if ((dptr = find_unit (gbuf, &uptr))) {
4270 if (uptr == NULL)
4271 return SCPE_NXUN;
4272 ctbr = set_unit_tab;
4273 lvl = MTAB_VUN;
4274 GET_SWITCHES (cptr);
4275 }
4276 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
4277 GET_SWITCHES (cptr);
4278 return gcmdp->action (gcmdp->arg, cptr);
4279 }
4280 else {
4281 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4282 if ((cvptr = strchr (gbuf, '=')))
4283 *cvptr++ = 0;
4284 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4285 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4286 dptr = sim_dflt_dev;
4287 cptr = svptr;
4288 while (sim_isspace(*cptr))
4289 ++cptr;
4290 break;
4291 }
4292 }
4293 }
4294 if (!dptr)
4295 return SCPE_NXDEV;
4296 lvl = MTAB_VDV;
4297 uptr = dptr->units;
4298 }
4299 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4300 return SCPE_2FARG;
4301 GET_SWITCHES (cptr);
4302
4303 while (*cptr != 0) {
4304 cptr = get_glyph (svptr = cptr, gbuf, ',');
4305 if (0 == strcmp (gbuf, ";"))
4306 break;
4307 if ((cvptr = strchr (gbuf, '=')))
4308 *cvptr++ = 0;
4309 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4310 if ((mptr->mstring) &&
4311 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4312 if (mptr->mask & MTAB_XTD) {
4313 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4314 return SCPE_ARG;
4315 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4316 return SCPE_UDIS;
4317 if (mptr->valid) {
4318 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4319 svptr = get_glyph_quoted (svptr, gbuf, ',');
4320 if ((cvptr = strchr (gbuf, '='))) {
4321 *cvptr++ = 0;
4322 cptr = svptr;
4323 }
4324 }
4325 else {
4326 if (cvptr && MODMASK(mptr,MTAB_NC)) {
4327 (void)get_glyph_nc (svptr, gbuf, ',');
4328 if ((cvptr = strchr (gbuf, '=')))
4329 *cvptr++ = 0;
4330 }
4331 }
4332 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4333 if (r != SCPE_OK)
4334 return r;
4335 }
4336 else if (!mptr->desc)
4337 break;
4338 else if (cvptr)
4339 return SCPE_ARG;
4340 else *((int32 *) mptr->desc) = mptr->match;
4341 }
4342 else {
4343 if (cvptr)
4344 return SCPE_ARG;
4345 if (uptr->flags & UNIT_DIS)
4346 return SCPE_UDIS;
4347 if ((mptr->valid) &&
4348 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4349 return r;
4350 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4351 (mptr->match & mptr->mask);
4352 }
4353 break;
4354 }
4355 }
4356 if (!mptr || (mptr->mask == 0)) {
4357 if ((glbr = find_c1tab (ctbr, gbuf))) {
4358 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
4359 if (r != SCPE_OK)
4360 return r;
4361 }
4362 else if (!dptr->modifiers)
4363 return SCPE_NOPARAM;
4364 else return SCPE_NXPAR;
4365 }
4366 }
4367 return SCPE_OK;
4368 }
4369
4370
4371
4372 CTAB *find_ctab (CTAB *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 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
4384 {
4385 if (!tab)
4386 return NULL;
4387 for (; tab->name != NULL; tab++) {
4388 if (MATCH_CMD (gbuf, tab->name) == 0)
4389 return tab;
4390 }
4391 return NULL;
4392 }
4393
4394
4395
4396 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4397 {
4398 if (cptr)
4399 return SCPE_ARG;
4400 dptr->dradix = flag & 037;
4401 return SCPE_OK;
4402 }
4403
4404
4405
4406 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4407 {
4408 UNIT *up;
4409 uint32 i;
4410
4411 if (cptr)
4412 return SCPE_ARG;
4413 if ((dptr->flags & DEV_DISABLE) == 0)
4414 return SCPE_NOFNC;
4415 if (flag) {
4416 if ((dptr->flags & DEV_DIS) == 0)
4417 return SCPE_OK;
4418 dptr->flags = dptr->flags & ~DEV_DIS;
4419 }
4420 else {
4421 if (dptr->flags & DEV_DIS)
4422 return SCPE_OK;
4423 for (i = 0; i < dptr->numunits; i++) {
4424 up = (dptr->units) + i;
4425 if ((up->flags & UNIT_ATT) || sim_is_active (up))
4426 return SCPE_NOFNC;
4427 }
4428 dptr->flags = dptr->flags | DEV_DIS;
4429 }
4430 if (dptr->reset)
4431 return dptr->reset (dptr);
4432 else return SCPE_OK;
4433 }
4434
4435
4436
4437 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4438 {
4439 if (cptr)
4440 return SCPE_ARG;
4441 if (!(uptr->flags & UNIT_DISABLE))
4442 return SCPE_NOFNC;
4443 if (flag)
4444 uptr->flags = uptr->flags & ~UNIT_DIS;
4445 else {
4446 if ((uptr->flags & UNIT_ATT) ||
4447 sim_is_active (uptr))
4448 return SCPE_NOFNC;
4449 uptr->flags = uptr->flags | UNIT_DIS;
4450 }
4451 return SCPE_OK;
4452 }
4453
4454
4455
4456 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4457 {
4458 char gbuf[CBUFSIZE];
4459 DEBTAB *dep;
4460
4461 if ((dptr->flags & DEV_DEBUG) == 0)
4462 return SCPE_NOFNC;
4463 if (cptr == NULL) {
4464 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4465 if (flag && dptr->debflags) {
4466 for (dep = dptr->debflags; dep->name != NULL; dep++)
4467 dptr->dctrl = dptr->dctrl | dep->mask;
4468 }
4469 return SCPE_OK;
4470 }
4471 if (dptr->debflags == NULL)
4472 return SCPE_ARG;
4473 while (*cptr) {
4474 cptr = get_glyph (cptr, gbuf, ';');
4475 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4476 if (strcmp (dep->name, gbuf) == 0) {
4477 if (flag)
4478 dptr->dctrl = dptr->dctrl | dep->mask;
4479 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4480 break;
4481 }
4482 }
4483 if (dep->mask == 0)
4484 return SCPE_ARG;
4485 }
4486 return SCPE_OK;
4487 }
4488
4489
4490
4491 t_stat show_cmd (int32 flag, CONST char *cptr)
4492 {
4493 t_stat r = SCPE_IERR;
4494
4495 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4496
4497 if (NULL == cptr)
4498 return r;
4499 if (sim_ofile) {
4500 r = show_cmd_fi (sim_ofile, flag, cptr);
4501 fclose (sim_ofile);
4502 }
4503 else {
4504 r = show_cmd_fi (stdout, flag, cptr);
4505 if (sim_log && (sim_log != stdout))
4506 show_cmd_fi (sim_log, flag, cptr);
4507 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4508 show_cmd_fi (sim_deb, flag, cptr);
4509 }
4510 return r;
4511 }
4512
4513 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4514 {
4515 uint32 lvl = 0xFFFFFFFF;
4516 char gbuf[CBUFSIZE], *cvptr;
4517 CONST char *svptr;
4518 DEVICE *dptr;
4519 UNIT *uptr;
4520 MTAB *mptr;
4521 SHTAB *shtb = NULL, *shptr;
4522
4523 GET_SWITCHES (cptr);
4524 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4525 return SCPE_2FARG;
4526 cptr = get_glyph (svptr = cptr, gbuf, 0);
4527
4528 if ((dptr = find_dev (gbuf))) {
4529 uptr = dptr->units;
4530 shtb = show_dev_tab;
4531 lvl = MTAB_VDV;
4532 GET_SWITCHES (cptr);
4533 }
4534 else if ((dptr = find_unit (gbuf, &uptr))) {
4535 if (uptr == NULL)
4536 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4537 if (uptr->flags & UNIT_DIS)
4538 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4539 shtb = show_unit_tab;
4540 lvl = MTAB_VUN;
4541 GET_SWITCHES (cptr);
4542 }
4543 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4544 GET_SWITCHES (cptr);
4545 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4546 }
4547 else {
4548 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4549 if ((cvptr = strchr (gbuf, '=')))
4550 *cvptr++ = 0;
4551 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4552 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4553 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4554 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4555 dptr = sim_dflt_dev;
4556 lvl = MTAB_VDV;
4557 cptr = svptr;
4558 while (sim_isspace(*cptr))
4559 ++cptr;
4560 break;
4561 }
4562 }
4563 }
4564 if (!dptr) {
4565 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4566 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4567 else
4568 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);
4569 }
4570 }
4571
4572 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4573 return (lvl == MTAB_VDV)?
4574 show_device (ofile, dptr, 0):
4575 show_unit (ofile, dptr, uptr, -1);
4576 }
4577 GET_SWITCHES (cptr);
4578
4579 while (*cptr != 0) {
4580 cptr = get_glyph (cptr, gbuf, ',');
4581 if ((cvptr = strchr (gbuf, '=')))
4582 *cvptr++ = 0;
4583 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4584 if (((mptr->mask & MTAB_XTD)?
4585 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4586 ((mptr->disp && mptr->pstring &&
4587 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4588 )) {
4589 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4590 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4591 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4592 break;
4593 }
4594 }
4595 if (!mptr || (mptr->mask == 0)) {
4596 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4597 t_stat r;
4598
4599 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4600 if (r != SCPE_OK)
4601 return r;
4602 }
4603 else {
4604 if (!dptr->modifiers)
4605 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4606 else
4607 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4608 }
4609 }
4610 }
4611 return SCPE_OK;
4612 }
4613
4614 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4615 {
4616 if (!tab)
4617 return NULL;
4618 for (; tab->name != NULL; tab++) {
4619 if (MATCH_CMD (gbuf, tab->name) == 0)
4620 return tab;
4621 }
4622 return NULL;
4623 }
4624
4625
4626
4627 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4628 {
4629 uint32 j, udbl, ucnt;
4630 UNIT *uptr;
4631 int32 toks = 0;
4632
4633 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4634 (void)fprintf (st, "%s", sim_dname (dptr));
4635 if ((flag == 2) && dptr->description) {
4636 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4637 }
4638 else {
4639 if ((sim_switches & SWMASK ('D')) && dptr->description)
4640 (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4641 }
4642 if (qdisable (dptr)) {
4643 (void)fprintf (st, "\tdisabled\r\n");
4644 return SCPE_OK;
4645 }
4646 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4647 uptr = dptr->units + j;
4648 if (!(uptr->flags & UNIT_DIS))
4649 ucnt++;
4650 else if (uptr->flags & UNIT_DISABLE)
4651 udbl++;
4652 }
4653
4654 if (dptr->numunits == 0) {
4655
4656
4657 }
4658 else
4659 {
4660 if (ucnt == 0) {
4661 fprint_sep (st, &toks);
4662 (void)fprintf (st, "all units disabled\r\n");
4663 }
4664 else if ((ucnt + udbl) == 1) {
4665 fprint_sep (st, &toks);
4666 (void)fprintf (st, " 1 unit\r\n");
4667 }
4668 else if ((ucnt > 1) || (udbl > 0)) {
4669 fprint_sep (st, &toks);
4670 (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4671 }
4672 else
4673 if ((flag != 2) || !dptr->description || toks)
4674 (void)fprintf (st, "\r\n");
4675 toks = 0;
4676 }
4677 if (flag)
4678 return SCPE_OK;
4679 for (j = 0; j < dptr->numunits; j++) {
4680 uptr = dptr->units + j;
4681 if ((uptr->flags & UNIT_DIS) == 0)
4682 show_unit (st, dptr, uptr, ucnt + udbl);
4683 }
4684 }
4685 return SCPE_OK;
4686 }
4687
4688 void fprint_sep (FILE *st, int32 *tokens)
4689 {
4690 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4691 *tokens += 1;
4692 }
4693
4694 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4695 {
4696 int32 u = (int32)(uptr - dptr->units);
4697 int32 toks = 0;
4698
4699 if (flag > 1)
4700 (void)fprintf (st, " %s%d\r\n", sim_dname (dptr), u);
4701 else if (flag < 0)
4702 (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4703 if (uptr->flags & UNIT_ATT) {
4704 fprint_sep (st, &toks);
4705 (void)fprintf (st, "status : attached to %s", uptr->filename);
4706 if (uptr->flags & UNIT_RO)
4707 (void)fprintf (st, ", read only");
4708 }
4709 else {
4710 if (uptr->flags & UNIT_ATTABLE) {
4711 fprint_sep (st, &toks);
4712 (void)fprintf (st, "status : not attached");
4713 }
4714 }
4715 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4716 fprint_sep (st, &toks);
4717 fprint_capac (st, dptr, uptr);
4718 }
4719 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4720 if (toks || (flag < 0) || (flag > 1))
4721 (void)fprintf (st, "\r\n");
4722 return SCPE_OK;
4723 }
4724
4725 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4726 {
4727 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4728 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4729 t_offset mval;
4730 t_offset psize = (t_offset)uptr->capac;
4731 char *scale, *width;
4732
4733 if (sim_switches & SWMASK ('B'))
4734 kval = 1024;
4735 mval = kval * kval;
4736 if (dptr->flags & DEV_SECTORS) {
4737 kval = kval / 512;
4738 mval = mval / 512;
4739 }
4740 if ((dptr->dwidth / dptr->aincr) > 8)
4741 width = "W";
4742 else
4743 width = "B";
4744 if ((psize < (kval * 10)) &&
4745 (0 != (psize % kval))) {
4746 scale = "";
4747 }
4748 else if ((psize < (mval * 10)) &&
4749 (0 != (psize % mval))){
4750 scale = "K";
4751 psize = psize / kval;
4752 }
4753 else {
4754 scale = "M";
4755 psize = psize / mval;
4756 }
4757 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4758 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4759 return capac_buf;
4760 }
4761
4762 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4763 {
4764 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4765 }
4766
4767
4768
4769 extern void print_default_base_system_script (void);
4770 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4771 {
4772 #if !defined(PERF_STRIP)
4773 print_default_base_system_script();
4774 #endif
4775 return 0;
4776 }
4777
4778 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4779 sim_printf (" %s ", label);
4780 sim_printf (" %2d %3o(8) '", length, offset);
4781 for (int l = 0; l < length; l ++)
4782 {
4783 unsigned int byte = PROM[offset + l];
4784 if (byte == 255)
4785 {
4786 byte = ' ';
4787 }
4788 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4789 }
4790 sim_printf ("'\r\n");
4791 }
4792
4793 static void strip_spaces(char* str) {
4794 int i, x;
4795 for (i=x=0; str[i]; ++i)
4796 {
4797 if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)])))
4798 {
4799 str[x++] = str[i];
4800 }
4801 }
4802 str[x] = '\0';
4803 i = -1;
4804 x = 0;
4805 while (str[x] != '\0')
4806 {
4807 if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4808 {
4809 i=x;
4810 }
4811 x++;
4812 }
4813 str[i+1] = '\0';
4814 }
4815
4816 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
4817 char sx[1024];
4818 sx[1023] = '\0';
4819 unsigned int lastbyte = 0;
4820 for (int l = 0; l < length; l ++)
4821 {
4822 unsigned int byte = PROM[offset + l];
4823 if (byte == 255)
4824 {
4825 byte = 20;
4826 }
4827 if ((lastbyte != 20) && (byte != 20))
4828 {
4829 (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4830 }
4831 lastbyte = byte;
4832 }
4833 strip_spaces(sx);
4834 (void)fprintf (st, "%s", sx);
4835 }
4836
4837 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4838 {
4839 unsigned char PROM[1024];
4840 setupPROM (0, PROM);
4841
4842 sim_printf (" PROM size: %llu bytes\r\n",
4843 (long long unsigned)sizeof(PROM));
4844 sim_printf (" PROM initialization data:\r\n\r\n");
4845
4846 sim_printf (" Field Description Length Offset Contents\r\n");
4847 sim_printf (" ========================= ======== ======== ==================================\r\n");
4848 sim_printf ("\r\n");
4849
4850
4851
4852 printp (PROM, "CPU Model ", 0, 11);
4853 printp (PROM, "CPU Serial ", 11, 11);
4854 printp (PROM, "Ship Date ", 22, 6);
4855 printp (PROM, "PROM Layout Version ", 60, 1);
4856 printp (PROM, "Release Git Commit Date ", 70, 10);
4857 printp (PROM, "Release Major ", 80, 3);
4858 printp (PROM, "Release Minor ", 83, 3);
4859 printp (PROM, "Release Patch ", 86, 3);
4860 printp (PROM, "Release Iteration ", 89, 3);
4861 printp (PROM, "Release Build Number ", 92, 8);
4862 printp (PROM, "Release Type ", 100, 1);
4863 printp (PROM, "Release Version Text ", 101, 29);
4864 printp (PROM, "Build Architecture ", 130, 20);
4865 printp (PROM, "Build Operating System ", 150, 20);
4866 printp (PROM, "Target Architecture ", 170, 20);
4867 printp (PROM, "Target Operating System ", 190, 20);
4868
4869 sim_printf("\r\n");
4870 return 0;
4871 }
4872
4873 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4874 {
4875 (void)fprintf (st, "\r Build Information:\r\n");
4876 #if defined(BUILDINFO_scp)
4877 (void)fprintf (st, "\r\n Compilation info: %s\r\n", BUILDINFO_scp );
4878 #else
4879 (void)fprintf (st, "\r\n Compilation info: Not available\r\n" );
4880 #endif
4881 #if !defined(__CYGWIN__)
4882 # if !defined(__APPLE__)
4883 # if !defined(_AIX)
4884 # if !defined(__MINGW32__)
4885 # if !defined(__MINGW64__)
4886 # if !defined(CROSS_MINGW32)
4887 # if !defined(CROSS_MINGW64)
4888 # if !defined(_WIN32)
4889 # if !defined(__HAIKU__)
4890 # if !defined(__QNX__)
4891 # if !defined(__FILC__)
4892 (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4893 if (dl_iterate_phdr_callback_called)
4894 (void)fprintf (st, "\r\n");
4895 dl_iterate_phdr_callback_called = 0;
4896 # endif
4897 # endif
4898 # endif
4899 # endif
4900 # endif
4901 # endif
4902 # endif
4903 # endif
4904 # endif
4905 # endif
4906 #endif
4907 #if defined(UV_VERSION_MAJOR) && \
4908 defined(UV_VERSION_MINOR) && \
4909 defined(UV_VERSION_PATCH)
4910 # if defined(UV_VERSION_MAJOR)
4911 # if !defined(UV_VERSION_MINOR) && \
4912 !defined(UV_VERSION_PATCH) && \
4913 !defined(UV_VERSION_SUFFIX)
4914 (void)fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4915 # endif
4916 # if defined(UV_VERSION_MINOR)
4917 # if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4918 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4919 UV_VERSION_MINOR);
4920 # endif
4921 # if defined(UV_VERSION_PATCH)
4922 # if !defined(UV_VERSION_SUFFIX)
4923 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4924 UV_VERSION_MINOR, UV_VERSION_PATCH);
4925 # endif
4926 # if defined(UV_VERSION_SUFFIX)
4927 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4928 UV_VERSION_MINOR, UV_VERSION_PATCH);
4929 # if defined(UV_VERSION_IS_RELEASE)
4930 # if UV_VERSION_IS_RELEASE == 1
4931 # define UV_RELEASE_TYPE " (release)"
4932 # endif
4933 # if UV_VERSION_IS_RELEASE == 0
4934 # define UV_RELEASE_TYPE "-dev"
4935 # endif
4936 # if !defined(UV_RELEASE_TYPE)
4937 # define UV_RELEASE_TYPE ""
4938 # endif
4939 # if defined(UV_RELEASE_TYPE)
4940 (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4941 # endif
4942 # endif
4943 # endif
4944 # endif
4945 # endif
4946 unsigned int CurrentUvVersion = uv_version();
4947 if (CurrentUvVersion > 0)
4948 if (uv_version_string() != NULL)
4949 (void)fprintf (st, "; %s in use", uv_version_string());
4950 # endif
4951 #else
4952 (void)fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4953 #endif
4954
4955
4956
4957 (void)fprintf (st, "\r\n Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4958 SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4959 SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4960 sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4961 #if defined(DECNUMBERLOC)
4962 # if defined(DECVERSION)
4963 # if defined(DECVERSEXT)
4964 (void)fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4965 # else
4966 # if defined(DECNLAUTHOR)
4967 (void)fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4968 # else
4969 (void)fprintf (st, "\r\n Math library: %s", DECVERSION);
4970 # endif
4971 # endif
4972 # else
4973 (void)fprintf (st, "\r\n Math library: decNumber, unknown version");
4974 # endif
4975 #endif
4976 #if defined(LOCKLESS)
4977 (void)fprintf (st, "\r\n Atomic operations: ");
4978 # if defined(AIX_ATOMICS)
4979 (void)fprintf (st, "C11 and IBM AIX-style");
4980 # elif defined(BSD_ATOMICS)
4981 (void)fprintf (st, "C11 and FreeBSD-style");
4982 # elif defined(GNU_ATOMICS)
4983 (void)fprintf (st, "C11 and GNU-style");
4984 # elif defined(SYNC_ATOMICS)
4985 (void)fprintf (st, "C11 and GNU sync-style");
4986 # elif defined(ISO_ATOMICS)
4987 (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4988 # elif defined(NT_ATOMICS)
4989 (void)fprintf (st, "C11 and Windows NT interlocked operations");
4990 # endif
4991 #endif
4992 (void)fprintf (st, "\r\n File locking: ");
4993 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4994 (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4995 #endif
4996 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4997 (void)fprintf (st, "POSIX-style fcntl() locking");
4998 #endif
4999 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
5000 (void)fprintf (st, "BSD-style flock() locking");
5001 #endif
5002 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
5003 (void)fprintf (st, "No file locking available");
5004 #endif
5005 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
5006 (void)fprintf (st, "\r\n Windows support: ");
5007 #endif
5008 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
5009 # if defined(__MINGW64_VERSION_STR)
5010 (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
5011 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
5012 (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
5013 # else
5014 (void)fprintf (st, "Built with MinGW");
5015 # endif
5016
5017 # if defined(MINGW_CRT)
5018 (void)fprintf (st, "; %s", MINGW_CRT);
5019 # if !defined(_UCRT)
5020 # if defined(__MSVCRT_VERSION__)
5021 # if __MSVCRT_VERSION__ > 0x00
5022 (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
5023 # endif
5024 # endif
5025 # else
5026
5027 struct UCRTVersion ucrtversion;
5028 int result = GetUCRTVersion (&ucrtversion);
5029
5030 if (result == 0)
5031 (void)fprintf (st, " %u.%u.%u.%u",
5032 ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
5033 ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
5034 # endif
5035 (void)fprintf (st, " in use");
5036 # endif
5037 #elif defined(__CYGWIN__)
5038 struct utsname utsname;
5039 (void)fprintf (st, "Built with Cygwin %d.%d.%d",
5040 CYGWIN_VERSION_DLL_MAJOR / 1000,
5041 CYGWIN_VERSION_DLL_MAJOR % 1000,
5042 CYGWIN_VERSION_DLL_MINOR);
5043 if (uname(&utsname) == 0)
5044 fprintf (st, "; %s in use", utsname.release);
5045 #endif
5046
5047 (void)fprintf (st, "\r\n");
5048 return 0;
5049 }
5050
5051 static void
5052 removehex(char *s)
5053 {
5054 if (!s) return;
5055
5056 size_t len = strlen(s);
5057 for (size_t i = 0; i < len; i++) {
5058 if (s[i] != ' ')
5059 continue;
5060
5061 if ((len - i) < 41)
5062 continue;
5063
5064 size_t j;
5065 for (j = 1; j <= 40; j++) {
5066 unsigned char uc = (unsigned char)s[i + j];
5067 if (!isxdigit(uc))
5068 break;
5069 }
5070
5071 if (j == 41) {
5072 memmove(&s[i], &s[i + 41], strlen(&s[i + 41]) + 1);
5073 return;
5074 }
5075 }
5076 }
5077
5078 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5079 {
5080 const char *arch = "";
5081 char *whydirty = " ";
5082 int dirty = 0;
5083
5084 if (cptr && (*cptr != 0))
5085 return SCPE_2MARG;
5086 if (flag) {
5087 (void)fprintf (st, " %s Simulator:", sim_name);
5088 #if defined(USE_DUMA)
5089 # undef NO_SUPPORT_VERSION
5090 # define NO_SUPPORT_VERSION 1
5091 nodist++;
5092 #endif
5093 #if defined(NO_SUPPORT_VERSION) || \
5094 defined(WITH_SOCKET_DEV) || \
5095 defined(WITH_ABSI_DEV) || \
5096 defined(TESTING) || \
5097 defined(ISOLTS) || \
5098 defined(USE_DUMA)
5099 # if !defined(NO_SUPPORT_VERSION)
5100 # define NO_SUPPORT_VERSION 1
5101 # endif
5102 #endif
5103 #if defined(NO_SUPPORT_VERSION)
5104 dirty++;
5105 #endif
5106 #if defined(GENERATED_MAKE_VER_H)
5107 # if defined(VER_H_GIT_VERSION)
5108
5109
5110 if (strstr(VER_H_GIT_VERSION, "*"))
5111 {
5112 dirty++;
5113 }
5114
5115
5116 if ((strstr(VER_H_GIT_VERSION, "X")) || \
5117 (strstr(VER_H_GIT_VERSION, "D")) || \
5118 (strstr(VER_H_GIT_VERSION, "A")) || \
5119 (strstr(VER_H_GIT_VERSION, "B")))
5120 {
5121 dirty++;
5122 }
5123
5124
5125 if (dirty)
5126 {
5127 if ((strstr(VER_H_GIT_VERSION, "X")))
5128 {
5129 whydirty = " ";
5130 }
5131 else if ((strstr(VER_H_GIT_VERSION, "D")))
5132 {
5133 whydirty = " DEV ";
5134 }
5135 else if ((strstr(VER_H_GIT_VERSION, "A")))
5136 {
5137 whydirty = " ALPHA ";
5138 }
5139 else if ((strstr(VER_H_GIT_VERSION, "B")))
5140 {
5141 whydirty = " BETA ";
5142 }
5143 }
5144
5145 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5146 # if defined(VER_H_GIT_HASH)
5147 # if VER_H_GIT_PATCH_INT < 1
5148 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5149 VER_H_GIT_VERSION,
5150 (long)(CHAR_BIT*sizeof(void *)),
5151 VER_H_GIT_HASH);
5152 # else
5153 # define NO_SUPPORT_VERSION 1
5154 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)\r\n Commit: %s",
5155 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5156 (long)(CHAR_BIT*sizeof(void *)),
5157 VER_H_GIT_HASH);
5158 # endif
5159 # else
5160 # if VER_H_GIT_PATCH_INT < 1
5161 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5162 VER_H_GIT_VERSION,
5163 (long)(CHAR_BIT*sizeof(void *)));
5164 # else
5165 # define NO_SUPPORT_VERSION 1
5166 (void)fprintf (st, "\r\n Version: %s+%s (%ld-bit)",
5167 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5168 (long)(CHAR_BIT*sizeof(void *)));
5169 # endif
5170 # endif
5171 # else
5172 # if defined(VER_H_GIT_HASH)
5173 (void)fprintf (st, "\r\n Version: %s (%ld-bit)\r\n Commit: %s",
5174 VER_H_GIT_VERSION,
5175 (long)(CHAR_BIT*sizeof(void *)),
5176 VER_H_GIT_HASH);
5177 # else
5178 (void)fprintf (st, "\r\n Version: %s (%ld-bit)",
5179 VER_H_GIT_VERSION,
5180 (long)(CHAR_BIT*sizeof(void *)));
5181 # endif
5182 # endif
5183 # endif
5184 #endif
5185
5186
5187 #if defined(TESTING)
5188 (void)fprintf (st, "\r\n Options: ");
5189 # if !defined(HAVE_DPSOPT)
5190 # define HAVE_DPSOPT 1
5191 # endif
5192 (void)fprintf (st, "TESTING");
5193 #endif
5194
5195
5196 #if defined(ISOLTS)
5197 # if defined(HAVE_DPSOPT)
5198 (void)fprintf (st, ", ");
5199 # else
5200 (void)fprintf (st, "\r\n Options: ");
5201 # endif
5202 # if !defined(HAVE_DPSOPT)
5203 # define HAVE_DPSOPT 1
5204 # endif
5205 (void)fprintf (st, "ISOLTS");
5206 #endif
5207
5208
5209 #if defined(NEED_128)
5210 # if defined(HAVE_DPSOPT)
5211 (void)fprintf (st, ", ");
5212 # else
5213 (void)fprintf (st, "\r\n Options: ");
5214 # endif
5215 # if !defined(HAVE_DPSOPT)
5216 # define HAVE_DPSOPT 1
5217 # endif
5218 (void)fprintf (st, "NEED_128");
5219 #endif
5220
5221
5222 #if !defined(LOCKLESS)
5223 # if defined(HAVE_DPSOPT)
5224 (void)fprintf (st, ", ");
5225 # else
5226 (void)fprintf (st, "\r\n Options: ");
5227 # endif
5228 # if !defined(HAVE_DPSOPT)
5229 # define HAVE_DPSOPT 1
5230 # endif
5231 (void)fprintf (st, "NO_LOCKLESS");
5232 #endif
5233
5234
5235 #if defined(PANEL68)
5236 # if defined(HAVE_DPSOPT)
5237 (void)fprintf (st, ", ");
5238 # else
5239 (void)fprintf (st, "\r\n Options: ");
5240 # endif
5241 # if !defined(HAVE_DPSOPT)
5242 # define HAVE_DPSOPT 1
5243 # endif
5244 (void)fprintf (st, "PANEL68");
5245 #endif
5246
5247
5248 #if defined(WITH_ABSI_DEV)
5249 # if defined(HAVE_DPSOPT)
5250 (void)fprintf (st, ", ");
5251 # else
5252 (void)fprintf (st, "\r\n Options: ");
5253 # endif
5254 # if !defined(HAVE_DPSOPT)
5255 # define HAVE_DPSOPT 1
5256 # endif
5257 (void)fprintf (st, "ABSI");
5258 #endif
5259
5260
5261 #if defined(WITH_SOCKET_DEV)
5262 # if defined(HAVE_DPSOPT)
5263 (void)fprintf (st, ", ");
5264 # else
5265 (void)fprintf (st, "\r\n Options: ");
5266 # endif
5267 # if !defined(HAVE_DPSOPT)
5268 # define HAVE_DPSOPT 1
5269 # endif
5270 (void)fprintf (st, "SOCKET");
5271 #endif
5272
5273
5274 #if !defined(WITH_MGP_DEV)
5275 # if defined(HAVE_DPSOPT)
5276 (void)fprintf (st, ", ");
5277 # else
5278 (void)fprintf (st, "\r\n Options: ");
5279 # endif
5280 # if !defined(HAVE_DPSOPT)
5281 # define HAVE_DPSOPT 1
5282 # endif
5283 (void)fprintf (st, "NO_CHAOSNET");
5284 #endif
5285
5286
5287 #if !defined(WITH_NET_DEV)
5288 # if defined(HAVE_DPSOPT)
5289 (void)fprintf (st, ", ");
5290 # else
5291 (void)fprintf (st, "\r\n Options: ");
5292 # endif
5293 # if !defined(HAVE_DPSOPT)
5294 # define HAVE_DPSOPT 1
5295 # endif
5296 (void)fprintf (st, "NO_INTERNET");
5297 #endif
5298
5299
5300 #if defined(USE_DUMA)
5301 # if defined(HAVE_DPSOPT)
5302 (void)fprintf (st, ", ");
5303 # else
5304 (void)fprintf (st, "\r\n Options: ");
5305 # endif
5306 # if !defined(HAVE_DPSOPT)
5307 # define HAVE_DPSOPT 1
5308 # endif
5309 (void)fprintf (st, "DUMA");
5310 #endif
5311
5312 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5313 # if defined(NO_SUPPORT_VERSION)
5314 (void)fprintf (st, "\r\n Modified: %s", VER_H_GIT_DATE);
5315 # else
5316 (void)fprintf (st, "\r\n Released: %s", VER_H_GIT_DATE);
5317 # endif
5318 #endif
5319 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5320 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5321 #endif
5322 #if defined(VER_CURRENT_TIME)
5323 (void)fprintf (st, "\r\n Compiled: %s", VER_CURRENT_TIME);
5324 #endif
5325 if (dirty)
5326 {
5327 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5328 }
5329 (void)fprintf (st, "\r\n\r\n Build Information:");
5330 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5331 char build_os_version_raw[255];
5332 char build_os_arch_raw[255];
5333 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5334 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5335 char *build_os_version = strdup(build_os_version_raw);
5336 if (!build_os_version)
5337 {
5338 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5339 __func__, __FILE__, __LINE__);
5340 # if defined(USE_BACKTRACE)
5341 # if defined(SIGUSR2)
5342 (void)raise(SIGUSR2);
5343
5344 # endif
5345 # endif
5346 abort();
5347 }
5348 char *build_os_arch = strdup(build_os_arch_raw);
5349 if (!build_os_arch)
5350 {
5351 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5352 __func__, __FILE__, __LINE__);
5353 # if defined(USE_BACKTRACE)
5354 # if defined(SIGUSR2)
5355 (void)raise(SIGUSR2);
5356
5357 # endif
5358 # endif
5359 abort();
5360 }
5361 unsigned char SPROM[1024];
5362 setupPROM (0, SPROM);
5363 (void)fprintf (st, "\r\n Target: ");
5364 printpq (SPROM, st, 190, 20);
5365 if (SPROM[170] != 20)
5366 {
5367 if (SPROM[170] != 255)
5368 {
5369 (void)fprintf (st, " on ");
5370 printpq (SPROM, st, 170, 20);
5371 }
5372 }
5373 strtrimspace(build_os_version, build_os_version_raw);
5374 strtrimspace(build_os_arch, build_os_arch_raw);
5375 (void)fprintf (st, "\r\n Build OS: %s %s", build_os_version, build_os_arch);
5376 FREE(build_os_version);
5377 FREE(build_os_arch);
5378 #endif
5379 #if defined(__VERSION__)
5380 char gnumver[2];
5381 char postver[1024];
5382 (void)sprintf(gnumver, "%.1s", __VERSION__);
5383 (void)sprintf(postver, "%.1023s", __VERSION__);
5384 strremove(postver, "(TM)");
5385 strremove(postver, "(R)");
5386 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5387 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5388 strremove(postver, " gcc 4.9 mode");
5389 strremove(postver, "4.2.1 Compatible ");
5390 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5391 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5392 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5393 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5394 strremove(postver, "(experimental) ");
5395 strremove(postver, ".module+el8.7.0+20823+214a699d");
5396 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5397 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5398 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5399 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5400 strremove(postver, "llvmorg-16.0.6-0-");
5401 strremove(postver, " Clang 15.0.0 (build 760095e)");
5402 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5403 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5404 strremove(postver, " Clang 15.0.0 (build 232543c)");
5405 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5406 strremove(postver, "CLANG: ");
5407 removehex(postver);
5408 strremove(postver, " (git@github.com:pizlonator/llvm-project-deluge.git)");
5409 #endif
5410 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5411 # if !defined(__clang_version__)
5412 if (isdigit((unsigned char)gnumver[0])) {
5413 (void)fprintf (st, "\r\n Compiler: GCC %s", postver);
5414 } else {
5415 (void)fprintf (st, "\r\n Compiler: %s", postver);
5416 }
5417 # endif
5418 # if defined(__clang_analyzer__ )
5419 (void)fprintf (st, "\r\n Compiler: Clang C/C++ Static Analyzer");
5420 # elif defined(__clang_version__) && defined(__VERSION__)
5421 char clangllvmver[1024];
5422 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5423 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5424 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5425 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5426 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5427 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5428 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5429 strremove(clangllvmver, " ( )");
5430 strremove(clangllvmver, " ()");
5431 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5432 (void)fprintf (st, "\r\n Compiler: Clang %s", clangllvmver);
5433 } else {
5434 (void)fprintf (st, "\r\n Compiler: %s", postver);
5435 }
5436 # elif defined(__clang_version__)
5437 (void)fprintf (st, "\r\n Compiler: %s", postver);
5438 # endif
5439 #elif defined(__PGI) && !defined(__NVCOMPILER)
5440 (void)fprintf (st, "\r\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5441 # if defined(__PGIC__)
5442 (void)fprintf (st, "%d", __PGIC__);
5443 # if defined(__PGIC_MINOR__)
5444 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5445 # if defined(__PGIC_PATCHLEVEL__)
5446 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5447 # endif
5448 # endif
5449 # endif
5450 #elif defined(__NVCOMPILER)
5451 (void)fprintf (st, "\r\n Compiler: NVIDIA HPC SDK C Compiler ");
5452 # if defined(__NVCOMPILER_MAJOR__)
5453 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5454 # if defined(__NVCOMPILER_MINOR__)
5455 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5456 # if defined(__NVCOMPILER_PATCHLEVEL__)
5457 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5458 # endif
5459 # endif
5460 # endif
5461 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5462 (void)fprintf (st, "\r\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5463 _MSC_FULL_VER/10000000,
5464 (_MSC_FULL_VER/100000)%100,
5465 _MSC_FULL_VER%100000,
5466 _MSC_BUILD);
5467 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5468 # if defined(_AIX) && defined(__PASE__)
5469 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5470 # endif
5471 # if defined(_AIX) && !defined(__PASE__)
5472 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5473 # endif
5474 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5475 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5476 # endif
5477 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5478 # if defined(__PPC__) && defined(__APPLE__)
5479 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5480 # else
5481 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++ V%s", __xlc__);
5482 # endif
5483 # endif
5484 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5485 # define VER_ENC(maj, min, rev) \
5486 (((maj) * 1000000) + ((min) * 1000) + (rev))
5487 # define VER_DEC_MAJ(ver) \
5488 ((ver) / 1000000)
5489 # define VER_DEC_MIN(ver) \
5490 (((ver) % 1000000) / 1000)
5491 # define VER_DEC_REV(ver) \
5492 ((ver) % 1000)
5493 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5494 # define COMP_VER VER_ENC( \
5495 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5496 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5497 (__SUNPRO_C & 0xf) * 10)
5498 # elif defined(__SUNPRO_C)
5499 # define COMP_VER VER_ENC( \
5500 (__SUNPRO_C >> 8) & 0xf, \
5501 (__SUNPRO_C >> 4) & 0xf, \
5502 (__SUNPRO_C) & 0xf)
5503 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5504 # define COMP_VER VER_ENC( \
5505 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5506 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5507 (__SUNPRO_CC & 0xf) * 10)
5508 # elif defined(__SUNPRO_CC)
5509 # define COMP_VER VER_ENC( \
5510 (__SUNPRO_CC >> 8) & 0xf, \
5511 (__SUNPRO_CC >> 4) & 0xf, \
5512 (__SUNPRO_CC) & 0xf)
5513 # endif
5514 # if !defined(COMP_VER)
5515 # define COMP_VER 0
5516 # endif
5517 (void)fprintf (st, "\r\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5518 VER_DEC_MAJ(COMP_VER),
5519 VER_DEC_MIN(COMP_VER),
5520 VER_DEC_REV(COMP_VER));
5521 #elif defined(__DMC__)
5522 (void)fprintf (st, "\r\n Compiler: Digital Mars C/C++");
5523 #elif defined(__PCC__)
5524 (void)fprintf (st, "\r\n Compiler: Portable C Compiler");
5525 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5526 (void)fprintf (st, "\r\n Compiler: Plan 9 Compiler Suite");
5527 #elif defined(__ACK__)
5528 (void)fprintf (st, "\r\n Compiler: Amsterdam Compiler Kit");
5529 #elif defined(__COMO__)
5530 (void)fprintf (st, "\r\n Compiler: Comeau C++");
5531 #elif defined(__COMPCERT__)
5532 (void)fprintf (st, "\r\n Compiler: CompCert C");
5533 #elif defined(__COVERITY__)
5534 (void)fprintf (st, "\r\n Compiler: Coverity C/C++ Static Analyzer");
5535 #elif defined(__LCC__)
5536 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5537 (void)fprintf (st, "\r\n Compiler: MCST Elbrus C Compiler");
5538 # if __LCC__ > 99
5539 (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5540 # if defined(__LCC_MINOR__)
5541 # if __LCC_MINOR__ > 0
5542 (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5543 # endif
5544 # endif
5545 # endif
5546 # if defined(__EDG__) && defined(__EDG_VERSION__)
5547 # if __EDG_VERSION__ > 99
5548 (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5549 (int)(((__EDG_VERSION__) % 100) % 10));
5550 # endif
5551 # endif
5552 # else
5553 (void)fprintf (st, "\r\n Compiler: Local/Little C Compiler (lcc)");
5554 # endif
5555 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5556 (void)fprintf (st, "\r\n Compiler: SGI MIPSpro");
5557 #elif defined(__OPEN64__)
5558 (void)fprintf (st, "\r\n Compiler: Open64 %s", __OPEN64__);
5559 #elif defined(__PGI) || defined(__PGIC__)
5560 (void)fprintf (st, "\r\n Compiler: Portland Group/PGI C/C++");
5561 #elif defined(__VBCC__)
5562 (void)fprintf (st, "\r\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5563 #elif defined(__WATCOMC__)
5564 (void)fprintf (st, "\r\n Compiler: Watcom C/C++ %d.%d",
5565 __WATCOMC__ / 100,
5566 __WATCOMC__ % 100);
5567 #elif defined(__xlC__)
5568 (void)fprintf (st, "\r\n Compiler: IBM XL C/C++");
5569 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5570 # if defined(__INTEL_COMPILER_UPDATE)
5571 # if defined(__INTEL_COMPILER_BUILD_DATE)
5572 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d (%d)",
5573 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5574 __INTEL_COMPILER_BUILD_DATE);
5575 # else
5576 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d.%d",
5577 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5578 # endif
5579 # else
5580 (void)fprintf (st, "\r\n Compiler: Intel C++ Compiler %d",
5581 __INTEL_COMPILER);
5582 # endif
5583 #elif defined(SIM_COMPILER)
5584 # define S_xstr(a) S_str(a)
5585 # define S_str(a) #a
5586 (void)fprintf (st, "\r\n Compiler: %s", S_xstr(SIM_COMPILER));
5587 # undef S_str
5588 # undef S_xstr
5589 #else
5590 (void)fprintf (st, "\r\n Compiler: Unknown");
5591 #endif
5592
5593 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5594 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5595 # define SC_IS_PPC64 1
5596 #else
5597 # define SC_IS_PPC64 0
5598 #endif
5599
5600 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5601 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5602 defined(__PPC32)
5603 # define SC_IS_PPC32 1
5604 #else
5605 # define SC_IS_PPC32 0
5606 #endif
5607
5608 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5609 arch = " x86_64";
5610 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5611 arch = " x86";
5612 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5613 arch = " arm64";
5614 #elif defined(_M_ARM) || defined(__arm__)
5615 arch = " arm";
5616 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5617 arch = " ia64";
5618 #elif SC_IS_PPC64
5619 arch = " powerpc64";
5620 #elif SC_IS_PPC32
5621 arch = " powerpc";
5622 #elif defined(__s390x__)
5623 arch = " s390x";
5624 #elif defined(__s390__)
5625 arch = " s390";
5626 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5627 arch = " j2";
5628 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5629 arch = " sh4";
5630 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5631 arch = " sh2";
5632 #elif defined(__alpha__)
5633 arch = " alpha";
5634 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5635 arch = " hppa";
5636 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5637 arch = " ice9";
5638 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5639 arch = " mips64";
5640 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5641 arch = " mips";
5642 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5643 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5644 arch = " openrisc";
5645 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5646 arch = " sparc64";
5647 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5648 arch = " sparc";
5649 #elif defined(__riscv) || defined(__riscv__)
5650 arch = " riscv";
5651 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5652 arch = " e2k";
5653 #elif defined(__myriad2__)
5654 arch = " myriad2";
5655 #elif defined(__loongarch64) || defined(__loongarch__)
5656 arch = " loongarch";
5657 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5658 arch = " m68k";
5659 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5660 arch = " m88k";
5661 #elif defined(__VAX__) || defined(__vax__)
5662 arch = " vax";
5663 #elif defined(__NIOS2__) || defined(__nios2__)
5664 arch = " nios2";
5665 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5666 arch = " microblaze";
5667 #else
5668 arch = " ";
5669 #endif
5670 (void)fprintf (st, "%s", arch);
5671 #if defined(BUILD_BY_USER)
5672 (void)fprintf (st, "\r\n Built by: %s", BUILD_BY_USER);
5673 #else
5674 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5675 (void)fprintf (st, "\r\n Built by: %s", VER_H_PREP_USER);
5676 # endif
5677 #endif
5678 (void)fprintf (st, "\r\n\r\n Host System Information:");
5679 #if defined(_WIN32)
5680 if (1) {
5681 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5682 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5683 char osversion[PATH_MAX+1] = "";
5684 FILE *f;
5685
5686 if ((f = _popen ("ver", "r"))) {
5687 (void)memset (osversion, 0, sizeof(osversion));
5688 do {
5689 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5690 break;
5691 sim_trim_endspc (osversion);
5692 } while (osversion[0] == '\0');
5693 _pclose (f);
5694 }
5695 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5696 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5697 }
5698 #else
5699 if (1) {
5700 char osversion[2*PATH_MAX+1] = "";
5701 FILE *f;
5702 # if !defined(_AIX)
5703 if ((f = popen \
5704 ("uname -mrs 2> /dev/null", "r"))) {
5705 # else
5706 if ((f = popen \
5707 ("sh -c 'echo \"$(command -p env uname -v \
5708 2> /dev/null).$(command -p env uname -r \
5709 2> /dev/null) $(command -p env uname -p \
5710 2> /dev/null)\"' 2> /dev/null", "r"))) {
5711 # endif
5712 (void)memset (osversion, 0, sizeof(osversion));
5713 do {
5714 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5715 break;
5716 }
5717 sim_trim_endspc (osversion);
5718 } while (osversion[0] == '\0');
5719 pclose (f);
5720 strremove(osversion, "0000000000000000 ");
5721 strremove(osversion, " 0000000000000000");
5722 strremove(osversion, "000000000000 ");
5723 strremove(osversion, " 000000000000");
5724 strremove(osversion, "IBM ");
5725 strremove(osversion, " (emulated by qemu)");
5726 strremove(osversion, " (emulated by QEMU)");
5727 }
5728 # if !defined(_AIX)
5729 (void)fprintf (st, "\r\n Host OS: %s", osversion);
5730 # else
5731 strremove(osversion, "AIX ");
5732 # if !defined(__PASE__)
5733 (void)fprintf (st, "\r\n Host OS: IBM AIX %s", osversion);
5734 # else
5735 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE) %s", osversion);
5736 # endif
5737 # endif
5738 } else {
5739 # if !defined(_AIX)
5740 (void)fprintf (st, "\r\n Host OS: Unknown");
5741 # else
5742 # if !defined(__PASE__)
5743 (void)fprintf (st, "\r\n Host OS: IBM AIX");
5744 # else
5745 (void)fprintf (st, "\r\n Host OS: IBM OS/400 (PASE)");
5746 # endif
5747 # endif
5748 }
5749 #endif
5750 if (nodist)
5751 {
5752 sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5753 }
5754 else
5755 {
5756 (void)fprintf (st, "\r\n");
5757 (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5758 (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5759 (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5760 }
5761 (void)fprintf (st, "\r\n");
5762 }
5763 return SCPE_OK;
5764 }
5765
5766 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5767 {
5768 size_t i;
5769 DEVICE *dptr;
5770 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5771
5772 if (cptr && (*cptr != 0))
5773 return SCPE_2MARG;
5774 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5775 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5776 if (!only_enabled || !qdisable (dptr))
5777 show_device (st, dptr, flag);
5778 return SCPE_OK;
5779 }
5780
5781 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5782 {
5783 int32 i;
5784 DEVICE *dptr;
5785
5786 if (cptr && (*cptr != 0))
5787 return SCPE_2MARG;
5788 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5789 show_dev_logicals (st, dptr, NULL, 1, cptr);
5790 return SCPE_OK;
5791 }
5792
5793 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5794 {
5795 if (dptr->lname)
5796 (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5797 else if (!flag)
5798 fputs ("no logical name assigned\r\n", st);
5799 return SCPE_OK;
5800 }
5801
5802 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5803 {
5804 DEVICE *dptr;
5805 UNIT *uptr;
5806 int32 accum;
5807
5808 if (cptr && (*cptr != 0))
5809 return SCPE_2MARG;
5810 if (sim_clock_queue == QUEUE_LIST_END)
5811 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5812 sim_name, sim_time, sim_timer_inst_per_sec ());
5813 else {
5814 const char *tim;
5815
5816 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5817 sim_name, sim_time, sim_timer_inst_per_sec ());
5818 accum = 0;
5819 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5820 if (uptr == &sim_step_unit)
5821 (void)fprintf (st, " Step timer");
5822 else
5823 if (uptr == &sim_expect_unit)
5824 (void)fprintf (st, " Expect fired");
5825 else
5826 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5827 (void)fprintf (st, " %s", sim_dname (dptr));
5828 if (dptr->numunits > 1)
5829 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5830 }
5831 else
5832 (void)fprintf (st, " Unknown");
5833 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5834 (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5835 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5836 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5837 accum = accum + uptr->time;
5838 }
5839 }
5840 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5841 return SCPE_OK;
5842 }
5843
5844 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5845 {
5846 if (cptr && (*cptr != 0))
5847 return SCPE_2MARG;
5848 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5849 return SCPE_OK;
5850 }
5851
5852 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5853 {
5854 t_stat r;
5855
5856 if (cptr && (*cptr != 0))
5857 r = ssh_break (st, cptr, 1);
5858 else
5859 r = sim_brk_showall (st, (uint32)sim_switches);
5860 return r;
5861 }
5862
5863 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5864 {
5865 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5866 return SCPE_OK;
5867 }
5868
5869 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5870 {
5871 int32 any = 0;
5872 DEBTAB *dep;
5873
5874 if (dptr->flags & DEV_DEBUG) {
5875 if (dptr->dctrl == 0)
5876 fputs ("Debugging disabled", st);
5877 else if (dptr->debflags == NULL)
5878 fputs ("Debugging enabled", st);
5879 else {
5880 uint32 dctrl = dptr->dctrl;
5881
5882 fputs ("Debug=", st);
5883 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5884 if ((dctrl & dep->mask) == dep->mask) {
5885 dctrl &= ~dep->mask;
5886 if (any)
5887 fputc (';', st);
5888 fputs (dep->name, st);
5889 any = 1;
5890 }
5891 }
5892 }
5893 fputc ('\n', st);
5894 return SCPE_OK;
5895 }
5896 else return SCPE_NOFNC;
5897 }
5898
5899
5900
5901 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5902 {
5903 int32 lvl, i;
5904
5905 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5906 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5907 if (lvl > 0)
5908 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5909 else
5910 (void)fprintf(st, "On Processing for input commands");
5911 (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5912 for (i=1; i<SCPE_BASE; ++i) {
5913 if (sim_on_actions[lvl][i])
5914 (void)fprintf(st, " on %5d %s\r\n", i, sim_on_actions[lvl][i]); }
5915 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5916 if (sim_on_actions[lvl][i])
5917 (void)fprintf(st, " on %-5s %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5918 if (sim_on_actions[lvl][0])
5919 (void)fprintf(st, " on ERROR %s\r\n", sim_on_actions[lvl][0]);
5920 (void)fprintf(st, "\r\n");
5921 }
5922 if (sim_on_inherit)
5923 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5924 return SCPE_OK;
5925 }
5926
5927
5928
5929 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5930 {
5931 int32 i;
5932 DEVICE *dptr;
5933
5934 if (cptr && (*cptr != 0))
5935 return SCPE_2MARG;
5936 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5937 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5938 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5939 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5940 return SCPE_OK;
5941 }
5942
5943 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5944 {
5945 fprint_set_help (st, dptr);
5946 return SCPE_OK;
5947 }
5948
5949 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5950 {
5951 MTAB *mptr;
5952 t_stat r = SCPE_OK;
5953
5954 if (dptr->modifiers == NULL)
5955 return SCPE_OK;
5956 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5957 if (mptr->pstring &&
5958 ((mptr->mask & MTAB_XTD)?
5959 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5960 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5961 if (*toks > 0) {
5962 (void)fprintf (st, "\r\n");
5963 *toks = 0;
5964 }
5965 if (r == SCPE_OK)
5966 fprint_sep (st, toks);
5967 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5968 }
5969 }
5970 return SCPE_OK;
5971 }
5972
5973 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5974 CONST char *cptr, int32 flag)
5975 {
5976 t_stat r = SCPE_OK;
5977
5978 if (mptr->disp)
5979 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5980 else
5981 fputs (mptr->pstring, st);
5982 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5983 fputc ('\n', st);
5984 return r;
5985 }
5986
5987
5988
5989 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5990 {
5991 int32 i;
5992 DEVICE *dptr;
5993
5994 if (cptr && (*cptr != 0))
5995 return SCPE_2MARG;
5996 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5997 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5998 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5999 show_dev_show_commands (st, dptr, NULL, flag, cptr);
6000 return SCPE_OK;
6001 }
6002
6003 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
6004 {
6005 fprint_show_help (st, dptr);
6006 return SCPE_OK;
6007 }
6008
6009
6010
6011 t_stat brk_cmd (int32 flg, CONST char *cptr)
6012 {
6013 GET_SWITCHES (cptr);
6014 return ssh_break (NULL, cptr, flg);
6015 }
6016
6017 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
6018 {
6019 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
6020 CONST char *tptr, *t1ptr;
6021 DEVICE *dptr = sim_dflt_dev;
6022 UNIT *uptr;
6023 t_stat r;
6024 t_addr lo, hi, max;
6025 int32 cnt;
6026
6027 if (sim_brk_types == 0)
6028 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6029 if (dptr == NULL)
6030 return SCPE_IERR;
6031 uptr = dptr->units;
6032 if (uptr == NULL)
6033 return SCPE_IERR;
6034 max = uptr->capac - 1;
6035 abuf[sizeof(abuf)-1] = '\0';
6036 strncpy (abuf, cptr, sizeof(abuf)-1);
6037 cptr = abuf;
6038 if ((aptr = strchr (abuf, ';'))) {
6039 if (flg != SSH_ST)
6040 return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
6041 *aptr++ = 0;
6042 }
6043 if (*cptr == 0) {
6044 lo = (t_addr) get_rval (sim_PC, 0);
6045 return ssh_break_one (st, flg, lo, 0, aptr);
6046 }
6047 while (*cptr) {
6048 cptr = get_glyph (cptr, gbuf, ',');
6049 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
6050 if (tptr == NULL)
6051 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
6052 if (*tptr == '[') {
6053 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
6054 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
6055 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
6056 tptr = t1ptr + 1;
6057 }
6058 else cnt = 0;
6059 if (*tptr != 0)
6060 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
6061 if ((lo == 0) && (hi == max)) {
6062 if (flg == SSH_CL)
6063 sim_brk_clrall (sim_switches);
6064 else
6065 if (flg == SSH_SH)
6066 sim_brk_showall (st, (uint32)sim_switches);
6067 else
6068 return SCPE_ARG;
6069 }
6070 else {
6071 for ( ; lo <= hi; lo = lo + 1) {
6072 r = ssh_break_one (st, flg, lo, cnt, aptr);
6073 if (r != SCPE_OK)
6074 return r;
6075 }
6076 }
6077 }
6078 return SCPE_OK;
6079 }
6080
6081 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
6082 {
6083 if (!sim_brk_types)
6084 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6085 switch (flg) {
6086 case SSH_ST:
6087 return sim_brk_set (lo, sim_switches, cnt, aptr);
6088
6089 break;
6090
6091 case SSH_CL:
6092 return sim_brk_clr (lo, sim_switches);
6093
6094 break;
6095
6096 case SSH_SH:
6097 return sim_brk_show (st, lo, sim_switches);
6098
6099 break;
6100
6101 default:
6102 return SCPE_ARG;
6103 }
6104 }
6105
6106
6107
6108 static t_bool run_cmd_did_reset = FALSE;
6109
6110 t_stat reset_cmd (int32 flag, CONST char *cptr)
6111 {
6112 char gbuf[CBUFSIZE];
6113 DEVICE *dptr;
6114
6115 GET_SWITCHES (cptr);
6116 run_cmd_did_reset = FALSE;
6117 if (*cptr == 0)
6118 return (reset_all (0));
6119 cptr = get_glyph (cptr, gbuf, 0);
6120 if (*cptr != 0)
6121 return SCPE_2MARG;
6122 if (strcmp (gbuf, "ALL") == 0)
6123 return (reset_all (0));
6124 dptr = find_dev (gbuf);
6125 if (dptr == NULL)
6126 return SCPE_NXDEV;
6127 if (dptr->reset != NULL)
6128 return dptr->reset (dptr);
6129 else return SCPE_OK;
6130 }
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140 t_stat reset_all (uint32 start)
6141 {
6142 DEVICE *dptr;
6143 uint32 i;
6144 t_stat reason;
6145
6146 for (i = 0; i < start; i++) {
6147 if (sim_devices[i] == NULL)
6148 return SCPE_IERR;
6149 }
6150 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6151 if (dptr->reset != NULL) {
6152 reason = dptr->reset (dptr);
6153 if (reason != SCPE_OK)
6154 return reason;
6155 }
6156 }
6157 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6158 if (dptr->reset != NULL) {
6159 reason = dptr->reset (dptr);
6160 if (reason != SCPE_OK)
6161 return reason;
6162 }
6163 }
6164 return SCPE_OK;
6165 }
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175 t_stat reset_all_p (uint32 start)
6176 {
6177 t_stat r;
6178 int32 old_sw = sim_switches;
6179
6180 sim_switches = SWMASK ('P');
6181 r = reset_all (start);
6182 sim_switches = old_sw;
6183 return r;
6184 }
6185
6186
6187
6188 t_stat attach_cmd (int32 flag, CONST char *cptr)
6189 {
6190 char gbuf[4*CBUFSIZE];
6191 DEVICE *dptr;
6192 UNIT *uptr;
6193 t_stat r;
6194
6195 GET_SWITCHES (cptr);
6196 if ((NULL == cptr) || (*cptr == 0))
6197 return SCPE_2FARG;
6198 cptr = get_glyph (cptr, gbuf, 0);
6199 GET_SWITCHES (cptr);
6200 if ((NULL == cptr) || (*cptr == 0))
6201 return SCPE_2FARG;
6202 dptr = find_unit (gbuf, &uptr);
6203 if (dptr == NULL)
6204 return SCPE_NXDEV;
6205 if (uptr == NULL)
6206 return SCPE_NXUN;
6207 if (uptr->flags & UNIT_ATT) {
6208 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6209 !(dptr->flags & DEV_DONTAUTO)) {
6210 r = scp_detach_unit (dptr, uptr);
6211 if (r != SCPE_OK)
6212 return r; }
6213 else {
6214 if (!(uptr->dynflags & UNIT_ATTMULT))
6215 return SCPE_ALATT;
6216 }
6217 }
6218 gbuf[sizeof(gbuf)-1] = '\0';
6219 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6220 sim_trim_endspc (gbuf);
6221 return scp_attach_unit (dptr, uptr, gbuf);
6222 }
6223
6224
6225
6226 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6227 {
6228 if (dptr->attach != NULL)
6229 return dptr->attach (uptr, (CONST char *)cptr);
6230 return attach_unit (uptr, (CONST char *)cptr);
6231 }
6232
6233
6234
6235 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6236 {
6237 DEVICE *dptr;
6238
6239 if (uptr->flags & UNIT_DIS)
6240 return SCPE_UDIS;
6241 if (!(uptr->flags & UNIT_ATTABLE))
6242 return SCPE_NOATT;
6243 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6244 return SCPE_NOATT;
6245 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6246 if (uptr->filename == NULL)
6247 return SCPE_MEM;
6248 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6249 if ((sim_switches & SWMASK ('R')) ||
6250 ((uptr->flags & UNIT_RO) != 0)) {
6251 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6252 ((uptr->flags & UNIT_RO) == 0))
6253 return attach_err (uptr, SCPE_NORO);
6254 uptr->fileref = sim_fopen (cptr, "rb");
6255 if (uptr->fileref == NULL)
6256 return attach_err (uptr, SCPE_OPENERR);
6257 uptr->flags = uptr->flags | UNIT_RO;
6258 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6259 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6260 }
6261 }
6262 else {
6263 if (sim_switches & SWMASK ('N')) {
6264 uptr->fileref = sim_fopen (cptr, "wb+");
6265 if (uptr->fileref == NULL)
6266 return attach_err (uptr, SCPE_OPENERR);
6267 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6268 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6269 }
6270 }
6271 else {
6272 uptr->fileref = sim_fopen (cptr, "rb+");
6273 if (uptr->fileref == NULL) {
6274 #if defined(EWOULDBLOCK)
6275 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6276 #else
6277 if ((errno == EAGAIN))
6278 #endif
6279 return attach_err (uptr, SCPE_OPENERR);
6280
6281 #if defined(EPERM)
6282 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6283 #else
6284 if ((errno == EROFS) || (errno == EACCES)) {
6285 #endif
6286 if ((uptr->flags & UNIT_ROABLE) == 0)
6287 return attach_err (uptr, SCPE_NORO);
6288 uptr->fileref = sim_fopen (cptr, "rb");
6289 if (uptr->fileref == NULL)
6290 return attach_err (uptr, SCPE_OPENERR);
6291 uptr->flags = uptr->flags | UNIT_RO;
6292 if (!sim_quiet) {
6293 sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6294 }
6295 }
6296 else {
6297 if (sim_switches & SWMASK ('E'))
6298 return attach_err (uptr, SCPE_OPENERR);
6299 uptr->fileref = sim_fopen (cptr, "wb+");
6300 if (uptr->fileref == NULL)
6301 return attach_err (uptr, SCPE_OPENERR);
6302 if (!sim_quiet) {
6303 sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6304 }
6305 }
6306 }
6307 }
6308 }
6309 if (uptr->flags & UNIT_BUFABLE) {
6310 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6311 if (uptr->flags & UNIT_MUSTBUF)
6312 uptr->filebuf = calloc (cap, SZ_D (dptr));
6313 if (uptr->filebuf == NULL)
6314 return attach_err (uptr, SCPE_MEM);
6315 if (!sim_quiet) {
6316 sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6317 }
6318 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6319 SZ_D (dptr), cap, uptr->fileref);
6320 uptr->flags = uptr->flags | UNIT_BUF;
6321 }
6322 uptr->flags = uptr->flags | UNIT_ATT;
6323 uptr->pos = 0;
6324 return SCPE_OK;
6325 }
6326
6327 t_stat attach_err (UNIT *uptr, t_stat stat)
6328 {
6329 FREE (uptr->filename);
6330 uptr->filename = NULL;
6331 return stat;
6332 }
6333
6334
6335
6336 t_stat detach_cmd (int32 flag, CONST char *cptr)
6337 {
6338 char gbuf[CBUFSIZE];
6339 DEVICE *dptr;
6340 UNIT *uptr;
6341
6342 GET_SWITCHES (cptr);
6343 if ((NULL == cptr) || (*cptr == 0))
6344 return SCPE_2FARG;
6345 cptr = get_glyph (cptr, gbuf, 0);
6346 if (*cptr != 0)
6347 return SCPE_2MARG;
6348 if (strcmp (gbuf, "ALL") == 0)
6349 return (detach_all (0, FALSE));
6350 dptr = find_unit (gbuf, &uptr);
6351 if (dptr == NULL)
6352 return SCPE_NXDEV;
6353 if (uptr == NULL)
6354 return SCPE_NXUN;
6355 return scp_detach_unit (dptr, uptr);
6356 }
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371 t_stat detach_all (int32 start, t_bool shutdown)
6372 {
6373 uint32 i, j;
6374 DEVICE *dptr;
6375 UNIT *uptr;
6376 t_stat r;
6377
6378 if ((start < 0) || (start > 1))
6379 return SCPE_IERR;
6380 if (shutdown)
6381 sim_switches = sim_switches | SIM_SW_SHUT;
6382 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6383 for (j = 0; j < dptr->numunits; j++) {
6384 uptr = (dptr->units) + j;
6385 if ((uptr->flags & UNIT_ATT) ||
6386 (shutdown && dptr->detach &&
6387 !(uptr->flags & UNIT_ATTABLE))) {
6388 r = scp_detach_unit (dptr, uptr);
6389
6390 if ((r != SCPE_OK) && !shutdown)
6391 return r;
6392 }
6393 }
6394 }
6395 return SCPE_OK;
6396 }
6397
6398
6399
6400 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6401 {
6402 if (dptr->detach != NULL)
6403 return dptr->detach (uptr);
6404 return detach_unit (uptr);
6405 }
6406
6407
6408
6409 t_stat detach_unit (UNIT *uptr)
6410 {
6411 DEVICE *dptr;
6412
6413 if (uptr == NULL)
6414 return SCPE_IERR;
6415 if (!(uptr->flags & UNIT_ATTABLE))
6416 return SCPE_NOATT;
6417 if (!(uptr->flags & UNIT_ATT)) {
6418 if (sim_switches & SIM_SW_REST)
6419 return SCPE_OK;
6420 else
6421 return SCPE_NOTATT;
6422 }
6423 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6424 return SCPE_OK;
6425 if (uptr->flags & UNIT_BUF) {
6426 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6427 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6428 if (!sim_quiet) {
6429 sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6430 }
6431 rewind (uptr->fileref);
6432 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6433 if (ferror (uptr->fileref))
6434 sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6435 sim_dname (dptr), xstrerror_l(errno), errno);
6436 }
6437 if (uptr->flags & UNIT_MUSTBUF) {
6438 FREE (uptr->filebuf);
6439 uptr->filebuf = NULL;
6440 }
6441 uptr->flags = uptr->flags & ~UNIT_BUF;
6442 }
6443 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6444 FREE (uptr->filename);
6445 uptr->filename = NULL;
6446 if (fclose (uptr->fileref) == EOF)
6447 return SCPE_IOERR;
6448 return SCPE_OK;
6449 }
6450
6451
6452
6453 const char *sim_dname (DEVICE *dptr)
6454 {
6455 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6456 }
6457
6458
6459
6460 const char *sim_uname (UNIT *uptr)
6461 {
6462 DEVICE *d = find_dev_from_unit(uptr);
6463 static char uname[CBUFSIZE];
6464
6465 if (!d)
6466 return "";
6467 if (d->numunits == 1)
6468 return sim_dname (d);
6469 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6470 return uname;
6471 }
6472
6473
6474
6475 t_stat run_cmd (int32 flag, CONST char *cptr)
6476 {
6477 char gbuf[CBUFSIZE] = "";
6478 CONST char *tptr;
6479 uint32 i, j;
6480 int32 sim_next = 0;
6481 int32 unitno;
6482 t_value pcv, orig_pcv;
6483 t_stat r;
6484 DEVICE *dptr;
6485 UNIT *uptr;
6486
6487 GET_SWITCHES (cptr);
6488 sim_step = 0;
6489 if ((flag == RU_RUN) || (flag == RU_GO)) {
6490 orig_pcv = get_rval (sim_PC, 0);
6491 if (*cptr != 0) {
6492 cptr = get_glyph (cptr, gbuf, 0);
6493 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6494 if (sim_dflt_dev && sim_vm_parse_addr)
6495 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6496 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6497 if ((tptr == gbuf) || (*tptr != 0) ||
6498 (pcv > width_mask[sim_PC->width]))
6499 return SCPE_ARG;
6500 put_rval (sim_PC, 0, pcv);
6501 }
6502 }
6503 if ((flag == RU_RUN) &&
6504 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6505 put_rval (sim_PC, 0, orig_pcv);
6506 return r;
6507 }
6508 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6509 int32 saved_switches = sim_switches;
6510
6511 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6512 cptr = get_glyph (cptr, gbuf, 0);
6513 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6514 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6515 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6516 sim_switches = 0;
6517 GET_SWITCHES (cptr);
6518 if ((*cptr == '\'') || (*cptr == '"')) {
6519 r = expect_cmd (1, cptr);
6520 if (r != SCPE_OK)
6521 return r;
6522 }
6523 else {
6524 if (sim_switches == 0)
6525 sim_switches = sim_brk_dflt;
6526 sim_switches |= BRK_TYP_TEMP;
6527 sim_brk_types |= BRK_TYP_TEMP;
6528 r = ssh_break (NULL, cptr, SSH_ST);
6529 if (r != SCPE_OK)
6530 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6531 }
6532 sim_switches = saved_switches;
6533 }
6534 }
6535
6536 else if ((flag == RU_STEP) ||
6537 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6538 static t_bool not_implemented_message = FALSE;
6539
6540 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6541 not_implemented_message = TRUE;
6542 flag = RU_STEP;
6543 }
6544 if (*cptr != 0) {
6545 cptr = get_glyph (cptr, gbuf, 0);
6546 if (*cptr != 0)
6547 return SCPE_2MARG;
6548 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6549 if ((r != SCPE_OK) || (sim_step <= 0))
6550 return SCPE_ARG;
6551 }
6552 else sim_step = 1;
6553 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6554 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6555 }
6556 else if (flag == RU_NEXT) {
6557 t_addr *addrs;
6558
6559 if (*cptr != 0) {
6560 cptr = get_glyph (cptr, gbuf, 0);
6561 if (*cptr != 0)
6562 return SCPE_2MARG;
6563 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6564 if ((r != SCPE_OK) || (sim_next <= 0))
6565 return SCPE_ARG;
6566 }
6567 else sim_next = 1;
6568 if (sim_vm_is_subroutine_call(&addrs)) {
6569 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6570 for (i=0; addrs[i]; i++)
6571 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6572 }
6573 else
6574 sim_step = 1;
6575 }
6576 else if (flag == RU_BOOT) {
6577 if (*cptr == 0)
6578 return SCPE_2FARG;
6579 cptr = get_glyph (cptr, gbuf, 0);
6580 if (*cptr != 0)
6581 return SCPE_2MARG;
6582 dptr = find_unit (gbuf, &uptr);
6583 if (dptr == NULL)
6584 return SCPE_NXDEV;
6585 if (uptr == NULL)
6586 return SCPE_NXUN;
6587 if (dptr->boot == NULL)
6588 return SCPE_NOFNC;
6589 if (uptr->flags & UNIT_DIS)
6590 return SCPE_UDIS;
6591 if ((uptr->flags & UNIT_ATTABLE) &&
6592 !(uptr->flags & UNIT_ATT))
6593 return SCPE_UNATT;
6594 unitno = (int32) (uptr - dptr->units);
6595 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6596 return r;
6597 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6598 return r;
6599 }
6600
6601 else
6602 if (flag != RU_CONT)
6603 return SCPE_IERR;
6604 else
6605 if (*cptr != 0)
6606 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6607
6608 if (sim_switches & SIM_SW_HIDE)
6609 return SCPE_OK;
6610
6611 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6612 for (j = 0; j < dptr->numunits; j++) {
6613 uptr = dptr->units + j;
6614 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6615 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6616 }
6617 }
6618 stop_cpu = 0;
6619 sim_is_running = 1;
6620 if (sim_ttrun () != SCPE_OK) {
6621 sim_is_running = 0;
6622 sim_ttcmd ();
6623 return SCPE_TTYERR;
6624 }
6625 if ((r = sim_check_console (30)) != SCPE_OK) {
6626 sim_is_running = 0;
6627 sim_ttcmd ();
6628 return r;
6629 }
6630 #if !defined(IS_WINDOWS)
6631 # if defined(SIGINT)
6632 if (signal (SIGINT, int_handler) == SIG_ERR) {
6633 sim_is_running = 0;
6634 sim_ttcmd ();
6635 return SCPE_SIGERR;
6636 }
6637 # endif
6638 #endif
6639 #if !defined(IS_WINDOWS)
6640 # if defined(SIGHUP)
6641 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6642 sim_is_running = 0;
6643 sim_ttcmd ();
6644 return SCPE_SIGERR;
6645 }
6646 # endif
6647 #endif
6648 #if !defined(IS_WINDOWS)
6649 # if defined(SIGTERM)
6650 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6651 sim_is_running = 0;
6652 sim_ttcmd ();
6653 return SCPE_SIGERR;
6654 }
6655 # endif
6656 #endif
6657 if (sim_step)
6658 sim_activate (&sim_step_unit, sim_step);
6659 (void)fflush(stdout);
6660 if (sim_log)
6661 (void)fflush (sim_log);
6662 sim_rtcn_init_all ();
6663 sim_start_timer_services ();
6664
6665 do {
6666 t_addr *addrs;
6667
6668 while (1) {
6669 r = sim_instr();
6670 if (r != SCPE_REMOTE)
6671 break;
6672 sim_remote_process_command ();
6673 }
6674 if ((flag != RU_NEXT) ||
6675 (--sim_next <=0))
6676 break;
6677 if (sim_step == 0) {
6678 t_addr val;
6679 BRKTAB *bp;
6680
6681 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6682 break;
6683 if (sim_vm_pc_value)
6684 val = (t_addr)(*sim_vm_pc_value)();
6685 else
6686 val = (t_addr)get_rval (sim_PC, 0);
6687 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6688 break;
6689 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6690 }
6691 else {
6692 if (r != SCPE_STEP)
6693 break;
6694 }
6695
6696 sim_step = 0;
6697 if (sim_vm_is_subroutine_call(&addrs)) {
6698 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6699 for (i=0; addrs[i]; i++)
6700 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6701 }
6702 else
6703 sim_step = 1;
6704 if (sim_step)
6705 sim_activate (&sim_step_unit, sim_step);
6706 } while (1);
6707
6708 sim_is_running = 0;
6709 sim_stop_timer_services ();
6710 sim_ttcmd ();
6711 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6712 signal (SIGINT, SIG_DFL);
6713 #if defined(SIGHUP)
6714 signal (SIGHUP, SIG_DFL);
6715 #endif
6716 signal (SIGTERM, SIG_DFL);
6717 if (sim_log)
6718 (void)fflush (sim_log);
6719 if (sim_deb)
6720 sim_debug_flush ();
6721 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6722 for (j = 0; j < dptr->numunits; j++) {
6723 uptr = dptr->units + j;
6724 if (uptr->flags & UNIT_ATT) {
6725 if (uptr->io_flush)
6726 uptr->io_flush (uptr);
6727 else {
6728 if (!(uptr->flags & UNIT_BUF) &&
6729 (uptr->fileref) &&
6730 !(uptr->dynflags & UNIT_NO_FIO) &&
6731 !(uptr->flags & UNIT_RO))
6732 (void)fflush (uptr->fileref);
6733 }
6734 }
6735 }
6736 }
6737 sim_cancel (&sim_step_unit);
6738 UPDATE_SIM_TIME;
6739 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6740 }
6741
6742
6743
6744 void
6745 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6746 {
6747 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6748 sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6749 #if defined(WIN_STDIO)
6750 (void)fflush(stderr);
6751 (void)fflush(stdout);
6752 #endif
6753 fprint_stopped (stdout, r);
6754 if (sim_log && (sim_log != stdout))
6755 fprint_stopped (sim_log, r);
6756 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6757 fprint_stopped (sim_deb, r);
6758 #if defined(WIN_STDIO)
6759 (void)fflush(stderr);
6760 (void)fflush(stdout);
6761 #endif
6762 }
6763
6764
6765
6766 t_stat sim_run_boot_prep (int32 flag)
6767 {
6768 UNIT *uptr;
6769 t_stat r;
6770
6771 sim_interval = 0;
6772 sim_time = sim_rtime = 0;
6773 noqueue_time = 0;
6774 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6775 sim_clock_queue = uptr->next;
6776 uptr->next = NULL;
6777 }
6778 r = reset_all (0);
6779 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6780 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6781 sim_printf ("Resetting all devices... This may not have been your intention.\r\n");
6782 sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6783 }
6784 run_cmd_did_reset = TRUE;
6785 }
6786 return r;
6787 }
6788
6789
6790
6791
6792
6793
6794
6795
6796 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6797 {
6798 int32 i;
6799 t_stat r = 0;
6800 t_addr k;
6801 t_value pcval;
6802
6803 fputc ('\n', st);
6804
6805 if (v >= SCPE_BASE)
6806 fputs (sim_error_text (v), st);
6807 else {
6808 fputs (sim_stop_messages [v], st);
6809
6810 if ((sim_vm_fprint_stopped != NULL) &&
6811 (!sim_vm_fprint_stopped (st, v)))
6812 return;
6813 }
6814
6815 (void)fprintf (st, ", %s: ", pc->name);
6816
6817 pcval = get_rval (pc, 0);
6818 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6819 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6820 else fprint_val (st, pcval, pc->radix, pc->width,
6821 pc->flags & REG_FMT);
6822 if ((dptr != NULL) && (dptr->examine != NULL)) {
6823 for (i = 0; i < sim_emax; i++)
6824 sim_eval[i] = 0;
6825 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6826 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6827 break;
6828 }
6829 if ((r == SCPE_OK) || (i > 0)) {
6830 (void)fprintf (st, " (");
6831 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6832 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6833 (void)fprintf (st, ")");
6834 }
6835 }
6836 (void)fprintf (st, "\r\n");
6837 return;
6838 }
6839
6840 void fprint_stopped (FILE *st, t_stat v)
6841 {
6842 #if defined(WIN_STDIO)
6843 (void)fflush(stderr);
6844 (void)fflush(stdout);
6845 #endif
6846 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6847 return;
6848 }
6849
6850
6851
6852
6853 t_stat step_svc (UNIT *uptr)
6854 {
6855 return SCPE_STEP;
6856 }
6857
6858
6859
6860
6861 t_stat expect_svc (UNIT *uptr)
6862 {
6863 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6864 }
6865
6866
6867
6868 void int_handler (int sig)
6869 {
6870 stop_cpu = 1;
6871 return;
6872 }
6873
6874
6875
6876 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6877 {
6878 char gbuf[CBUFSIZE];
6879 CONST char *gptr;
6880 CONST char *tptr = NULL;
6881 int32 opt;
6882 t_addr low, high;
6883 t_stat reason = SCPE_IERR;
6884 DEVICE *tdptr;
6885 REG *lowr, *highr;
6886 FILE *ofile;
6887
6888 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6889 if (flag == EX_E)
6890 opt = opt | CMD_OPT_OF;
6891 cptr = get_sim_opt (opt, cptr, &reason);
6892 if (NULL == cptr)
6893 return reason;
6894 if (*cptr == 0)
6895 return SCPE_2FARG;
6896 if (sim_dfunit == NULL)
6897 return SCPE_NXUN;
6898 cptr = get_glyph (cptr, gbuf, 0);
6899 if ((flag == EX_D) && (*cptr == 0))
6900
6901 return SCPE_2FARG;
6902 ofile = sim_ofile? sim_ofile: stdout;
6903
6904 for (gptr = gbuf, reason = SCPE_OK;
6905 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6906 tdptr = sim_dfdev;
6907 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6908 tptr = gptr + strlen ("STATE");
6909 if (*tptr && (*tptr++ != ','))
6910 return SCPE_ARG;
6911 if ((lowr = sim_dfdev->registers) == NULL)
6912 return SCPE_NXREG;
6913 for (highr = lowr; highr->name != NULL; highr++) ;
6914 sim_switches = sim_switches | SIM_SW_HIDE;
6915 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6916 lowr, --highr, 0, 0);
6917 continue;
6918 }
6919
6920
6921 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6922 (!(sim_opt_out & CMD_OPT_DFT) &&
6923 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6924 low = high = 0;
6925 if ((*tptr == '-') || (*tptr == ':')) {
6926 highr = find_reg (tptr + 1, &tptr, tdptr);
6927 if (highr == NULL)
6928 return SCPE_NXREG;
6929 }
6930 else {
6931 highr = lowr;
6932 if (*tptr == '[') {
6933 if (lowr->depth <= 1)
6934 return SCPE_ARG;
6935 tptr = get_range (NULL, tptr + 1, &low, &high,
6936 10, lowr->depth - 1, ']');
6937 if (tptr == NULL)
6938 return SCPE_ARG;
6939 }
6940 }
6941 if (*tptr && (*tptr++ != ','))
6942 return SCPE_ARG;
6943 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6944 lowr, highr, (uint32) low, (uint32) high);
6945 continue;
6946 }
6947
6948 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6949 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6950 sim_dfunit->capac - sim_dfdev->aincr), 0);
6951 if (tptr == NULL)
6952 return SCPE_ARG;
6953 if (*tptr && (*tptr++ != ','))
6954 return SCPE_ARG;
6955 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6956 sim_dfdev, sim_dfunit);
6957 }
6958 if (sim_ofile)
6959 fclose (sim_ofile);
6960 return reason;
6961 }
6962
6963
6964
6965
6966
6967
6968
6969 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6970 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6971 {
6972 t_stat reason;
6973 uint32 idx, val_start=lows;
6974 t_value val, last_val;
6975 REG *rptr;
6976
6977 if ((lowr == NULL) || (highr == NULL))
6978 return SCPE_IERR;
6979 if (lowr > highr)
6980 return SCPE_ARG;
6981 for (rptr = lowr; rptr <= highr; rptr++) {
6982 if ((sim_switches & SIM_SW_HIDE) &&
6983 (rptr->flags & REG_HIDDEN))
6984 continue;
6985 val = last_val = 0;
6986 for (idx = lows; idx <= highs; idx++) {
6987 if (idx >= rptr->depth)
6988 return SCPE_SUB;
6989 val = get_rval (rptr, idx);
6990 if (schptr && !test_search (&val, schptr))
6991 continue;
6992 if (flag == EX_E) {
6993 if ((idx > lows) && (val == last_val))
6994 continue;
6995 if (idx > val_start+1) {
6996 if (idx-1 == val_start+1) {
6997 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6998 if (reason != SCPE_OK)
6999 return reason;
7000 if (sim_log && (ofile == stdout))
7001 ex_reg (sim_log, val, flag, rptr, idx-1);
7002 }
7003 else {
7004 if (val_start+1 != idx-1) {
7005 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
7006 if (sim_log && (ofile == stdout))
7007 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
7008 }
7009 else {
7010 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7011 if (sim_log && (ofile == stdout))
7012 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7013 }
7014 }
7015 }
7016 sim_last_val = last_val = val;
7017 val_start = idx;
7018 reason = ex_reg (ofile, val, flag, rptr, idx);
7019 if (reason != SCPE_OK)
7020 return reason;
7021 if (sim_log && (ofile == stdout))
7022 ex_reg (sim_log, val, flag, rptr, idx);
7023 }
7024 if (flag != EX_E) {
7025 reason = dep_reg (flag, cptr, rptr, idx);
7026 if (reason != SCPE_OK)
7027 return reason;
7028 }
7029 }
7030 if ((flag == EX_E) && (val_start != highs)) {
7031 if (highs == val_start+1) {
7032 reason = ex_reg (ofile, val, flag, rptr, highs);
7033 if (reason != SCPE_OK)
7034 return reason;
7035 if (sim_log && (ofile == stdout))
7036 ex_reg (sim_log, val, flag, rptr, highs);
7037 }
7038 else {
7039 if (val_start+1 != highs) {
7040 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
7041 if (sim_log && (ofile == stdout))
7042 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
7043 }
7044 else {
7045 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7046 if (sim_log && (ofile == stdout))
7047 (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7048 }
7049 }
7050 }
7051 }
7052 return SCPE_OK;
7053 }
7054
7055 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
7056 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
7057 {
7058 t_addr i, mask;
7059 t_stat reason;
7060
7061 if (uptr->flags & UNIT_DIS)
7062 return SCPE_UDIS;
7063 mask = (t_addr) width_mask[dptr->awidth];
7064 if ((low > mask) || (high > mask) || (low > high))
7065 return SCPE_ARG;
7066 for (i = low; i <= high; ) {
7067 reason = get_aval (i, dptr, uptr);
7068 if (reason != SCPE_OK)
7069 return reason;
7070 if (schptr && !test_search (sim_eval, schptr))
7071 i = i + dptr->aincr;
7072 else {
7073 if (flag != EX_D) {
7074 reason = ex_addr (ofile, flag, i, dptr, uptr);
7075 if (reason > SCPE_OK)
7076 return reason;
7077 if (sim_log && (ofile == stdout))
7078 ex_addr (sim_log, flag, i, dptr, uptr);
7079 }
7080 else reason = 1 - dptr->aincr;
7081 if (flag != EX_E) {
7082 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7083 if (reason > SCPE_OK)
7084 return reason;
7085 }
7086 i = i + (1 - reason);
7087 }
7088 }
7089 return SCPE_OK;
7090 }
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
7105 {
7106 int32 rdx;
7107
7108 if (rptr == NULL)
7109 return SCPE_IERR;
7110 if (rptr->depth > 1)
7111 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7112 else
7113 (void)Fprintf (ofile, "%s:\t", rptr->name);
7114 if (!(flag & EX_E))
7115 return SCPE_OK;
7116 GET_RADIX (rdx, rptr->radix);
7117 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7118 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7119 else if (!(rptr->flags & REG_VMFLAGS) ||
7120 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7121 NULL, sim_switches | SIM_SW_REG) > 0)) {
7122 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7123 if (rptr->fields) {
7124 (void)Fprintf (ofile, "\t");
7125 fprint_fields (ofile, val, val, rptr->fields);
7126 }
7127 }
7128 if (flag & EX_I)
7129 (void)Fprintf (ofile, "\t");
7130 else
7131 (void)Fprintf (ofile, "\r\n");
7132 return SCPE_OK;
7133 }
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144 t_value get_rval (REG *rptr, uint32 idx)
7145 {
7146 size_t sz;
7147 t_value val;
7148 uint32 *ptr;
7149
7150 sz = SZ_R (rptr);
7151 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7152 idx = idx + rptr->qptr;
7153 if (idx >= rptr->depth) idx = idx - rptr->depth;
7154 }
7155 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7156 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7157 if (sz <= sizeof (uint32))
7158 val = *ptr;
7159 else val = *((t_uint64 *) ptr);
7160 }
7161 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7162 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7163 if (sz <= sizeof (uint32))
7164 val = *ptr;
7165 else val = *((t_uint64 *) ptr);
7166 }
7167 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7168 (sz == sizeof (uint8)))
7169 val = *(((uint8 *) rptr->loc) + idx);
7170 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7171 (sz == sizeof (uint16)))
7172 val = *(((uint16 *) rptr->loc) + idx);
7173 else if (sz <= sizeof (uint32))
7174 val = *(((uint32 *) rptr->loc) + idx);
7175 else val = *(((t_uint64 *) rptr->loc) + idx);
7176 val = (val >> rptr->offset) & width_mask[rptr->width];
7177 return val;
7178 }
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7192 {
7193 t_stat r;
7194 t_value val, mask;
7195 int32 rdx;
7196 CONST char *tptr;
7197 char gbuf[CBUFSIZE];
7198
7199 if ((cptr == NULL) || (rptr == NULL))
7200 return SCPE_IERR;
7201 if (rptr->flags & REG_RO)
7202 return SCPE_RO;
7203 if (flag & EX_I) {
7204 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7205 if (sim_log)
7206 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7207 if (cptr == NULL)
7208 return 1;
7209 if (*cptr == 0)
7210 return SCPE_OK;
7211 }
7212 mask = width_mask[rptr->width];
7213 GET_RADIX (rdx, rptr->radix);
7214 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7215 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7216 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7217 return SCPE_ARG;
7218 }
7219 else
7220 if (!(rptr->flags & REG_VMFLAGS) ||
7221 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7222 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7223 val = get_uint (cptr, rdx, mask, &r);
7224 if (r != SCPE_OK)
7225 return SCPE_ARG;
7226 }
7227 if ((rptr->flags & REG_NZ) && (val == 0))
7228 return SCPE_ARG;
7229 put_rval (rptr, idx, val);
7230 return SCPE_OK;
7231 }
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244 void put_rval (REG *rptr, uint32 idx, t_value val)
7245 {
7246 size_t sz;
7247 t_value mask;
7248 uint32 *ptr;
7249
7250 #define PUT_RVAL(sz,rp,id,v,m) \
7251 *(((sz *) rp->loc) + id) = \
7252 (sz)((*(((sz *) rp->loc) + id) & \
7253 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7254
7255 if (rptr == sim_PC)
7256 sim_brk_npc (0);
7257 sz = SZ_R (rptr);
7258 mask = width_mask[rptr->width];
7259 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7260 idx = idx + rptr->qptr;
7261 if (idx >= rptr->depth)
7262 idx = idx - rptr->depth;
7263 }
7264 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7265 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7266 if (sz <= sizeof (uint32))
7267 *ptr = (*ptr &
7268 ~(((uint32) mask) << rptr->offset)) |
7269 (((uint32) val) << rptr->offset);
7270 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7271 & ~(mask << rptr->offset)) | (val << rptr->offset);
7272 }
7273 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7274 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7275 if (sz <= sizeof (uint32))
7276 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7277 ~(((uint32) mask) << rptr->offset)) |
7278 (((uint32) val) << rptr->offset);
7279 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7280 & ~(mask << rptr->offset)) | (val << rptr->offset);
7281 }
7282 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7283 (sz == sizeof (uint8)))
7284 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7285 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7286 (sz == sizeof (uint16)))
7287 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7288 else if (sz <= sizeof (uint32))
7289 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7290 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7291 return;
7292 }
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7308 {
7309 t_stat reason;
7310 int32 rdx;
7311
7312 if (sim_vm_fprint_addr)
7313 sim_vm_fprint_addr (ofile, dptr, addr);
7314 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7315 (void)Fprintf (ofile, ":\t");
7316 if (!(flag & EX_E))
7317 return (1 - dptr->aincr);
7318
7319 GET_RADIX (rdx, dptr->dradix);
7320 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7321 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7322 reason = 1 - dptr->aincr;
7323 }
7324 if (flag & EX_I)
7325 (void)Fprintf (ofile, "\t");
7326 else
7327 (void)Fprintf (ofile, "\r\n");
7328 return reason;
7329 }
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7343 {
7344 int32 i;
7345 t_value mask;
7346 t_addr j, loc;
7347 size_t sz;
7348 t_stat reason = SCPE_OK;
7349
7350 if ((dptr == NULL) || (uptr == NULL))
7351 return SCPE_IERR;
7352 mask = width_mask[dptr->dwidth];
7353 for (i = 0; i < sim_emax; i++)
7354 sim_eval[i] = 0;
7355 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7356 if (dptr->examine != NULL) {
7357 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7358 if (reason != SCPE_OK)
7359 break;
7360 }
7361 else {
7362 if (!(uptr->flags & UNIT_ATT))
7363 return SCPE_UNATT;
7364 if (uptr->dynflags & UNIT_NO_FIO)
7365 return SCPE_NOFNC;
7366 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7367 reason = SCPE_NXM;
7368 break;
7369 }
7370 sz = SZ_D (dptr);
7371 loc = j / dptr->aincr;
7372 if (uptr->flags & UNIT_BUF) {
7373 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7374 }
7375 else {
7376 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7377 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7378 if ((feof (uptr->fileref)) &&
7379 !(uptr->flags & UNIT_FIX)) {
7380 reason = SCPE_EOF;
7381 break;
7382 }
7383 else if (ferror (uptr->fileref)) {
7384 clearerr (uptr->fileref);
7385 reason = SCPE_IOERR;
7386 break;
7387 }
7388 }
7389 }
7390 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7391 }
7392 if ((reason != SCPE_OK) && (i == 0))
7393 return reason;
7394 return SCPE_OK;
7395 }
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7412 UNIT *uptr, int32 dfltinc)
7413 {
7414 int32 i, count, rdx;
7415 t_addr j, loc;
7416 t_stat r, reason;
7417 t_value mask;
7418 size_t sz;
7419 char gbuf[CBUFSIZE];
7420
7421 if (dptr == NULL)
7422 return SCPE_IERR;
7423 if (flag & EX_I) {
7424 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7425 if (sim_log)
7426 (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7427 if (cptr == NULL)
7428 return 1;
7429 if (*cptr == 0)
7430 return dfltinc;
7431 }
7432 if (uptr->flags & UNIT_RO)
7433 return SCPE_RO;
7434 mask = width_mask[dptr->dwidth];
7435
7436 GET_RADIX (rdx, dptr->dradix);
7437 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7438 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7439 if (reason != SCPE_OK)
7440 return reason;
7441 reason = dfltinc;
7442 }
7443 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7444
7445 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7446 sim_eval[i] = sim_eval[i] & mask;
7447 if (dptr->deposit != NULL) {
7448 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7449 if (r != SCPE_OK)
7450 return r;
7451 }
7452 else {
7453 if (!(uptr->flags & UNIT_ATT))
7454 return SCPE_UNATT;
7455 if (uptr->dynflags & UNIT_NO_FIO)
7456 return SCPE_NOFNC;
7457 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7458 return SCPE_NXM;
7459 sz = SZ_D (dptr);
7460 loc = j / dptr->aincr;
7461 if (uptr->flags & UNIT_BUF) {
7462 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7463 if (loc >= uptr->hwmark)
7464 uptr->hwmark = (uint32) loc + 1;
7465 }
7466 else {
7467 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7468 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7469 if (ferror (uptr->fileref)) {
7470 clearerr (uptr->fileref);
7471 return SCPE_IOERR;
7472 }
7473 }
7474 }
7475 }
7476 return reason;
7477 }
7478
7479
7480
7481 t_stat eval_cmd (int32 flg, CONST char *cptr)
7482 {
7483 if (!sim_dflt_dev)
7484 return SCPE_ARG;
7485 DEVICE *dptr = sim_dflt_dev;
7486 int32 i, rdx, a, lim;
7487 t_stat r;
7488
7489 GET_SWITCHES (cptr);
7490 GET_RADIX (rdx, dptr->dradix);
7491 for (i = 0; i < sim_emax; i++)
7492 sim_eval[i] = 0;
7493 if (*cptr == 0)
7494 return SCPE_2FARG;
7495 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7496 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7497 if (r != SCPE_OK)
7498 return r;
7499 }
7500 lim = 1 - r;
7501 for (i = a = 0; a < lim; ) {
7502 sim_printf ("%d:\t", a);
7503 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7504 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7505 if (sim_log) {
7506 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7507 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7508 }
7509 sim_printf ("\r\n");
7510 if (r < 0)
7511 a = a + 1 - r;
7512 else a = a + dptr->aincr;
7513 i = a / dptr->aincr;
7514 }
7515 return SCPE_OK;
7516 }
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531 char *read_line (char *cptr, int32 size, FILE *stream)
7532 {
7533 return read_line_p (NULL, cptr, size, stream);
7534 }
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7549 {
7550 char *tptr;
7551
7552 if (prompt) {
7553 #if defined(HAVE_LINEHISTORY)
7554 char *tmpc = linenoise (prompt);
7555 if (tmpc == NULL)
7556 cptr = NULL;
7557 else {
7558 strncpy (cptr, tmpc, size-1);
7559 linenoiseHistoryAdd (tmpc);
7560 FREE (tmpc);
7561 }
7562 }
7563 #else
7564 (void)fflush (stdout);
7565 (void)printf ("%s", prompt);
7566 (void)fflush (stdout);
7567 cptr = fgets (cptr, size, stream);
7568 }
7569 #endif
7570 else cptr = fgets (cptr, size, stream);
7571
7572 if (cptr == NULL) {
7573 clearerr (stream);
7574 return NULL;
7575 }
7576 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7577 if ((*tptr == '\n') || (*tptr == '\r') ||
7578 (tptr == (cptr + size - 1))) {
7579 *tptr = 0;
7580 break;
7581 }
7582 }
7583 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7584 memmove (cptr, cptr + 3, strlen (cptr + 3));
7585 while (sim_isspace (*cptr))
7586 cptr++;
7587 if ((*cptr == ';') || (*cptr == '#')) {
7588 if (sim_do_echo)
7589 sim_printf("%s> %s\r\n", do_position(), cptr);
7590 *cptr = 0;
7591 }
7592
7593 return cptr;
7594 }
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7615 {
7616 t_bool quoting = FALSE;
7617 t_bool escaping = FALSE;
7618 char quote_char = 0;
7619
7620 while ((*iptr != 0) &&
7621 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7622 if (quote) {
7623 if (quoting) {
7624 if (!escaping) {
7625 if (*iptr == escape_char)
7626 escaping = TRUE;
7627 else
7628 if (*iptr == quote_char)
7629 quoting = FALSE;
7630 }
7631 else
7632 escaping = FALSE;
7633 }
7634 else {
7635 if ((*iptr == '"') || (*iptr == '\'')) {
7636 quoting = TRUE;
7637 quote_char = *iptr;
7638 }
7639 }
7640 }
7641 if (sim_islower (*iptr) && uc)
7642 *optr = (char)toupper (*iptr);
7643 else *optr = *iptr;
7644 iptr++; optr++;
7645 }
7646 if (mchar && (*iptr == mchar))
7647 iptr++;
7648 *optr = 0;
7649 while (sim_isspace (*iptr))
7650 iptr++;
7651 return iptr;
7652 }
7653
7654 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7655 {
7656 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7657 }
7658
7659 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7660 {
7661 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7662 }
7663
7664 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7665 {
7666 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7667 }
7668
7669 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7670 {
7671
7672 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7673 strcpy (optr, "!");
7674 return (CONST char *)(iptr + 1);
7675 }
7676 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7677 }
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687 char *sim_trim_endspc (char *cptr)
7688 {
7689 char *tptr;
7690
7691 tptr = cptr + strlen (cptr);
7692 while ((--tptr >= cptr) && sim_isspace (*tptr))
7693 *tptr = 0;
7694 return cptr;
7695 }
7696
7697 int sim_isspace (char c)
7698 {
7699 return (c & 0x80) ? 0 : isspace (c);
7700 }
7701
7702 int sim_islower (char c)
7703 {
7704 return (c & 0x80) ? 0 : islower (c);
7705 }
7706
7707 int sim_isalpha (char c)
7708 {
7709 return (c & 0x80) ? 0 : isalpha (c);
7710 }
7711
7712 int sim_isprint (char c)
7713 {
7714 return (c & 0x80) ? 0 : isprint (c);
7715 }
7716
7717 int sim_isdigit (char c)
7718 {
7719 return (c & 0x80) ? 0 : isdigit (c);
7720 }
7721
7722 int sim_isgraph (char c)
7723 {
7724 return (c & 0x80) ? 0 : isgraph (c);
7725 }
7726
7727 int sim_isalnum (char c)
7728 {
7729 return (c & 0x80) ? 0 : isalnum (c);
7730 }
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7744 {
7745 t_value val;
7746 CONST char *tptr;
7747
7748 *status = SCPE_OK;
7749 val = strtotv ((CONST char *)cptr, &tptr, radix);
7750 if ((cptr == tptr) || (val > max))
7751 *status = SCPE_ARG;
7752 else {
7753 while (sim_isspace (*tptr)) tptr++;
7754 if (*tptr != 0)
7755 *status = SCPE_ARG;
7756 }
7757 return val;
7758 }
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7776 uint32 rdx, t_addr max, char term)
7777 {
7778 CONST char *tptr;
7779
7780 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7781 tptr = cptr + strlen ("ALL");
7782 *lo = 0;
7783 *hi = max;
7784 }
7785 else {
7786 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7787 ((cptr[1] == '\0') ||
7788 (cptr[1] == '-') ||
7789 (cptr[1] == ':') ||
7790 (cptr[1] == '/'))) {
7791 tptr = cptr + strlen (".");
7792 *lo = *hi = sim_last_addr;
7793 }
7794 else {
7795 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7796 tptr = cptr + strlen ("$");
7797 *hi = *lo = (t_addr)sim_last_val;
7798 }
7799 else {
7800 if (dptr && sim_vm_parse_addr)
7801 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7802 else
7803 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7804 if (cptr == tptr)
7805 return NULL;
7806 }
7807 }
7808 if ((*tptr == '-') || (*tptr == ':')) {
7809 cptr = tptr + 1;
7810 if (dptr && sim_vm_parse_addr)
7811 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7812 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7813 if (cptr == tptr)
7814 return NULL;
7815 if (*lo > *hi)
7816 return NULL;
7817 }
7818 else if (*tptr == '/') {
7819 cptr = tptr + 1;
7820 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7821 if ((cptr == tptr) || (*hi == 0))
7822 return NULL;
7823 *hi = *lo + *hi - 1;
7824 }
7825 else *hi = *lo;
7826 }
7827 sim_last_addr = *hi;
7828 if (term && (*tptr++ != term))
7829 return NULL;
7830 return tptr;
7831 }
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7852 {
7853 char quote_char;
7854 uint8 *ostart = optr;
7855
7856 *osize = 0;
7857 if ((strlen(iptr) == 1) ||
7858 (iptr[0] != iptr[strlen(iptr)-1]) ||
7859 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7860 return SCPE_ARG;
7861 quote_char = *iptr++;
7862 while (iptr[1]) {
7863 if (*iptr != '\\') {
7864 if (*iptr == quote_char)
7865 return SCPE_ARG;
7866 *(optr++) = (uint8)(*(iptr++));
7867 continue;
7868 }
7869 ++iptr;
7870 switch (*iptr) {
7871 case 'r':
7872 *(optr++) = 13; ++iptr;
7873 break;
7874 case 'n':
7875 *(optr++) = 10; ++iptr;
7876 break;
7877 case 'f':
7878 *(optr++) = 12; ++iptr;
7879 break;
7880 case 't':
7881 *(optr++) = 9; ++iptr;
7882 break;
7883 case 'v':
7884 *(optr++) = 11; ++iptr;
7885 break;
7886 case 'b':
7887 *(optr++) = 8; ++iptr;
7888 break;
7889 case '\\':
7890 *(optr++) = 92; ++iptr;
7891 break;
7892 case 'e':
7893 *(optr++) = 27; ++iptr;
7894 break;
7895 case '\'':
7896 *(optr++) = 39; ++iptr;
7897 break;
7898 case '"':
7899 *(optr++) = 34; ++iptr;
7900 break;
7901 case '?':
7902 *(optr++) = 63; ++iptr;
7903 break;
7904 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7905 *optr = *(iptr++) - '0';
7906 if ((*iptr >= '0') && (*iptr <= '7'))
7907 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7908 if ((*iptr >= '0') && (*iptr <= '7'))
7909 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7910 ++optr;
7911 break;
7912 case 'x':
7913 if (1) {
7914 static const char *hex_digits = "0123456789ABCDEF";
7915 const char *c;
7916
7917 ++iptr;
7918 *optr = 0;
7919 c = strchr (hex_digits, toupper(*iptr));
7920 if (c) {
7921 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7922 ++iptr;
7923 }
7924 c = strchr (hex_digits, toupper(*iptr));
7925 if (c) {
7926 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7927 ++iptr;
7928 }
7929 ++optr;
7930 }
7931 break;
7932 default:
7933 return SCPE_ARG;
7934 }
7935 }
7936 *optr = '\0';
7937 *osize = (uint32)(optr-ostart);
7938 return SCPE_OK;
7939 }
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7955 {
7956 size_t i;
7957 t_bool double_quote_found = FALSE;
7958 t_bool single_quote_found = FALSE;
7959 char quote = '"';
7960 char *tptr, *optr;
7961
7962 optr = (char *)malloc (4*size + 3);
7963 if (optr == NULL)
7964 return NULL;
7965 tptr = optr;
7966 for (i=0; i<size; i++)
7967 switch ((char)iptr[i]) {
7968 case '"':
7969 double_quote_found = TRUE;
7970 break;
7971 case '\'':
7972 single_quote_found = TRUE;
7973 break;
7974 }
7975 if (double_quote_found && (!single_quote_found))
7976 quote = '\'';
7977 *tptr++ = quote;
7978 while (size--) {
7979 switch (*iptr) {
7980 case '\r':
7981 *tptr++ = '\\'; *tptr++ = 'r'; break;
7982 case '\n':
7983 *tptr++ = '\\'; *tptr++ = 'n'; break;
7984 case '\f':
7985 *tptr++ = '\\'; *tptr++ = 'f'; break;
7986 case '\t':
7987 *tptr++ = '\\'; *tptr++ = 't'; break;
7988 case '\v':
7989 *tptr++ = '\\'; *tptr++ = 'v'; break;
7990 case '\b':
7991 *tptr++ = '\\'; *tptr++ = 'b'; break;
7992 case '\\':
7993 *tptr++ = '\\'; *tptr++ = '\\'; break;
7994 case '"':
7995 case '\'':
7996 if (quote == *iptr)
7997 *tptr++ = '\\';
7998
7999 default:
8000 if (sim_isprint (*iptr))
8001 *tptr++ = *iptr;
8002 else {
8003 (void)sprintf (tptr, "\\%03o", *iptr);
8004 tptr += 4;
8005 }
8006 break;
8007 }
8008 ++iptr;
8009 }
8010 *tptr++ = quote;
8011 *tptr++ = '\0';
8012 return optr;
8013 }
8014
8015 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
8016 {
8017 char *string;
8018
8019 string = sim_encode_quoted_string (buf, size);
8020 (void)fprintf (st, "%s", string);
8021 FREE (string);
8022 }
8023
8024
8025
8026
8027
8028
8029
8030
8031
8032 DEVICE *find_dev (const char *cptr)
8033 {
8034 int32 i;
8035 DEVICE *dptr;
8036
8037 if (cptr == NULL)
8038 return NULL;
8039 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8040 if ((strcmp (cptr, dptr->name) == 0) ||
8041 (dptr->lname &&
8042 (strcmp (cptr, dptr->lname) == 0)))
8043 return dptr;
8044 }
8045 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
8046 if ((strcmp (cptr, dptr->name) == 0) ||
8047 (dptr->lname &&
8048 (strcmp (cptr, dptr->lname) == 0)))
8049 return dptr;
8050 }
8051 return NULL;
8052 }
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065 DEVICE *find_unit (const char *cptr, UNIT **uptr)
8066 {
8067 uint32 i, u;
8068 const char *nptr;
8069 const char *tptr;
8070 t_stat r;
8071 DEVICE *dptr;
8072
8073 if (uptr == NULL)
8074 return NULL;
8075 *uptr = NULL;
8076 if ((dptr = find_dev (cptr))) {
8077 if (qdisable (dptr))
8078 return NULL;
8079 *uptr = dptr->units;
8080 return dptr;
8081 }
8082
8083 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8084 if (qdisable (dptr))
8085 continue;
8086 if (dptr->numunits &&
8087 (((nptr = dptr->name) &&
8088 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
8089 ((nptr = dptr->lname) &&
8090 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8091 tptr = cptr + strlen (nptr);
8092 if (sim_isdigit (*tptr)) {
8093 if (qdisable (dptr))
8094 return NULL;
8095 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8096 if (r != SCPE_OK)
8097 *uptr = NULL;
8098 else
8099 *uptr = dptr->units + u;
8100 return dptr;
8101 }
8102 }
8103 for (u = 0; u < dptr->numunits; u++) {
8104 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8105 *uptr = &dptr->units[u];
8106 return dptr;
8107 }
8108 }
8109 }
8110 return NULL;
8111 }
8112
8113
8114
8115
8116
8117
8118
8119 t_stat sim_register_internal_device (DEVICE *dptr)
8120 {
8121 uint32 i;
8122
8123 for (i = 0; (sim_devices[i] != NULL); i++)
8124 if (sim_devices[i] == dptr)
8125 return SCPE_OK;
8126 for (i = 0; i < sim_internal_device_count; i++)
8127 if (sim_internal_devices[i] == dptr)
8128 return SCPE_OK;
8129 ++sim_internal_device_count;
8130 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8131 if (!sim_internal_devices)
8132 {
8133 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8134 __func__, __FILE__, __LINE__);
8135 #if defined(USE_BACKTRACE)
8136 # if defined(SIGUSR2)
8137 (void)raise(SIGUSR2);
8138
8139 # endif
8140 #endif
8141 abort();
8142 }
8143 sim_internal_devices[sim_internal_device_count-1] = dptr;
8144 sim_internal_devices[sim_internal_device_count] = NULL;
8145 return SCPE_OK;
8146 }
8147
8148
8149
8150
8151
8152
8153
8154
8155
8156 DEVICE *find_dev_from_unit (UNIT *uptr)
8157 {
8158 DEVICE *dptr;
8159 uint32 i, j;
8160
8161 if (uptr == NULL)
8162 return NULL;
8163 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8164 for (j = 0; j < dptr->numunits; j++) {
8165 if (uptr == (dptr->units + j))
8166 return dptr;
8167 }
8168 }
8169 for (i = 0; i<sim_internal_device_count; i++) {
8170 dptr = sim_internal_devices[i];
8171 for (j = 0; j < dptr->numunits; j++) {
8172 if (uptr == (dptr->units + j))
8173 return dptr;
8174 }
8175 }
8176 return NULL;
8177 }
8178
8179
8180
8181 t_bool qdisable (DEVICE *dptr)
8182 {
8183 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8184 }
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195
8196
8197
8198 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8199 {
8200 int32 i;
8201 DEVICE *dptr;
8202 REG *rptr, *srptr = NULL;
8203
8204 *gdptr = NULL;
8205 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8206 if (dptr->flags & DEV_DIS)
8207 continue;
8208 if ((rptr = find_reg (cptr, optr, dptr))) {
8209 if (srptr)
8210 return NULL;
8211 srptr = rptr;
8212 *gdptr = dptr;
8213 }
8214 }
8215 return srptr;
8216 }
8217
8218
8219
8220
8221
8222
8223
8224
8225
8226
8227
8228
8229 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8230 {
8231 CONST char *tptr;
8232 REG *rptr;
8233 size_t slnt;
8234
8235 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8236 return NULL;
8237 tptr = cptr;
8238 do {
8239 tptr++;
8240 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8241 slnt = tptr - cptr;
8242 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8243 if ((slnt == strlen (rptr->name)) &&
8244 (strncmp (cptr, rptr->name, slnt) == 0)) {
8245 if (optr != NULL)
8246 *optr = tptr;
8247 return rptr;
8248 }
8249 }
8250 return NULL;
8251 }
8252
8253
8254
8255
8256
8257
8258
8259
8260
8261
8262 int32 get_switches (const char *cptr)
8263 {
8264 int32 sw;
8265
8266 if (*cptr != '-')
8267 return 0;
8268 sw = 0;
8269 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8270 if (sim_isalpha (*cptr) == 0)
8271 return -1;
8272 sw = sw | SWMASK (toupper (*cptr));
8273 }
8274 return sw;
8275 }
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286 CONST char *get_sim_sw (CONST char *cptr)
8287 {
8288 int32 lsw;
8289 char gbuf[CBUFSIZE];
8290
8291 while (*cptr == '-') {
8292 cptr = get_glyph (cptr, gbuf, 0);
8293 lsw = get_switches (gbuf);
8294 if (lsw <= 0)
8295 return NULL;
8296 sim_switches = sim_switches | lsw;
8297 }
8298 return cptr;
8299 }
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8312 {
8313 int32 t;
8314 char gbuf[CBUFSIZE];
8315 CONST char *svptr;
8316 DEVICE *tdptr;
8317 UNIT *tuptr;
8318
8319 sim_switches = 0;
8320 sim_ofile = NULL;
8321 sim_schrptr = NULL;
8322 sim_schaptr = NULL;
8323 sim_stabr.logic = sim_staba.logic = SCH_OR;
8324 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8325 sim_stabr.count = 1;
8326 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8327 if (!sim_stabr.mask)
8328 {
8329 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8330 __func__, __FILE__, __LINE__);
8331 #if defined(USE_BACKTRACE)
8332 # if defined(SIGUSR2)
8333 (void)raise(SIGUSR2);
8334
8335 # endif
8336 #endif
8337 abort();
8338 }
8339 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8340 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8341 if (!sim_stabr.comp)
8342 {
8343 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8344 __func__, __FILE__, __LINE__);
8345 #if defined(USE_BACKTRACE)
8346 # if defined(SIGUSR2)
8347 (void)raise(SIGUSR2);
8348
8349 # endif
8350 #endif
8351 abort();
8352 }
8353 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8354 sim_staba.count = sim_emax;
8355 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8356 if (!sim_staba.mask)
8357 {
8358 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8359 __func__, __FILE__, __LINE__);
8360 #if defined(USE_BACKTRACE)
8361 # if defined(SIGUSR2)
8362 (void)raise(SIGUSR2);
8363
8364 # endif
8365 #endif
8366 abort();
8367 }
8368 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8369 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8370 if (!sim_staba.comp)
8371 {
8372 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8373 __func__, __FILE__, __LINE__);
8374 #if defined(USE_BACKTRACE)
8375 # if defined(SIGUSR2)
8376 (void)raise(SIGUSR2);
8377
8378 # endif
8379 #endif
8380 abort();
8381 }
8382 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8383 if (! sim_dflt_dev)
8384 return NULL;
8385 sim_dfdev = sim_dflt_dev;
8386 sim_dfunit = sim_dfdev->units;
8387 sim_opt_out = 0;
8388 *st = SCPE_OK;
8389 while (*cptr) {
8390 svptr = cptr;
8391 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8392 if (sim_ofile) {
8393 fclose (sim_ofile);
8394 *st = SCPE_ARG;
8395 return NULL;
8396 }
8397 cptr = get_glyph (cptr + 1, gbuf, 0);
8398 sim_ofile = sim_fopen (gbuf, "a");
8399 if (sim_ofile == NULL) {
8400 *st = SCPE_OPENERR;
8401 return NULL;
8402 }
8403 sim_opt_out |= CMD_OPT_OF;
8404 continue;
8405 }
8406 cptr = get_glyph (cptr, gbuf, 0);
8407 if ((t = get_switches (gbuf)) != 0) {
8408 if (t < 0) {
8409 *st = SCPE_INVSW;
8410 return NULL;
8411 }
8412 sim_switches = sim_switches | t;
8413 }
8414 else if ((opt & CMD_OPT_SCH) &&
8415 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8416 sim_schrptr = &sim_stabr;
8417 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8418 sim_opt_out |= CMD_OPT_SCH;
8419 }
8420 else if ((opt & CMD_OPT_DFT) &&
8421 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8422 (tdptr = find_unit (gbuf, &tuptr)) &&
8423 (tuptr != NULL)) {
8424 sim_dfdev = tdptr;
8425 sim_dfunit = tuptr;
8426 sim_opt_out |= CMD_OPT_DFT;
8427 }
8428 else return svptr;
8429 }
8430 return cptr;
8431 }
8432
8433
8434
8435
8436
8437
8438
8439
8440
8441
8442
8443 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8444 {
8445 char *optr = buf;
8446 int32 bit;
8447
8448 (void)memset (buf, 0, bufsize);
8449 if ((sw == 0) || (bufsize < 3))
8450 return buf;
8451 --bufsize;
8452 *optr++ = '-';
8453 for (bit=0; bit <= ('Z'-'A'); bit++)
8454 if (sw & (1 << bit))
8455 if ((size_t)(optr - buf) < bufsize)
8456 *optr++ = 'A' + bit;
8457 return buf;
8458 }
8459
8460
8461
8462
8463
8464
8465
8466
8467
8468
8469
8470
8471 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8472 {
8473 int32 c;
8474 size_t logop, cmpop;
8475 t_value logval, cmpval;
8476 const char *sptr;
8477 CONST char *tptr;
8478 const char logstr[] = "|&^", cmpstr[] = "=!><";
8479
8480 const size_t invalid_op = (size_t) -1;
8481
8482 logval = cmpval = 0;
8483 if (*cptr == 0)
8484 return NULL;
8485
8486 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8487 if ((sptr = strchr (logstr, c))) {
8488 logop = sptr - logstr;
8489 logval = strtotv (cptr, &tptr, radix);
8490 if (cptr == tptr)
8491 return NULL;
8492 cptr = tptr;
8493 }
8494 else if ((sptr = strchr (cmpstr, c))) {
8495 cmpop = sptr - cmpstr;
8496 if (*cptr == '=') {
8497 cmpop = cmpop + strlen (cmpstr);
8498 cptr++;
8499 }
8500 cmpval = strtotv (cptr, &tptr, radix);
8501 if (cptr == tptr)
8502 return NULL;
8503 cptr = tptr;
8504 }
8505 else return NULL;
8506 }
8507 if (schptr->count != 1) {
8508 FREE (schptr->mask);
8509 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8510 FREE (schptr->comp);
8511 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8512 }
8513 if (logop != invalid_op) {
8514 schptr->logic = logop;
8515 schptr->mask[0] = logval;
8516 }
8517 if (cmpop != invalid_op) {
8518 schptr->boolop = cmpop;
8519 schptr->comp[0] = cmpval;
8520 }
8521 schptr->count = 1;
8522 return schptr;
8523 }
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
8535
8536 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8537 {
8538 int32 c;
8539 size_t logop, cmpop;
8540 t_value *logval, *cmpval;
8541 t_stat reason = SCPE_OK;
8542 CONST char *ocptr = cptr;
8543 const char *sptr;
8544 char gbuf[CBUFSIZE];
8545 const char logstr[] = "|&^", cmpstr[] = "=!><";
8546
8547 const size_t invalid_op = (size_t) -1;
8548
8549 if (*cptr == 0)
8550 return NULL;
8551 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8552 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8553
8554 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8555 if (NULL != (sptr = strchr (logstr, c))) {
8556 logop = sptr - logstr;
8557 cptr = get_glyph (cptr, gbuf, 0);
8558 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8559 if (reason > 0) {
8560 FREE (logval);
8561 FREE (cmpval);
8562 return get_rsearch (ocptr, radix, schptr);
8563 }
8564 }
8565 else if (NULL != (sptr = strchr (cmpstr, c))) {
8566 cmpop = sptr - cmpstr;
8567 if (*cptr == '=') {
8568 cmpop = cmpop + strlen (cmpstr);
8569 cptr++;
8570 }
8571 cptr = get_glyph (cptr, gbuf, 0);
8572 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8573 if (reason > 0) {
8574 FREE (logval);
8575 FREE (cmpval);
8576 return get_rsearch (ocptr, radix, schptr);
8577 }
8578 }
8579 else {
8580 FREE (logval);
8581 FREE (cmpval);
8582 return NULL;
8583 }
8584 }
8585 if (schptr->count != (uint32)(1 - reason)) {
8586 schptr->count = 1 - reason;
8587 FREE (schptr->mask);
8588 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8589 FREE (schptr->comp);
8590 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8591 }
8592 if (logop != invalid_op) {
8593 schptr->logic = logop;
8594 FREE (schptr->mask);
8595 schptr->mask = logval;
8596 }
8597 else {
8598 FREE (logval);
8599 }
8600 if (cmpop != invalid_op) {
8601 schptr->boolop = cmpop;
8602 FREE (schptr->comp);
8603 schptr->comp = cmpval;
8604 }
8605 else {
8606 FREE (cmpval);
8607 }
8608 return schptr;
8609 }
8610
8611
8612
8613
8614
8615
8616
8617
8618
8619
8620 int32 test_search (t_value *values, SCHTAB *schptr)
8621 {
8622 t_value *val = NULL;
8623 int32 i, updown;
8624 int32 ret = 0;
8625
8626 if (schptr == NULL)
8627 return ret;
8628
8629 val = (t_value *)malloc (schptr->count * sizeof (*values));
8630 if (!val)
8631 {
8632 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8633 __func__, __FILE__, __LINE__);
8634 #if defined(USE_BACKTRACE)
8635 # if defined(SIGUSR2)
8636 (void)raise(SIGUSR2);
8637
8638 # endif
8639 #endif
8640 abort();
8641 }
8642 for (i=0; i<(int32)schptr->count; i++) {
8643 val[i] = values[i];
8644 switch (schptr->logic) {
8645
8646 case SCH_OR:
8647 val[i] = val[i] | schptr->mask[i];
8648 break;
8649
8650 case SCH_AND:
8651 val[i] = val[i] & schptr->mask[i];
8652 break;
8653
8654 case SCH_XOR:
8655 val[i] = val[i] ^ schptr->mask[i];
8656 break;
8657 }
8658 }
8659
8660 ret = 1;
8661 if (1) {
8662 updown = -1;
8663 i=schptr->count-1;
8664 }
8665 else {
8666 updown = 1;
8667 i=0;
8668 }
8669 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8670 switch (schptr->boolop) {
8671
8672 case SCH_E: case SCH_EE:
8673 if (val[i] != schptr->comp[i])
8674 ret = 0;
8675 break;
8676
8677 case SCH_N: case SCH_NE:
8678 if (val[i] == schptr->comp[i])
8679 ret = 0;
8680 break;
8681
8682 case SCH_G:
8683 if (val[i] <= schptr->comp[i])
8684 ret = 0;
8685 break;
8686
8687 case SCH_GE:
8688 if (val[i] < schptr->comp[i])
8689 ret = 0;
8690 break;
8691
8692 case SCH_L:
8693 if (val[i] >= schptr->comp[i])
8694 ret = 0;
8695 break;
8696
8697 case SCH_LE:
8698 if (val[i] > schptr->comp[i])
8699 ret = 0;
8700 break;
8701 }
8702 }
8703 FREE (val);
8704 return ret;
8705 }
8706
8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8722 {
8723 int32 nodigit;
8724 t_value val;
8725 uint32 c, digit;
8726
8727 *endptr = inptr;
8728 if ((radix < 2) || (radix > 36))
8729 return 0;
8730 while (sim_isspace (*inptr))
8731 inptr++;
8732 val = 0;
8733 nodigit = 1;
8734 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8735 if (sim_islower (c))
8736 c = toupper (c);
8737 if (sim_isdigit (c))
8738 digit = c - (uint32) '0';
8739 else if (radix <= 10)
8740 break;
8741 else digit = c + 10 - (uint32) 'A';
8742 if (digit >= radix)
8743 return 0;
8744 val = (val * radix) + digit;
8745 nodigit = 0;
8746 }
8747 if (nodigit)
8748 return 0;
8749 *endptr = inptr;
8750 return val;
8751 }
8752
8753
8754
8755
8756
8757
8758
8759
8760
8761
8762
8763
8764
8765
8766
8767 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8768 size_t width, uint32 format)
8769 {
8770 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8771 t_value owtest, wtest;
8772 size_t d;
8773 size_t digit;
8774 size_t ndigits;
8775 size_t commas = 0;
8776 char dbuf[MAX_WIDTH + 1];
8777
8778 for (d = 0; d < MAX_WIDTH; d++)
8779 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8780 dbuf[MAX_WIDTH] = 0;
8781 d = MAX_WIDTH;
8782 do {
8783 d = d - 1;
8784 digit = val % radix;
8785 val = val / radix;
8786 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8787 } while ((d > 0) && (val != 0));
8788
8789 switch (format) {
8790 case PV_LEFT:
8791 break;
8792 case PV_RZRO:
8793 wtest = owtest = radix;
8794 ndigits = 1;
8795 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8796 owtest = wtest;
8797 wtest = wtest * radix;
8798 ndigits = ndigits + 1;
8799 }
8800 if ((MAX_WIDTH - (ndigits + commas)) < d)
8801 d = MAX_WIDTH - (ndigits + commas);
8802 break;
8803 }
8804 if (NULL == buffer)
8805 return ((t_stat) strlen(dbuf+d));
8806 *buffer = '\0';
8807 if (width < strlen(dbuf+d))
8808 return SCPE_IOERR;
8809 strcpy(buffer, dbuf+d);
8810 return SCPE_OK;
8811 }
8812
8813 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8814 uint32 width, uint32 format)
8815 {
8816 char dbuf[MAX_WIDTH + 1];
8817
8818 if (!stream)
8819 return sprint_val (NULL, val, radix, width, format);
8820 if (width > MAX_WIDTH)
8821 width = MAX_WIDTH;
8822 sprint_val (dbuf, val, radix, width, format);
8823 if (Fprintf (stream, "%s", dbuf) < 0)
8824 return SCPE_IOERR;
8825 return SCPE_OK;
8826 }
8827
8828 const char *sim_fmt_secs (double seconds)
8829 {
8830 static char buf[60];
8831 char frac[16] = "";
8832 const char *sign = "";
8833 double val = seconds;
8834 double days, hours, mins, secs, msecs, usecs;
8835
8836 if (val == 0.0)
8837 return "";
8838 if (val < 0.0) {
8839 sign = "-";
8840 val = -val;
8841 }
8842 days = floor (val / (24.0*60.0*60.0));
8843 val -= (days * 24.0*60.0*60.0);
8844 hours = floor (val / (60.0*60.0));
8845 val -= (hours * 60.0 * 60.0);
8846 mins = floor (val / 60.0);
8847 val -= (mins * 60.0);
8848 secs = floor (val);
8849 val -= secs;
8850 val *= 1000.0;
8851 msecs = floor (val);
8852 val -= msecs;
8853 val *= 1000.0;
8854 usecs = floor (val+0.5);
8855 if (usecs == 1000.0) {
8856 usecs = 0.0;
8857 msecs += 1;
8858 }
8859 if ((msecs > 0.0) || (usecs > 0.0)) {
8860 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8861 while (frac[strlen (frac) - 1] == '0')
8862 frac[strlen (frac) - 1] = '\0';
8863 if (strlen (frac) == 1)
8864 frac[0] = '\0';
8865 }
8866 if (days > 0)
8867 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8868 sign, days, (days != 1) ? "s" : "", hours, mins,
8869 secs, frac, (days == 1) ? "s" : "");
8870 else
8871 if (hours > 0)
8872 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8873 sign, hours, mins, secs, frac);
8874 else
8875 if (mins > 0)
8876 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8877 sign, mins, secs, frac);
8878 else
8879 if (secs > 0)
8880 (void)sprintf (buf, "%s%.0f%s second",
8881 sign, secs, frac);
8882 else
8883 if (msecs > 0) {
8884 if (usecs > 0)
8885 (void)sprintf (buf, "%s%.0f.%s msec",
8886 sign, msecs, frac+4);
8887 else
8888 (void)sprintf (buf, "%s%.0f msec",
8889 sign, msecs);
8890 }
8891 else
8892 (void)sprintf (buf, "%s%.0f usec",
8893 sign, usecs);
8894 if (0 != strncmp ("1 ", buf, 2))
8895 strcpy (&buf[strlen (buf)], "s");
8896 return buf;
8897 }
8898
8899
8900
8901
8902
8903
8904
8905
8906
8907
8908
8909
8910
8911
8912
8913
8914 t_stat sim_process_event (void)
8915 {
8916 UNIT *uptr;
8917 t_stat reason;
8918 #if defined(TESTING)
8919 cpu_state_t * cpup = _cpup;
8920 #endif
8921
8922 if (stop_cpu)
8923 {
8924 #if defined(WIN_STDIO)
8925 (void)fflush(stdout);
8926 (void)fflush(stderr);
8927 #endif
8928 return SCPE_STOP;
8929 }
8930 UPDATE_SIM_TIME;
8931
8932 if (sim_clock_queue == QUEUE_LIST_END) {
8933 sim_interval = noqueue_time = NOQUEUE_WAIT;
8934 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8935 "Queue Empty New Interval = %d\r\n",
8936 sim_interval);
8937 return SCPE_OK;
8938 }
8939 sim_processing_event = TRUE;
8940 do {
8941 uptr = sim_clock_queue;
8942 sim_clock_queue = uptr->next;
8943 uptr->next = NULL;
8944 sim_interval -= uptr->time;
8945 uptr->time = 0;
8946 if (sim_clock_queue != QUEUE_LIST_END)
8947 sim_interval = sim_clock_queue->time;
8948 else
8949 sim_interval = noqueue_time = NOQUEUE_WAIT;
8950 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8951 "Processing Event for %s\r\n", sim_uname (uptr));
8952 if (uptr->action != NULL)
8953 reason = uptr->action (uptr);
8954 else
8955 reason = SCPE_OK;
8956 } while ((reason == SCPE_OK) &&
8957 (sim_interval <= 0) &&
8958 (sim_clock_queue != QUEUE_LIST_END) &&
8959 (!stop_cpu));
8960
8961 if (sim_clock_queue == QUEUE_LIST_END) {
8962 sim_interval = noqueue_time = NOQUEUE_WAIT;
8963 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8964 "Processing Queue Complete New Interval = %d\r\n",
8965 sim_interval);
8966 }
8967 else
8968 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8969 "Processing Queue Complete New Interval = %d(%s)\r\n",
8970 sim_interval, sim_uname(sim_clock_queue));
8971
8972 if ((reason == SCPE_OK) && stop_cpu)
8973 {
8974 #if defined(WIN_STDIO)
8975 (void)fflush(stdout);
8976 (void)fflush(stderr);
8977 #endif
8978 reason = SCPE_STOP;
8979 }
8980 sim_processing_event = FALSE;
8981 return reason;
8982 }
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993 t_stat sim_activate (UNIT *uptr, int32 event_time)
8994 {
8995 if (uptr->dynflags & UNIT_TMR_UNIT)
8996 return sim_timer_activate (uptr, event_time);
8997 return _sim_activate (uptr, event_time);
8998 }
8999
9000 t_stat _sim_activate (UNIT *uptr, int32 event_time)
9001 {
9002 UNIT *cptr, *prvptr;
9003 int32 accum;
9004 #if defined(TESTING)
9005 cpu_state_t * cpup = _cpup;
9006 #endif
9007
9008 if (sim_is_active (uptr))
9009 return SCPE_OK;
9010 UPDATE_SIM_TIME;
9011
9012 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
9013
9014 prvptr = NULL;
9015 accum = 0;
9016 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9017 if (event_time < (accum + cptr->time))
9018 break;
9019 accum = accum + cptr->time;
9020 prvptr = cptr;
9021 }
9022 if (prvptr == NULL) {
9023 cptr = uptr->next = sim_clock_queue;
9024 sim_clock_queue = uptr;
9025 }
9026 else {
9027 cptr = uptr->next = prvptr->next;
9028 prvptr->next = uptr;
9029 }
9030 uptr->time = event_time - accum;
9031 if (cptr != QUEUE_LIST_END)
9032 cptr->time = cptr->time - uptr->time;
9033 sim_interval = sim_clock_queue->time;
9034 return SCPE_OK;
9035 }
9036
9037
9038
9039
9040
9041
9042
9043
9044
9045
9046 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
9047 {
9048 sim_cancel (uptr);
9049 return _sim_activate (uptr, event_time);
9050 }
9051
9052
9053
9054
9055
9056
9057
9058
9059
9060
9061 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
9062 {
9063 return _sim_activate_after (uptr, usec_delay);
9064 }
9065
9066 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
9067 {
9068 if (sim_is_active (uptr))
9069 return SCPE_OK;
9070 return sim_timer_activate_after (uptr, usec_delay);
9071 }
9072
9073
9074
9075
9076
9077
9078
9079
9080
9081
9082 t_stat sim_cancel (UNIT *uptr)
9083 {
9084 UNIT *cptr, *nptr;
9085 #if defined(TESTING)
9086 cpu_state_t * cpup = _cpup;
9087 #endif
9088
9089 if (sim_clock_queue == QUEUE_LIST_END)
9090 return SCPE_OK;
9091 if (!sim_is_active (uptr))
9092 return SCPE_OK;
9093 UPDATE_SIM_TIME;
9094 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9095 nptr = QUEUE_LIST_END;
9096
9097 if (sim_clock_queue == uptr) {
9098 nptr = sim_clock_queue = uptr->next;
9099 uptr->next = NULL;
9100 }
9101 else {
9102 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9103 if (cptr->next == uptr) {
9104 nptr = cptr->next = uptr->next;
9105 uptr->next = NULL;
9106 break;
9107 }
9108 }
9109 }
9110 if (nptr != QUEUE_LIST_END)
9111 nptr->time += (uptr->next) ? 0 : uptr->time;
9112 if (!uptr->next)
9113 uptr->time = 0;
9114 if (sim_clock_queue != QUEUE_LIST_END)
9115 sim_interval = sim_clock_queue->time;
9116 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9117 if (uptr->next) {
9118 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9119 if (sim_deb)
9120 fclose(sim_deb);
9121 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9122 __func__, __FILE__, __LINE__);
9123 abort ();
9124 }
9125 return SCPE_OK;
9126 }
9127
9128
9129
9130
9131
9132
9133
9134
9135
9136 t_bool sim_is_active (UNIT *uptr)
9137 {
9138 if (uptr->next == NULL)
9139 return FALSE;
9140 else
9141 return TRUE;
9142 }
9143
9144
9145
9146
9147
9148
9149
9150
9151
9152 int32 sim_activate_time (UNIT *uptr)
9153 {
9154 UNIT *cptr;
9155 int32 accum = 0;
9156
9157 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9158 if (cptr == sim_clock_queue) {
9159 if (sim_interval > 0)
9160 accum = accum + sim_interval;
9161 }
9162 else
9163 accum = accum + cptr->time;
9164 if (cptr == uptr)
9165 return accum + 1;
9166 }
9167 return 0;
9168 }
9169
9170
9171
9172
9173
9174
9175
9176
9177 double sim_gtime (void)
9178 {
9179 return sim_time;
9180 }
9181
9182
9183
9184
9185
9186
9187
9188
9189 int32 sim_qcount (void)
9190 {
9191 int32 cnt;
9192 UNIT *uptr;
9193
9194 cnt = 0;
9195 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9196 cnt++;
9197 return cnt;
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
9225
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235 t_stat sim_brk_init (void)
9236 {
9237 int32 i;
9238
9239 for (i=0; i<sim_brk_lnt; i++) {
9240 BRKTAB *bp;
9241 if (sim_brk_tab)
9242 {
9243 bp = sim_brk_tab[i];
9244
9245 while (bp)
9246 {
9247 BRKTAB *bpt = bp->next;
9248
9249 FREE (bp->act);
9250 FREE (bp);
9251 bp = bpt;
9252 }
9253 }
9254 }
9255 if (sim_brk_tab != NULL)
9256 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9257 sim_brk_lnt = SIM_BRK_INILNT;
9258 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9259 if (sim_brk_tab == NULL)
9260 return SCPE_MEM;
9261 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9262 sim_brk_ent = sim_brk_ins = 0;
9263 sim_brk_clract ();
9264 sim_brk_npc (0);
9265 return SCPE_OK;
9266 }
9267
9268
9269
9270 BRKTAB *sim_brk_fnd (t_addr loc)
9271 {
9272 int32 lo, hi, p;
9273 BRKTAB *bp;
9274
9275 if (sim_brk_ent == 0) {
9276 sim_brk_ins = 0;
9277 return NULL;
9278 }
9279 lo = 0;
9280 hi = sim_brk_ent - 1;
9281 do {
9282 p = (lo + hi) >> 1;
9283 bp = sim_brk_tab[p];
9284 if (loc == bp->addr) {
9285 sim_brk_ins = p;
9286 return bp;
9287 }
9288 else if (loc < bp->addr)
9289 hi = p - 1;
9290 else lo = p + 1;
9291 } while (lo <= hi);
9292 if (loc < bp->addr)
9293 sim_brk_ins = p;
9294 else sim_brk_ins = p + 1;
9295 return NULL;
9296 }
9297
9298 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9299 {
9300 BRKTAB *bp = sim_brk_fnd (loc);
9301
9302 while (bp) {
9303 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9304 (bp->typ == btyp))
9305 return bp;
9306 bp = bp->next;
9307 }
9308 return bp;
9309 }
9310
9311
9312
9313 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9314 {
9315 int32 i, t;
9316 BRKTAB *bp, **newp;
9317
9318 if (sim_brk_ins < 0)
9319 return NULL;
9320 if (sim_brk_ent >= sim_brk_lnt) {
9321 t = sim_brk_lnt + SIM_BRK_INILNT;
9322 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9323 if (newp == NULL)
9324 return NULL;
9325 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9326 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9327 FREE (sim_brk_tab);
9328 sim_brk_tab = newp;
9329 sim_brk_lnt = t;
9330 }
9331 if ((sim_brk_ins == sim_brk_ent) ||
9332 ((sim_brk_ins != sim_brk_ent) &&
9333 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9334 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9335 sim_brk_tab[i] = sim_brk_tab[i - 1];
9336 sim_brk_tab[sim_brk_ins] = NULL;
9337 }
9338 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9339 if (!bp)
9340 {
9341 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9342 __func__, __FILE__, __LINE__);
9343 #if defined(USE_BACKTRACE)
9344 # if defined(SIGUSR2)
9345 (void)raise(SIGUSR2);
9346
9347 # endif
9348 #endif
9349 abort();
9350 }
9351 bp->next = sim_brk_tab[sim_brk_ins];
9352 sim_brk_tab[sim_brk_ins] = bp;
9353 if (bp->next == NULL)
9354 sim_brk_ent += 1;
9355 bp->addr = loc;
9356 bp->typ = btyp;
9357 bp->cnt = 0;
9358 bp->act = NULL;
9359 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9360 bp->time_fired[i] = -1.0;
9361 return bp;
9362 }
9363
9364
9365
9366 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9367 {
9368 BRKTAB *bp;
9369
9370 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9371 sw |= sim_brk_dflt;
9372 if (~sim_brk_types & sw) {
9373 char gbuf[CBUFSIZE];
9374
9375 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9376 }
9377 if ((sw & BRK_TYP_DYN_ALL) && act)
9378 return SCPE_ARG;
9379 bp = sim_brk_fnd (loc);
9380 if (!bp)
9381 bp = sim_brk_new (loc, sw);
9382 else {
9383 while (bp && (bp->typ != (uint32)sw))
9384 bp = bp->next;
9385 if (!bp)
9386 bp = sim_brk_new (loc, sw);
9387 }
9388 if (!bp)
9389 return SCPE_MEM;
9390 bp->cnt = ncnt;
9391 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9392 (bp->act != NULL) && (act != NULL)) {
9393 FREE (bp->act);
9394 bp->act = NULL;
9395 }
9396 if ((act != NULL) && (*act != 0)) {
9397 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9398 if (newp == NULL)
9399 return SCPE_MEM;
9400 strncpy (newp, act, CBUFSIZE);
9401 bp->act = newp;
9402 }
9403 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9404 return SCPE_OK;
9405 }
9406
9407
9408
9409 t_stat sim_brk_clr (t_addr loc, int32 sw)
9410 {
9411 BRKTAB *bpl = NULL;
9412 BRKTAB *bp = sim_brk_fnd (loc);
9413 int32 i;
9414
9415 if (!bp)
9416 return SCPE_OK;
9417 if (sw == 0)
9418 sw = SIM_BRK_ALLTYP;
9419
9420 #if !defined(__clang_analyzer__)
9421 while (bp) {
9422 if (bp->typ == (bp->typ & sw)) {
9423 FREE (bp->act);
9424 if (bp == sim_brk_tab[sim_brk_ins])
9425 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9426 else
9427 {
9428 if (bpl)
9429 bpl->next = bp->next;
9430 }
9431 FREE (bp);
9432 bp = bpl;
9433 }
9434 else {
9435 bpl = bp;
9436 bp = bp->next;
9437 }
9438 }
9439 #endif
9440 if (sim_brk_tab[sim_brk_ins] == NULL) {
9441 sim_brk_ent = sim_brk_ent - 1;
9442 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9443 sim_brk_tab[i] = sim_brk_tab[i+1];
9444 }
9445 sim_brk_summ = 0;
9446 for (i = 0; i < sim_brk_ent; i++) {
9447 bp = sim_brk_tab[i];
9448 while (bp) {
9449 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9450 bp = bp->next;
9451 }
9452 }
9453 return SCPE_OK;
9454 }
9455
9456
9457
9458 t_stat sim_brk_clrall (int32 sw)
9459 {
9460 int32 i;
9461
9462 if (sw == 0)
9463 sw = SIM_BRK_ALLTYP;
9464 for (i = 0; i < sim_brk_ent;) {
9465 t_addr loc = sim_brk_tab[i]->addr;
9466 sim_brk_clr (loc, sw);
9467 if ((i < sim_brk_ent) &&
9468 (loc == sim_brk_tab[i]->addr))
9469 ++i;
9470 }
9471 return SCPE_OK;
9472 }
9473
9474
9475
9476 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9477 {
9478 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9479 DEVICE *dptr;
9480 uint32 i, any;
9481
9482 if ((sw == 0) || (sw == SWMASK ('C'))) {
9483 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9484 if (!bp || (!(bp->typ & sw))) {
9485 return SCPE_OK; }
9486 dptr = sim_dflt_dev;
9487 if (dptr == NULL) {
9488 return SCPE_OK; }
9489 if (sw & SWMASK ('C')) {
9490 if (st != NULL) {
9491 (void)fprintf (st, "SET BREAK "); }
9492 } else {
9493 if (sim_vm_fprint_addr) {
9494 sim_vm_fprint_addr
9495 (st, dptr, loc);
9496 } else {
9497 fprint_val
9498 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9499 if (st != NULL) {
9500 (void)fprintf (st, ":\t"); }
9501 }
9502 for (i = any = 0; i < 26; i++) {
9503 if ((bp->typ >> i) & 1) {
9504 if ((sw & SWMASK ('C')) == 0) {
9505 if (any) {
9506 if (st != NULL) {
9507 (void)fprintf (st, ", "); } }
9508 if (st != NULL) {
9509 fputc (i + 'A', st); }
9510 }
9511 } else {
9512 if (st != NULL) {
9513 (void)fprintf (st, "-%c", i + 'A'); }
9514 any = 1;
9515 }
9516 }
9517 if (sw & SWMASK ('C')) {
9518 if (st != NULL) {
9519 (void)fprintf (st, " "); }
9520 if (sim_vm_fprint_addr) {
9521 if (st != NULL) {
9522 sim_vm_fprint_addr (st, dptr, loc); }
9523 } else {
9524 fprint_val
9525 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9526 }
9527 if (bp->cnt > 0) {
9528 if (st != NULL) {
9529 (void)fprintf (st, "[%d]", bp->cnt); } }
9530 if (bp->act != NULL) {
9531 if (st != NULL) {
9532 (void)fprintf (st, "; %s", bp->act); } }
9533 (void)fprintf (st, "\r\n");
9534 return SCPE_OK;
9535 }
9536
9537
9538
9539 t_stat sim_brk_showall (FILE *st, uint32 sw)
9540 {
9541 int32 bit, mask, types;
9542 BRKTAB **bpt;
9543
9544 if ((sw == 0) || (sw == SWMASK ('C')))
9545 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9546 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9547 if (sim_brk_types & (1 << bit))
9548 ++types;
9549 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9550 (void)fprintf (st, "Supported Breakpoint Types:");
9551 for (bit=0; bit <= ('Z'-'A'); bit++)
9552 if (sim_brk_types & (1 << bit))
9553 (void)fprintf (st, " -%c", 'A' + bit);
9554 (void)fprintf (st, "\r\n");
9555 }
9556 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9557 mask = (sw & sim_brk_types);
9558 (void)fprintf (st, "Displaying Breakpoint Types:");
9559 for (bit=0; bit <= ('Z'-'A'); bit++)
9560 if (mask & (1 << bit))
9561 (void)fprintf (st, " -%c", 'A' + bit);
9562 (void)fprintf (st, "\r\n");
9563 }
9564 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9565 BRKTAB *prev = NULL;
9566 BRKTAB *cur = *bpt;
9567 BRKTAB *next;
9568
9569 while (cur) {
9570 next = cur->next;
9571 cur->next = prev;
9572 prev = cur;
9573 cur = next;
9574 }
9575
9576 *bpt = prev;
9577
9578 cur = prev;
9579 while (cur) {
9580 if (cur->typ & sw)
9581 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9582 cur = cur->next;
9583 }
9584
9585 cur = prev;
9586 prev = NULL;
9587 while (cur) {
9588 next = cur->next;
9589 cur->next = prev;
9590 prev = cur;
9591 cur = next;
9592 }
9593
9594 *bpt = prev;
9595 }
9596 return SCPE_OK;
9597 }
9598
9599
9600
9601 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9602 {
9603 BRKTAB *bp;
9604 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9605
9606 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9607 btyp |= BRK_TYP_DYN_ALL;
9608
9609 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9610 double s_gtime = sim_gtime ();
9611
9612 if (bp->time_fired[spc] == s_gtime)
9613 return 0;
9614 bp->time_fired[spc] = s_gtime;
9615 if (--bp->cnt > 0)
9616 return 0;
9617 bp->cnt = 0;
9618 sim_brk_setact (bp->act);
9619 sim_brk_match_type = btyp & bp->typ;
9620 if (bp->typ & BRK_TYP_TEMP)
9621 sim_brk_clr (loc, bp->typ);
9622 sim_brk_match_addr = loc;
9623 return sim_brk_match_type;
9624 }
9625 return 0;
9626 }
9627
9628
9629
9630 CONST char *sim_brk_getact (char *buf, int32 size)
9631 {
9632 char *ep;
9633 size_t lnt;
9634
9635 if (sim_brk_act[sim_do_depth] == NULL)
9636 return NULL;
9637 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9638 sim_brk_act[sim_do_depth]++;
9639 if (*sim_brk_act[sim_do_depth] == 0) {
9640 return sim_brk_clract ();
9641 }
9642 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9643 lnt = ep - sim_brk_act[sim_do_depth];
9644 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9645 buf[lnt] = 0;
9646 sim_brk_act[sim_do_depth] += lnt + 1;
9647 }
9648 else {
9649 strncpy (buf, sim_brk_act[sim_do_depth], size);
9650 sim_brk_clract ();
9651 }
9652 return buf;
9653 }
9654
9655
9656
9657 char *sim_brk_clract (void)
9658 {
9659 FREE (sim_brk_act_buf[sim_do_depth]);
9660 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9661 }
9662
9663
9664
9665 void sim_brk_setact (const char *action)
9666 {
9667 if (action) {
9668 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9669 if (!sim_brk_act_buf[sim_do_depth])
9670 {
9671 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9672 __func__, __FILE__, __LINE__);
9673 #if defined(USE_BACKTRACE)
9674 # if defined(SIGUSR2)
9675 (void)raise(SIGUSR2);
9676
9677 # endif
9678 #endif
9679 abort();
9680 }
9681 strcpy (sim_brk_act_buf[sim_do_depth], action);
9682 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9683 }
9684 else
9685 sim_brk_clract ();
9686 }
9687
9688
9689
9690 void sim_brk_npc (uint32 cnt)
9691 {
9692 uint32 spc;
9693 BRKTAB **bpt, *bp;
9694
9695 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9696 cnt = SIM_BKPT_N_SPC;
9697 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9698 for (bp = *bpt; bp; bp = bp->next) {
9699 for (spc = 0; spc < cnt; spc++)
9700 bp->time_fired[spc] = -1.0;
9701 }
9702 }
9703 }
9704
9705
9706
9707 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9708 {
9709 BRKTAB **bpt, *bp;
9710
9711 if (spc < SIM_BKPT_N_SPC) {
9712 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9713 for (bp = *bpt; bp; bp = bp->next) {
9714 if (bp->typ & btyp)
9715 bp->time_fired[spc] = -1.0;
9716 }
9717 }
9718 }
9719 }
9720
9721 const char *sim_brk_message(void)
9722 {
9723 static char msg[256];
9724 char addr[65] = "";
9725 char buf[32];
9726
9727 msg[0] = '\0';
9728 if (sim_dflt_dev) {
9729 if (sim_vm_sprint_addr)
9730 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9731 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9732 }
9733 if (sim_brk_type_desc) {
9734 BRKTYPTAB *brk = sim_brk_type_desc;
9735
9736 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9737 if (brk->btyp == sim_brk_match_type) {
9738 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9739 break;
9740 }
9741 brk++;
9742 }
9743 }
9744 if (!msg[0])
9745 (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9746 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9747
9748 return msg;
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
9777
9778
9779
9780
9781
9782
9783
9784
9785
9786
9787 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9788 {
9789 char gbuf[CBUFSIZE];
9790 CONST char *tptr;
9791 CONST char *c1ptr;
9792 t_bool after_set = FALSE;
9793 uint32 after;
9794 int32 cnt = 0;
9795 t_stat r;
9796
9797 if (exp == NULL)
9798 return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9799 after = exp->after;
9800
9801 if ((cptr == NULL) || (*cptr == 0))
9802 return SCPE_2FARG;
9803 if (*cptr == '[') {
9804 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9805 if ((cptr == c1ptr) || (*c1ptr != ']'))
9806 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9807 cptr = c1ptr + 1;
9808 while (sim_isspace(*cptr))
9809 ++cptr;
9810 }
9811 tptr = get_glyph (cptr, gbuf, ',');
9812 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9813 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9814 if (r != SCPE_OK)
9815 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9816 after_set = TRUE;
9817 cptr = tptr;
9818 }
9819 if ((*cptr != '"') && (*cptr != '\''))
9820 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9821 cptr = get_glyph_quoted (cptr, gbuf, 0);
9822
9823 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9824 }
9825
9826
9827
9828 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9829 {
9830 char gbuf[CBUFSIZE];
9831
9832 if (NULL == cptr || !*cptr)
9833 return sim_exp_clrall (exp);
9834 if ((*cptr != '"') && (*cptr != '\''))
9835 return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9836 cptr = get_glyph_quoted (cptr, gbuf, 0);
9837 if (*cptr != '\0')
9838 return SCPE_2MARG;
9839 return sim_exp_clr (exp, gbuf);
9840 }
9841
9842
9843
9844 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9845 {
9846 size_t i;
9847
9848 if (NULL == exp->rules)
9849 return NULL;
9850 for (i=start_rule; i<exp->size; i++)
9851 if (!strcmp (exp->rules[i].match_pattern, match))
9852 return &exp->rules[i];
9853 return NULL;
9854 }
9855
9856
9857
9858 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9859 {
9860 size_t i;
9861
9862 if (NULL == ep)
9863 return SCPE_OK;
9864 FREE (ep->match);
9865 FREE (ep->match_pattern);
9866 FREE (ep->act);
9867 exp->size -= 1;
9868 #if !defined(__clang_analyzer__)
9869 for (i=ep-exp->rules; i<exp->size; i++)
9870 exp->rules[i] = exp->rules[i+1];
9871 if (exp->size == 0) {
9872 FREE (exp->rules);
9873 exp->rules = NULL;
9874 }
9875 #endif
9876 return SCPE_OK;
9877 }
9878
9879 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9880 {
9881 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9882
9883 while (ep) {
9884 sim_exp_clr_tab (exp, ep);
9885 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9886 }
9887 return SCPE_OK;
9888 }
9889
9890
9891
9892 t_stat sim_exp_clrall (EXPECT *exp)
9893 {
9894 int32 i;
9895
9896 for (i=0; i<exp->size; i++) {
9897 FREE (exp->rules[i].match);
9898 FREE (exp->rules[i].match_pattern);
9899 FREE (exp->rules[i].act);
9900 }
9901 FREE (exp->rules);
9902 exp->rules = NULL;
9903 exp->size = 0;
9904 FREE (exp->buf);
9905 exp->buf = NULL;
9906 exp->buf_size = 0;
9907 exp->buf_ins = 0;
9908 return SCPE_OK;
9909 }
9910
9911
9912
9913 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9914 {
9915 EXPTAB *ep;
9916 uint8 *match_buf;
9917 uint32 match_size;
9918 size_t i;
9919
9920
9921 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9922 if (!match_buf)
9923 return SCPE_MEM;
9924 if (switches & EXP_TYP_REGEX) {
9925 FREE (match_buf);
9926 return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9927 }
9928 else {
9929 if (switches & EXP_TYP_REGEX_I) {
9930 FREE (match_buf);
9931 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9932 }
9933 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9934 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9935 FREE (match_buf);
9936 return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9937 }
9938 }
9939 FREE (match_buf);
9940 for (i=0; i<exp->size; i++) {
9941 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9942 (exp->rules[i].switches & EXP_TYP_PERSIST))
9943 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9944 }
9945 if (after && exp->size)
9946 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9947 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9948 if (!exp->rules)
9949 {
9950 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9951 __func__, __FILE__, __LINE__);
9952 #if defined(USE_BACKTRACE)
9953 # if defined(SIGUSR2)
9954 (void)raise(SIGUSR2);
9955
9956 # endif
9957 #endif
9958 abort();
9959 }
9960 ep = &exp->rules[exp->size];
9961 exp->size += 1;
9962 exp->after = after;
9963 (void)memset (ep, 0, sizeof(*ep));
9964 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9965 if (ep->match_pattern)
9966 strcpy (ep->match_pattern, match);
9967 ep->cnt = cnt;
9968 ep->switches = switches;
9969 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9970 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9971 sim_exp_clr_tab (exp, ep);
9972 FREE (match_buf);
9973 return SCPE_MEM;
9974 }
9975 if (switches & EXP_TYP_REGEX) {
9976 FREE (match_buf);
9977 match_buf = NULL;
9978 }
9979 else {
9980 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9981 sim_decode_quoted_string (match, match_buf, &match_size);
9982 ep->match = match_buf;
9983 ep->size = match_size;
9984 }
9985 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9986 if (!ep->match_pattern)
9987 {
9988 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9989 __func__, __FILE__, __LINE__);
9990 #if defined(USE_BACKTRACE)
9991 # if defined(SIGUSR2)
9992 (void)raise(SIGUSR2);
9993
9994 # endif
9995 #endif
9996 abort();
9997 }
9998 strcpy (ep->match_pattern, match);
9999 if (ep->act) {
10000 FREE (ep->act);
10001 ep->act = NULL;
10002 }
10003 if (act) while (sim_isspace(*act)) ++act;
10004 if ((act != NULL) && (*act != 0)) {
10005 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
10006 if (newp == NULL)
10007 return SCPE_MEM;
10008 strcpy (newp, act);
10009 ep->act = newp;
10010 }
10011
10012 for (i=0; i<exp->size; i++) {
10013 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
10014 if (compare_size >= exp->buf_size) {
10015 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
10016 exp->buf_size = compare_size + 1;
10017 }
10018 }
10019 return SCPE_OK;
10020 }
10021
10022
10023
10024 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
10025 {
10026 if (!ep)
10027 return SCPE_OK;
10028 (void)fprintf (st, "EXPECT");
10029 if (ep->switches & EXP_TYP_PERSIST)
10030 (void)fprintf (st, " -p");
10031 if (ep->switches & EXP_TYP_CLEARALL)
10032 (void)fprintf (st, " -c");
10033 if (ep->switches & EXP_TYP_REGEX)
10034 (void)fprintf (st, " -r");
10035 if (ep->switches & EXP_TYP_REGEX_I)
10036 (void)fprintf (st, " -i");
10037 (void)fprintf (st, " %s", ep->match_pattern);
10038 if (ep->cnt > 0)
10039 (void)fprintf (st, " [%d]", ep->cnt);
10040 if (ep->act)
10041 (void)fprintf (st, " %s", ep->act);
10042 (void)fprintf (st, "\r\n");
10043 return SCPE_OK;
10044 }
10045
10046 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
10047 {
10048 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
10049
10050 if (exp->buf_size) {
10051 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10052
10053 (void)fprintf (st, "Match Buffer Size: %lld\r\n",
10054 (long long)exp->buf_size);
10055 (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
10056 (long long)exp->buf_ins);
10057 (void)fprintf (st, "Buffer Contents: %s\r\n",
10058 bstr);
10059 FREE (bstr);
10060 }
10061 if (exp->after)
10062 (void)fprintf (st, "Halt After: %lld instructions\r\n",
10063 (long long)exp->after);
10064 if (exp->dptr && exp->dbit)
10065 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10066 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10067 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10068 (void)fprintf (st, "Match Rules:\r\n");
10069 if (!*match)
10070 return sim_exp_showall (st, exp);
10071 if (!ep) {
10072 (void)fprintf (st, "No Rules match '%s'\r\n", match);
10073 return SCPE_ARG;
10074 }
10075 do {
10076 sim_exp_show_tab (st, exp, ep);
10077 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10078 } while (ep);
10079 return SCPE_OK;
10080 }
10081
10082
10083
10084 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
10085 {
10086 size_t i;
10087
10088 for (i=0; i < exp->size; i++)
10089 sim_exp_show_tab (st, exp, &exp->rules[i]);
10090 return SCPE_OK;
10091 }
10092
10093
10094
10095 t_stat sim_exp_check (EXPECT *exp, uint8 data)
10096 {
10097 size_t i;
10098 EXPTAB *ep = NULL;
10099 char *tstr = NULL;
10100 #if defined(TESTING)
10101 cpu_state_t * cpup = _cpup;
10102 #endif
10103
10104 if ((!exp) || (!exp->rules))
10105 return SCPE_OK;
10106
10107 exp->buf[exp->buf_ins++] = data;
10108 exp->buf[exp->buf_ins] = '\0';
10109
10110 for (i=0; i < exp->size; i++) {
10111 ep = &exp->rules[i];
10112 if (ep == NULL)
10113 break;
10114 if (ep->switches & EXP_TYP_REGEX) {
10115 }
10116 else {
10117 if (exp->buf_ins < ep->size) {
10118
10119
10120
10121
10122 if (exp->buf_ins > 0) {
10123 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10124 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10125 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10126
10127 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10128 (long long)exp->buf_ins, estr);
10129 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10130 FREE (estr);
10131 FREE (mstr);
10132 }
10133 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10134 continue;
10135 }
10136 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10137 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10138 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10139
10140 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10141 (long long)exp->buf_size-(ep->size-exp->buf_ins),
10142 (long long)ep->size-exp->buf_ins, estr);
10143 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10144 FREE (estr);
10145 FREE (mstr);
10146 }
10147 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10148 continue;
10149 break;
10150 }
10151 else {
10152 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10153 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10154 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10155
10156 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10157 (long long)exp->buf_ins-ep->size,
10158 (long long)ep->size, estr);
10159 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10160 FREE (estr);
10161 FREE (mstr);
10162 }
10163 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10164 continue;
10165 break;
10166 }
10167 }
10168 }
10169 if (exp->buf_ins == exp->buf_size) {
10170 exp->buf_ins = 0;
10171 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10172 }
10173 if ((ep != NULL) && (i != exp->size)) {
10174 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10175 if (ep->cnt > 0) {
10176 ep->cnt -= 1;
10177 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10178 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10179 }
10180 else {
10181 uint32 after = exp->after;
10182 int32 switches = ep->switches;
10183 if (ep->act && *ep->act) {
10184 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10185 }
10186 else {
10187 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10188 }
10189 sim_brk_setact (ep->act);
10190 if (ep->switches & EXP_TYP_CLEARALL)
10191 sim_exp_clrall (exp);
10192 else {
10193 if (!(ep->switches & EXP_TYP_PERSIST))
10194 sim_exp_clr_tab (exp, ep);
10195 }
10196 sim_activate (&sim_expect_unit,
10197 (switches & EXP_TYP_TIME) ?
10198 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10199 after);
10200 }
10201
10202 exp->buf_ins = 0;
10203 }
10204 if (tstr)
10205 FREE (tstr);
10206 return SCPE_OK;
10207 }
10208
10209
10210
10211 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10212 {
10213 if (snd->extoff != 0) {
10214 if (snd->insoff > snd->extoff)
10215 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10216 snd->insoff -= snd->extoff;
10217 snd->extoff = 0;
10218 }
10219 if (snd->insoff+size > snd->bufsize) {
10220 snd->bufsize = snd->insoff+size;
10221 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10222 if (!snd->buffer)
10223 {
10224 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10225 __func__, __FILE__, __LINE__);
10226 #if defined(USE_BACKTRACE)
10227 # if defined(SIGUSR2)
10228 (void)raise(SIGUSR2);
10229
10230 # endif
10231 #endif
10232 abort();
10233 }
10234 }
10235 memcpy(snd->buffer+snd->insoff, data, size);
10236 snd->insoff += size;
10237 if (delay)
10238 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10239 if (after)
10240 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10241 if (snd->after == 0)
10242 snd->after = snd->delay;
10243 snd->next_time = sim_gtime() + snd->after;
10244 return SCPE_OK;
10245 }
10246
10247
10248 t_stat sim_send_clear (SEND *snd)
10249 {
10250 snd->insoff = 0;
10251 snd->extoff = 0;
10252 return SCPE_OK;
10253 }
10254
10255
10256
10257 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10258 {
10259 if (snd->extoff < snd->insoff) {
10260 (void)fprintf (st, "%lld bytes of pending input Data:\r\n ",
10261 (long long)snd->insoff-snd->extoff);
10262 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10263 (void)fprintf (st, "\r\n");
10264 }
10265 else
10266 (void)fprintf (st, "No Pending Input Data\r\n");
10267 if ((snd->next_time - sim_gtime()) > 0) {
10268 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10269 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10270 (int)(snd->next_time - sim_gtime()),
10271 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10272 else
10273 (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10274 (int)(snd->next_time - sim_gtime()));
10275 }
10276 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10277 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10278 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10279 else
10280 (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10281 (int)snd->delay);
10282 if (snd->dptr && snd->dbit)
10283 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10284 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10285 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10286 return SCPE_OK;
10287 }
10288
10289
10290
10291 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10292 {
10293 #if defined(TESTING)
10294 cpu_state_t * cpup = _cpup;
10295 #endif
10296 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10297 if (sim_gtime() < snd->next_time) {
10298 *stat = SCPE_OK;
10299 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10300 }
10301 else {
10302 char dstr[8] = "";
10303 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10304 snd->next_time = sim_gtime() + snd->delay;
10305 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10306 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10307 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10308 }
10309 return TRUE;
10310 }
10311 return FALSE;
10312 }
10313
10314
10315
10316 const char *sim_error_text (t_stat stat)
10317 {
10318 static char msgbuf[64];
10319
10320 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10321 if (stat == SCPE_OK)
10322 return "No Error";
10323 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10324 return scp_errors[stat-SCPE_BASE].message;
10325 (void)sprintf(msgbuf, "Error %d", stat);
10326 return msgbuf;
10327 }
10328
10329 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10330 {
10331 char gbuf[CBUFSIZE];
10332 size_t cond;
10333
10334 *stat = SCPE_ARG;
10335 cptr = get_glyph (cptr, gbuf, 0);
10336 if (0 == memcmp("SCPE_", gbuf, 5))
10337 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10338 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10339 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10340 cond += SCPE_BASE;
10341 break;
10342 }
10343 if (0 == strcmp(gbuf, "OK"))
10344 cond = SCPE_OK;
10345 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10346 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10347 if (0 == numeric_cond)
10348 return SCPE_ARG;
10349 cond = (t_stat) numeric_cond;
10350 }
10351 if (cond > SCPE_MAX_ERR)
10352 return SCPE_ARG;
10353 *stat = cond;
10354 return SCPE_OK;
10355 }
10356
10357
10358
10359 const char* debug_bstates = "01_^";
10360 char debug_line_prefix[256];
10361 int32 debug_unterm = 0;
10362
10363
10364
10365 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10366 {
10367 static const char *debtab_none = "DEBTAB_ISNULL";
10368 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10369 const char *some_match = NULL;
10370 int32 offset = 0;
10371
10372 if (dptr->debflags == 0)
10373 return debtab_none;
10374
10375 dbits &= dptr->dctrl;
10376
10377
10378
10379 while ((offset < 32) && dptr->debflags[offset].name) {
10380 if (dptr->debflags[offset].mask == dbits)
10381 return dptr->debflags[offset].name;
10382 if (dptr->debflags[offset].mask & dbits)
10383 some_match = dptr->debflags[offset].name;
10384 offset++;
10385 }
10386 return some_match ? some_match : debtab_nomatch;
10387 }
10388
10389
10390
10391 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10392 {
10393 const char* debug_type = get_dbg_verb (dbits, dptr);
10394 char tim_t[32] = "";
10395 char tim_a[32] = "";
10396 char pc_s[64] = "";
10397 struct timespec time_now;
10398
10399 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10400 clock_gettime(CLOCK_REALTIME, &time_now);
10401 if (sim_deb_switches & SWMASK ('R'))
10402 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10403 if (sim_deb_switches & SWMASK ('T')) {
10404 time_t tnow = (time_t)time_now.tv_sec;
10405 struct tm *now = gmtime(&tnow);
10406 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10407 (int)now->tm_hour,
10408 (int)now->tm_min,
10409 (int)now->tm_sec,
10410 (long)(time_now.tv_nsec / 1000000));
10411 }
10412 if (sim_deb_switches & SWMASK ('A')) {
10413 (void)sprintf(tim_t, "%d.%03ld ",
10414 (int)(time_now.tv_sec),
10415 (long)(time_now.tv_nsec / 1000000));
10416 }
10417 }
10418 if (sim_deb_switches & SWMASK ('P')) {
10419 t_value val;
10420
10421 if (sim_vm_pc_value)
10422 val = (*sim_vm_pc_value)();
10423 else
10424 val = get_rval (sim_PC, 0);
10425 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10426 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10427 }
10428 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10429 tim_t, tim_a, sim_gtime(), pc_s,
10430 "", dptr->name, debug_type);
10431 return debug_line_prefix;
10432 }
10433
10434 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10435 {
10436 int32 i, fields, offset;
10437 uint32 value, beforevalue, mask;
10438
10439 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10440 if (bitdefs[fields].offset == 0xffffffff)
10441 bitdefs[fields].offset = offset;
10442 offset += bitdefs[fields].width;
10443 }
10444 for (i = fields-1; i >= 0; i--) {
10445 if (bitdefs[i].name[0] == '\0')
10446 continue;
10447 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10448 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10449 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10450 }
10451 else {
10452 const char *delta = "";
10453 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10454 value = (uint32)((after >> bitdefs[i].offset) & mask);
10455 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10456 if (value < beforevalue)
10457 delta = "_";
10458 if (value > beforevalue)
10459 delta = "^";
10460 if (bitdefs[i].valuenames)
10461 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10462 else
10463 if (bitdefs[i].format) {
10464 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10465 (void)Fprintf(stream, bitdefs[i].format, value);
10466 (void)Fprintf(stream, " ");
10467 }
10468 else
10469 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10470 }
10471 }
10472 }
10473
10474
10475
10476
10477
10478 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10479 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10480 {
10481 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10482 if (!debug_unterm)
10483 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10484 if (header)
10485 (void)fprintf(sim_deb, "%s: ", header);
10486 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10487 if (terminate)
10488 (void)fprintf(sim_deb, "\r\n");
10489 debug_unterm = terminate ? 0 : 1;
10490 }
10491 }
10492 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10493 uint32 before, uint32 after, int terminate)
10494 {
10495 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10496 }
10497
10498
10499 void sim_printf (const char* fmt, ...)
10500 {
10501 char stackbuf[STACKBUFSIZE];
10502 int32 bufsize = sizeof(stackbuf);
10503 char *buf = stackbuf;
10504 int32 len;
10505 va_list arglist;
10506
10507 while (1) {
10508 va_start (arglist, fmt);
10509 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10510 va_end (arglist);
10511
10512
10513
10514 if ((len < 0) || (len >= bufsize-1)) {
10515 if (buf != stackbuf)
10516 FREE (buf);
10517 if (bufsize >= (INT_MAX / 2))
10518 return;
10519 bufsize = bufsize * 2;
10520 if (bufsize < len + 2)
10521 bufsize = len + 2;
10522 buf = (char *) malloc (bufsize);
10523 if (buf == NULL)
10524 return;
10525 buf[bufsize-1] = '\0';
10526 continue;
10527 }
10528 break;
10529 }
10530
10531 if (sim_is_running) {
10532 char *c, *remnant = buf;
10533 while ((c = strchr(remnant, '\n'))) {
10534 if ((c != buf) && (*(c - 1) != '\r'))
10535 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10536 else
10537 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10538 remnant = c + 1;
10539 }
10540 (void)printf("%s", remnant);
10541 }
10542 else
10543 (void)printf("%s", buf);
10544
10545
10546
10547
10548
10549
10550
10551 (void)fflush (stdout);
10552 if (sim_log && (sim_log != stdout)) {
10553 (void)fprintf (sim_log, "%s", buf);
10554 (void)fflush (sim_log);
10555 }
10556 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log)) {
10557 (void)fprintf (sim_deb, "%s", buf);
10558 (void)fflush (sim_deb);
10559 }
10560
10561 if (buf != stackbuf)
10562 FREE (buf);
10563 }
10564
10565
10566 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10567 {
10568 char stackbuf[STACKBUFSIZE];
10569 size_t bufsize = sizeof(stackbuf);
10570 char *buf = stackbuf;
10571 size_t len;
10572 va_list arglist;
10573 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10574
10575 while (1) {
10576 va_start (arglist, fmt);
10577 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10578 va_end (arglist);
10579
10580
10581
10582 if (len >= bufsize - 1) {
10583 if (buf != stackbuf)
10584 FREE (buf);
10585 bufsize = bufsize * 2;
10586 if (bufsize < len + 2)
10587 bufsize = len + 2;
10588 buf = (char *) malloc (bufsize);
10589 if (buf == NULL)
10590 return SCPE_MEM;
10591 buf[bufsize-1] = '\0';
10592 continue;
10593 }
10594 break;
10595 }
10596
10597 if (sim_do_ocptr[sim_do_depth]) {
10598 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10599 sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10600 else {
10601 if (sim_deb)
10602 (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10603 }
10604 }
10605 if (sim_is_running && !inhibit_message) {
10606 char *c, *remnant = buf;
10607 while ((c = strchr(remnant, '\n'))) {
10608 if ((c != buf) && (*(c - 1) != '\r'))
10609 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10610 else
10611 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10612 remnant = c + 1;
10613 }
10614 (void)printf("%s", remnant);
10615 }
10616 else {
10617 if (!inhibit_message)
10618 (void)printf("%s", buf);
10619 }
10620 if (sim_log && (sim_log != stdout) && !inhibit_message)
10621 (void)fprintf (sim_log, "%s", buf);
10622 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10623 (void)fprintf (sim_deb, "%s", buf);
10624
10625 if (buf != stackbuf)
10626 FREE (buf);
10627 return stat | SCPE_NOMESSAGE;
10628 }
10629
10630
10631
10632
10633
10634
10635
10636
10637
10638 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10639 {
10640 DEVICE *dptr = (DEVICE *)vdptr;
10641 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10642 char stackbuf[STACKBUFSIZE];
10643 int32 bufsize = sizeof(stackbuf);
10644 char *buf = stackbuf;
10645 va_list arglist;
10646 int32 i, j, len;
10647 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10648
10649 buf[bufsize-1] = '\0';
10650 while (1) {
10651 va_start (arglist, fmt);
10652 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10653 va_end (arglist);
10654
10655
10656
10657 if ((len < 0) || (len >= bufsize-1)) {
10658 if (buf != stackbuf)
10659 FREE (buf);
10660 if (bufsize >= (INT_MAX / 2))
10661 return;
10662 bufsize = bufsize * 2;
10663 if (bufsize < len + 2)
10664 bufsize = len + 2;
10665 buf = (char *) malloc (bufsize);
10666 if (buf == NULL)
10667 return;
10668 buf[bufsize-1] = '\0';
10669 continue;
10670 }
10671 break;
10672 }
10673
10674
10675
10676 for (i = j = 0; i < len; ++i) {
10677 if ('\n' == buf[i]) {
10678 if (i >= j) {
10679 if ((i != j) || (i == 0)) {
10680 if (debug_unterm)
10681 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10682 else
10683 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10684 }
10685 debug_unterm = 0;
10686 }
10687 j = i + 1;
10688 }
10689 }
10690 if (i > j) {
10691 if (debug_unterm)
10692 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10693 else
10694 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10695 }
10696
10697
10698
10699 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10700 if (buf != stackbuf)
10701 FREE (buf);
10702 }
10703 return;
10704 }
10705
10706 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10707 {
10708 #if defined(TESTING)
10709 cpu_state_t * cpup = _cpup;
10710 #endif
10711 if (sim_deb && (dptr->dctrl & reason)) {
10712 sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10713 if (data && len) {
10714 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10715 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10716 static char hex[] = "0123456789ABCDEF";
10717 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10718 static unsigned char ebcdic2ascii[] = {
10719 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10720 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10721 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10722 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10723 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10724 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10725 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10726 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10727 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10728 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10729 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10730 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10731 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10732 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10733 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10734 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10735 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10736 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10737 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10738 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10739 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10740 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10741 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10742 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10743 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10744 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10745 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10746 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10747 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10748 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10749 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10750 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10751 };
10752
10753 for (i=same=0; i<len; i += 16) {
10754 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10755 ++same;
10756 continue;
10757 }
10758 if (same > 0) {
10759 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10760 (unsigned long int)(i - (16*same)),
10761 (unsigned long int)(i - 1));
10762 same = 0;
10763 }
10764 group = (((len - i) > 16) ? 16 : (len - i));
10765 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10766 eidx = strlen(ebcdicbuf);
10767 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10768 ridx = strlen(rad50buf);
10769 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10770 soff = strlen(strbuf);
10771 for (sidx=oidx=0; sidx<group; ++sidx) {
10772 outbuf[oidx++] = ' ';
10773 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10774 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10775 if (sim_isprint (data[i+sidx]))
10776 strbuf[soff+sidx] = data[i+sidx];
10777 else
10778 strbuf[soff+sidx] = '.';
10779 if (ridx && ((sidx&1) == 0)) {
10780 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10781
10782 if (word >= 64000) {
10783 rad50buf[ridx++] = '|';
10784 rad50buf[ridx++] = '|';
10785 rad50buf[ridx++] = '|';
10786 }
10787 else {
10788 rad50buf[ridx++] = rad50[word/1600];
10789 rad50buf[ridx++] = rad50[(word/40)%40];
10790 rad50buf[ridx++] = rad50[word%40];
10791 }
10792 }
10793 if (eidx) {
10794 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10795 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10796 else
10797 ebcdicbuf[eidx++] = '.';
10798 }
10799 }
10800 outbuf[oidx] = '\0';
10801 strbuf[soff+sidx] = '\0';
10802 ebcdicbuf[eidx] = '\0';
10803 rad50buf[ridx] = '\0';
10804 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10805 (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10806 }
10807 if (same > 0) {
10808 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10809 (unsigned long int)(i-(16*same)),
10810 (unsigned long int)(len-1));
10811 }
10812 }
10813 }
10814 }
10815
10816 int Fprintf (FILE *f, const char* fmt, ...)
10817 {
10818 int ret = 0;
10819 va_list args;
10820
10821 va_start (args, fmt);
10822 ret = vfprintf (f, fmt, args);
10823 va_end (args);
10824 return ret;
10825 }
10826
10827
10828
10829
10830
10831
10832
10833
10834
10835
10836
10837
10838
10839
10840
10841
10842
10843
10844
10845 #define blankch(x) ((x) == ' ' || (x) == '\t')
10846
10847 typedef struct topic {
10848 size_t level;
10849 char *title;
10850 char *label;
10851 struct topic *parent;
10852 struct topic **children;
10853 uint32 kids;
10854 char *text;
10855 size_t len;
10856 uint32 flags;
10857 size_t kidwid;
10858 #define HLP_MAGIC_TOPIC 1
10859 } TOPIC;
10860
10861 static volatile struct {
10862 const char *error;
10863 const char *prox;
10864 size_t block;
10865 size_t line;
10866 } help_where = { "", NULL, 0, 0 };
10867 jmp_buf help_env;
10868
10869 #define FAIL(why,text,here) \
10870 { \
10871 help_where.error = #text; \
10872 help_where.prox = here; \
10873 longjmp ( help_env, (why) ); \
10874 \
10875 }
10876
10877
10878
10879
10880
10881
10882 static void appendText (TOPIC *topic, const char *text, size_t len)
10883 {
10884 char *newt;
10885
10886 if (!len)
10887 return;
10888
10889 newt = (char *)realloc (topic->text, topic->len + len +1);
10890 if (!newt) {
10891 #if !defined(SUNLINT)
10892 FAIL (SCPE_MEM, No memory, NULL);
10893 #endif
10894 }
10895 topic->text = newt;
10896 memcpy (newt + topic->len, text, len);
10897 topic->len +=len;
10898 newt[topic->len] = '\0';
10899 return;
10900 }
10901
10902
10903
10904 static void cleanHelp (TOPIC *topic)
10905 {
10906 TOPIC *child;
10907 size_t i;
10908
10909 FREE (topic->title);
10910 FREE (topic->text);
10911 FREE (topic->label);
10912 for (i = 0; i < topic->kids; i++) {
10913 child = topic->children[i];
10914 cleanHelp (child);
10915 FREE (child);
10916 }
10917 FREE (topic->children);
10918 return;
10919 }
10920
10921
10922
10923
10924 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10925 UNIT *uptr, const char *htext, va_list ap)
10926 {
10927 char *end;
10928 size_t n, ilvl;
10929 #define VSMAX 100
10930 char *vstrings[VSMAX];
10931 size_t vsnum = 0;
10932 char * astrings[VSMAX+1];
10933 size_t asnum = 0;
10934 char *const *hblock;
10935 const char *ep;
10936 t_bool excluded = FALSE;
10937
10938
10939
10940
10941
10942
10943
10944 (void)memset (vstrings, 0, sizeof (vstrings));
10945 (void)memset (astrings, 0, sizeof (astrings));
10946 astrings[asnum++] = (char *) htext;
10947
10948 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10949 help_where.block = hblock - astrings;
10950 help_where.line = 0;
10951 while (*htext) {
10952 const char *start;
10953
10954 help_where.line++;
10955 if (sim_isspace (*htext) || *htext == '+') {
10956 if (excluded) {
10957 while (*htext && *htext != '\n')
10958 htext++;
10959 if (*htext)
10960 ++htext;
10961 continue;
10962 }
10963 ilvl = 1;
10964 appendText (topic, " ", 4);
10965 if (*htext == '+') {
10966 while (*htext == '+') {
10967 ilvl++;
10968 appendText (topic, " ", 4);
10969 htext++;
10970 }
10971 }
10972 while (*htext && *htext != '\n' && sim_isspace (*htext))
10973 htext++;
10974 if (!*htext)
10975 break;
10976 start = htext;
10977 while (*htext) {
10978 if (*htext == '%') {
10979 appendText (topic, start, htext - start);
10980 switch (*++htext) {
10981 case 'U':
10982 if (dptr) {
10983 char buf[129];
10984 n = uptr? uptr - dptr->units: 0;
10985 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10986 appendText (topic, buf, strlen (buf));
10987 }
10988 break;
10989 case 'D':
10990 if (dptr != NULL)
10991 appendText (topic, dptr->name, strlen (dptr->name));
10992 break;
10993 case 'S':
10994 appendText (topic, sim_name, strlen (sim_name));
10995 break;
10996 case '%':
10997 appendText (topic, "%", 1);
10998 break;
10999 case '+':
11000 appendText (topic, "+", 1);
11001 break;
11002 default:
11003 if (sim_isdigit (*htext)) {
11004 n = 0;
11005 while (sim_isdigit (*htext))
11006 n += (n * 10) + (*htext++ - '0');
11007 if (( *htext != 'H' && *htext != 's') ||
11008 n == 0 || n >= VSMAX) {
11009 #if !defined(SUNLINT)
11010 FAIL (SCPE_ARG, Invalid escape, htext);
11011 #endif
11012 }
11013 while (n > vsnum)
11014 vstrings[vsnum++] = va_arg (ap, char *);
11015 start = vstrings[n-1];
11016 if (*htext == 'H') {
11017 if (asnum >= VSMAX) {
11018 #if !defined(SUNLINT)
11019 FAIL (SCPE_ARG, Too many blocks, htext);
11020 #endif
11021 }
11022 astrings[asnum++] = (char *)start;
11023 break;
11024 }
11025 ep = start;
11026 while (*ep) {
11027 if (*ep == '\n') {
11028 ep++;
11029 appendText (topic, start, ep - start);
11030 if (*ep) {
11031 size_t i;
11032 for (i = 0; i < ilvl; i++)
11033 appendText (topic, " ", 4);
11034 }
11035 start = ep;
11036 }
11037 else
11038 ep++;
11039 }
11040 appendText (topic, start, ep-start);
11041 break;
11042 }
11043 #if !defined(SUNLINT)
11044 FAIL (SCPE_ARG, Invalid escape, htext);
11045 #endif
11046 }
11047 start = ++htext;
11048 continue;
11049 }
11050 if (*htext == '\n') {
11051 htext++;
11052 appendText (topic, start, htext - start);
11053 break;
11054 }
11055 htext++;
11056 }
11057 continue;
11058 }
11059 if (sim_isdigit (*htext)) {
11060 TOPIC **children;
11061 TOPIC *newt;
11062 char nbuf[100];
11063
11064 n = 0;
11065 start = htext;
11066 while (sim_isdigit (*htext))
11067 n += (n * 10) + (*htext++ - '0');
11068 if ((htext == start) || !n) {
11069 #if !defined(SUNLINT)
11070 FAIL (SCPE_ARG, Invalid topic heading, htext);
11071 #endif
11072 }
11073 if (n <= topic->level) {
11074 while (n <= topic->level)
11075 topic = topic->parent;
11076 }
11077 else {
11078 if (n > topic->level + 1) {
11079 #if !defined(SUNLINT)
11080 FAIL (SCPE_ARG, Level not contiguous, htext);
11081 #endif
11082 }
11083 }
11084 while (*htext && (*htext != '\n') && sim_isspace (*htext))
11085 htext++;
11086 if (!*htext || (*htext == '\n')) {
11087 #if !defined(SUNLINT)
11088 FAIL (SCPE_ARG, Missing topic name, htext);
11089 #endif
11090 }
11091 start = htext;
11092 while (*htext && (*htext != '\n'))
11093 htext++;
11094 if (start == htext) {
11095 #if !defined(SUNLINT)
11096 FAIL (SCPE_ARG, Null topic name, htext);
11097 #endif
11098 }
11099 excluded = FALSE;
11100 if (*start == '?') {
11101 size_t n = 0;
11102 start++;
11103 while (sim_isdigit (*start))
11104 n += (n * 10) + (*start++ - '0');
11105 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11106 #if !defined(SUNLINT)
11107 FAIL (SCPE_ARG, Invalid parameter number, start);
11108 #endif
11109 }
11110 while (n > vsnum)
11111 vstrings[vsnum++] = va_arg (ap, char *);
11112 end = vstrings[n-1];
11113 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11114 excluded = TRUE;
11115 if (*htext)
11116 htext++;
11117 continue;
11118 }
11119 }
11120 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11121 if (!newt) {
11122 #if !defined(SUNLINT)
11123 FAIL (SCPE_MEM, No memory, NULL);
11124 #endif
11125 }
11126 size_t len = (htext > start) ? (htext - start) : 0;
11127 newt->title = (char *) malloc(len + 1);
11128 if (!newt->title) {
11129 FREE (newt);
11130 #if !defined(SUNLINT)
11131 FAIL (SCPE_MEM, No memory, NULL);
11132 #endif
11133 }
11134 memcpy (newt->title, start, htext - start);
11135 newt->title[htext - start] = '\0';
11136 if (*htext)
11137 htext++;
11138
11139 if (newt->title[0] == '$')
11140 newt->flags |= HLP_MAGIC_TOPIC;
11141
11142 children = (TOPIC **) realloc (topic->children,
11143 (topic->kids +1) * sizeof (TOPIC *));
11144 if (NULL == children) {
11145 FREE (newt->title);
11146 FREE (newt);
11147 #if !defined(SUNLINT)
11148 FAIL (SCPE_MEM, No memory, NULL);
11149 #endif
11150 }
11151 topic->children = children;
11152 topic->children[topic->kids++] = newt;
11153 newt->level = n;
11154 newt->parent = topic;
11155 n = strlen (newt->title);
11156 if (n > topic->kidwid)
11157 topic->kidwid = n;
11158 (void)sprintf (nbuf, ".%u", topic->kids);
11159 n = strlen (topic->label) + strlen (nbuf) + 1;
11160 newt->label = (char *) malloc (n);
11161 if (NULL == newt->label) {
11162 FREE (newt->title);
11163 topic->children[topic->kids -1] = NULL;
11164 FREE (newt);
11165 #if !defined(SUNLINT)
11166 FAIL (SCPE_MEM, No memory, NULL);
11167 #endif
11168 }
11169 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11170 topic = newt;
11171 continue;
11172 }
11173 if (*htext == ';') {
11174 while (*htext && *htext != '\n')
11175 htext++;
11176 continue;
11177 }
11178 #if !defined(SUNLINT)
11179 FAIL (SCPE_ARG, Unknown line type, htext);
11180 #endif
11181 }
11182 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11183 vsnum = 0;
11184 }
11185
11186 return topic;
11187 }
11188
11189
11190
11191
11192
11193 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
11194 {
11195 char *prefix;
11196 char *newp, *newt;
11197
11198 if (topic->level == 0) {
11199 prefix = (char *) calloc (2,1);
11200 if (!prefix) {
11201 #if !defined(SUNLINT)
11202 FAIL (SCPE_MEM, No memory, NULL);
11203 #endif
11204 }
11205 prefix[0] = '\n';
11206 }
11207 else
11208 prefix = helpPrompt (topic->parent, "", oneword);
11209
11210 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11211 strlen (pstring) +1);
11212 if (!newp) {
11213 FREE (prefix);
11214 #if !defined(SUNLINT)
11215 FAIL (SCPE_MEM, No memory, NULL);
11216 #endif
11217 }
11218 strcpy (newp, prefix);
11219 if (topic->children) {
11220 if (topic->level != 0)
11221 strcat (newp, " ");
11222 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11223 topic->title+1: topic->title;
11224 if (oneword) {
11225 char *np = newp + strlen (newp);
11226 while (*newt) {
11227 *np++ = blankch (*newt)? '_' : *newt;
11228 newt++;
11229 }
11230 *np = '\0';
11231 }
11232 else
11233 strcat (newp, newt);
11234 if (*pstring && *pstring != '?')
11235 strcat (newp, " ");
11236 }
11237 strcat (newp, pstring);
11238 FREE (prefix);
11239 return newp;
11240 }
11241
11242 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11243 {
11244 char tbuf[CBUFSIZE];
11245 size_t i, skiplines;
11246 #if defined(_WIN32)
11247 FILE *tmp;
11248 char *tmpnam;
11249
11250 do {
11251 int fd;
11252 tmpnam = _tempnam (NULL, "simh");
11253 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11254 if (fd != -1) {
11255 tmp = _fdopen (fd, "w+");
11256 break;
11257 }
11258 } while (1);
11259 #else
11260 FILE *tmp = tmpfile();
11261 #endif
11262
11263 if (!tmp) {
11264 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11265 xstrerror_l(errno), errno);
11266 return;
11267 }
11268
11269 if (topic->title)
11270 (void)fprintf (st, "%s\r\n", topic->title+1);
11271
11272 skiplines = 0;
11273 if (topic->title) {
11274 if (!strcmp (topic->title+1, "Registers")) {
11275 fprint_reg_help (tmp, dptr) ;
11276 skiplines = 1;
11277 }
11278 else
11279 if (!strcmp (topic->title+1, "Set commands")) {
11280 fprint_set_help (tmp, dptr);
11281 skiplines = 3;
11282 }
11283 else
11284 if (!strcmp (topic->title+1, "Show commands")) {
11285 fprint_show_help (tmp, dptr);
11286 skiplines = 3;
11287 }
11288 }
11289 rewind (tmp);
11290 if (errno) {
11291 (void)fprintf (st, "rewind: error %d\r\n", errno);
11292 }
11293
11294
11295
11296 for (i =0; i < skiplines; i++)
11297 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11298
11299 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11300 if (tbuf[0] != '\n')
11301 fputs (" ", st);
11302 fputs (tbuf, st);
11303 }
11304 fclose (tmp);
11305 #if defined(_WIN32)
11306 remove (tmpnam);
11307 FREE (tmpnam);
11308 #endif
11309 return;
11310 }
11311
11312
11313 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11314 UNIT *uptr, int32 flag,
11315 TOPIC *topic, va_list ap )
11316 {
11317 size_t i;
11318
11319 if (topic->flags & HLP_MAGIC_TOPIC) {
11320 (void)fprintf (st, "\r\n%s ", topic->label);
11321 displayMagicTopic (st, dptr, topic);
11322 }
11323 else
11324 (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11325
11326
11327
11328
11329
11330
11331 if (topic->text)
11332 fputs (topic->text, st);
11333
11334 for (i = 0; i < topic->kids; i++)
11335 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11336
11337 return SCPE_OK;
11338 }
11339
11340 #define HLP_MATCH_AMBIGUOUS (~0u)
11341 #define HLP_MATCH_WILDCARD (~1U)
11342 #define HLP_MATCH_NONE 0
11343 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11344 {
11345 size_t i, match;
11346 char cbuf[CBUFSIZE], *cptr;
11347
11348 if (!strcmp (token, "*"))
11349 return HLP_MATCH_WILDCARD;
11350
11351 match = 0;
11352 for (i = 0; i < topic->kids; i++) {
11353 strcpy (cbuf,topic->children[i]->title +
11354 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11355 cptr = cbuf;
11356 while (*cptr) {
11357 if (blankch (*cptr)) {
11358 *cptr++ = '_';
11359 }
11360 else {
11361 *cptr = (char)toupper (*cptr);
11362 cptr++;
11363 }
11364 }
11365 if (!strcmp (cbuf, token))
11366 return i+1;
11367 if (!strncmp (cbuf, token, strlen (token))) {
11368 if (match)
11369 return HLP_MATCH_AMBIGUOUS;
11370 match = i+1;
11371 }
11372 }
11373 return match;
11374 }
11375
11376
11377
11378 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11379 UNIT *uptr, int32 flag,
11380 const char *help, const char *cptr, va_list ap)
11381 {
11382 TOPIC top;
11383 TOPIC *topic = ⊤
11384 int failed;
11385 size_t match;
11386 size_t i;
11387 const char *p;
11388 t_bool flat_help = FALSE;
11389 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11390
11391 static const char attach_help[] = { " ATTACH" };
11392 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\r\n" };
11393 static const char onecmd_help[] = { "%s help.\r\n" };
11394 static const char help_help[] = {
11395
11396 " To see more HELP information, type the listed subtopic name. To move\r\n"
11397 " up a level, just type <CR>. To review the current subtopic, type \"?\".\r\n"
11398 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11399 };
11400
11401 (void)memset (&top, 0, sizeof(top));
11402 top.parent = ⊤
11403 if ((failed = setjmp (help_env)) != 0) {
11404 (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11405 "Error in block %u line %u: %s\r\n"
11406 "%s%*.*s%s\r\n",
11407 (int)help_where.block, (int)help_where.line, help_where.error,
11408 help_where.prox ? "Near '" : "",
11409 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11410 help_where.prox ? help_where.prox : "",
11411 help_where.prox ? "'" : "");
11412 cleanHelp (&top);
11413 return failed;
11414 }
11415
11416
11417
11418
11419
11420 if (dptr) {
11421 p = dptr->name;
11422 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11423 }
11424 else
11425 p = sim_name;
11426 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11427 if (!top.title)
11428 {
11429 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11430 __func__, __FILE__, __LINE__);
11431 #if defined(USE_BACKTRACE)
11432 # if defined(SIGUSR2)
11433 (void)raise(SIGUSR2);
11434
11435 # endif
11436 #endif
11437 abort();
11438 }
11439 for (i = 0; p[i]; i++ )
11440 top.title[i] = (char)toupper (p[i]);
11441 top.title[i] = '\0';
11442 if (flag & SCP_HELP_ATTACH)
11443 strcpy (top.title+i, attach_help);
11444
11445 top.label = (char *) malloc (sizeof ("1"));
11446 if (!top.label)
11447 {
11448 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11449 __func__, __FILE__, __LINE__);
11450 #if defined(USE_BACKTRACE)
11451 # if defined(SIGUSR2)
11452 (void)raise(SIGUSR2);
11453
11454 # endif
11455 #endif
11456 abort();
11457 }
11458 strcpy (top.label, "1");
11459
11460 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11461
11462 if (flat_help) {
11463 flag |= SCP_HELP_FLAT;
11464 if (sim_ttisatty())
11465 (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11466 else
11467 (void)fprintf (st, "%s help.\r\n", top.title);
11468 }
11469 else
11470 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11471
11472
11473
11474 (void) buildHelp (&top, dptr, uptr, help, ap);
11475
11476
11477
11478 while (cptr && *cptr) {
11479 cptr = get_glyph (cptr, gbuf, 0);
11480 if (!gbuf[0])
11481 break;
11482 if (!strcmp (gbuf, "HELP")) {
11483 (void)fprintf (st, "\r\n");
11484 fputs (help_help, st);
11485 break;
11486 }
11487 match = matchHelpTopicName (topic, gbuf);
11488 if (match == HLP_MATCH_WILDCARD) {
11489 if (dptr)
11490 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11491 cleanHelp (&top);
11492 return SCPE_OK;
11493 }
11494 if (match == HLP_MATCH_AMBIGUOUS) {
11495 (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11496 break;
11497 }
11498 if (match == HLP_MATCH_NONE) {
11499 (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11500 break;
11501 }
11502 topic = topic->children[match-1];
11503 }
11504 cptr = NULL;
11505
11506 if (flat_help) {
11507 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11508 cleanHelp (&top);
11509 return SCPE_OK;
11510 }
11511
11512
11513
11514 while (TRUE) {
11515 char *pstring;
11516 const char *prompt[2] = {"? ", "Subtopic? "};
11517
11518
11519
11520 if (topic->flags & HLP_MAGIC_TOPIC) {
11521 fputc ('\n', st);
11522 displayMagicTopic (st, dptr, topic);
11523 }
11524 else
11525 (void)fprintf (st, "\r\n%s\r\n", topic->title);
11526
11527
11528
11529
11530
11531 if (topic->text)
11532 fputs (topic->text, st);
11533
11534 if (topic->kids) {
11535 size_t w = 0;
11536 char *p;
11537 char tbuf[CBUFSIZE];
11538
11539 (void)fprintf (st, "\r\n Additional information available:\r\n\r\n");
11540 for (i = 0; i < topic->kids; i++) {
11541 strcpy (tbuf, topic->children[i]->title +
11542 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11543 for (p = tbuf; *p; p++) {
11544 if (blankch (*p))
11545 *p = '_';
11546 }
11547 w += 4 + topic->kidwid;
11548 if (w > 80) {
11549 w = 4 + topic->kidwid;
11550 fputc ('\r', st);
11551 fputc ('\n', st);
11552 }
11553 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11554 }
11555 (void)fprintf (st, "\r\n\r\n");
11556 if (flag & SCP_HELP_ONECMD) {
11557 pstring = helpPrompt (topic, "", TRUE);
11558 (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11559 FREE (pstring);
11560 break;
11561 }
11562 }
11563
11564 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11565 break;
11566
11567 reprompt:
11568 if (NULL == cptr || !*cptr) {
11569 if (topic->kids == 0)
11570 topic = topic->parent;
11571 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11572
11573 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11574 FREE (pstring);
11575 if ((cptr != NULL) &&
11576 ((0 == strcmp (cptr, "\x04")) ||
11577 (0 == strcmp (cptr, "\x1A"))))
11578 cptr = NULL;
11579 }
11580
11581 if (NULL == cptr)
11582 break;
11583
11584 cptr = get_glyph (cptr, gbuf, 0);
11585 if (!strcmp (gbuf, "*")) {
11586 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11587 gbuf[0] = '\0';
11588 }
11589 if (!gbuf[0]) {
11590 if (topic->level == 0)
11591 break;
11592 topic = topic->parent;
11593 continue;
11594 }
11595 if (!strcmp (gbuf, "?"))
11596 continue;
11597 if (!strcmp (gbuf, "HELP")) {
11598 fputs (help_help, st);
11599 goto reprompt;
11600 }
11601 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11602 break;
11603
11604
11605
11606 if (!topic->kids) {
11607 (void)fprintf (st, "No additional help at this level.\r\n");
11608 cptr = NULL;
11609 goto reprompt;
11610 }
11611 match = matchHelpTopicName (topic, gbuf);
11612 if (match == HLP_MATCH_AMBIGUOUS) {
11613 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11614 cptr = NULL;
11615 goto reprompt;
11616 }
11617
11618 if (match == HLP_MATCH_NONE) {
11619 (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11620 cptr = NULL;
11621 goto reprompt;
11622 }
11623
11624
11625 topic = topic->children[match-1];
11626 }
11627
11628
11629
11630 cleanHelp (&top);
11631
11632 return SCPE_OK;
11633 }
11634
11635
11636
11637 t_stat scp_help (FILE *st, DEVICE *dptr,
11638 UNIT *uptr, int32 flag,
11639 const char *help, const char *cptr, ...)
11640 {
11641 t_stat r;
11642 va_list ap;
11643
11644 va_start (ap, cptr);
11645 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11646 va_end (ap);
11647
11648 return r;
11649 }
11650
11651 #if defined(_MSC_VER)
11652 # pragma warning(pop)
11653 #endif