This source file includes following definitions.
- setenv
- unsetenv
- xstrerror_l
- processIsTranslated
- strremove
- strtrimspace
- allowCores
- CleanDUMA
- dl_iterate_phdr_callback
- GetUCRTVersion
- dps8_sir_report_error
- main
- process_stdin_commands
- set_prompt
- find_cmd
- exit_cmd
- _cmd_name_compare
- fprint_help
- fprint_header
- fprint_reg_help_ex
- fprint_reg_help
- fprint_attach_help_ex
- fprint_set_help_ex
- fprint_set_help
- fprint_show_help_ex
- fprint_show_help
- fprint_brk_help_ex
- help_dev_help
- help_cmd_output
- help_cmd
- spawn_cmd
- echo_cmd
- do_cmd
- do_position
- do_cmd_label
- sim_sub_args
- sim_cmp_string
- assert_cmd
- send_cmd
- sim_show_send
- expect_cmd
- sim_show_expect
- goto_cmd
- return_cmd
- shift_cmd
- call_cmd
- on_cmd
- noop_cmd
- set_on
- set_verify
- set_message
- set_localopc
- set_quiet
- sim_set_environment
- set_cmd
- find_ctab
- find_c1tab
- set_dev_radix
- set_dev_enbdis
- set_unit_enbdis
- set_dev_debug
- show_cmd
- show_cmd_fi
- find_shtab
- show_device
- fprint_sep
- show_unit
- sprint_capac
- fprint_capac
- show_default_base_system_script
- printp
- strip_spaces
- printpq
- show_prom
- show_buildinfo
- show_version
- show_config
- show_log_names
- show_dev_logicals
- show_queue
- show_time
- show_break
- show_dev_radix
- show_dev_debug
- show_on
- show_mod_names
- show_dev_modifiers
- show_all_mods
- show_one_mod
- show_show_commands
- show_dev_show_commands
- brk_cmd
- ssh_break
- ssh_break_one
- reset_cmd
- reset_all
- reset_all_p
- attach_cmd
- scp_attach_unit
- attach_unit
- attach_err
- detach_cmd
- detach_all
- scp_detach_unit
- detach_unit
- sim_dname
- sim_uname
- run_cmd
- run_cmd_message
- sim_run_boot_prep
- fprint_stopped_gen
- fprint_stopped
- step_svc
- expect_svc
- int_handler
- exdep_cmd
- exdep_reg_loop
- exdep_addr_loop
- ex_reg
- get_rval
- dep_reg
- put_rval
- ex_addr
- get_aval
- dep_addr
- eval_cmd
- read_line
- read_line_p
- get_glyph_gen
- get_glyph
- get_glyph_nc
- get_glyph_quoted
- get_glyph_cmd
- sim_trim_endspc
- sim_isspace
- sim_islower
- sim_isalpha
- sim_isprint
- sim_isdigit
- sim_isgraph
- sim_isalnum
- get_uint
- get_range
- sim_decode_quoted_string
- sim_encode_quoted_string
- fprint_buffer_string
- find_dev
- find_unit
- sim_register_internal_device
- find_dev_from_unit
- qdisable
- find_reg_glob
- find_reg
- get_switches
- get_sim_sw
- get_sim_opt
- put_switches
- get_rsearch
- get_asearch
- test_search
- strtotv
- sprint_val
- fprint_val
- sim_fmt_secs
- sim_process_event
- sim_activate
- _sim_activate
- sim_activate_abs
- sim_activate_after
- _sim_activate_after
- sim_cancel
- sim_is_active
- sim_activate_time
- sim_gtime
- sim_qcount
- sim_brk_init
- sim_brk_fnd
- sim_brk_fnd_ex
- sim_brk_new
- sim_brk_set
- sim_brk_clr
- sim_brk_clrall
- sim_brk_show
- sim_brk_showall
- sim_brk_test
- sim_brk_getact
- sim_brk_clract
- sim_brk_setact
- sim_brk_npc
- sim_brk_clrspc
- sim_brk_message
- sim_set_expect
- sim_set_noexpect
- sim_exp_fnd
- sim_exp_clr_tab
- sim_exp_clr
- sim_exp_clrall
- sim_exp_set
- sim_exp_show_tab
- sim_exp_show
- sim_exp_showall
- sim_exp_check
- sim_send_input
- sim_send_clear
- sim_show_send_input
- sim_send_poll_data
- sim_error_text
- sim_string_to_stat
- get_dbg_verb
- sim_debug_prefix
- fprint_fields
- sim_debug_bits_hdr
- sim_debug_bits
- sim_printf
- sim_messagef
- _sim_debug
- sim_data_trace
- Fprintf
- appendText
- cleanHelp
- buildHelp
- helpPrompt
- displayMagicTopic
- displayFlatHelp
- matchHelpTopicName
- scp_vhelp
- scp_help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 #if !defined(__EXTENSIONS__)
43 # define __EXTENSIONS__
44 #endif
45
46 #if !defined(__STDC_WANT_LIB_EXT1__)
47 # define __STDC_WANT_LIB_EXT1__ 1
48 #endif
49
50 #if !defined(_GNU_SOURCE)
51 # define _GNU_SOURCE
52 #endif
53
54
55
56 #include "sim_defs.h"
57 #include "sim_disk.h"
58 #include "sim_tape.h"
59 #include "sim_sock.h"
60
61 #include <signal.h>
62 #include <ctype.h>
63 #include <time.h>
64 #include <math.h>
65 #include <stddef.h>
66 #if defined(_WIN32)
67 # if !defined(WIN32_LEAN_AND_MEAN)
68 # define WIN32_LEAN_AND_MEAN
69 # endif
70 # if defined(_MSC_VER)
71 # pragma warning(push, 3)
72 # endif
73 # include <direct.h>
74 # include <io.h>
75 # include <fcntl.h>
76 #else
77 # include <unistd.h>
78 # define HAVE_UNISTD 1
79 #endif
80 #include <sys/stat.h>
81 #include <sys/types.h>
82 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
83 # include <sys/resource.h>
84 #endif
85 #include <setjmp.h>
86 #include <stdint.h>
87 #include <limits.h>
88 #if defined(__APPLE__)
89 # include <xlocale.h>
90 #endif
91 #include <locale.h>
92
93 #include "linehistory.h"
94
95 #if defined(__APPLE__)
96 # include <sys/sysctl.h>
97 #endif
98
99 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) )
100 # include <sys/sysinfo.h>
101 # define LINUX_OS
102 #endif
103
104 #include <uv.h>
105
106 #if !defined(HAVE_UNISTD)
107 # undef USE_BACKTRACE
108 #endif
109
110 #if defined(USE_BACKTRACE)
111 # include <string.h>
112 # include <signal.h>
113 #endif
114
115 #if defined(__HAIKU__)
116 # include <OS.h>
117 #endif
118
119 #if !defined(__CYGWIN__)
120 # if !defined(__APPLE__)
121 # if !defined(_AIX)
122 # if !defined(__MINGW32__)
123 # if !defined(__MINGW64__)
124 # if !defined(CROSS_MINGW32)
125 # if !defined(CROSS_MINGW64)
126 # if !defined(_WIN32)
127 # if !defined(__HAIKU__)
128 # include <link.h>
129 # endif
130 # endif
131 # endif
132 # endif
133 # endif
134 # endif
135 # endif
136 # endif
137 #endif
138
139 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
140 # include <windows.h>
141 #endif
142
143 #if defined(__CYGWIN__)
144 # include <windows.h>
145 # include <sys/utsname.h>
146 # include <sys/cygwin.h>
147 # include <cygwin/version.h>
148 #endif
149
150 #define DBG_CTR 0
151
152 #include "../dps8/dps8.h"
153 #include "../dps8/dps8_cpu.h"
154 #include "../dps8/ver.h"
155
156 #include "../dps8/dps8_iom.h"
157 #include "../dps8/dps8_fnp2.h"
158
159 #include "../decNumber/decContext.h"
160 #include "../decNumber/decNumberLocal.h"
161
162 #include "../dps8/dps8_math128.h"
163
164 #include "../dps8/dps8_sir.h"
165
166 #if !defined(__CYGWIN__)
167 # if !defined(__APPLE__)
168 # if !defined(_AIX)
169 # if !defined(__MINGW32__)
170 # if !defined(__MINGW64__)
171 # if !defined(CROSS_MINGW32)
172 # if !defined(CROSS_MINGW64)
173 # if !defined(_WIN32)
174 # if !defined(__HAIKU__)
175 static unsigned int dl_iterate_phdr_callback_called = 0;
176 # endif
177 # endif
178 # endif
179 # endif
180 # endif
181 # endif
182 # endif
183 # endif
184 #endif
185
186 #if defined(MAX)
187 # undef MAX
188 #endif
189 #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
190
191 #if defined(FREE)
192 # undef FREE
193 #endif
194 #define FREE(p) do \
195 { \
196 free((p)); \
197 (p) = NULL; \
198 } while(0)
199
200
201
202 #define SCH_OR 0
203 #define SCH_AND 1
204 #define SCH_XOR 2
205 #define SCH_E 0
206 #define SCH_N 1
207 #define SCH_G 2
208 #define SCH_L 3
209 #define SCH_EE 4
210 #define SCH_NE 5
211 #define SCH_GE 6
212 #define SCH_LE 7
213
214 #define MAX_DO_NEST_LVL 20
215 #define SRBSIZ 1024
216 #define SIM_BRK_INILNT 4096
217 #define SIM_BRK_ALLTYP 0xFFFFFFFB
218
219 #define UPDATE_SIM_TIME \
220 if (1) { \
221 int32 _x; \
222 if (sim_clock_queue == QUEUE_LIST_END) \
223 _x = noqueue_time; \
224 else \
225 _x = sim_clock_queue->time; \
226 sim_time = sim_time + (_x - sim_interval); \
227 sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
228 if (sim_clock_queue == QUEUE_LIST_END) \
229 noqueue_time = sim_interval; \
230 else \
231 sim_clock_queue->time = sim_interval; \
232 } \
233 else \
234 (void)0
235
236 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
237
238 #define SZ_R(rp) \
239 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
240
241 #define SZ_LOAD(sz,v,mb,j) \
242 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
243 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
244 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
245 else v = *(((t_uint64 *) mb) + ((uint32) j));
246
247 #define SZ_STORE(sz,v,mb,j) \
248 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
249 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
250 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
251 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
252
253 #define GET_SWITCHES(cp) \
254 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
255
256 #define GET_RADIX(val,dft) \
257 if (sim_switches & SWMASK ('O')) val = 8; \
258 else if (sim_switches & SWMASK ('D')) val = 10; \
259 else if (sim_switches & SWMASK ('H')) val = 16; \
260 else val = dft;
261
262
263
264
265
266
267 t_bool sim_asynch_enabled = FALSE;
268 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
269 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
270 extern void (*sim_vm_init) (void);
271 extern void (*sim_vm_exit) (void);
272 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
273 void (*sim_vm_post) (t_bool from_scp) = NULL;
274 CTAB *sim_vm_cmd = NULL;
275 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
276 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
277 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
278 t_value (*sim_vm_pc_value) (void) = NULL;
279 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
280 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
281 unsigned int nprocs;
282
283
284
285
286
287 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
288 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
289 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
290 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
291 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
292 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
293 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
294 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
295 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
296 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
297 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
298 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
299 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
300 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
301 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
302 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
303 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
304 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
305 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
306 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
307 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
308 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
309 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
310 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
311 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
312 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
313 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
314 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
315 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
316 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
317 t_stat sim_save (FILE *sfile);
318 t_stat sim_rest (FILE *rfile);
319
320
321
322 t_stat sim_brk_init (void);
323 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
324 t_stat sim_brk_clr (t_addr loc, int32 sw);
325 t_stat sim_brk_clrall (int32 sw);
326 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
327 t_stat sim_brk_showall (FILE *st, uint32 sw);
328 CONST char *sim_brk_getact (char *buf, int32 size);
329 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
330 char *sim_brk_clract (void);
331
332 FILE *stdnul;
333
334
335
336 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
337 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
338 int32 test_search (t_value *val, SCHTAB *schptr);
339 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
340 int32 get_switches (const char *cptr);
341 CONST char *get_sim_sw (CONST char *cptr);
342 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
343 t_value get_rval (REG *rptr, uint32 idx);
344 void put_rval (REG *rptr, uint32 idx, t_value val);
345 void fprint_help (FILE *st);
346 void fprint_stopped (FILE *st, t_stat r);
347 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
348 void fprint_sep (FILE *st, int32 *tokens);
349 char *read_line (char *ptr, int32 size, FILE *stream);
350 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
351 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
352 char *sim_trim_endspc (char *cptr);
353
354
355
356 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
357 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
358 t_bool qdisable (DEVICE *dptr);
359 t_stat attach_err (UNIT *uptr, t_stat stat);
360 t_stat detach_all (int32 start_device, t_bool shutdown);
361 t_stat assign_device (DEVICE *dptr, const char *cptr);
362 t_stat deassign_device (DEVICE *dptr);
363 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
364 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
365 REG *lowr, REG *highr, uint32 lows, uint32 highs);
366 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
367 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
368 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
369 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
370 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
371 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
372 UNIT *uptr, int32 dfltinc);
373 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
374 t_stat step_svc (UNIT *ptr);
375 t_stat expect_svc (UNIT *ptr);
376 t_stat set_on (int32 flag, CONST char *cptr);
377 t_stat set_verify (int32 flag, CONST char *cptr);
378 t_stat set_message (int32 flag, CONST char *cptr);
379 t_stat set_quiet (int32 flag, CONST char *cptr);
380 t_stat set_localopc (int32 flag, CONST char *cptr);
381 t_stat set_asynch (int32 flag, CONST char *cptr);
382 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
383 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
384 void int_handler (int signal);
385 t_stat set_prompt (int32 flag, CONST char *cptr);
386 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
387 t_stat sim_set_environment (int32 flag, CONST char *cptr);
388 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
389
390
391
392 DEVICE *sim_dflt_dev = NULL;
393 UNIT *sim_clock_queue = QUEUE_LIST_END;
394 int32 sim_interval = 0;
395 int32 sim_switches = 0;
396 FILE *sim_ofile = NULL;
397 SCHTAB *sim_schrptr = NULL;
398 SCHTAB *sim_schaptr = NULL;
399 DEVICE *sim_dfdev = NULL;
400 UNIT *sim_dfunit = NULL;
401 DEVICE **sim_internal_devices = NULL;
402 uint32 sim_internal_device_count = 0;
403 int32 sim_opt_out = 0;
404 int32 sim_is_running = 0;
405 t_bool sim_processing_event = FALSE;
406 uint32 sim_brk_summ = 0;
407 uint32 sim_brk_types = 0;
408 BRKTYPTAB *sim_brk_type_desc = NULL;
409 uint32 sim_brk_dflt = 0;
410 uint32 sim_brk_match_type;
411 t_addr sim_brk_match_addr;
412 char *sim_brk_act[MAX_DO_NEST_LVL];
413 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
414 BRKTAB **sim_brk_tab = NULL;
415 int32 sim_brk_ent = 0;
416 int32 sim_brk_lnt = 0;
417 int32 sim_brk_ins = 0;
418 int32 sim_iglock = 0;
419 int32 sim_nolock = 0;
420 int32 sim_quiet = 0;
421 int32 sim_localopc = 1;
422 int32 sim_randompst = 0;
423 int32 sim_randstate = 0;
424 int32 sim_step = 0;
425 int nodist = 0;
426 #if defined(PERF_STRIP)
427 int32 sim_nostate = 1;
428 #else
429 int32 sim_nostate = 0;
430 #endif
431 static double sim_time;
432 static uint32 sim_rtime;
433 static int32 noqueue_time;
434 volatile int32 stop_cpu = 0;
435 t_value *sim_eval = NULL;
436 static t_value sim_last_val;
437 static t_addr sim_last_addr;
438 FILE *sim_log = NULL;
439 FILEREF *sim_log_ref = NULL;
440 FILE *sim_deb = NULL;
441 FILEREF *sim_deb_ref = NULL;
442 int32 sim_deb_switches = 0;
443 struct timespec sim_deb_basetime;
444 char *sim_prompt = NULL;
445 static FILE *sim_gotofile;
446 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];
447 static int32 sim_do_echo = 0;
448 static int32 sim_show_message = 1;
449 static int32 sim_on_inherit = 0;
450 static int32 sim_do_depth = 0;
451
452 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
453 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
454 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
455 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
456 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
457
458 t_stat sim_last_cmd_stat;
459
460 static SCHTAB sim_stabr;
461 static SCHTAB sim_staba;
462
463 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };
464 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) };
465
466
467
468 const char save_vercur[] = "V4.1";
469 const char save_ver40[] = "V4.0";
470 const char save_ver35[] = "V3.5";
471 const char save_ver32[] = "V3.2";
472 const char save_ver30[] = "V3.0";
473 const struct scp_error {
474 const char *code;
475 const char *message;
476 } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
477 {{"NXM", "Address space exceeded"},
478 {"UNATT", "Unit not attached"},
479 {"IOERR", "I/O error"},
480 {"CSUM", "Checksum error"},
481 {"FMT", "Format error"},
482 {"NOATT", "Unit not attachable"},
483 {"OPENERR", "File open error"},
484 {"MEM", "Memory exhausted"},
485 {"ARG", "Invalid argument"},
486 {"STEP", "Step expired"},
487 {"UNK", "Unknown command"},
488 {"RO", "Read only argument"},
489 {"INCOMP", "Command not completed"},
490 {"STOP", "Simulation stopped"},
491 {"EXIT", "Goodbye"},
492 {"TTIERR", "Console input I/O error"},
493 {"TTOERR", "Console output I/O error"},
494 {"EOF", "End of file"},
495 {"REL", "Relocation error"},
496 {"NOPARAM", "No settable parameters"},
497 {"ALATT", "Unit already attached"},
498 {"TIMER", "Hardware timer error"},
499 {"SIGERR", "Signal handler setup error"},
500 {"TTYERR", "Console terminal setup error"},
501 {"SUB", "Subscript out of range"},
502 {"NOFNC", "Command not allowed"},
503 {"UDIS", "Unit disabled"},
504 {"NORO", "Read only operation not allowed"},
505 {"INVSW", "Invalid switch"},
506 {"MISVAL", "Missing value"},
507 {"2FARG", "Too few arguments"},
508 {"2MARG", "Too many arguments"},
509 {"NXDEV", "Non-existent device"},
510 {"NXUN", "Non-existent unit"},
511 {"NXREG", "Non-existent register"},
512 {"NXPAR", "Non-existent parameter"},
513 {"NEST", "Nested DO command limit exceeded"},
514 {"IERR", "Internal error"},
515 {"MTRLNT", "Invalid magtape record length"},
516 {"LOST", "Console Telnet connection lost"},
517 {"TTMO", "Console Telnet connection timed out"},
518 {"STALL", "Console Telnet output stall"},
519 {"AFAIL", "Assertion failed"},
520 {"INVREM", "Invalid remote console command"},
521 {"NOTATT", "Not attached"},
522 {"EXPECT", "Expect matched"},
523 {"REMOTE", "Remote console command"},
524 };
525
526 const size_t size_map[] = { sizeof (int8),
527 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
528 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
529 };
530
531 const t_value width_mask[] = { 0,
532 0x1, 0x3, 0x7, 0xF,
533 0x1F, 0x3F, 0x7F, 0xFF,
534 0x1FF, 0x3FF, 0x7FF, 0xFFF,
535 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
536 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
537 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
538 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
539 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
540 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
541 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
542 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
543 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
544 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
545 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
546 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
547 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
548 };
549
550 static const char simh_help[] =
551
552 "1Commands\n"
553 #define HLP_RESET "*Commands Resetting Devices"
554
555 "2Resetting Devices\n"
556 " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\n"
557 " simulator to a predefined condition. If the switch \"`-p`\" is specified,\n"
558 " the device is reset to its initial power-on state:\n\n"
559 "++RESET resets all devices\n"
560 "++RESET -p power-cycle all devices\n"
561 "++RESET ALL resets all devices\n"
562 "++RESET <device> resets the specified <device>\n\n"
563 " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\n"
564 " interrupt requests, and returns the device to a quiescent state.\n\n"
565 " * It does **NOT** clear the main memory or affect associated I/O\n"
566 " connections.\n"
567 #define HLP_EXAMINE "*Commands Examining_and_Changing_State"
568 #define HLP_IEXAMINE "*Commands Examining_and_Changing_State"
569 #define HLP_DEPOSIT "*Commands Examining_and_Changing_State"
570 #define HLP_IDEPOSIT "*Commands Examining_and_Changing_State"
571
572 "2Examining and Changing State\n"
573 " There are four commands to examine and change state:\n\n"
574 " * `EXAMINE` (*abbreviated* `E`) examines state\n"
575 " * `DEPOSIT` (*abbreviated* `D`) changes state\n"
576 " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\n"
577 " and allows the user to interactively change it\n"
578 " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\n"
579 " interactively change state\n\n"
580 " All four commands take the form:\n\n"
581 "++command {modifiers} <object list>\n\n"
582 " The `DEPOSIT` command requires the deposit value at the end of the command.\n\n"
583 " There are four kinds of modifiers: **switches**, **device/unit name**,\n"
584 " **search specifier**, and for `EXAMINE`, **output file**.\n\n"
585 " * **Switches** have been described previously.\n"
586 " * A **device/unit name** identifies the device and unit whose address\n"
587 " space is to be examined or modified. If no device is specified, the CPU\n"
588 " main memory is selected. If a device but no unit is specified, unit `0`\n"
589 " of the specified device is selected automatically.\n"
590 " * The **search specifier** provides criteria for testing addresses or\n"
591 " registers to see if they should be processed. The search specifier\n"
592 " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\n"
593 " both, optionally separated by spaces:\n\n"
594 "++{ < logical op > < value > } < relational op > < value >\n\n"
595
596 " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\n"
597 " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\n"
598 " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\n"
599 " equal*), \">=\" (*greater than or equal*), \">\" (*greater\n"
600 " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\n"
601 " * * If any \"<`logical operator`>\" is specified without\n"
602 " a \"<`relational operator`>\", it is ignored.\n"
603 " * * If any \"<`relational operator`>\" is specified without\n"
604 " a \"<`logical operator`>\", no logical operation is performed.\n"
605 " * * All comparisons are unsigned.\n\n"
606 " * The **output file** modifier redirects the command output to a file\n"
607 " instead of the console. The **output file** modifier is specified with\n"
608 " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\n\n"
609 " **NOTE**: Modifiers may be specified in any order. If multiple\n"
610 " modifiers of the same type are specified, later modifiers override earlier\n"
611 " modifiers. If the **device/unit name** comes *after* the search specifier,\n"
612 " the search values will interpreted in the *radix of the CPU*, rather than\n"
613 " of the device/unit.\n\n"
614 " The \"<`object list`>\" argument consists of one or more of the following,\n"
615 " separated by commas:\n\n"
616
617 "++register the specified register\n"
618 "++register[sub1-sub2] the specified register array locations,\n"
619 "++++++++ starting at location sub1 up to and\n"
620 "++++++++ including location sub2\n"
621 "++register[sub1/length] the specified register array locations,\n"
622 "++++++++ starting at location sub1 up to but\n"
623 "++++++++ not including sub1+length\n"
624 "++register[ALL] all locations in the specified register\n"
625 "++++++++ array\n"
626 "++register1-register2 all the registers starting at register1\n"
627 "++++++++ up to and including register2\n"
628 "++address the specified location\n"
629 "++address1-address2 all locations starting at address1 up to\n"
630 "++++++++ and including address2\n"
631 "++address/length all location starting at address up to\n"
632 "++++++++ but not including address+length\n"
633 "++STATE all registers in the device\n"
634 "++ALL all locations in the unit\n"
635 "++$ the last value displayed by an EXAMINE\n"
636 "++++++++ command interpreted as an address\n"
637 "3Switches\n"
638 "4Formatting Control\n"
639 " Switches can be used to control the format of the displayed information:\n\n"
640
641 "5-a\n"
642 " display as ASCII\n"
643 "5-c\n"
644 " display as character string\n"
645 "5-m\n"
646 " display as instruction mnemonics\n"
647 "5-o\n"
648 " display as octal\n"
649 "5-d\n"
650 " display as decimal\n"
651 "5-h\n"
652 " display as hexadecimal\n\n"
653 "3Examples\n"
654 "++ex 1000-1100 examine 1000 to 1100\n"
655 "++de PC 1040 set PC to 1040\n"
656 "++ie 40-50 interactively examine 40:50\n"
657 "++ie >1000 40-50 interactively examine the subset\n"
658 "+++++++++ of locations 40:50 that are >1000\n"
659 "++ex rx0 50060 examine 50060, RX unit 0\n"
660 "++ex rx sbuf[3-6] examine SBUF[3] to SBUF[6] in RX\n"
661 "++de all 0 set main memory to 0\n"
662 "++de &77>0 0 set all addresses whose low order\n"
663 "+++++++++ bits are non-zero to 0\n"
664 "++ex -m @memdump.txt 0-7777 dump memory to file\n\n"
665 " * **NOTE**: To terminate an interactive command, simply type any bad value\n"
666 " (*e.g.* `XYZ`) when input is requested.\n"
667 #define HLP_EVALUATE "*Commands Evaluating_Instructions"
668
669 "2Evaluating Instructions\n"
670 " The `EVAL` command evaluates a symbolic expression and returns the\n"
671 " equivalent numeric value.\n\n"
672
673 "2Running A Simulated Program\n"
674 #define HLP_RUN "*Commands Running_A_Simulated_Program RUN"
675 "3RUN\n"
676 " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\n"
677 " argument, if given, in the PC (program counter), and starts execution.\n"
678 " If no argument is given execution starts at the current PC.\n"
679 #define HLP_GO "*Commands Running_A_Simulated_Program GO"
680 "3GO\n"
681 " The `GO` command does *not* reset devices, deposits its argument (if\n"
682 " given) in the PC, and starts execution. If no argument is given,\n"
683 " execution starts at the current PC (program counter).\n"
684 #define HLP_CONTINUE "*Commands Running_A_Simulated_Program Continuing_Execution"
685 "3Continuing Execution\n"
686 " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\n"
687 " (if execution was stopped, possibly due to hitting a breakpoint) at the\n"
688 " current program counter without resetting any devices.\n"
689 #define HLP_STEP "*Commands Running_A_Simulated_Program Step_Execution"
690 "3Step Execution\n"
691 " The `STEP` command (*abbreviated* `S`) resumes execution at the current\n"
692 " PC for the number of instructions given by its argument. If no argument\n"
693 " is supplied, one instruction is executed.\n"
694 "4Switches\n"
695 "5`-T`\n"
696 " If the `STEP` command is invoked with the \"`-T`\" switch, the step\n"
697 " command will cause execution to run for *microseconds* rather than\n"
698 " instructions.\n"
699 #define HLP_NEXT "*Commands Running_A_Simulated_Program NEXT"
700 "3NEXT\n"
701 " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\n"
702 " for one instruction, attempting to execute *through* subroutine calls.\n"
703 " If the next instruction to be executed is *not* a subroutine call, then\n"
704 " one instruction is executed.\n"
705 #define HLP_BOOT "*Commands Running_A_Simulated_Program Booting_the_system"
706 "3Booting the system\n"
707 " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\n"
708 " the device and unit given by its argument. If no unit is supplied,\n"
709 " unit `0` is bootstrapped. The specified unit must be `ATTACH`'ed.\n\n"
710 " When booting Multics, the boot device should always be `iom0`.\n"
711 " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\n"
712 " into memory and the system will transfer control to the boot record.\n\n"
713 " **Example**\n\n"
714 "++; Boot Multics using iom0\n"
715 "++boot iom0\n\n"
716
717 "2Stopping The Simulator\n"
718 " The simulator runs until the simulated hardware encounters an error, or\n"
719 " until the user forces a stop condition.\n"
720 "3Simulator Detected Stop Conditions\n"
721 " These simulator-detected conditions stop simulation:\n\n"
722 "++- HALT instruction. If a HALT instruction is decoded, simulation stops.\n\n"
723 "++- I/O error. If an I/O error occurs during simulation of an I/O\n"
724 "+++operation, and the device stop-on-I/O-error flag is set, simulation\n"
725 "+++usually stops.\n\n"
726 "++- Processor condition. Certain processor conditions can stop\n"
727 "+++the simulation.\n"
728 "3User Specified Stop Conditions\n"
729 " Typing the interrupt character stops simulation. The interrupt character\n"
730 " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\n"
731 " set to `005` (`^E`).\n\n"
732
733 #define HLP_BREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
734 #define HLP_NOBREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
735 "4Breakpoints\n"
736 " The simulator offers breakpoint capability for debugging. Users may define\n"
737 " breakpoints of different types, identified by letter (for example, `E`\n"
738 " for *execution*, `R` for *read*, `W` for *write*, etc).\n\n"
739 " Associated with each breakpoint is a count and, optionally, one or more\n"
740 " actions. Each time a breakpoint occurs, the associated count\n"
741 " is *decremented*. If the count is less than or equal to `0`, the breakpoint\n"
742 " occurs; otherwise, it is deferred. When the breakpoint occurs, any\n"
743 " optional actions are automatically executed.\n\n"
744 " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\n\n"
745 "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\n\n"
746 " If no type is specified, the default breakpoint type (`E`, *execution*) is\n"
747 " used. If no address range is specified, the current PC is used. As\n"
748 " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\n"
749 " range of addresses low-high, or a relative range of address/length.\n"
750
751 "5Displaying Breakpoints\n"
752 " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\n\n"
753 "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\n\n"
754 " Locations with breakpoints of the specified type are displayed.\n\n"
755 " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\n"
756 " commands which may be subsequently used to establish the same\n"
757 " breakpoint(s).\n\n"
758 "5Removing Breakpoints\n"
759 " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\n"
760 "5Examples\n"
761 " The following examples illustrate breakpoint usage:\n\n"
762 "++BREAK set E break at current PC\n"
763 "++BREAK -e 200 set E break at 200\n"
764 "++BREAK 2000/2[2] set E breaks at 2000,2001 with count = 2\n"
765 "++BREAK 100;EX AC;D MQ 0 set E break at 100 with actions EX AC and\n"
766 "+++++++++D MQ 0\n"
767 "++BREAK 100; delete action on break at 100\n\n"
768
769 "2Connecting and Disconnecting Devices\n"
770 " Units are simulated as files on the host file system. Before using any\n"
771 " simulated unit, the user must specify the file to be accessed by that unit.\n"
772 #define HLP_ATTACH "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
773 "3Attaching devices\n"
774 " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\n\n"
775 "++ATTACH <unit> <filename>\n\n"
776 " Some devices have more detailed or specific help available with:\n\n"
777 "++HELP <device> ATTACH\n\n"
778 "4Switches\n"
779 "5-n\n"
780 " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\n"
781 " file will be created when the filename specified does not exist, or an\n"
782 " existing file will have it's size truncated to zero, and an appropriate\n"
783 " message is printed.\n"
784 "5-e\n"
785 " If the file does not exist, and the \"`-e`\" switch *was not* specified,\n"
786 " a new file is created, and an appropriate message is printed. If\n"
787 " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\n"
788 " error message is printed.\n"
789 "5-r\n"
790 " If the \"`-r`\" switch is specified, or the file is write protected by\n"
791 " host operating system, `ATTACH` tries to open the file in read only mode.\n"
792 " If the file does not exist, or the unit does not support read only\n"
793 " operation, an error occurs. Input-only devices, such as card readers, or\n"
794 " storage devices with write locking switches, such as disks or tapes,\n"
795 " support read only operation - other devices do not. If a file is\n"
796 " attached read only, its contents can be examined but not modified.\n"
797 "5-q\n"
798 " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\n"
799 " or opening one read only (\"`-r`\"), the message announcing this fact\n"
800 " is suppressed.\n"
801 "5-f\n"
802 " For simulated magnetic tapes, the `ATTACH` command can specify the format\n"
803 " of the attached tape image file:\n\n"
804 "++ATTACH -f <tape_unit> <format> <filename>\n\n"
805 " * The currently supported magnetic tape image file formats are:\n\n"
806 " | | |\n"
807 " | ----------------:|:---------------------------------------------------- |\n"
808 " | \"**`SIMH`**\" | The **SIMH** / **DPS8M** native portable tape format |\n"
809 " | \"**`E11`**\" | The *D Bit* **Ersatz-11** simulator format |\n"
810 " | \"**`TPC`**\" | The **TPC** format (*used by _SIMH_ prior to V2.3*) |\n"
811 " | \"**`P7B`**\" | The **Paul Pierce** `7`-track tape archive format |\n\n"
812
813 " * The default tape format can also be specified with the `SET` command\n"
814 " prior to using the `ATTACH` command:\n\n"
815 "++SET <tape_unit> FORMAT=<format>\n"
816 "++ATTACH <tape_unit> <filename>\n\n"
817 " * The format of a currently attached tape image can be displayed with\n"
818 " the `SHOW FORMAT` command:\n\n"
819 "++SHOW <unit> FORMAT\n\n"
820 " **Examples**\n\n"
821 " The following example illustrates common `ATTACH` usage:\n"
822 "++; Associate the tape image file \"12.7MULTICS.tap\" with the tape0 unit\n"
823 "++; in read-only mode, where tape0 corresponds to the first tape device.\n"
824 "++ATTACH -r tape0 12.7MULTICS.tap\n\n"
825 "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\n"
826 "++; The disk0 unit corresponds to the first disk device.\n"
827 "++ATTACH disk0 root.dsk\n\n"
828
829 #define HLP_DETACH "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
830 "3Detaching devices\n"
831 " The `DETACH` (*abbreviation* `DET`) command breaks the association between\n"
832 " a unit and its backing file or device:\n\n"
833 "++DETACH ALL Detach all units\n"
834 "++DETACH <unit> Detach specified unit\n\n"
835 " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\n"
836 #define HLP_SET "*Commands SET"
837 "2SET\n"
838
839 #define HLP_SET_LOG "*Commands SET Logging"
840 "3Logging\n"
841 " Interactions with the simulator session can be recorded to a log file.\n\n"
842 "+SET LOG log_file Specify the log destination\n"
843 "++++++++ (STDOUT, DEBUG, or filename)\n"
844 "+SET NOLOG Disables any currently active logging\n"
845 "4Switches\n"
846 "5`-N`\n"
847 " By default, log output is written at the *end* of the specified log file.\n"
848 " A new log file can created if the \"`-N`\" switch is used on the command\n"
849 " line.\n\n"
850 "5`-B`\n"
851 " By default, log output is written in *text* mode. The log file can be\n"
852 " opened for *binary* mode writing if the \"`-B`\" switch is used on the\n"
853 " command line.\n"
854 #define HLP_SET_DEBUG "*Commands SET Debug_Messages"
855
856 "3Debug Messages\n"
857 "+SET DEBUG debug_file Specify the debug destination\n"
858 "++++++++ (STDOUT, STDERR, LOG, or filename)\n"
859 "+SET NODEBUG Disables any currently active debug output\n"
860 "4Switches\n"
861 " Debug message output contains a timestamp which indicates the number of\n"
862 " simulated instructions which have been executed prior to the debug event.\n\n"
863 " Debug message output can be enhanced to contain additional, potentially\n"
864 " useful information.\n\n\n"
865 " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\n"
866 "5-T\n"
867 " The \"`-T`\" switch causes debug output to contain a time of day displayed\n"
868 " as `hh:mm:ss.msec`.\n"
869 "5-A\n"
870 " The \"`-A`\" switch causes debug output to contain a time of day displayed\n"
871 " as `seconds.msec`.\n"
872 "5-R\n"
873 " The \"`-R`\" switch causes timing to be relative to the start of debugging.\n"
874 "5-P\n"
875 " The \"`-P`\" switch adds the output of the PC (program counter) to each\n"
876 " debug message.\n"
877 "5-N\n"
878 " The \"`-N`\" switch causes a new (empty) file to be written to.\n"
879 " (The default is to append to an existing debug log file).\n"
880 "5-D\n"
881 " The \"`-D`\" switch causes data blob output to also display the data\n"
882 " as **`RADIX-50`** characters.\n"
883 "5-E\n"
884 " The \"`-E`\" switch causes data blob output to also display the data\n"
885 " as \"**EBCDIC**\" characters.\n"
886
887 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
888 "3Environment Variables\n"
889 "+SET ENVIRONMENT NAME=val Set environment variable\n"
890 "+SET ENVIRONMENT NAME Clear environment variable\n"
891 #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
892 "3Command Status Trap Dispatching\n"
893 "+SET ON Enables error checking command execution\n"
894 "+SET NOON Disables error checking command execution\n"
895 "+SET ON INHERIT Enables inheritance of ON state and actions\n"
896 "+SET ON NOINHERIT Disables inheritance of ON state and actions\n"
897 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
898 "3Command Execution Display\n"
899 "+SET VERIFY Enables display of processed script commands\n"
900 "+SET VERBOSE Enables display of processed script commands\n"
901 "+SET NOVERIFY Disables display of processed script commands\n"
902 "+SET NOVERBOSE Disables display of processed script commands\n"
903 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
904 "3Command Error Status Display\n"
905 "+SET MESSAGE Re-enables display of script error messages\n"
906 "+SET NOMESSAGE Disables display of script error messages\n"
907 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
908 "3Command Output Display\n"
909 "+SET QUIET Disables suppression of some messages\n"
910 "+SET NOQUIET Re-enables suppression of some messages\n"
911 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
912 "3Local Operator Console\n"
913 "+SET LOCALOPC Enables local operator console\n"
914 "+SET NOLOCALOPC Disables local operator console\n"
915 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
916 "3Command Prompt\n"
917 "+SET PROMPT \"string\" Sets an alternate simulator prompt string\n"
918 "3Device and Unit Settings\n"
919 "+SET <dev> OCT|DEC|HEX Set device display radix\n"
920 "+SET <dev> ENABLED Enable device\n"
921 "+SET <dev> DISABLED Disable device\n"
922 "+SET <dev> DEBUG{=arg} Set device debug flags\n"
923 "+SET <dev> NODEBUG={arg} Clear device debug flags\n"
924 "+SET <dev> arg{,arg...} Set device parameters\n"
925 "+SET <unit> ENABLED Enable unit\n"
926 "+SET <unit> DISABLED Disable unit\n"
927 "+SET <unit> arg{,arg...} Set unit parameters\n"
928 "+HELP <dev> SET Displays any device specific SET commands\n"
929 " \n\n"
930 " See the Omnibus documentation for a complete SET command reference.\n"
931
932 #define HLP_SHOW "*Commands SHOW"
933 "2SHOW\n"
934 "+SH{OW} B{UILDINFO} Show build-time compilation information\n"
935 "+SH{OW} CL{OCKS} Show wall clock and timer information\n"
936 "+SH{OW} C{ONFIGURATION} Show simulator configuration\n"
937 "+SH{OW} D{EFAULT_BASE_SYSTEM} Show default base system script\n"
938 "+SH{OW} DEV{ICES} Show devices\n"
939 "+SH{OW} M{ODIFIERS} Show SET commands for all devices\n"
940 "+SH{OW} O{N} Show ON condition actions\n"
941 "+SH{OW} P{ROM} Show CPU ID PROM initialization data\n"
942 "+SH{OW} Q{UEUE} Show event queue\n"
943 "+SH{OW} S{HOW} Show SHOW commands for all devices\n"
944 "+SH{OW} T{IME} Show simulated timer\n"
945 "+SH{OW} VE{RSION} Show simulator version\n"
946 "+H{ELP} <dev> SHOW Show device-specific SHOW commands\n"
947 "+SH{OW} <dev> {arg,...} Show device parameters\n"
948 "+SH{OW} <dev> DEBUG Show device debug flags\n"
949 "+SH{OW} <dev> MODIFIERS Show device modifiers\n"
950 "+SH{OW} <dev> RADIX Show device display radix\n"
951 "+SH{OW} <dev> SHOW Show device SHOW commands\n"
952 "+SH{OW} <unit> {arg,...} Show unit parameters\n\n"
953 " See the Omnibus documentation for a complete SHOW command reference.\n\n"
954 #define HLP_SHOW_CONFIG "*Commands SHOW"
955 #define HLP_SHOW_DEVICES "*Commands SHOW"
956 #define HLP_SHOW_FEATURES "*Commands SHOW"
957 #define HLP_SHOW_QUEUE "*Commands SHOW"
958 #define HLP_SHOW_TIME "*Commands SHOW"
959 #define HLP_SHOW_MODIFIERS "*Commands SHOW"
960 #define HLP_SHOW_NAMES "*Commands SHOW"
961 #define HLP_SHOW_SHOW "*Commands SHOW"
962 #define HLP_SHOW_VERSION "*Commands SHOW"
963 #define HLP_SHOW_BUILDINFO "*Commands SHOW"
964 #define HLP_SHOW_PROM "*Commands SHOW"
965 #define HLP_SHOW_DBS "*Commands SHOW"
966 #define HLP_SHOW_DEFAULT "*Commands SHOW"
967 #define HLP_SHOW_CONSOLE "*Commands SHOW"
968 #define HLP_SHOW_REMOTE "*Commands SHOW"
969 #define HLP_SHOW_BREAK "*Commands SHOW"
970 #define HLP_SHOW_LOG "*Commands SHOW"
971 #define HLP_SHOW_DEBUG "*Commands SHOW"
972 #define HLP_SHOW_CLOCKS "*Commands SHOW"
973 #define HLP_SHOW_ON "*Commands SHOW"
974 #define HLP_SHOW_SEND "*Commands SHOW"
975 #define HLP_SHOW_EXPECT "*Commands SHOW"
976 #define HLP_HELP "*Commands HELP"
977
978 "2HELP\n"
979 "+H{ELP} Show this message\n"
980 "+H{ELP} <command> Show help for command\n"
981 "+H{ELP} <dev> Show help for device\n"
982 "+H{ELP} <dev> REGISTERS Show help for device register variables\n"
983 "+H{ELP} <dev> ATTACH Show help for device specific ATTACH command\n"
984 "+H{ELP} <dev> SET Show help for device specific SET commands\n"
985 "+H{ELP} <dev> SHOW Show help for device specific SHOW commands\n"
986 "+H{ELP} <dev> <command> Show help for device specific <command> command\n"
987
988 "2Altering The Simulated Configuration\n"
989 " The \"SET <device> DISABLED\" command removes a device from the configuration.\n"
990 " A `DISABLED` device is invisible to running programs. The device can still\n"
991 " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\n\n"
992 " The \"SET <device> ENABLED\" command restores a disabled device to a\n"
993 " configuration.\n\n"
994 " Most multi-unit devices allow units to be enabled or disabled:\n\n"
995 "++SET <unit> ENABLED\n"
996 "++SET <unit> DISABLED\n\n"
997 " When a unit is disabled, it will not be displayed by SHOW DEVICE.\n\n"
998
999 #define HLP_DO "*Commands Executing_Command_Files Processing_Command_Files"
1000 "2Executing Command Files\n"
1001 "3Processing Command Files\n"
1002 " The simulator can invoke another script file with the \"`DO`\" command:\n\n"
1003 "++DO <filename> {arguments...} execute commands in specified file\n\n"
1004 " The \"`DO`\" command allows command files to contain substitutable\n"
1005 " arguments. The string \"`%%n`\", where \"`n`\" is a number\n"
1006 " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\n"
1007 " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\n"
1008 " The string \"`%%0`\" is replaced with \"<`filename`>\".\n The\n"
1009 " sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\n"
1010 " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\n"
1011 " be enclosed in matching single or double quotation marks.\n\n"
1012 " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\n"
1013 " deep.\n\n"
1014 "4Switches\n"
1015 "5`-v`\n\n"
1016 " If the switch \"`-v`\" is specified, commands in the command file are\n"
1017 " echoed *before* they are executed.\n\n"
1018 "5`-e`\n\n"
1019 " If the switch \"`-e`\" is specified, command processing (including nested\n"
1020 " command invocations) will be aborted if any command error is encountered.\n"
1021 " (A simulation stop **never** aborts processing; use `ASSERT` to catch\n"
1022 " unexpected stops.) Without this switch, all errors except `ASSERT` failures\n"
1023 " will be ignored, and command processing will continue.\n\n"
1024 "5`-o`\n\n"
1025 " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\n"
1026 " the calling command file will be inherited by the command file being\n"
1027 " invoked.\n"
1028 "5`-q`\n\n"
1029 " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\n"
1030 " enabled for the called command file, otherwise the *quiet mode* setting\n"
1031 " is inherited from the calling context.\n"
1032
1033 #define HLP_GOTO "*Commands Executing_Command_Files GOTO"
1034 "3GOTO\n"
1035 " Commands in a command file execute in sequence until either an error\n"
1036 " trap occurs (when a command completes with an error status), or when an\n"
1037 " explicit request is made to start command execution elsewhere with\n"
1038 " the `GOTO` command:\n\n"
1039 "++GOTO <label>\n\n"
1040 " * Labels are lines in a command file which the first non-whitespace\n"
1041 " character is a \"`:`\".\n"
1042 " * The target of a `GOTO` is the first matching label in the current `DO`\n"
1043 " command file which is encountered.\n\n"
1044 " **Example**\n\n"
1045 " The following example illustrates usage of the `GOTO` command (by\n"
1046 " creating an infinite loop):\n\n"
1047 "++:Label\n"
1048 "++:: This is a loop.\n"
1049 "++GOTO Label\n\n"
1050 #define HLP_RETURN "*Commands Executing_Command_Files RETURN"
1051
1052 "3RETURN\n"
1053 " The `RETURN` command causes the current procedure call to be restored to\n"
1054 " the calling context, possibly returning a specific return status.\n"
1055 " If no return status is specified, the return status from the last command\n"
1056 " executed will be returned. The calling context may have `ON` traps defined\n"
1057 " which may redirect command flow in that context.\n\n"
1058 "++RETURN return from command file with last command status\n"
1059 "++RETURN {-Q} <status> return from command file with specific status\n\n"
1060 " * The status return can be any numeric value or one of the standard SCPE_\n"
1061 " condition names.\n\n"
1062 " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\n"
1063 " status to be returned, but normal error status message printing to be\n"
1064 " suppressed.\n\n"
1065 " **Condition Names**\n\n"
1066 " The available standard SCPE_ condition names and their meanings are:\n\n"
1067 " | Name | Meaning | Name | Meaning |\n"
1068 " | ------- | --------------------------------| ------- | ----------------------------------- |\n"
1069 " | NXM | Address space exceeded | UNATT | Unit not attached |\n"
1070 " | IOERR | I/O error | CSUM | Checksum error |\n"
1071 " | FMT | Format error | NOATT | Unit not attachable |\n"
1072 " | OPENERR | File open error | MEM | Memory exhausted |\n"
1073 " | ARG | Invalid argument | STEP | Step expired |\n"
1074 " | UNK | Unknown command | RO | Read only argument |\n"
1075 " | INCOMP | Command not completed | STOP | Simulation stopped |\n"
1076 " | EXIT | Goodbye | TTIERR | Console input I/O error |\n"
1077 " | TTOERR | Console output I/O error | EOF | End of file |\n"
1078 " | REL | Relocation error | NOPARAM | No settable parameters |\n"
1079 " | ALATT | Unit already attached | TIMER | Hardware timer error |\n"
1080 " | SIGERR | Signal handler setup error | TTYERR | Console terminal setup error |\n"
1081 " | NOFNC | Command not allowed | UDIS | Unit disabled |\n"
1082 " | NORO | Read only operation not allowed | INVSW | Invalid switch |\n"
1083 " | MISVAL | Missing value | 2FARG | Too few arguments |\n"
1084 " | 2MARG | Too many arguments | NXDEV | Non-existent device |\n"
1085 " | NXUN | Non-existent unit | NXREG | Non-existent register |\n"
1086 " | NXPAR | Non-existent parameter | NEST | Nested DO command limit exceeded |\n"
1087 " | IERR | Internal error | MTRLNT | Invalid magtape record length |\n"
1088 " | LOST | Console Telnet connection lost | TTMO | Console Telnet connection timed out |\n"
1089 " | STALL | Console Telnet output stall | AFAIL | Assertion failed |\n"
1090 " | INVREM | Invalid remote console command | | |\n"
1091 "\n\n"
1092 #define HLP_SHIFT "*Commands Executing_Command_Files Shift_Parameters"
1093 "3Shift Parameters\n"
1094 " Shift the command files positional parameters\n"
1095 #define HLP_CALL "*Commands Executing_Command_Files Call_a_subroutine"
1096 "3Call a subroutine\n"
1097 " Control can be transferred to a labeled subroutine using `CALL`.\n\n"
1098 " **Example**\n\n"
1099 "++CALL routine\n"
1100 "++BYE\n"
1101 "++\n"
1102 "++:routine\n"
1103 "++ECHO routine called\n"
1104 "++RETURN\n\n"
1105 #define HLP_ON "*Commands Executing_Command_Files ON"
1106 "3ON\n"
1107 " The `ON` command performs actions after a condition, or clears a condition.\n"
1108 "++ON <condition> <action> Perform action after condition\n"
1109 "++ON <condition> Clears action of specified condition\n"
1110 #define HLP_PROCEED "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1111 #define HLP_IGNORE "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1112
1113 "3PROCEED or IGNORE\n"
1114 " The `PROCEED` (or `IGNORE`) command does nothing. It is potentially\n"
1115 " useful as a placeholder for any `ON` action condition that should be\n"
1116 " explicitly ignored, allowing command file execution to continue without\n"
1117 " taking any specific action.\n"
1118 #define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1119
1120 "3Displaying Arbitrary Text\n"
1121 " The `ECHO` command is a useful way of annotating command files. `ECHO`\n"
1122 " prints out its arguments to the console (and to any applicable log file):\n\n"
1123 "++ECHO <string> Output string to console\n\n"
1124 " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\n"
1125 " This may be used to provide spacing for console messages or log file\n"
1126 " output.\n"
1127
1128 #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Assertions"
1129 "3Testing Assertions\n"
1130 " The `ASSERT` command tests a simulator state condition and halts command\n"
1131 " file execution if the condition is false:\n\n"
1132 "++ASSERT <Simulator State Expressions>\n\n"
1133 " * If the indicated expression evaluates to false, the command completes\n"
1134 " with an `AFAIL` condition. By default, when a command file encounters a\n"
1135 " command which returns the `AFAIL` condition, it will exit the running\n"
1136 " command file with the `AFAIL` status to the calling command file. This\n"
1137 " behavior can be changed with the `ON` command as well as switches to the\n"
1138 " invoking `DO` command.\n\n"
1139 " **Examples**\n\n"
1140 " The command file below might be used to bootstrap a hypothetical system\n"
1141 " that halts after the initial load from disk. The `ASSERT` command can then\n"
1142 " be used to confirm that the load completed successfully by examining the\n"
1143 " CPU's \"`A`\" register for the expected value:\n\n"
1144 "++; Example INI file\n"
1145 "++BOOT\n"
1146 "++; A register contains error code; 0 = good boot\n"
1147 "++ASSERT A=0\n"
1148 "++RUN\n\n"
1149
1150 " * In the above example, if the \"`A`\" register is *not* `0`,\n"
1151 " the \"`ASSERT A=0`\" command will be displayed to the user, and the\n"
1152 " command file will be aborted with an \"`Assertion failed`\" message.\n"
1153 " Otherwise, the command file will continue to bring up the system.\n\n"
1154 " * See the **`IF`** command documentation for more information and details\n"
1155 " regarding simulator state expressions.\n\n"
1156 #define HLP_IF "*Commands Executing_Command_Files Testing_Conditions"
1157 "3Testing Conditions\n"
1158 " The `IF` command tests a simulator state condition and executes additional\n"
1159 " commands if the condition is true:\n\n"
1160 "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\n\n"
1161 " **Examples**\n\n"
1162 " The command file below might be used to bootstrap a hypothetical system\n"
1163 " that halts after the initial load from disk. The `IF` command can then\n"
1164 " be used to confirm that the load completed successfully by examining the\n"
1165 " CPU's \"`A`\" register for an expected value:\n\n"
1166 "++; Example INI file\n"
1167 "++BOOT\n"
1168 "++; A register contains error code; 0 = good boot\n"
1169 "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\n"
1170 "++RUN\n\n"
1171
1172 " * In the above example, if the \"`A`\" register is *not* `0`, the\n"
1173 " message \"`Boot failed - Failure Code `\" will be displayed, the contents\n"
1174 " of the \"`A`\" register will be displayed, and the command file will be\n"
1175 " aborted with an \"`Assertion failed`\" message. Otherwise, the command\n"
1176 " file will continue to bring up the system.\n"
1177 "4Conditional Expressions\n"
1178 " The `IF` and `ASSERT` commands evaluate the following two different forms\n"
1179 " of conditional expressions.\n\n"
1180 "5Simulator State Expressions\n"
1181 " \n \n"
1182 " The values of simulator registers can be evaluated with:\n\n"
1183 "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
1184 " * If \"<`dev`>\" is not specified, `CPU` is assumed. \"<`reg`>\" is a\n"
1185 " register belonging to the indicated device.\n"
1186 " * The \"<`addr`>\" is an address in the address space of the indicated\n"
1187 " device.\n"
1188 " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\n"
1189 " the same as those used for \"search specifiers\" by the `EXAMINE` and\n"
1190 " `DEPOSIT` commands.\n"
1191 " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\n"
1192 " not in the radix for the device when referencing a register; when an\n"
1193 " address is referenced the device radix is used as the default.\n\n"
1194 " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\n"
1195 " register value is first altered as indicated. The result is then compared\n"
1196 " to the \"<`value`>\" via the \"<`conditional-op`>\".\n"
1197 " * * If the result is *true*, the command(s) are executed before proceeding\n"
1198 " to the next line in the command file.\n"
1199 " * * If the result is *false*, the next command in the command file is\n"
1200 " processed.\n\n"
1201 "5String Comparison Expressions\n"
1202 " \n \n"
1203 " String Values can be compared with:\n\n"
1204 "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\n\n"
1205 " * The \"`-i`\" switch, if present, causes a comparison to be case\n"
1206 " insensitive.\n"
1207 " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\n"
1208 " values which may have environment variables substituted as desired.\n"
1209 " * The \"<`compare-op`>\" may be one of:\n\n"
1210 " | | |\n"
1211 " | --------------:|:---------------------- |\n"
1212 " | \"**`==`**\" | equal |\n"
1213 " | \"**`EQU`**\" | equal |\n"
1214 " | \"**`!=`**\" | not equal |\n"
1215 " | \"**`NEQ`**\" | not equal |\n"
1216 " | \"**<**\" | less than |\n"
1217 " | \"**`LSS`**\" | less than |\n"
1218 " | \"**<=**\" | less than or equal |\n"
1219 " | \"**`LEQ`**\" | less than or equal |\n"
1220 " | \"**>**\" | greater than |\n"
1221 " | \"**`GTR`**\" | greater than |\n"
1222 " | \"**>=**\" | greater than or equal |\n"
1223 " | \"**`GEQ`**\" | greater than or equal |\n"
1224 " * **NOTE**: Comparisons are *generic*. This means that if\n"
1225 " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\n"
1226 " digits, then the strings are converted to numbers and a numeric\n"
1227 " comparison is performed. For example, the comparison\n"
1228 " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\n"
1229
1230 #define HLP_EXIT "*Commands Exiting_the_Simulator"
1231 "2Exiting the Simulator\n"
1232 " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\n"
1233 " returning control to the host operating system.\n"
1234
1235 #define HLP_SPAWN "*Commands Executing_System_Commands"
1236 "2Executing System Commands\n"
1237 " * The simulator can execute host operating system commands with\n"
1238 " the \"`!`\" (*spawn*) command.\n\n"
1239 " | | |\n"
1240 " |:----------------------- |:------------------------------------------- |\n"
1241 " | \"**`!`**\" | Spawn the hosts default command interpreter |\n"
1242 " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\n\n"
1243 " * **NOTE**: The *exit status* from the command which was executed is set\n"
1244 " as the *command completion status* for the \"`!`\" command. This may\n"
1245 " influence any enabled `ON` condition traps.\n" ;
1246
1247
1248 static CTAB cmd_table[] = {
1249 { "RESET", &reset_cmd, 0, HLP_RESET },
1250 { "EXAMINE", &exdep_cmd, EX_E, HLP_EXAMINE },
1251 { "IEXAMINE", &exdep_cmd, EX_E+EX_I, HLP_IEXAMINE },
1252 { "DEPOSIT", &exdep_cmd, EX_D, HLP_DEPOSIT },
1253 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, HLP_IDEPOSIT },
1254 { "EVALUATE", &eval_cmd, 0, HLP_EVALUATE },
1255 { "RUN", &run_cmd, RU_RUN, HLP_RUN, NULL, &run_cmd_message },
1256 { "GO", &run_cmd, RU_GO, HLP_GO, NULL, &run_cmd_message },
1257 { "STEP", &run_cmd, RU_STEP, HLP_STEP, NULL, &run_cmd_message },
1258 { "NEXT", &run_cmd, RU_NEXT, HLP_NEXT, NULL, &run_cmd_message },
1259 { "CONTINUE", &run_cmd, RU_CONT, HLP_CONTINUE, NULL, &run_cmd_message },
1260 { "BOOT", &run_cmd, RU_BOOT, HLP_BOOT, NULL, &run_cmd_message },
1261 { "BREAK", &brk_cmd, SSH_ST, HLP_BREAK },
1262 { "NOBREAK", &brk_cmd, SSH_CL, HLP_NOBREAK },
1263 { "ATTACH", &attach_cmd, 0, HLP_ATTACH },
1264 { "DETACH", &detach_cmd, 0, HLP_DETACH },
1265 { "EXIT", &exit_cmd, 0, HLP_EXIT },
1266 { "QUIT", &exit_cmd, 0, NULL },
1267 { "BYE", &exit_cmd, 0, NULL },
1268 { "SET", &set_cmd, 0, HLP_SET },
1269 { "SHOW", &show_cmd, 0, HLP_SHOW },
1270 { "DO", &do_cmd, 1, HLP_DO },
1271 { "GOTO", &goto_cmd, 1, HLP_GOTO },
1272 { "RETURN", &return_cmd, 0, HLP_RETURN },
1273 { "SHIFT", &shift_cmd, 0, HLP_SHIFT },
1274 { "CALL", &call_cmd, 0, HLP_CALL },
1275 { "ON", &on_cmd, 0, HLP_ON },
1276 { "IF", &assert_cmd, 0, HLP_IF },
1277 { "PROCEED", &noop_cmd, 0, HLP_PROCEED },
1278 { "IGNORE", &noop_cmd, 0, HLP_IGNORE },
1279 { "ECHO", &echo_cmd, 0, HLP_ECHO },
1280 { "ASSERT", &assert_cmd, 1, HLP_ASSERT },
1281 { "SEND", &send_cmd, 0 },
1282 { "EXPECT", &expect_cmd, 1 },
1283 { "NOEXPECT", &expect_cmd, 0 },
1284 { "!", &spawn_cmd, 0, HLP_SPAWN },
1285 { "HELP", &help_cmd, 0, HLP_HELP },
1286 { NULL, NULL, 0 }
1287 };
1288
1289 static CTAB set_glob_tab[] = {
1290 { "CONSOLE", &sim_set_console, 0 },
1291 { "REMOTE", &sim_set_remote_console, 0 },
1292 { "BREAK", &brk_cmd, SSH_ST },
1293 { "NOBREAK", &brk_cmd, SSH_CL },
1294 { "TELNET", &sim_set_telnet, 0 },
1295 { "NOTELNET", &sim_set_notelnet, 0 },
1296 { "LOG", &sim_set_logon, 0, HLP_SET_LOG },
1297 { "NOLOG", &sim_set_logoff, 0, HLP_SET_LOG },
1298 { "DEBUG", &sim_set_debon, 0, HLP_SET_DEBUG },
1299 { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
1300 { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
1301 { "ON", &set_on, 1, HLP_SET_ON },
1302 { "NOON", &set_on, 0, HLP_SET_ON },
1303 { "VERIFY", &set_verify, 1, HLP_SET_VERIFY },
1304 { "VERBOSE", &set_verify, 1, HLP_SET_VERIFY },
1305 { "NOVERIFY", &set_verify, 0, HLP_SET_VERIFY },
1306 { "NOVERBOSE", &set_verify, 0, HLP_SET_VERIFY },
1307 { "MESSAGE", &set_message, 1, HLP_SET_MESSAGE },
1308 { "NOMESSAGE", &set_message, 0, HLP_SET_MESSAGE },
1309 { "QUIET", &set_quiet, 1, HLP_SET_QUIET },
1310 { "NOQUIET", &set_quiet, 0, HLP_SET_QUIET },
1311 { "LOCALOPC", &set_localopc, 1, HLP_SET_LOCALOPC },
1312 { "NOLOCALOPC", &set_localopc, 0, HLP_SET_LOCALOPC },
1313 { "PROMPT", &set_prompt, 0, HLP_SET_PROMPT },
1314 { NULL, NULL, 0 }
1315 };
1316
1317 static C1TAB set_dev_tab[] = {
1318 { "OCTAL", &set_dev_radix, 8 },
1319 { "DECIMAL", &set_dev_radix, 10 },
1320 { "HEX", &set_dev_radix, 16 },
1321 { "ENABLED", &set_dev_enbdis, 1 },
1322 { "DISABLED", &set_dev_enbdis, 0 },
1323 { "DEBUG", &set_dev_debug, 1 },
1324 { "NODEBUG", &set_dev_debug, 0 },
1325 { NULL, NULL, 0 }
1326 };
1327
1328 static C1TAB set_unit_tab[] = {
1329 { "ENABLED", &set_unit_enbdis, 1 },
1330 { "DISABLED", &set_unit_enbdis, 0 },
1331 { NULL, NULL, 0 }
1332 };
1333
1334 static SHTAB show_glob_tab[] = {
1335 { "CONFIGURATION", &show_config, 0, HLP_SHOW_CONFIG },
1336 { "DEFAULT_BASE_SYSTEM_SCRIPT",
1337 &show_default_base_system_script, 0, HLP_SHOW_DBS },
1338 { "DEVICES", &show_config, 1, HLP_SHOW_DEVICES },
1339 { "FEATURES", &show_config, 2, HLP_SHOW_FEATURES },
1340 { "QUEUE", &show_queue, 0, HLP_SHOW_QUEUE },
1341 { "TIME", &show_time, 0, HLP_SHOW_TIME },
1342 { "MODIFIERS", &show_mod_names, 0, HLP_SHOW_MODIFIERS },
1343 { "NAMES", &show_log_names, 0, HLP_SHOW_NAMES },
1344 { "SHOW", &show_show_commands, 0, HLP_SHOW_SHOW },
1345 { "VERSION", &show_version, 1, HLP_SHOW_VERSION },
1346 { "BUILDINFO", &show_buildinfo, 1, HLP_SHOW_BUILDINFO },
1347 { "PROM", &show_prom, 0, HLP_SHOW_PROM },
1348 { "CONSOLE", &sim_show_console, 0, HLP_SHOW_CONSOLE },
1349 { "REMOTE", &sim_show_remote_console, 0, HLP_SHOW_REMOTE },
1350 { "BREAK", &show_break, 0, HLP_SHOW_BREAK },
1351 { "LOG", &sim_show_log, 0, HLP_SHOW_LOG },
1352 { "TELNET", &sim_show_telnet, 0 },
1353 { "DEBUG", &sim_show_debug, 0, HLP_SHOW_DEBUG },
1354 { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS },
1355 { "SEND", &sim_show_send, 0, HLP_SHOW_SEND },
1356 { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT },
1357 { "ON", &show_on, 0, HLP_SHOW_ON },
1358 { NULL, NULL, 0 }
1359 };
1360
1361 static SHTAB show_dev_tab[] = {
1362 { "RADIX", &show_dev_radix, 0 },
1363 { "DEBUG", &show_dev_debug, 0 },
1364 { "MODIFIERS", &show_dev_modifiers, 0 },
1365 { "NAMES", &show_dev_logicals, 0 },
1366 { "SHOW", &show_dev_show_commands, 0 },
1367 { NULL, NULL, 0 }
1368 };
1369
1370 static SHTAB show_unit_tab[] = {
1371 { NULL, NULL, 0 }
1372 };
1373
1374 #if defined(_WIN32)
1375 static
1376 int setenv(const char *envname, const char *envval, int overwrite)
1377 {
1378 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1379 int r;
1380
1381 (void)sprintf(envstr, "%s=%s", envname, envval);
1382 r = _putenv(envstr);
1383 FREE(envstr);
1384 return r;
1385 }
1386
1387 static
1388 int unsetenv(const char *envname)
1389 {
1390 setenv(envname, "", 1);
1391 return 0;
1392 }
1393 #endif
1394
1395 #define XSTR_EMAXLEN 32767
1396
1397 const char
1398 *xstrerror_l(int errnum)
1399 {
1400 int saved = errno;
1401 const char *ret = NULL;
1402 static __thread char buf[XSTR_EMAXLEN];
1403
1404 #if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1405 defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1406 # if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1407 if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf;
1408 # else
1409 if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf;
1410 # endif
1411 #else
1412 # if defined(__NetBSD__)
1413 locale_t loc = LC_GLOBAL_LOCALE;
1414 # else
1415 locale_t loc = uselocale((locale_t)0);
1416 # endif
1417 locale_t copy = loc;
1418 if (copy == LC_GLOBAL_LOCALE)
1419 copy = duplocale(copy);
1420
1421 if (copy != (locale_t)0)
1422 {
1423 ret = strerror_l(errnum, copy);
1424 if (loc == LC_GLOBAL_LOCALE)
1425 {
1426 freelocale(copy);
1427 }
1428 }
1429 #endif
1430
1431 if (!ret)
1432 {
1433 (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1434 ret = buf;
1435 }
1436
1437 errno = saved;
1438 return ret;
1439 }
1440
1441 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1442
1443
1444
1445 #if defined(__APPLE__)
1446 int processIsTranslated(void)
1447 {
1448 int ret = 0;
1449 size_t size = sizeof(ret);
1450 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
1451 if (errno == ENOENT)
1452 return 0;
1453 return -1; }
1454 return ret;
1455 }
1456 #endif
1457
1458
1459
1460 char *strremove(char *str, const char *sub)
1461 {
1462 char *p, *q, *r;
1463 if (*sub && (q = r = strstr(str, sub)) != NULL) {
1464 size_t len = strlen(sub);
1465 while ((r = strstr(p = r + len, sub)) != NULL) {
1466 while (p < r)
1467 *q++ = *p++;
1468 }
1469 while ((*q++ = *p++) != '\0')
1470 continue;
1471 }
1472 return str;
1473 }
1474
1475
1476
1477 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
1478 {
1479 while (*str_untrimmed != '\0') {
1480 if(!isspace((unsigned char)*str_untrimmed)) {
1481 *str_trimmed = (char)*str_untrimmed;
1482 str_trimmed++;
1483 }
1484 str_untrimmed++;
1485 }
1486 *str_trimmed = '\0';
1487 }
1488
1489 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1490 void allowCores(void)
1491 {
1492 int ret;
1493 struct rlimit limit;
1494 # if defined(RLIMIT_CORE)
1495 ret = getrlimit(RLIMIT_CORE, &limit);
1496 (void)ret;
1497 # if defined(TESTING)
1498 if (ret != 0)
1499 {
1500 sim_warn ("Failed to query core dump configuration.");
1501 return;
1502 }
1503 # endif
1504 limit.rlim_cur = limit.rlim_max;
1505 ret = setrlimit(RLIMIT_CORE, &limit);
1506 # if defined(TESTING)
1507 if (ret != 0)
1508 {
1509 sim_warn ("Failed to enable unlimited core dumps.");
1510 return;
1511 }
1512 # endif
1513 # else
1514 # if defined(TESTING)
1515 sim_warn ("Unable to query core dump configuration.");
1516 # endif
1517 # endif
1518 return;
1519 }
1520 #endif
1521
1522 #if defined(USE_DUMA)
1523 void CleanDUMA(void)
1524 {
1525 (void)fflush(stdout);
1526 DUMA_CHECKALL();
1527 (void)fflush(stderr);
1528 }
1529 # undef USE_DUMA
1530 # define USE_DUMA 1
1531 #endif
1532
1533 #if !defined(SIG_SETMASK)
1534 # undef USE_BACKTRACE
1535 #endif
1536
1537 #if defined(PERF_STRIP)
1538 # undef USE_BACKTRACE
1539 #endif
1540
1541 #if defined(USE_BACKTRACE)
1542 # include <backtrace.h>
1543 # include <backtrace-supported.h>
1544 # define BACKTRACE_SKIP 1
1545 # define BACKTRACE_MAIN "main"
1546 # undef USE_BACKTRACE
1547 # define USE_BACKTRACE 1
1548 #endif
1549
1550 #if defined(BACKTRACE_SUPPORTED)
1551 # if defined(BACKTRACE_SUPPORTS_THREADS)
1552 # if !(BACKTRACE_SUPPORTED)
1553 # undef USE_BACKTRACE
1554 # endif
1555 # else
1556 # undef USE_BACKTRACE
1557 # endif
1558 #else
1559 # undef USE_BACKTRACE
1560 #endif
1561
1562 #if defined(USE_BACKTRACE)
1563 # if defined(BACKTRACE_SUPPORTED)
1564 # include "backtrace_func.c"
1565 # endif
1566 #endif
1567
1568 #if !defined(__CYGWIN__)
1569 # if !defined(__APPLE__)
1570 # if !defined(_AIX)
1571 # if !defined(__MINGW32__)
1572 # if !defined(__MINGW64__)
1573 # if !defined(CROSS_MINGW32)
1574 # if !defined(CROSS_MINGW64)
1575 # if !defined(_WIN32)
1576 # if !defined(__HAIKU__)
1577 static int
1578 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
1579 {
1580 (void)size;
1581 (void)data;
1582
1583 if (strlen(info->dlpi_name) >= 2) {
1584 if (!dl_iterate_phdr_callback_called)
1585 (void)printf ("\r\n Loaded shared objects: ");
1586
1587 dl_iterate_phdr_callback_called++;
1588 (void)printf ("%s ", info->dlpi_name);
1589 }
1590
1591 return 0;
1592 }
1593 # endif
1594 # endif
1595 # endif
1596 # endif
1597 # endif
1598 # endif
1599 # endif
1600 # endif
1601 #endif
1602
1603 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1604 # if defined(_UCRT)
1605 # define MINGW_CRT "UCRT"
1606 # else
1607 # define MINGW_CRT "MSVCRT"
1608 # endif
1609 #endif
1610
1611 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1612 struct UCRTVersion
1613 {
1614 uint16_t ProductVersion[4];
1615 };
1616
1617 int
1618 GetUCRTVersion (struct UCRTVersion *ucrtversion)
1619 {
1620 # ifdef _DEBUG
1621 static const wchar_t *DllName = L"ucrtbased.dll";
1622 # else
1623 static const wchar_t *DllName = L"ucrtbase.dll";
1624 # endif
1625
1626 HMODULE ucrt = GetModuleHandleW (DllName);
1627 if (!ucrt)
1628 return GetLastError ();
1629
1630 wchar_t path[MAX_PATH];
1631 if (!GetModuleFileNameW (ucrt, path, MAX_PATH))
1632 return GetLastError ();
1633
1634 DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1635 if (!versionInfoSize)
1636 return GetLastError ();
1637
1638 uint8_t versionInfo[versionInfoSize];
1639
1640 if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1641 return GetLastError ();
1642
1643 VS_FIXEDFILEINFO *fixedFileInfo;
1644 UINT fixedFileInfoSize;
1645 if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1646 return GetLastError ();
1647
1648 memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1649
1650 return 0;
1651 }
1652 #endif
1653
1654
1655
1656 #if !defined(PERF_STRIP)
1657 static int dps8_sir_report_error(void)
1658 {
1659 char message[SIR_MAXERROR] = {0};
1660 (void)sir_geterror(message);
1661 (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1662 return EXIT_FAILURE;
1663 }
1664
1665
1666
1667 int main (int argc, char *argv[])
1668 {
1669 char *cptr, *cptr2;
1670 char nbuf[PATH_MAX + 7];
1671 char cbuf[4*CBUFSIZE];
1672 char **targv = NULL;
1673 # if defined(USE_BACKTRACE)
1674 # if defined(BACKTRACE_SUPPORTED)
1675 # if defined(_INC_BACKTRACE_FUNC)
1676 bt_pid = (long)getpid();
1677 (void)bt_pid;
1678 # endif
1679 # endif
1680 # endif
1681 int32 i, sw;
1682 t_bool lookswitch;
1683 t_stat stat;
1684
1685 # if defined(__MINGW32__)
1686 # undef IS_WINDOWS
1687 # define IS_WINDOWS 1
1688 # if !defined(NEED_CONSOLE_SETUP)
1689 # define NEED_CONSOLE_SETUP
1690 # endif
1691 # endif
1692
1693 # if defined(CROSS_MINGW32)
1694 # undef IS_WINDOWS
1695 # define IS_WINDOWS 1
1696 # if !defined(NEED_CONSOLE_SETUP)
1697 # define NEED_CONSOLE_SETUP
1698 # endif
1699 # endif
1700
1701 # if defined(__MINGW64__)
1702 # undef IS_WINDOWS
1703 # define IS_WINDOWS 1
1704 # if !defined(NEED_CONSOLE_SETUP)
1705 # define NEED_CONSOLE_SETUP
1706 # endif
1707 # endif
1708
1709 # if defined(CROSS_MINGW64)
1710 # undef IS_WINDOWS
1711 # define IS_WINDOWS 1
1712 # if !defined(NEED_CONSOLE_SETUP)
1713 # define NEED_CONSOLE_SETUP
1714 # endif
1715 # endif
1716
1717 # if defined(__CYGWIN__)
1718 # if defined(IS_WINDOWS)
1719 # undef IS_WINDOWS
1720 # endif
1721 # endif
1722
1723 # if defined(USE_DUMA)
1724 # if defined(DUMA_EXPLICIT_INIT)
1725 duma_init();
1726 (void)fflush(stderr);
1727 # endif
1728 # if defined(DUMA_MIN_ALIGNMENT)
1729 # if DUMA_MIN_ALIGNMENT > 0
1730 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1731 # endif
1732 # endif
1733 DUMA_SET_FILL(0x2E);
1734 (void)fflush(stderr);
1735 (void)atexit(CleanDUMA);
1736 # endif
1737
1738 # if defined(USE_BACKTRACE)
1739 # if defined(BACKTRACE_SUPPORTED)
1740 # include "backtrace_main.c"
1741 # endif
1742 # endif
1743
1744 (void)setlocale(LC_ALL, "");
1745
1746 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1747 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1748 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1749 # endif
1750 # endif
1751
1752 # if defined(NEED_CONSOLE_SETUP)
1753 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1754 if (handle != INVALID_HANDLE_VALUE)
1755 {
1756 DWORD mode = 0;
1757 if (GetConsoleMode(handle, &mode))
1758 {
1759 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1760 SetConsoleMode(handle, mode);
1761 }
1762 }
1763 puts ("\e[0m");
1764 # endif
1765
1766 # if defined(__HAIKU__)
1767 (void)disable_debugger(1);
1768 # endif
1769
1770
1771
1772 sirinit si;
1773 if (!sir_makeinit(&si))
1774 return dps8_sir_report_error();
1775
1776
1777 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1778
1779
1780 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1781
1782
1783 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1784
1785
1786 si.d_stderr.opts = SIRO_NOHOST;
1787
1788
1789 si.d_syslog.levels = SIRL_NONE;
1790
1791
1792 si.d_syslog.opts = SIRO_DEFAULT;
1793
1794
1795 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1796
1797
1798 if (!sir_init(&si))
1799 return dps8_sir_report_error();
1800
1801
1802 char thread_name[SIR_MAXPID] = {0};
1803 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1804 (void)_sir_setthreadname(thread_name);
1805
1806
1807
1808 # if defined(__clang_analyzer__)
1809 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\n");
1810 return 1;
1811 # endif
1812
1813 if (argc == 0) {
1814 (void)fprintf (stderr, "Error: main() called directly!\n");
1815 return 1;
1816 }
1817
1818
1819 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1820 allowCores();
1821 # endif
1822
1823 int testEndian = decContextTestEndian();
1824 if (testEndian != 0) {
1825 if (testEndian == 1) {
1826 (void)fprintf (stderr,
1827 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\n");
1828 return 1;
1829 }
1830 if (testEndian == -1) {
1831 (void)fprintf (stderr,
1832 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\n");
1833 return 1;
1834 }
1835 (void)fprintf (stderr,
1836 "Error: Unable to determine system byte order; aborting.\n");
1837 return 1;
1838 }
1839 # if defined(NEED_128)
1840 test_math128();
1841 # endif
1842
1843 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1844
1845 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1846
1847
1848
1849
1850 nprocs = (unsigned int)uv_available_parallelism();
1851 # else
1852 nprocs = (unsigned int)_sir_nprocs();
1853 # endif
1854
1855
1856 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1857 if (!targv)
1858 {
1859 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1860 __func__, __FILE__, __LINE__);
1861 # if defined(USE_BACKTRACE)
1862 # if defined(SIGUSR2)
1863 (void)raise(SIGUSR2);
1864
1865 # endif
1866 # endif
1867 abort();
1868 }
1869 for (i=0; i<argc; i++)
1870 targv[i] = argv[i];
1871 argv = targv;
1872
1873
1874 set_prompt (0, "sim>");
1875 *cbuf = 0;
1876 sim_switches = 0;
1877 lookswitch = TRUE;
1878 stdnul = fopen(NULL_DEVICE,"wb");
1879
1880
1881 for (i = 1; i < argc; i++) {
1882 if (argv[i] == NULL)
1883 continue;
1884
1885 # if defined(THREADZ) || defined(LOCKLESS)
1886
1887 int perftestflag = strcmp(argv[i], "--perftest");
1888 if (perftestflag == 0) {
1889 char * testName = NULL;
1890 if (i + 1 < argc)
1891 testName = argv[i + 1];
1892 perfTest (testName);
1893 return 0;
1894 }
1895 # endif
1896
1897
1898 int onlyvers = strcmp(argv[i], "--version");
1899 if (onlyvers == 0) {
1900 # if defined(VER_H_GIT_VERSION)
1901 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1902 # if VER_H_GIT_PATCH_INT < 1
1903 (void)fprintf (stdout, "%s simulator %s\n",
1904 sim_name, VER_H_GIT_VERSION);
1905 # else
1906 (void)fprintf (stdout, "%s simulator %s+%s\n",
1907 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1908 # endif
1909 # else
1910 (void)fprintf (stdout, "%s simulator %s\n",
1911 sim_name, VER_H_GIT_VERSION);
1912 # endif
1913 # else
1914 (void)fprintf (stdout, "%s simulator\n", sim_name);
1915 # endif
1916 FREE (targv);
1917 return 0;
1918 }
1919
1920
1921 int longhelp = strcmp(argv[i], "--help");
1922 int shorthelp = strcmp(argv[i], "-h");
1923 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
1924 if (longhelp == 0 || shorthelp == 0) {
1925 # if defined(VER_H_GIT_VERSION)
1926 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1927 # if VER_H_GIT_PATCH_INT < 1
1928 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1929 # else
1930 (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1931 # endif
1932 # else
1933 (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1934 # endif
1935 # else
1936 (void)fprintf (stdout, "%s simulator", sim_name);
1937 # endif
1938 (void)fprintf (stdout, "\n");
1939 (void)fprintf (stdout, "\n USAGE: %s { [ SWITCHES ] ... } { < SCRIPT > }", argv[0]);
1940 (void)fprintf (stdout, "\n");
1941 (void)fprintf (stdout, "\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
1942 (void)fprintf (stdout, "\n");
1943 (void)fprintf (stdout, "\n Switches:");
1944 (void)fprintf (stdout, "\n -e, -E Aborts script processing immediately upon any error");
1945 (void)fprintf (stdout, "\n -h, -H, --help Prints only this informational help text and exit");
1946 (void)fprintf (stdout, "\n -k, -K Disables all support for exclusive file locking");
1947 (void)fprintf (stdout, "\n -l, -L Reports but ignores all exclusive file locking errors");
1948 (void)fprintf (stdout, "\n -o, -O Makes scripting ON conditions and actions inheritable");
1949 (void)fprintf (stdout, "\n -q, -Q Disables printing of non-fatal informational messages");
1950 (void)fprintf (stdout, "\n -r, -R Enables an unlinked ephemeral system state file");
1951 (void)fprintf (stdout, "\n -s, -S Enables a randomized persistent system state file");
1952 (void)fprintf (stdout, "\n -t, -T Disables fsync and creation/usage of system state file");
1953 (void)fprintf (stdout, "\n -v, -V Prints commands read from script file before execution");
1954 (void)fprintf (stdout, "\n --version Prints only the simulator identification text and exit");
1955 (void)fprintf (stdout, "\n");
1956 # if defined(USE_DUMA)
1957 nodist++;
1958 # endif
1959 if (!nodist) {
1960 (void)fprintf (stdout, "\n This software is made available under the terms of the ICU License.");
1961 (void)fprintf (stdout, "\n For complete license details, see the LICENSE file included with the");
1962 (void)fprintf (stdout, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\n");
1963 }
1964 else
1965 {
1966 (void)fprintf (stdout, "\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
1967 }
1968 (void)fprintf (stdout, "\n");
1969 FREE(argv);
1970 return 0;
1971 }
1972
1973 if ((*argv[i] == '-') && lookswitch) {
1974 if ((sw = get_switches (argv[i])) < 0) {
1975 (void)fprintf (stderr, "Invalid switch \"%s\".\nTry \"%s -h\" for help.\n", argv[i], argv[0]);
1976 FREE(argv);
1977 return 1;
1978 }
1979 sim_switches = sim_switches | sw;
1980 }
1981
1982 else {
1983 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
1984 (void)fprintf (stderr, "Argument string too long\n");
1985 FREE(argv);
1986 return 1;
1987 }
1988 if (*cbuf)
1989 strcat (cbuf, " ");
1990 (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s",
1991 strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
1992 lookswitch = FALSE;
1993 }
1994 }
1995 sim_nolock = sim_switches & SWMASK ('K');
1996 sim_iglock = sim_switches & SWMASK ('L');
1997 sim_randompst = sim_switches & SWMASK ('S');
1998 sim_quiet = sim_switches & SWMASK ('Q');
1999 sim_randstate = sim_switches & SWMASK ('R');
2000 if (sim_randompst) sim_randstate = 1;
2001 sim_nostate = sim_switches & SWMASK ('T');
2002 if (sim_nostate)
2003 {
2004 sim_randompst = 0;
2005 sim_randstate = 0;
2006 }
2007 sim_on_inherit = sim_switches & SWMASK ('O');
2008
2009 sim_init_sock ();
2010 if (sim_dflt_dev == NULL)
2011 sim_dflt_dev = sim_devices[0];
2012 if (sim_vm_init != NULL)
2013 (*sim_vm_init)();
2014 sim_finit ();
2015 for (i = 0; cmd_table[i].name; i++) {
2016 size_t alias_len = strlen (cmd_table[i].name);
2017 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2018 if (!cmd_name)
2019 {
2020 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2021 __func__, __FILE__, __LINE__);
2022 # if defined(USE_BACKTRACE)
2023 # if defined(SIGUSR2)
2024 (void)raise(SIGUSR2);
2025
2026 # endif
2027 # endif
2028 abort();
2029 }
2030
2031 strcpy (cmd_name, cmd_table[i].name);
2032 while (alias_len > 1) {
2033 cmd_name[alias_len] = '\0';
2034 --alias_len;
2035 if (getenv (cmd_name))
2036 unsetenv (cmd_name);
2037 }
2038 FREE (cmd_name);
2039 }
2040 stop_cpu = 0;
2041 sim_interval = 0;
2042 sim_time = sim_rtime = 0;
2043 noqueue_time = 0;
2044 sim_clock_queue = QUEUE_LIST_END;
2045 sim_is_running = 0;
2046 sim_log = NULL;
2047 if (sim_emax <= 0)
2048 sim_emax = 1;
2049 sim_timer_init ();
2050
2051 if ((stat = sim_ttinit ()) != SCPE_OK) {
2052 (void)fprintf (stderr, "Fatal terminal initialization error\n%s\n",
2053 sim_error_text (stat));
2054 FREE(argv);
2055 return 1;
2056 }
2057 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2058 (void)fprintf (stderr, "Unable to allocate examine buffer\n");
2059 FREE(argv);
2060 return 1;
2061 };
2062 if ((stat = reset_all_p (0)) != SCPE_OK) {
2063 (void)fprintf (stderr, "Fatal simulator initialization error\n%s\n",
2064 sim_error_text (stat));
2065 FREE(argv);
2066 return 1;
2067 }
2068 if ((stat = sim_brk_init ()) != SCPE_OK) {
2069 (void)fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",
2070 sim_error_text (stat));
2071 FREE(argv);
2072 return 1;
2073 }
2074 if (!sim_quiet) {
2075 (void)printf ("\n");
2076 show_version (stdout, NULL, NULL, 0, NULL);
2077 }
2078
2079 cptr = getenv("HOME");
2080 if (cptr == NULL) {
2081 cptr = getenv("HOMEPATH");
2082 cptr2 = getenv("HOMEDRIVE");
2083 }
2084 else
2085 cptr2 = NULL;
2086 (void)cptr2;
2087 if ( (*cbuf) && (strcmp(cbuf, "")) )
2088 stat = do_cmd (0, cbuf);
2089 else if (*argv[0]) {
2090 char *np;
2091 nbuf[0] = '"';
2092 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
2093 if (stat == SCPE_OPENERR) {
2094 np = strrchr (nbuf, '/');
2095 if (np == NULL)
2096 np = strrchr (nbuf, '\\');
2097 if (np != NULL) {
2098 *np = '"';
2099 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
2100 }
2101 }
2102 }
2103
2104 argv = uv_setup_args(argc, argv);
2105
2106 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2107
2108 if (sim_vm_exit != NULL)
2109 (*sim_vm_exit)();
2110
2111 detach_all (0, TRUE);
2112 sim_set_deboff (0, NULL);
2113 sim_set_logoff (0, NULL);
2114 sim_set_notelnet (0, NULL);
2115 sim_ttclose ();
2116 sim_cleanup_sock ();
2117 fclose (stdnul);
2118 FREE (targv);
2119 FREE (sim_prompt);
2120 FREE (sim_eval);
2121 FREE (sim_internal_devices);
2122 FREE (sim_brk_tab);
2123 FREE (sim_staba.comp);
2124 FREE (sim_staba.mask);
2125 FREE (sim_stabr.comp);
2126 FREE (sim_stabr.mask);
2127 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2128 }
2129 #endif
2130
2131 t_stat process_stdin_commands (t_stat stat, char *argv[])
2132 {
2133 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2134 CONST char *cptr;
2135 t_stat stat_nomessage;
2136 CTAB *cmdp = NULL;
2137
2138 stat = SCPE_BARE_STATUS(stat);
2139 while (stat != SCPE_EXIT) {
2140 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
2141 (void)printf ("%s%s\n", sim_prompt, cptr);
2142 else if (sim_vm_read != NULL) {
2143 (void)printf ("%s", sim_prompt);
2144 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2145 }
2146 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
2147 if (cptr == NULL) {
2148 if (sim_ttisatty()) continue;
2149 else break;
2150 }
2151 if (*cptr == 0)
2152 continue;
2153 sim_sub_args (cbuf, sizeof(cbuf), argv);
2154 if (sim_log)
2155 (void)fprintf (sim_log, "%s%s\n", sim_prompt, cptr);
2156 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2157 (void)fprintf (sim_deb, "%s%s\n", sim_prompt, cptr);
2158 cptr = get_glyph_cmd (cptr, gbuf);
2159 sim_switches = 0;
2160 if ((cmdp = find_cmd (gbuf)))
2161 stat = cmdp->action (cmdp->arg, cptr);
2162 else
2163 stat = SCPE_UNK;
2164 stat_nomessage = stat & SCPE_NOMESSAGE;
2165 stat_nomessage = stat_nomessage || (!sim_show_message);
2166 stat = SCPE_BARE_STATUS(stat);
2167 sim_last_cmd_stat = stat;
2168 if (!stat_nomessage) {
2169 if (cmdp && (cmdp->message))
2170 cmdp->message (NULL, stat);
2171 else
2172 if (stat >= SCPE_BASE)
2173 sim_printf ("%s\n", sim_error_text (stat));
2174 }
2175 if (sim_vm_post != NULL)
2176 (*sim_vm_post) (TRUE);
2177 }
2178 return stat;
2179 }
2180
2181
2182
2183 t_stat set_prompt (int32 flag, CONST char *cptr)
2184 {
2185 char gbuf[CBUFSIZE], *gptr;
2186
2187 if ((NULL == cptr) || (*cptr == '\0'))
2188 return SCPE_ARG;
2189
2190 cptr = get_glyph_nc (cptr, gbuf, '"');
2191 if (gbuf[0] == '\0') {
2192 gbuf[sizeof (gbuf)-1] = '\0';
2193 strncpy (gbuf, cptr, sizeof (gbuf)-1);
2194 gptr = strchr (gbuf, '"');
2195 if (NULL != gptr)
2196 *gptr = '\0';
2197 }
2198 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
2199 if (!sim_prompt)
2200 {
2201 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2202 __func__, __FILE__, __LINE__);
2203 #if defined(USE_BACKTRACE)
2204 # if defined(SIGUSR2)
2205 (void)raise(SIGUSR2);
2206
2207 # endif
2208 #endif
2209 abort();
2210 }
2211 (void)sprintf (sim_prompt, "%s ", gbuf);
2212 return SCPE_OK;
2213 }
2214
2215
2216
2217 CTAB *find_cmd (const char *gbuf)
2218 {
2219 CTAB *cmdp = NULL;
2220
2221 if (sim_vm_cmd)
2222 cmdp = find_ctab (sim_vm_cmd, gbuf);
2223 if (cmdp == NULL)
2224 cmdp = find_ctab (cmd_table, gbuf);
2225 return cmdp;
2226 }
2227
2228
2229
2230 t_stat exit_cmd (int32 flag, CONST char *cptr)
2231 {
2232 return SCPE_EXIT;
2233 }
2234
2235
2236
2237
2238 static int _cmd_name_compare (const void *pa, const void *pb)
2239 {
2240 CTAB * const *a = (CTAB * const *)pa;
2241 CTAB * const *b = (CTAB * const *)pb;
2242
2243 return strcmp((*a)->name, (*b)->name);
2244 }
2245
2246 void fprint_help (FILE *st)
2247 {
2248 CTAB *cmdp;
2249 CTAB **hlp_cmdp = NULL;
2250 size_t cmd_cnt = 0;
2251 size_t cmd_size = 0;
2252 size_t max_cmdname_size = 0;
2253 size_t i, line_offset;
2254
2255 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2256 if (cmdp->help) {
2257 if (cmd_cnt >= cmd_size) {
2258 cmd_size += 20;
2259 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2260 if (!hlp_cmdp)
2261 {
2262 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2263 __func__, __FILE__, __LINE__);
2264 #if defined(USE_BACKTRACE)
2265 # if defined(SIGUSR2)
2266 (void)raise(SIGUSR2);
2267
2268 # endif
2269 #endif
2270 abort();
2271 }
2272 }
2273 hlp_cmdp[cmd_cnt] = cmdp;
2274 ++cmd_cnt;
2275 if (strlen(cmdp->name) > max_cmdname_size)
2276 max_cmdname_size = strlen(cmdp->name);
2277 }
2278 }
2279 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2280 if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2281 if (cmd_cnt >= cmd_size) {
2282 cmd_size += 20;
2283 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2284 if (!hlp_cmdp)
2285 {
2286 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2287 __func__, __FILE__, __LINE__);
2288 #if defined(USE_BACKTRACE)
2289 # if defined(SIGUSR2)
2290 (void)raise(SIGUSR2);
2291
2292 # endif
2293 #endif
2294 abort();
2295 }
2296 }
2297 hlp_cmdp[cmd_cnt] = cmdp;
2298 ++cmd_cnt;
2299 if (strlen (cmdp->name) > max_cmdname_size)
2300 max_cmdname_size = strlen(cmdp->name);
2301 }
2302 }
2303 (void)fprintf (st, "HELP is available for the following commands:\n\n ");
2304 if (hlp_cmdp)
2305 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2306 line_offset = 4;
2307 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2308 fputs (hlp_cmdp[i]->name, st);
2309 line_offset += 5 + max_cmdname_size;
2310 if (line_offset + max_cmdname_size > 79) {
2311 line_offset = 4;
2312 (void)fprintf (st, "\n ");
2313 }
2314 else
2315 (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2316 }
2317 FREE (hlp_cmdp);
2318 (void)fprintf (st, "\n");
2319 return;
2320 }
2321
2322 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2323 {
2324 if (!*pdone)
2325 (void)fprintf (st, "%s", context);
2326 *pdone = TRUE;
2327 }
2328
2329 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2330 {
2331 REG *rptr, *trptr;
2332 t_bool found = FALSE;
2333 t_bool all_unique = TRUE;
2334 size_t max_namelen = 0;
2335 DEVICE *tdptr;
2336 CONST char *tptr;
2337 char *namebuf;
2338 char rangebuf[32];
2339
2340 if (dptr->registers)
2341 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2342 if (rptr->flags & REG_HIDDEN)
2343 continue;
2344 if (rptr->depth > 1)
2345 (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2346 else
2347 strcpy (rangebuf, "");
2348 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2349 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2350 found = TRUE;
2351 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2352 if ((trptr == NULL) || (tdptr != dptr))
2353 all_unique = FALSE;
2354 }
2355 if (!found) {
2356 if (!silent)
2357 (void)fprintf (st, "No register HELP available for the %s device\n",
2358 dptr->name);
2359 }
2360 else {
2361 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2362 if (!namebuf)
2363 {
2364 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2365 __func__, __FILE__, __LINE__);
2366 #if defined(USE_BACKTRACE)
2367 # if defined(SIGUSR2)
2368 (void)raise(SIGUSR2);
2369
2370 # endif
2371 #endif
2372 abort();
2373 }
2374 (void)fprintf (st, "\nThe %s device implements these registers:\n\n",
2375 dptr->name);
2376 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2377 if (rptr->flags & REG_HIDDEN)
2378 continue;
2379 if (rptr->depth <= 1)
2380 (void)sprintf (namebuf, "%*s",
2381 -((int)max_namelen),
2382 rptr->name);
2383 else {
2384 (void)sprintf (rangebuf, "[%d:%d]",
2385 0,
2386 rptr->depth-1);
2387 (void)sprintf (namebuf, "%s%*s",
2388 rptr->name,
2389 (int)(strlen(rptr->name))-((int)max_namelen),
2390 rangebuf);
2391 }
2392 if (all_unique) {
2393 (void)fprintf (st, " %s %4d %s\n",
2394 namebuf,
2395 rptr->width,
2396 rptr->desc ? rptr->desc : "");
2397 continue;
2398 }
2399 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2400 if ((trptr == NULL) || (tdptr != dptr))
2401 (void)fprintf (st, " %s %s %4d %s\n",
2402 dptr->name,
2403 namebuf,
2404 rptr->width,
2405 rptr->desc ? rptr->desc : "");
2406 else
2407 (void)fprintf (st, " %*s %s %4d %s\n",
2408 (int)strlen(dptr->name), "",
2409 namebuf,
2410 rptr->width,
2411 rptr->desc ? rptr->desc : "");
2412 }
2413 FREE (namebuf);
2414 }
2415 }
2416
2417 void fprint_reg_help (FILE *st, DEVICE *dptr)
2418 {
2419 fprint_reg_help_ex (st, dptr, TRUE);
2420 }
2421
2422 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2423 {
2424 if (dptr->attach_help) {
2425 (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2426 dptr->attach_help (st, dptr, NULL, 0, NULL);
2427 return;
2428 }
2429 if (DEV_TYPE(dptr) == DEV_DISK) {
2430 (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2431 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2432 return;
2433 }
2434 if (DEV_TYPE(dptr) == DEV_TAPE) {
2435 (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2436 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2437 return;
2438 }
2439 if (!silent) {
2440 (void)fprintf (st, "No ATTACH help is available for the %s device\n", dptr->name);
2441 if (dptr->help)
2442 dptr->help (st, dptr, NULL, 0, NULL);
2443 }
2444 }
2445
2446 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2447 {
2448 MTAB *mptr;
2449 DEBTAB *dep;
2450 t_bool found = FALSE;
2451 char buf[CBUFSIZE], header[CBUFSIZE];
2452 uint32 enabled_units = dptr->numunits;
2453 uint32 unit;
2454
2455 (void)sprintf (header, "\n%s device SET commands:\n\n", dptr->name);
2456 for (unit=0; unit < dptr->numunits; unit++)
2457 if (dptr->units[unit].flags & UNIT_DIS)
2458 --enabled_units;
2459 if (dptr->modifiers) {
2460 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2461 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2462 continue;
2463 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2464 continue;
2465 if (mptr->mstring) {
2466 fprint_header (st, &found, header);
2467 (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2468 mptr->mstring,
2469 (strchr(mptr->mstring, '=')) \
2470 ? "" : (MODMASK(mptr,MTAB_VALR) \
2471 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2472 ? "{=val}" : "")));
2473 if ((strlen (buf) < 30) || (NULL == mptr->help))
2474 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2475 else
2476 (void)fprintf (st, "%s\n%-30s\t%s\n", buf, "", mptr->help);
2477 }
2478 }
2479 }
2480 if (dptr->flags & DEV_DISABLE) {
2481 fprint_header (st, &found, header);
2482 (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2483 (void)fprintf (st, "%-30s\tEnables device %s\n", buf, sim_dname (dptr));
2484 (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2485 (void)fprintf (st, "%-30s\tDisables device %s\n", buf, sim_dname (dptr));
2486 }
2487 if (dptr->flags & DEV_DEBUG) {
2488 fprint_header (st, &found, header);
2489 (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2490 (void)fprintf (st, "%-30s\tEnables debugging for device %s\n", buf, sim_dname (dptr));
2491 (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2492 (void)fprintf (st, "%-30s\tDisables debugging for device %s\n", buf, sim_dname (dptr));
2493 if (dptr->debflags) {
2494 t_bool desc_available = FALSE;
2495 strcpy (buf, "");
2496 (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2497 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2498 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2499 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2500 }
2501 (void)fprintf (st, "\n");
2502 (void)fprintf (st, "%-30s\tEnables specific debugging for device %s\n", buf, sim_dname (dptr));
2503 (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2504 for (dep = dptr->debflags; dep->name != NULL; dep++)
2505 (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2506 (void)fprintf (st, "\n");
2507 (void)fprintf (st, "%-30s\tDisables specific debugging for device %s\n", buf, sim_dname (dptr));
2508 if (desc_available) {
2509 (void)fprintf (st, "\n*%s device DEBUG settings:\n", sim_dname (dptr));
2510 for (dep = dptr->debflags; dep->name != NULL; dep++)
2511 (void)fprintf (st, "%4s%-12s%s\n", "", dep->name, dep->desc ? dep->desc : "");
2512 }
2513 }
2514 }
2515 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2516 if (dptr->units->flags & UNIT_DISABLE) {
2517 fprint_header (st, &found, header);
2518 (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2519 (void)fprintf (st, "%-30s\tEnables unit %sn\n", buf, sim_dname (dptr));
2520 (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2521 (void)fprintf (st, "%-30s\tDisables unit %sn\n", buf, sim_dname (dptr));
2522 }
2523 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2524 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2525 continue;
2526 if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2527 continue;
2528 if (mptr->mstring) {
2529 fprint_header (st, &found, header);
2530 (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2531 (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2532 (strchr(mptr->mstring, '=')) \
2533 ? "" : (MODMASK(mptr,MTAB_VALR) \
2534 ? "=val" : (MODMASK(mptr,MTAB_VALO) \
2535 ? "{=val}" : "")));
2536 (void)fprintf (st, "%-30s\t%s\n", buf,
2537 (strchr(mptr->mstring, '=')) \
2538 ? "" : (mptr->help ? mptr->help : ""));
2539 }
2540 }
2541 }
2542 if (!found && !silent)
2543 (void)fprintf (st, "No SET help is available for the %s device\n", dptr->name);
2544 }
2545
2546 void fprint_set_help (FILE *st, DEVICE *dptr)
2547 {
2548 fprint_set_help_ex (st, dptr, TRUE);
2549 }
2550
2551 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2552 {
2553 MTAB *mptr;
2554 t_bool found = FALSE;
2555 char buf[CBUFSIZE], header[CBUFSIZE];
2556 uint32 enabled_units = dptr->numunits;
2557 uint32 unit;
2558
2559 (void)sprintf (header, "\n%s device SHOW commands:\n\n", dptr->name);
2560 for (unit=0; unit < dptr->numunits; unit++)
2561 if (dptr->units[unit].flags & UNIT_DIS)
2562 --enabled_units;
2563 if (dptr->modifiers) {
2564 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2565 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2566 continue;
2567 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2568 continue;
2569 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2570 continue;
2571 fprint_header (st, &found, header);
2572 (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2573 mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2574 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2575 }
2576 }
2577 if (dptr->flags & DEV_DEBUG) {
2578 fprint_header (st, &found, header);
2579 (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2580 (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\n", buf, sim_dname (dptr));
2581 }
2582 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2583 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2584 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2585 continue;
2586 if ((!mptr->disp) || (!mptr->pstring))
2587 continue;
2588 fprint_header (st, &found, header);
2589 (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2590 (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2591 MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2592 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2593 }
2594 }
2595 if (!found && !silent)
2596 (void)fprintf (st, "No SHOW help is available for the %s device\n", dptr->name);
2597 }
2598
2599 void fprint_show_help (FILE *st, DEVICE *dptr)
2600 {
2601 fprint_show_help_ex (st, dptr, TRUE);
2602 }
2603
2604 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2605 {
2606 BRKTYPTAB *brkt = dptr->brk_types;
2607 char gbuf[CBUFSIZE];
2608
2609 if (sim_brk_types == 0) {
2610 if ((dptr != sim_dflt_dev) && (!silent)) {
2611 (void)fprintf (st, "Breakpoints are not supported in the %s simulator\n", sim_name);
2612 if (dptr->help)
2613 dptr->help (st, dptr, NULL, 0, NULL);
2614 }
2615 return;
2616 }
2617 if (brkt == NULL) {
2618 int i;
2619
2620 if (dptr == sim_dflt_dev) {
2621 if (sim_brk_types & ~sim_brk_dflt) {
2622 (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2623 for (i=0; i<26; i++) {
2624 if (sim_brk_types & (1<<i))
2625 (void)fprintf (st, " -%c\n", 'A'+i);
2626 }
2627 }
2628 (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2629 }
2630 return;
2631 }
2632 (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2633 while (brkt->btyp) {
2634 (void)fprintf (st, " %s %s\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2635 ++brkt;
2636 }
2637 (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2638 }
2639
2640 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2641 {
2642 char gbuf[CBUFSIZE];
2643 CTAB *cmdp;
2644
2645 if (*cptr) {
2646 (void)get_glyph (cptr, gbuf, 0);
2647 if ((cmdp = find_cmd (gbuf))) {
2648 if (cmdp->action == &exdep_cmd) {
2649 if (dptr->help)
2650 return dptr->help (st, dptr, uptr, flag, cptr);
2651 else
2652 (void)fprintf (st, "No HELP available for the %s %s command\n", cmdp->name, sim_dname(dptr));
2653 return SCPE_OK;
2654 }
2655 if (cmdp->action == &set_cmd) {
2656 fprint_set_help_ex (st, dptr, FALSE);
2657 return SCPE_OK;
2658 }
2659 if (cmdp->action == &show_cmd) {
2660 fprint_show_help_ex (st, dptr, FALSE);
2661 return SCPE_OK;
2662 }
2663 if (cmdp->action == &attach_cmd) {
2664 fprint_attach_help_ex (st, dptr, FALSE);
2665 return SCPE_OK;
2666 }
2667 if (cmdp->action == &brk_cmd) {
2668 fprint_brk_help_ex (st, dptr, FALSE);
2669 return SCPE_OK;
2670 }
2671 if (dptr->help)
2672 return dptr->help (st, dptr, uptr, flag, cptr);
2673 (void)fprintf (st, "No %s HELP is available for the %s device\n", cmdp->name, dptr->name);
2674 return SCPE_OK;
2675 }
2676 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2677 fprint_reg_help_ex (st, dptr, FALSE);
2678 return SCPE_OK;
2679 }
2680 if (dptr->help)
2681 return dptr->help (st, dptr, uptr, flag, cptr);
2682 (void)fprintf (st, "No %s HELP is available for the %s device\n", gbuf, dptr->name);
2683 return SCPE_OK;
2684 }
2685 if (dptr->help) {
2686 return dptr->help (st, dptr, uptr, flag, cptr);
2687 }
2688 if (dptr->description)
2689 (void)fprintf (st, "%s %s HELP\n", dptr->description (dptr), dptr->name);
2690 else
2691 (void)fprintf (st, "%s HELP\n", dptr->name);
2692 fprint_set_help_ex (st, dptr, TRUE);
2693 fprint_show_help_ex (st, dptr, TRUE);
2694 fprint_attach_help_ex (st, dptr, TRUE);
2695 fprint_reg_help_ex (st, dptr, TRUE);
2696 fprint_brk_help_ex (st, dptr, TRUE);
2697 return SCPE_OK;
2698 }
2699
2700 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2701 {
2702 switch (help[0]) {
2703 case '*':
2704 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2705 if (sim_log)
2706 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2707 break;
2708 default:
2709 fputs (help, stdout);
2710 if (sim_log)
2711 fputs (help, sim_log);
2712 break;
2713 }
2714 return SCPE_OK;
2715 }
2716
2717 t_stat help_cmd (int32 flag, CONST char *cptr)
2718 {
2719 char gbuf[CBUFSIZE];
2720 CTAB *cmdp;
2721
2722 GET_SWITCHES (cptr);
2723 if (sim_switches & SWMASK ('F'))
2724 flag = flag | SCP_HELP_FLAT;
2725 if (*cptr) {
2726 cptr = get_glyph (cptr, gbuf, 0);
2727 if ((cmdp = find_cmd (gbuf))) {
2728 if (*cptr) {
2729 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2730 DEVICE *dptr;
2731 UNIT *uptr;
2732 t_stat r;
2733 cptr = get_glyph (cptr, gbuf, 0);
2734 dptr = find_unit (gbuf, &uptr);
2735 if (dptr == NULL)
2736 dptr = find_dev (gbuf);
2737 if (dptr != NULL) {
2738 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2739 if (sim_log)
2740 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2741 return r;
2742 }
2743 if (cmdp->action == &set_cmd) {
2744
2745 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2746 (cmdp->help))
2747 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2748 }
2749 else {
2750 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2751 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2752 return SCPE_ARG;
2753 return help_cmd_output (flag, shptr->help, NULL);
2754 }
2755 return SCPE_ARG;
2756 }
2757 else
2758 return SCPE_2MARG;
2759 }
2760 if (cmdp->help) {
2761 if (strcmp (cmdp->name, "HELP") == 0) {
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796 }
2797 else {
2798 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2799 sim_dflt_dev && sim_dflt_dev->help) {
2800 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2801 if (sim_log)
2802 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2803 }
2804 }
2805 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2806 }
2807 else {
2808 CTAB *cmdpa;
2809 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2810 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2811 sim_printf ("%s is an alias for the %s command:\n%s",
2812 cmdp->name, cmdpa->name, cmdpa->help);
2813 break;
2814 }
2815 if (cmdpa->name == NULL)
2816 sim_printf ("No help available for the %s command\n", cmdp->name);
2817 }
2818 }
2819 else {
2820 DEVICE *dptr;
2821 UNIT *uptr;
2822 t_stat r;
2823 dptr = find_unit (gbuf, &uptr);
2824 if (dptr == NULL) {
2825 dptr = find_dev (gbuf);
2826 if (dptr == NULL)
2827 return SCPE_ARG;
2828 if (dptr->flags & DEV_DIS)
2829 sim_printf ("Device %s is currently disabled\n", dptr->name);
2830 }
2831 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2832 if (sim_log)
2833 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2834 return r;
2835 }
2836 }
2837 else {
2838 fprint_help (stdout);
2839 if (sim_log)
2840 fprint_help (sim_log);
2841 }
2842 return SCPE_OK;
2843 }
2844
2845
2846
2847 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2848 {
2849 t_stat status;
2850 if ((cptr == NULL) || (strlen (cptr) == 0))
2851 cptr = getenv("SHELL");
2852 if ((cptr == NULL) || (strlen (cptr) == 0))
2853 cptr = getenv("ComSpec");
2854 (void)fflush(stdout);
2855 if (sim_log)
2856 (void)fflush (sim_log);
2857 if (sim_deb)
2858 (void)fflush (sim_deb);
2859 status = system (cptr);
2860
2861 return status;
2862 }
2863
2864
2865
2866 t_stat echo_cmd (int32 flag, CONST char *cptr)
2867 {
2868 sim_printf ("%s\n", cptr);
2869 return SCPE_OK;
2870 }
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892 t_stat do_cmd (int32 flag, CONST char *fcptr)
2893 {
2894 return do_cmd_label (flag, fcptr, NULL);
2895 }
2896
2897 static char *do_position(void)
2898 {
2899 static char cbuf[4*CBUFSIZE];
2900
2901 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
2902 sim_do_label[sim_do_depth] ? "::" : "",
2903 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
2904 sim_goto_line[sim_do_depth]);
2905 return cbuf;
2906 }
2907
2908 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
2909 {
2910 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
2911 CONST char *cptr;
2912 FILE *fpin;
2913 CTAB *cmdp = NULL;
2914 int32 echo, nargs, errabort, i;
2915 int32 saved_sim_do_echo = sim_do_echo,
2916 saved_sim_show_message = sim_show_message,
2917 saved_sim_on_inherit = sim_on_inherit,
2918 saved_sim_quiet = sim_quiet;
2919 t_bool staying;
2920 t_stat stat, stat_nomessage;
2921
2922 stat = SCPE_OK;
2923 staying = TRUE;
2924 if (flag > 0)
2925 GET_SWITCHES (fcptr);
2926 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
2927 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
2928 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
2929 errabort = sim_switches & SWMASK ('E');
2930
2931 abuf[sizeof(abuf)-1] = '\0';
2932 strncpy (abuf, fcptr, sizeof(abuf)-1);
2933 c = abuf;
2934 do_arg[10] = NULL;
2935 for (nargs = 0; nargs < 10; ) {
2936 while (sim_isspace (*c))
2937 c++;
2938 if (*c == 0)
2939 do_arg [nargs++] = NULL;
2940 else {
2941 if (*c == '\'' || *c == '"')
2942 quote = *c++;
2943 else quote = 0;
2944 do_arg[nargs++] = c;
2945 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
2946 c++;
2947 if (*c)
2948 *c++ = 0;
2949 }
2950 }
2951
2952 if (do_arg [0] == NULL)
2953 return SCPE_2FARG;
2954 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
2955 strcat (strcpy (cbuf, do_arg[0]), ".ini");
2956 if ((fpin = fopen (cbuf, "r")) == NULL) {
2957 if (flag == 0)
2958 (void)fprintf (stderr, "Can't open file %s\n", do_arg[0]);
2959 return SCPE_OPENERR;
2960 }
2961 }
2962 if (flag >= 0) {
2963 ++sim_do_depth;
2964 if (sim_on_inherit) {
2965 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
2966 for (i=0; i<SCPE_MAX_ERR; i++) {
2967 if (sim_on_actions[sim_do_depth-1][i]) {
2968 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
2969 if (NULL == sim_on_actions[sim_do_depth][i]) {
2970 while (--i >= 0) {
2971 FREE(sim_on_actions[sim_do_depth][i]);
2972 sim_on_actions[sim_do_depth][i] = NULL;
2973 }
2974 sim_on_check[sim_do_depth] = 0;
2975 sim_brk_clract ();
2976 --sim_do_depth;
2977 fclose(fpin);
2978 return SCPE_MEM;
2979 }
2980 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
2981 }
2982 }
2983 }
2984 }
2985
2986 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
2987 sim_do_label[sim_do_depth] = label;
2988 sim_goto_line[sim_do_depth] = 0;
2989 if (label) {
2990 sim_gotofile = fpin;
2991 sim_do_echo = echo;
2992 stat = goto_cmd (0, label);
2993 if (stat != SCPE_OK) {
2994 strcpy(cbuf, "RETURN SCPE_ARG");
2995 cptr = get_glyph (cbuf, gbuf, 0);
2996 cmdp = find_cmd (gbuf);
2997 goto Cleanup_Return;
2998 }
2999 }
3000 if (errabort)
3001 set_on (1, NULL);
3002
3003 do {
3004 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
3005 if (!sim_do_ocptr[sim_do_depth]) {
3006 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
3007 sim_goto_line[sim_do_depth] += 1;
3008 }
3009 if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {
3010 sim_sub_args(cbuf, sizeof(cbuf), do_arg);
3011 }
3012 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
3013 if (cptr == NULL) {
3014 stat = SCPE_OK;
3015 break;
3016 }
3017 if (*cptr == 0)
3018 continue;
3019 if (echo)
3020 sim_printf("%s> %s\n", do_position(), cptr);
3021 if (*cptr == ':')
3022 continue;
3023 cptr = get_glyph_cmd (cptr, gbuf);
3024 sim_switches = 0;
3025 sim_gotofile = fpin;
3026 sim_do_echo = echo;
3027 if ((cmdp = find_cmd (gbuf))) {
3028 if (cmdp->action == &return_cmd)
3029 break;
3030 if (cmdp->action == &do_cmd) {
3031 if (sim_do_depth >= MAX_DO_NEST_LVL)
3032 stat = SCPE_NEST;
3033 else
3034 stat = do_cmd (sim_do_depth+1, cptr);
3035 }
3036 else
3037 stat = cmdp->action (cmdp->arg, cptr);
3038 }
3039 else stat = SCPE_UNK;
3040 echo = sim_do_echo;
3041 stat_nomessage = stat & SCPE_NOMESSAGE;
3042 stat_nomessage = stat_nomessage || (!sim_show_message);
3043 stat = SCPE_BARE_STATUS(stat);
3044 if (cmdp)
3045 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3046 ((cmdp->action != &return_cmd) &&
3047 (cmdp->action != &goto_cmd) &&
3048 (cmdp->action != &on_cmd) &&
3049 (cmdp->action != &echo_cmd)))
3050 sim_last_cmd_stat = stat;
3051 switch (stat) {
3052 case SCPE_AFAIL:
3053 staying = (sim_on_check[sim_do_depth] &&
3054 sim_on_actions[sim_do_depth][stat]);
3055 break;
3056 case SCPE_EXIT:
3057 staying = FALSE;
3058 break;
3059 case SCPE_OK:
3060 case SCPE_STEP:
3061 break;
3062 default:
3063 break;
3064 }
3065 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
3066 (stat != SCPE_STEP)) {
3067 if (!echo && !sim_quiet &&
3068 !stat_nomessage &&
3069 !(cmdp && cmdp->message)) {
3070 sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
3071 }
3072 }
3073 if (!stat_nomessage) {
3074 if (cmdp && cmdp->message)
3075 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3076 else
3077 if (stat >= SCPE_BASE)
3078 sim_printf ("%s\n", sim_error_text (stat));
3079 }
3080 if (stat == SCPE_EXPECT)
3081 stat = SCPE_OK;
3082 if (staying &&
3083 (sim_on_check[sim_do_depth]) &&
3084 (stat != SCPE_OK) &&
3085 (stat != SCPE_STEP)) {
3086 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3087 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3088 else
3089 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3090 }
3091 if (sim_vm_post != NULL)
3092 (*sim_vm_post) (TRUE);
3093 } while (staying);
3094 Cleanup_Return:
3095 if (fpin)
3096 fclose (fpin);
3097 sim_gotofile = NULL;
3098 if (flag >= 0) {
3099 sim_do_echo = saved_sim_do_echo;
3100 sim_show_message = saved_sim_show_message;
3101 sim_on_inherit = saved_sim_on_inherit;
3102 }
3103 sim_quiet = saved_sim_quiet;
3104 if ((flag >= 0) || (!sim_on_inherit)) {
3105 for (i=0; i<SCPE_MAX_ERR; i++) {
3106 FREE (sim_on_actions[sim_do_depth][i]);
3107 sim_on_actions[sim_do_depth][i] = NULL;
3108 }
3109 sim_on_check[sim_do_depth] = 0;
3110 }
3111 if (flag >= 0)
3112 --sim_do_depth;
3113 sim_brk_clract ();
3114 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
3115 sim_string_to_stat (cptr, &stat);
3116 sim_last_cmd_stat = stat;
3117 if (sim_switches & SWMASK ('Q'))
3118 stat |= SCPE_NOMESSAGE;
3119 return stat;
3120 }
3121 return stat | SCPE_NOMESSAGE;
3122 }
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
3167 {
3168 char gbuf[CBUFSIZE];
3169 char *ip = instr, *op, *oend, *tmpbuf;
3170 const char *ap;
3171 char rbuf[CBUFSIZE];
3172 int i;
3173 time_t now;
3174 struct tm *tmnow;
3175
3176 time(&now);
3177 tmnow = localtime(&now);
3178 tmpbuf = (char *)malloc(instr_size);
3179 if (!tmpbuf)
3180 {
3181 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3182 __func__, __FILE__, __LINE__);
3183 #if defined(USE_BACKTRACE)
3184 # if defined(SIGUSR2)
3185 (void)raise(SIGUSR2);
3186
3187 # endif
3188 #endif
3189 abort();
3190 }
3191 op = tmpbuf;
3192 oend = tmpbuf + instr_size - 2;
3193 while (sim_isspace (*ip))
3194 *op++ = *ip++;
3195 for (; *ip && (op < oend); ) {
3196 if ((ip [0] == '\\') &&
3197 ((ip [1] == '%') || (ip [1] == '\\'))) {
3198 ip++;
3199 *op++ = *ip++;
3200 }
3201 else
3202 if ((*ip == '%') &&
3203 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
3204 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
3205 ap = do_arg[ip[1] - '0'];
3206 for (i=0; i<ip[1] - '0'; ++i)
3207 if (do_arg[i] == NULL) {
3208 ap = NULL;
3209 break;
3210 }
3211 ip = ip + 2;
3212 }
3213 else if (ip[1] == '*') {
3214 (void)memset (rbuf, '\0', sizeof(rbuf));
3215 ap = rbuf;
3216 for (i=1; i<=9; ++i)
3217 if (do_arg[i] == NULL)
3218 break;
3219 else
3220 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3221 if (strchr(do_arg[i], ' ')) {
3222 char quote = '"';
3223 if (strchr(do_arg[i], quote))
3224 quote = '\'';
3225 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3226 (i != 1) ? " " : "", quote,
3227 do_arg[i], quote);
3228 }
3229 else
3230 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3231 (i != 1) ? " " : "", do_arg[i]);
3232 }
3233 else
3234 break;
3235 ip = ip + 2;
3236 }
3237 else {
3238 ap = NULL;
3239 (void)get_glyph_nc (ip+1, gbuf, '%');
3240 ap = getenv(gbuf);
3241 if (!ap) {
3242 (void)get_glyph (ip+1, gbuf, '%');
3243 ap = getenv(gbuf);
3244 }
3245 ip += 1 + strlen (gbuf);
3246 if (*ip == '%') ++ip;
3247 if (!ap) {
3248
3249 if (!strcmp ("DATE", gbuf)) {
3250 (void)sprintf (rbuf, "%4d-%02d-%02d",
3251 tmnow->tm_year + 1900,
3252 tmnow->tm_mon + 1,
3253 tmnow->tm_mday);
3254 ap = rbuf;
3255 }
3256 else if (!strcmp ("TIME", gbuf)) {
3257 (void)sprintf (rbuf, "%02d:%02d:%02d",
3258 tmnow->tm_hour,
3259 tmnow->tm_min,
3260 tmnow->tm_sec);
3261 ap = rbuf;
3262 }
3263 else if (!strcmp ("DATETIME", gbuf)) {
3264 (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3265 tmnow->tm_year + 1900,
3266 tmnow->tm_mon + 1,
3267 tmnow->tm_mday,
3268 tmnow->tm_hour,
3269 tmnow->tm_min,
3270 tmnow->tm_sec);
3271 ap = rbuf;
3272 }
3273
3274 if (!strcmp ("LDATE", gbuf)) {
3275 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3276 ap = rbuf;
3277 }
3278 else if (!strcmp ("LTIME", gbuf)) {
3279 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3280 ap = rbuf;
3281 }
3282 else if (!strcmp ("CTIME", gbuf)) {
3283 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3284 ap = rbuf;
3285 }
3286
3287 else if (!strcmp ("DATE_YYYY", gbuf)) {
3288 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3289 ap = rbuf;
3290 }
3291 else if (!strcmp ("DATE_YY", gbuf)) {
3292 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3293 ap = rbuf;
3294 }
3295 else if (!strcmp ("DATE_YC", gbuf)) {
3296 (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3297 ap = rbuf;
3298 }
3299 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3300 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3301 int year = tmnow->tm_year + 1900;
3302 int days = year - 2001;
3303 int leaps = days/4 - days/100 + days/400;
3304 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3305 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3306 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3307 96, 80, 92, 76, 88, 72, 84};
3308 int cal_year = years[selector];
3309
3310 if (!strcmp ("DATE_19XX_YY", gbuf))
3311 (void)sprintf (rbuf, "%d", cal_year);
3312 else
3313 (void)sprintf (rbuf, "%d", cal_year + 1900);
3314 ap = rbuf;
3315 }
3316 else if (!strcmp ("DATE_MM", gbuf)) {
3317 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3318 ap = rbuf;
3319 }
3320 else if (!strcmp ("DATE_MMM", gbuf)) {
3321 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3322 ap = rbuf;
3323 }
3324 else if (!strcmp ("DATE_DD", gbuf)) {
3325 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3326 ap = rbuf;
3327 }
3328 else if (!strcmp ("DATE_D", gbuf)) {
3329 (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3330 ap = rbuf;
3331 }
3332 else if ((!strcmp ("DATE_WW", gbuf)) ||
3333 (!strcmp ("DATE_WYYYY", gbuf))) {
3334 int iso_yr = tmnow->tm_year + 1900;
3335 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3336
3337 if (iso_wk == 0) {
3338 iso_yr = iso_yr - 1;
3339 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3340 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3341 }
3342 else
3343 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3344 ++iso_yr;
3345 iso_wk = 1;
3346 }
3347 if (!strcmp ("DATE_WW", gbuf))
3348 (void)sprintf (rbuf, "%02d", iso_wk);
3349 else
3350 (void)sprintf (rbuf, "%04d", iso_yr);
3351 ap = rbuf;
3352 }
3353 else if (!strcmp ("DATE_JJJ", gbuf)) {
3354 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3355 ap = rbuf;
3356 }
3357 else if (!strcmp ("TIME_HH", gbuf)) {
3358 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3359 ap = rbuf;
3360 }
3361 else if (!strcmp ("TIME_MM", gbuf)) {
3362 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3363 ap = rbuf;
3364 }
3365 else if (!strcmp ("TIME_SS", gbuf)) {
3366 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3367 ap = rbuf;
3368 }
3369 else if (!strcmp ("STATUS", gbuf)) {
3370 (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3371 ap = rbuf;
3372 }
3373 else if (!strcmp ("TSTATUS", gbuf)) {
3374 (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3375 ap = rbuf;
3376 }
3377 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3378 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3379 ap = rbuf;
3380 }
3381 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3382 (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3383 ap = rbuf;
3384 }
3385 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3386 (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3387 ap = rbuf;
3388 }
3389 else if (!strcmp ("SIM_QUIET", gbuf)) {
3390 (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3391 ap = rbuf;
3392 }
3393 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3394 (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3395 ap = rbuf;
3396 }
3397 else if (!strcmp ("HOSTID", gbuf)) {
3398 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__)
3399 (void)sprintf (rbuf, "%ld", (long)gethostid());
3400 #else
3401 (void)sprintf (rbuf, "00000000");
3402 #endif
3403 ap = rbuf;
3404 }
3405 else if (!strcmp ("UID", gbuf)) {
3406 #if defined(HAVE_UNISTD)
3407 (void)sprintf (rbuf, "%ld", (long)getuid());
3408 #else
3409 (void)sprintf (rbuf, "0");
3410 #endif
3411 ap = rbuf;
3412 }
3413 else if (!strcmp ("GID", gbuf)) {
3414 #if defined(HAVE_UNISTD)
3415 (void)sprintf (rbuf, "%ld", (long)getgid());
3416 #else
3417 (void)sprintf (rbuf, "0");
3418 #endif
3419 ap = rbuf;
3420 }
3421 else if (!strcmp ("EUID", gbuf)) {
3422 #if defined(HAVE_UNISTD)
3423 (void)sprintf (rbuf, "%ld", (long)geteuid());
3424 #else
3425 (void)sprintf (rbuf, "0");
3426 #endif
3427 ap = rbuf;
3428 }
3429 else if (!strcmp ("EGID", gbuf)) {
3430 #if defined(HAVE_UNISTD)
3431 (void)sprintf (rbuf, "%ld", (long)getegid());
3432 #else
3433 (void)sprintf (rbuf, "0");
3434 #endif
3435 ap = rbuf;
3436 }
3437 else if (!strcmp ("PID", gbuf)) {
3438 #if defined(HAVE_UNISTD)
3439 (void)sprintf (rbuf, "%ld", (long)getpid());
3440 #else
3441 (void)sprintf (rbuf, "0");
3442 #endif
3443 ap = rbuf;
3444 }
3445 else if (!strcmp ("PPID", gbuf)) {
3446 #if defined(HAVE_UNISTD)
3447 (void)sprintf (rbuf, "%ld", (long)getppid());
3448 #else
3449 (void)sprintf (rbuf, "0");
3450 #endif
3451 ap = rbuf;
3452 }
3453 else if (!strcmp ("PGID", gbuf)) {
3454 #if defined(HAVE_UNISTD)
3455 (void)sprintf (rbuf, "%ld", (long)getpgid(getpid()));
3456 #else
3457 (void)sprintf (rbuf, "0");
3458 #endif
3459 ap = rbuf;
3460 }
3461 else if (!strcmp ("SID", gbuf)) {
3462 #if defined(HAVE_UNISTD)
3463 (void)sprintf (rbuf, "%ld", (long)getsid(getpid()));
3464 #else
3465 (void)sprintf (rbuf, "0");
3466 #endif
3467 ap = rbuf;
3468 }
3469 else if (!strcmp ("ENDIAN", gbuf)) {
3470 #if ( defined(DECLITEND) && DECLITEND == 1 )
3471 (void)sprintf (rbuf, "LITTLE");
3472 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3473 (void)sprintf (rbuf, "BIG");
3474 #else
3475 (void)sprintf (rbuf, "UNKNOWN");
3476 #endif
3477 ap = rbuf;
3478 }
3479 else if (!strcmp("SIM_NAME", gbuf)) {
3480 (void)sprintf (rbuf, "%s", sim_name);
3481 ap = rbuf;
3482 }
3483 else if (!strcmp("SIM_VERSION", gbuf)) {
3484 #if defined(VER_H_GIT_VERSION)
3485 (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3486 #else
3487 (void)sprintf (rbuf, "UNKNOWN");
3488 #endif
3489 ap = rbuf;
3490 }
3491 else if (!strcmp("SIM_HASH", gbuf)) {
3492 #if defined(VER_H_GIT_HASH)
3493 (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3494 #else
3495 (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3496 #endif
3497 ap = rbuf;
3498 }
3499 else if (!strcmp("SIM_RELT", gbuf)) {
3500 #if defined(VER_H_GIT_RELT)
3501 (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3502 #else
3503 (void)sprintf (rbuf, "X");
3504 #endif
3505 ap = rbuf;
3506 }
3507 else if (!strcmp("SIM_DATE", gbuf)) {
3508 #if defined(VER_H_GIT_DATE)
3509 (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3510 #else
3511 (void)sprintf (rbuf, "UNKNOWN");
3512 #endif
3513 ap = rbuf;
3514 }
3515 else if ( (!strcmp("CPUS", gbuf)) \
3516 || (!strcmp("SIM_PROCESSORS", gbuf) ) ) {
3517 (void)sprintf(rbuf, "%u", nprocs);
3518 ap = rbuf;
3519 }
3520 }
3521 }
3522 if (ap) {
3523 while (*ap && (op < oend))
3524 *op++ = *ap++;
3525 }
3526 }
3527 else
3528 *op++ = *ip++;
3529 }
3530 *op = 0;
3531 strcpy (instr, tmpbuf);
3532 FREE (tmpbuf);
3533 return;
3534 }
3535
3536 static
3537 int sim_cmp_string (const char *s1, const char *s2)
3538 {
3539 long int v1, v2;
3540 char *ep1, *ep2;
3541
3542 v1 = strtol(s1+1, &ep1, 0);
3543 v2 = strtol(s2+1, &ep2, 0);
3544 if ((ep1 != s1 + strlen (s1) - 1) ||
3545 (ep2 != s2 + strlen (s2) - 1))
3546 return strcmp (s1, s2);
3547 if (v1 == v2)
3548 return 0;
3549 if (v1 < v2)
3550 return -1;
3551 return 1;
3552 }
3553
3554
3555
3556 t_stat assert_cmd (int32 flag, CONST char *cptr)
3557 {
3558 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3559 CONST char *tptr, *gptr;
3560 REG *rptr;
3561 uint32 idx = 0;
3562 t_value val;
3563 t_stat r;
3564 t_bool Not = FALSE;
3565 t_bool result;
3566 t_addr addr = 0;
3567 t_stat reason = SCPE_AFAIL;
3568
3569 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3570
3571 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3572 # pragma diagnostic push
3573 # pragma diag_suppress = integer_sign_change
3574 #endif
3575 sim_stabr.boolop = sim_staba.boolop = -1;
3576 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3577 # pragma diagnostic pop
3578 #endif
3579 if (*cptr == 0)
3580 return SCPE_2FARG;
3581 tptr = get_glyph (cptr, gbuf, 0);
3582 if (!strcmp (gbuf, "NOT")) {
3583 Not = TRUE;
3584 cptr = (CONST char *)tptr;
3585 }
3586 if (*cptr == '"') {
3587 char op[CBUFSIZE];
3588 static struct {
3589 const char *op;
3590 int aval;
3591 int bval;
3592 t_bool invert;
3593 } *optr, compare_ops[] =
3594 {
3595 { "==", 0, 0, FALSE },
3596 { "EQU", 0, 0, FALSE },
3597 { "!=", 0, 0, TRUE },
3598 { "NEQ", 0, 0, TRUE },
3599 { "<", -1, -1, FALSE },
3600 { "LSS", -1, -1, FALSE },
3601 { "<=", 0, -1, FALSE },
3602 { "LEQ", 0, -1, FALSE },
3603 { ">", 1, 1, FALSE },
3604 { "GTR", 1, 1, FALSE },
3605 { ">=", 0, 1, FALSE },
3606 { "GEQ", 0, 1, FALSE },
3607 { NULL }
3608 };
3609
3610 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3611
3612 if (!*tptr)
3613 return SCPE_2FARG;
3614 cptr += strlen (gbuf);
3615 while (sim_isspace (*cptr))
3616 ++cptr;
3617 (void)get_glyph (cptr, op, '"');
3618 for (optr = compare_ops; optr->op; optr++)
3619 if (0 == strcmp (op, optr->op))
3620 break;
3621 if (!optr->op)
3622 return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
3623 cptr += strlen (op);
3624 while (sim_isspace (*cptr))
3625 ++cptr;
3626 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3627
3628 if (*cptr) {
3629 if (flag)
3630 return SCPE_2MARG;
3631 }
3632 else {
3633 if (!flag)
3634 return SCPE_2FARG;
3635 }
3636 result = sim_cmp_string (gbuf, gbuf2);
3637 result = ((result == optr->aval) || (result == optr->bval));
3638 if (optr->invert)
3639 result = !result;
3640 }
3641 else {
3642 cptr = get_glyph (cptr, gbuf, 0);
3643 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3644 if (rptr) {
3645 if (*gptr == '[') {
3646 if (rptr->depth <= 1)
3647 return SCPE_ARG;
3648 idx = (uint32) strtotv (++gptr, &tptr, 10);
3649 if ((gptr == tptr) || (*tptr++ != ']'))
3650 return SCPE_ARG;
3651 gptr = tptr;
3652 }
3653 else idx = 0;
3654 if (idx >= rptr->depth)
3655 return SCPE_SUB;
3656 }
3657 else {
3658 if (sim_dfdev && sim_vm_parse_addr)
3659 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3660 else if (sim_dfdev)
3661 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3662 if (gbuf == gptr)
3663 return SCPE_NXREG;
3664 }
3665 if (*gptr != 0)
3666 (void)get_glyph (gptr, gbuf, 0);
3667 else {
3668 if (*cptr == 0)
3669 return SCPE_2FARG;
3670 cptr = get_glyph (cptr, gbuf, 0);
3671 }
3672 if (*cptr) {
3673 if (flag)
3674 return SCPE_2MARG;
3675 }
3676 else {
3677 if (!flag)
3678 return SCPE_2FARG;
3679 }
3680 if (rptr) {
3681 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3682 # pragma diagnostic push
3683 # pragma diag_suppress = integer_sign_change
3684 #endif
3685 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3686 (sim_stabr.boolop == -1))
3687 return SCPE_MISVAL;
3688 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3689 # pragma diagnostic pop
3690 #endif
3691 val = get_rval (rptr, idx);
3692 result = test_search (&val, &sim_stabr);
3693 }
3694 else {
3695 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3696 # pragma diagnostic push
3697 # pragma diag_suppress = integer_sign_change
3698 #endif
3699 if (sim_dfdev)
3700 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3701 (sim_staba.boolop == -1))
3702 return SCPE_MISVAL;
3703 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3704 # pragma diagnostic pop
3705 #endif
3706 if (sim_dfdev)
3707 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3708 if (reason != SCPE_OK)
3709 return reason;
3710 result = test_search (sim_eval, &sim_staba);
3711 }
3712 }
3713 if (Not ^ result) {
3714 if (!flag)
3715 sim_brk_setact (cptr);
3716 }
3717 else
3718 if (flag)
3719 return SCPE_AFAIL;
3720 return SCPE_OK;
3721 }
3722
3723
3724
3725 t_stat send_cmd (int32 flag, CONST char *cptr)
3726 {
3727 char gbuf[CBUFSIZE];
3728 CONST char *tptr;
3729 uint8 dbuf[CBUFSIZE];
3730 uint32 dsize = 0;
3731 uint32 delay = 0;
3732 uint32 after = 0;
3733 t_stat r;
3734 SEND *snd = NULL;
3735
3736 GET_SWITCHES (cptr);
3737 tptr = get_glyph (cptr, gbuf, ',');
3738 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3739 r = tmxr_locate_line_send (gbuf, &snd);
3740 if (r != SCPE_OK)
3741 return r;
3742 cptr = tptr;
3743 tptr = get_glyph (tptr, gbuf, ',');
3744 }
3745 else
3746 snd = sim_cons_get_send ();
3747
3748 while (*cptr) {
3749 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3750 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3751 if (r != SCPE_OK)
3752 return sim_messagef (SCPE_ARG, "Invalid Delay Value\n");
3753 cptr = tptr;
3754 tptr = get_glyph (cptr, gbuf, ',');
3755 continue;
3756 }
3757 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3758 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3759 if (r != SCPE_OK)
3760 return sim_messagef (SCPE_ARG, "Invalid After Value\n");
3761 cptr = tptr;
3762 tptr = get_glyph (cptr, gbuf, ',');
3763 continue;
3764 }
3765 if ((*cptr == '"') || (*cptr == '\''))
3766 break;
3767 return SCPE_ARG;
3768 }
3769 if (*cptr) {
3770 if ((*cptr != '"') && (*cptr != '\''))
3771 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
3772 cptr = get_glyph_quoted (cptr, gbuf, 0);
3773 if (*cptr != '\0')
3774 return SCPE_2MARG;
3775
3776 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3777 return sim_messagef (SCPE_ARG, "Invalid String\n");
3778 }
3779 if ((dsize == 0) && (delay == 0) && (after == 0))
3780 return SCPE_2FARG;
3781 return sim_send_input (snd, dbuf, dsize, after, delay);
3782 }
3783
3784 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3785 {
3786 char gbuf[CBUFSIZE];
3787 CONST char *tptr;
3788 t_stat r;
3789 SEND *snd = NULL;
3790
3791 tptr = get_glyph (cptr, gbuf, ',');
3792 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3793 r = tmxr_locate_line_send (gbuf, &snd);
3794 if (r != SCPE_OK)
3795 return r;
3796 cptr = tptr;
3797 }
3798 else
3799 snd = sim_cons_get_send ();
3800 if (*cptr)
3801 return SCPE_2MARG;
3802 return sim_show_send_input (st, snd);
3803 }
3804
3805 t_stat expect_cmd (int32 flag, CONST char *cptr)
3806 {
3807 char gbuf[CBUFSIZE];
3808 CONST char *tptr;
3809 EXPECT *exp = NULL;
3810
3811 GET_SWITCHES (cptr);
3812 tptr = get_glyph (cptr, gbuf, ',');
3813 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3814 cptr = tptr;
3815 } else {
3816 exp = sim_cons_get_expect ();
3817 }
3818
3819 if (flag) {
3820 return sim_set_expect (exp, cptr);
3821 } else {
3822 if (exp == NULL) {
3823 exp = sim_cons_get_expect();
3824 }
3825 return sim_set_noexpect (exp, cptr);
3826 }
3827 }
3828
3829 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3830 {
3831 char gbuf[CBUFSIZE];
3832 CONST char *tptr;
3833 EXPECT *exp = NULL;
3834 t_stat r;
3835
3836 tptr = get_glyph (cptr, gbuf, ',');
3837 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3838 r = tmxr_locate_line_expect (gbuf, &exp);
3839 if (r != SCPE_OK)
3840 return r;
3841 cptr = tptr;
3842 }
3843 else
3844 exp = sim_cons_get_expect ();
3845 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3846 return SCPE_ARG;
3847 tptr = get_glyph_quoted (cptr, gbuf, 0);
3848 if (*tptr != '\0')
3849 return SCPE_2MARG;
3850 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3851 return SCPE_ARG;
3852 return sim_exp_show (st, exp, gbuf);
3853 }
3854
3855
3856
3857 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3858 {
3859 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3860 const char *cptr;
3861 long fpos;
3862 int32 saved_do_echo = sim_do_echo;
3863 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3864
3865 if (NULL == sim_gotofile) return SCPE_UNK;
3866 (void)get_glyph (fcptr, gbuf1, 0);
3867 if ('\0' == gbuf1[0]) return SCPE_ARG;
3868 fpos = ftell(sim_gotofile);
3869 rewind(sim_gotofile);
3870 sim_goto_line[sim_do_depth] = 0;
3871 sim_do_echo = 0;
3872 while (1) {
3873 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
3874 if (cptr == NULL) break;
3875 sim_goto_line[sim_do_depth] += 1;
3876 if (*cptr == 0) continue;
3877 if (*cptr != ':') continue;
3878 ++cptr;
3879 while (sim_isspace (*cptr)) ++cptr;
3880 cptr = get_glyph (cptr, gbuf, 0);
3881 if (0 == strcmp(gbuf, gbuf1)) {
3882 sim_brk_clract ();
3883 sim_do_echo = saved_do_echo;
3884 if (sim_do_echo)
3885 sim_printf("%s> %s\n", do_position(), cbuf);
3886 return SCPE_OK;
3887 }
3888 }
3889 sim_do_echo = saved_do_echo;
3890 fseek(sim_gotofile, fpos, SEEK_SET);
3891 sim_goto_line[sim_do_depth] = saved_goto_line;
3892 return SCPE_ARG;
3893 }
3894
3895
3896
3897
3898
3899
3900
3901
3902 t_stat return_cmd (int32 flag, CONST char *fcptr)
3903 {
3904 return SCPE_UNK;
3905 }
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915 t_stat shift_cmd (int32 flag, CONST char *fcptr)
3916 {
3917 return SCPE_UNK;
3918 }
3919
3920
3921
3922
3923
3924
3925
3926
3927 t_stat call_cmd (int32 flag, CONST char *fcptr)
3928 {
3929 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
3930 const char *cptr;
3931
3932 if (NULL == sim_gotofile) return SCPE_UNK;
3933 cptr = get_glyph (fcptr, gbuf, 0);
3934 if ('\0' == gbuf[0]) return SCPE_ARG;
3935 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
3936 sim_switches |= SWMASK ('O');
3937 return do_cmd_label (flag, cbuf, gbuf);
3938 }
3939
3940
3941
3942 t_stat on_cmd (int32 flag, CONST char *cptr)
3943 {
3944 char gbuf[CBUFSIZE];
3945 t_stat cond;
3946
3947 cptr = get_glyph (cptr, gbuf, 0);
3948 if ('\0' == gbuf[0]) return SCPE_ARG;
3949 if (0 == strcmp("ERROR", gbuf))
3950 cond = 0;
3951 else
3952 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
3953 return SCPE_ARG;
3954 if ((NULL == cptr) || ('\0' == *cptr)) {
3955 FREE(sim_on_actions[sim_do_depth][cond]);
3956 sim_on_actions[sim_do_depth][cond] = NULL; }
3957 else {
3958 sim_on_actions[sim_do_depth][cond] =
3959 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
3960 if (!sim_on_actions[sim_do_depth][cond])
3961 {
3962 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3963 __func__, __FILE__, __LINE__);
3964 #if defined(USE_BACKTRACE)
3965 # if defined(SIGUSR2)
3966 (void)raise(SIGUSR2);
3967
3968 # endif
3969 #endif
3970 abort();
3971 }
3972 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
3973 }
3974 return SCPE_OK;
3975 }
3976
3977
3978
3979 t_stat noop_cmd (int32 flag, CONST char *cptr)
3980 {
3981 if (cptr && (*cptr != 0))
3982 return SCPE_2MARG;
3983 return SCPE_OK;
3984 }
3985
3986
3987
3988 t_stat set_on (int32 flag, CONST char *cptr)
3989 {
3990 if ((flag) && (cptr) && (*cptr)) {
3991 char gbuf[CBUFSIZE];
3992
3993 cptr = get_glyph (cptr, gbuf, 0);
3994 if (((MATCH_CMD(gbuf,"INHERIT")) &&
3995 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
3996 (*cptr))
3997 return SCPE_2MARG;
3998 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
3999 sim_on_inherit = 1;
4000 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
4001 sim_on_inherit = 0;
4002 return SCPE_OK;
4003 }
4004 if (cptr && (*cptr != 0))
4005 return SCPE_2MARG;
4006 sim_on_check[sim_do_depth] = flag;
4007 if ((sim_do_depth != 0) &&
4008 (NULL == sim_on_actions[sim_do_depth][0])) {
4009 sim_on_actions[sim_do_depth][0] =
4010 (char *)malloc(1+strlen("RETURN"));
4011 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4012 }
4013 if ((sim_do_depth != 0) &&
4014 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
4015 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
4016 (char *)malloc(1+strlen("RETURN"));
4017 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4018 }
4019 return SCPE_OK;
4020 }
4021
4022
4023
4024 t_stat set_verify (int32 flag, CONST char *cptr)
4025 {
4026 if (cptr && (*cptr != 0))
4027 return SCPE_2MARG;
4028 if (flag == sim_do_echo)
4029 return SCPE_OK;
4030 sim_do_echo = flag;
4031 return SCPE_OK;
4032 }
4033
4034
4035
4036 t_stat set_message (int32 flag, CONST char *cptr)
4037 {
4038 if (cptr && (*cptr != 0))
4039 return SCPE_2MARG;
4040 if (flag == sim_show_message)
4041 return SCPE_OK;
4042 sim_show_message = flag;
4043 return SCPE_OK;
4044 }
4045
4046
4047
4048 t_stat set_localopc (int32 flag, CONST char *cptr)
4049 {
4050 if (cptr && (*cptr != 0))
4051 return SCPE_2MARG;
4052 if (flag == sim_localopc)
4053 return SCPE_OK;
4054 sim_localopc = flag;
4055 return SCPE_OK;
4056 }
4057
4058
4059 t_stat set_quiet (int32 flag, CONST char *cptr)
4060 {
4061 if (cptr && (*cptr != 0))
4062 return SCPE_2MARG;
4063 if (flag == sim_quiet)
4064 return SCPE_OK;
4065 sim_quiet = flag;
4066 return SCPE_OK;
4067 }
4068
4069
4070
4071 t_stat sim_set_environment (int32 flag, CONST char *cptr)
4072 {
4073 char varname[CBUFSIZE];
4074
4075 if ((NULL == cptr) || (*cptr == 0))
4076 return SCPE_2FARG;
4077 cptr = get_glyph (cptr, varname, '=');
4078 setenv(varname, cptr, 1);
4079 return SCPE_OK;
4080 }
4081
4082
4083
4084 t_stat set_cmd (int32 flag, CONST char *cptr)
4085 {
4086 uint32 lvl = 0;
4087 t_stat r;
4088 char gbuf[CBUFSIZE], *cvptr;
4089 CONST char *svptr;
4090 DEVICE *dptr;
4091 UNIT *uptr;
4092 MTAB *mptr;
4093 CTAB *gcmdp;
4094 C1TAB *ctbr = NULL, *glbr;
4095
4096 GET_SWITCHES (cptr);
4097 if ((NULL == cptr) || (*cptr == 0))
4098 return SCPE_2FARG;
4099 cptr = get_glyph (svptr = cptr, gbuf, 0);
4100
4101 if ((dptr = find_dev (gbuf))) {
4102 uptr = dptr->units;
4103 ctbr = set_dev_tab;
4104 lvl = MTAB_VDV;
4105 GET_SWITCHES (cptr);
4106 }
4107 else if ((dptr = find_unit (gbuf, &uptr))) {
4108 if (uptr == NULL)
4109 return SCPE_NXUN;
4110 ctbr = set_unit_tab;
4111 lvl = MTAB_VUN;
4112 GET_SWITCHES (cptr);
4113 }
4114 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
4115 GET_SWITCHES (cptr);
4116 return gcmdp->action (gcmdp->arg, cptr);
4117 }
4118 else {
4119 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4120 if ((cvptr = strchr (gbuf, '=')))
4121 *cvptr++ = 0;
4122 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4123 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4124 dptr = sim_dflt_dev;
4125 cptr = svptr;
4126 while (sim_isspace(*cptr))
4127 ++cptr;
4128 break;
4129 }
4130 }
4131 }
4132 if (!dptr)
4133 return SCPE_NXDEV;
4134 lvl = MTAB_VDV;
4135 uptr = dptr->units;
4136 }
4137 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4138 return SCPE_2FARG;
4139 GET_SWITCHES (cptr);
4140
4141 while (*cptr != 0) {
4142 cptr = get_glyph (svptr = cptr, gbuf, ',');
4143 if (0 == strcmp (gbuf, ";"))
4144 break;
4145 if ((cvptr = strchr (gbuf, '=')))
4146 *cvptr++ = 0;
4147 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4148 if ((mptr->mstring) &&
4149 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4150 if (mptr->mask & MTAB_XTD) {
4151 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4152 return SCPE_ARG;
4153 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4154 return SCPE_UDIS;
4155 if (mptr->valid) {
4156 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4157 svptr = get_glyph_quoted (svptr, gbuf, ',');
4158 if ((cvptr = strchr (gbuf, '='))) {
4159 *cvptr++ = 0;
4160 cptr = svptr;
4161 }
4162 }
4163 else {
4164 if (cvptr && MODMASK(mptr,MTAB_NC)) {
4165 (void)get_glyph_nc (svptr, gbuf, ',');
4166 if ((cvptr = strchr (gbuf, '=')))
4167 *cvptr++ = 0;
4168 }
4169 }
4170 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4171 if (r != SCPE_OK)
4172 return r;
4173 }
4174 else if (!mptr->desc)
4175 break;
4176 else if (cvptr)
4177 return SCPE_ARG;
4178 else *((int32 *) mptr->desc) = mptr->match;
4179 }
4180 else {
4181 if (cvptr)
4182 return SCPE_ARG;
4183 if (uptr->flags & UNIT_DIS)
4184 return SCPE_UDIS;
4185 if ((mptr->valid) &&
4186 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4187 return r;
4188 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4189 (mptr->match & mptr->mask);
4190 }
4191 break;
4192 }
4193 }
4194 if (!mptr || (mptr->mask == 0)) {
4195 if ((glbr = find_c1tab (ctbr, gbuf))) {
4196 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
4197 if (r != SCPE_OK)
4198 return r;
4199 }
4200 else if (!dptr->modifiers)
4201 return SCPE_NOPARAM;
4202 else return SCPE_NXPAR;
4203 }
4204 }
4205 return SCPE_OK;
4206 }
4207
4208
4209
4210 CTAB *find_ctab (CTAB *tab, const char *gbuf)
4211 {
4212 if (!tab)
4213 return NULL;
4214 for (; tab->name != NULL; tab++) {
4215 if (MATCH_CMD (gbuf, tab->name) == 0)
4216 return tab;
4217 }
4218 return NULL;
4219 }
4220
4221 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
4222 {
4223 if (!tab)
4224 return NULL;
4225 for (; tab->name != NULL; tab++) {
4226 if (MATCH_CMD (gbuf, tab->name) == 0)
4227 return tab;
4228 }
4229 return NULL;
4230 }
4231
4232
4233
4234 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4235 {
4236 if (cptr)
4237 return SCPE_ARG;
4238 dptr->dradix = flag & 037;
4239 return SCPE_OK;
4240 }
4241
4242
4243
4244 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4245 {
4246 UNIT *up;
4247 uint32 i;
4248
4249 if (cptr)
4250 return SCPE_ARG;
4251 if ((dptr->flags & DEV_DISABLE) == 0)
4252 return SCPE_NOFNC;
4253 if (flag) {
4254 if ((dptr->flags & DEV_DIS) == 0)
4255 return SCPE_OK;
4256 dptr->flags = dptr->flags & ~DEV_DIS;
4257 }
4258 else {
4259 if (dptr->flags & DEV_DIS)
4260 return SCPE_OK;
4261 for (i = 0; i < dptr->numunits; i++) {
4262 up = (dptr->units) + i;
4263 if ((up->flags & UNIT_ATT) || sim_is_active (up))
4264 return SCPE_NOFNC;
4265 }
4266 dptr->flags = dptr->flags | DEV_DIS;
4267 }
4268 if (dptr->reset)
4269 return dptr->reset (dptr);
4270 else return SCPE_OK;
4271 }
4272
4273
4274
4275 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4276 {
4277 if (cptr)
4278 return SCPE_ARG;
4279 if (!(uptr->flags & UNIT_DISABLE))
4280 return SCPE_NOFNC;
4281 if (flag)
4282 uptr->flags = uptr->flags & ~UNIT_DIS;
4283 else {
4284 if ((uptr->flags & UNIT_ATT) ||
4285 sim_is_active (uptr))
4286 return SCPE_NOFNC;
4287 uptr->flags = uptr->flags | UNIT_DIS;
4288 }
4289 return SCPE_OK;
4290 }
4291
4292
4293
4294 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4295 {
4296 char gbuf[CBUFSIZE];
4297 DEBTAB *dep;
4298
4299 if ((dptr->flags & DEV_DEBUG) == 0)
4300 return SCPE_NOFNC;
4301 if (cptr == NULL) {
4302 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4303 if (flag && dptr->debflags) {
4304 for (dep = dptr->debflags; dep->name != NULL; dep++)
4305 dptr->dctrl = dptr->dctrl | dep->mask;
4306 }
4307 return SCPE_OK;
4308 }
4309 if (dptr->debflags == NULL)
4310 return SCPE_ARG;
4311 while (*cptr) {
4312 cptr = get_glyph (cptr, gbuf, ';');
4313 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4314 if (strcmp (dep->name, gbuf) == 0) {
4315 if (flag)
4316 dptr->dctrl = dptr->dctrl | dep->mask;
4317 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4318 break;
4319 }
4320 }
4321 if (dep->mask == 0)
4322 return SCPE_ARG;
4323 }
4324 return SCPE_OK;
4325 }
4326
4327
4328
4329 t_stat show_cmd (int32 flag, CONST char *cptr)
4330 {
4331 t_stat r = SCPE_IERR;
4332
4333 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4334
4335 if (NULL == cptr)
4336 return r;
4337 if (sim_ofile) {
4338 r = show_cmd_fi (sim_ofile, flag, cptr);
4339 fclose (sim_ofile);
4340 }
4341 else {
4342 r = show_cmd_fi (stdout, flag, cptr);
4343 if (sim_log && (sim_log != stdout))
4344 show_cmd_fi (sim_log, flag, cptr);
4345 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4346 show_cmd_fi (sim_deb, flag, cptr);
4347 }
4348 return r;
4349 }
4350
4351 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4352 {
4353 uint32 lvl = 0xFFFFFFFF;
4354 char gbuf[CBUFSIZE], *cvptr;
4355 CONST char *svptr;
4356 DEVICE *dptr;
4357 UNIT *uptr;
4358 MTAB *mptr;
4359 SHTAB *shtb = NULL, *shptr;
4360
4361 GET_SWITCHES (cptr);
4362 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4363 return SCPE_2FARG;
4364 cptr = get_glyph (svptr = cptr, gbuf, 0);
4365
4366 if ((dptr = find_dev (gbuf))) {
4367 uptr = dptr->units;
4368 shtb = show_dev_tab;
4369 lvl = MTAB_VDV;
4370 GET_SWITCHES (cptr);
4371 }
4372 else if ((dptr = find_unit (gbuf, &uptr))) {
4373 if (uptr == NULL)
4374 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\n", gbuf);
4375 if (uptr->flags & UNIT_DIS)
4376 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", gbuf);
4377 shtb = show_unit_tab;
4378 lvl = MTAB_VUN;
4379 GET_SWITCHES (cptr);
4380 }
4381 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4382 GET_SWITCHES (cptr);
4383 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4384 }
4385 else {
4386 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4387 if ((cvptr = strchr (gbuf, '=')))
4388 *cvptr++ = 0;
4389 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4390 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4391 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4392 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4393 dptr = sim_dflt_dev;
4394 lvl = MTAB_VDV;
4395 cptr = svptr;
4396 while (sim_isspace(*cptr))
4397 ++cptr;
4398 break;
4399 }
4400 }
4401 }
4402 if (!dptr) {
4403 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4404 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4405 else
4406 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf);
4407 }
4408 }
4409
4410 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4411 return (lvl == MTAB_VDV)?
4412 show_device (ofile, dptr, 0):
4413 show_unit (ofile, dptr, uptr, -1);
4414 }
4415 GET_SWITCHES (cptr);
4416
4417 while (*cptr != 0) {
4418 cptr = get_glyph (cptr, gbuf, ',');
4419 if ((cvptr = strchr (gbuf, '=')))
4420 *cvptr++ = 0;
4421 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4422 if (((mptr->mask & MTAB_XTD)?
4423 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4424 ((mptr->disp && mptr->pstring &&
4425 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4426 )) {
4427 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4428 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\n", gbuf, cvptr);
4429 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4430 break;
4431 }
4432 }
4433 if (!mptr || (mptr->mask == 0)) {
4434 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4435 t_stat r;
4436
4437 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4438 if (r != SCPE_OK)
4439 return r;
4440 }
4441 else {
4442 if (!dptr->modifiers)
4443 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\n", dptr->name);
4444 else
4445 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\n", gbuf);
4446 }
4447 }
4448 }
4449 return SCPE_OK;
4450 }
4451
4452 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4453 {
4454 if (!tab)
4455 return NULL;
4456 for (; tab->name != NULL; tab++) {
4457 if (MATCH_CMD (gbuf, tab->name) == 0)
4458 return tab;
4459 }
4460 return NULL;
4461 }
4462
4463
4464
4465 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4466 {
4467 uint32 j, udbl, ucnt;
4468 UNIT *uptr;
4469 int32 toks = 0;
4470
4471 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4472 (void)fprintf (st, "%s", sim_dname (dptr));
4473 if ((flag == 2) && dptr->description) {
4474 (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4475 }
4476 else {
4477 if ((sim_switches & SWMASK ('D')) && dptr->description)
4478 (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4479 }
4480 if (qdisable (dptr)) {
4481 (void)fprintf (st, "\tdisabled\n");
4482 return SCPE_OK;
4483 }
4484 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4485 uptr = dptr->units + j;
4486 if (!(uptr->flags & UNIT_DIS))
4487 ucnt++;
4488 else if (uptr->flags & UNIT_DISABLE)
4489 udbl++;
4490 }
4491
4492 if (dptr->numunits == 0) {
4493
4494
4495 }
4496 else
4497 {
4498 if (ucnt == 0) {
4499 fprint_sep (st, &toks);
4500 (void)fprintf (st, "all units disabled\n");
4501 }
4502 else if ((ucnt + udbl) == 1) {
4503 fprint_sep (st, &toks);
4504 (void)fprintf (st, " 1 unit\n");
4505 }
4506 else if ((ucnt > 1) || (udbl > 0)) {
4507 fprint_sep (st, &toks);
4508 (void)fprintf (st, "%2.d units\n", ucnt + udbl);
4509 }
4510 else
4511 if ((flag != 2) || !dptr->description || toks)
4512 (void)fprintf (st, "\n");
4513 toks = 0;
4514 }
4515 if (flag)
4516 return SCPE_OK;
4517 for (j = 0; j < dptr->numunits; j++) {
4518 uptr = dptr->units + j;
4519 if ((uptr->flags & UNIT_DIS) == 0)
4520 show_unit (st, dptr, uptr, ucnt + udbl);
4521 }
4522 }
4523 return SCPE_OK;
4524 }
4525
4526 void fprint_sep (FILE *st, int32 *tokens)
4527 {
4528 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4529 *tokens += 1;
4530 }
4531
4532 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4533 {
4534 int32 u = (int32)(uptr - dptr->units);
4535 int32 toks = 0;
4536
4537 if (flag > 1)
4538 (void)fprintf (st, " %s%d \n", sim_dname (dptr), u);
4539 else if (flag < 0)
4540 (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4541 if (uptr->flags & UNIT_ATT) {
4542 fprint_sep (st, &toks);
4543 (void)fprintf (st, "status : attached to %s", uptr->filename);
4544 if (uptr->flags & UNIT_RO)
4545 (void)fprintf (st, ", read only");
4546 }
4547 else {
4548 if (uptr->flags & UNIT_ATTABLE) {
4549 fprint_sep (st, &toks);
4550 (void)fprintf (st, "status : not attached");
4551 }
4552 }
4553 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4554 fprint_sep (st, &toks);
4555 fprint_capac (st, dptr, uptr);
4556 }
4557 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4558 if (toks || (flag < 0) || (flag > 1))
4559 (void)fprintf (st, "\n");
4560 return SCPE_OK;
4561 }
4562
4563 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4564 {
4565 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4566 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4567 t_offset mval;
4568 t_offset psize = (t_offset)uptr->capac;
4569 char *scale, *width;
4570
4571 if (sim_switches & SWMASK ('B'))
4572 kval = 1024;
4573 mval = kval * kval;
4574 if (dptr->flags & DEV_SECTORS) {
4575 kval = kval / 512;
4576 mval = mval / 512;
4577 }
4578 if ((dptr->dwidth / dptr->aincr) > 8)
4579 width = "W";
4580 else
4581 width = "B";
4582 if ((psize < (kval * 10)) &&
4583 (0 != (psize % kval))) {
4584 scale = "";
4585 }
4586 else if ((psize < (mval * 10)) &&
4587 (0 != (psize % mval))){
4588 scale = "K";
4589 psize = psize / kval;
4590 }
4591 else {
4592 scale = "M";
4593 psize = psize / mval;
4594 }
4595 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4596 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4597 return capac_buf;
4598 }
4599
4600 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4601 {
4602 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4603 }
4604
4605
4606
4607 extern void print_default_base_system_script (void);
4608 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4609 {
4610 #if !defined(PERF_STRIP)
4611 print_default_base_system_script();
4612 #endif
4613 return 0;
4614 }
4615
4616 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4617 sim_printf (" %s ", label);
4618 sim_printf (" %2d %3o(8) '", length, offset);
4619 for (int l = 0; l < length; l ++)
4620 {
4621 unsigned int byte = PROM[offset + l];
4622 if (byte == 255)
4623 {
4624 byte = ' ';
4625 }
4626 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4627 }
4628 sim_printf ("'\r\n");
4629 }
4630
4631 static void strip_spaces(char* str) {
4632 int i, x;
4633 for (i=x=0; str[i]; ++i)
4634 {
4635 if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)])))
4636 {
4637 str[x++] = str[i];
4638 }
4639 }
4640 str[x] = '\0';
4641 i = -1;
4642 x = 0;
4643 while (str[x] != '\0')
4644 {
4645 if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4646 {
4647 i=x;
4648 }
4649 x++;
4650 }
4651 str[i+1] = '\0';
4652 }
4653
4654 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
4655 char sx[1024];
4656 sx[1023] = '\0';
4657 unsigned int lastbyte = 0;
4658 for (int l = 0; l < length; l ++)
4659 {
4660 unsigned int byte = PROM[offset + l];
4661 if (byte == 255)
4662 {
4663 byte = 20;
4664 }
4665 if ((lastbyte != 20) && (byte != 20))
4666 {
4667 (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4668 }
4669 lastbyte = byte;
4670 }
4671 strip_spaces(sx);
4672 (void)fprintf (st, "%s", sx);
4673 }
4674
4675 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4676 {
4677 unsigned char PROM[1024];
4678 setupPROM (0, PROM);
4679
4680 sim_printf (" PROM size: %llu bytes\r\n",
4681 (long long unsigned)sizeof(PROM));
4682 sim_printf (" PROM initialization data:\r\n\r\n");
4683
4684 sim_printf (" Field Description Length Offset Contents\r\n");
4685 sim_printf (" ========================= ======== ======== ==================================\r\n");
4686 sim_printf ("\r\n");
4687
4688
4689
4690 printp (PROM, "CPU Model ", 0, 11);
4691 printp (PROM, "CPU Serial ", 11, 11);
4692 printp (PROM, "Ship Date ", 22, 6);
4693 printp (PROM, "PROM Layout Version ", 60, 1);
4694 printp (PROM, "Release Git Commit Date ", 70, 10);
4695 printp (PROM, "Release Major ", 80, 3);
4696 printp (PROM, "Release Minor ", 83, 3);
4697 printp (PROM, "Release Patch ", 86, 3);
4698 printp (PROM, "Release Iteration ", 89, 3);
4699 printp (PROM, "Release Build Number ", 92, 8);
4700 printp (PROM, "Release Type ", 100, 1);
4701 printp (PROM, "Release Version Text ", 101, 29);
4702 printp (PROM, "Build Architecture ", 130, 20);
4703 printp (PROM, "Build Operating System ", 150, 20);
4704 printp (PROM, "Target Architecture ", 170, 20);
4705 printp (PROM, "Target Operating System ", 190, 20);
4706
4707 sim_printf("\r\n");
4708 return 0;
4709 }
4710
4711 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4712 {
4713 (void)fprintf (st, "\r Build Information:\n");
4714 #if defined(BUILDINFO_scp)
4715 (void)fprintf (st, "\r\n Compilation info: %s\n", BUILDINFO_scp );
4716 #else
4717 (void)fprintf (st, "\r\n Compilation info: Not available\n" );
4718 #endif
4719 #if !defined(__CYGWIN__)
4720 # if !defined(__APPLE__)
4721 # if !defined(_AIX)
4722 # if !defined(__MINGW32__)
4723 # if !defined(__MINGW64__)
4724 # if !defined(CROSS_MINGW32)
4725 # if !defined(CROSS_MINGW64)
4726 # if !defined(_WIN32)
4727 # if !defined(__HAIKU__)
4728 (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4729 if (dl_iterate_phdr_callback_called)
4730 (void)fprintf (st, "\n");
4731 dl_iterate_phdr_callback_called = 0;
4732 # endif
4733 # endif
4734 # endif
4735 # endif
4736 # endif
4737 # endif
4738 # endif
4739 # endif
4740 #endif
4741 #if defined(UV_VERSION_MAJOR) && \
4742 defined(UV_VERSION_MINOR) && \
4743 defined(UV_VERSION_PATCH)
4744 # if defined(UV_VERSION_MAJOR)
4745 # if !defined(UV_VERSION_MINOR) && \
4746 !defined(UV_VERSION_PATCH) && \
4747 !defined(UV_VERSION_SUFFIX)
4748 (void)fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4749 # endif
4750 # if defined(UV_VERSION_MINOR)
4751 # if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4752 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4753 UV_VERSION_MINOR);
4754 # endif
4755 # if defined(UV_VERSION_PATCH)
4756 # if !defined(UV_VERSION_SUFFIX)
4757 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4758 UV_VERSION_MINOR, UV_VERSION_PATCH);
4759 # endif
4760 # if defined(UV_VERSION_SUFFIX)
4761 (void)fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4762 UV_VERSION_MINOR, UV_VERSION_PATCH);
4763 # if defined(UV_VERSION_IS_RELEASE)
4764 # if UV_VERSION_IS_RELEASE == 1
4765 # define UV_RELEASE_TYPE " (release)"
4766 # endif
4767 # if UV_VERSION_IS_RELEASE == 0
4768 # define UV_RELEASE_TYPE "-dev"
4769 # endif
4770 # if !defined(UV_RELEASE_TYPE)
4771 # define UV_RELEASE_TYPE ""
4772 # endif
4773 # if defined(UV_RELEASE_TYPE)
4774 (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4775 # endif
4776 # endif
4777 # endif
4778 # endif
4779 # endif
4780 unsigned int CurrentUvVersion = uv_version();
4781 if (CurrentUvVersion > 0)
4782 if (uv_version_string() != NULL)
4783 (void)fprintf (st, "; %s in use", uv_version_string());
4784 # endif
4785 #else
4786 (void)fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4787 #endif
4788
4789
4790
4791 (void)fprintf (st, "\r\n Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4792 SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4793 SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4794 sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4795 #if defined(DECNUMBERLOC)
4796 # if defined(DECVERSION)
4797 # if defined(DECVERSEXT)
4798 (void)fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4799 # else
4800 # if defined(DECNLAUTHOR)
4801 (void)fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4802 # else
4803 (void)fprintf (st, "\r\n Math library: %s", DECVERSION);
4804 # endif
4805 # endif
4806 # else
4807 (void)fprintf (st, "\r\n Math library: decNumber, unknown version");
4808 # endif
4809 #endif
4810 #if defined(LOCKLESS)
4811 (void)fprintf (st, "\r\n Atomic operations: ");
4812 # if defined(AIX_ATOMICS)
4813 (void)fprintf (st, "C11 and IBM AIX-style");
4814 # elif defined(BSD_ATOMICS)
4815 (void)fprintf (st, "C11 and FreeBSD-style");
4816 # elif defined(GNU_ATOMICS)
4817 (void)fprintf (st, "C11 and GNU-style");
4818 # elif defined(SYNC_ATOMICS)
4819 (void)fprintf (st, "C11 and GNU sync-style");
4820 # elif defined(ISO_ATOMICS)
4821 (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4822 # elif defined(NT_ATOMICS)
4823 (void)fprintf (st, "C11 and Windows NT interlocked operations");
4824 # endif
4825 #endif
4826 (void)fprintf (st, "\r\n File locking: ");
4827 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4828 (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4829 #endif
4830 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4831 (void)fprintf (st, "POSIX-style fcntl() locking");
4832 #endif
4833 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4834 (void)fprintf (st, "BSD-style flock() locking");
4835 #endif
4836 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4837 (void)fprintf (st, "No file locking available");
4838 #endif
4839 (void)fprintf (st, "\r\n Windows support: ");
4840 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4841 # if defined(__MINGW64_VERSION_STR)
4842 (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4843 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4844 (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4845 # else
4846 (void)fprintf (st, "Built with MinGW");
4847 # endif
4848
4849 # if defined(MINGW_CRT)
4850 (void)fprintf (st, "; %s", MINGW_CRT);
4851 # if !defined(_UCRT)
4852 # if defined(__MSVCRT_VERSION__)
4853 # if __MSVCRT_VERSION__ > 0x00
4854 (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4855 # endif
4856 # endif
4857 # else
4858
4859 struct UCRTVersion ucrtversion;
4860 int result = GetUCRTVersion (&ucrtversion);
4861
4862 if (result == 0)
4863 (void)fprintf (st, " %u.%u.%u.%u",
4864 ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4865 ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4866 # endif
4867 (void)fprintf (st, " in use");
4868 # endif
4869 #elif defined(__CYGWIN__)
4870 struct utsname utsname;
4871 (void)fprintf (st, "Built with Cygwin %d.%d.%d",
4872 CYGWIN_VERSION_DLL_MAJOR / 1000,
4873 CYGWIN_VERSION_DLL_MAJOR % 1000,
4874 CYGWIN_VERSION_DLL_MINOR);
4875 if (uname(&utsname) == 0)
4876 fprintf (st, "; %s in use", utsname.release);
4877 #else
4878 (void)fprintf (st, "Disabled");
4879 #endif
4880
4881 (void)fprintf (st, "\r\n");
4882 return 0;
4883 }
4884
4885 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4886 {
4887 const char *arch = "";
4888 char *whydirty = " ";
4889 int dirty = 0;
4890
4891 if (cptr && (*cptr != 0))
4892 return SCPE_2MARG;
4893 if (flag) {
4894 (void)fprintf (st, " %s Simulator:", sim_name);
4895 #if defined(USE_DUMA)
4896 # undef NO_SUPPORT_VERSION
4897 # define NO_SUPPORT_VERSION 1
4898 nodist++;
4899 #endif
4900 #if defined(NO_SUPPORT_VERSION) || \
4901 defined(WITH_SOCKET_DEV) || \
4902 defined(WITH_ABSI_DEV) || \
4903 defined(WITH_MGP_DEV) || \
4904 defined(TESTING) || \
4905 defined(ISOLTS) || \
4906 defined(USE_DUMA)
4907 # if !defined(NO_SUPPORT_VERSION)
4908 # define NO_SUPPORT_VERSION 1
4909 # endif
4910 #endif
4911 #if defined(NO_SUPPORT_VERSION)
4912 dirty++;
4913 #endif
4914 #if defined(GENERATED_MAKE_VER_H)
4915 # if defined(VER_H_GIT_VERSION)
4916
4917
4918 if (strstr(VER_H_GIT_VERSION, "*"))
4919 {
4920 dirty++;
4921 }
4922
4923
4924 if ((strstr(VER_H_GIT_VERSION, "X")) || \
4925 (strstr(VER_H_GIT_VERSION, "D")) || \
4926 (strstr(VER_H_GIT_VERSION, "A")) || \
4927 (strstr(VER_H_GIT_VERSION, "B")))
4928 {
4929 dirty++;
4930 }
4931
4932
4933 if (dirty)
4934 {
4935 if ((strstr(VER_H_GIT_VERSION, "X")))
4936 {
4937 whydirty = " ";
4938 }
4939 else if ((strstr(VER_H_GIT_VERSION, "D")))
4940 {
4941 whydirty = " DEV ";
4942 }
4943 else if ((strstr(VER_H_GIT_VERSION, "A")))
4944 {
4945 whydirty = " ALPHA ";
4946 }
4947 else if ((strstr(VER_H_GIT_VERSION, "B")))
4948 {
4949 whydirty = " BETA ";
4950 }
4951 }
4952
4953 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
4954 # if defined(VER_H_GIT_HASH)
4955 # if VER_H_GIT_PATCH_INT < 1
4956 (void)fprintf (st, "\n Version: %s (%ld-bit)\n Commit: %s",
4957 VER_H_GIT_VERSION,
4958 (long)(CHAR_BIT*sizeof(void *)),
4959 VER_H_GIT_HASH);
4960 # else
4961 # define NO_SUPPORT_VERSION 1
4962 (void)fprintf (st, "\n Version: %s+%s (%ld-bit)\n Commit: %s",
4963 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
4964 (long)(CHAR_BIT*sizeof(void *)),
4965 VER_H_GIT_HASH);
4966 # endif
4967 # else
4968 # if VER_H_GIT_PATCH_INT < 1
4969 (void)fprintf (st, "\n Version: %s (%ld-bit)",
4970 VER_H_GIT_VERSION,
4971 (long)(CHAR_BIT*sizeof(void *)));
4972 # else
4973 # define NO_SUPPORT_VERSION 1
4974 (void)fprintf (st, "\n Version: %s+%s (%ld-bit)",
4975 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
4976 (long)(CHAR_BIT*sizeof(void *)));
4977 # endif
4978 # endif
4979 # else
4980 # if defined(VER_H_GIT_HASH)
4981 (void)fprintf (st, "\n Version: %s (%ld-bit)\n Commit: %s",
4982 VER_H_GIT_VERSION,
4983 (long)(CHAR_BIT*sizeof(void *)),
4984 VER_H_GIT_HASH);
4985 # else
4986 (void)fprintf (st, "\n Version: %s (%ld-bit)",
4987 VER_H_GIT_VERSION,
4988 (long)(CHAR_BIT*sizeof(void *)));
4989 # endif
4990 # endif
4991 # endif
4992 #endif
4993
4994
4995 #if defined(TESTING)
4996 (void)fprintf (st, "\n Options: ");
4997 # if !defined(HAVE_DPSOPT)
4998 # define HAVE_DPSOPT 1
4999 # endif
5000 (void)fprintf (st, "TESTING");
5001 #endif
5002
5003
5004 #if defined(ISOLTS)
5005 # if defined(HAVE_DPSOPT)
5006 (void)fprintf (st, ", ");
5007 # else
5008 (void)fprintf (st, "\n Options: ");
5009 # endif
5010 # if !defined(HAVE_DPSOPT)
5011 # define HAVE_DPSOPT 1
5012 # endif
5013 (void)fprintf (st, "ISOLTS");
5014 #endif
5015
5016
5017 #if defined(NO_UCACHE)
5018 # if defined(HAVE_DPSOPT)
5019 (void)fprintf (st, ", ");
5020 # else
5021 (void)fprintf (st, "\n Options: ");
5022 # endif
5023 # if !defined(HAVE_DPSOPT)
5024 # define HAVE_DPSOPT 1
5025 # endif
5026 (void)fprintf (st, "NO_UCACHE");
5027 #endif
5028
5029
5030 #if defined(NEED_128)
5031 # if defined(HAVE_DPSOPT)
5032 (void)fprintf (st, ", ");
5033 # else
5034 (void)fprintf (st, "\n Options: ");
5035 # endif
5036 # if !defined(HAVE_DPSOPT)
5037 # define HAVE_DPSOPT 1
5038 # endif
5039 (void)fprintf (st, "NEED_128");
5040 #endif
5041
5042
5043 #if defined(WAM)
5044 # if defined(HAVE_DPSOPT)
5045 (void)fprintf (st, ", ");
5046 # else
5047 (void)fprintf (st, "\n Options: ");
5048 # endif
5049 # if !defined(HAVE_DPSOPT)
5050 # define HAVE_DPSOPT 1
5051 # endif
5052 (void)fprintf (st, "WAM");
5053 #endif
5054
5055
5056 #if defined(ROUND_ROBIN)
5057 # if defined(HAVE_DPSOPT)
5058 (void)fprintf (st, ", ");
5059 # else
5060 (void)fprintf (st, "\n Options: ");
5061 # endif
5062 # if !defined(HAVE_DPSOPT)
5063 # define HAVE_DPSOPT 1
5064 # endif
5065 (void)fprintf (st, "ROUND_ROBIN");
5066 #endif
5067
5068
5069 #if !defined(LOCKLESS)
5070 # if defined(HAVE_DPSOPT)
5071 (void)fprintf (st, ", ");
5072 # else
5073 (void)fprintf (st, "\n Options: ");
5074 # endif
5075 # if !defined(HAVE_DPSOPT)
5076 # define HAVE_DPSOPT 1
5077 # endif
5078 (void)fprintf (st, "NO_LOCKLESS");
5079 #endif
5080
5081
5082 #if defined(WITH_ABSI_DEV)
5083 # if defined(HAVE_DPSOPT)
5084 (void)fprintf (st, ", ");
5085 # else
5086 (void)fprintf (st, "\n Options: ");
5087 # endif
5088 # if !defined(HAVE_DPSOPT)
5089 # define HAVE_DPSOPT 1
5090 # endif
5091 (void)fprintf (st, "ABSI");
5092 #endif
5093
5094
5095 #if defined(WITH_SOCKET_DEV)
5096 # if defined(HAVE_DPSOPT)
5097 (void)fprintf (st, ", ");
5098 # else
5099 (void)fprintf (st, "\n Options: ");
5100 # endif
5101 # if !defined(HAVE_DPSOPT)
5102 # define HAVE_DPSOPT 1
5103 # endif
5104 (void)fprintf (st, "SOCKET");
5105 #endif
5106
5107
5108 #if defined(WITH_MGP_DEV)
5109 # if defined(HAVE_DPSOPT)
5110 (void)fprintf (st, ", ");
5111 # else
5112 (void)fprintf (st, "\n Options: ");
5113 # endif
5114 # if !defined(HAVE_DPSOPT)
5115 # define HAVE_DPSOPT 1
5116 # endif
5117 (void)fprintf (st, "CHAOSNET");
5118 # if USE_SOCKET_DEV_APPROACH
5119 (void)fprintf (st, "-S");
5120 # endif
5121 #endif
5122
5123
5124 #if defined(USE_DUMA)
5125 # if defined(HAVE_DPSOPT)
5126 (void)fprintf (st, ", ");
5127 # else
5128 (void)fprintf (st, "\n Options: ");
5129 # endif
5130 # if !defined(HAVE_DPSOPT)
5131 # define HAVE_DPSOPT 1
5132 # endif
5133 (void)fprintf (st, "DUMA");
5134 #endif
5135
5136 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5137 # if defined(NO_SUPPORT_VERSION)
5138 (void)fprintf (st, "\n Modified: %s", VER_H_GIT_DATE);
5139 # else
5140 (void)fprintf (st, "\n Released: %s", VER_H_GIT_DATE);
5141 # endif
5142 #endif
5143 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5144 (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5145 #endif
5146 #if defined(VER_CURRENT_TIME)
5147 (void)fprintf (st, "\n Compiled: %s", VER_CURRENT_TIME);
5148 #endif
5149 if (dirty)
5150 {
5151 (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5152 }
5153 (void)fprintf (st, "\r\n\r\n Build Information:");
5154 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5155 char build_os_version_raw[255];
5156 char build_os_arch_raw[255];
5157 (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5158 (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5159 char *build_os_version = strdup(build_os_version_raw);
5160 if (!build_os_version)
5161 {
5162 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5163 __func__, __FILE__, __LINE__);
5164 # if defined(USE_BACKTRACE)
5165 # if defined(SIGUSR2)
5166 (void)raise(SIGUSR2);
5167
5168 # endif
5169 # endif
5170 abort();
5171 }
5172 char *build_os_arch = strdup(build_os_arch_raw);
5173 if (!build_os_arch)
5174 {
5175 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5176 __func__, __FILE__, __LINE__);
5177 # if defined(USE_BACKTRACE)
5178 # if defined(SIGUSR2)
5179 (void)raise(SIGUSR2);
5180
5181 # endif
5182 # endif
5183 abort();
5184 }
5185 unsigned char SPROM[1024];
5186 setupPROM (0, SPROM);
5187 (void)fprintf (st, "\n Target: ");
5188 printpq (SPROM, st, 190, 20);
5189 if (SPROM[170] != 20)
5190 {
5191 if (SPROM[170] != 255)
5192 {
5193 (void)fprintf (st, " on ");
5194 printpq (SPROM, st, 170, 20);
5195 }
5196 }
5197 strtrimspace(build_os_version, build_os_version_raw);
5198 strtrimspace(build_os_arch, build_os_arch_raw);
5199 (void)fprintf (st, "\n Build OS: %s %s", build_os_version, build_os_arch);
5200 FREE(build_os_version);
5201 FREE(build_os_arch);
5202 #endif
5203 #if defined(__VERSION__)
5204 char gnumver[2];
5205 char postver[1024];
5206 (void)sprintf(gnumver, "%.1s", __VERSION__);
5207 (void)sprintf(postver, "%.1023s", __VERSION__);
5208 strremove(postver, "(TM)");
5209 strremove(postver, "(R)");
5210 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5211 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5212 strremove(postver, " gcc 4.9 mode");
5213 strremove(postver, "4.2.1 Compatible ");
5214 strremove(postver, "git@github.com:llvm/llvm-project.git ");
5215 strremove(postver, "https://github.com/llvm/llvm-project.git ");
5216 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5217 strremove(postver, "https://github.com/yrnkrn/zapcc ");
5218 strremove(postver, "(experimental) ");
5219 strremove(postver, ".module+el8.7.0+20823+214a699d");
5220 strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5221 strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5222 strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5223 strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5224 strremove(postver, "llvmorg-16.0.6-0-");
5225 strremove(postver, " Clang 15.0.0 (build 760095e)");
5226 strremove(postver, " Clang 15.0.0 (build 6af5742)");
5227 strremove(postver, " Clang 15.0.0 (build ca7115e)");
5228 strremove(postver, " Clang 15.0.0 (build 232543c)");
5229 strremove(postver, " Clang 17.0.6 (build 19a779f)");
5230 strremove(postver, "CLANG: ");
5231 #endif
5232 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5233 # if !defined(__clang_version__)
5234 if (isdigit((unsigned char)gnumver[0])) {
5235 (void)fprintf (st, "\n Compiler: GCC %s", postver);
5236 } else {
5237 (void)fprintf (st, "\n Compiler: %s", postver);
5238 }
5239 # endif
5240 # if defined(__clang_analyzer__ )
5241 (void)fprintf (st, "\n Compiler: Clang C/C++ Static Analyzer");
5242 # elif defined(__clang_version__) && defined(__VERSION__)
5243 char clangllvmver[1024];
5244 (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5245 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5246 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5247 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5248 strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5249 strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5250 strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5251 strremove(clangllvmver, " ( )");
5252 strremove(clangllvmver, " ()");
5253 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5254 (void)fprintf (st, "\n Compiler: Clang %s", clangllvmver);
5255 } else {
5256 (void)fprintf (st, "\n Compiler: %s", postver);
5257 }
5258 # elif defined(__clang_version__)
5259 (void)fprintf (st, "\n Compiler: %s", postver);
5260 # endif
5261 #elif defined(__PGI) && !defined(__NVCOMPILER)
5262 (void)fprintf (st, "\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
5263 # if defined(__PGIC__)
5264 (void)fprintf (st, "%d", __PGIC__);
5265 # if defined(__PGIC_MINOR__)
5266 (void)fprintf (st, ".%d", __PGIC_MINOR__);
5267 # if defined(__PGIC_PATCHLEVEL__)
5268 (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5269 # endif
5270 # endif
5271 # endif
5272 #elif defined(__NVCOMPILER)
5273 (void)fprintf (st, "\n Compiler: NVIDIA HPC SDK C Compiler ");
5274 # if defined(__NVCOMPILER_MAJOR__)
5275 (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5276 # if defined(__NVCOMPILER_MINOR__)
5277 (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5278 # if defined(__NVCOMPILER_PATCHLEVEL__)
5279 (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5280 # endif
5281 # endif
5282 # endif
5283 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5284 (void)fprintf (st, "\n Compiler: Microsoft C %d.%02d.%05d.%02d",
5285 _MSC_FULL_VER/10000000,
5286 (_MSC_FULL_VER/100000)%100,
5287 _MSC_FULL_VER%100000,
5288 _MSC_BUILD);
5289 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5290 # if defined(_AIX) && defined(__PASE__)
5291 (void)fprintf (st, "\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5292 # endif
5293 # if defined(_AIX) && !defined(__PASE__)
5294 (void)fprintf (st, "\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5295 # endif
5296 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5297 (void)fprintf (st, "\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5298 # endif
5299 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5300 # if defined(__PPC__) && defined(__APPLE__)
5301 (void)fprintf (st, "\n Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5302 # else
5303 (void)fprintf (st, "\n Compiler: IBM XL C/C++ V%s", __xlc__);
5304 # endif
5305 # endif
5306 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5307 # define VER_ENC(maj, min, rev) \
5308 (((maj) * 1000000) + ((min) * 1000) + (rev))
5309 # define VER_DEC_MAJ(ver) \
5310 ((ver) / 1000000)
5311 # define VER_DEC_MIN(ver) \
5312 (((ver) % 1000000) / 1000)
5313 # define VER_DEC_REV(ver) \
5314 ((ver) % 1000)
5315 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5316 # define COMP_VER VER_ENC( \
5317 (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5318 (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
5319 (__SUNPRO_C & 0xf) * 10)
5320 # elif defined(__SUNPRO_C)
5321 # define COMP_VER VER_ENC( \
5322 (__SUNPRO_C >> 8) & 0xf, \
5323 (__SUNPRO_C >> 4) & 0xf, \
5324 (__SUNPRO_C) & 0xf)
5325 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5326 # define COMP_VER VER_ENC( \
5327 (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5328 (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
5329 (__SUNPRO_CC & 0xf) * 10)
5330 # elif defined(__SUNPRO_CC)
5331 # define COMP_VER VER_ENC( \
5332 (__SUNPRO_CC >> 8) & 0xf, \
5333 (__SUNPRO_CC >> 4) & 0xf, \
5334 (__SUNPRO_CC) & 0xf)
5335 # endif
5336 # if !defined(COMP_VER)
5337 # define COMP_VER 0
5338 # endif
5339 (void)fprintf (st, "\n Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5340 VER_DEC_MAJ(COMP_VER),
5341 VER_DEC_MIN(COMP_VER),
5342 VER_DEC_REV(COMP_VER));
5343 #elif defined(__DMC__)
5344 (void)fprintf (st, "\n Compiler: Digital Mars C/C++");
5345 #elif defined(__PCC__)
5346 (void)fprintf (st, "\n Compiler: Portable C Compiler");
5347 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5348 (void)fprintf (st, "\n Compiler: Plan 9 Compiler Suite");
5349 #elif defined(__ACK__)
5350 (void)fprintf (st, "\n Compiler: Amsterdam Compiler Kit");
5351 #elif defined(__COMO__)
5352 (void)fprintf (st, "\n Compiler: Comeau C++");
5353 #elif defined(__COMPCERT__)
5354 (void)fprintf (st, "\n Compiler: CompCert C");
5355 #elif defined(__COVERITY__)
5356 (void)fprintf (st, "\n Compiler: Coverity C/C++ Static Analyzer");
5357 #elif defined(__LCC__)
5358 (void)fprintf (st, "\n Compiler: Local C Compiler (lcc)");
5359 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5360 (void)fprintf (st, "\n Compiler: SGI MIPSpro");
5361 #elif defined(__OPEN64__)
5362 (void)fprintf (st, "\n Compiler: Open64 %s", __OPEN64__);
5363 #elif defined(__PGI) || defined(__PGIC__)
5364 (void)fprintf (st, "\n Compiler: Portland Group/PGI C/C++");
5365 #elif defined(__VBCC__)
5366 (void)fprintf (st, "\n Compiler: Volker Barthelmann C Compiler (vbcc)");
5367 #elif defined(__WATCOMC__)
5368 (void)fprintf (st, "\n Compiler: Watcom C/C++ %d.%d",
5369 __WATCOMC__ / 100,
5370 __WATCOMC__ % 100);
5371 #elif defined(__xlC__)
5372 (void)fprintf (st, "\n Compiler: IBM XL C/C++");
5373 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5374 # if defined(__INTEL_COMPILER_UPDATE)
5375 # if defined(__INTEL_COMPILER_BUILD_DATE)
5376 (void)fprintf (st, "\n Compiler: Intel C++ Compiler %d.%d (%d)",
5377 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5378 __INTEL_COMPILER_BUILD_DATE);
5379 # else
5380 (void)fprintf (st, "\n Compiler: Intel C++ Compiler %d.%d",
5381 __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5382 # endif
5383 # else
5384 (void)fprintf (st, "\n Compiler: Intel C++ Compiler %d",
5385 __INTEL_COMPILER);
5386 # endif
5387 #elif defined(SIM_COMPILER)
5388 # define S_xstr(a) S_str(a)
5389 # define S_str(a) #a
5390 (void)fprintf (st, "\n Compiler: %s", S_xstr(SIM_COMPILER));
5391 # undef S_str
5392 # undef S_xstr
5393 #else
5394 (void)fprintf (st, "\n Compiler: Unknown");
5395 #endif
5396
5397 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5398 defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5399 # define SC_IS_PPC64 1
5400 #else
5401 # define SC_IS_PPC64 0
5402 #endif
5403
5404 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5405 defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5406 defined(__PPC32)
5407 # define SC_IS_PPC32 1
5408 #else
5409 # define SC_IS_PPC32 0
5410 #endif
5411
5412 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5413 arch = " x86_64";
5414 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5415 arch = " x86";
5416 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5417 arch = " arm64";
5418 #elif defined(_M_ARM) || defined(__arm__)
5419 arch = " arm";
5420 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5421 arch = " ia64";
5422 #elif SC_IS_PPC64
5423 arch = " powerpc64";
5424 #elif SC_IS_PPC32
5425 arch = " powerpc";
5426 #elif defined(__s390x__)
5427 arch = " s390x";
5428 #elif defined(__s390__)
5429 arch = " s390";
5430 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5431 arch = " j2";
5432 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5433 arch = " sh4";
5434 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5435 arch = " sh2";
5436 #elif defined(__alpha__)
5437 arch = " alpha";
5438 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5439 arch = " hppa";
5440 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5441 arch = " ice9";
5442 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5443 arch = " mips64";
5444 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5445 arch = " mips";
5446 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5447 defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5448 arch = " openrisc";
5449 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5450 arch = " sparc64";
5451 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5452 arch = " sparc";
5453 #elif defined(__riscv) || defined(__riscv__)
5454 arch = " riscv";
5455 #elif defined(__myriad2__)
5456 arch = " myriad2";
5457 #elif defined(__loongarch64) || defined(__loongarch__)
5458 arch = " loongarch";
5459 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5460 arch = " m68k";
5461 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5462 arch = " m88k";
5463 #elif defined(__VAX__) || defined(__vax__)
5464 arch = " vax";
5465 #elif defined(__NIOS2__) || defined(__nios2__)
5466 arch = " nios2";
5467 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5468 arch = " microblaze";
5469 #else
5470 arch = " ";
5471 #endif
5472 (void)fprintf (st, "%s", arch);
5473 #if defined(BUILD_BY_USER)
5474 (void)fprintf (st, "\n Built by: %s", BUILD_BY_USER);
5475 #else
5476 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5477 (void)fprintf (st, "\n Built by: %s", VER_H_PREP_USER);
5478 # endif
5479 #endif
5480 (void)fprintf (st, "\n\n Host System Information:");
5481 #if defined(_WIN32)
5482 if (1) {
5483 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5484 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5485 char osversion[PATH_MAX+1] = "";
5486 FILE *f;
5487
5488 if ((f = _popen ("ver", "r"))) {
5489 (void)memset (osversion, 0, sizeof(osversion));
5490 do {
5491 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5492 break;
5493 sim_trim_endspc (osversion);
5494 } while (osversion[0] == '\0');
5495 _pclose (f);
5496 }
5497 (void)fprintf (st, "\n Host OS: %s", osversion);
5498 (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
5499 }
5500 #else
5501 if (1) {
5502 char osversion[2*PATH_MAX+1] = "";
5503 FILE *f;
5504 # if !defined(_AIX)
5505 if ((f = popen \
5506 ("uname -mrs 2> /dev/null", "r"))) {
5507 # else
5508 if ((f = popen \
5509 ("sh -c 'echo \"$(command -p env uname -v \
5510 2> /dev/null).$(command -p env uname -r \
5511 2> /dev/null) $(command -p env uname -p \
5512 2> /dev/null)\"' 2> /dev/null", "r"))) {
5513 # endif
5514 (void)memset (osversion, 0, sizeof(osversion));
5515 do {
5516 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5517 break;
5518 }
5519 sim_trim_endspc (osversion);
5520 } while (osversion[0] == '\0');
5521 pclose (f);
5522 strremove(osversion, "0000000000000000 ");
5523 strremove(osversion, " 0000000000000000");
5524 strremove(osversion, "000000000000 ");
5525 strremove(osversion, " 000000000000");
5526 strremove(osversion, "IBM ");
5527 strremove(osversion, " (emulated by qemu)");
5528 strremove(osversion, " (emulated by QEMU)");
5529 }
5530 # if !defined(_AIX)
5531 (void)fprintf (st, "\n Host OS: %s", osversion);
5532 # else
5533 strremove(osversion, "AIX ");
5534 # if !defined(__PASE__)
5535 (void)fprintf (st, "\n Host OS: IBM AIX %s", osversion);
5536 # else
5537 (void)fprintf (st, "\n Host OS: IBM OS/400 (PASE) %s", osversion);
5538 # endif
5539 # endif
5540 } else {
5541 # if !defined(_AIX)
5542 (void)fprintf (st, "\n Host OS: Unknown");
5543 # else
5544 # if !defined(__PASE__)
5545 (void)fprintf (st, "\n Host OS: IBM AIX");
5546 # else
5547 (void)fprintf (st, "\n Host OS: IBM OS/400 (PASE)");
5548 # endif
5549 # endif
5550 }
5551 #endif
5552 #if defined(__APPLE__)
5553 int isRosetta = processIsTranslated();
5554 if (isRosetta == 1) {
5555 sim_printf ("\n\n ****** RUNNING UNDER APPLE ROSETTA 2, EXPECT REDUCED PERFORMANCE ******");
5556 }
5557 #endif
5558 if (nodist)
5559 {
5560 sim_printf ("\n\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\n");
5561 }
5562 else
5563 {
5564 (void)fprintf (st, "\n");
5565 (void)fprintf (st, "\n This software is made available under the terms of the ICU License.");
5566 (void)fprintf (st, "\n For complete license details, see the LICENSE file included with the");
5567 (void)fprintf (st, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5568 }
5569 (void)fprintf (st, "\n");
5570 }
5571 return SCPE_OK;
5572 }
5573
5574 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5575 {
5576 size_t i;
5577 DEVICE *dptr;
5578 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5579
5580 if (cptr && (*cptr != 0))
5581 return SCPE_2MARG;
5582 (void)fprintf (st, "%s simulator configuration%s\n\n", sim_name, only_enabled ? " (enabled devices)" : "");
5583 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5584 if (!only_enabled || !qdisable (dptr))
5585 show_device (st, dptr, flag);
5586 return SCPE_OK;
5587 }
5588
5589 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5590 {
5591 int32 i;
5592 DEVICE *dptr;
5593
5594 if (cptr && (*cptr != 0))
5595 return SCPE_2MARG;
5596 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5597 show_dev_logicals (st, dptr, NULL, 1, cptr);
5598 return SCPE_OK;
5599 }
5600
5601 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5602 {
5603 if (dptr->lname)
5604 (void)fprintf (st, "%s -> %s\n", dptr->lname, dptr->name);
5605 else if (!flag)
5606 fputs ("no logical name assigned\n", st);
5607 return SCPE_OK;
5608 }
5609
5610 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5611 {
5612 DEVICE *dptr;
5613 UNIT *uptr;
5614 int32 accum;
5615
5616 if (cptr && (*cptr != 0))
5617 return SCPE_2MARG;
5618 if (sim_clock_queue == QUEUE_LIST_END)
5619 (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\n",
5620 sim_name, sim_time, sim_timer_inst_per_sec ());
5621 else {
5622 const char *tim;
5623
5624 (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\n",
5625 sim_name, sim_time, sim_timer_inst_per_sec ());
5626 accum = 0;
5627 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5628 if (uptr == &sim_step_unit)
5629 (void)fprintf (st, " Step timer");
5630 else
5631 if (uptr == &sim_expect_unit)
5632 (void)fprintf (st, " Expect fired");
5633 else
5634 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5635 (void)fprintf (st, " %s", sim_dname (dptr));
5636 if (dptr->numunits > 1)
5637 (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5638 }
5639 else
5640 (void)fprintf (st, " Unknown");
5641 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5642 (void)fprintf (st, " at %d%s%s%s%s\n", accum + uptr->time,
5643 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5644 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5645 accum = accum + uptr->time;
5646 }
5647 }
5648 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5649 return SCPE_OK;
5650 }
5651
5652 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5653 {
5654 if (cptr && (*cptr != 0))
5655 return SCPE_2MARG;
5656 (void)fprintf (st, "Time:\t%.0f\n", sim_gtime());
5657 return SCPE_OK;
5658 }
5659
5660 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5661 {
5662 t_stat r;
5663
5664 if (cptr && (*cptr != 0))
5665 r = ssh_break (st, cptr, 1);
5666 else
5667 r = sim_brk_showall (st, (uint32)sim_switches);
5668 return r;
5669 }
5670
5671 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5672 {
5673 (void)fprintf (st, "Radix=%d\n", dptr->dradix);
5674 return SCPE_OK;
5675 }
5676
5677 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5678 {
5679 int32 any = 0;
5680 DEBTAB *dep;
5681
5682 if (dptr->flags & DEV_DEBUG) {
5683 if (dptr->dctrl == 0)
5684 fputs ("Debugging disabled", st);
5685 else if (dptr->debflags == NULL)
5686 fputs ("Debugging enabled", st);
5687 else {
5688 uint32 dctrl = dptr->dctrl;
5689
5690 fputs ("Debug=", st);
5691 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5692 if ((dctrl & dep->mask) == dep->mask) {
5693 dctrl &= ~dep->mask;
5694 if (any)
5695 fputc (';', st);
5696 fputs (dep->name, st);
5697 any = 1;
5698 }
5699 }
5700 }
5701 fputc ('\n', st);
5702 return SCPE_OK;
5703 }
5704 else return SCPE_NOFNC;
5705 }
5706
5707
5708
5709 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5710 {
5711 int32 lvl, i;
5712
5713 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5714 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5715 if (lvl > 0)
5716 (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5717 else
5718 (void)fprintf(st, "On Processing for input commands");
5719 (void)fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5720 for (i=1; i<SCPE_BASE; ++i) {
5721 if (sim_on_actions[lvl][i])
5722 (void)fprintf(st, " on %5d %s\n", i, sim_on_actions[lvl][i]); }
5723 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5724 if (sim_on_actions[lvl][i])
5725 (void)fprintf(st, " on %-5s %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5726 if (sim_on_actions[lvl][0])
5727 (void)fprintf(st, " on ERROR %s\n", sim_on_actions[lvl][0]);
5728 (void)fprintf(st, "\n");
5729 }
5730 if (sim_on_inherit)
5731 (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\n");
5732 return SCPE_OK;
5733 }
5734
5735
5736
5737 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5738 {
5739 int32 i;
5740 DEVICE *dptr;
5741
5742 if (cptr && (*cptr != 0))
5743 return SCPE_2MARG;
5744 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5745 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5746 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5747 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5748 return SCPE_OK;
5749 }
5750
5751 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5752 {
5753 fprint_set_help (st, dptr);
5754 return SCPE_OK;
5755 }
5756
5757 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5758 {
5759 MTAB *mptr;
5760 t_stat r = SCPE_OK;
5761
5762 if (dptr->modifiers == NULL)
5763 return SCPE_OK;
5764 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5765 if (mptr->pstring &&
5766 ((mptr->mask & MTAB_XTD)?
5767 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5768 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5769 if (*toks > 0) {
5770 (void)fprintf (st, "\n");
5771 *toks = 0;
5772 }
5773 if (r == SCPE_OK)
5774 fprint_sep (st, toks);
5775 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5776 }
5777 }
5778 return SCPE_OK;
5779 }
5780
5781 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5782 CONST char *cptr, int32 flag)
5783 {
5784 t_stat r = SCPE_OK;
5785
5786 if (mptr->disp)
5787 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5788 else
5789 fputs (mptr->pstring, st);
5790 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5791 fputc ('\n', st);
5792 return r;
5793 }
5794
5795
5796
5797 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5798 {
5799 int32 i;
5800 DEVICE *dptr;
5801
5802 if (cptr && (*cptr != 0))
5803 return SCPE_2MARG;
5804 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5805 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5806 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5807 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5808 return SCPE_OK;
5809 }
5810
5811 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5812 {
5813 fprint_show_help (st, dptr);
5814 return SCPE_OK;
5815 }
5816
5817
5818
5819 t_stat brk_cmd (int32 flg, CONST char *cptr)
5820 {
5821 GET_SWITCHES (cptr);
5822 return ssh_break (NULL, cptr, flg);
5823 }
5824
5825 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
5826 {
5827 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5828 CONST char *tptr, *t1ptr;
5829 DEVICE *dptr = sim_dflt_dev;
5830 UNIT *uptr;
5831 t_stat r;
5832 t_addr lo, hi, max;
5833 int32 cnt;
5834
5835 if (sim_brk_types == 0)
5836 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5837 if (dptr == NULL)
5838 return SCPE_IERR;
5839 uptr = dptr->units;
5840 if (uptr == NULL)
5841 return SCPE_IERR;
5842 max = uptr->capac - 1;
5843 abuf[sizeof(abuf)-1] = '\0';
5844 strncpy (abuf, cptr, sizeof(abuf)-1);
5845 cptr = abuf;
5846 if ((aptr = strchr (abuf, ';'))) {
5847 if (flg != SSH_ST)
5848 return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", aptr);
5849 *aptr++ = 0;
5850 }
5851 if (*cptr == 0) {
5852 lo = (t_addr) get_rval (sim_PC, 0);
5853 return ssh_break_one (st, flg, lo, 0, aptr);
5854 }
5855 while (*cptr) {
5856 cptr = get_glyph (cptr, gbuf, ',');
5857 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5858 if (tptr == NULL)
5859 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\n", gbuf);
5860 if (*tptr == '[') {
5861 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5862 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5863 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\n", tptr + 1);
5864 tptr = t1ptr + 1;
5865 }
5866 else cnt = 0;
5867 if (*tptr != 0)
5868 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\n", tptr);
5869 if ((lo == 0) && (hi == max)) {
5870 if (flg == SSH_CL)
5871 sim_brk_clrall (sim_switches);
5872 else
5873 if (flg == SSH_SH)
5874 sim_brk_showall (st, (uint32)sim_switches);
5875 else
5876 return SCPE_ARG;
5877 }
5878 else {
5879 for ( ; lo <= hi; lo = lo + 1) {
5880 r = ssh_break_one (st, flg, lo, cnt, aptr);
5881 if (r != SCPE_OK)
5882 return r;
5883 }
5884 }
5885 }
5886 return SCPE_OK;
5887 }
5888
5889 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
5890 {
5891 if (!sim_brk_types)
5892 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5893 switch (flg) {
5894 case SSH_ST:
5895 return sim_brk_set (lo, sim_switches, cnt, aptr);
5896
5897 break;
5898
5899 case SSH_CL:
5900 return sim_brk_clr (lo, sim_switches);
5901
5902 break;
5903
5904 case SSH_SH:
5905 return sim_brk_show (st, lo, sim_switches);
5906
5907 break;
5908
5909 default:
5910 return SCPE_ARG;
5911 }
5912 }
5913
5914
5915
5916 static t_bool run_cmd_did_reset = FALSE;
5917
5918 t_stat reset_cmd (int32 flag, CONST char *cptr)
5919 {
5920 char gbuf[CBUFSIZE];
5921 DEVICE *dptr;
5922
5923 GET_SWITCHES (cptr);
5924 run_cmd_did_reset = FALSE;
5925 if (*cptr == 0)
5926 return (reset_all (0));
5927 cptr = get_glyph (cptr, gbuf, 0);
5928 if (*cptr != 0)
5929 return SCPE_2MARG;
5930 if (strcmp (gbuf, "ALL") == 0)
5931 return (reset_all (0));
5932 dptr = find_dev (gbuf);
5933 if (dptr == NULL)
5934 return SCPE_NXDEV;
5935 if (dptr->reset != NULL)
5936 return dptr->reset (dptr);
5937 else return SCPE_OK;
5938 }
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948 t_stat reset_all (uint32 start)
5949 {
5950 DEVICE *dptr;
5951 uint32 i;
5952 t_stat reason;
5953
5954 for (i = 0; i < start; i++) {
5955 if (sim_devices[i] == NULL)
5956 return SCPE_IERR;
5957 }
5958 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
5959 if (dptr->reset != NULL) {
5960 reason = dptr->reset (dptr);
5961 if (reason != SCPE_OK)
5962 return reason;
5963 }
5964 }
5965 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
5966 if (dptr->reset != NULL) {
5967 reason = dptr->reset (dptr);
5968 if (reason != SCPE_OK)
5969 return reason;
5970 }
5971 }
5972 return SCPE_OK;
5973 }
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983 t_stat reset_all_p (uint32 start)
5984 {
5985 t_stat r;
5986 int32 old_sw = sim_switches;
5987
5988 sim_switches = SWMASK ('P');
5989 r = reset_all (start);
5990 sim_switches = old_sw;
5991 return r;
5992 }
5993
5994
5995
5996 t_stat attach_cmd (int32 flag, CONST char *cptr)
5997 {
5998 char gbuf[4*CBUFSIZE];
5999 DEVICE *dptr;
6000 UNIT *uptr;
6001 t_stat r;
6002
6003 GET_SWITCHES (cptr);
6004 if ((NULL == cptr) || (*cptr == 0))
6005 return SCPE_2FARG;
6006 cptr = get_glyph (cptr, gbuf, 0);
6007 GET_SWITCHES (cptr);
6008 if ((NULL == cptr) || (*cptr == 0))
6009 return SCPE_2FARG;
6010 dptr = find_unit (gbuf, &uptr);
6011 if (dptr == NULL)
6012 return SCPE_NXDEV;
6013 if (uptr == NULL)
6014 return SCPE_NXUN;
6015 if (uptr->flags & UNIT_ATT) {
6016 if (!(uptr->dynflags & UNIT_ATTMULT) &&
6017 !(dptr->flags & DEV_DONTAUTO)) {
6018 r = scp_detach_unit (dptr, uptr);
6019 if (r != SCPE_OK)
6020 return r; }
6021 else {
6022 if (!(uptr->dynflags & UNIT_ATTMULT))
6023 return SCPE_ALATT;
6024 }
6025 }
6026 gbuf[sizeof(gbuf)-1] = '\0';
6027 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6028 sim_trim_endspc (gbuf);
6029 return scp_attach_unit (dptr, uptr, gbuf);
6030 }
6031
6032
6033
6034 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
6035 {
6036 if (dptr->attach != NULL)
6037 return dptr->attach (uptr, (CONST char *)cptr);
6038 return attach_unit (uptr, (CONST char *)cptr);
6039 }
6040
6041
6042
6043 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
6044 {
6045 DEVICE *dptr;
6046
6047 if (uptr->flags & UNIT_DIS)
6048 return SCPE_UDIS;
6049 if (!(uptr->flags & UNIT_ATTABLE))
6050 return SCPE_NOATT;
6051 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6052 return SCPE_NOATT;
6053 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
6054 if (uptr->filename == NULL)
6055 return SCPE_MEM;
6056 strncpy (uptr->filename, cptr, CBUFSIZE-1);
6057 if ((sim_switches & SWMASK ('R')) ||
6058 ((uptr->flags & UNIT_RO) != 0)) {
6059 if (((uptr->flags & UNIT_ROABLE) == 0) &&
6060 ((uptr->flags & UNIT_RO) == 0))
6061 return attach_err (uptr, SCPE_NORO);
6062 uptr->fileref = sim_fopen (cptr, "rb");
6063 if (uptr->fileref == NULL)
6064 return attach_err (uptr, SCPE_OPENERR);
6065 uptr->flags = uptr->flags | UNIT_RO;
6066 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6067 sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6068 }
6069 }
6070 else {
6071 if (sim_switches & SWMASK ('N')) {
6072 uptr->fileref = sim_fopen (cptr, "wb+");
6073 if (uptr->fileref == NULL)
6074 return attach_err (uptr, SCPE_OPENERR);
6075 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6076 sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6077 }
6078 }
6079 else {
6080 uptr->fileref = sim_fopen (cptr, "rb+");
6081 if (uptr->fileref == NULL) {
6082 #if defined(EWOULDBLOCK)
6083 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6084 #else
6085 if ((errno == EAGAIN))
6086 #endif
6087 return attach_err (uptr, SCPE_OPENERR);
6088
6089 #if defined(EPERM)
6090 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
6091 #else
6092 if ((errno == EROFS) || (errno == EACCES)) {
6093 #endif
6094 if ((uptr->flags & UNIT_ROABLE) == 0)
6095 return attach_err (uptr, SCPE_NORO);
6096 uptr->fileref = sim_fopen (cptr, "rb");
6097 if (uptr->fileref == NULL)
6098 return attach_err (uptr, SCPE_OPENERR);
6099 uptr->flags = uptr->flags | UNIT_RO;
6100 if (!sim_quiet) {
6101 sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6102 }
6103 }
6104 else {
6105 if (sim_switches & SWMASK ('E'))
6106 return attach_err (uptr, SCPE_OPENERR);
6107 uptr->fileref = sim_fopen (cptr, "wb+");
6108 if (uptr->fileref == NULL)
6109 return attach_err (uptr, SCPE_OPENERR);
6110 if (!sim_quiet) {
6111 sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6112 }
6113 }
6114 }
6115 }
6116 }
6117 if (uptr->flags & UNIT_BUFABLE) {
6118 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
6119 if (uptr->flags & UNIT_MUSTBUF)
6120 uptr->filebuf = calloc (cap, SZ_D (dptr));
6121 if (uptr->filebuf == NULL)
6122 return attach_err (uptr, SCPE_MEM);
6123 if (!sim_quiet) {
6124 sim_printf ("%s: buffering file in memory\n", sim_dname (dptr));
6125 }
6126 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
6127 SZ_D (dptr), cap, uptr->fileref);
6128 uptr->flags = uptr->flags | UNIT_BUF;
6129 }
6130 uptr->flags = uptr->flags | UNIT_ATT;
6131 uptr->pos = 0;
6132 return SCPE_OK;
6133 }
6134
6135 t_stat attach_err (UNIT *uptr, t_stat stat)
6136 {
6137 FREE (uptr->filename);
6138 uptr->filename = NULL;
6139 return stat;
6140 }
6141
6142
6143
6144 t_stat detach_cmd (int32 flag, CONST char *cptr)
6145 {
6146 char gbuf[CBUFSIZE];
6147 DEVICE *dptr;
6148 UNIT *uptr;
6149
6150 GET_SWITCHES (cptr);
6151 if ((NULL == cptr) || (*cptr == 0))
6152 return SCPE_2FARG;
6153 cptr = get_glyph (cptr, gbuf, 0);
6154 if (*cptr != 0)
6155 return SCPE_2MARG;
6156 if (strcmp (gbuf, "ALL") == 0)
6157 return (detach_all (0, FALSE));
6158 dptr = find_unit (gbuf, &uptr);
6159 if (dptr == NULL)
6160 return SCPE_NXDEV;
6161 if (uptr == NULL)
6162 return SCPE_NXUN;
6163 return scp_detach_unit (dptr, uptr);
6164 }
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179 t_stat detach_all (int32 start, t_bool shutdown)
6180 {
6181 uint32 i, j;
6182 DEVICE *dptr;
6183 UNIT *uptr;
6184 t_stat r;
6185
6186 if ((start < 0) || (start > 1))
6187 return SCPE_IERR;
6188 if (shutdown)
6189 sim_switches = sim_switches | SIM_SW_SHUT;
6190 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6191 for (j = 0; j < dptr->numunits; j++) {
6192 uptr = (dptr->units) + j;
6193 if ((uptr->flags & UNIT_ATT) ||
6194 (shutdown && dptr->detach &&
6195 !(uptr->flags & UNIT_ATTABLE))) {
6196 r = scp_detach_unit (dptr, uptr);
6197
6198 if ((r != SCPE_OK) && !shutdown)
6199 return r;
6200 }
6201 }
6202 }
6203 return SCPE_OK;
6204 }
6205
6206
6207
6208 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
6209 {
6210 if (dptr->detach != NULL)
6211 return dptr->detach (uptr);
6212 return detach_unit (uptr);
6213 }
6214
6215
6216
6217 t_stat detach_unit (UNIT *uptr)
6218 {
6219 DEVICE *dptr;
6220
6221 if (uptr == NULL)
6222 return SCPE_IERR;
6223 if (!(uptr->flags & UNIT_ATTABLE))
6224 return SCPE_NOATT;
6225 if (!(uptr->flags & UNIT_ATT)) {
6226 if (sim_switches & SIM_SW_REST)
6227 return SCPE_OK;
6228 else
6229 return SCPE_NOTATT;
6230 }
6231 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6232 return SCPE_OK;
6233 if (uptr->flags & UNIT_BUF) {
6234 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6235 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6236 if (!sim_quiet) {
6237 sim_printf ("%s: writing buffer to file\n", sim_dname (dptr));
6238 }
6239 rewind (uptr->fileref);
6240 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6241 if (ferror (uptr->fileref))
6242 sim_printf ("%s: I/O error - %s (Error %d)",
6243 sim_dname (dptr), xstrerror_l(errno), errno);
6244 }
6245 if (uptr->flags & UNIT_MUSTBUF) {
6246 FREE (uptr->filebuf);
6247 uptr->filebuf = NULL;
6248 }
6249 uptr->flags = uptr->flags & ~UNIT_BUF;
6250 }
6251 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6252 FREE (uptr->filename);
6253 uptr->filename = NULL;
6254 if (fclose (uptr->fileref) == EOF)
6255 return SCPE_IOERR;
6256 return SCPE_OK;
6257 }
6258
6259
6260
6261 const char *sim_dname (DEVICE *dptr)
6262 {
6263 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6264 }
6265
6266
6267
6268 const char *sim_uname (UNIT *uptr)
6269 {
6270 DEVICE *d = find_dev_from_unit(uptr);
6271 static char uname[CBUFSIZE];
6272
6273 if (!d)
6274 return "";
6275 if (d->numunits == 1)
6276 return sim_dname (d);
6277 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6278 return uname;
6279 }
6280
6281
6282
6283 t_stat run_cmd (int32 flag, CONST char *cptr)
6284 {
6285 char gbuf[CBUFSIZE] = "";
6286 CONST char *tptr;
6287 uint32 i, j;
6288 int32 sim_next = 0;
6289 int32 unitno;
6290 t_value pcv, orig_pcv;
6291 t_stat r;
6292 DEVICE *dptr;
6293 UNIT *uptr;
6294
6295 GET_SWITCHES (cptr);
6296 sim_step = 0;
6297 if ((flag == RU_RUN) || (flag == RU_GO)) {
6298 orig_pcv = get_rval (sim_PC, 0);
6299 if (*cptr != 0) {
6300 cptr = get_glyph (cptr, gbuf, 0);
6301 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6302 if (sim_dflt_dev && sim_vm_parse_addr)
6303 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6304 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
6305 if ((tptr == gbuf) || (*tptr != 0) ||
6306 (pcv > width_mask[sim_PC->width]))
6307 return SCPE_ARG;
6308 put_rval (sim_PC, 0, pcv);
6309 }
6310 }
6311 if ((flag == RU_RUN) &&
6312 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
6313 put_rval (sim_PC, 0, orig_pcv);
6314 return r;
6315 }
6316 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
6317 int32 saved_switches = sim_switches;
6318
6319 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6320 cptr = get_glyph (cptr, gbuf, 0);
6321 if (MATCH_CMD (gbuf, "UNTIL") != 0)
6322 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n",
6323 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6324 sim_switches = 0;
6325 GET_SWITCHES (cptr);
6326 if ((*cptr == '\'') || (*cptr == '"')) {
6327 r = expect_cmd (1, cptr);
6328 if (r != SCPE_OK)
6329 return r;
6330 }
6331 else {
6332 if (sim_switches == 0)
6333 sim_switches = sim_brk_dflt;
6334 sim_switches |= BRK_TYP_TEMP;
6335 sim_brk_types |= BRK_TYP_TEMP;
6336 r = ssh_break (NULL, cptr, SSH_ST);
6337 if (r != SCPE_OK)
6338 return sim_messagef (r, "Unable to establish breakpoint at: %s\n", cptr);
6339 }
6340 sim_switches = saved_switches;
6341 }
6342 }
6343
6344 else if ((flag == RU_STEP) ||
6345 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
6346 static t_bool not_implemented_message = FALSE;
6347
6348 if ((!not_implemented_message) && (flag == RU_NEXT)) {
6349 not_implemented_message = TRUE;
6350 flag = RU_STEP;
6351 }
6352 if (*cptr != 0) {
6353 cptr = get_glyph (cptr, gbuf, 0);
6354 if (*cptr != 0)
6355 return SCPE_2MARG;
6356 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6357 if ((r != SCPE_OK) || (sim_step <= 0))
6358 return SCPE_ARG;
6359 }
6360 else sim_step = 1;
6361 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6362 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6363 }
6364 else if (flag == RU_NEXT) {
6365 t_addr *addrs;
6366
6367 if (*cptr != 0) {
6368 cptr = get_glyph (cptr, gbuf, 0);
6369 if (*cptr != 0)
6370 return SCPE_2MARG;
6371 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6372 if ((r != SCPE_OK) || (sim_next <= 0))
6373 return SCPE_ARG;
6374 }
6375 else sim_next = 1;
6376 if (sim_vm_is_subroutine_call(&addrs)) {
6377 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6378 for (i=0; addrs[i]; i++)
6379 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6380 }
6381 else
6382 sim_step = 1;
6383 }
6384 else if (flag == RU_BOOT) {
6385 if (*cptr == 0)
6386 return SCPE_2FARG;
6387 cptr = get_glyph (cptr, gbuf, 0);
6388 if (*cptr != 0)
6389 return SCPE_2MARG;
6390 dptr = find_unit (gbuf, &uptr);
6391 if (dptr == NULL)
6392 return SCPE_NXDEV;
6393 if (uptr == NULL)
6394 return SCPE_NXUN;
6395 if (dptr->boot == NULL)
6396 return SCPE_NOFNC;
6397 if (uptr->flags & UNIT_DIS)
6398 return SCPE_UDIS;
6399 if ((uptr->flags & UNIT_ATTABLE) &&
6400 !(uptr->flags & UNIT_ATT))
6401 return SCPE_UNATT;
6402 unitno = (int32) (uptr - dptr->units);
6403 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
6404 return r;
6405 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
6406 return r;
6407 }
6408
6409 else
6410 if (flag != RU_CONT)
6411 return SCPE_IERR;
6412 else
6413 if (*cptr != 0)
6414 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\n");
6415
6416 if (sim_switches & SIM_SW_HIDE)
6417 return SCPE_OK;
6418
6419 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6420 for (j = 0; j < dptr->numunits; j++) {
6421 uptr = dptr->units + j;
6422 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6423 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6424 }
6425 }
6426 stop_cpu = 0;
6427 sim_is_running = 1;
6428 if (sim_ttrun () != SCPE_OK) {
6429 sim_is_running = 0;
6430 sim_ttcmd ();
6431 return SCPE_TTYERR;
6432 }
6433 if ((r = sim_check_console (30)) != SCPE_OK) {
6434 sim_is_running = 0;
6435 sim_ttcmd ();
6436 return r;
6437 }
6438 #if !defined(IS_WINDOWS)
6439 # if defined(SIGINT)
6440 if (signal (SIGINT, int_handler) == SIG_ERR) {
6441 sim_is_running = 0;
6442 sim_ttcmd ();
6443 return SCPE_SIGERR;
6444 }
6445 # endif
6446 #endif
6447 #if !defined(IS_WINDOWS)
6448 # if defined(SIGHUP)
6449 if (signal (SIGHUP, int_handler) == SIG_ERR) {
6450 sim_is_running = 0;
6451 sim_ttcmd ();
6452 return SCPE_SIGERR;
6453 }
6454 # endif
6455 #endif
6456 #if !defined(IS_WINDOWS)
6457 # if defined(SIGTERM)
6458 if (signal (SIGTERM, int_handler) == SIG_ERR) {
6459 sim_is_running = 0;
6460 sim_ttcmd ();
6461 return SCPE_SIGERR;
6462 }
6463 # endif
6464 #endif
6465 if (sim_step)
6466 sim_activate (&sim_step_unit, sim_step);
6467 (void)fflush(stdout);
6468 if (sim_log)
6469 (void)fflush (sim_log);
6470 sim_rtcn_init_all ();
6471 sim_start_timer_services ();
6472
6473 do {
6474 t_addr *addrs;
6475
6476 while (1) {
6477 r = sim_instr();
6478 if (r != SCPE_REMOTE)
6479 break;
6480 sim_remote_process_command ();
6481 }
6482 if ((flag != RU_NEXT) ||
6483 (--sim_next <=0))
6484 break;
6485 if (sim_step == 0) {
6486 t_addr val;
6487 BRKTAB *bp;
6488
6489 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
6490 break;
6491 if (sim_vm_pc_value)
6492 val = (t_addr)(*sim_vm_pc_value)();
6493 else
6494 val = (t_addr)get_rval (sim_PC, 0);
6495 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6496 break;
6497 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6498 }
6499 else {
6500 if (r != SCPE_STEP)
6501 break;
6502 }
6503
6504 sim_step = 0;
6505 if (sim_vm_is_subroutine_call(&addrs)) {
6506 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6507 for (i=0; addrs[i]; i++)
6508 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6509 }
6510 else
6511 sim_step = 1;
6512 if (sim_step)
6513 sim_activate (&sim_step_unit, sim_step);
6514 } while (1);
6515
6516 sim_is_running = 0;
6517 sim_stop_timer_services ();
6518 sim_ttcmd ();
6519 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
6520 signal (SIGINT, SIG_DFL);
6521 #if defined(SIGHUP)
6522 signal (SIGHUP, SIG_DFL);
6523 #endif
6524 signal (SIGTERM, SIG_DFL);
6525 if (sim_log)
6526 (void)fflush (sim_log);
6527 if (sim_deb)
6528 sim_debug_flush ();
6529 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
6530 for (j = 0; j < dptr->numunits; j++) {
6531 uptr = dptr->units + j;
6532 if (uptr->flags & UNIT_ATT) {
6533 if (uptr->io_flush)
6534 uptr->io_flush (uptr);
6535 else {
6536 if (!(uptr->flags & UNIT_BUF) &&
6537 (uptr->fileref) &&
6538 !(uptr->dynflags & UNIT_NO_FIO) &&
6539 !(uptr->flags & UNIT_RO))
6540 (void)fflush (uptr->fileref);
6541 }
6542 }
6543 }
6544 }
6545 sim_cancel (&sim_step_unit);
6546 UPDATE_SIM_TIME;
6547 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6548 }
6549
6550
6551
6552 void
6553 run_cmd_message (const char *unechoed_cmdline, t_stat r)
6554 {
6555 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6556 sim_printf("%s> %s\n", do_position(), unechoed_cmdline);
6557 #if defined(WIN_STDIO)
6558 (void)fflush(stderr);
6559 (void)fflush(stdout);
6560 #endif
6561 fprint_stopped (stdout, r);
6562 if (sim_log && (sim_log != stdout))
6563 fprint_stopped (sim_log, r);
6564 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
6565 fprint_stopped (sim_deb, r);
6566 #if defined(WIN_STDIO)
6567 (void)fflush(stderr);
6568 (void)fflush(stdout);
6569 #endif
6570 }
6571
6572
6573
6574 t_stat sim_run_boot_prep (int32 flag)
6575 {
6576 UNIT *uptr;
6577 t_stat r;
6578
6579 sim_interval = 0;
6580 sim_time = sim_rtime = 0;
6581 noqueue_time = 0;
6582 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6583 sim_clock_queue = uptr->next;
6584 uptr->next = NULL;
6585 }
6586 r = reset_all (0);
6587 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6588 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6589 sim_printf ("Resetting all devices... This may not have been your intention.\n");
6590 sim_printf ("The GO and CONTINUE commands do not reset devices.\n");
6591 }
6592 run_cmd_did_reset = TRUE;
6593 }
6594 return r;
6595 }
6596
6597
6598
6599
6600
6601
6602
6603
6604 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
6605 {
6606 int32 i;
6607 t_stat r = 0;
6608 t_addr k;
6609 t_value pcval;
6610
6611 fputc ('\n', st);
6612
6613 if (v >= SCPE_BASE)
6614 fputs (sim_error_text (v), st);
6615 else {
6616 fputs (sim_stop_messages [v], st);
6617
6618 if ((sim_vm_fprint_stopped != NULL) &&
6619 (!sim_vm_fprint_stopped (st, v)))
6620 return;
6621 }
6622
6623 (void)fprintf (st, ", %s: ", pc->name);
6624
6625 pcval = get_rval (pc, 0);
6626 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6627 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6628 else fprint_val (st, pcval, pc->radix, pc->width,
6629 pc->flags & REG_FMT);
6630 if ((dptr != NULL) && (dptr->examine != NULL)) {
6631 for (i = 0; i < sim_emax; i++)
6632 sim_eval[i] = 0;
6633 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6634 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6635 break;
6636 }
6637 if ((r == SCPE_OK) || (i > 0)) {
6638 (void)fprintf (st, " (");
6639 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6640 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6641 (void)fprintf (st, ")");
6642 }
6643 }
6644 (void)fprintf (st, "\n");
6645 return;
6646 }
6647
6648 void fprint_stopped (FILE *st, t_stat v)
6649 {
6650 #if defined(WIN_STDIO)
6651 (void)fflush(stderr);
6652 (void)fflush(stdout);
6653 #endif
6654 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6655 return;
6656 }
6657
6658
6659
6660
6661 t_stat step_svc (UNIT *uptr)
6662 {
6663 return SCPE_STEP;
6664 }
6665
6666
6667
6668
6669 t_stat expect_svc (UNIT *uptr)
6670 {
6671 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6672 }
6673
6674
6675
6676 void int_handler (int sig)
6677 {
6678 stop_cpu = 1;
6679 return;
6680 }
6681
6682
6683
6684 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6685 {
6686 char gbuf[CBUFSIZE];
6687 CONST char *gptr;
6688 CONST char *tptr = NULL;
6689 int32 opt;
6690 t_addr low, high;
6691 t_stat reason = SCPE_IERR;
6692 DEVICE *tdptr;
6693 REG *lowr, *highr;
6694 FILE *ofile;
6695
6696 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6697 if (flag == EX_E)
6698 opt = opt | CMD_OPT_OF;
6699 cptr = get_sim_opt (opt, cptr, &reason);
6700 if (NULL == cptr)
6701 return reason;
6702 if (*cptr == 0)
6703 return SCPE_2FARG;
6704 if (sim_dfunit == NULL)
6705 return SCPE_NXUN;
6706 cptr = get_glyph (cptr, gbuf, 0);
6707 if ((flag == EX_D) && (*cptr == 0))
6708
6709 return SCPE_2FARG;
6710 ofile = sim_ofile? sim_ofile: stdout;
6711
6712 for (gptr = gbuf, reason = SCPE_OK;
6713 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6714 tdptr = sim_dfdev;
6715 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6716 tptr = gptr + strlen ("STATE");
6717 if (*tptr && (*tptr++ != ','))
6718 return SCPE_ARG;
6719 if ((lowr = sim_dfdev->registers) == NULL)
6720 return SCPE_NXREG;
6721 for (highr = lowr; highr->name != NULL; highr++) ;
6722 sim_switches = sim_switches | SIM_SW_HIDE;
6723 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6724 lowr, --highr, 0, 0);
6725 continue;
6726 }
6727
6728
6729 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6730 (!(sim_opt_out & CMD_OPT_DFT) &&
6731 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6732 low = high = 0;
6733 if ((*tptr == '-') || (*tptr == ':')) {
6734 highr = find_reg (tptr + 1, &tptr, tdptr);
6735 if (highr == NULL)
6736 return SCPE_NXREG;
6737 }
6738 else {
6739 highr = lowr;
6740 if (*tptr == '[') {
6741 if (lowr->depth <= 1)
6742 return SCPE_ARG;
6743 tptr = get_range (NULL, tptr + 1, &low, &high,
6744 10, lowr->depth - 1, ']');
6745 if (tptr == NULL)
6746 return SCPE_ARG;
6747 }
6748 }
6749 if (*tptr && (*tptr++ != ','))
6750 return SCPE_ARG;
6751 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6752 lowr, highr, (uint32) low, (uint32) high);
6753 continue;
6754 }
6755
6756 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6757 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6758 sim_dfunit->capac - sim_dfdev->aincr), 0);
6759 if (tptr == NULL)
6760 return SCPE_ARG;
6761 if (*tptr && (*tptr++ != ','))
6762 return SCPE_ARG;
6763 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6764 sim_dfdev, sim_dfunit);
6765 }
6766 if (sim_ofile)
6767 fclose (sim_ofile);
6768 return reason;
6769 }
6770
6771
6772
6773
6774
6775
6776
6777 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6778 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6779 {
6780 t_stat reason;
6781 uint32 idx, val_start=lows;
6782 t_value val, last_val;
6783 REG *rptr;
6784
6785 if ((lowr == NULL) || (highr == NULL))
6786 return SCPE_IERR;
6787 if (lowr > highr)
6788 return SCPE_ARG;
6789 for (rptr = lowr; rptr <= highr; rptr++) {
6790 if ((sim_switches & SIM_SW_HIDE) &&
6791 (rptr->flags & REG_HIDDEN))
6792 continue;
6793 val = last_val = 0;
6794 for (idx = lows; idx <= highs; idx++) {
6795 if (idx >= rptr->depth)
6796 return SCPE_SUB;
6797 val = get_rval (rptr, idx);
6798 if (schptr && !test_search (&val, schptr))
6799 continue;
6800 if (flag == EX_E) {
6801 if ((idx > lows) && (val == last_val))
6802 continue;
6803 if (idx > val_start+1) {
6804 if (idx-1 == val_start+1) {
6805 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6806 if (reason != SCPE_OK)
6807 return reason;
6808 if (sim_log && (ofile == stdout))
6809 ex_reg (sim_log, val, flag, rptr, idx-1);
6810 }
6811 else {
6812 if (val_start+1 != idx-1) {
6813 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6814 if (sim_log && (ofile == stdout))
6815 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6816 }
6817 else {
6818 (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6819 if (sim_log && (ofile == stdout))
6820 (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6821 }
6822 }
6823 }
6824 sim_last_val = last_val = val;
6825 val_start = idx;
6826 reason = ex_reg (ofile, val, flag, rptr, idx);
6827 if (reason != SCPE_OK)
6828 return reason;
6829 if (sim_log && (ofile == stdout))
6830 ex_reg (sim_log, val, flag, rptr, idx);
6831 }
6832 if (flag != EX_E) {
6833 reason = dep_reg (flag, cptr, rptr, idx);
6834 if (reason != SCPE_OK)
6835 return reason;
6836 }
6837 }
6838 if ((flag == EX_E) && (val_start != highs)) {
6839 if (highs == val_start+1) {
6840 reason = ex_reg (ofile, val, flag, rptr, highs);
6841 if (reason != SCPE_OK)
6842 return reason;
6843 if (sim_log && (ofile == stdout))
6844 ex_reg (sim_log, val, flag, rptr, highs);
6845 }
6846 else {
6847 if (val_start+1 != highs) {
6848 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6849 if (sim_log && (ofile == stdout))
6850 (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6851 }
6852 else {
6853 (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6854 if (sim_log && (ofile == stdout))
6855 (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6856 }
6857 }
6858 }
6859 }
6860 return SCPE_OK;
6861 }
6862
6863 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
6864 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6865 {
6866 t_addr i, mask;
6867 t_stat reason;
6868
6869 if (uptr->flags & UNIT_DIS)
6870 return SCPE_UDIS;
6871 mask = (t_addr) width_mask[dptr->awidth];
6872 if ((low > mask) || (high > mask) || (low > high))
6873 return SCPE_ARG;
6874 for (i = low; i <= high; ) {
6875 reason = get_aval (i, dptr, uptr);
6876 if (reason != SCPE_OK)
6877 return reason;
6878 if (schptr && !test_search (sim_eval, schptr))
6879 i = i + dptr->aincr;
6880 else {
6881 if (flag != EX_D) {
6882 reason = ex_addr (ofile, flag, i, dptr, uptr);
6883 if (reason > SCPE_OK)
6884 return reason;
6885 if (sim_log && (ofile == stdout))
6886 ex_addr (sim_log, flag, i, dptr, uptr);
6887 }
6888 else reason = 1 - dptr->aincr;
6889 if (flag != EX_E) {
6890 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
6891 if (reason > SCPE_OK)
6892 return reason;
6893 }
6894 i = i + (1 - reason);
6895 }
6896 }
6897 return SCPE_OK;
6898 }
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
6913 {
6914 int32 rdx;
6915
6916 if (rptr == NULL)
6917 return SCPE_IERR;
6918 if (rptr->depth > 1)
6919 (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
6920 else
6921 (void)Fprintf (ofile, "%s:\t", rptr->name);
6922 if (!(flag & EX_E))
6923 return SCPE_OK;
6924 GET_RADIX (rdx, rptr->radix);
6925 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
6926 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
6927 else if (!(rptr->flags & REG_VMFLAGS) ||
6928 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
6929 NULL, sim_switches | SIM_SW_REG) > 0)) {
6930 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
6931 if (rptr->fields) {
6932 (void)Fprintf (ofile, "\t");
6933 fprint_fields (ofile, val, val, rptr->fields);
6934 }
6935 }
6936 if (flag & EX_I)
6937 (void)Fprintf (ofile, "\t");
6938 else
6939 (void)Fprintf (ofile, "\n");
6940 return SCPE_OK;
6941 }
6942
6943
6944
6945
6946
6947
6948
6949
6950
6951
6952 t_value get_rval (REG *rptr, uint32 idx)
6953 {
6954 size_t sz;
6955 t_value val;
6956 uint32 *ptr;
6957
6958 sz = SZ_R (rptr);
6959 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
6960 idx = idx + rptr->qptr;
6961 if (idx >= rptr->depth) idx = idx - rptr->depth;
6962 }
6963 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
6964 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
6965 if (sz <= sizeof (uint32))
6966 val = *ptr;
6967 else val = *((t_uint64 *) ptr);
6968 }
6969 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
6970 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
6971 if (sz <= sizeof (uint32))
6972 val = *ptr;
6973 else val = *((t_uint64 *) ptr);
6974 }
6975 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6976 (sz == sizeof (uint8)))
6977 val = *(((uint8 *) rptr->loc) + idx);
6978 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6979 (sz == sizeof (uint16)))
6980 val = *(((uint16 *) rptr->loc) + idx);
6981 else if (sz <= sizeof (uint32))
6982 val = *(((uint32 *) rptr->loc) + idx);
6983 else val = *(((t_uint64 *) rptr->loc) + idx);
6984 val = (val >> rptr->offset) & width_mask[rptr->width];
6985 return val;
6986 }
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
7000 {
7001 t_stat r;
7002 t_value val, mask;
7003 int32 rdx;
7004 CONST char *tptr;
7005 char gbuf[CBUFSIZE];
7006
7007 if ((cptr == NULL) || (rptr == NULL))
7008 return SCPE_IERR;
7009 if (rptr->flags & REG_RO)
7010 return SCPE_RO;
7011 if (flag & EX_I) {
7012 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7013 if (sim_log)
7014 (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7015 if (cptr == NULL)
7016 return 1;
7017 if (*cptr == 0)
7018 return SCPE_OK;
7019 }
7020 mask = width_mask[rptr->width];
7021 GET_RADIX (rdx, rptr->radix);
7022 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
7023 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7024 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7025 return SCPE_ARG;
7026 }
7027 else
7028 if (!(rptr->flags & REG_VMFLAGS) ||
7029 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7030 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7031 val = get_uint (cptr, rdx, mask, &r);
7032 if (r != SCPE_OK)
7033 return SCPE_ARG;
7034 }
7035 if ((rptr->flags & REG_NZ) && (val == 0))
7036 return SCPE_ARG;
7037 put_rval (rptr, idx, val);
7038 return SCPE_OK;
7039 }
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052 void put_rval (REG *rptr, uint32 idx, t_value val)
7053 {
7054 size_t sz;
7055 t_value mask;
7056 uint32 *ptr;
7057
7058 #define PUT_RVAL(sz,rp,id,v,m) \
7059 *(((sz *) rp->loc) + id) = \
7060 (sz)((*(((sz *) rp->loc) + id) & \
7061 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7062
7063 if (rptr == sim_PC)
7064 sim_brk_npc (0);
7065 sz = SZ_R (rptr);
7066 mask = width_mask[rptr->width];
7067 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7068 idx = idx + rptr->qptr;
7069 if (idx >= rptr->depth)
7070 idx = idx - rptr->depth;
7071 }
7072 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7073 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7074 if (sz <= sizeof (uint32))
7075 *ptr = (*ptr &
7076 ~(((uint32) mask) << rptr->offset)) |
7077 (((uint32) val) << rptr->offset);
7078 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7079 & ~(mask << rptr->offset)) | (val << rptr->offset);
7080 }
7081 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7082 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7083 if (sz <= sizeof (uint32))
7084 *((uint32 *) ptr) = (*((uint32 *) ptr) &
7085 ~(((uint32) mask) << rptr->offset)) |
7086 (((uint32) val) << rptr->offset);
7087 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7088 & ~(mask << rptr->offset)) | (val << rptr->offset);
7089 }
7090 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7091 (sz == sizeof (uint8)))
7092 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7093 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7094 (sz == sizeof (uint16)))
7095 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7096 else if (sz <= sizeof (uint32))
7097 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7098 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7099 return;
7100 }
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
7116 {
7117 t_stat reason;
7118 int32 rdx;
7119
7120 if (sim_vm_fprint_addr)
7121 sim_vm_fprint_addr (ofile, dptr, addr);
7122 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7123 (void)Fprintf (ofile, ":\t");
7124 if (!(flag & EX_E))
7125 return (1 - dptr->aincr);
7126
7127 GET_RADIX (rdx, dptr->dradix);
7128 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7129 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7130 reason = 1 - dptr->aincr;
7131 }
7132 if (flag & EX_I)
7133 (void)Fprintf (ofile, "\t");
7134 else
7135 (void)Fprintf (ofile, "\n");
7136 return reason;
7137 }
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
7151 {
7152 int32 i;
7153 t_value mask;
7154 t_addr j, loc;
7155 size_t sz;
7156 t_stat reason = SCPE_OK;
7157
7158 if ((dptr == NULL) || (uptr == NULL))
7159 return SCPE_IERR;
7160 mask = width_mask[dptr->dwidth];
7161 for (i = 0; i < sim_emax; i++)
7162 sim_eval[i] = 0;
7163 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7164 if (dptr->examine != NULL) {
7165 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7166 if (reason != SCPE_OK)
7167 break;
7168 }
7169 else {
7170 if (!(uptr->flags & UNIT_ATT))
7171 return SCPE_UNATT;
7172 if (uptr->dynflags & UNIT_NO_FIO)
7173 return SCPE_NOFNC;
7174 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7175 reason = SCPE_NXM;
7176 break;
7177 }
7178 sz = SZ_D (dptr);
7179 loc = j / dptr->aincr;
7180 if (uptr->flags & UNIT_BUF) {
7181 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7182 }
7183 else {
7184 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7185 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7186 if ((feof (uptr->fileref)) &&
7187 !(uptr->flags & UNIT_FIX)) {
7188 reason = SCPE_EOF;
7189 break;
7190 }
7191 else if (ferror (uptr->fileref)) {
7192 clearerr (uptr->fileref);
7193 reason = SCPE_IOERR;
7194 break;
7195 }
7196 }
7197 }
7198 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7199 }
7200 if ((reason != SCPE_OK) && (i == 0))
7201 return reason;
7202 return SCPE_OK;
7203 }
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
7220 UNIT *uptr, int32 dfltinc)
7221 {
7222 int32 i, count, rdx;
7223 t_addr j, loc;
7224 t_stat r, reason;
7225 t_value mask;
7226 size_t sz;
7227 char gbuf[CBUFSIZE];
7228
7229 if (dptr == NULL)
7230 return SCPE_IERR;
7231 if (flag & EX_I) {
7232 cptr = read_line (gbuf, sizeof(gbuf), stdin);
7233 if (sim_log)
7234 (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7235 if (cptr == NULL)
7236 return 1;
7237 if (*cptr == 0)
7238 return dfltinc;
7239 }
7240 if (uptr->flags & UNIT_RO)
7241 return SCPE_RO;
7242 mask = width_mask[dptr->dwidth];
7243
7244 GET_RADIX (rdx, dptr->dradix);
7245 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7246 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7247 if (reason != SCPE_OK)
7248 return reason;
7249 reason = dfltinc;
7250 }
7251 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7252
7253 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7254 sim_eval[i] = sim_eval[i] & mask;
7255 if (dptr->deposit != NULL) {
7256 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7257 if (r != SCPE_OK)
7258 return r;
7259 }
7260 else {
7261 if (!(uptr->flags & UNIT_ATT))
7262 return SCPE_UNATT;
7263 if (uptr->dynflags & UNIT_NO_FIO)
7264 return SCPE_NOFNC;
7265 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7266 return SCPE_NXM;
7267 sz = SZ_D (dptr);
7268 loc = j / dptr->aincr;
7269 if (uptr->flags & UNIT_BUF) {
7270 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7271 if (loc >= uptr->hwmark)
7272 uptr->hwmark = (uint32) loc + 1;
7273 }
7274 else {
7275 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7276 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7277 if (ferror (uptr->fileref)) {
7278 clearerr (uptr->fileref);
7279 return SCPE_IOERR;
7280 }
7281 }
7282 }
7283 }
7284 return reason;
7285 }
7286
7287
7288
7289 t_stat eval_cmd (int32 flg, CONST char *cptr)
7290 {
7291 if (!sim_dflt_dev)
7292 return SCPE_ARG;
7293 DEVICE *dptr = sim_dflt_dev;
7294 int32 i, rdx, a, lim;
7295 t_stat r;
7296
7297 GET_SWITCHES (cptr);
7298 GET_RADIX (rdx, dptr->dradix);
7299 for (i = 0; i < sim_emax; i++)
7300 sim_eval[i] = 0;
7301 if (*cptr == 0)
7302 return SCPE_2FARG;
7303 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7304 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7305 if (r != SCPE_OK)
7306 return r;
7307 }
7308 lim = 1 - r;
7309 for (i = a = 0; a < lim; ) {
7310 sim_printf ("%d:\t", a);
7311 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7312 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7313 if (sim_log) {
7314 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7315 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7316 }
7317 sim_printf ("\n");
7318 if (r < 0)
7319 a = a + 1 - r;
7320 else a = a + dptr->aincr;
7321 i = a / dptr->aincr;
7322 }
7323 return SCPE_OK;
7324 }
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339 char *read_line (char *cptr, int32 size, FILE *stream)
7340 {
7341 return read_line_p (NULL, cptr, size, stream);
7342 }
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
7357 {
7358 char *tptr;
7359
7360 if (prompt) {
7361 #if defined(HAVE_LINEHISTORY)
7362 char *tmpc = linenoise (prompt);
7363 if (tmpc == NULL)
7364 cptr = NULL;
7365 else {
7366 strncpy (cptr, tmpc, size-1);
7367 linenoiseHistoryAdd (tmpc);
7368 FREE (tmpc);
7369 }
7370 }
7371 #else
7372 (void)fflush (stdout);
7373 (void)printf ("%s", prompt);
7374 (void)fflush (stdout);
7375 cptr = fgets (cptr, size, stream);
7376 }
7377 #endif
7378 else cptr = fgets (cptr, size, stream);
7379
7380 if (cptr == NULL) {
7381 clearerr (stream);
7382 return NULL;
7383 }
7384 for (tptr = cptr; tptr < (cptr + size); tptr++) {
7385 if ((*tptr == '\n') || (*tptr == '\r') ||
7386 (tptr == (cptr + size - 1))) {
7387 *tptr = 0;
7388 break;
7389 }
7390 }
7391 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
7392 memmove (cptr, cptr + 3, strlen (cptr + 3));
7393 while (sim_isspace (*cptr))
7394 cptr++;
7395 if ((*cptr == ';') || (*cptr == '#')) {
7396 if (sim_do_echo)
7397 sim_printf("%s> %s\n", do_position(), cptr);
7398 *cptr = 0;
7399 }
7400
7401 return cptr;
7402 }
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
7423 {
7424 t_bool quoting = FALSE;
7425 t_bool escaping = FALSE;
7426 char quote_char = 0;
7427
7428 while ((*iptr != 0) &&
7429 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7430 if (quote) {
7431 if (quoting) {
7432 if (!escaping) {
7433 if (*iptr == escape_char)
7434 escaping = TRUE;
7435 else
7436 if (*iptr == quote_char)
7437 quoting = FALSE;
7438 }
7439 else
7440 escaping = FALSE;
7441 }
7442 else {
7443 if ((*iptr == '"') || (*iptr == '\'')) {
7444 quoting = TRUE;
7445 quote_char = *iptr;
7446 }
7447 }
7448 }
7449 if (sim_islower (*iptr) && uc)
7450 *optr = (char)toupper (*iptr);
7451 else *optr = *iptr;
7452 iptr++; optr++;
7453 }
7454 if (mchar && (*iptr == mchar))
7455 iptr++;
7456 *optr = 0;
7457 while (sim_isspace (*iptr))
7458 iptr++;
7459 return iptr;
7460 }
7461
7462 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
7463 {
7464 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7465 }
7466
7467 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
7468 {
7469 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7470 }
7471
7472 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
7473 {
7474 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7475 }
7476
7477 CONST char *get_glyph_cmd (const char *iptr, char *optr)
7478 {
7479
7480 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7481 strcpy (optr, "!");
7482 return (CONST char *)(iptr + 1);
7483 }
7484 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7485 }
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495 char *sim_trim_endspc (char *cptr)
7496 {
7497 char *tptr;
7498
7499 tptr = cptr + strlen (cptr);
7500 while ((--tptr >= cptr) && sim_isspace (*tptr))
7501 *tptr = 0;
7502 return cptr;
7503 }
7504
7505 int sim_isspace (char c)
7506 {
7507 return (c & 0x80) ? 0 : isspace (c);
7508 }
7509
7510 int sim_islower (char c)
7511 {
7512 return (c & 0x80) ? 0 : islower (c);
7513 }
7514
7515 int sim_isalpha (char c)
7516 {
7517 return (c & 0x80) ? 0 : isalpha (c);
7518 }
7519
7520 int sim_isprint (char c)
7521 {
7522 return (c & 0x80) ? 0 : isprint (c);
7523 }
7524
7525 int sim_isdigit (char c)
7526 {
7527 return (c & 0x80) ? 0 : isdigit (c);
7528 }
7529
7530 int sim_isgraph (char c)
7531 {
7532 return (c & 0x80) ? 0 : isgraph (c);
7533 }
7534
7535 int sim_isalnum (char c)
7536 {
7537 return (c & 0x80) ? 0 : isalnum (c);
7538 }
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
7552 {
7553 t_value val;
7554 CONST char *tptr;
7555
7556 *status = SCPE_OK;
7557 val = strtotv ((CONST char *)cptr, &tptr, radix);
7558 if ((cptr == tptr) || (val > max))
7559 *status = SCPE_ARG;
7560 else {
7561 while (sim_isspace (*tptr)) tptr++;
7562 if (*tptr != 0)
7563 *status = SCPE_ARG;
7564 }
7565 return val;
7566 }
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
7584 uint32 rdx, t_addr max, char term)
7585 {
7586 CONST char *tptr;
7587
7588 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
7589 tptr = cptr + strlen ("ALL");
7590 *lo = 0;
7591 *hi = max;
7592 }
7593 else {
7594 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
7595 ((cptr[1] == '\0') ||
7596 (cptr[1] == '-') ||
7597 (cptr[1] == ':') ||
7598 (cptr[1] == '/'))) {
7599 tptr = cptr + strlen (".");
7600 *lo = *hi = sim_last_addr;
7601 }
7602 else {
7603 if (strncmp (cptr, "$", strlen ("$")) == 0) {
7604 tptr = cptr + strlen ("$");
7605 *hi = *lo = (t_addr)sim_last_val;
7606 }
7607 else {
7608 if (dptr && sim_vm_parse_addr)
7609 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7610 else
7611 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7612 if (cptr == tptr)
7613 return NULL;
7614 }
7615 }
7616 if ((*tptr == '-') || (*tptr == ':')) {
7617 cptr = tptr + 1;
7618 if (dptr && sim_vm_parse_addr)
7619 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7620 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7621 if (cptr == tptr)
7622 return NULL;
7623 if (*lo > *hi)
7624 return NULL;
7625 }
7626 else if (*tptr == '/') {
7627 cptr = tptr + 1;
7628 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7629 if ((cptr == tptr) || (*hi == 0))
7630 return NULL;
7631 *hi = *lo + *hi - 1;
7632 }
7633 else *hi = *lo;
7634 }
7635 sim_last_addr = *hi;
7636 if (term && (*tptr++ != term))
7637 return NULL;
7638 return tptr;
7639 }
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7660 {
7661 char quote_char;
7662 uint8 *ostart = optr;
7663
7664 *osize = 0;
7665 if ((strlen(iptr) == 1) ||
7666 (iptr[0] != iptr[strlen(iptr)-1]) ||
7667 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7668 return SCPE_ARG;
7669 quote_char = *iptr++;
7670 while (iptr[1]) {
7671 if (*iptr != '\\') {
7672 if (*iptr == quote_char)
7673 return SCPE_ARG;
7674 *(optr++) = (uint8)(*(iptr++));
7675 continue;
7676 }
7677 ++iptr;
7678 switch (*iptr) {
7679 case 'r':
7680 *(optr++) = 13; ++iptr;
7681 break;
7682 case 'n':
7683 *(optr++) = 10; ++iptr;
7684 break;
7685 case 'f':
7686 *(optr++) = 12; ++iptr;
7687 break;
7688 case 't':
7689 *(optr++) = 9; ++iptr;
7690 break;
7691 case 'v':
7692 *(optr++) = 11; ++iptr;
7693 break;
7694 case 'b':
7695 *(optr++) = 8; ++iptr;
7696 break;
7697 case '\\':
7698 *(optr++) = 92; ++iptr;
7699 break;
7700 case 'e':
7701 *(optr++) = 27; ++iptr;
7702 break;
7703 case '\'':
7704 *(optr++) = 39; ++iptr;
7705 break;
7706 case '"':
7707 *(optr++) = 34; ++iptr;
7708 break;
7709 case '?':
7710 *(optr++) = 63; ++iptr;
7711 break;
7712 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7713 *optr = *(iptr++) - '0';
7714 if ((*iptr >= '0') && (*iptr <= '7'))
7715 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7716 if ((*iptr >= '0') && (*iptr <= '7'))
7717 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7718 ++optr;
7719 break;
7720 case 'x':
7721 if (1) {
7722 static const char *hex_digits = "0123456789ABCDEF";
7723 const char *c;
7724
7725 ++iptr;
7726 *optr = 0;
7727 c = strchr (hex_digits, toupper(*iptr));
7728 if (c) {
7729 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7730 ++iptr;
7731 }
7732 c = strchr (hex_digits, toupper(*iptr));
7733 if (c) {
7734 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7735 ++iptr;
7736 }
7737 ++optr;
7738 }
7739 break;
7740 default:
7741 return SCPE_ARG;
7742 }
7743 }
7744 *optr = '\0';
7745 *osize = (uint32)(optr-ostart);
7746 return SCPE_OK;
7747 }
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
7763 {
7764 size_t i;
7765 t_bool double_quote_found = FALSE;
7766 t_bool single_quote_found = FALSE;
7767 char quote = '"';
7768 char *tptr, *optr;
7769
7770 optr = (char *)malloc (4*size + 3);
7771 if (optr == NULL)
7772 return NULL;
7773 tptr = optr;
7774 for (i=0; i<size; i++)
7775 switch ((char)iptr[i]) {
7776 case '"':
7777 double_quote_found = TRUE;
7778 break;
7779 case '\'':
7780 single_quote_found = TRUE;
7781 break;
7782 }
7783 if (double_quote_found && (!single_quote_found))
7784 quote = '\'';
7785 *tptr++ = quote;
7786 while (size--) {
7787 switch (*iptr) {
7788 case '\r':
7789 *tptr++ = '\\'; *tptr++ = 'r'; break;
7790 case '\n':
7791 *tptr++ = '\\'; *tptr++ = 'n'; break;
7792 case '\f':
7793 *tptr++ = '\\'; *tptr++ = 'f'; break;
7794 case '\t':
7795 *tptr++ = '\\'; *tptr++ = 't'; break;
7796 case '\v':
7797 *tptr++ = '\\'; *tptr++ = 'v'; break;
7798 case '\b':
7799 *tptr++ = '\\'; *tptr++ = 'b'; break;
7800 case '\\':
7801 *tptr++ = '\\'; *tptr++ = '\\'; break;
7802 case '"':
7803 case '\'':
7804 if (quote == *iptr)
7805 *tptr++ = '\\';
7806
7807 default:
7808 if (sim_isprint (*iptr))
7809 *tptr++ = *iptr;
7810 else {
7811 (void)sprintf (tptr, "\\%03o", *iptr);
7812 tptr += 4;
7813 }
7814 break;
7815 }
7816 ++iptr;
7817 }
7818 *tptr++ = quote;
7819 *tptr++ = '\0';
7820 return optr;
7821 }
7822
7823 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
7824 {
7825 char *string;
7826
7827 string = sim_encode_quoted_string (buf, size);
7828 (void)fprintf (st, "%s", string);
7829 FREE (string);
7830 }
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840 DEVICE *find_dev (const char *cptr)
7841 {
7842 int32 i;
7843 DEVICE *dptr;
7844
7845 if (cptr == NULL)
7846 return NULL;
7847 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7848 if ((strcmp (cptr, dptr->name) == 0) ||
7849 (dptr->lname &&
7850 (strcmp (cptr, dptr->lname) == 0)))
7851 return dptr;
7852 }
7853 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7854 if ((strcmp (cptr, dptr->name) == 0) ||
7855 (dptr->lname &&
7856 (strcmp (cptr, dptr->lname) == 0)))
7857 return dptr;
7858 }
7859 return NULL;
7860 }
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873 DEVICE *find_unit (const char *cptr, UNIT **uptr)
7874 {
7875 uint32 i, u;
7876 const char *nptr;
7877 const char *tptr;
7878 t_stat r;
7879 DEVICE *dptr;
7880
7881 if (uptr == NULL)
7882 return NULL;
7883 *uptr = NULL;
7884 if ((dptr = find_dev (cptr))) {
7885 if (qdisable (dptr))
7886 return NULL;
7887 *uptr = dptr->units;
7888 return dptr;
7889 }
7890
7891 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7892 if (qdisable (dptr))
7893 continue;
7894 if (dptr->numunits &&
7895 (((nptr = dptr->name) &&
7896 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
7897 ((nptr = dptr->lname) &&
7898 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
7899 tptr = cptr + strlen (nptr);
7900 if (sim_isdigit (*tptr)) {
7901 if (qdisable (dptr))
7902 return NULL;
7903 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
7904 if (r != SCPE_OK)
7905 *uptr = NULL;
7906 else
7907 *uptr = dptr->units + u;
7908 return dptr;
7909 }
7910 }
7911 for (u = 0; u < dptr->numunits; u++) {
7912 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
7913 *uptr = &dptr->units[u];
7914 return dptr;
7915 }
7916 }
7917 }
7918 return NULL;
7919 }
7920
7921
7922
7923
7924
7925
7926
7927 t_stat sim_register_internal_device (DEVICE *dptr)
7928 {
7929 uint32 i;
7930
7931 for (i = 0; (sim_devices[i] != NULL); i++)
7932 if (sim_devices[i] == dptr)
7933 return SCPE_OK;
7934 for (i = 0; i < sim_internal_device_count; i++)
7935 if (sim_internal_devices[i] == dptr)
7936 return SCPE_OK;
7937 ++sim_internal_device_count;
7938 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
7939 if (!sim_internal_devices)
7940 {
7941 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7942 __func__, __FILE__, __LINE__);
7943 #if defined(USE_BACKTRACE)
7944 # if defined(SIGUSR2)
7945 (void)raise(SIGUSR2);
7946
7947 # endif
7948 #endif
7949 abort();
7950 }
7951 sim_internal_devices[sim_internal_device_count-1] = dptr;
7952 sim_internal_devices[sim_internal_device_count] = NULL;
7953 return SCPE_OK;
7954 }
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964 DEVICE *find_dev_from_unit (UNIT *uptr)
7965 {
7966 DEVICE *dptr;
7967 uint32 i, j;
7968
7969 if (uptr == NULL)
7970 return NULL;
7971 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7972 for (j = 0; j < dptr->numunits; j++) {
7973 if (uptr == (dptr->units + j))
7974 return dptr;
7975 }
7976 }
7977 for (i = 0; i<sim_internal_device_count; i++) {
7978 dptr = sim_internal_devices[i];
7979 for (j = 0; j < dptr->numunits; j++) {
7980 if (uptr == (dptr->units + j))
7981 return dptr;
7982 }
7983 }
7984 return NULL;
7985 }
7986
7987
7988
7989 t_bool qdisable (DEVICE *dptr)
7990 {
7991 return (dptr->flags & DEV_DIS? TRUE: FALSE);
7992 }
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
8005
8006 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
8007 {
8008 int32 i;
8009 DEVICE *dptr;
8010 REG *rptr, *srptr = NULL;
8011
8012 *gdptr = NULL;
8013 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
8014 if (dptr->flags & DEV_DIS)
8015 continue;
8016 if ((rptr = find_reg (cptr, optr, dptr))) {
8017 if (srptr)
8018 return NULL;
8019 srptr = rptr;
8020 *gdptr = dptr;
8021 }
8022 }
8023 return srptr;
8024 }
8025
8026
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
8038 {
8039 CONST char *tptr;
8040 REG *rptr;
8041 size_t slnt;
8042
8043 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8044 return NULL;
8045 tptr = cptr;
8046 do {
8047 tptr++;
8048 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8049 slnt = tptr - cptr;
8050 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8051 if ((slnt == strlen (rptr->name)) &&
8052 (strncmp (cptr, rptr->name, slnt) == 0)) {
8053 if (optr != NULL)
8054 *optr = tptr;
8055 return rptr;
8056 }
8057 }
8058 return NULL;
8059 }
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070 int32 get_switches (const char *cptr)
8071 {
8072 int32 sw;
8073
8074 if (*cptr != '-')
8075 return 0;
8076 sw = 0;
8077 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8078 if (sim_isalpha (*cptr) == 0)
8079 return -1;
8080 sw = sw | SWMASK (toupper (*cptr));
8081 }
8082 return sw;
8083 }
8084
8085
8086
8087
8088
8089
8090
8091
8092
8093
8094 CONST char *get_sim_sw (CONST char *cptr)
8095 {
8096 int32 lsw;
8097 char gbuf[CBUFSIZE];
8098
8099 while (*cptr == '-') {
8100 cptr = get_glyph (cptr, gbuf, 0);
8101 lsw = get_switches (gbuf);
8102 if (lsw <= 0)
8103 return NULL;
8104 sim_switches = sim_switches | lsw;
8105 }
8106 return cptr;
8107 }
8108
8109
8110
8111
8112
8113
8114
8115
8116
8117
8118
8119 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
8120 {
8121 int32 t;
8122 char gbuf[CBUFSIZE];
8123 CONST char *svptr;
8124 DEVICE *tdptr;
8125 UNIT *tuptr;
8126
8127 sim_switches = 0;
8128 sim_ofile = NULL;
8129 sim_schrptr = NULL;
8130 sim_schaptr = NULL;
8131 sim_stabr.logic = sim_staba.logic = SCH_OR;
8132 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8133 sim_stabr.count = 1;
8134 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8135 if (!sim_stabr.mask)
8136 {
8137 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8138 __func__, __FILE__, __LINE__);
8139 #if defined(USE_BACKTRACE)
8140 # if defined(SIGUSR2)
8141 (void)raise(SIGUSR2);
8142
8143 # endif
8144 #endif
8145 abort();
8146 }
8147 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8148 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8149 if (!sim_stabr.comp)
8150 {
8151 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8152 __func__, __FILE__, __LINE__);
8153 #if defined(USE_BACKTRACE)
8154 # if defined(SIGUSR2)
8155 (void)raise(SIGUSR2);
8156
8157 # endif
8158 #endif
8159 abort();
8160 }
8161 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8162 sim_staba.count = sim_emax;
8163 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8164 if (!sim_staba.mask)
8165 {
8166 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8167 __func__, __FILE__, __LINE__);
8168 #if defined(USE_BACKTRACE)
8169 # if defined(SIGUSR2)
8170 (void)raise(SIGUSR2);
8171
8172 # endif
8173 #endif
8174 abort();
8175 }
8176 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8177 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8178 if (!sim_staba.comp)
8179 {
8180 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8181 __func__, __FILE__, __LINE__);
8182 #if defined(USE_BACKTRACE)
8183 # if defined(SIGUSR2)
8184 (void)raise(SIGUSR2);
8185
8186 # endif
8187 #endif
8188 abort();
8189 }
8190 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8191 if (! sim_dflt_dev)
8192 return NULL;
8193 sim_dfdev = sim_dflt_dev;
8194 sim_dfunit = sim_dfdev->units;
8195 sim_opt_out = 0;
8196 *st = SCPE_OK;
8197 while (*cptr) {
8198 svptr = cptr;
8199 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
8200 if (sim_ofile) {
8201 fclose (sim_ofile);
8202 *st = SCPE_ARG;
8203 return NULL;
8204 }
8205 cptr = get_glyph (cptr + 1, gbuf, 0);
8206 sim_ofile = sim_fopen (gbuf, "a");
8207 if (sim_ofile == NULL) {
8208 *st = SCPE_OPENERR;
8209 return NULL;
8210 }
8211 sim_opt_out |= CMD_OPT_OF;
8212 continue;
8213 }
8214 cptr = get_glyph (cptr, gbuf, 0);
8215 if ((t = get_switches (gbuf)) != 0) {
8216 if (t < 0) {
8217 *st = SCPE_INVSW;
8218 return NULL;
8219 }
8220 sim_switches = sim_switches | t;
8221 }
8222 else if ((opt & CMD_OPT_SCH) &&
8223 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
8224 sim_schrptr = &sim_stabr;
8225 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
8226 sim_opt_out |= CMD_OPT_SCH;
8227 }
8228 else if ((opt & CMD_OPT_DFT) &&
8229 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
8230 (tdptr = find_unit (gbuf, &tuptr)) &&
8231 (tuptr != NULL)) {
8232 sim_dfdev = tdptr;
8233 sim_dfunit = tuptr;
8234 sim_opt_out |= CMD_OPT_DFT;
8235 }
8236 else return svptr;
8237 }
8238 return cptr;
8239 }
8240
8241
8242
8243
8244
8245
8246
8247
8248
8249
8250
8251 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
8252 {
8253 char *optr = buf;
8254 int32 bit;
8255
8256 (void)memset (buf, 0, bufsize);
8257 if ((sw == 0) || (bufsize < 3))
8258 return buf;
8259 --bufsize;
8260 *optr++ = '-';
8261 for (bit=0; bit <= ('Z'-'A'); bit++)
8262 if (sw & (1 << bit))
8263 if ((size_t)(optr - buf) < bufsize)
8264 *optr++ = 'A' + bit;
8265 return buf;
8266 }
8267
8268
8269
8270
8271
8272
8273
8274
8275
8276
8277
8278
8279 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8280 {
8281 int32 c;
8282 size_t logop, cmpop;
8283 t_value logval, cmpval;
8284 const char *sptr;
8285 CONST char *tptr;
8286 const char logstr[] = "|&^", cmpstr[] = "=!><";
8287
8288 const size_t invalid_op = (size_t) -1;
8289
8290 logval = cmpval = 0;
8291 if (*cptr == 0)
8292 return NULL;
8293
8294 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8295 if ((sptr = strchr (logstr, c))) {
8296 logop = sptr - logstr;
8297 logval = strtotv (cptr, &tptr, radix);
8298 if (cptr == tptr)
8299 return NULL;
8300 cptr = tptr;
8301 }
8302 else if ((sptr = strchr (cmpstr, c))) {
8303 cmpop = sptr - cmpstr;
8304 if (*cptr == '=') {
8305 cmpop = cmpop + strlen (cmpstr);
8306 cptr++;
8307 }
8308 cmpval = strtotv (cptr, &tptr, radix);
8309 if (cptr == tptr)
8310 return NULL;
8311 cptr = tptr;
8312 }
8313 else return NULL;
8314 }
8315 if (schptr->count != 1) {
8316 FREE (schptr->mask);
8317 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8318 FREE (schptr->comp);
8319 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8320 }
8321 if (logop != invalid_op) {
8322 schptr->logic = logop;
8323 schptr->mask[0] = logval;
8324 }
8325 if (cmpop != invalid_op) {
8326 schptr->boolop = cmpop;
8327 schptr->comp[0] = cmpval;
8328 }
8329 schptr->count = 1;
8330 return schptr;
8331 }
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
8345 {
8346 int32 c;
8347 size_t logop, cmpop;
8348 t_value *logval, *cmpval;
8349 t_stat reason = SCPE_OK;
8350 CONST char *ocptr = cptr;
8351 const char *sptr;
8352 char gbuf[CBUFSIZE];
8353 const char logstr[] = "|&^", cmpstr[] = "=!><";
8354
8355 const size_t invalid_op = (size_t) -1;
8356
8357 if (*cptr == 0)
8358 return NULL;
8359 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8360 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8361
8362 for (logop = cmpop = invalid_op; (c = *cptr++); ) {
8363 if (NULL != (sptr = strchr (logstr, c))) {
8364 logop = sptr - logstr;
8365 cptr = get_glyph (cptr, gbuf, 0);
8366 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8367 if (reason > 0) {
8368 FREE (logval);
8369 FREE (cmpval);
8370 return get_rsearch (ocptr, radix, schptr);
8371 }
8372 }
8373 else if (NULL != (sptr = strchr (cmpstr, c))) {
8374 cmpop = sptr - cmpstr;
8375 if (*cptr == '=') {
8376 cmpop = cmpop + strlen (cmpstr);
8377 cptr++;
8378 }
8379 cptr = get_glyph (cptr, gbuf, 0);
8380 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8381 if (reason > 0) {
8382 FREE (logval);
8383 FREE (cmpval);
8384 return get_rsearch (ocptr, radix, schptr);
8385 }
8386 }
8387 else {
8388 FREE (logval);
8389 FREE (cmpval);
8390 return NULL;
8391 }
8392 }
8393 if (schptr->count != (uint32)(1 - reason)) {
8394 schptr->count = 1 - reason;
8395 FREE (schptr->mask);
8396 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8397 FREE (schptr->comp);
8398 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8399 }
8400 if (logop != invalid_op) {
8401 schptr->logic = logop;
8402 FREE (schptr->mask);
8403 schptr->mask = logval;
8404 }
8405 else {
8406 FREE (logval);
8407 }
8408 if (cmpop != invalid_op) {
8409 schptr->boolop = cmpop;
8410 FREE (schptr->comp);
8411 schptr->comp = cmpval;
8412 }
8413 else {
8414 FREE (cmpval);
8415 }
8416 return schptr;
8417 }
8418
8419
8420
8421
8422
8423
8424
8425
8426
8427
8428 int32 test_search (t_value *values, SCHTAB *schptr)
8429 {
8430 t_value *val = NULL;
8431 int32 i, updown;
8432 int32 ret = 0;
8433
8434 if (schptr == NULL)
8435 return ret;
8436
8437 val = (t_value *)malloc (schptr->count * sizeof (*values));
8438 if (!val)
8439 {
8440 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8441 __func__, __FILE__, __LINE__);
8442 #if defined(USE_BACKTRACE)
8443 # if defined(SIGUSR2)
8444 (void)raise(SIGUSR2);
8445
8446 # endif
8447 #endif
8448 abort();
8449 }
8450 for (i=0; i<(int32)schptr->count; i++) {
8451 val[i] = values[i];
8452 switch (schptr->logic) {
8453
8454 case SCH_OR:
8455 val[i] = val[i] | schptr->mask[i];
8456 break;
8457
8458 case SCH_AND:
8459 val[i] = val[i] & schptr->mask[i];
8460 break;
8461
8462 case SCH_XOR:
8463 val[i] = val[i] ^ schptr->mask[i];
8464 break;
8465 }
8466 }
8467
8468 ret = 1;
8469 if (1) {
8470 updown = -1;
8471 i=schptr->count-1;
8472 }
8473 else {
8474 updown = 1;
8475 i=0;
8476 }
8477 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8478 switch (schptr->boolop) {
8479
8480 case SCH_E: case SCH_EE:
8481 if (val[i] != schptr->comp[i])
8482 ret = 0;
8483 break;
8484
8485 case SCH_N: case SCH_NE:
8486 if (val[i] == schptr->comp[i])
8487 ret = 0;
8488 break;
8489
8490 case SCH_G:
8491 if (val[i] <= schptr->comp[i])
8492 ret = 0;
8493 break;
8494
8495 case SCH_GE:
8496 if (val[i] < schptr->comp[i])
8497 ret = 0;
8498 break;
8499
8500 case SCH_L:
8501 if (val[i] >= schptr->comp[i])
8502 ret = 0;
8503 break;
8504
8505 case SCH_LE:
8506 if (val[i] > schptr->comp[i])
8507 ret = 0;
8508 break;
8509 }
8510 }
8511 FREE (val);
8512 return ret;
8513 }
8514
8515
8516
8517
8518
8519
8520
8521
8522
8523
8524
8525
8526
8527
8528
8529 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
8530 {
8531 int32 nodigit;
8532 t_value val;
8533 uint32 c, digit;
8534
8535 *endptr = inptr;
8536 if ((radix < 2) || (radix > 36))
8537 return 0;
8538 while (sim_isspace (*inptr))
8539 inptr++;
8540 val = 0;
8541 nodigit = 1;
8542 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
8543 if (sim_islower (c))
8544 c = toupper (c);
8545 if (sim_isdigit (c))
8546 digit = c - (uint32) '0';
8547 else if (radix <= 10)
8548 break;
8549 else digit = c + 10 - (uint32) 'A';
8550 if (digit >= radix)
8551 return 0;
8552 val = (val * radix) + digit;
8553 nodigit = 0;
8554 }
8555 if (nodigit)
8556 return 0;
8557 *endptr = inptr;
8558 return val;
8559 }
8560
8561
8562
8563
8564
8565
8566
8567
8568
8569
8570
8571
8572
8573
8574
8575 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
8576 size_t width, uint32 format)
8577 {
8578 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8579 t_value owtest, wtest;
8580 size_t d;
8581 size_t digit;
8582 size_t ndigits;
8583 size_t commas = 0;
8584 char dbuf[MAX_WIDTH + 1];
8585
8586 for (d = 0; d < MAX_WIDTH; d++)
8587 dbuf[d] = (format == PV_RZRO)? '0': ' ';
8588 dbuf[MAX_WIDTH] = 0;
8589 d = MAX_WIDTH;
8590 do {
8591 d = d - 1;
8592 digit = val % radix;
8593 val = val / radix;
8594 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8595 } while ((d > 0) && (val != 0));
8596
8597 switch (format) {
8598 case PV_LEFT:
8599 break;
8600 case PV_RZRO:
8601 wtest = owtest = radix;
8602 ndigits = 1;
8603 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8604 owtest = wtest;
8605 wtest = wtest * radix;
8606 ndigits = ndigits + 1;
8607 }
8608 if ((MAX_WIDTH - (ndigits + commas)) < d)
8609 d = MAX_WIDTH - (ndigits + commas);
8610 break;
8611 }
8612 if (NULL == buffer)
8613 return ((t_stat) strlen(dbuf+d));
8614 *buffer = '\0';
8615 if (width < strlen(dbuf+d))
8616 return SCPE_IOERR;
8617 strcpy(buffer, dbuf+d);
8618 return SCPE_OK;
8619 }
8620
8621 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8622 uint32 width, uint32 format)
8623 {
8624 char dbuf[MAX_WIDTH + 1];
8625
8626 if (!stream)
8627 return sprint_val (NULL, val, radix, width, format);
8628 if (width > MAX_WIDTH)
8629 width = MAX_WIDTH;
8630 sprint_val (dbuf, val, radix, width, format);
8631 if (Fprintf (stream, "%s", dbuf) < 0)
8632 return SCPE_IOERR;
8633 return SCPE_OK;
8634 }
8635
8636 const char *sim_fmt_secs (double seconds)
8637 {
8638 static char buf[60];
8639 char frac[16] = "";
8640 const char *sign = "";
8641 double val = seconds;
8642 double days, hours, mins, secs, msecs, usecs;
8643
8644 if (val == 0.0)
8645 return "";
8646 if (val < 0.0) {
8647 sign = "-";
8648 val = -val;
8649 }
8650 days = floor (val / (24.0*60.0*60.0));
8651 val -= (days * 24.0*60.0*60.0);
8652 hours = floor (val / (60.0*60.0));
8653 val -= (hours * 60.0 * 60.0);
8654 mins = floor (val / 60.0);
8655 val -= (mins * 60.0);
8656 secs = floor (val);
8657 val -= secs;
8658 val *= 1000.0;
8659 msecs = floor (val);
8660 val -= msecs;
8661 val *= 1000.0;
8662 usecs = floor (val+0.5);
8663 if (usecs == 1000.0) {
8664 usecs = 0.0;
8665 msecs += 1;
8666 }
8667 if ((msecs > 0.0) || (usecs > 0.0)) {
8668 (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8669 while (frac[strlen (frac) - 1] == '0')
8670 frac[strlen (frac) - 1] = '\0';
8671 if (strlen (frac) == 1)
8672 frac[0] = '\0';
8673 }
8674 if (days > 0)
8675 (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8676 sign, days, (days != 1) ? "s" : "", hours, mins,
8677 secs, frac, (days == 1) ? "s" : "");
8678 else
8679 if (hours > 0)
8680 (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8681 sign, hours, mins, secs, frac);
8682 else
8683 if (mins > 0)
8684 (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8685 sign, mins, secs, frac);
8686 else
8687 if (secs > 0)
8688 (void)sprintf (buf, "%s%.0f%s second",
8689 sign, secs, frac);
8690 else
8691 if (msecs > 0) {
8692 if (usecs > 0)
8693 (void)sprintf (buf, "%s%.0f.%s msec",
8694 sign, msecs, frac+4);
8695 else
8696 (void)sprintf (buf, "%s%.0f msec",
8697 sign, msecs);
8698 }
8699 else
8700 (void)sprintf (buf, "%s%.0f usec",
8701 sign, usecs);
8702 if (0 != strncmp ("1 ", buf, 2))
8703 strcpy (&buf[strlen (buf)], "s");
8704 return buf;
8705 }
8706
8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
8722 t_stat sim_process_event (void)
8723 {
8724 UNIT *uptr;
8725 t_stat reason;
8726 #if defined(TESTING)
8727 cpu_state_t * cpup = _cpup;
8728 #endif
8729
8730 if (stop_cpu)
8731 {
8732 #if defined(WIN_STDIO)
8733 (void)fflush(stdout);
8734 (void)fflush(stderr);
8735 #endif
8736 return SCPE_STOP;
8737 }
8738 UPDATE_SIM_TIME;
8739
8740 if (sim_clock_queue == QUEUE_LIST_END) {
8741 sim_interval = noqueue_time = NOQUEUE_WAIT;
8742 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8743 "Queue Empty New Interval = %d\n",
8744 sim_interval);
8745 return SCPE_OK;
8746 }
8747 sim_processing_event = TRUE;
8748 do {
8749 uptr = sim_clock_queue;
8750 sim_clock_queue = uptr->next;
8751 uptr->next = NULL;
8752 sim_interval -= uptr->time;
8753 uptr->time = 0;
8754 if (sim_clock_queue != QUEUE_LIST_END)
8755 sim_interval = sim_clock_queue->time;
8756 else
8757 sim_interval = noqueue_time = NOQUEUE_WAIT;
8758 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8759 "Processing Event for %s\n", sim_uname (uptr));
8760 if (uptr->action != NULL)
8761 reason = uptr->action (uptr);
8762 else
8763 reason = SCPE_OK;
8764 } while ((reason == SCPE_OK) &&
8765 (sim_interval <= 0) &&
8766 (sim_clock_queue != QUEUE_LIST_END) &&
8767 (!stop_cpu));
8768
8769 if (sim_clock_queue == QUEUE_LIST_END) {
8770 sim_interval = noqueue_time = NOQUEUE_WAIT;
8771 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8772 "Processing Queue Complete New Interval = %d\n",
8773 sim_interval);
8774 }
8775 else
8776 sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8777 "Processing Queue Complete New Interval = %d(%s)\n",
8778 sim_interval, sim_uname(sim_clock_queue));
8779
8780 if ((reason == SCPE_OK) && stop_cpu)
8781 {
8782 #if defined(WIN_STDIO)
8783 (void)fflush(stdout);
8784 (void)fflush(stderr);
8785 #endif
8786 reason = SCPE_STOP;
8787 }
8788 sim_processing_event = FALSE;
8789 return reason;
8790 }
8791
8792
8793
8794
8795
8796
8797
8798
8799
8800
8801 t_stat sim_activate (UNIT *uptr, int32 event_time)
8802 {
8803 if (uptr->dynflags & UNIT_TMR_UNIT)
8804 return sim_timer_activate (uptr, event_time);
8805 return _sim_activate (uptr, event_time);
8806 }
8807
8808 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8809 {
8810 UNIT *cptr, *prvptr;
8811 int32 accum;
8812 #if defined(TESTING)
8813 cpu_state_t * cpup = _cpup;
8814 #endif
8815
8816 if (sim_is_active (uptr))
8817 return SCPE_OK;
8818 UPDATE_SIM_TIME;
8819
8820 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\n", sim_uname (uptr), event_time);
8821
8822 prvptr = NULL;
8823 accum = 0;
8824 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8825 if (event_time < (accum + cptr->time))
8826 break;
8827 accum = accum + cptr->time;
8828 prvptr = cptr;
8829 }
8830 if (prvptr == NULL) {
8831 cptr = uptr->next = sim_clock_queue;
8832 sim_clock_queue = uptr;
8833 }
8834 else {
8835 cptr = uptr->next = prvptr->next;
8836 prvptr->next = uptr;
8837 }
8838 uptr->time = event_time - accum;
8839 if (cptr != QUEUE_LIST_END)
8840 cptr->time = cptr->time - uptr->time;
8841 sim_interval = sim_clock_queue->time;
8842 return SCPE_OK;
8843 }
8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
8855 {
8856 sim_cancel (uptr);
8857 return _sim_activate (uptr, event_time);
8858 }
8859
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
8870 {
8871 return _sim_activate_after (uptr, usec_delay);
8872 }
8873
8874 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
8875 {
8876 if (sim_is_active (uptr))
8877 return SCPE_OK;
8878 return sim_timer_activate_after (uptr, usec_delay);
8879 }
8880
8881
8882
8883
8884
8885
8886
8887
8888
8889
8890 t_stat sim_cancel (UNIT *uptr)
8891 {
8892 UNIT *cptr, *nptr;
8893 #if defined(TESTING)
8894 cpu_state_t * cpup = _cpup;
8895 #endif
8896
8897 if (sim_clock_queue == QUEUE_LIST_END)
8898 return SCPE_OK;
8899 if (!sim_is_active (uptr))
8900 return SCPE_OK;
8901 UPDATE_SIM_TIME;
8902 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr));
8903 nptr = QUEUE_LIST_END;
8904
8905 if (sim_clock_queue == uptr) {
8906 nptr = sim_clock_queue = uptr->next;
8907 uptr->next = NULL;
8908 }
8909 else {
8910 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8911 if (cptr->next == uptr) {
8912 nptr = cptr->next = uptr->next;
8913 uptr->next = NULL;
8914 break;
8915 }
8916 }
8917 }
8918 if (nptr != QUEUE_LIST_END)
8919 nptr->time += (uptr->next) ? 0 : uptr->time;
8920 if (!uptr->next)
8921 uptr->time = 0;
8922 if (sim_clock_queue != QUEUE_LIST_END)
8923 sim_interval = sim_clock_queue->time;
8924 else sim_interval = noqueue_time = NOQUEUE_WAIT;
8925 if (uptr->next) {
8926 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
8927 if (sim_deb)
8928 fclose(sim_deb);
8929 (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
8930 __func__, __FILE__, __LINE__);
8931 abort ();
8932 }
8933 return SCPE_OK;
8934 }
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944 t_bool sim_is_active (UNIT *uptr)
8945 {
8946 if (uptr->next == NULL)
8947 return FALSE;
8948 else
8949 return TRUE;
8950 }
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960 int32 sim_activate_time (UNIT *uptr)
8961 {
8962 UNIT *cptr;
8963 int32 accum = 0;
8964
8965 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8966 if (cptr == sim_clock_queue) {
8967 if (sim_interval > 0)
8968 accum = accum + sim_interval;
8969 }
8970 else
8971 accum = accum + cptr->time;
8972 if (cptr == uptr)
8973 return accum + 1;
8974 }
8975 return 0;
8976 }
8977
8978
8979
8980
8981
8982
8983
8984
8985 double sim_gtime (void)
8986 {
8987 return sim_time;
8988 }
8989
8990
8991
8992
8993
8994
8995
8996
8997 int32 sim_qcount (void)
8998 {
8999 int32 cnt;
9000 UNIT *uptr;
9001
9002 cnt = 0;
9003 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9004 cnt++;
9005 return cnt;
9006 }
9007
9008
9009
9010
9011
9012
9013
9014
9015
9016
9017
9018
9019
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029
9030
9031
9032
9033
9034
9035
9036
9037
9038
9039
9040
9041
9042
9043 t_stat sim_brk_init (void)
9044 {
9045 int32 i;
9046
9047 for (i=0; i<sim_brk_lnt; i++) {
9048 BRKTAB *bp;
9049 if (sim_brk_tab)
9050 {
9051 bp = sim_brk_tab[i];
9052
9053 while (bp)
9054 {
9055 BRKTAB *bpt = bp->next;
9056
9057 FREE (bp->act);
9058 FREE (bp);
9059 bp = bpt;
9060 }
9061 }
9062 }
9063 if (sim_brk_tab != NULL)
9064 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9065 sim_brk_lnt = SIM_BRK_INILNT;
9066 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9067 if (sim_brk_tab == NULL)
9068 return SCPE_MEM;
9069 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9070 sim_brk_ent = sim_brk_ins = 0;
9071 sim_brk_clract ();
9072 sim_brk_npc (0);
9073 return SCPE_OK;
9074 }
9075
9076
9077
9078 BRKTAB *sim_brk_fnd (t_addr loc)
9079 {
9080 int32 lo, hi, p;
9081 BRKTAB *bp;
9082
9083 if (sim_brk_ent == 0) {
9084 sim_brk_ins = 0;
9085 return NULL;
9086 }
9087 lo = 0;
9088 hi = sim_brk_ent - 1;
9089 do {
9090 p = (lo + hi) >> 1;
9091 bp = sim_brk_tab[p];
9092 if (loc == bp->addr) {
9093 sim_brk_ins = p;
9094 return bp;
9095 }
9096 else if (loc < bp->addr)
9097 hi = p - 1;
9098 else lo = p + 1;
9099 } while (lo <= hi);
9100 if (loc < bp->addr)
9101 sim_brk_ins = p;
9102 else sim_brk_ins = p + 1;
9103 return NULL;
9104 }
9105
9106 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
9107 {
9108 BRKTAB *bp = sim_brk_fnd (loc);
9109
9110 while (bp) {
9111 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9112 (bp->typ == btyp))
9113 return bp;
9114 bp = bp->next;
9115 }
9116 return bp;
9117 }
9118
9119
9120
9121 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
9122 {
9123 int32 i, t;
9124 BRKTAB *bp, **newp;
9125
9126 if (sim_brk_ins < 0)
9127 return NULL;
9128 if (sim_brk_ent >= sim_brk_lnt) {
9129 t = sim_brk_lnt + SIM_BRK_INILNT;
9130 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
9131 if (newp == NULL)
9132 return NULL;
9133 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
9134 (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
9135 FREE (sim_brk_tab);
9136 sim_brk_tab = newp;
9137 sim_brk_lnt = t;
9138 }
9139 if ((sim_brk_ins == sim_brk_ent) ||
9140 ((sim_brk_ins != sim_brk_ent) &&
9141 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
9142 for (i = sim_brk_ent; i > sim_brk_ins; --i)
9143 sim_brk_tab[i] = sim_brk_tab[i - 1];
9144 sim_brk_tab[sim_brk_ins] = NULL;
9145 }
9146 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9147 if (!bp)
9148 {
9149 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9150 __func__, __FILE__, __LINE__);
9151 #if defined(USE_BACKTRACE)
9152 # if defined(SIGUSR2)
9153 (void)raise(SIGUSR2);
9154
9155 # endif
9156 #endif
9157 abort();
9158 }
9159 bp->next = sim_brk_tab[sim_brk_ins];
9160 sim_brk_tab[sim_brk_ins] = bp;
9161 if (bp->next == NULL)
9162 sim_brk_ent += 1;
9163 bp->addr = loc;
9164 bp->typ = btyp;
9165 bp->cnt = 0;
9166 bp->act = NULL;
9167 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9168 bp->time_fired[i] = -1.0;
9169 return bp;
9170 }
9171
9172
9173
9174 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
9175 {
9176 BRKTAB *bp;
9177
9178 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9179 sw |= sim_brk_dflt;
9180 if (~sim_brk_types & sw) {
9181 char gbuf[CBUFSIZE];
9182
9183 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9184 }
9185 if ((sw & BRK_TYP_DYN_ALL) && act)
9186 return SCPE_ARG;
9187 bp = sim_brk_fnd (loc);
9188 if (!bp)
9189 bp = sim_brk_new (loc, sw);
9190 else {
9191 while (bp && (bp->typ != (uint32)sw))
9192 bp = bp->next;
9193 if (!bp)
9194 bp = sim_brk_new (loc, sw);
9195 }
9196 if (!bp)
9197 return SCPE_MEM;
9198 bp->cnt = ncnt;
9199 if ((!(sw & BRK_TYP_DYN_ALL)) &&
9200 (bp->act != NULL) && (act != NULL)) {
9201 FREE (bp->act);
9202 bp->act = NULL;
9203 }
9204 if ((act != NULL) && (*act != 0)) {
9205 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
9206 if (newp == NULL)
9207 return SCPE_MEM;
9208 strncpy (newp, act, CBUFSIZE);
9209 bp->act = newp;
9210 }
9211 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9212 return SCPE_OK;
9213 }
9214
9215
9216
9217 t_stat sim_brk_clr (t_addr loc, int32 sw)
9218 {
9219 BRKTAB *bpl = NULL;
9220 BRKTAB *bp = sim_brk_fnd (loc);
9221 int32 i;
9222
9223 if (!bp)
9224 return SCPE_OK;
9225 if (sw == 0)
9226 sw = SIM_BRK_ALLTYP;
9227
9228 #if !defined(__clang_analyzer__)
9229 while (bp) {
9230 if (bp->typ == (bp->typ & sw)) {
9231 FREE (bp->act);
9232 if (bp == sim_brk_tab[sim_brk_ins])
9233 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9234 else
9235 {
9236 if (bpl)
9237 bpl->next = bp->next;
9238 }
9239 FREE (bp);
9240 bp = bpl;
9241 }
9242 else {
9243 bpl = bp;
9244 bp = bp->next;
9245 }
9246 }
9247 #endif
9248 if (sim_brk_tab[sim_brk_ins] == NULL) {
9249 sim_brk_ent = sim_brk_ent - 1;
9250 for (i = sim_brk_ins; i < sim_brk_ent; i++)
9251 sim_brk_tab[i] = sim_brk_tab[i+1];
9252 }
9253 sim_brk_summ = 0;
9254 for (i = 0; i < sim_brk_ent; i++) {
9255 bp = sim_brk_tab[i];
9256 while (bp) {
9257 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9258 bp = bp->next;
9259 }
9260 }
9261 return SCPE_OK;
9262 }
9263
9264
9265
9266 t_stat sim_brk_clrall (int32 sw)
9267 {
9268 int32 i;
9269
9270 if (sw == 0)
9271 sw = SIM_BRK_ALLTYP;
9272 for (i = 0; i < sim_brk_ent;) {
9273 t_addr loc = sim_brk_tab[i]->addr;
9274 sim_brk_clr (loc, sw);
9275 if ((i < sim_brk_ent) &&
9276 (loc == sim_brk_tab[i]->addr))
9277 ++i;
9278 }
9279 return SCPE_OK;
9280 }
9281
9282
9283
9284 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
9285 {
9286 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9287 DEVICE *dptr;
9288 uint32 i, any;
9289
9290 if ((sw == 0) || (sw == SWMASK ('C'))) {
9291 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9292 if (!bp || (!(bp->typ & sw))) {
9293 return SCPE_OK; }
9294 dptr = sim_dflt_dev;
9295 if (dptr == NULL) {
9296 return SCPE_OK; }
9297 if (sw & SWMASK ('C')) {
9298 if (st != NULL) {
9299 (void)fprintf (st, "SET BREAK "); }
9300 } else {
9301 if (sim_vm_fprint_addr) {
9302 sim_vm_fprint_addr
9303 (st, dptr, loc);
9304 } else {
9305 fprint_val
9306 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9307 if (st != NULL) {
9308 (void)fprintf (st, ":\t"); }
9309 }
9310 for (i = any = 0; i < 26; i++) {
9311 if ((bp->typ >> i) & 1) {
9312 if ((sw & SWMASK ('C')) == 0) {
9313 if (any) {
9314 if (st != NULL) {
9315 (void)fprintf (st, ", "); } }
9316 if (st != NULL) {
9317 fputc (i + 'A', st); }
9318 }
9319 } else {
9320 if (st != NULL) {
9321 (void)fprintf (st, "-%c", i + 'A'); }
9322 any = 1;
9323 }
9324 }
9325 if (sw & SWMASK ('C')) {
9326 if (st != NULL) {
9327 (void)fprintf (st, " "); }
9328 if (sim_vm_fprint_addr) {
9329 if (st != NULL) {
9330 sim_vm_fprint_addr (st, dptr, loc); }
9331 } else {
9332 fprint_val
9333 (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9334 }
9335 if (bp->cnt > 0) {
9336 if (st != NULL) {
9337 (void)fprintf (st, "[%d]", bp->cnt); } }
9338 if (bp->act != NULL) {
9339 if (st != NULL) {
9340 (void)fprintf (st, "; %s", bp->act); } }
9341 (void)fprintf (st, "\n");
9342 return SCPE_OK;
9343 }
9344
9345
9346
9347 t_stat sim_brk_showall (FILE *st, uint32 sw)
9348 {
9349 int32 bit, mask, types;
9350 BRKTAB **bpt;
9351
9352 if ((sw == 0) || (sw == SWMASK ('C')))
9353 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9354 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9355 if (sim_brk_types & (1 << bit))
9356 ++types;
9357 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9358 (void)fprintf (st, "Supported Breakpoint Types:");
9359 for (bit=0; bit <= ('Z'-'A'); bit++)
9360 if (sim_brk_types & (1 << bit))
9361 (void)fprintf (st, " -%c", 'A' + bit);
9362 (void)fprintf (st, "\n");
9363 }
9364 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9365 mask = (sw & sim_brk_types);
9366 (void)fprintf (st, "Displaying Breakpoint Types:");
9367 for (bit=0; bit <= ('Z'-'A'); bit++)
9368 if (mask & (1 << bit))
9369 (void)fprintf (st, " -%c", 'A' + bit);
9370 (void)fprintf (st, "\n");
9371 }
9372 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9373 BRKTAB *prev = NULL;
9374 BRKTAB *cur = *bpt;
9375 BRKTAB *next;
9376
9377 while (cur) {
9378 next = cur->next;
9379 cur->next = prev;
9380 prev = cur;
9381 cur = next;
9382 }
9383
9384 *bpt = prev;
9385
9386 cur = prev;
9387 while (cur) {
9388 if (cur->typ & sw)
9389 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9390 cur = cur->next;
9391 }
9392
9393 cur = prev;
9394 prev = NULL;
9395 while (cur) {
9396 next = cur->next;
9397 cur->next = prev;
9398 prev = cur;
9399 cur = next;
9400 }
9401
9402 *bpt = prev;
9403 }
9404 return SCPE_OK;
9405 }
9406
9407
9408
9409 uint32 sim_brk_test (t_addr loc, uint32 btyp)
9410 {
9411 BRKTAB *bp;
9412 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9413
9414 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9415 btyp |= BRK_TYP_DYN_ALL;
9416
9417 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
9418 double s_gtime = sim_gtime ();
9419
9420 if (bp->time_fired[spc] == s_gtime)
9421 return 0;
9422 bp->time_fired[spc] = s_gtime;
9423 if (--bp->cnt > 0)
9424 return 0;
9425 bp->cnt = 0;
9426 sim_brk_setact (bp->act);
9427 sim_brk_match_type = btyp & bp->typ;
9428 if (bp->typ & BRK_TYP_TEMP)
9429 sim_brk_clr (loc, bp->typ);
9430 sim_brk_match_addr = loc;
9431 return sim_brk_match_type;
9432 }
9433 return 0;
9434 }
9435
9436
9437
9438 CONST char *sim_brk_getact (char *buf, int32 size)
9439 {
9440 char *ep;
9441 size_t lnt;
9442
9443 if (sim_brk_act[sim_do_depth] == NULL)
9444 return NULL;
9445 while (sim_isspace (*sim_brk_act[sim_do_depth]))
9446 sim_brk_act[sim_do_depth]++;
9447 if (*sim_brk_act[sim_do_depth] == 0) {
9448 return sim_brk_clract ();
9449 }
9450 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
9451 lnt = ep - sim_brk_act[sim_do_depth];
9452 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
9453 buf[lnt] = 0;
9454 sim_brk_act[sim_do_depth] += lnt + 1;
9455 }
9456 else {
9457 strncpy (buf, sim_brk_act[sim_do_depth], size);
9458 sim_brk_clract ();
9459 }
9460 return buf;
9461 }
9462
9463
9464
9465 char *sim_brk_clract (void)
9466 {
9467 FREE (sim_brk_act_buf[sim_do_depth]);
9468 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9469 }
9470
9471
9472
9473 void sim_brk_setact (const char *action)
9474 {
9475 if (action) {
9476 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9477 if (!sim_brk_act_buf[sim_do_depth])
9478 {
9479 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9480 __func__, __FILE__, __LINE__);
9481 #if defined(USE_BACKTRACE)
9482 # if defined(SIGUSR2)
9483 (void)raise(SIGUSR2);
9484
9485 # endif
9486 #endif
9487 abort();
9488 }
9489 strcpy (sim_brk_act_buf[sim_do_depth], action);
9490 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9491 }
9492 else
9493 sim_brk_clract ();
9494 }
9495
9496
9497
9498 void sim_brk_npc (uint32 cnt)
9499 {
9500 uint32 spc;
9501 BRKTAB **bpt, *bp;
9502
9503 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9504 cnt = SIM_BKPT_N_SPC;
9505 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9506 for (bp = *bpt; bp; bp = bp->next) {
9507 for (spc = 0; spc < cnt; spc++)
9508 bp->time_fired[spc] = -1.0;
9509 }
9510 }
9511 }
9512
9513
9514
9515 void sim_brk_clrspc (uint32 spc, uint32 btyp)
9516 {
9517 BRKTAB **bpt, *bp;
9518
9519 if (spc < SIM_BKPT_N_SPC) {
9520 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9521 for (bp = *bpt; bp; bp = bp->next) {
9522 if (bp->typ & btyp)
9523 bp->time_fired[spc] = -1.0;
9524 }
9525 }
9526 }
9527 }
9528
9529 const char *sim_brk_message(void)
9530 {
9531 static char msg[256];
9532 char addr[65] = "";
9533 char buf[32];
9534
9535 msg[0] = '\0';
9536 if (sim_dflt_dev) {
9537 if (sim_vm_sprint_addr)
9538 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9539 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9540 }
9541 if (sim_brk_type_desc) {
9542 BRKTYPTAB *brk = sim_brk_type_desc;
9543
9544 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9545 if (brk->btyp == sim_brk_match_type) {
9546 (void)sprintf (msg, "%s: %s", brk->desc, addr);
9547 break;
9548 }
9549 brk++;
9550 }
9551 }
9552 if (!msg[0])
9553 (void)sprintf (msg, "%s Breakpoint at: %s\n",
9554 put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9555
9556 return msg;
9557 }
9558
9559
9560
9561
9562
9563
9564
9565
9566
9567
9568
9569
9570
9571
9572
9573
9574
9575
9576
9577
9578
9579
9580
9581
9582
9583
9584
9585
9586
9587
9588
9589
9590
9591
9592
9593
9594
9595 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
9596 {
9597 char gbuf[CBUFSIZE];
9598 CONST char *tptr;
9599 CONST char *c1ptr;
9600 t_bool after_set = FALSE;
9601 uint32 after;
9602 int32 cnt = 0;
9603 t_stat r;
9604
9605 if (exp == NULL)
9606 return sim_messagef (SCPE_ARG, "Null exp!\n");
9607 after = exp->after;
9608
9609 if ((cptr == NULL) || (*cptr == 0))
9610 return SCPE_2FARG;
9611 if (*cptr == '[') {
9612 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9613 if ((cptr == c1ptr) || (*c1ptr != ']'))
9614 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n");
9615 cptr = c1ptr + 1;
9616 while (sim_isspace(*cptr))
9617 ++cptr;
9618 }
9619 tptr = get_glyph (cptr, gbuf, ',');
9620 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9621 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9622 if (r != SCPE_OK)
9623 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n");
9624 after_set = TRUE;
9625 cptr = tptr;
9626 }
9627 if ((*cptr != '"') && (*cptr != '\''))
9628 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9629 cptr = get_glyph_quoted (cptr, gbuf, 0);
9630
9631 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9632 }
9633
9634
9635
9636 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
9637 {
9638 char gbuf[CBUFSIZE];
9639
9640 if (NULL == cptr || !*cptr)
9641 return sim_exp_clrall (exp);
9642 if ((*cptr != '"') && (*cptr != '\''))
9643 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9644 cptr = get_glyph_quoted (cptr, gbuf, 0);
9645 if (*cptr != '\0')
9646 return SCPE_2MARG;
9647 return sim_exp_clr (exp, gbuf);
9648 }
9649
9650
9651
9652 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
9653 {
9654 size_t i;
9655
9656 if (NULL == exp->rules)
9657 return NULL;
9658 for (i=start_rule; i<exp->size; i++)
9659 if (!strcmp (exp->rules[i].match_pattern, match))
9660 return &exp->rules[i];
9661 return NULL;
9662 }
9663
9664
9665
9666 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9667 {
9668 size_t i;
9669
9670 if (NULL == ep)
9671 return SCPE_OK;
9672 FREE (ep->match);
9673 FREE (ep->match_pattern);
9674 FREE (ep->act);
9675 exp->size -= 1;
9676 #if !defined(__clang_analyzer__)
9677 for (i=ep-exp->rules; i<exp->size; i++)
9678 exp->rules[i] = exp->rules[i+1];
9679 if (exp->size == 0) {
9680 FREE (exp->rules);
9681 exp->rules = NULL;
9682 }
9683 #endif
9684 return SCPE_OK;
9685 }
9686
9687 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9688 {
9689 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9690
9691 while (ep) {
9692 sim_exp_clr_tab (exp, ep);
9693 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9694 }
9695 return SCPE_OK;
9696 }
9697
9698
9699
9700 t_stat sim_exp_clrall (EXPECT *exp)
9701 {
9702 int32 i;
9703
9704 for (i=0; i<exp->size; i++) {
9705 FREE (exp->rules[i].match);
9706 FREE (exp->rules[i].match_pattern);
9707 FREE (exp->rules[i].act);
9708 }
9709 FREE (exp->rules);
9710 exp->rules = NULL;
9711 exp->size = 0;
9712 FREE (exp->buf);
9713 exp->buf = NULL;
9714 exp->buf_size = 0;
9715 exp->buf_ins = 0;
9716 return SCPE_OK;
9717 }
9718
9719
9720
9721 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9722 {
9723 EXPTAB *ep;
9724 uint8 *match_buf;
9725 uint32 match_size;
9726 size_t i;
9727
9728
9729 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9730 if (!match_buf)
9731 return SCPE_MEM;
9732 if (switches & EXP_TYP_REGEX) {
9733 FREE (match_buf);
9734 return sim_messagef (SCPE_ARG, "RegEx support not available\n");
9735 }
9736 else {
9737 if (switches & EXP_TYP_REGEX_I) {
9738 FREE (match_buf);
9739 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\n");
9740 }
9741 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9742 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9743 FREE (match_buf);
9744 return sim_messagef (SCPE_ARG, "Invalid quoted string\n");
9745 }
9746 }
9747 FREE (match_buf);
9748 for (i=0; i<exp->size; i++) {
9749 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9750 (exp->rules[i].switches & EXP_TYP_PERSIST))
9751 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n");
9752 }
9753 if (after && exp->size)
9754 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n");
9755 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9756 if (!exp->rules)
9757 {
9758 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9759 __func__, __FILE__, __LINE__);
9760 #if defined(USE_BACKTRACE)
9761 # if defined(SIGUSR2)
9762 (void)raise(SIGUSR2);
9763
9764 # endif
9765 #endif
9766 abort();
9767 }
9768 ep = &exp->rules[exp->size];
9769 exp->size += 1;
9770 exp->after = after;
9771 (void)memset (ep, 0, sizeof(*ep));
9772 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9773 if (ep->match_pattern)
9774 strcpy (ep->match_pattern, match);
9775 ep->cnt = cnt;
9776 ep->switches = switches;
9777 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9778 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9779 sim_exp_clr_tab (exp, ep);
9780 FREE (match_buf);
9781 return SCPE_MEM;
9782 }
9783 if (switches & EXP_TYP_REGEX) {
9784 FREE (match_buf);
9785 match_buf = NULL;
9786 }
9787 else {
9788 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9789 sim_decode_quoted_string (match, match_buf, &match_size);
9790 ep->match = match_buf;
9791 ep->size = match_size;
9792 }
9793 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9794 if (!ep->match_pattern)
9795 {
9796 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9797 __func__, __FILE__, __LINE__);
9798 #if defined(USE_BACKTRACE)
9799 # if defined(SIGUSR2)
9800 (void)raise(SIGUSR2);
9801
9802 # endif
9803 #endif
9804 abort();
9805 }
9806 strcpy (ep->match_pattern, match);
9807 if (ep->act) {
9808 FREE (ep->act);
9809 ep->act = NULL;
9810 }
9811 if (act) while (sim_isspace(*act)) ++act;
9812 if ((act != NULL) && (*act != 0)) {
9813 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9814 if (newp == NULL)
9815 return SCPE_MEM;
9816 strcpy (newp, act);
9817 ep->act = newp;
9818 }
9819
9820 for (i=0; i<exp->size; i++) {
9821 size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9822 if (compare_size >= exp->buf_size) {
9823 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
9824 exp->buf_size = compare_size + 1;
9825 }
9826 }
9827 return SCPE_OK;
9828 }
9829
9830
9831
9832 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
9833 {
9834 if (!ep)
9835 return SCPE_OK;
9836 (void)fprintf (st, "EXPECT");
9837 if (ep->switches & EXP_TYP_PERSIST)
9838 (void)fprintf (st, " -p");
9839 if (ep->switches & EXP_TYP_CLEARALL)
9840 (void)fprintf (st, " -c");
9841 if (ep->switches & EXP_TYP_REGEX)
9842 (void)fprintf (st, " -r");
9843 if (ep->switches & EXP_TYP_REGEX_I)
9844 (void)fprintf (st, " -i");
9845 (void)fprintf (st, " %s", ep->match_pattern);
9846 if (ep->cnt > 0)
9847 (void)fprintf (st, " [%d]", ep->cnt);
9848 if (ep->act)
9849 (void)fprintf (st, " %s", ep->act);
9850 (void)fprintf (st, "\n");
9851 return SCPE_OK;
9852 }
9853
9854 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
9855 {
9856 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9857
9858 if (exp->buf_size) {
9859 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9860
9861 (void)fprintf (st, "Match Buffer Size: %lld\n",
9862 (long long)exp->buf_size);
9863 (void)fprintf (st, "Buffer Insert Offset: %lld\n",
9864 (long long)exp->buf_ins);
9865 (void)fprintf (st, "Buffer Contents: %s\n",
9866 bstr);
9867 FREE (bstr);
9868 }
9869 if (exp->after)
9870 (void)fprintf (st, "Halt After: %lld instructions\n",
9871 (long long)exp->after);
9872 if (exp->dptr && exp->dbit)
9873 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
9874 sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
9875 exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9876 (void)fprintf (st, "Match Rules:\n");
9877 if (!*match)
9878 return sim_exp_showall (st, exp);
9879 if (!ep) {
9880 (void)fprintf (st, "No Rules match '%s'\n", match);
9881 return SCPE_ARG;
9882 }
9883 do {
9884 sim_exp_show_tab (st, exp, ep);
9885 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9886 } while (ep);
9887 return SCPE_OK;
9888 }
9889
9890
9891
9892 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
9893 {
9894 size_t i;
9895
9896 for (i=0; i < exp->size; i++)
9897 sim_exp_show_tab (st, exp, &exp->rules[i]);
9898 return SCPE_OK;
9899 }
9900
9901
9902
9903 t_stat sim_exp_check (EXPECT *exp, uint8 data)
9904 {
9905 size_t i;
9906 EXPTAB *ep = NULL;
9907 char *tstr = NULL;
9908 #if defined(TESTING)
9909 cpu_state_t * cpup = _cpup;
9910 #endif
9911
9912 if ((!exp) || (!exp->rules))
9913 return SCPE_OK;
9914
9915 exp->buf[exp->buf_ins++] = data;
9916 exp->buf[exp->buf_ins] = '\0';
9917
9918 for (i=0; i < exp->size; i++) {
9919 ep = &exp->rules[i];
9920 if (ep == NULL)
9921 break;
9922 if (ep->switches & EXP_TYP_REGEX) {
9923 }
9924 else {
9925 if (exp->buf_ins < ep->size) {
9926
9927
9928
9929
9930 if (exp->buf_ins > 0) {
9931 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9932 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9933 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
9934
9935 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\n",
9936 (long long)exp->buf_ins, estr);
9937 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9938 FREE (estr);
9939 FREE (mstr);
9940 }
9941 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
9942 continue;
9943 }
9944 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9945 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
9946 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
9947
9948 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
9949 (long long)exp->buf_size-(ep->size-exp->buf_ins),
9950 (long long)ep->size-exp->buf_ins, estr);
9951 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9952 FREE (estr);
9953 FREE (mstr);
9954 }
9955 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
9956 continue;
9957 break;
9958 }
9959 else {
9960 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9961 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
9962 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
9963
9964 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
9965 (long long)exp->buf_ins-ep->size,
9966 (long long)ep->size, estr);
9967 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9968 FREE (estr);
9969 FREE (mstr);
9970 }
9971 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
9972 continue;
9973 break;
9974 }
9975 }
9976 }
9977 if (exp->buf_ins == exp->buf_size) {
9978 exp->buf_ins = 0;
9979 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\n");
9980 }
9981 if ((ep != NULL) && (i != exp->size)) {
9982 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\n");
9983 if (ep->cnt > 0) {
9984 ep->cnt -= 1;
9985 sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\n",
9986 (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
9987 }
9988 else {
9989 uint32 after = exp->after;
9990 int32 switches = ep->switches;
9991 if (ep->act && *ep->act) {
9992 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\n", ep->act);
9993 }
9994 else {
9995 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\n");
9996 }
9997 sim_brk_setact (ep->act);
9998 if (ep->switches & EXP_TYP_CLEARALL)
9999 sim_exp_clrall (exp);
10000 else {
10001 if (!(ep->switches & EXP_TYP_PERSIST))
10002 sim_exp_clr_tab (exp, ep);
10003 }
10004 sim_activate (&sim_expect_unit,
10005 (switches & EXP_TYP_TIME) ?
10006 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10007 after);
10008 }
10009
10010 exp->buf_ins = 0;
10011 }
10012 if (tstr)
10013 FREE (tstr);
10014 return SCPE_OK;
10015 }
10016
10017
10018
10019 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
10020 {
10021 if (snd->extoff != 0) {
10022 if (snd->insoff > snd->extoff)
10023 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10024 snd->insoff -= snd->extoff;
10025 snd->extoff = 0;
10026 }
10027 if (snd->insoff+size > snd->bufsize) {
10028 snd->bufsize = snd->insoff+size;
10029 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
10030 if (!snd->buffer)
10031 {
10032 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10033 __func__, __FILE__, __LINE__);
10034 #if defined(USE_BACKTRACE)
10035 # if defined(SIGUSR2)
10036 (void)raise(SIGUSR2);
10037
10038 # endif
10039 #endif
10040 abort();
10041 }
10042 }
10043 memcpy(snd->buffer+snd->insoff, data, size);
10044 snd->insoff += size;
10045 if (delay)
10046 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10047 if (after)
10048 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10049 if (snd->after == 0)
10050 snd->after = snd->delay;
10051 snd->next_time = sim_gtime() + snd->after;
10052 return SCPE_OK;
10053 }
10054
10055
10056 t_stat sim_send_clear (SEND *snd)
10057 {
10058 snd->insoff = 0;
10059 snd->extoff = 0;
10060 return SCPE_OK;
10061 }
10062
10063
10064
10065 t_stat sim_show_send_input (FILE *st, const SEND *snd)
10066 {
10067 if (snd->extoff < snd->insoff) {
10068 (void)fprintf (st, "%lld bytes of pending input Data:\n ",
10069 (long long)snd->insoff-snd->extoff);
10070 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10071 (void)fprintf (st, "\n");
10072 }
10073 else
10074 (void)fprintf (st, "No Pending Input Data\n");
10075 if ((snd->next_time - sim_gtime()) > 0) {
10076 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10077 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\n",
10078 (int)(snd->next_time - sim_gtime()),
10079 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10080 else
10081 (void)fprintf (st, "Minimum of %d instructions before sending first character\n",
10082 (int)(snd->next_time - sim_gtime()));
10083 }
10084 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10085 (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\n",
10086 (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10087 else
10088 (void)fprintf (st, "Minimum of %d instructions between characters\n",
10089 (int)snd->delay);
10090 if (snd->dptr && snd->dbit)
10091 (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
10092 sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10093 snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10094 return SCPE_OK;
10095 }
10096
10097
10098
10099 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
10100 {
10101 #if defined(TESTING)
10102 cpu_state_t * cpup = _cpup;
10103 #endif
10104 if ((NULL != snd) && (snd->extoff < snd->insoff)) {
10105 if (sim_gtime() < snd->next_time) {
10106 *stat = SCPE_OK;
10107 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\n");
10108 }
10109 else {
10110 char dstr[8] = "";
10111 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
10112 snd->next_time = sim_gtime() + snd->delay;
10113 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10114 (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10115 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\n", *stat & 0xFF, dstr);
10116 }
10117 return TRUE;
10118 }
10119 return FALSE;
10120 }
10121
10122
10123
10124 const char *sim_error_text (t_stat stat)
10125 {
10126 static char msgbuf[64];
10127
10128 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
10129 if (stat == SCPE_OK)
10130 return "No Error";
10131 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10132 return scp_errors[stat-SCPE_BASE].message;
10133 (void)sprintf(msgbuf, "Error %d", stat);
10134 return msgbuf;
10135 }
10136
10137 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
10138 {
10139 char gbuf[CBUFSIZE];
10140 size_t cond;
10141
10142 *stat = SCPE_ARG;
10143 cptr = get_glyph (cptr, gbuf, 0);
10144 if (0 == memcmp("SCPE_", gbuf, 5))
10145 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
10146 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10147 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10148 cond += SCPE_BASE;
10149 break;
10150 }
10151 if (0 == strcmp(gbuf, "OK"))
10152 cond = SCPE_OK;
10153 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
10154 unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10155 if (0 == numeric_cond)
10156 return SCPE_ARG;
10157 cond = (t_stat) numeric_cond;
10158 }
10159 if (cond > SCPE_MAX_ERR)
10160 return SCPE_ARG;
10161 *stat = cond;
10162 return SCPE_OK;
10163 }
10164
10165
10166
10167 const char* debug_bstates = "01_^";
10168 char debug_line_prefix[256];
10169 int32 debug_unterm = 0;
10170
10171
10172
10173 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
10174 {
10175 static const char *debtab_none = "DEBTAB_ISNULL";
10176 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10177 const char *some_match = NULL;
10178 int32 offset = 0;
10179
10180 if (dptr->debflags == 0)
10181 return debtab_none;
10182
10183 dbits &= dptr->dctrl;
10184
10185
10186
10187 while ((offset < 32) && dptr->debflags[offset].name) {
10188 if (dptr->debflags[offset].mask == dbits)
10189 return dptr->debflags[offset].name;
10190 if (dptr->debflags[offset].mask & dbits)
10191 some_match = dptr->debflags[offset].name;
10192 offset++;
10193 }
10194 return some_match ? some_match : debtab_nomatch;
10195 }
10196
10197
10198
10199 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
10200 {
10201 const char* debug_type = get_dbg_verb (dbits, dptr);
10202 char tim_t[32] = "";
10203 char tim_a[32] = "";
10204 char pc_s[64] = "";
10205 struct timespec time_now;
10206
10207 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10208 clock_gettime(CLOCK_REALTIME, &time_now);
10209 if (sim_deb_switches & SWMASK ('R'))
10210 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10211 if (sim_deb_switches & SWMASK ('T')) {
10212 time_t tnow = (time_t)time_now.tv_sec;
10213 struct tm *now = gmtime(&tnow);
10214 (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10215 (int)now->tm_hour,
10216 (int)now->tm_min,
10217 (int)now->tm_sec,
10218 (long)(time_now.tv_nsec / 1000000));
10219 }
10220 if (sim_deb_switches & SWMASK ('A')) {
10221 (void)sprintf(tim_t, "%d.%03ld ",
10222 (int)(time_now.tv_sec),
10223 (long)(time_now.tv_nsec / 1000000));
10224 }
10225 }
10226 if (sim_deb_switches & SWMASK ('P')) {
10227 t_value val;
10228
10229 if (sim_vm_pc_value)
10230 val = (*sim_vm_pc_value)();
10231 else
10232 val = get_rval (sim_PC, 0);
10233 (void)sprintf(pc_s, "-%s:", sim_PC->name);
10234 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10235 }
10236 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10237 tim_t, tim_a, sim_gtime(), pc_s,
10238 "", dptr->name, debug_type);
10239 return debug_line_prefix;
10240 }
10241
10242 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
10243 {
10244 int32 i, fields, offset;
10245 uint32 value, beforevalue, mask;
10246
10247 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10248 if (bitdefs[fields].offset == 0xffffffff)
10249 bitdefs[fields].offset = offset;
10250 offset += bitdefs[fields].width;
10251 }
10252 for (i = fields-1; i >= 0; i--) {
10253 if (bitdefs[i].name[0] == '\0')
10254 continue;
10255 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10256 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10257 (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10258 }
10259 else {
10260 const char *delta = "";
10261 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10262 value = (uint32)((after >> bitdefs[i].offset) & mask);
10263 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10264 if (value < beforevalue)
10265 delta = "_";
10266 if (value > beforevalue)
10267 delta = "^";
10268 if (bitdefs[i].valuenames)
10269 (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10270 else
10271 if (bitdefs[i].format) {
10272 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10273 (void)Fprintf(stream, bitdefs[i].format, value);
10274 (void)Fprintf(stream, " ");
10275 }
10276 else
10277 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10278 }
10279 }
10280 }
10281
10282
10283
10284
10285
10286 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
10287 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10288 {
10289 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10290 if (!debug_unterm)
10291 (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
10292 if (header)
10293 (void)fprintf(sim_deb, "%s: ", header);
10294 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
10295 if (terminate)
10296 (void)fprintf(sim_deb, "\r\n");
10297 debug_unterm = terminate ? 0 : 1;
10298 }
10299 }
10300 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
10301 uint32 before, uint32 after, int terminate)
10302 {
10303 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10304 }
10305
10306
10307 void sim_printf (const char* fmt, ...)
10308 {
10309 char stackbuf[STACKBUFSIZE];
10310 int32 bufsize = sizeof(stackbuf);
10311 char *buf = stackbuf;
10312 int32 len;
10313 va_list arglist;
10314
10315 while (1) {
10316 va_start (arglist, fmt);
10317 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10318 va_end (arglist);
10319
10320
10321
10322 if ((len < 0) || (len >= bufsize-1)) {
10323 if (buf != stackbuf)
10324 FREE (buf);
10325 if (bufsize >= (INT_MAX / 2))
10326 return;
10327 bufsize = bufsize * 2;
10328 if (bufsize < len + 2)
10329 bufsize = len + 2;
10330 buf = (char *) malloc (bufsize);
10331 if (buf == NULL)
10332 return;
10333 buf[bufsize-1] = '\0';
10334 continue;
10335 }
10336 break;
10337 }
10338
10339 if (sim_is_running) {
10340 char *c, *remnant = buf;
10341 while ((c = strchr(remnant, '\n'))) {
10342 if ((c != buf) && (*(c - 1) != '\r'))
10343 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10344 else
10345 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10346 remnant = c + 1;
10347 }
10348 (void)printf("%s", remnant);
10349 }
10350 else
10351 (void)printf("%s", buf);
10352 if (sim_log && (sim_log != stdout))
10353 (void)fprintf (sim_log, "%s", buf);
10354 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10355 (void)fprintf (sim_deb, "%s", buf);
10356
10357 if (buf != stackbuf)
10358 FREE (buf);
10359 }
10360
10361
10362 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
10363 {
10364 char stackbuf[STACKBUFSIZE];
10365 size_t bufsize = sizeof(stackbuf);
10366 char *buf = stackbuf;
10367 size_t len;
10368 va_list arglist;
10369 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10370
10371 while (1) {
10372 va_start (arglist, fmt);
10373 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10374 va_end (arglist);
10375
10376
10377
10378 if (len >= bufsize - 1) {
10379 if (buf != stackbuf)
10380 FREE (buf);
10381 bufsize = bufsize * 2;
10382 if (bufsize < len + 2)
10383 bufsize = len + 2;
10384 buf = (char *) malloc (bufsize);
10385 if (buf == NULL)
10386 return SCPE_MEM;
10387 buf[bufsize-1] = '\0';
10388 continue;
10389 }
10390 break;
10391 }
10392
10393 if (sim_do_ocptr[sim_do_depth]) {
10394 if (!sim_do_echo && !sim_quiet && !inhibit_message)
10395 sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10396 else {
10397 if (sim_deb)
10398 (void)fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10399 }
10400 }
10401 if (sim_is_running && !inhibit_message) {
10402 char *c, *remnant = buf;
10403 while ((c = strchr(remnant, '\n'))) {
10404 if ((c != buf) && (*(c - 1) != '\r'))
10405 (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10406 else
10407 (void)printf("%.*s\n", (int)(c-remnant), remnant);
10408 remnant = c + 1;
10409 }
10410 (void)printf("%s", remnant);
10411 }
10412 else {
10413 if (!inhibit_message)
10414 (void)printf("%s", buf);
10415 }
10416 if (sim_log && (sim_log != stdout) && !inhibit_message)
10417 (void)fprintf (sim_log, "%s", buf);
10418 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
10419 (void)fprintf (sim_deb, "%s", buf);
10420
10421 if (buf != stackbuf)
10422 FREE (buf);
10423 return stat | SCPE_NOMESSAGE;
10424 }
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
10435 {
10436 DEVICE *dptr = (DEVICE *)vdptr;
10437 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10438 char stackbuf[STACKBUFSIZE];
10439 int32 bufsize = sizeof(stackbuf);
10440 char *buf = stackbuf;
10441 va_list arglist;
10442 int32 i, j, len;
10443 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
10444
10445 buf[bufsize-1] = '\0';
10446 while (1) {
10447 va_start (arglist, fmt);
10448 len = vsnprintf (buf, bufsize-1, fmt, arglist);
10449 va_end (arglist);
10450
10451
10452
10453 if ((len < 0) || (len >= bufsize-1)) {
10454 if (buf != stackbuf)
10455 FREE (buf);
10456 if (bufsize >= (INT_MAX / 2))
10457 return;
10458 bufsize = bufsize * 2;
10459 if (bufsize < len + 2)
10460 bufsize = len + 2;
10461 buf = (char *) malloc (bufsize);
10462 if (buf == NULL)
10463 return;
10464 buf[bufsize-1] = '\0';
10465 continue;
10466 }
10467 break;
10468 }
10469
10470
10471
10472 for (i = j = 0; i < len; ++i) {
10473 if ('\n' == buf[i]) {
10474 if (i >= j) {
10475 if ((i != j) || (i == 0)) {
10476 if (debug_unterm)
10477 (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10478 else
10479 (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10480 }
10481 debug_unterm = 0;
10482 }
10483 j = i + 1;
10484 }
10485 }
10486 if (i > j) {
10487 if (debug_unterm)
10488 (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10489 else
10490 (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10491 }
10492
10493
10494
10495 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10496 if (buf != stackbuf)
10497 FREE (buf);
10498 }
10499 return;
10500 }
10501
10502 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
10503 {
10504 #if defined(TESTING)
10505 cpu_state_t * cpup = _cpup;
10506 #endif
10507 if (sim_deb && (dptr->dctrl & reason)) {
10508 sim_debug (reason, dptr, "%s %s %slen: %08X\n", sim_uname(uptr), txt, position, (unsigned int)len);
10509 if (data && len) {
10510 size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10511 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10512 static char hex[] = "0123456789ABCDEF";
10513 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10514 static unsigned char ebcdic2ascii[] = {
10515 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10516 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10517 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10518 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10519 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10520 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10521 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10522 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10523 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10524 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10525 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10526 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10527 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10528 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10529 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10530 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10531 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10532 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10533 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10534 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10535 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10536 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10537 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10538 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10539 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10540 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10541 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10542 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10543 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10544 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10545 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10546 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10547 };
10548
10549 for (i=same=0; i<len; i += 16) {
10550 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10551 ++same;
10552 continue;
10553 }
10554 if (same > 0) {
10555 sim_debug (reason, dptr, "%04lx thru %04lx same as above\n",
10556 i - (16*same),
10557 i - 1);
10558 same = 0;
10559 }
10560 group = (((len - i) > 16) ? 16 : (len - i));
10561 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10562 eidx = strlen(ebcdicbuf);
10563 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10564 ridx = strlen(rad50buf);
10565 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10566 soff = strlen(strbuf);
10567 for (sidx=oidx=0; sidx<group; ++sidx) {
10568 outbuf[oidx++] = ' ';
10569 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10570 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10571 if (sim_isprint (data[i+sidx]))
10572 strbuf[soff+sidx] = data[i+sidx];
10573 else
10574 strbuf[soff+sidx] = '.';
10575 if (ridx && ((sidx&1) == 0)) {
10576 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10577
10578 if (word >= 64000) {
10579 rad50buf[ridx++] = '|';
10580 rad50buf[ridx++] = '|';
10581 rad50buf[ridx++] = '|';
10582 }
10583 else {
10584 rad50buf[ridx++] = rad50[word/1600];
10585 rad50buf[ridx++] = rad50[(word/40)%40];
10586 rad50buf[ridx++] = rad50[word%40];
10587 }
10588 }
10589 if (eidx) {
10590 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10591 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10592 else
10593 ebcdicbuf[eidx++] = '.';
10594 }
10595 }
10596 outbuf[oidx] = '\0';
10597 strbuf[soff+sidx] = '\0';
10598 ebcdicbuf[eidx] = '\0';
10599 rad50buf[ridx] = '\0';
10600 sim_debug (reason, dptr, "%04lx%-48s %s%s%s\n", i, outbuf, strbuf, ebcdicbuf, rad50buf);
10601 }
10602 if (same > 0) {
10603 sim_debug (reason, dptr, "%04lx thru %04lx same as above\n", i-(16*same), (long unsigned int)(len-1));
10604 }
10605 }
10606 }
10607 }
10608
10609 int Fprintf (FILE *f, const char* fmt, ...)
10610 {
10611 int ret = 0;
10612 va_list args;
10613
10614 va_start (args, fmt);
10615 ret = vfprintf (f, fmt, args);
10616 va_end (args);
10617 return ret;
10618 }
10619
10620
10621
10622
10623
10624
10625
10626
10627
10628
10629
10630
10631
10632
10633
10634
10635
10636
10637
10638 #define blankch(x) ((x) == ' ' || (x) == '\t')
10639
10640 typedef struct topic {
10641 size_t level;
10642 char *title;
10643 char *label;
10644 struct topic *parent;
10645 struct topic **children;
10646 uint32 kids;
10647 char *text;
10648 size_t len;
10649 uint32 flags;
10650 size_t kidwid;
10651 #define HLP_MAGIC_TOPIC 1
10652 } TOPIC;
10653
10654 static volatile struct {
10655 const char *error;
10656 const char *prox;
10657 size_t block;
10658 size_t line;
10659 } help_where = { "", NULL, 0, 0 };
10660 jmp_buf help_env;
10661
10662 #define FAIL(why,text,here) \
10663 { \
10664 help_where.error = #text; \
10665 help_where.prox = here; \
10666 longjmp ( help_env, (why) ); \
10667 \
10668 }
10669
10670
10671
10672
10673
10674
10675 static void appendText (TOPIC *topic, const char *text, size_t len)
10676 {
10677 char *newt;
10678
10679 if (!len)
10680 return;
10681
10682 newt = (char *)realloc (topic->text, topic->len + len +1);
10683 if (!newt) {
10684 #if !defined(SUNLINT)
10685 FAIL (SCPE_MEM, No memory, NULL);
10686 #endif
10687 }
10688 topic->text = newt;
10689 memcpy (newt + topic->len, text, len);
10690 topic->len +=len;
10691 newt[topic->len] = '\0';
10692 return;
10693 }
10694
10695
10696
10697 static void cleanHelp (TOPIC *topic)
10698 {
10699 TOPIC *child;
10700 size_t i;
10701
10702 FREE (topic->title);
10703 FREE (topic->text);
10704 FREE (topic->label);
10705 for (i = 0; i < topic->kids; i++) {
10706 child = topic->children[i];
10707 cleanHelp (child);
10708 FREE (child);
10709 }
10710 FREE (topic->children);
10711 return;
10712 }
10713
10714
10715
10716
10717 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10718 UNIT *uptr, const char *htext, va_list ap)
10719 {
10720 char *end;
10721 size_t n, ilvl;
10722 #define VSMAX 100
10723 char *vstrings[VSMAX];
10724 size_t vsnum = 0;
10725 char * astrings[VSMAX+1];
10726 size_t asnum = 0;
10727 char *const *hblock;
10728 const char *ep;
10729 t_bool excluded = FALSE;
10730
10731
10732
10733
10734
10735
10736
10737 (void)memset (vstrings, 0, sizeof (vstrings));
10738 (void)memset (astrings, 0, sizeof (astrings));
10739 astrings[asnum++] = (char *) htext;
10740
10741 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10742 help_where.block = hblock - astrings;
10743 help_where.line = 0;
10744 while (*htext) {
10745 const char *start;
10746
10747 help_where.line++;
10748 if (sim_isspace (*htext) || *htext == '+') {
10749 if (excluded) {
10750 while (*htext && *htext != '\n')
10751 htext++;
10752 if (*htext)
10753 ++htext;
10754 continue;
10755 }
10756 ilvl = 1;
10757 appendText (topic, " ", 4);
10758 if (*htext == '+') {
10759 while (*htext == '+') {
10760 ilvl++;
10761 appendText (topic, " ", 4);
10762 htext++;
10763 }
10764 }
10765 while (*htext && *htext != '\n' && sim_isspace (*htext))
10766 htext++;
10767 if (!*htext)
10768 break;
10769 start = htext;
10770 while (*htext) {
10771 if (*htext == '%') {
10772 appendText (topic, start, htext - start);
10773 switch (*++htext) {
10774 case 'U':
10775 if (dptr) {
10776 char buf[129];
10777 n = uptr? uptr - dptr->units: 0;
10778 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10779 appendText (topic, buf, strlen (buf));
10780 }
10781 break;
10782 case 'D':
10783 if (dptr != NULL)
10784 appendText (topic, dptr->name, strlen (dptr->name));
10785 break;
10786 case 'S':
10787 appendText (topic, sim_name, strlen (sim_name));
10788 break;
10789 case '%':
10790 appendText (topic, "%", 1);
10791 break;
10792 case '+':
10793 appendText (topic, "+", 1);
10794 break;
10795 default:
10796 if (sim_isdigit (*htext)) {
10797 n = 0;
10798 while (sim_isdigit (*htext))
10799 n += (n * 10) + (*htext++ - '0');
10800 if (( *htext != 'H' && *htext != 's') ||
10801 n == 0 || n >= VSMAX) {
10802 #if !defined(SUNLINT)
10803 FAIL (SCPE_ARG, Invalid escape, htext);
10804 #endif
10805 }
10806 while (n > vsnum)
10807 vstrings[vsnum++] = va_arg (ap, char *);
10808 start = vstrings[n-1];
10809 if (*htext == 'H') {
10810 if (asnum >= VSMAX) {
10811 #if !defined(SUNLINT)
10812 FAIL (SCPE_ARG, Too many blocks, htext);
10813 #endif
10814 }
10815 astrings[asnum++] = (char *)start;
10816 break;
10817 }
10818 ep = start;
10819 while (*ep) {
10820 if (*ep == '\n') {
10821 ep++;
10822 appendText (topic, start, ep - start);
10823 if (*ep) {
10824 size_t i;
10825 for (i = 0; i < ilvl; i++)
10826 appendText (topic, " ", 4);
10827 }
10828 start = ep;
10829 }
10830 else
10831 ep++;
10832 }
10833 appendText (topic, start, ep-start);
10834 break;
10835 }
10836 #if !defined(SUNLINT)
10837 FAIL (SCPE_ARG, Invalid escape, htext);
10838 #endif
10839 }
10840 start = ++htext;
10841 continue;
10842 }
10843 if (*htext == '\n') {
10844 htext++;
10845 appendText (topic, start, htext - start);
10846 break;
10847 }
10848 htext++;
10849 }
10850 continue;
10851 }
10852 if (sim_isdigit (*htext)) {
10853 TOPIC **children;
10854 TOPIC *newt;
10855 char nbuf[100];
10856
10857 n = 0;
10858 start = htext;
10859 while (sim_isdigit (*htext))
10860 n += (n * 10) + (*htext++ - '0');
10861 if ((htext == start) || !n) {
10862 #if !defined(SUNLINT)
10863 FAIL (SCPE_ARG, Invalid topic heading, htext);
10864 #endif
10865 }
10866 if (n <= topic->level) {
10867 while (n <= topic->level)
10868 topic = topic->parent;
10869 }
10870 else {
10871 if (n > topic->level + 1) {
10872 #if !defined(SUNLINT)
10873 FAIL (SCPE_ARG, Level not contiguous, htext);
10874 #endif
10875 }
10876 }
10877 while (*htext && (*htext != '\n') && sim_isspace (*htext))
10878 htext++;
10879 if (!*htext || (*htext == '\n')) {
10880 #if !defined(SUNLINT)
10881 FAIL (SCPE_ARG, Missing topic name, htext);
10882 #endif
10883 }
10884 start = htext;
10885 while (*htext && (*htext != '\n'))
10886 htext++;
10887 if (start == htext) {
10888 #if !defined(SUNLINT)
10889 FAIL (SCPE_ARG, Null topic name, htext);
10890 #endif
10891 }
10892 excluded = FALSE;
10893 if (*start == '?') {
10894 size_t n = 0;
10895 start++;
10896 while (sim_isdigit (*start))
10897 n += (n * 10) + (*start++ - '0');
10898 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
10899 #if !defined(SUNLINT)
10900 FAIL (SCPE_ARG, Invalid parameter number, start);
10901 #endif
10902 }
10903 while (n > vsnum)
10904 vstrings[vsnum++] = va_arg (ap, char *);
10905 end = vstrings[n-1];
10906 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
10907 excluded = TRUE;
10908 if (*htext)
10909 htext++;
10910 continue;
10911 }
10912 }
10913 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
10914 if (!newt) {
10915 #if !defined(SUNLINT)
10916 FAIL (SCPE_MEM, No memory, NULL);
10917 #endif
10918 }
10919 newt->title = (char *) malloc ((htext - start)+1);
10920 if (!newt->title) {
10921 FREE (newt);
10922 #if !defined(SUNLINT)
10923 FAIL (SCPE_MEM, No memory, NULL);
10924 #endif
10925 }
10926 memcpy (newt->title, start, htext - start);
10927 newt->title[htext - start] = '\0';
10928 if (*htext)
10929 htext++;
10930
10931 if (newt->title[0] == '$')
10932 newt->flags |= HLP_MAGIC_TOPIC;
10933
10934 children = (TOPIC **) realloc (topic->children,
10935 (topic->kids +1) * sizeof (TOPIC *));
10936 if (NULL == children) {
10937 FREE (newt->title);
10938 FREE (newt);
10939 #if !defined(SUNLINT)
10940 FAIL (SCPE_MEM, No memory, NULL);
10941 #endif
10942 }
10943 topic->children = children;
10944 topic->children[topic->kids++] = newt;
10945 newt->level = n;
10946 newt->parent = topic;
10947 n = strlen (newt->title);
10948 if (n > topic->kidwid)
10949 topic->kidwid = n;
10950 (void)sprintf (nbuf, ".%u", topic->kids);
10951 n = strlen (topic->label) + strlen (nbuf) + 1;
10952 newt->label = (char *) malloc (n);
10953 if (NULL == newt->label) {
10954 FREE (newt->title);
10955 topic->children[topic->kids -1] = NULL;
10956 FREE (newt);
10957 #if !defined(SUNLINT)
10958 FAIL (SCPE_MEM, No memory, NULL);
10959 #endif
10960 }
10961 (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
10962 topic = newt;
10963 continue;
10964 }
10965 if (*htext == ';') {
10966 while (*htext && *htext != '\n')
10967 htext++;
10968 continue;
10969 }
10970 #if !defined(SUNLINT)
10971 FAIL (SCPE_ARG, Unknown line type, htext);
10972 #endif
10973 }
10974 (void)memset (vstrings, 0, VSMAX * sizeof (char *));
10975 vsnum = 0;
10976 }
10977
10978 return topic;
10979 }
10980
10981
10982
10983
10984
10985 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
10986 {
10987 char *prefix;
10988 char *newp, *newt;
10989
10990 if (topic->level == 0) {
10991 prefix = (char *) calloc (2,1);
10992 if (!prefix) {
10993 #if !defined(SUNLINT)
10994 FAIL (SCPE_MEM, No memory, NULL);
10995 #endif
10996 }
10997 prefix[0] = '\n';
10998 }
10999 else
11000 prefix = helpPrompt (topic->parent, "", oneword);
11001
11002 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11003 strlen (pstring) +1);
11004 if (!newp) {
11005 FREE (prefix);
11006 #if !defined(SUNLINT)
11007 FAIL (SCPE_MEM, No memory, NULL);
11008 #endif
11009 }
11010 strcpy (newp, prefix);
11011 if (topic->children) {
11012 if (topic->level != 0)
11013 strcat (newp, " ");
11014 newt = (topic->flags & HLP_MAGIC_TOPIC)?
11015 topic->title+1: topic->title;
11016 if (oneword) {
11017 char *np = newp + strlen (newp);
11018 while (*newt) {
11019 *np++ = blankch (*newt)? '_' : *newt;
11020 newt++;
11021 }
11022 *np = '\0';
11023 }
11024 else
11025 strcat (newp, newt);
11026 if (*pstring && *pstring != '?')
11027 strcat (newp, " ");
11028 }
11029 strcat (newp, pstring);
11030 FREE (prefix);
11031 return newp;
11032 }
11033
11034 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
11035 {
11036 char tbuf[CBUFSIZE];
11037 size_t i, skiplines;
11038 #if defined(_WIN32)
11039 FILE *tmp;
11040 char *tmpnam;
11041
11042 do {
11043 int fd;
11044 tmpnam = _tempnam (NULL, "simh");
11045 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11046 if (fd != -1) {
11047 tmp = _fdopen (fd, "w+");
11048 break;
11049 }
11050 } while (1);
11051 #else
11052 FILE *tmp = tmpfile();
11053 #endif
11054
11055 if (!tmp) {
11056 (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\n",
11057 xstrerror_l(errno), errno);
11058 return;
11059 }
11060
11061 if (topic->title)
11062 (void)fprintf (st, "%s\n", topic->title+1);
11063
11064 skiplines = 0;
11065 if (topic->title) {
11066 if (!strcmp (topic->title+1, "Registers")) {
11067 fprint_reg_help (tmp, dptr) ;
11068 skiplines = 1;
11069 }
11070 else
11071 if (!strcmp (topic->title+1, "Set commands")) {
11072 fprint_set_help (tmp, dptr);
11073 skiplines = 3;
11074 }
11075 else
11076 if (!strcmp (topic->title+1, "Show commands")) {
11077 fprint_show_help (tmp, dptr);
11078 skiplines = 3;
11079 }
11080 }
11081 rewind (tmp);
11082 if (errno) {
11083 (void)fprintf (st, "rewind: error %d\r\n", errno);
11084 }
11085
11086
11087
11088 for (i =0; i < skiplines; i++)
11089 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11090
11091 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11092 if (tbuf[0] != '\n')
11093 fputs (" ", st);
11094 fputs (tbuf, st);
11095 }
11096 fclose (tmp);
11097 #if defined(_WIN32)
11098 remove (tmpnam);
11099 FREE (tmpnam);
11100 #endif
11101 return;
11102 }
11103
11104
11105 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
11106 UNIT *uptr, int32 flag,
11107 TOPIC *topic, va_list ap )
11108 {
11109 size_t i;
11110
11111 if (topic->flags & HLP_MAGIC_TOPIC) {
11112 (void)fprintf (st, "\n%s ", topic->label);
11113 displayMagicTopic (st, dptr, topic);
11114 }
11115 else
11116 (void)fprintf (st, "\n%s %s\n", topic->label, topic->title);
11117
11118
11119
11120
11121
11122
11123 if (topic->text)
11124 fputs (topic->text, st);
11125
11126 for (i = 0; i < topic->kids; i++)
11127 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11128
11129 return SCPE_OK;
11130 }
11131
11132 #define HLP_MATCH_AMBIGUOUS (~0u)
11133 #define HLP_MATCH_WILDCARD (~1U)
11134 #define HLP_MATCH_NONE 0
11135 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
11136 {
11137 size_t i, match;
11138 char cbuf[CBUFSIZE], *cptr;
11139
11140 if (!strcmp (token, "*"))
11141 return HLP_MATCH_WILDCARD;
11142
11143 match = 0;
11144 for (i = 0; i < topic->kids; i++) {
11145 strcpy (cbuf,topic->children[i]->title +
11146 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11147 cptr = cbuf;
11148 while (*cptr) {
11149 if (blankch (*cptr)) {
11150 *cptr++ = '_';
11151 }
11152 else {
11153 *cptr = (char)toupper (*cptr);
11154 cptr++;
11155 }
11156 }
11157 if (!strcmp (cbuf, token))
11158 return i+1;
11159 if (!strncmp (cbuf, token, strlen (token))) {
11160 if (match)
11161 return HLP_MATCH_AMBIGUOUS;
11162 match = i+1;
11163 }
11164 }
11165 return match;
11166 }
11167
11168
11169
11170 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
11171 UNIT *uptr, int32 flag,
11172 const char *help, const char *cptr, va_list ap)
11173 {
11174 TOPIC top;
11175 TOPIC *topic = ⊤
11176 int failed;
11177 size_t match;
11178 size_t i;
11179 const char *p;
11180 t_bool flat_help = FALSE;
11181 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11182
11183 static const char attach_help[] = { " ATTACH" };
11184 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\n" };
11185 static const char onecmd_help[] = { "%s help.\n" };
11186 static const char help_help[] = {
11187
11188 " To see more HELP information, type the listed subtopic name. To move\n"
11189 " up a level, just type <CR>. To review the current subtopic, type \"?\".\n"
11190 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\n\n"
11191 };
11192
11193 (void)memset (&top, 0, sizeof(top));
11194 top.parent = ⊤
11195 if ((failed = setjmp (help_env)) != 0) {
11196 (void)fprintf (stderr, "\nHELP was unable to process HELP for this device.\n"
11197 "Error in block %u line %u: %s\n"
11198 "%s%*.*s%s\n",
11199 (int)help_where.block, (int)help_where.line, help_where.error,
11200 help_where.prox ? "Near '" : "",
11201 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11202 help_where.prox ? help_where.prox : "",
11203 help_where.prox ? "'" : "");
11204 cleanHelp (&top);
11205 return failed;
11206 }
11207
11208
11209
11210
11211
11212 if (dptr) {
11213 p = dptr->name;
11214 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11215 }
11216 else
11217 p = sim_name;
11218 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11219 if (!top.title)
11220 {
11221 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11222 __func__, __FILE__, __LINE__);
11223 #if defined(USE_BACKTRACE)
11224 # if defined(SIGUSR2)
11225 (void)raise(SIGUSR2);
11226
11227 # endif
11228 #endif
11229 abort();
11230 }
11231 for (i = 0; p[i]; i++ )
11232 top.title[i] = (char)toupper (p[i]);
11233 top.title[i] = '\0';
11234 if (flag & SCP_HELP_ATTACH)
11235 strcpy (top.title+i, attach_help);
11236
11237 top.label = (char *) malloc (sizeof ("1"));
11238 if (!top.label)
11239 {
11240 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11241 __func__, __FILE__, __LINE__);
11242 #if defined(USE_BACKTRACE)
11243 # if defined(SIGUSR2)
11244 (void)raise(SIGUSR2);
11245
11246 # endif
11247 #endif
11248 abort();
11249 }
11250 strcpy (top.label, "1");
11251
11252 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11253
11254 if (flat_help) {
11255 flag |= SCP_HELP_FLAT;
11256 if (sim_ttisatty())
11257 (void)fprintf (st, "%s help.\nThis help is also available in hierarchical form.\n", top.title);
11258 else
11259 (void)fprintf (st, "%s help.\n", top.title);
11260 }
11261 else
11262 (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11263
11264
11265
11266 (void) buildHelp (&top, dptr, uptr, help, ap);
11267
11268
11269
11270 while (cptr && *cptr) {
11271 cptr = get_glyph (cptr, gbuf, 0);
11272 if (!gbuf[0])
11273 break;
11274 if (!strcmp (gbuf, "HELP")) {
11275 (void)fprintf (st, "\n");
11276 fputs (help_help, st);
11277 break;
11278 }
11279 match = matchHelpTopicName (topic, gbuf);
11280 if (match == HLP_MATCH_WILDCARD) {
11281 if (dptr)
11282 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11283 cleanHelp (&top);
11284 return SCPE_OK;
11285 }
11286 if (match == HLP_MATCH_AMBIGUOUS) {
11287 (void)fprintf (st, "\n%s is ambiguous in %s\n", gbuf, topic->title);
11288 break;
11289 }
11290 if (match == HLP_MATCH_NONE) {
11291 (void)fprintf (st, "\n%s is not available in %s\n", gbuf, topic->title);
11292 break;
11293 }
11294 topic = topic->children[match-1];
11295 }
11296 cptr = NULL;
11297
11298 if (flat_help) {
11299 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11300 cleanHelp (&top);
11301 return SCPE_OK;
11302 }
11303
11304
11305
11306 while (TRUE) {
11307 char *pstring;
11308 const char *prompt[2] = {"? ", "Subtopic? "};
11309
11310
11311
11312 if (topic->flags & HLP_MAGIC_TOPIC) {
11313 fputc ('\n', st);
11314 displayMagicTopic (st, dptr, topic);
11315 }
11316 else
11317 (void)fprintf (st, "\n%s\n", topic->title);
11318
11319
11320
11321
11322
11323 if (topic->text)
11324 fputs (topic->text, st);
11325
11326 if (topic->kids) {
11327 size_t w = 0;
11328 char *p;
11329 char tbuf[CBUFSIZE];
11330
11331 (void)fprintf (st, "\n Additional information available:\n\n");
11332 for (i = 0; i < topic->kids; i++) {
11333 strcpy (tbuf, topic->children[i]->title +
11334 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11335 for (p = tbuf; *p; p++) {
11336 if (blankch (*p))
11337 *p = '_';
11338 }
11339 w += 4 + topic->kidwid;
11340 if (w > 80) {
11341 w = 4 + topic->kidwid;
11342 fputc ('\n', st);
11343 }
11344 (void)fprintf (st, " %-*s", (int32_t)topic->kidwid, tbuf);
11345 }
11346 (void)fprintf (st, "\n\n");
11347 if (flag & SCP_HELP_ONECMD) {
11348 pstring = helpPrompt (topic, "", TRUE);
11349 (void)fprintf (st, "To view additional topics, type HELP %s topicname\n", pstring+1);
11350 FREE (pstring);
11351 break;
11352 }
11353 }
11354
11355 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11356 break;
11357
11358 reprompt:
11359 if (NULL == cptr || !*cptr) {
11360 if (topic->kids == 0)
11361 topic = topic->parent;
11362 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11363
11364 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11365 FREE (pstring);
11366 if ((cptr != NULL) &&
11367 ((0 == strcmp (cptr, "\x04")) ||
11368 (0 == strcmp (cptr, "\x1A"))))
11369 cptr = NULL;
11370 }
11371
11372 if (NULL == cptr)
11373 break;
11374
11375 cptr = get_glyph (cptr, gbuf, 0);
11376 if (!strcmp (gbuf, "*")) {
11377 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11378 gbuf[0] = '\0';
11379 }
11380 if (!gbuf[0]) {
11381 if (topic->level == 0)
11382 break;
11383 topic = topic->parent;
11384 continue;
11385 }
11386 if (!strcmp (gbuf, "?"))
11387 continue;
11388 if (!strcmp (gbuf, "HELP")) {
11389 fputs (help_help, st);
11390 goto reprompt;
11391 }
11392 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
11393 break;
11394
11395
11396
11397 if (!topic->kids) {
11398 (void)fprintf (st, "No additional help at this level.\n");
11399 cptr = NULL;
11400 goto reprompt;
11401 }
11402 match = matchHelpTopicName (topic, gbuf);
11403 if (match == HLP_MATCH_AMBIGUOUS) {
11404 (void)fprintf (st, "%s is ambiguous, please type more of the topic name\n", gbuf);
11405 cptr = NULL;
11406 goto reprompt;
11407 }
11408
11409 if (match == HLP_MATCH_NONE) {
11410 (void)fprintf (st, "Help for %s is not available\n", gbuf);
11411 cptr = NULL;
11412 goto reprompt;
11413 }
11414
11415
11416 topic = topic->children[match-1];
11417 }
11418
11419
11420
11421 cleanHelp (&top);
11422
11423 return SCPE_OK;
11424 }
11425
11426
11427
11428 t_stat scp_help (FILE *st, DEVICE *dptr,
11429 UNIT *uptr, int32 flag,
11430 const char *help, const char *cptr, ...)
11431 {
11432 t_stat r;
11433 va_list ap;
11434
11435 va_start (ap, cptr);
11436 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11437 va_end (ap);
11438
11439 return r;
11440 }
11441
11442 #if defined(_MSC_VER)
11443 # pragma warning(pop)
11444 #endif