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