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