1 /* scp.c: simulator control program
3 Copyright (c) 1993-2008, Robert M Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 31-Mar-08 RMS Fixed bug in local/global register search (found by Mark Pizzolato)
27 Fixed bug in restore of RO units (from Mark Pizzolato)
28 06-Feb-08 RMS Added SET/SHO/NO BR with default argument
29 18-Jul-07 RMS Modified match_ext for VMS ext;version support
30 28-Apr-07 RMS Modified sim_instr invocation to call sim_rtcn_init_all
31 Fixed bug in get_sim_opt
32 Fixed bug in restoration with changed memory size
33 08-Mar-07 JDB Fixed breakpoint actions in DO command file processing
34 30-Jan-07 RMS Fixed bugs in get_ipaddr
35 17-Oct-06 RMS Added idle support
36 04-Oct-06 JDB DO cmd failure now echoes cmd unless -q
37 14-Jul-06 RMS Added sim_activate_abs
38 02-Jun-06 JDB Fixed do_cmd to exit nested files on assertion failure
39 Added -E switch to do_cmd to exit on any error
40 14-Feb-06 RMS Upgraded save file format to V3.5
41 18-Jan-06 RMS Added fprint_stopped_gen
42 Added breakpoint spaces
43 Fixed unaligned register access (found by Doug Carman)
44 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
45 30-Aug-05 RMS Revised to trim trailing spaces on file names
46 25-Aug-05 RMS Added variable default device support
47 23-Aug-05 RMS Added Linux line history support
48 16-Aug-05 RMS Fixed C++ declaration and cast problems
49 01-May-05 RMS Revised syntax for SET DEBUG (from Dave Bryan)
50 22-Mar-05 JDB Modified DO command to allow ten-level nesting
51 18-Mar-05 RMS Moved DETACH tests into detach_unit (from Dave Bryan)
52 Revised interface to fprint_sym, fparse_sym
53 07-Feb-05 RMS Added ASSERT command (from Dave Bryan)
54 02-Feb-05 RMS Fixed bug in global register search
55 26-Dec-04 RMS Qualified SAVE examine, RESTORE deposit with SIM_SW_REST
56 10-Nov-04 JDB Fixed logging of errors from cmds in "do" file
57 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy
58 Renamed unit OFFLINE/ONLINE to DISABLED/ENABLED (from Dave Bryan)
59 Revised to flush output files after simulation stop (from Dave Bryan)
60 15-Oct-04 RMS Fixed HELP to suppress duplicate descriptions
61 27-Sep-04 RMS Fixed comma-separation options in set (from David Bryan)
62 09-Sep-04 RMS Added -p option for RESET
63 13-Aug-04 RMS Qualified RESTORE detach with SIM_SW_REST
64 17-Jul-04 RMS Added ECHO command (from Dave Bryan)
65 12-Jul-04 RMS Fixed problem ATTACHing to read only files
66 (found by John Dundas)
67 28-May-04 RMS Added SET/SHOW CONSOLE
68 14-Feb-04 RMS Updated SAVE/RESTORE (V3.2)
69 RMS Added debug print routines (from Dave Hittner)
70 RMS Added sim_vm_parse_addr and sim_vm_fprint_addr
71 RMS Added REG_VMAD support
72 RMS Split out libraries
73 RMS Moved logging function to SCP
74 RMS Exposed step counter interface(s)
75 RMS Fixed double logging of SHOW BREAK (found by Mark Pizzolato)
76 RMS Fixed implementation of REG_VMIO
77 RMS Added SET/SHOW DEBUG, SET/SHOW <device> DEBUG,
78 SHOW <device> MODIFIERS, SHOW <device> RADIX
79 RMS Changed sim_fsize to take uptr argument
80 29-Dec-03 RMS Added Telnet console output stall support
81 01-Nov-03 RMS Cleaned up implicit detach on attach/restore
82 Fixed bug in command line read while logging (found by Mark Pizzolato)
83 01-Sep-03 RMS Fixed end-of-file problem in dep, idep
84 Fixed error on trailing spaces in dep, idep
85 15-Jul-03 RMS Removed unnecessary test in reset_all
86 15-Jun-03 RMS Added register flag REG_VMIO
87 25-Apr-03 RMS Added extended address support (V3.0)
88 Fixed bug in SAVE (found by Peter Schorn)
90 Added logical name support
91 03-Mar-03 RMS Added sim_fsize
92 27-Feb-03 RMS Fixed bug in multiword deposits to files
93 08-Feb-03 RMS Changed sim_os_sleep to void, match_ext to char*
94 Added multiple actions, .ini file support
95 Added multiple switch evaluations per line
96 07-Feb-03 RMS Added VMS support for ! (from Mark Pizzolato)
97 01-Feb-03 RMS Added breakpoint table extension, actions
98 14-Jan-03 RMS Added missing function prototypes
99 10-Jan-03 RMS Added attach/restore flag, dynamic memory size support,
100 case sensitive SET options
101 22-Dec-02 RMS Added ! (OS command) feature (from Mark Pizzolato)
102 17-Dec-02 RMS Added get_ipaddr
103 02-Dec-02 RMS Added EValuate command
104 16-Nov-02 RMS Fixed bug in register name match algorithm
105 13-Oct-02 RMS Fixed Borland compiler warnings (found by Hans Pufal)
106 05-Oct-02 RMS Fixed bugs in set_logon, ssh_break (found by David Hittner)
107 Added support for fixed buffer devices
108 Added support for Telnet console, removed VT support
110 Added VMS file optimizations (from Robert Alan Byer)
111 Added quiet mode, DO with parameters, GUI interface,
112 extensible commands (from Brian Knittel)
113 Added device enable/disable commands
114 14-Jul-02 RMS Fixed exit bug in do, added -v switch (from Brian Knittel)
115 17-May-02 RMS Fixed bug in fxread/fxwrite error usage (found by
117 02-May-02 RMS Added VT emulation interface, changed {NO}LOG to SET {NO}LOG
118 22-Apr-02 RMS Fixed laptop sleep problem in clock calibration, added
119 magtape record length error (found by Jonathan Engdahl)
120 26-Feb-02 RMS Fixed initialization bugs in do_cmd, get_aval
121 (found by Brian Knittel)
122 10-Feb-02 RMS Fixed problem in clock calibration
123 06-Jan-02 RMS Moved device enable/disable to simulators
124 30-Dec-01 RMS Generalized timer packaged, added circular arrays
125 19-Dec-01 RMS Fixed DO command bug (found by John Dundas)
126 07-Dec-01 RMS Implemented breakpoint package
127 05-Dec-01 RMS Fixed bug in universal register logic
128 03-Dec-01 RMS Added read-only units, extended SET/SHOW, universal registers
129 24-Nov-01 RMS Added unit-based registers
130 16-Nov-01 RMS Added DO command
131 28-Oct-01 RMS Added relative range addressing
132 08-Oct-01 RMS Added SHOW VERSION
133 30-Sep-01 RMS Relaxed attach test in BOOT
134 27-Sep-01 RMS Added queue count routine, fixed typo in ex/mod
135 17-Sep-01 RMS Removed multiple console support
136 07-Sep-01 RMS Removed conditional externs on function prototypes
137 Added special modifier print
138 31-Aug-01 RMS Changed int64 to t_int64 for Windoze (V2.7)
139 18-Jul-01 RMS Minor changes for Macintosh port
140 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy)
141 27-May-01 RMS Added multiple console support
142 16-May-01 RMS Added logging
143 15-May-01 RMS Added features from Tim Litt
144 12-May-01 RMS Fixed missing return in disable_cmd
145 25-Mar-01 RMS Added ENABLE/DISABLE
146 14-Mar-01 RMS Revised LOAD/DUMP interface (again)
147 05-Mar-01 RMS Added clock calibration support
148 05-Feb-01 RMS Fixed bug, DETACH buffered unit with hwmark = 0
149 04-Feb-01 RMS Fixed bug, RESTORE not using device's attach routine
150 21-Jan-01 RMS Added relative time
151 22-Dec-00 RMS Fixed find_device for devices ending in numbers
152 08-Dec-00 RMS V2.5a changes
153 30-Oct-00 RMS Added output file option to examine
154 11-Jul-99 RMS V2.5 changes
155 13-Apr-99 RMS Fixed handling of 32b addresses
156 04-Oct-98 RMS V2.4 changes
157 20-Aug-98 RMS Added radix commands
158 05-Jun-98 RMS Fixed bug in ^D handling for UNIX
159 10-Apr-98 RMS Added switches to all commands
160 26-Oct-97 RMS Added search capability
161 25-Jan-97 RMS Revised data types
162 23-Jan-97 RMS Added bi-endian I/O
163 06-Sep-96 RMS Fixed bug in variable length IEXAMINE
164 16-Jun-96 RMS Changed interface to parse/print_sym
165 06-Apr-96 RMS Added error checking in reset all
166 07-Jan-96 RMS Added register buffers in save/restore
167 11-Dec-95 RMS Fixed ordering bug in save/restore
168 22-May-95 RMS Added symbolic input
169 13-Apr-95 RMS Added symbolic printouts
172 /* Macros and data structures */
174 #include "sim_defs.h"
180 #include <sim_readline.h>
183 #define EX_D 0 /* deposit */
184 #define EX_E 1 /* examine */
185 #define EX_I 2 /* interactive */
186 #define SCH_OR 0 /* search logicals */
189 #define SCH_E 0 /* search booleans */
197 #define SSH_ST 0 /* set */
198 #define SSH_SH 1 /* show */
199 #define SSH_CL 2 /* clear */
201 #define DO_NEST_LVL 10 /* DO cmd nesting level */
202 #define SRBSIZ 1024 /* save/restore buffer */
203 #define SIM_BRK_INILNT 4096 /* bpt tbl length */
204 #define SIM_BRK_ALLTYP 0xFFFFFFFF
205 #define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \
206 sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \
209 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
211 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
212 #if defined (USE_INT64)
213 #define SZ_LOAD(sz,v,mb,j) \
214 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
215 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
216 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
217 else v = *(((t_uint64 *) mb) + ((uint32) j));
218 #define SZ_STORE(sz,v,mb,j) \
219 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
220 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
221 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
222 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
224 #define SZ_LOAD(sz,v,mb,j) \
225 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
226 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
227 else v = *(((uint32 *) mb) + ((uint32) j));
228 #define SZ_STORE(sz,v,mb,j) \
229 if (sz == sizeof (uint8)) *(((uint8 *) mb) + ((uint32) j)) = (uint8) v; \
230 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
231 else *(((uint32 *) mb) + ((uint32) j)) = v;
233 #define GET_SWITCHES(cp) \
234 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
235 #define GET_RADIX(val,dft) \
236 if (sim_switches & SWMASK ('O')) val = 8; \
237 else if (sim_switches & SWMASK ('D')) val = 10; \
238 else if (sim_switches & SWMASK ('H')) val = 16; \
243 extern char sim_name
[];
244 extern DEVICE
*sim_devices
[];
246 extern const char *sim_stop_messages
[];
247 extern t_stat
sim_instr (void);
248 extern t_stat
sim_load (FILE *ptr
, char *cptr
, char *fnam
, int32 flag
);
249 extern int32 sim_emax
;
250 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
251 UNIT
*uptr
, int32 sw
);
252 extern t_stat
parse_sym (char *cptr
, t_addr addr
, UNIT
*uptr
, t_value
*val
,
255 /* The per-simulator init routine is a weak global that defaults to NULL
256 The other per-simulator pointers can be overrriden by the init routine */
258 void (*sim_vm_init
) (void);
259 char* (*sim_vm_read
) (char *ptr
, int32 size
, FILE *stream
) = NULL
;
260 void (*sim_vm_post
) (t_bool from_scp
) = NULL
;
261 CTAB
*sim_vm_cmd
= NULL
;
262 void (*sim_vm_fprint_addr
) (FILE *st
, DEVICE
*dptr
, t_addr addr
) = NULL
;
263 t_addr (*sim_vm_parse_addr
) (DEVICE
*dptr
, char *cptr
, char **tptr
) = NULL
;
267 /* Set and show command processors */
269 t_stat
set_dev_radix (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
270 t_stat
set_dev_enbdis (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
271 t_stat
set_dev_debug (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
272 t_stat
set_unit_enbdis (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
273 t_stat
ssh_break (FILE *st
, char *cptr
, int32 flg
);
274 t_stat
show_cmd_fi (FILE *ofile
, int32 flag
, char *cptr
);
275 t_stat
show_config (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
276 t_stat
show_queue (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
277 t_stat
show_time (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
278 t_stat
show_mod_names (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
279 t_stat
show_log_names (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
280 t_stat
show_dev_radix (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
281 t_stat
show_dev_debug (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
282 t_stat
show_dev_logicals (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
283 t_stat
show_dev_modifiers (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
284 t_stat
show_version (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
285 t_stat
show_break (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
);
286 t_stat
show_device (FILE *st
, DEVICE
*dptr
, int32 flag
);
287 t_stat
show_unit (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
);
288 t_stat
show_all_mods (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flg
);
289 t_stat
show_one_mod (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, MTAB
*mptr
, char *cptr
, int32 flag
);
290 t_stat
sim_check_console (int32 sec
);
291 t_stat
sim_save (FILE *sfile
);
292 t_stat
sim_rest (FILE *rfile
);
294 /* Breakpoint package */
296 t_stat
sim_brk_init (void);
297 t_stat
sim_brk_set (t_addr loc
, int32 sw
, int32 ncnt
, char *act
);
298 t_stat
sim_brk_clr (t_addr loc
, int32 sw
);
299 t_stat
sim_brk_clrall (int32 sw
);
300 t_stat
sim_brk_show (FILE *st
, t_addr loc
, int32 sw
);
301 t_stat
sim_brk_showall (FILE *st
, int32 sw
);
302 char *sim_brk_getact (char *buf
, int32 size
);
303 void sim_brk_clract (void);
304 void sim_brk_npc (uint32 cnt
);
305 BRKTAB
*sim_brk_new (t_addr loc
);
307 /* Commands support routines */
309 SCHTAB
*get_search (char *cptr
, int32 radix
, SCHTAB
*schptr
);
310 int32
test_search (t_value val
, SCHTAB
*schptr
);
311 char *get_glyph_gen (char *iptr
, char *optr
, char mchar
, t_bool uc
);
312 int32
get_switches (char *cptr
);
313 char *get_sim_sw (char *cptr
);
314 t_stat
get_aval (t_addr addr
, DEVICE
*dptr
, UNIT
*uptr
);
315 t_value
get_rval (REG
*rptr
, uint32 idx
);
316 void put_rval (REG
*rptr
, uint32 idx
, t_value val
);
317 t_value
strtotv (char *inptr
, char **endptr
, uint32 radix
);
318 void fprint_help (FILE *st
);
319 void fprint_stopped (FILE *st
, t_stat r
);
320 void fprint_capac (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
);
321 char *read_line (char *ptr
, int32 size
, FILE *stream
);
322 REG
*find_reg_glob (char *ptr
, char **optr
, DEVICE
**gdptr
);
323 char *sim_trim_endspc (char *cptr
);
325 /* Forward references */
327 t_stat
scp_attach_unit (DEVICE
*dptr
, UNIT
*uptr
, char *cptr
);
328 t_stat
scp_detach_unit (DEVICE
*dptr
, UNIT
*uptr
);
329 t_bool
qdisable (DEVICE
*dptr
);
330 t_stat
attach_err (UNIT
*uptr
, t_stat stat
);
331 t_stat
detach_all (int32 start_device
, t_bool shutdown
);
332 t_stat
assign_device (DEVICE
*dptr
, char *cptr
);
333 t_stat
deassign_device (DEVICE
*dptr
);
334 t_stat
ssh_break_one (FILE *st
, int32 flg
, t_addr lo
, int32 cnt
, char *aptr
);
335 t_stat
run_boot_prep (void);
336 t_stat
exdep_reg_loop (FILE *ofile
, SCHTAB
*schptr
, int32 flag
, char *cptr
,
337 REG
*lowr
, REG
*highr
, uint32 lows
, uint32 highs
);
338 t_stat
ex_reg (FILE *ofile
, t_value val
, int32 flag
, REG
*rptr
, uint32 idx
);
339 t_stat
dep_reg (int32 flag
, char *cptr
, REG
*rptr
, uint32 idx
);
340 t_stat
exdep_addr_loop (FILE *ofile
, SCHTAB
*schptr
, int32 flag
, char *cptr
,
341 t_addr low
, t_addr high
, DEVICE
*dptr
, UNIT
*uptr
);
342 t_stat
ex_addr (FILE *ofile
, int32 flag
, t_addr addr
, DEVICE
*dptr
, UNIT
*uptr
);
343 t_stat
dep_addr (int32 flag
, char *cptr
, t_addr addr
, DEVICE
*dptr
,
344 UNIT
*uptr
, int32 dfltinc
);
345 t_stat
step_svc (UNIT
*ptr
);
346 void sub_args (char *instr
, char *tmpbuf
, int32 maxstr
, int32 nargs
, char *do_arg
[]);
350 DEVICE
*sim_dflt_dev
= NULL
;
351 UNIT
*sim_clock_queue
= NULL
;
352 int32 sim_interval
= 0;
353 int32 sim_switches
= 0;
354 FILE *sim_ofile
= NULL
;
355 SCHTAB
*sim_schptr
= FALSE
;
356 DEVICE
*sim_dfdev
= NULL
;
357 UNIT
*sim_dfunit
= NULL
;
358 int32 sim_opt_out
= 0;
359 int32 sim_is_running
= 0;
360 uint32 sim_brk_summ
= 0;
361 uint32 sim_brk_types
= 0;
362 uint32 sim_brk_dflt
= 0;
363 char *sim_brk_act
= NULL
;
364 BRKTAB
*sim_brk_tab
= NULL
;
365 int32 sim_brk_ent
= 0;
366 int32 sim_brk_lnt
= 0;
367 int32 sim_brk_ins
= 0;
368 t_bool sim_brk_pend
[SIM_BKPT_N_SPC
] = { FALSE
};
369 t_addr sim_brk_ploc
[SIM_BKPT_N_SPC
] = { 0 };
372 static double sim_time
;
373 static uint32 sim_rtime
;
374 static int32 noqueue_time
;
375 volatile int32 stop_cpu
= 0;
376 t_value
*sim_eval
= NULL
;
377 int32 sim_deb_close
= 0; /* 1 = close debug */
378 FILE *sim_log
= NULL
; /* log file */
379 FILE *sim_deb
= NULL
; /* debug file */
380 static SCHTAB sim_stab
;
382 static UNIT sim_step_unit
= { UDATA (&step_svc
, 0, 0) };
383 #if defined USE_INT64
384 static const char *sim_si64
= "64b data";
386 static const char *sim_si64
= "32b data";
388 #if defined USE_ADDR64
389 static const char *sim_sa64
= "64b addresses";
391 static const char *sim_sa64
= "32b addresses";
393 #if defined USE_NETWORK
394 static const char *sim_snet
= "Ethernet support";
396 static const char *sim_snet
= "no Ethernet";
399 /* Tables and strings */
401 const char save_vercur
[] = "V3.5";
402 const char save_ver32
[] = "V3.2";
403 const char save_ver30
[] = "V3.0";
404 const char *scp_error_messages
[] = {
405 "Address space exceeded",
410 "Unit not attachable",
416 "Read only argument",
417 "Command not completed",
418 "Simulation stopped",
420 "Console input I/O error",
421 "Console output I/O error",
424 "No settable parameters",
425 "Unit already attached",
426 "Hardware timer error",
427 "SIGINT handler setup error",
428 "Console terminal setup error",
429 "Subscript out of range",
430 "Command not allowed",
432 "Read only operation not allowed",
436 "Too many arguments",
437 "Non-existent device",
439 "Non-existent register",
440 "Non-existent parameter",
441 "Nested DO command limit exceeded",
443 "Invalid magtape record length",
444 "Console Telnet connection lost",
445 "Console Telnet connection timed out",
446 "Console Telnet output stall",
450 const size_t size_map
[] = { sizeof (int8
),
451 sizeof (int8
), sizeof (int16
), sizeof (int32
), sizeof (int32
)
452 #if defined (USE_INT64)
453 , sizeof (t_int64
), sizeof (t_int64
), sizeof (t_int64
), sizeof (t_int64
)
457 const t_value width_mask
[] = { 0,
459 0x1F, 0x3F, 0x7F, 0xFF,
460 0x1FF, 0x3FF, 0x7FF, 0xFFF,
461 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
462 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
463 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
464 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
465 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
466 #if defined (USE_INT64)
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,
474 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
475 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF,
476 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
480 static CTAB cmd_table
[] = {
481 { "RESET", &reset_cmd
, 0,
482 "r{eset} {ALL|<device>} reset simulator\n" },
483 { "EXAMINE", &exdep_cmd
, EX_E
,
484 "e{xamine} <list> examine memory or registers\n" },
485 { "IEXAMINE", &exdep_cmd
, EX_E
+EX_I
,
486 "ie{xamine} <list> interactive examine memory or registers\n" },
487 { "DEPOSIT", &exdep_cmd
, EX_D
,
488 "d{eposit} <list> <val> deposit in memory or registers\n" },
489 { "IDEPOSIT", &exdep_cmd
, EX_D
+EX_I
,
490 "id{eposit} <list> interactive deposit in memory or registers\n" },
491 { "EVALUATE", &eval_cmd
, 0,
492 "ev{aluate} <expr> evaluate symbolic expression\n" },
493 { "RUN", &run_cmd
, RU_RUN
,
494 "ru{n} {new PC} reset and start simulation\n" },
495 { "GO", &run_cmd
, RU_GO
,
496 "go {new PC} start simulation\n" },
497 { "STEP", &run_cmd
, RU_STEP
,
498 "s{tep} {n} simulate n instructions\n" },
499 { "CONT", &run_cmd
, RU_CONT
,
500 "c{ont} continue simulation\n" },
501 { "BOOT", &run_cmd
, RU_BOOT
,
502 "b{oot} <unit> bootstrap unit\n" },
503 { "BREAK", &brk_cmd
, SSH_ST
,
504 "br{eak} <list> set breakpoints\n" },
505 { "NOBREAK", &brk_cmd
, SSH_CL
,
506 "nobr{eak} <list> clear breakpoints\n" },
507 { "ATTACH", &attach_cmd
, 0,
508 "at{tach} <unit> <file> attach file to simulated unit\n" },
509 { "DETACH", &detach_cmd
, 0,
510 "det{ach} <unit> detach file from simulated unit\n" },
511 { "ASSIGN", &assign_cmd
, 0,
512 "as{sign} <device> <name> assign logical name for device\n" },
513 { "DEASSIGN", &deassign_cmd
, 0,
514 "dea{ssign} <device> deassign logical name for device\n" },
515 { "SAVE", &save_cmd
, 0,
516 "sa{ve} <file> save simulator to file\n" },
517 { "RESTORE", &restore_cmd
, 0,
518 "rest{ore}|ge{t} <file> restore simulator from file\n" },
519 { "GET", &restore_cmd
, 0, NULL
},
520 { "LOAD", &load_cmd
, 0,
521 "l{oad} <file> {<args>} load binary file\n" },
522 { "DUMP", &load_cmd
, 1,
523 "du(mp) <file> {<args>} dump binary file\n" },
524 { "EXIT", &exit_cmd
, 0,
525 "exi{t}|q{uit}|by{e} exit from simulation\n" },
526 { "QUIT", &exit_cmd
, 0, NULL
},
527 { "BYE", &exit_cmd
, 0, NULL
},
528 { "SET", &set_cmd
, 0,
529 "set console arg{,arg...} set console options\n"
530 "set break <list> set breakpoints\n"
531 "set nobreak <list> clear breakpoints\n"
532 "set throttle x{M|K|%%} set simulation rate\n"
533 "set nothrottle set simulation rate to maximum\n"
534 "set <dev> OCT|DEC|HEX set device display radix\n"
535 "set <dev> ENABLED enable device\n"
536 "set <dev> DISABLED disable device\n"
537 "set <dev> DEBUG{=arg} set device debug flags\n"
538 "set <dev> NODEBUG={arg} clear device debug flags\n"
539 "set <dev> arg{,arg...} set device parameters\n"
540 "set <unit> ENABLED enable unit\n"
541 "set <unit> DISABLED disable unit\n"
542 "set <unit> arg{,arg...} set unit parameters\n"
544 { "SHOW", &show_cmd
, 0,
545 "sh{ow} br{eak} <list> show breakpoints\n"
546 "sh{ow} con{figuration} show configuration\n"
547 "sh{ow} cons{ole} {arg} show console options\n"
548 "sh{ow} dev{ices} show devices\n"
549 "sh{ow} m{odifiers} show modifiers\n"
550 "sh{ow} n{ames} show logical names\n"
551 "sh{ow} q{ueue} show event queue\n"
552 "sh{ow} ti{me} show simulated time\n"
553 "sh{ow} th{rottle} show simulation rate\n"
554 "sh{ow} ve{rsion} show simulator version\n"
555 "sh{ow} <dev> RADIX show device display radix\n"
556 "sh{ow} <dev> DEBUG show device debug flags\n"
557 "sh{ow} <dev> MODIFIERS show device modifiers\n"
558 "sh{ow} <dev} NAMES show device logical name\n"
559 "sh{ow} <dev> {arg,...} show device parameters\n"
560 "sh{ow} <unit> {arg,...} show unit parameters\n" },
562 "do <file> {arg,arg...} process command file\n" },
563 { "ECHO", &echo_cmd
, 0,
564 "echo <string> display <string>\n" },
565 { "ASSERT", &assert_cmd
, 0,
566 "assert {<dev>} <cond> test simulator state against condition\n" },
567 { "HELP", &help_cmd
, 0,
568 "h{elp} type this message\n"
569 "h{elp} <command> type help for command\n" },
570 { "!", &spawn_cmd
, 0,
571 "! execute local command interpreter\n"
572 "! <command> execute local host command\n" },
576 /* Main command loop */
578 int main (int argc
, char *argv
[])
580 char cbuf
[CBUFSIZE
], gbuf
[CBUFSIZE
], *cptr
;
587 readline_read_history();
590 #if defined (__MWERKS__) && defined (macintosh)
591 argc
= ccommand (&argv
);
594 *cbuf
= 0; /* init arg buffer */
595 sim_switches
= 0; /* init switches */
597 for (i
= 1; i
< argc
; i
++) { /* loop thru args */
598 if (argv
[i
] == NULL
) continue; /* paranoia */
599 if ((*argv
[i
] == '-') && lookswitch
) { /* switch? */
600 if ((sw
= get_switches (argv
[i
])) < 0) {
601 fprintf (stderr
, "Invalid switch %s\n", argv
[i
]);
604 sim_switches
= sim_switches
| sw
;
607 if ((strlen (argv
[i
]) + strlen (cbuf
) + 1) >= CBUFSIZE
) {
608 fprintf (stderr
, "Argument string too long\n");
611 if (*cbuf
) strcat (cbuf
, " "); /* concat args */
612 strcat (cbuf
, argv
[i
]);
613 lookswitch
= FALSE
; /* no more switches */
616 sim_quiet
= sim_switches
& SWMASK ('Q'); /* -q means quiet */
618 if (sim_vm_init
!= NULL
) (*sim_vm_init
)(); /* call once only */
619 sim_finit (); /* init fio package */
622 sim_time
= sim_rtime
= 0;
624 sim_clock_queue
= NULL
;
627 if (sim_emax
<= 0) sim_emax
= 1;
630 if ((stat
= sim_ttinit ()) != SCPE_OK
) {
631 fprintf (stderr
, "Fatal terminal initialization error\n%s\n",
632 scp_error_messages
[stat
- SCPE_BASE
]);
635 if ((sim_eval
= (t_value
*) calloc (sim_emax
, sizeof (t_value
))) == NULL
) {
636 fprintf (stderr
, "Unable to allocate examine buffer\n");
639 if ((stat
= reset_all_p (0)) != SCPE_OK
) {
640 fprintf (stderr
, "Fatal simulator initialization error\n%s\n",
641 scp_error_messages
[stat
- SCPE_BASE
]);
644 if ((stat
= sim_brk_init ()) != SCPE_OK
) {
645 fprintf (stderr
, "Fatal breakpoint table initialization error\n%s\n",
646 scp_error_messages
[stat
- SCPE_BASE
]);
651 show_version (stdout
, NULL
, NULL
, 0, NULL
);
653 if (sim_dflt_dev
== NULL
) sim_dflt_dev
= sim_devices
[0]; /* if no default */
655 if (*cbuf
) /* cmd file arg? */
656 stat
= do_cmd (0, cbuf
); /* proc cmd file */
657 else if (*argv
[0]) { /* sim name arg? */
658 char nbuf
[PATH_MAX
+ 7], *np
; /* "path.ini" */
659 nbuf
[0] = '"'; /* starting " */
660 strncpy (nbuf
+ 1, argv
[0], PATH_MAX
+ 1); /* copy sim name */
661 if (np
= match_ext (nbuf
, "EXE")) *np
= 0; /* remove .exe */
662 strcat (nbuf
, ".ini\""); /* add .ini" */
663 stat
= do_cmd (-1, nbuf
); /* proc cmd file */
666 while (stat
!= SCPE_EXIT
) { /* in case exit */
668 if (cptr
= sim_brk_getact (cbuf
, CBUFSIZE
)) /* pending action? */
669 printf ("sim> %s\n", cptr
); /* echo */
670 else if (sim_vm_read
!= NULL
) /* sim routine? */
671 cptr
= (*sim_vm_read
) (cbuf
, CBUFSIZE
, stdin
);
675 cptr
= readline_read_line(cbuf
,CBUFSIZE
,"sim>");
678 cptr
= read_line (cbuf
, CBUFSIZE
, stdin
); /* read command line */
680 if (cptr
== NULL
){ /* ignore EOF */
684 if (*cptr
== 0) continue; /* ignore blank */
686 if (sim_log
) fprintf (sim_log
, "sim> %s\n", cptr
); /* log cmd */
687 cptr
= get_glyph (cptr
, gbuf
, 0); /* get command glyph */
688 sim_switches
= 0; /* init switches */
689 if (cmdp
= find_cmd (gbuf
)) /* lookup command */
690 stat
= cmdp
->action (cmdp
->arg
, cptr
); /* if found, exec */
691 else stat
= SCPE_UNK
;
692 if (stat
>= SCPE_BASE
) { /* error? */
693 printf ("%s\n", scp_error_messages
[stat
- SCPE_BASE
]);
694 if (sim_log
) fprintf (sim_log
, "%s\n",
695 scp_error_messages
[stat
- SCPE_BASE
]);
697 if (sim_vm_post
!= NULL
) (*sim_vm_post
) (TRUE
);
700 detach_all (0, TRUE
); /* close files */
701 sim_set_deboff (0, NULL
); /* close debug */
702 sim_set_logoff (0, NULL
); /* close log */
703 sim_set_notelnet (0, NULL
); /* close Telnet */
704 sim_ttclose (); /* close console */
706 /* Write command history back to file */
708 readline_write_history();
714 /* Find command routine */
716 CTAB
*find_cmd (char *gbuf
)
720 if (sim_vm_cmd
) cmdp
= find_ctab (sim_vm_cmd
, gbuf
); /* try ext commands */
721 if (cmdp
== NULL
) cmdp
= find_ctab (cmd_table
, gbuf
); /* try regular cmds */
727 t_stat
exit_cmd (int32 flag
, char *cptr
)
734 void fprint_help (FILE *st
)
738 for (cmdp
= sim_vm_cmd
; cmdp
&& (cmdp
->name
!= NULL
); cmdp
++) {
739 if (cmdp
->help
) fprintf (st
, cmdp
->help
);
741 for (cmdp
= cmd_table
; cmdp
&& (cmdp
->name
!= NULL
); cmdp
++) {
742 if (cmdp
->help
&& (!sim_vm_cmd
|| !find_ctab (sim_vm_cmd
, cmdp
->name
)))
743 fprintf (st
, cmdp
->help
);
748 t_stat
help_cmd (int32 flag
, char *cptr
)
755 cptr
= get_glyph (cptr
, gbuf
, 0);
756 if (*cptr
) return SCPE_2MARG
;
757 if (cmdp
= find_cmd (gbuf
)) {
759 if (sim_log
) fprintf (sim_log
, cmdp
->help
);
761 else return SCPE_ARG
;
764 fprint_help (stdout
);
765 if (sim_log
) fprint_help (sim_log
);
772 t_stat
spawn_cmd (int32 flag
, char *cptr
)
774 if ((cptr
== NULL
) || (strlen (cptr
) == 0)) cptr
= getenv("SHELL");
775 if ((cptr
== NULL
) || (strlen (cptr
) == 0)) cptr
= getenv("ComSpec");
777 if ((cptr
== NULL
) || (strlen (cptr
) == 0)) cptr
= "SPAWN/INPUT=SYS$COMMAND:";
779 fflush(stdout
); /* flush stdout */
780 if (sim_log
) fflush (sim_log
); /* flush log if enabled */
791 t_stat
echo_cmd (int32 flag
, char *cptr
)
794 if (sim_log
) fprintf (sim_log
, "%s\n", cptr
);
800 Syntax: DO {-E} {-V} <filename> {<arguments>...}
802 -E causes all command errors to be fatal; without it, only EXIT and ASSERT
803 failure will stop a command file.
805 -V causes commands to be echoed before execution.
807 Note that SCPE_STEP ("Step expired") is considered a note and not an error
808 and so does not abort command execution when using -E.
811 flag = caller and nesting level indicator
812 fcptr = filename and optional arguments, space-separated
814 status = error status
816 The "flag" input value indicates the source of the call, as follows:
818 -1 = initialization file (no error if not found)
819 0 = command line file
821 >1 = nested "DO" command
824 #define SCPE_DOFAILED 0040000 /* fail in DO, not subproc */
826 t_stat
do_cmd (int32 flag
, char *fcptr
)
828 char *cptr
, cbuf
[CBUFSIZE
], gbuf
[CBUFSIZE
], *c
, quote
, *do_arg
[10];
831 int32 echo
, nargs
, errabort
;
832 t_bool interactive
, isdo
, staying
;
838 interactive
= (flag
> 0); /* issued interactively? */
839 if (interactive
) { GET_SWITCHES (fcptr
); } /* get switches */
840 echo
= sim_switches
& SWMASK ('V'); /* -v means echo */
841 errabort
= sim_switches
& SWMASK ('E'); /* -e means abort on error */
844 for (nargs
= 0; nargs
< 10; ) { /* extract arguments */
845 while (isspace (*c
)) c
++; /* skip blanks */
846 if (*c
== 0) break; /* all done */
847 if (*c
== '\'' || *c
== '"') quote
= *c
++; /* quoted string? */
849 do_arg
[nargs
++] = c
; /* save start */
850 while (*c
&& (quote
? (*c
!= quote
): !isspace (*c
))) c
++;
851 if (*c
) *c
++ = 0; /* term at quote/spc */
853 if (nargs
<= 0) return SCPE_2FARG
; /* need at least 1 */
854 if ((fpin
= fopen (do_arg
[0], "r")) == NULL
) { /* file failed to open? */
855 if (flag
== 0) /* cmd line file? */
856 fprintf (stderr
, "Can't open file %s\n", do_arg
[0]);
858 return SCPE_OPENERR
| SCPE_DOFAILED
; /* return failure with flag */
860 return SCPE_OPENERR
; /* return failure */
862 if (flag
< 1) flag
= 1; /* start at level 1 */
865 ocptr
= cptr
= sim_brk_getact (cbuf
, CBUFSIZE
); /* get bkpt action */
866 if (!ocptr
) /* no pending action? */
867 ocptr
= cptr
= read_line (cbuf
, CBUFSIZE
, fpin
); /* get cmd line */
868 sub_args (cbuf
, gbuf
, CBUFSIZE
, nargs
, do_arg
); /* substitute args */
869 if (cptr
== NULL
) { /* EOF? */
870 stat
= SCPE_OK
; /* set good return */
873 if (*cptr
== 0) continue; /* ignore blank */
874 if (echo
) printf("do> %s\n", cptr
); /* echo if -v */
875 if (echo
&& sim_log
) fprintf (sim_log
, "do> %s\n", cptr
);
876 cptr
= get_glyph (cptr
, gbuf
, 0); /* get command glyph */
877 sim_switches
= 0; /* init switches */
879 if (cmdp
= find_cmd (gbuf
)) { /* lookup command */
880 isdo
= (cmdp
->action
== &do_cmd
);
881 if (isdo
) { /* DO command? */
882 if (flag
>= DO_NEST_LVL
) stat
= SCPE_NEST
; /* nest too deep? */
883 else stat
= do_cmd (flag
+ 1, cptr
); /* exec DO cmd */
885 else stat
= cmdp
->action (cmdp
->arg
, cptr
); /* exec other cmd */
887 else stat
= SCPE_UNK
; /* bad cmd given */
888 staying
= (stat
!= SCPE_EXIT
) && /* decide if staying */
889 (stat
!= SCPE_AFAIL
) &&
890 (!errabort
|| (stat
< SCPE_BASE
) || (stat
== SCPE_STEP
));
891 if ((stat
>= SCPE_BASE
) && (stat
!= SCPE_EXIT
) && /* error from cmd? */
892 (stat
!= SCPE_STEP
)) {
893 if (!echo
&& !sim_quiet
&& /* report if not echoing */
894 (!isdo
|| (stat
& SCPE_DOFAILED
))) { /* and not from DO return */
895 printf("%s> %s\n", do_arg
[0], ocptr
);
897 fprintf (sim_log
, "%s> %s\n", do_arg
[0], ocptr
);
899 stat
= stat
& ~SCPE_DOFAILED
; /* remove possible flag */
901 if ((staying
|| !interactive
) && /* report error if staying */
902 (stat
>= SCPE_BASE
)) { /* or in cmdline file */
903 printf ("%s\n", scp_error_messages
[stat
- SCPE_BASE
]);
904 if (sim_log
) fprintf (sim_log
, "%s\n",
905 scp_error_messages
[stat
- SCPE_BASE
]);
907 if (sim_vm_post
!= NULL
) (*sim_vm_post
) (TRUE
);
910 fclose (fpin
); /* close file */
914 /* Substitute_args - replace %n tokens in 'instr' with the do command's arguments
919 maxstr = min (len (instr), len (tmpbuf))
920 nargs = number of arguments
921 do_arg[10] = arguments
924 void sub_args (char *instr
, char *tmpbuf
, int32 maxstr
, int32 nargs
, char *do_arg
[])
926 char *ip
, *op
, *ap
, *oend
= tmpbuf
+ maxstr
- 2;
928 for (ip
= instr
, op
= tmpbuf
; *ip
&& (op
< oend
); ) {
929 if ((*ip
== '\\') && (ip
[1] == '%')) { /* \% = literal % */
931 if (*ip
) *op
++ = *ip
++; /* copy next */
933 else if ((*ip
== '%') && /* %n = sub */
934 ((ip
[1] >= '1') && (ip
[1] <= ('0'+ nargs
- 1)))) {
935 ap
= do_arg
[ip
[1] - '0'];
937 while (*ap
&& (op
< oend
)) *op
++ = *ap
++; /* copy the argument */
939 else *op
++ = *ip
++; /* literal character */
941 *op
= 0; /* term buffer */
942 strcpy (instr
, tmpbuf
);
948 Syntax: ASSERT {<dev>} <reg>{<logical-op><value>}<conditional-op><value>
950 If <dev> is not specified, CPU is assumed. <value> is expressed in the radix
951 specified for <reg>. <logical-op> and <conditional-op> are the same as that
952 allowed for examine and deposit search specifications. */
954 t_stat
assert_cmd (int32 flag
, char *cptr
)
956 char gbuf
[CBUFSIZE
], *gptr
, *aptr
, *tptr
;
962 aptr
= cptr
; /* save assertion */
963 cptr
= get_sim_opt (CMD_OPT_SW
|CMD_OPT_DFT
, cptr
, &r
); /* get sw, default */
964 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
965 cptr
= get_glyph (cptr
, gbuf
, 0); /* get register */
966 rptr
= find_reg (gbuf
, &gptr
, sim_dfdev
); /* parse register */
967 if (!rptr
) return SCPE_NXREG
; /* not there */
968 if (*gptr
== '[') { /* subscript? */
969 if (rptr
->depth
<= 1) return SCPE_ARG
; /* array register? */
970 idx
= (uint32
) strtotv (++gptr
, &tptr
, 10); /* convert index */
971 if ((gptr
== tptr
) || (*tptr
++ != ']')) return SCPE_ARG
;
972 gptr
= tptr
; /* update */
974 else idx
= 0; /* not array */
975 if (idx
>= rptr
->depth
) return SCPE_SUB
; /* validate subscript */
976 if (*gptr
!= 0) get_glyph (gptr
, gbuf
, 0); /* more? must be search */
978 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
979 cptr
= get_glyph (cptr
, gbuf
, 0); /* get search cond */
981 if (*cptr
!= 0) return SCPE_2MARG
; /* must be done */
982 if (!get_search (gbuf
, rptr
->radix
, &sim_stab
)) /* parse condition */
984 val
= get_rval (rptr
, idx
); /* get register value */
985 if (test_search (val
, &sim_stab
)) return SCPE_OK
; /* test condition */
986 return SCPE_AFAIL
; /* condition fails */
991 t_stat
set_cmd (int32 flag
, char *cptr
)
995 char gbuf
[CBUFSIZE
], *cvptr
, *svptr
;
1002 static CTAB set_glob_tab
[] = {
1003 { "CONSOLE", &sim_set_console
, 0 },
1004 { "BREAK", &brk_cmd
, SSH_ST
},
1005 { "TELNET", &sim_set_telnet
, 0 }, /* deprecated */
1006 { "NOTELNET", &sim_set_notelnet
, 0 }, /* deprecated */
1007 { "LOG", &sim_set_logon
, 0 }, /* deprecated */
1008 { "NOLOG", &sim_set_logoff
, 0 }, /* deprecated */
1009 { "DEBUG", &sim_set_debon
, 0 }, /* deprecated */
1010 { "NODEBUG", &sim_set_deboff
, 0 }, /* deprecated */
1011 { "THROTTLE", &sim_set_throt
, 1 },
1012 { "NOTHROTTLE", &sim_set_throt
, 0 },
1016 static C1TAB set_dev_tab
[] = {
1017 { "OCTAL", &set_dev_radix
, 8 },
1018 { "DECIMAL", &set_dev_radix
, 10 },
1019 { "HEX", &set_dev_radix
, 16 },
1020 { "ENABLED", &set_dev_enbdis
, 1 },
1021 { "DISABLED", &set_dev_enbdis
, 0 },
1022 { "DEBUG", &set_dev_debug
, 1 },
1023 { "NODEBUG", &set_dev_debug
, 0 },
1027 static C1TAB set_unit_tab
[] = {
1028 { "ENABLED", &set_unit_enbdis
, 1 },
1029 { "DISABLED", &set_unit_enbdis
, 0 },
1033 GET_SWITCHES (cptr
); /* get switches */
1034 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1035 cptr
= get_glyph (cptr
, gbuf
, 0); /* get glob/dev/unit */
1037 if (dptr
= find_dev (gbuf
)) { /* device match? */
1038 uptr
= dptr
->units
; /* first unit */
1039 ctbr
= set_dev_tab
; /* global table */
1040 lvl
= MTAB_VDV
; /* device match */
1042 else if (dptr
= find_unit (gbuf
, &uptr
)) { /* unit match? */
1043 if (uptr
== NULL
) return SCPE_NXUN
; /* invalid unit */
1044 ctbr
= set_unit_tab
; /* global table */
1045 lvl
= MTAB_VUN
; /* unit match */
1047 else if (gcmdp
= find_ctab (set_glob_tab
, gbuf
)) /* global? */
1048 return gcmdp
->action (gcmdp
->arg
, cptr
); /* do the rest */
1049 else return SCPE_NXDEV
; /* no match */
1050 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1052 while (*cptr
!= 0) { /* do all mods */
1053 cptr
= get_glyph (svptr
= cptr
, gbuf
, ','); /* get modifier */
1054 if (cvptr
= strchr (gbuf
, '=')) *cvptr
++ = 0; /* = value? */
1055 for (mptr
= dptr
->modifiers
; mptr
&& (mptr
->mask
!= 0); mptr
++) {
1056 if ((mptr
->mstring
) && /* match string */
1057 (MATCH_CMD (gbuf
, mptr
->mstring
) == 0)) { /* matches option? */
1058 if (mptr
->mask
& MTAB_XTD
) { /* extended? */
1059 if ((lvl
& mptr
->mask
) == 0) return SCPE_ARG
;
1060 if ((lvl
& MTAB_VUN
) && (uptr
->flags
& UNIT_DIS
))
1061 return SCPE_UDIS
; /* unit disabled? */
1062 if (mptr
->valid
) { /* validation rtn? */
1063 if (cvptr
&& (mptr
->mask
& MTAB_NC
))
1064 get_glyph_nc (svptr
, gbuf
, ',');
1065 r
= mptr
->valid (uptr
, mptr
->match
, cvptr
, mptr
->desc
);
1066 if (r
!= SCPE_OK
) return r
;
1068 else if (!mptr
->desc
) break; /* value desc? */
1069 else if (mptr
->mask
& MTAB_VAL
) { /* take a value? */
1070 if (!cvptr
) return SCPE_MISVAL
; /* none? error */
1071 r
= dep_reg (0, cvptr
, (REG
*) mptr
->desc
, 0);
1072 if (r
!= SCPE_OK
) return r
;
1074 else if (cvptr
) return SCPE_ARG
; /* = value? */
1075 else *((int32
*) mptr
->desc
) = mptr
->match
;
1077 else { /* old style */
1078 if (cvptr
) return SCPE_ARG
; /* = value? */
1079 if (uptr
->flags
& UNIT_DIS
) /* disabled? */
1081 if ((mptr
->valid
) && ((r
= mptr
->valid
1082 (uptr
, mptr
->match
, cvptr
, mptr
->desc
))
1083 != SCPE_OK
)) return r
; /* invalid? */
1084 uptr
->flags
= (uptr
->flags
& ~(mptr
->mask
)) |
1085 (mptr
->match
& mptr
->mask
); /* set new value */
1086 } /* end else xtd */
1087 break; /* terminate for */
1088 } /* end if match */
1090 if (!mptr
|| (mptr
->mask
== 0)) { /* no match? */
1091 if (glbr
= find_c1tab (ctbr
, gbuf
)) { /* global match? */
1092 r
= glbr
->action (dptr
, uptr
, glbr
->arg
, cvptr
); /* do global */
1093 if (r
!= SCPE_OK
) return r
;
1095 else if (!dptr
->modifiers
) return SCPE_NOPARAM
; /* no modifiers? */
1096 else return SCPE_NXPAR
;
1097 } /* end if no mat */
1099 return SCPE_OK
; /* done all */
1102 /* Match CTAB/CTAB1 name */
1104 CTAB
*find_ctab (CTAB
*tab
, char *gbuf
)
1106 for (; tab
->name
!= NULL
; tab
++) {
1107 if (MATCH_CMD (gbuf
, tab
->name
) == 0) return tab
;
1112 C1TAB
*find_c1tab (C1TAB
*tab
, char *gbuf
)
1114 for (; tab
->name
!= NULL
; tab
++) {
1115 if (MATCH_CMD (gbuf
, tab
->name
) == 0) return tab
;
1120 /* Set device data radix routine */
1122 t_stat
set_dev_radix (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1124 if (cptr
) return SCPE_ARG
;
1125 dptr
->dradix
= flag
& 037;
1129 /* Set device enabled/disabled routine */
1131 t_stat
set_dev_enbdis (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1136 if (cptr
) return SCPE_ARG
;
1137 if ((dptr
->flags
& DEV_DISABLE
) == 0) return SCPE_NOFNC
;/* allowed? */
1138 if (flag
) { /* enable? */
1139 if ((dptr
->flags
& DEV_DIS
) == 0) /* already enb? ok */
1141 dptr
->flags
= dptr
->flags
& ~DEV_DIS
; /* no, enable */
1144 if (dptr
->flags
& DEV_DIS
) return SCPE_OK
; /* already dsb? ok */
1145 for (i
= 0; i
< dptr
->numunits
; i
++) { /* check units */
1146 up
= (dptr
->units
) + i
; /* att or active? */
1147 if ((up
->flags
& UNIT_ATT
) || sim_is_active (up
))
1148 return SCPE_NOFNC
; /* can't do it */
1150 dptr
->flags
= dptr
->flags
| DEV_DIS
; /* disable */
1152 if (dptr
->reset
) return dptr
->reset (dptr
); /* reset device */
1153 else return SCPE_OK
;
1156 /* Set unit enabled/disabled routine */
1158 t_stat
set_unit_enbdis (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1160 if (cptr
) return SCPE_ARG
;
1161 if (!(uptr
->flags
& UNIT_DISABLE
)) return SCPE_NOFNC
; /* allowed? */
1162 if (flag
) uptr
->flags
= uptr
->flags
& ~UNIT_DIS
; /* enb? enable */
1164 if ((uptr
->flags
& UNIT_ATT
) || /* dsb */
1165 sim_is_active (uptr
)) return SCPE_NOFNC
; /* more tests */
1166 uptr
->flags
= uptr
->flags
| UNIT_DIS
; /* disable */
1171 /* Set device debug enabled/disabled routine */
1173 t_stat
set_dev_debug (DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1175 char gbuf
[CBUFSIZE
];
1178 if ((dptr
->flags
& DEV_DEBUG
) == 0) return SCPE_NOFNC
;
1179 if (cptr
== NULL
) { /* no arguments? */
1180 dptr
->dctrl
= flag
; /* disable/enable w/o table */
1181 if (flag
&& dptr
->debflags
) { /* enable with table? */
1182 for (dep
= dptr
->debflags
; dep
->name
!= NULL
; dep
++)
1183 dptr
->dctrl
= dptr
->dctrl
| dep
->mask
; /* set all */
1187 if (dptr
->debflags
== NULL
) return SCPE_ARG
; /* must have table */
1189 cptr
= get_glyph (cptr
, gbuf
, ';'); /* get debug flag */
1190 for (dep
= dptr
->debflags
; dep
->name
!= NULL
; dep
++) {
1191 if (strcmp (dep
->name
, gbuf
) == 0) { /* match? */
1192 if (flag
) dptr
->dctrl
= dptr
->dctrl
| dep
->mask
;
1193 else dptr
->dctrl
= dptr
->dctrl
& ~dep
->mask
;
1197 if (dep
->mask
== 0) return SCPE_ARG
; /* no match? */
1204 t_stat
show_cmd (int32 flag
, char *cptr
)
1208 cptr
= get_sim_opt (CMD_OPT_SW
|CMD_OPT_OF
, cptr
, &r
); /* get sw, ofile */
1209 if (!cptr
) return r
; /* error? */
1210 if (sim_ofile
) { /* output file? */
1211 r
= show_cmd_fi (sim_ofile
, flag
, cptr
); /* do show */
1215 r
= show_cmd_fi (stdout
, flag
, cptr
); /* no, stdout, log */
1216 if (sim_log
) show_cmd_fi (sim_log
, flag
, cptr
);
1221 t_stat
show_cmd_fi (FILE *ofile
, int32 flag
, char *cptr
)
1224 char gbuf
[CBUFSIZE
], *cvptr
;
1228 SHTAB
*shtb
, *shptr
;
1230 static SHTAB show_glob_tab
[] = {
1231 { "CONFIGURATION", &show_config
, 0 },
1232 { "DEVICES", &show_config
, 1 },
1233 { "QUEUE", &show_queue
, 0 },
1234 { "TIME", &show_time
, 0 },
1235 { "MODIFIERS", &show_mod_names
, 0 },
1236 { "NAMES", &show_log_names
, 0 },
1237 { "VERSION", &show_version
, 1 },
1238 { "CONSOLE", &sim_show_console
, 0 },
1239 { "BREAK", &show_break
, 0 },
1240 { "LOG", &sim_show_log
, 0 }, /* deprecated */
1241 { "TELNET", &sim_show_telnet
, 0 }, /* deprecated */
1242 { "DEBUG", &sim_show_debug
, 0 }, /* deprecated */
1243 { "THROTTLE", &sim_show_throt
, 0 },
1247 static SHTAB show_dev_tab
[] = {
1248 { "RADIX", &show_dev_radix
, 0 },
1249 { "DEBUG", &show_dev_debug
, 0 },
1250 { "MODIFIERS", &show_dev_modifiers
, 0 },
1251 { "NAMES", &show_dev_logicals
, 0 },
1255 static SHTAB show_unit_tab
[] = {
1259 GET_SWITCHES (cptr
); /* get switches */
1260 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1261 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
1262 if (shptr
= find_shtab (show_glob_tab
, gbuf
)) /* global? */
1263 return shptr
->action (ofile
, NULL
, NULL
, shptr
->arg
, cptr
);
1265 if (dptr
= find_dev (gbuf
)) { /* device match? */
1266 uptr
= dptr
->units
; /* first unit */
1267 shtb
= show_dev_tab
; /* global table */
1268 lvl
= MTAB_VDV
; /* device match */
1270 else if (dptr
= find_unit (gbuf
, &uptr
)) { /* unit match? */
1271 if (uptr
== NULL
) return SCPE_NXUN
; /* invalid unit */
1272 if (uptr
->flags
& UNIT_DIS
) return SCPE_UDIS
; /* disabled? */
1273 shtb
= show_unit_tab
; /* global table */
1274 lvl
= MTAB_VUN
; /* unit match */
1276 else return SCPE_NXDEV
; /* no match */
1278 if (*cptr
== 0) { /* now eol? */
1279 return (lvl
== MTAB_VDV
)?
1280 show_device (ofile
, dptr
, 0):
1281 show_unit (ofile
, dptr
, uptr
, -1);
1283 if (dptr
->modifiers
== NULL
) return SCPE_NOPARAM
; /* any modifiers? */
1285 while (*cptr
!= 0) { /* do all mods */
1286 cptr
= get_glyph (cptr
, gbuf
, ','); /* get modifier */
1287 if (cvptr
= strchr (gbuf
, '=')) *cvptr
++ = 0; /* = value? */
1288 for (mptr
= dptr
->modifiers
; mptr
->mask
!= 0; mptr
++) {
1289 if (((mptr
->mask
& MTAB_XTD
)? /* right level? */
1290 (mptr
->mask
& lvl
): (MTAB_VUN
& lvl
)) &&
1291 ((mptr
->disp
&& mptr
->pstring
&& /* named disp? */
1292 (MATCH_CMD (gbuf
, mptr
->pstring
) == 0)) ||
1293 ((mptr
->mask
& MTAB_VAL
) && /* named value? */
1295 (MATCH_CMD (gbuf
, mptr
->mstring
) == 0)))) {
1296 if (cvptr
&& !(mptr
->mask
& MTAB_SHP
)) return SCPE_ARG
;
1297 show_one_mod (ofile
, dptr
, uptr
, mptr
, cvptr
, 1);
1301 if (mptr
->mask
== 0) { /* no match? */
1302 if (shptr
= find_shtab (shtb
, gbuf
)) /* global match? */
1303 shptr
->action (ofile
, dptr
, uptr
, shptr
->arg
, cptr
);
1304 else return SCPE_ARG
;
1310 SHTAB
*find_shtab (SHTAB
*tab
, char *gbuf
)
1312 for (; tab
->name
!= NULL
; tab
++) {
1313 if (MATCH_CMD (gbuf
, tab
->name
) == 0) return tab
;
1318 /* Show device and unit */
1320 t_stat
show_device (FILE *st
, DEVICE
*dptr
, int32 flag
)
1322 uint32 j
, udbl
, ucnt
;
1325 fprintf (st
, "%s", sim_dname (dptr
)); /* print dev name */
1326 if (qdisable (dptr
)) { /* disabled? */
1327 fprintf (st
, ", disabled\n");
1330 for (j
= ucnt
= udbl
= 0; j
< dptr
->numunits
; j
++) { /* count units */
1331 uptr
= dptr
->units
+ j
;
1332 if (uptr
->flags
& UNIT_DISABLE
) udbl
++;
1333 if (!(uptr
->flags
& UNIT_DIS
)) ucnt
++;
1335 show_all_mods (st
, dptr
, dptr
->units
, MTAB_VDV
); /* show dev mods */
1336 if (dptr
->numunits
== 0) fprintf (st
, "\n");
1338 if (udbl
&& (ucnt
== 0)) fprintf (st
, ", all units disabled\n");
1339 else if (ucnt
> 1) fprintf (st
, ", %d units\n", ucnt
);
1340 else if (flag
) fprintf (st
, "\n");
1342 if (flag
) return SCPE_OK
; /* dev only? */
1343 for (j
= 0; j
< dptr
->numunits
; j
++) { /* loop thru units */
1344 uptr
= dptr
->units
+ j
;
1345 if ((uptr
->flags
& UNIT_DIS
) == 0)
1346 show_unit (st
, dptr
, uptr
, ucnt
);
1351 t_stat
show_unit (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
)
1353 int32 u
= uptr
- dptr
->units
;
1355 if (flag
> 1) fprintf (st
, " %s%d", sim_dname (dptr
), u
);
1356 else if (flag
< 0) fprintf (st
, "%s%d", sim_dname (dptr
), u
);
1357 if (uptr
->flags
& UNIT_FIX
) {
1359 fprint_capac (st
, dptr
, uptr
);
1361 if (uptr
->flags
& UNIT_ATT
) {
1362 fprintf (st
, ", attached to %s", uptr
->filename
);
1363 if (uptr
->flags
& UNIT_RO
) fprintf (st
, ", read only");
1365 else if (uptr
->flags
& UNIT_ATTABLE
)
1366 fprintf (st
, ", not attached");
1367 show_all_mods (st
, dptr
, uptr
, MTAB_VUN
); /* show unit mods */
1372 void fprint_capac (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
)
1374 t_addr kval
= (uptr
->flags
& UNIT_BINK
)? 1024: 1000;
1375 t_addr mval
= kval
* kval
;
1376 t_addr psize
= uptr
->capac
;
1379 if ((dptr
->dwidth
/ dptr
->aincr
) > 8) width
= 'W';
1381 if (uptr
->capac
< (kval
* 10)) scale
= 0;
1382 else if (uptr
->capac
< (mval
* 10)) {
1384 psize
= psize
/ kval
;
1388 psize
= psize
/ mval
;
1390 fprint_val (st
, (t_value
) psize
, 10, T_ADDR_W
, PV_LEFT
);
1391 if (scale
) fputc (scale
, st
);
1396 /* Show <global name> processors */
1398 t_stat
show_version (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1400 int32 vmaj
= SIM_MAJOR
, vmin
= SIM_MINOR
, vpat
= SIM_PATCH
, vdelt
= SIM_DELTA
;
1402 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
1403 fprintf (st
, "%s simulator V%d.%d-%d", sim_name
, vmaj
, vmin
, vpat
);
1404 if (vdelt
) fprintf (st
, "(%d)", vdelt
);
1405 if (flag
) fprintf (st
, " [%s, %s, %s]", sim_si64
, sim_sa64
, sim_snet
);
1410 t_stat
show_config (FILE *st
, DEVICE
*dnotused
, UNIT
*unotused
, int32 flag
, char *cptr
)
1415 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
1416 fprintf (st
, "%s simulator configuration\n\n", sim_name
);
1417 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++)
1418 show_device (st
, dptr
, flag
);
1422 t_stat
show_log_names (FILE *st
, DEVICE
*dnotused
, UNIT
*unotused
, int32 flag
, char *cptr
)
1427 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
1428 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++)
1429 show_dev_logicals (st
, dptr
, NULL
, 1, cptr
);
1433 t_stat
show_dev_logicals (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1435 if (dptr
->lname
) fprintf (st
, "%s -> %s\n", dptr
->lname
, dptr
->name
);
1436 else if (!flag
) fputs ("no logical name assigned\n", st
);
1440 t_stat
show_queue (FILE *st
, DEVICE
*dnotused
, UNIT
*unotused
, int32 flag
, char *cptr
)
1446 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
1447 if (sim_clock_queue
== NULL
) {
1448 fprintf (st
, "%s event queue empty, time = %.0f\n",
1449 sim_name
, sim_time
);
1452 fprintf (st
, "%s event queue status, time = %.0f\n",
1453 sim_name
, sim_time
);
1455 for (uptr
= sim_clock_queue
; uptr
!= NULL
; uptr
= uptr
->next
) {
1456 if (uptr
== &sim_step_unit
) fprintf (st
, " Step timer");
1457 else if ((dptr
= find_dev_from_unit (uptr
)) != NULL
) {
1458 fprintf (st
, " %s", sim_dname (dptr
));
1459 if (dptr
->numunits
> 1) fprintf (st
, " unit %d",
1460 (int32
) (uptr
- dptr
->units
));
1462 else fprintf (st
, " Unknown");
1463 fprintf (st
, " at %d\n", accum
+ uptr
->time
);
1464 accum
= accum
+ uptr
->time
;
1469 t_stat
show_time (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1471 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
1472 fprintf (st
, "Time:\t%.0f\n", sim_time
);
1476 t_stat
show_break (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1480 if (cptr
&& (*cptr
!= 0)) r
= ssh_break (st
, cptr
, 1); /* more? */
1481 else r
= sim_brk_showall (st
, sim_switches
);
1485 t_stat
show_dev_radix (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1487 fprintf (st
, "Radix=%d\n", dptr
->dradix
);
1491 t_stat
show_dev_debug (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1496 if (dptr
->flags
& DEV_DEBUG
) {
1497 if (dptr
->dctrl
== 0) fputs ("Debugging disabled", st
);
1498 else if (dptr
->debflags
== NULL
) fputs ("Debugging enabled", st
);
1500 fputs ("Debug=", st
);
1501 for (dep
= dptr
->debflags
; dep
->name
!= NULL
; dep
++) {
1502 if (dptr
->dctrl
& dep
->mask
) {
1503 if (any
) fputc (';', st
);
1504 fputs (dep
->name
, st
);
1512 else return SCPE_NOFNC
;
1515 /* Show modifiers */
1517 t_stat
show_mod_names (FILE *st
, DEVICE
*dnotused
, UNIT
*unotused
, int32 flag
, char *cptr
)
1522 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
; /* now eol? */
1523 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++)
1524 show_dev_modifiers (st
, dptr
, NULL
, flag
, cptr
);
1528 t_stat
show_dev_modifiers (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
1535 if (dptr
->modifiers
) {
1536 for (mptr
= dptr
->modifiers
; mptr
->mask
!= 0; mptr
++) {
1537 if (mptr
->mstring
) {
1538 if (strcmp (mptr
->mstring
, "ENABLED") == 0) enb
= 1;
1539 if (any
++) fprintf (st
, ", %s", mptr
->mstring
);
1540 else fprintf (st
, "%s\t%s", sim_dname (dptr
), mptr
->mstring
);
1544 if (dptr
->flags
& DEV_DEBUG
) {
1545 if (any
++) fprintf (st
, ", DEBUG, NODEBUG");
1546 else fprintf (st
, "%s\tDEBUG, NODEBUG", sim_dname (dptr
));
1548 if (!enb
&& (dptr
->flags
& DEV_DISABLE
)) {
1549 if (any
++) fprintf (st
, ", ENABLED, DISABLED");
1550 else fprintf (st
, "%s\tENABLED, DISABLED", sim_dname (dptr
));
1552 if (any
) fprintf (st
, "\n");
1553 if ((dptr
->flags
& DEV_DEBUG
) && dptr
->debflags
) {
1554 fprintf (st
, "%s\tDEBUG=", sim_dname (dptr
));
1555 for (dep
= dptr
->debflags
; dep
->name
!= NULL
; dep
++)
1556 fprintf (st
, "%s%s", ((dep
== dptr
->debflags
) ? "" : ","), dep
->name
);
1562 t_stat
show_all_mods (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
)
1566 if (dptr
->modifiers
== NULL
) return SCPE_OK
;
1567 for (mptr
= dptr
->modifiers
; mptr
->mask
!= 0; mptr
++) {
1568 if (mptr
->pstring
&& ((mptr
->mask
& MTAB_XTD
)?
1569 ((mptr
->mask
& flag
) && !(mptr
->mask
& MTAB_NMO
)):
1570 ((MTAB_VUN
& flag
) && ((uptr
->flags
& mptr
->mask
) == mptr
->match
)))) {
1572 show_one_mod (st
, dptr
, uptr
, mptr
, NULL
, 0);
1578 t_stat
show_one_mod (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, MTAB
*mptr
,
1579 char *cptr
, int32 flag
)
1583 if (mptr
->disp
) mptr
->disp (st
, uptr
, mptr
->match
, cptr
? cptr
: mptr
->desc
);
1584 else if ((mptr
->mask
& MTAB_XTD
) && (mptr
->mask
& MTAB_VAL
)) {
1585 REG
*rptr
= (REG
*) mptr
->desc
;
1586 fprintf (st
, "%s=", mptr
->pstring
);
1587 val
= get_rval (rptr
, 0);
1588 fprint_val (st
, val
, rptr
->radix
, rptr
->width
,
1589 rptr
->flags
& REG_FMT
);
1591 else fputs (mptr
->pstring
, st
);
1592 if (flag
&& !((mptr
->mask
& MTAB_XTD
) &&
1593 (mptr
->mask
& MTAB_NMO
))) fputc ('\n', st
);
1597 /* Breakpoint commands */
1599 t_stat
brk_cmd (int32 flg
, char *cptr
)
1601 GET_SWITCHES (cptr
); /* get switches */
1602 return ssh_break (NULL
, cptr
, flg
); /* call common code */
1605 t_stat
ssh_break (FILE *st
, char *cptr
, int32 flg
)
1607 char gbuf
[CBUFSIZE
], *tptr
, *t1ptr
, *aptr
;
1608 DEVICE
*dptr
= sim_dflt_dev
;
1609 UNIT
*uptr
= dptr
->units
;
1611 t_addr lo
, hi
, max
= uptr
->capac
- 1;
1614 if (sim_brk_types
== 0) return SCPE_NOFNC
;
1615 if ((dptr
== NULL
) || (uptr
== NULL
)) return SCPE_IERR
;
1616 if (aptr
= strchr (cptr
, ';')) { /* ;action? */
1617 if (flg
!= SSH_ST
) return SCPE_ARG
; /* only on SET */
1618 *aptr
++ = 0; /* separate strings */
1620 if (*cptr
== 0) { /* no argument? */
1621 lo
= (t_addr
) get_rval (sim_PC
, 0); /* use PC */
1622 return ssh_break_one (st
, flg
, lo
, 0, aptr
);
1625 cptr
= get_glyph (cptr
, gbuf
, ',');
1626 tptr
= get_range (dptr
, gbuf
, &lo
, &hi
, dptr
->aradix
, max
, 0);
1627 if (tptr
== NULL
) return SCPE_ARG
;
1629 cnt
= (int32
) strtotv (tptr
+ 1, &t1ptr
, 10);
1630 if ((tptr
== t1ptr
) || (*t1ptr
!= ']') ||
1631 (flg
!= SSH_ST
)) return SCPE_ARG
;
1635 if (*tptr
!= 0) return SCPE_ARG
;
1636 if ((lo
== 0) && (hi
== max
)) {
1637 if (flg
== SSH_CL
) sim_brk_clrall (sim_switches
);
1638 else if (flg
== SSH_SH
) sim_brk_showall (st
, sim_switches
);
1639 else return SCPE_ARG
;
1642 for ( ; lo
<= hi
; lo
= lo
+ 1) {
1643 r
= ssh_break_one (st
, flg
, lo
, cnt
, aptr
);
1644 if (r
!= SCPE_OK
) return r
;
1651 t_stat
ssh_break_one (FILE *st
, int32 flg
, t_addr lo
, int32 cnt
, char *aptr
)
1656 return sim_brk_set (lo
, sim_switches
, cnt
, aptr
);
1660 return sim_brk_clr (lo
, sim_switches
);
1664 return sim_brk_show (st
, lo
, sim_switches
);
1672 /* Reset command and routines
1674 re[set] reset all devices
1675 re[set] all reset all devices
1676 re[set] device reset specific device
1679 t_stat
reset_cmd (int32 flag
, char *cptr
)
1681 char gbuf
[CBUFSIZE
];
1684 GET_SWITCHES (cptr
); /* get switches */
1685 if (*cptr
== 0) return (reset_all (0)); /* reset(cr) */
1686 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
1687 if (*cptr
!= 0) return SCPE_2MARG
; /* now eol? */
1688 if (strcmp (gbuf
, "ALL") == 0) return (reset_all (0));
1689 dptr
= find_dev (gbuf
); /* locate device */
1690 if (dptr
== NULL
) return SCPE_NXDEV
; /* found it? */
1691 if (dptr
->reset
!= NULL
) return dptr
->reset (dptr
);
1692 else return SCPE_OK
;
1695 /* Reset devices start..end
1698 start = number of starting device
1700 status = error status
1703 t_stat
reset_all (uint32 start
)
1709 for (i
= 0; i
< start
; i
++) {
1710 if (sim_devices
[i
] == NULL
) return SCPE_IERR
;
1712 for (i
= start
; (dptr
= sim_devices
[i
]) != NULL
; i
++) {
1713 if (dptr
->reset
!= NULL
) {
1714 reason
= dptr
->reset (dptr
);
1715 if (reason
!= SCPE_OK
) return reason
;
1721 /* Reset to powerup state
1724 start = number of starting device
1726 status = error status
1729 t_stat
reset_all_p (uint32 start
)
1732 int32 old_sw
= sim_switches
;
1734 sim_switches
= SWMASK ('P');
1735 r
= reset_all (start
);
1736 sim_switches
= old_sw
;
1740 /* Load and dump commands
1742 lo[ad] filename {arg} load specified file
1743 du[mp] filename {arg} dump to specified file
1746 t_stat
load_cmd (int32 flag
, char *cptr
)
1748 char gbuf
[CBUFSIZE
];
1752 GET_SWITCHES (cptr
); /* get switches */
1753 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1754 cptr
= get_glyph_nc (cptr
, gbuf
, 0); /* get file name */
1755 loadfile
= sim_fopen (gbuf
, flag
? "wb": "rb"); /* open for wr/rd */
1756 if (loadfile
== NULL
) return SCPE_OPENERR
;
1757 GET_SWITCHES (cptr
); /* get switches */
1758 reason
= sim_load (loadfile
, cptr
, gbuf
, flag
); /* load or dump */
1765 at[tach] unit file attach specified unit to file
1768 t_stat
attach_cmd (int32 flag
, char *cptr
)
1770 char gbuf
[CBUFSIZE
];
1775 GET_SWITCHES (cptr
); /* get switches */
1776 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1777 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
1778 GET_SWITCHES (cptr
); /* get switches */
1779 if (*cptr
== 0) return SCPE_2FARG
; /* now eol? */
1780 dptr
= find_unit (gbuf
, &uptr
); /* locate unit */
1781 if (dptr
== NULL
) return SCPE_NXDEV
; /* found dev? */
1782 if (uptr
== NULL
) return SCPE_NXUN
; /* valid unit? */
1783 if (uptr
->flags
& UNIT_ATT
) { /* already attached? */
1784 r
= scp_detach_unit (dptr
, uptr
); /* detach it */
1785 if (r
!= SCPE_OK
) return r
; /* error? */
1787 sim_trim_endspc (cptr
); /* trim trailing spc */
1788 return scp_attach_unit (dptr
, uptr
, cptr
); /* attach */
1791 /* Call device-specific or file-oriented attach unit routine */
1793 t_stat
scp_attach_unit (DEVICE
*dptr
, UNIT
*uptr
, char *cptr
)
1795 if (dptr
->attach
!= NULL
) /* device routine? */
1796 return dptr
->attach (uptr
, cptr
); /* call it */
1797 return attach_unit (uptr
, cptr
); /* no, std routine */
1800 /* Attach unit to file */
1802 t_stat
attach_unit (UNIT
*uptr
, char *cptr
)
1806 if (uptr
->flags
& UNIT_DIS
) return SCPE_UDIS
; /* disabled? */
1807 if (!(uptr
->flags
& UNIT_ATTABLE
)) return SCPE_NOATT
; /* not attachable? */
1808 if ((dptr
= find_dev_from_unit (uptr
)) == NULL
) return SCPE_NOATT
;
1809 if (dptr
->flags
& DEV_RAWONLY
) return SCPE_NOFNC
; /* raw mode only? */
1810 uptr
->filename
= (char *) calloc (CBUFSIZE
, sizeof (char)); /* alloc name buf */
1811 if (uptr
->filename
== NULL
) return SCPE_MEM
;
1812 strncpy (uptr
->filename
, cptr
, CBUFSIZE
); /* save name */
1813 if (sim_switches
& SWMASK ('R')) { /* read only? */
1814 if ((uptr
->flags
& UNIT_ROABLE
) == 0) /* allowed? */
1815 return attach_err (uptr
, SCPE_NORO
); /* no, error */
1816 uptr
->fileref
= sim_fopen (cptr
, "rb"); /* open rd only */
1817 if (uptr
->fileref
== NULL
) /* open fail? */
1818 return attach_err (uptr
, SCPE_OPENERR
); /* yes, error */
1819 uptr
->flags
= uptr
->flags
| UNIT_RO
; /* set rd only */
1820 if (!sim_quiet
) printf ("%s: unit is read only\n", sim_dname (dptr
));
1823 uptr
->fileref
= sim_fopen (cptr
, "rb+"); /* open r/w */
1824 if (uptr
->fileref
== NULL
) { /* open fail? */
1825 if ((errno
== EROFS
) || (errno
== EACCES
)) { /* read only? */
1826 if ((uptr
->flags
& UNIT_ROABLE
) == 0) /* allowed? */
1827 return attach_err (uptr
, SCPE_NORO
); /* no error */
1828 uptr
->fileref
= sim_fopen (cptr
, "rb"); /* open rd only */
1829 if (uptr
->fileref
== NULL
) /* open fail? */
1830 return attach_err (uptr
, SCPE_OPENERR
); /* yes, error */
1831 uptr
->flags
= uptr
->flags
| UNIT_RO
; /* set rd only */
1832 if (!sim_quiet
) printf ("%s: unit is read only\n", sim_dname (dptr
));
1834 else { /* doesn't exist */
1835 if (sim_switches
& SWMASK ('E')) /* must exist? */
1836 return attach_err (uptr
, SCPE_OPENERR
); /* yes, error */
1837 uptr
->fileref
= sim_fopen (cptr
, "wb+"); /* open new file */
1838 if (uptr
->fileref
== NULL
) /* open fail? */
1839 return attach_err (uptr
, SCPE_OPENERR
); /* yes, error */
1840 if (!sim_quiet
) printf ("%s: creating new file\n", sim_dname (dptr
));
1844 if (uptr
->flags
& UNIT_BUFABLE
) { /* buffer? */
1845 uint32 cap
= ((uint32
) uptr
->capac
) / dptr
->aincr
; /* effective size */
1846 if (uptr
->flags
& UNIT_MUSTBUF
) /* dyn alloc? */
1847 uptr
->filebuf
= calloc (cap
, SZ_D (dptr
)); /* allocate */
1848 if (uptr
->filebuf
== NULL
) /* no buffer? */
1849 return attach_err (uptr
, SCPE_MEM
); /* error */
1850 if (!sim_quiet
) printf ("%s: buffering file in memory\n", sim_dname (dptr
));
1851 uptr
->hwmark
= sim_fread (uptr
->filebuf
, /* read file */
1852 SZ_D (dptr
), cap
, uptr
->fileref
);
1853 uptr
->flags
= uptr
->flags
| UNIT_BUF
; /* set buffered */
1855 uptr
->flags
= uptr
->flags
| UNIT_ATT
;
1860 t_stat
attach_err (UNIT
*uptr
, t_stat stat
)
1862 free (uptr
->filename
);
1863 uptr
->filename
= NULL
;
1869 det[ach] all detach all units
1870 det[ach] unit detach specified unit
1873 t_stat
detach_cmd (int32 flag
, char *cptr
)
1875 char gbuf
[CBUFSIZE
];
1879 GET_SWITCHES (cptr
); /* get switches */
1880 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1881 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
1882 if (*cptr
!= 0) return SCPE_2MARG
; /* now eol? */
1883 if (strcmp (gbuf
, "ALL") == 0) return (detach_all (0, FALSE
));
1884 dptr
= find_unit (gbuf
, &uptr
); /* locate unit */
1885 if (dptr
== NULL
) return SCPE_NXDEV
; /* found dev? */
1886 if (uptr
== NULL
) return SCPE_NXUN
; /* valid unit? */
1887 return scp_detach_unit (dptr
, uptr
); /* detach */
1890 /* Detach devices start..end
1893 start = number of starting device
1894 shutdown = TRUE if simulator shutting down
1896 status = error status
1898 Note that during shutdown, detach routines for non-attachable devices
1899 will be called. These routines can implement simulator shutdown.
1902 t_stat
detach_all (int32 start
, t_bool shutdown
)
1909 if ((start
< 0) || (start
> 1)) return SCPE_IERR
;
1910 for (i
= start
; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* loop thru dev */
1911 for (j
= 0; j
< dptr
->numunits
; j
++) { /* loop thru units */
1912 uptr
= (dptr
->units
) + j
;
1913 if ((uptr
->flags
& UNIT_ATT
) || /* attached? */
1914 (shutdown
&& dptr
->detach
&& /* shutdown, spec rtn, */
1915 !(uptr
->flags
& UNIT_ATTABLE
))) { /* !attachable? */
1916 r
= scp_detach_unit (dptr
, uptr
); /* detach unit */
1917 if (r
!= SCPE_OK
) return r
;
1924 /* Call device-specific or file-oriented detach unit routine */
1926 t_stat
scp_detach_unit (DEVICE
*dptr
, UNIT
*uptr
)
1928 if (dptr
->detach
!= NULL
) return dptr
->detach (uptr
); /* device routine? */
1929 return detach_unit (uptr
); /* no, standard */
1932 /* Detach unit from file */
1934 t_stat
detach_unit (UNIT
*uptr
)
1938 if (uptr
== NULL
) return SCPE_IERR
;
1939 if (!(uptr
->flags
& UNIT_ATTABLE
)) return SCPE_NOATT
; /* attachable? */
1940 if (!(uptr
->flags
& UNIT_ATT
)) return SCPE_OK
; /* attached? */
1941 if ((dptr
= find_dev_from_unit (uptr
)) == NULL
) return SCPE_OK
;
1942 if (uptr
->flags
& UNIT_BUF
) {
1943 uint32 cap
= (uptr
->hwmark
+ dptr
->aincr
- 1) / dptr
->aincr
;
1944 if (uptr
->hwmark
&& ((uptr
->flags
& UNIT_RO
) == 0)) {
1945 if (!sim_quiet
) printf ("%s: writing buffer to file\n", sim_dname (dptr
));
1946 rewind (uptr
->fileref
);
1947 sim_fwrite (uptr
->filebuf
, SZ_D (dptr
), cap
, uptr
->fileref
);
1948 if (ferror (uptr
->fileref
)) perror ("I/O error");
1950 if (uptr
->flags
& UNIT_MUSTBUF
) { /* dyn alloc? */
1951 free (uptr
->filebuf
); /* free buf */
1952 uptr
->filebuf
= NULL
;
1954 uptr
->flags
= uptr
->flags
& ~UNIT_BUF
;
1956 uptr
->flags
= uptr
->flags
& ~(UNIT_ATT
| UNIT_RO
);
1957 free (uptr
->filename
);
1958 uptr
->filename
= NULL
;
1959 if (fclose (uptr
->fileref
) == EOF
) return SCPE_IOERR
;
1965 as[sign] device name assign logical name to device
1968 t_stat
assign_cmd (int32 flag
, char *cptr
)
1970 char gbuf
[CBUFSIZE
];
1973 GET_SWITCHES (cptr
); /* get switches */
1974 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
1975 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
1976 GET_SWITCHES (cptr
); /* get switches */
1977 if (*cptr
== 0) return SCPE_2FARG
; /* now eol? */
1978 dptr
= find_dev (gbuf
); /* locate device */
1979 if (dptr
== NULL
) return SCPE_NXDEV
; /* found dev? */
1980 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
1981 if (*cptr
!= 0) return SCPE_2MARG
; /* must be eol */
1982 if (find_dev (gbuf
)) return SCPE_ARG
; /* name in use */
1983 deassign_device (dptr
); /* release current */
1984 return assign_device (dptr
, gbuf
);
1987 t_stat
assign_device (DEVICE
*dptr
, char *cptr
)
1989 dptr
->lname
= (char *) calloc (CBUFSIZE
, sizeof (char));
1990 if (dptr
->lname
== NULL
) return SCPE_MEM
;
1991 strncpy (dptr
->lname
, cptr
, CBUFSIZE
);
1997 dea[ssign] device deassign logical name
2000 t_stat
deassign_cmd (int32 flag
, char *cptr
)
2002 char gbuf
[CBUFSIZE
];
2005 GET_SWITCHES (cptr
); /* get switches */
2006 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
2007 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
2008 if (*cptr
!= 0) return SCPE_2MARG
; /* now eol? */
2009 dptr
= find_dev (gbuf
); /* locate device */
2010 if (dptr
== NULL
) return SCPE_NXDEV
; /* found dev? */
2011 return deassign_device (dptr
);
2014 t_stat
deassign_device (DEVICE
*dptr
)
2016 if (dptr
->lname
) free (dptr
->lname
);
2021 /* Get device display name */
2023 char *sim_dname (DEVICE
*dptr
)
2025 return (dptr
->lname
? dptr
->lname
: dptr
->name
);
2030 sa[ve] filename save state to specified file
2033 t_stat
save_cmd (int32 flag
, char *cptr
)
2037 GET_SWITCHES (cptr
); /* get switches */
2038 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
2039 sim_trim_endspc (cptr
);
2040 if ((sfile
= sim_fopen (cptr
, "wb")) == NULL
) return SCPE_OPENERR
;
2041 r
= sim_save (sfile
);
2046 t_stat
sim_save (FILE *sfile
)
2060 #define WRITE_I(xx) sim_fwrite (&(xx), sizeof (xx), 1, sfile)
2062 fprintf (sfile
, "%s\n%s\n%s\n%s\n%s\n%.0f\n",
2063 save_vercur
, /* [V2.5] save format */
2064 sim_name
, /* sim name */
2065 sim_si64
, sim_sa64
, sim_snet
, /* [V3.5] options */
2066 sim_time
); /* [V3.2] sim time */
2067 WRITE_I (sim_rtime
); /* [V2.6] sim rel time */
2069 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* loop thru devices */
2070 fputs (dptr
->name
, sfile
); /* device name */
2071 fputc ('\n', sfile
);
2072 if (dptr
->lname
) fputs (dptr
->lname
, sfile
); /* [V3.0] logical name */
2073 fputc ('\n', sfile
);
2074 WRITE_I (dptr
->flags
); /* [V2.10] flags */
2075 for (j
= 0; j
< dptr
->numunits
; j
++) {
2076 uptr
= dptr
->units
+ j
;
2077 t
= sim_is_active (uptr
);
2078 WRITE_I (j
); /* unit number */
2079 WRITE_I (t
); /* activation time */
2080 WRITE_I (uptr
->u3
); /* unit specific */
2082 WRITE_I (uptr
->u5
); /* [V3.0] more unit */
2084 WRITE_I (uptr
->flags
); /* [V2.10] flags */
2085 WRITE_I (uptr
->capac
); /* [V3.5] capacity */
2086 if (uptr
->flags
& UNIT_ATT
) fputs (uptr
->filename
, sfile
);
2087 fputc ('\n', sfile
);
2088 if (((uptr
->flags
& (UNIT_FIX
+ UNIT_ATTABLE
)) == UNIT_FIX
) &&
2089 (dptr
->examine
!= NULL
) &&
2090 ((high
= uptr
->capac
) != 0)) { /* memory-like unit? */
2091 WRITE_I (high
); /* [V2.5] write size */
2093 if ((mbuf
= calloc (SRBSIZ
, sz
)) == NULL
) {
2097 for (k
= 0; k
< high
; ) { /* loop thru mem */
2099 for (l
= 0; (l
< SRBSIZ
) && (k
< high
); l
++,
2100 k
= k
+ (dptr
->aincr
)) { /* check for 0 block */
2101 r
= dptr
->examine (&val
, k
, uptr
, SIM_SW_REST
);
2102 if (r
!= SCPE_OK
) return r
;
2103 if (val
) zeroflg
= FALSE
;
2104 SZ_STORE (sz
, val
, mbuf
, l
);
2106 if (zeroflg
) { /* all zero's? */
2107 l
= -l
; /* invert block count */
2108 WRITE_I (l
); /* write only count */
2111 WRITE_I (l
); /* block count */
2112 sim_fwrite (mbuf
, sz
, l
, sfile
);
2115 free (mbuf
); /* dealloc buffer */
2117 else { /* no memory */
2118 high
= 0; /* write 0 */
2120 } /* end else mem */
2121 } /* end unit loop */
2122 t
= -1; /* end units */
2123 WRITE_I (t
); /* write marker */
2124 for (rptr
= dptr
->registers
; (rptr
!= NULL
) && /* loop thru regs */
2125 (rptr
->name
!= NULL
); rptr
++) {
2126 fputs (rptr
->name
, sfile
); /* name */
2127 fputc ('\n', sfile
);
2128 WRITE_I (rptr
->depth
); /* [V2.10] depth */
2129 for (j
= 0; j
< rptr
->depth
; j
++) { /* loop thru values */
2130 val
= get_rval (rptr
, j
); /* get value */
2131 WRITE_I (val
); /* store */
2134 fputc ('\n', sfile
); /* end registers */
2136 fputc ('\n', sfile
); /* end devices */
2137 return (ferror (sfile
))? SCPE_IOERR
: SCPE_OK
; /* error during save? */
2142 re[store] filename restore state from specified file
2145 t_stat
restore_cmd (int32 flag
, char *cptr
)
2150 GET_SWITCHES (cptr
); /* get switches */
2151 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
2152 sim_trim_endspc (cptr
);
2153 if ((rfile
= sim_fopen (cptr
, "rb")) == NULL
) return SCPE_OPENERR
;
2154 r
= sim_rest (rfile
);
2159 t_stat
sim_rest (FILE *rfile
)
2163 int32 j
, blkcnt
, limit
, unitno
, time
, flg
;
2165 t_addr k
, high
, old_capac
;
2174 #define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \
2176 #define READ_I(xx) if (sim_fread (&xx, sizeof (xx), 1, rfile) == 0) \
2179 READ_S (buf
); /* [V2.5+] read version */
2181 if (strcmp (buf
, save_vercur
) == 0) v35
= v32
= TRUE
; /* version 3.5? */
2182 else if (strcmp (buf
, save_ver32
) == 0) v32
= TRUE
; /* version 3.2? */
2183 else if (strcmp (buf
, save_ver30
) != 0) { /* version 3.0? */
2184 printf ("Invalid file version: %s\n", buf
);
2187 READ_S (buf
); /* read sim name */
2188 if (strcmp (buf
, sim_name
)) { /* name match? */
2189 printf ("Wrong system type: %s\n", buf
);
2192 if (v35
) { /* [V3.5+] options */
2193 READ_S (buf
); /* integer size */
2194 if (strcmp (buf
, sim_si64
) != 0) {
2195 printf ("Incompatible integer size, save file = %s\n", buf
);
2198 READ_S (buf
); /* address size */
2199 if (strcmp (buf
, sim_sa64
) != 0) {
2200 printf ("Incompatible address size, save file = %s\n", buf
);
2203 READ_S (buf
); /* Ethernet */
2205 if (v32
) { /* [V3.2+] time as string */
2207 sscanf (buf
, "%lf", &sim_time
);
2209 else READ_I (sim_time
); /* sim time */
2210 READ_I (sim_rtime
); /* [V2.6+] sim rel time */
2212 for ( ;; ) { /* device loop */
2213 READ_S (buf
); /* read device name */
2214 if (buf
[0] == 0) break; /* last? */
2215 if ((dptr
= find_dev (buf
)) == NULL
) { /* locate device */
2216 printf ("Invalid device name: %s\n", buf
);
2219 READ_S (buf
); /* [V3.0+] logical name */
2220 deassign_device (dptr
); /* delete old name */
2221 if ((buf
[0] != 0) &&
2222 ((r
= assign_device (dptr
, buf
)) != SCPE_OK
)) return r
;
2223 READ_I (flg
); /* [V2.10+] ctlr flags */
2224 if (!v32
) flg
= ((flg
& DEV_UFMASK_31
) << (DEV_V_UF
- DEV_V_UF_31
)) |
2225 (flg
& ~DEV_UFMASK_31
); /* [V3.2+] flags moved */
2226 dptr
->flags
= (dptr
->flags
& ~DEV_RFLAGS
) | /* restore ctlr flags */
2228 for ( ;; ) { /* unit loop */
2229 sim_switches
= SIM_SW_REST
; /* flag rstr, clr RO */
2230 READ_I (unitno
); /* unit number */
2231 if (unitno
< 0) break; /* end units? */
2232 if ((uint32
) unitno
>= dptr
->numunits
) { /* too big? */
2233 printf ("Invalid unit number: %s%d\n", sim_dname (dptr
), unitno
);
2236 READ_I (time
); /* event time */
2237 uptr
= (dptr
->units
) + unitno
;
2239 if (time
> 0) sim_activate (uptr
, time
- 1);
2240 READ_I (uptr
->u3
); /* device specific */
2242 READ_I (uptr
->u5
); /* [V3.0+] more dev spec */
2244 READ_I (flg
); /* [V2.10+] unit flags */
2245 old_capac
= uptr
->capac
; /* save current capacity */
2246 if (v35
) { /* [V3.5+] capacity */
2247 READ_I (uptr
->capac
);
2249 if (!v32
) flg
= ((flg
& UNIT_UFMASK_31
) << (UNIT_V_UF
- UNIT_V_UF_31
)) |
2250 (flg
& ~UNIT_UFMASK_31
); /* [V3.2+] flags moved */
2251 uptr
->flags
= (uptr
->flags
& ~UNIT_RFLAGS
) |
2252 (flg
& UNIT_RFLAGS
); /* restore */
2253 READ_S (buf
); /* attached file */
2254 if ((uptr
->flags
& UNIT_ATTABLE
) && /* if attachable and */
2255 (!(dptr
->flags
& DEV_NET
) || /* not net dev or */
2256 !(uptr
->flags
& UNIT_ATT
) || /* not currently att */
2257 (buf
[0] == 0))) { /* or will not be att */
2258 r
= scp_detach_unit (dptr
, uptr
); /* detach old */
2259 if (r
!= SCPE_OK
) return r
;
2260 if (buf
[0] != 0) { /* any file? */
2261 uptr
->flags
= uptr
->flags
& ~UNIT_DIS
;
2262 if (flg
& UNIT_RO
) /* [V2.10+] saved flgs & RO? */
2263 sim_switches
|= SWMASK ('R'); /* RO attach */
2264 r
= scp_attach_unit (dptr
, uptr
, buf
);
2265 if (r
!= SCPE_OK
) return r
;
2268 READ_I (high
); /* memory capacity */
2269 if (high
> 0) { /* [V2.5+] any memory? */
2270 if (((uptr
->flags
& (UNIT_FIX
+ UNIT_ATTABLE
)) != UNIT_FIX
) ||
2271 (dptr
->deposit
== NULL
)) {
2272 printf ("Can't restore memory: %s%d\n", sim_dname (dptr
), unitno
);
2275 if (high
!= old_capac
) { /* size change? */
2276 uptr
->capac
= old_capac
; /* temp restore old */
2277 if ((dptr
->flags
& DEV_DYNM
) &&
2278 ((dptr
->msize
== NULL
) ||
2279 (dptr
->msize (uptr
, (int32
) high
, NULL
, NULL
) != SCPE_OK
))) {
2280 printf ("Can't change memory size: %s%d\n",
2281 sim_dname (dptr
), unitno
);
2284 uptr
->capac
= high
; /* new memory size */
2285 printf ("Memory size changed: %s%d = ", sim_dname (dptr
), unitno
);
2286 fprint_capac (stdout
, dptr
, uptr
);
2289 sz
= SZ_D (dptr
); /* allocate buffer */
2290 if ((mbuf
= calloc (SRBSIZ
, sz
)) == NULL
)
2292 for (k
= 0; k
< high
; ) { /* loop thru mem */
2293 READ_I (blkcnt
); /* block count */
2294 if (blkcnt
< 0) limit
= -blkcnt
; /* compressed? */
2295 else limit
= sim_fread (mbuf
, sz
, blkcnt
, rfile
);
2296 if (limit
<= 0) return SCPE_IOERR
; /* invalid or err? */
2297 for (j
= 0; j
< limit
; j
++, k
= k
+ (dptr
->aincr
)) {
2298 if (blkcnt
< 0) val
= 0; /* compressed? */
2299 else SZ_LOAD (sz
, val
, mbuf
, j
); /* saved value */
2300 r
= dptr
->deposit (val
, k
, uptr
, SIM_SW_REST
);
2301 if (r
!= SCPE_OK
) return r
;
2304 free (mbuf
); /* dealloc buffer */
2306 } /* end unit loop */
2307 for ( ;; ) { /* register loop */
2308 READ_S (buf
); /* read reg name */
2309 if (buf
[0] == 0) break; /* last? */
2310 READ_I (depth
); /* [V2.10+] depth */
2311 if ((rptr
= find_reg (buf
, NULL
, dptr
)) == NULL
) {
2312 printf ("Invalid register name: %s %s\n", sim_dname (dptr
), buf
);
2313 for (us
= 0; us
< depth
; us
++) { /* skip values */
2318 if (depth
!= rptr
->depth
) /* [V2.10+] mismatch? */
2319 printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n",
2320 sim_dname (dptr
), buf
, depth
, rptr
->depth
);
2321 mask
= width_mask
[rptr
->width
]; /* get mask */
2322 for (us
= 0; us
< depth
; us
++) { /* loop thru values */
2323 READ_I (val
); /* read value */
2324 if (val
> mask
) /* value ok? */
2325 printf ("Invalid register value: %s %s\n", sim_dname (dptr
), buf
);
2326 else if (us
< rptr
->depth
) /* in range? */
2327 put_rval (rptr
, us
, val
);
2330 } /* end device loop */
2334 /* Run, go, cont, step commands
2336 ru[n] [new PC] reset and start simulation
2337 go [new PC] start simulation
2338 co[nt] start simulation
2339 s[tep] [step limit] start simulation for 'limit' instructions
2340 b[oot] device bootstrap from device and start simulation
2343 t_stat
run_cmd (int32 flag
, char *cptr
)
2345 char *tptr
, gbuf
[CBUFSIZE
];
2352 void int_handler (int signal
);
2354 GET_SWITCHES (cptr
); /* get switches */
2356 if ((flag
== RU_RUN
) || (flag
== RU_GO
)) { /* run or go */
2357 if (*cptr
!= 0) { /* argument? */
2358 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
2359 if (*cptr
!= 0) return SCPE_2MARG
; /* should be end */
2360 if (sim_vm_parse_addr
) /* address parser? */
2361 pcv
= sim_vm_parse_addr (sim_dflt_dev
, gbuf
, &tptr
);
2362 else pcv
= strtotv (gbuf
, &tptr
, sim_PC
->radix
);/* parse PC */
2363 if ((tptr
== gbuf
) || (*tptr
!= 0) || /* error? */
2364 (pcv
> width_mask
[sim_PC
->width
])) return SCPE_ARG
;
2365 put_rval (sim_PC
, 0, pcv
);
2367 if ((flag
== RU_RUN
) && /* run? */
2368 ((r
= run_boot_prep ()) != SCPE_OK
)) return r
; /* reset sim */
2371 else if (flag
== RU_STEP
) { /* step */
2372 if (*cptr
!= 0) { /* argument? */
2373 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
2374 if (*cptr
!= 0) return SCPE_2MARG
; /* should be end */
2375 sim_step
= (int32
) get_uint (gbuf
, 10, INT_MAX
, &r
);
2376 if ((r
!= SCPE_OK
) || (sim_step
<= 0)) /* error? */
2382 else if (flag
== RU_BOOT
) { /* boot */
2383 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
2384 cptr
= get_glyph (cptr
, gbuf
, 0); /* get next glyph */
2385 if (*cptr
!= 0) return SCPE_2MARG
; /* should be end */
2386 dptr
= find_unit (gbuf
, &uptr
); /* locate unit */
2387 if (dptr
== NULL
) return SCPE_NXDEV
; /* found dev? */
2388 if (uptr
== NULL
) return SCPE_NXUN
; /* valid unit? */
2389 if (dptr
->boot
== NULL
) return SCPE_NOFNC
; /* can it boot? */
2390 if (uptr
->flags
& UNIT_DIS
) return SCPE_UDIS
; /* disabled? */
2391 if ((uptr
->flags
& UNIT_ATTABLE
) && /* if attable, att? */
2392 !(uptr
->flags
& UNIT_ATT
)) return SCPE_UNATT
;
2393 unitno
= (int32
) (uptr
- dptr
->units
); /* recover unit# */
2394 if ((r
= run_boot_prep ()) != SCPE_OK
) return r
; /* reset sim */
2395 if ((r
= dptr
->boot (unitno
, dptr
)) != SCPE_OK
) /* boot device */
2399 else if (flag
!= RU_CONT
) return SCPE_IERR
; /* must be cont */
2401 for (i
= 1; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* reposition all */
2402 for (j
= 0; j
< dptr
->numunits
; j
++) { /* seq devices */
2403 uptr
= dptr
->units
+ j
;
2404 if ((uptr
->flags
& (UNIT_ATT
+ UNIT_SEQ
)) ==
2405 (UNIT_ATT
+ UNIT_SEQ
))
2406 sim_fseek (uptr
->fileref
, uptr
->pos
, SEEK_SET
);
2410 if (signal (SIGINT
, int_handler
) == SIG_ERR
) { /* set WRU */
2413 if (sim_ttrun () != SCPE_OK
) { /* set console mode */
2417 if ((r
= sim_check_console (30)) != SCPE_OK
) { /* check console, error? */
2421 if (sim_step
) sim_activate (&sim_step_unit
, sim_step
); /* set step timer */
2422 sim_throt_sched (); /* set throttle */
2423 sim_is_running
= 1; /* flag running */
2424 sim_brk_clract (); /* defang actions */
2425 sim_rtcn_init_all (); /* re-init clocks */
2428 sim_is_running
= 0; /* flag idle */
2429 sim_ttcmd (); /* restore console */
2430 signal (SIGINT
, SIG_DFL
); /* cancel WRU */
2431 sim_cancel (&sim_step_unit
); /* cancel step timer */
2432 sim_throt_cancel (); /* cancel throttle */
2433 if (sim_clock_queue
!= NULL
) { /* update sim time */
2434 UPDATE_SIM_TIME (sim_clock_queue
->time
);
2437 UPDATE_SIM_TIME (noqueue_time
);
2439 if (sim_log
) fflush (sim_log
); /* flush console log */
2440 if (sim_deb
) fflush (sim_deb
); /* flush debug log */
2441 for (i
= 1; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* flush attached files */
2442 for (j
= 0; j
< dptr
->numunits
; j
++) { /* if not buffered in mem */
2443 uptr
= dptr
->units
+ j
;
2444 if ((uptr
->flags
& UNIT_ATT
) && /* attached, */
2445 !(uptr
->flags
& UNIT_BUF
) && /* not buffered, */
2446 (uptr
->fileref
) && /* real file, */
2447 !(uptr
->flags
& UNIT_RAW
) && /* not raw, */
2448 !(uptr
->flags
& UNIT_RO
)) /* not read only? */
2449 fflush (uptr
->fileref
);
2455 fprint_stopped (stdout
, r
); /* print msg */
2456 if (sim_log
) fprint_stopped (sim_log
, r
); /* log if enabled */
2460 /* Common setup for RUN or BOOT */
2462 t_stat
run_boot_prep (void)
2464 sim_interval
= 0; /* reset queue */
2465 sim_time
= sim_rtime
= 0;
2467 sim_clock_queue
= NULL
;
2468 return reset_all_p (0);
2471 /* Print stopped message */
2473 void fprint_stopped_gen (FILE *st
, t_stat v
, REG
*pc
, DEVICE
*dptr
)
2480 if (v
>= SCPE_BASE
) fprintf (st
, "\n%s, %s: ",
2481 scp_error_messages
[v
- SCPE_BASE
], pc
->name
);
2482 else fprintf (st
, "\n%s, %s: ", sim_stop_messages
[v
], pc
->name
);
2483 pcval
= get_rval (pc
, 0);
2484 if (sim_vm_fprint_addr
) sim_vm_fprint_addr (st
, dptr
, (t_addr
) pcval
);
2485 else fprint_val (st
, pcval
, pc
->radix
, pc
->width
,
2486 pc
->flags
& REG_FMT
);
2487 if ((dptr
!= NULL
) && (dptr
->examine
!= NULL
)) {
2488 for (i
= 0; i
< sim_emax
; i
++) sim_eval
[i
] = 0;
2489 for (i
= 0, k
= (t_addr
) pcval
; i
< sim_emax
; i
++, k
= k
+ dptr
->aincr
) {
2490 if ((r
= dptr
->examine (&sim_eval
[i
], k
, dptr
->units
,
2491 SWMASK ('V'))) != SCPE_OK
) break;
2493 if ((r
== SCPE_OK
) || (i
> 0)) {
2495 if (fprint_sym (st
, (t_addr
) pcval
, sim_eval
, NULL
, SWMASK('M')|SIM_SW_STOP
) > 0)
2496 fprint_val (st
, sim_eval
[0], dptr
->dradix
, dptr
->dwidth
, PV_RZRO
);
2504 void fprint_stopped (FILE *st
, t_stat v
)
2506 fprint_stopped_gen (st
, v
, sim_PC
, sim_dflt_dev
);
2510 /* Unit service for step timeout, originally scheduled by STEP n command
2511 Return step timeout SCP code, will cause simulation to stop */
2513 t_stat
step_svc (UNIT
*uptr
)
2518 /* Cancel scheduled step service */
2520 t_stat
sim_cancel_step (void)
2522 return sim_cancel (&sim_step_unit
);
2525 /* Signal handler for ^C signal - set stop simulation flag */
2527 void int_handler (int sig
)
2533 /* Examine/deposit commands
2535 ex[amine] [modifiers] list examine
2536 de[posit] [modifiers] list val deposit
2537 ie[xamine] [modifiers] list interactive examine
2538 id[eposit] [modifiers] list interactive deposit
2541 @filename output file
2543 devname'n device name and unit number
2544 [{&|^}value]{=|==|!|!=|>|>=|<|<=} value search specification
2546 list list of addresses and registers
2547 addr[:addr|-addr] address range
2549 register[:register|-register] register range
2553 t_stat
exdep_cmd (int32 flag
, char *cptr
)
2555 char gbuf
[CBUFSIZE
], *gptr
, *tptr
;
2563 opt
= CMD_OPT_SW
|CMD_OPT_SCH
|CMD_OPT_DFT
; /* options for all */
2564 if (flag
== EX_E
) opt
= opt
| CMD_OPT_OF
; /* extra for EX */
2565 cptr
= get_sim_opt (opt
, cptr
, &reason
); /* get cmd options */
2566 if (!cptr
) return reason
; /* error? */
2567 if (*cptr
== 0) return SCPE_2FARG
; /* must be more */
2568 if (sim_dfunit
== NULL
) return SCPE_NXUN
; /* got a unit? */
2569 cptr
= get_glyph (cptr
, gbuf
, 0); /* get list */
2570 if ((flag
== EX_D
) && (*cptr
== 0)) return SCPE_2FARG
; /* deposit needs more */
2571 ofile
= sim_ofile
? sim_ofile
: stdout
; /* no ofile? use stdout */
2573 for (gptr
= gbuf
, reason
= SCPE_OK
;
2574 (*gptr
!= 0) && (reason
== SCPE_OK
); gptr
= tptr
) {
2575 tdptr
= sim_dfdev
; /* working dptr */
2576 if (strncmp (gptr
, "STATE", strlen ("STATE")) == 0) {
2577 tptr
= gptr
+ strlen ("STATE");
2578 if (*tptr
&& (*tptr
++ != ',')) return SCPE_ARG
;
2579 if ((lowr
= sim_dfdev
->registers
) == NULL
) return SCPE_NXREG
;
2580 for (highr
= lowr
; highr
->name
!= NULL
; highr
++) ;
2581 sim_switches
= sim_switches
| SIM_SW_HIDE
;
2582 reason
= exdep_reg_loop (ofile
, sim_schptr
, flag
, cptr
,
2583 lowr
, --highr
, 0, 0);
2587 if ((lowr
= find_reg (gptr
, &tptr
, tdptr
)) || /* local reg or */
2588 (!(sim_opt_out
& CMD_OPT_DFT
) && /* no dflt, global? */
2589 (lowr
= find_reg_glob (gptr
, &tptr
, &tdptr
)))) {
2591 if ((*tptr
== '-') || (*tptr
== ':')) {
2592 highr
= find_reg (tptr
+ 1, &tptr
, tdptr
);
2593 if (highr
== NULL
) return SCPE_NXREG
;
2598 if (lowr
->depth
<= 1) return SCPE_ARG
;
2599 tptr
= get_range (NULL
, tptr
+ 1, &low
, &high
,
2600 10, lowr
->depth
- 1, ']');
2601 if (tptr
== NULL
) return SCPE_ARG
;
2604 if (*tptr
&& (*tptr
++ != ',')) return SCPE_ARG
;
2605 reason
= exdep_reg_loop (ofile
, sim_schptr
, flag
, cptr
,
2606 lowr
, highr
, (uint32
) low
, (uint32
) high
);
2610 tptr
= get_range (sim_dfdev
, gptr
, &low
, &high
, sim_dfdev
->aradix
,
2611 (((sim_dfunit
->capac
== 0) || (flag
== EX_E
))? 0:
2612 sim_dfunit
->capac
- sim_dfdev
->aincr
), 0);
2613 if (tptr
== NULL
) return SCPE_ARG
;
2614 if (*tptr
&& (*tptr
++ != ',')) return SCPE_ARG
;
2615 reason
= exdep_addr_loop (ofile
, sim_schptr
, flag
, cptr
, low
, high
,
2616 sim_dfdev
, sim_dfunit
);
2618 if (sim_ofile
) fclose (sim_ofile
); /* close output file */
2622 /* Loop controllers for examine/deposit
2624 exdep_reg_loop examine/deposit range of registers
2625 exdep_addr_loop examine/deposit range of addresses
2628 t_stat
exdep_reg_loop (FILE *ofile
, SCHTAB
*schptr
, int32 flag
, char *cptr
,
2629 REG
*lowr
, REG
*highr
, uint32 lows
, uint32 highs
)
2636 if ((lowr
== NULL
) || (highr
== NULL
)) return SCPE_IERR
;
2637 if (lowr
> highr
) return SCPE_ARG
;
2638 for (rptr
= lowr
; rptr
<= highr
; rptr
++) {
2639 if ((sim_switches
& SIM_SW_HIDE
) &&
2640 (rptr
->flags
& REG_HIDDEN
)) continue;
2641 for (idx
= lows
; idx
<= highs
; idx
++) {
2642 if (idx
>= rptr
->depth
) return SCPE_SUB
;
2643 val
= get_rval (rptr
, idx
);
2644 if (schptr
&& !test_search (val
, schptr
)) continue;
2646 reason
= ex_reg (ofile
, val
, flag
, rptr
, idx
);
2647 if (reason
!= SCPE_OK
) return reason
;
2648 if (sim_log
&& (ofile
== stdout
))
2649 ex_reg (sim_log
, val
, flag
, rptr
, idx
);
2652 reason
= dep_reg (flag
, cptr
, rptr
, idx
);
2653 if (reason
!= SCPE_OK
) return reason
;
2660 t_stat
exdep_addr_loop (FILE *ofile
, SCHTAB
*schptr
, int32 flag
, char *cptr
,
2661 t_addr low
, t_addr high
, DEVICE
*dptr
, UNIT
*uptr
)
2666 if (uptr
->flags
& UNIT_DIS
) return SCPE_UDIS
; /* disabled? */
2667 mask
= (t_addr
) width_mask
[dptr
->awidth
];
2668 if ((low
> mask
) || (high
> mask
) || (low
> high
)) return SCPE_ARG
;
2669 for (i
= low
; i
<= high
; ) { /* all paths must incr!! */
2670 reason
= get_aval (i
, dptr
, uptr
); /* get data */
2671 if (reason
!= SCPE_OK
) return reason
; /* return if error */
2672 if (schptr
&& !test_search (sim_eval
[0], schptr
))
2673 i
= i
+ dptr
->aincr
; /* sch fails, incr */
2674 else { /* no sch or success */
2675 if (flag
!= EX_D
) { /* ex, ie, or id? */
2676 reason
= ex_addr (ofile
, flag
, i
, dptr
, uptr
);
2677 if (reason
> SCPE_OK
) return reason
;
2678 if (sim_log
&& (ofile
== stdout
))
2679 ex_addr (sim_log
, flag
, i
, dptr
, uptr
);
2681 else reason
= 1 - dptr
->aincr
; /* no, dflt incr */
2682 if (flag
!= EX_E
) { /* ie, id, or d? */
2683 reason
= dep_addr (flag
, cptr
, i
, dptr
, uptr
, reason
);
2684 if (reason
> SCPE_OK
) return reason
;
2686 i
= i
+ (1 - reason
); /* incr */
2692 /* Examine register routine
2695 ofile = output stream
2696 val = current register value
2697 flag = type of ex/mod command (ex, iex, idep)
2698 rptr = pointer to register descriptor
2701 return = error status
2704 t_stat
ex_reg (FILE *ofile
, t_value val
, int32 flag
, REG
*rptr
, uint32 idx
)
2708 if (rptr
== NULL
) return SCPE_IERR
;
2709 if (rptr
->depth
> 1) fprintf (ofile
, "%s[%d]:\t", rptr
->name
, idx
);
2710 else fprintf (ofile
, "%s:\t", rptr
->name
);
2711 if (!(flag
& EX_E
)) return SCPE_OK
;
2712 GET_RADIX (rdx
, rptr
->radix
);
2713 if ((rptr
->flags
& REG_VMAD
) && sim_vm_fprint_addr
)
2714 sim_vm_fprint_addr (ofile
, sim_dflt_dev
, (t_addr
) val
);
2715 else if (!(rptr
->flags
& REG_VMIO
) ||
2716 (fprint_sym (ofile
, rdx
, &val
, NULL
, sim_switches
| SIM_SW_REG
) > 0))
2717 fprint_val (ofile
, val
, rdx
, rptr
->width
, rptr
->flags
& REG_FMT
);
2718 if (flag
& EX_I
) fprintf (ofile
, "\t");
2719 else fprintf (ofile
, "\n");
2723 /* Get register value
2726 rptr = pointer to register descriptor
2729 return = register value
2732 t_value
get_rval (REG
*rptr
, uint32 idx
)
2739 if ((rptr
->depth
> 1) && (rptr
->flags
& REG_CIRC
)) {
2740 idx
= idx
+ rptr
->qptr
;
2741 if (idx
>= rptr
->depth
) idx
= idx
- rptr
->depth
;
2743 if ((rptr
->depth
> 1) && (rptr
->flags
& REG_UNIT
)) {
2744 uptr
= ((UNIT
*) rptr
->loc
) + idx
;
2745 #if defined (USE_INT64)
2746 if (sz
<= sizeof (uint32
)) val
= *((uint32
*) uptr
);
2747 else val
= *((t_uint64
*) uptr
);
2749 val
= *((uint32
*) uptr
);
2752 else if (((rptr
->depth
> 1) || (rptr
->flags
& REG_FIT
)) &&
2753 (sz
== sizeof (uint8
)))
2754 val
= *(((uint8
*) rptr
->loc
) + idx
);
2755 else if (((rptr
->depth
> 1) || (rptr
->flags
& REG_FIT
)) &&
2756 (sz
== sizeof (uint16
)))
2757 val
= *(((uint16
*) rptr
->loc
) + idx
);
2758 #if defined (USE_INT64)
2759 else if (sz
<= sizeof (uint32
))
2760 val
= *(((uint32
*) rptr
->loc
) + idx
);
2761 else val
= *(((t_uint64
*) rptr
->loc
) + idx
);
2763 else val
= *(((uint32
*) rptr
->loc
) + idx
);
2765 val
= (val
>> rptr
->offset
) & width_mask
[rptr
->width
];
2769 /* Deposit register routine
2772 flag = type of deposit (normal/interactive)
2773 cptr = pointer to input string
2774 rptr = pointer to register descriptor
2777 return = error status
2780 t_stat
dep_reg (int32 flag
, char *cptr
, REG
*rptr
, uint32 idx
)
2785 char *tptr
, gbuf
[CBUFSIZE
];
2787 if ((cptr
== NULL
) || (rptr
== NULL
)) return SCPE_IERR
;
2788 if (rptr
->flags
& REG_RO
) return SCPE_RO
;
2790 cptr
= read_line (gbuf
, CBUFSIZE
, stdin
);
2791 if (sim_log
) fprintf (sim_log
, (cptr
? "%s\n": "\n"), cptr
);
2792 if (cptr
== NULL
) return 1; /* force exit */
2793 if (*cptr
== 0) return SCPE_OK
; /* success */
2795 mask
= width_mask
[rptr
->width
];
2796 GET_RADIX (rdx
, rptr
->radix
);
2797 if ((rptr
->flags
& REG_VMAD
) && sim_vm_parse_addr
) { /* address form? */
2798 val
= sim_vm_parse_addr (sim_dflt_dev
, cptr
, &tptr
);
2799 if ((tptr
== cptr
) || (*tptr
!= 0) ||
2800 (val
> mask
)) return SCPE_ARG
;
2802 else if (!(rptr
->flags
& REG_VMIO
) || /* dont use sym? */
2803 (parse_sym (cptr
, rdx
, NULL
, &val
, sim_switches
| SIM_SW_REG
) > SCPE_OK
)) {
2804 val
= get_uint (cptr
, rdx
, mask
, &r
);
2805 if (r
!= SCPE_OK
) return SCPE_ARG
;
2807 if ((rptr
->flags
& REG_NZ
) && (val
== 0)) return SCPE_ARG
;
2808 put_rval (rptr
, idx
, val
);
2812 /* Put register value
2815 rptr = pointer to register descriptor
2823 void put_rval (REG
*rptr
, uint32 idx
, t_value val
)
2829 #define PUT_RVAL(sz,rp,id,v,m) \
2830 *(((sz *) rp->loc) + id) = \
2831 (*(((sz *) rp->loc) + id) & \
2832 ~((m) << (rp)->offset)) | ((v) << (rp)->offset)
2834 if (rptr
== sim_PC
) sim_brk_npc (0);
2836 mask
= width_mask
[rptr
->width
];
2837 if ((rptr
->depth
> 1) && (rptr
->flags
& REG_CIRC
)) {
2838 idx
= idx
+ rptr
->qptr
;
2839 if (idx
>= rptr
->depth
) idx
= idx
- rptr
->depth
;
2841 if ((rptr
->depth
> 1) && (rptr
->flags
& REG_UNIT
)) {
2842 uptr
= ((UNIT
*) rptr
->loc
) + idx
;
2843 #if defined (USE_INT64)
2844 if (sz
<= sizeof (uint32
))
2845 *((uint32
*) uptr
) = (*((uint32
*) uptr
) &
2846 ~(((uint32
) mask
) << rptr
->offset
)) |
2847 (((uint32
) val
) << rptr
->offset
);
2848 else *((t_uint64
*) uptr
) = (*((t_uint64
*) uptr
)
2849 & ~(mask
<< rptr
->offset
)) | (val
<< rptr
->offset
);
2851 *((uint32
*) uptr
) = (*((uint32
*) uptr
) &
2852 ~(((uint32
) mask
) << rptr
->offset
)) |
2853 (((uint32
) val
) << rptr
->offset
);
2856 else if (((rptr
->depth
> 1) || (rptr
->flags
& REG_FIT
)) &&
2857 (sz
== sizeof (uint8
)))
2858 PUT_RVAL (uint8
, rptr
, idx
, (uint32
) val
, (uint32
) mask
);
2859 else if (((rptr
->depth
> 1) || (rptr
->flags
& REG_FIT
)) &&
2860 (sz
== sizeof (uint16
)))
2861 PUT_RVAL (uint16
, rptr
, idx
, (uint32
) val
, (uint32
) mask
);
2862 #if defined (USE_INT64)
2863 else if (sz
<= sizeof (uint32
))
2864 PUT_RVAL (uint32
, rptr
, idx
, (int32
) val
, (uint32
) mask
);
2865 else PUT_RVAL (t_uint64
, rptr
, idx
, val
, mask
);
2867 else PUT_RVAL (uint32
, rptr
, idx
, val
, mask
);
2872 /* Examine address routine
2874 Inputs: (sim_eval is an implicit argument)
2875 ofile = output stream
2876 flag = type of ex/mod command (ex, iex, idep)
2877 addr = address to examine
2878 dptr = pointer to device
2879 uptr = pointer to unit
2881 return = if > 0, error status
2882 if <= 0,-number of extra addr units retired
2885 t_stat
ex_addr (FILE *ofile
, int32 flag
, t_addr addr
, DEVICE
*dptr
, UNIT
*uptr
)
2890 if (sim_vm_fprint_addr
) sim_vm_fprint_addr (ofile
, dptr
, addr
);
2891 else fprint_val (ofile
, addr
, dptr
->aradix
, dptr
->awidth
, PV_LEFT
);
2892 fprintf (ofile
, ":\t");
2893 if (!(flag
& EX_E
)) return (1 - dptr
->aincr
);
2895 GET_RADIX (rdx
, dptr
->dradix
);
2896 if ((reason
= fprint_sym (ofile
, addr
, sim_eval
, uptr
, sim_switches
)) > 0) {
2897 fprint_val (ofile
, sim_eval
[0], rdx
, dptr
->dwidth
, PV_RZRO
);
2898 reason
= 1 - dptr
->aincr
;
2900 if (flag
& EX_I
) fprintf (ofile
, "\t");
2901 else fprintf (ofile
, "\n");
2905 /* Get address routine
2908 flag = type of ex/mod command (ex, iex, idep)
2909 addr = address to examine
2910 dptr = pointer to device
2911 uptr = pointer to unit
2912 Outputs: (sim_eval is an implicit output)
2913 return = error status
2916 t_stat
get_aval (t_addr addr
, DEVICE
*dptr
, UNIT
*uptr
)
2922 t_stat reason
= SCPE_OK
;
2924 if ((dptr
== NULL
) || (uptr
== NULL
)) return SCPE_IERR
;
2925 mask
= width_mask
[dptr
->dwidth
];
2926 for (i
= 0; i
< sim_emax
; i
++) sim_eval
[i
] = 0;
2927 for (i
= 0, j
= addr
; i
< sim_emax
; i
++, j
= j
+ dptr
->aincr
) {
2928 if (dptr
->examine
!= NULL
) {
2929 reason
= dptr
->examine (&sim_eval
[i
], j
, uptr
, sim_switches
);
2930 if (reason
!= SCPE_OK
) break;
2933 if (!(uptr
->flags
& UNIT_ATT
)) return SCPE_UNATT
;
2934 if (uptr
->flags
& UNIT_RAW
) return SCPE_NOFNC
;
2935 if ((uptr
->flags
& UNIT_FIX
) && (j
>= uptr
->capac
)) {
2940 loc
= j
/ dptr
->aincr
;
2941 if (uptr
->flags
& UNIT_BUF
) {
2942 SZ_LOAD (sz
, sim_eval
[i
], uptr
->filebuf
, loc
);
2945 sim_fseek (uptr
->fileref
, sz
* loc
, SEEK_SET
);
2946 sim_fread (&sim_eval
[i
], sz
, 1, uptr
->fileref
);
2947 if ((feof (uptr
->fileref
)) &&
2948 !(uptr
->flags
& UNIT_FIX
)) {
2952 else if (ferror (uptr
->fileref
)) {
2953 clearerr (uptr
->fileref
);
2954 reason
= SCPE_IOERR
;
2959 sim_eval
[i
] = sim_eval
[i
] & mask
;
2961 if ((reason
!= SCPE_OK
) && (i
== 0)) return reason
;
2965 /* Deposit address routine
2968 flag = type of deposit (normal/interactive)
2969 cptr = pointer to input string
2970 addr = address to examine
2971 dptr = pointer to device
2972 uptr = pointer to unit
2973 dfltinc = value to return on cr input
2975 return = if > 0, error status
2976 if <= 0, -number of extra address units retired
2979 t_stat
dep_addr (int32 flag
, char *cptr
, t_addr addr
, DEVICE
*dptr
,
2980 UNIT
*uptr
, int32 dfltinc
)
2982 int32 i
, count
, rdx
;
2987 char gbuf
[CBUFSIZE
];
2989 if (dptr
== NULL
) return SCPE_IERR
;
2991 cptr
= read_line (gbuf
, CBUFSIZE
, stdin
);
2992 if (sim_log
) fprintf (sim_log
, (cptr
? "%s\n": "\n"), cptr
);
2993 if (cptr
== NULL
) return 1; /* force exit */
2994 if (*cptr
== 0) return dfltinc
; /* success */
2996 if (uptr
->flags
& UNIT_RO
) return SCPE_RO
; /* read only? */
2997 mask
= width_mask
[dptr
->dwidth
];
2999 GET_RADIX (rdx
, dptr
->dradix
);
3000 if ((reason
= parse_sym (cptr
, addr
, uptr
, sim_eval
, sim_switches
)) > 0) {
3001 sim_eval
[0] = get_uint (cptr
, rdx
, mask
, &reason
);
3002 if (reason
!= SCPE_OK
) return reason
;
3004 count
= (1 - reason
+ (dptr
->aincr
- 1)) / dptr
->aincr
;
3006 for (i
= 0, j
= addr
; i
< count
; i
++, j
= j
+ dptr
->aincr
) {
3007 sim_eval
[i
] = sim_eval
[i
] & mask
;
3008 if (dptr
->deposit
!= NULL
) {
3009 r
= dptr
->deposit (sim_eval
[i
], j
, uptr
, sim_switches
);
3010 if (r
!= SCPE_OK
) return r
;
3013 if (!(uptr
->flags
& UNIT_ATT
)) return SCPE_UNATT
;
3014 if (uptr
->flags
& UNIT_RAW
) return SCPE_NOFNC
;
3015 if ((uptr
->flags
& UNIT_FIX
) && (j
>= uptr
->capac
))
3018 loc
= j
/ dptr
->aincr
;
3019 if (uptr
->flags
& UNIT_BUF
) {
3020 SZ_STORE (sz
, sim_eval
[i
], uptr
->filebuf
, loc
);
3021 if (loc
>= uptr
->hwmark
) uptr
->hwmark
= (uint32
) loc
+ 1;
3024 sim_fseek (uptr
->fileref
, sz
* loc
, SEEK_SET
);
3025 sim_fwrite (&sim_eval
[i
], sz
, 1, uptr
->fileref
);
3026 if (ferror (uptr
->fileref
)) {
3027 clearerr (uptr
->fileref
);
3036 /* Evaluate command */
3038 t_stat
eval_cmd (int32 flg
, char *cptr
)
3040 DEVICE
*dptr
= sim_dflt_dev
;
3041 int32 i
, rdx
, a
, lim
;
3044 GET_SWITCHES (cptr
);
3045 GET_RADIX (rdx
, dptr
->dradix
);
3046 for (i
= 0; i
< sim_emax
; i
++) sim_eval
[i
] = 0;
3047 if (*cptr
== 0) return SCPE_2FARG
;
3048 if ((r
= parse_sym (cptr
, 0, dptr
->units
, sim_eval
, sim_switches
)) > 0) {
3049 sim_eval
[0] = get_uint (cptr
, rdx
, width_mask
[dptr
->dwidth
], &r
);
3050 if (r
!= SCPE_OK
) return r
;
3053 for (i
= a
= 0; a
< lim
; ) {
3054 printf ("%d:\t", a
);
3055 if ((r
= fprint_sym (stdout
, a
, &sim_eval
[i
], dptr
->units
, sim_switches
)) > 0)
3056 r
= fprint_val (stdout
, sim_eval
[i
], rdx
, dptr
->dwidth
, PV_RZRO
);
3059 fprintf (sim_log
, "%d\t", i
);
3060 if ((r
= fprint_sym (sim_log
, a
, &sim_eval
[i
], dptr
->units
, sim_switches
)) > 0)
3061 r
= fprint_val (sim_log
, sim_eval
[i
], rdx
, dptr
->dwidth
, PV_RZRO
);
3062 fprintf (sim_log
, "\n");
3064 if (r
< 0) a
= a
+ 1 - r
;
3065 else a
= a
+ dptr
->aincr
;
3066 i
= a
/ dptr
->aincr
;
3071 /* String processing routines
3076 cptr = pointer to buffer
3078 stream = pointer to input stream
3080 optr = pointer to first non-blank character
3084 char *read_line (char *cptr
, int32 size
, FILE *stream
)
3088 cptr
= fgets (cptr
, size
, stream
); /* get cmd line */
3090 clearerr (stream
); /* clear error */
3091 return NULL
; /* ignore EOF */
3093 for (tptr
= cptr
; tptr
< (cptr
+ size
); tptr
++) { /* remove cr or nl */
3094 if ((*tptr
== '\n') || (*tptr
== '\r') ||
3095 (tptr
== (cptr
+ size
- 1))) { /* str max length? */
3096 *tptr
= 0; /* terminate */
3100 while (isspace (*cptr
)) cptr
++; /* trim leading spc */
3101 if (*cptr
== ';') *cptr
= 0; /* ignore comment */
3107 /* get_glyph get next glyph (force upper case)
3108 get_glyph_nc get next glyph (no conversion)
3109 get_glyph_gen get next glyph (general case)
3112 iptr = pointer to input string
3113 optr = pointer to output string
3114 mchar = optional end of glyph character
3115 flag = TRUE for convert to upper case (_gen only)
3117 result = pointer to next character in input string
3120 char *get_glyph_gen (char *iptr
, char *optr
, char mchar
, t_bool uc
)
3122 while ((isspace (*iptr
) == 0) && (*iptr
!= 0) && (*iptr
!= mchar
)) {
3123 if (islower (*iptr
) && uc
) *optr
= toupper (*iptr
);
3128 if (mchar
&& (*iptr
== mchar
)) iptr
++; /* skip terminator */
3129 while (isspace (*iptr
)) iptr
++; /* absorb spaces */
3133 char *get_glyph (char *iptr
, char *optr
, char mchar
)
3135 return get_glyph_gen (iptr
, optr
, mchar
, TRUE
);
3138 char *get_glyph_nc (char *iptr
, char *optr
, char mchar
)
3140 return get_glyph_gen (iptr
, optr
, mchar
, FALSE
);
3143 /* Trim trailing spaces from a string
3146 cptr = pointer to string
3148 cptr = pointer to string
3151 char *sim_trim_endspc (char *cptr
)
3155 tptr
= cptr
+ strlen (cptr
);
3156 while ((--tptr
>= cptr
) && isspace (*tptr
)) *tptr
= 0;
3160 /* get_yn yes/no question
3163 cptr = pointer to question
3164 deflt = default answer
3166 result = true if yes, false if no
3169 t_stat
get_yn (char *ques
, t_stat deflt
)
3171 char cbuf
[CBUFSIZE
], *cptr
;
3173 printf ("%s ", ques
);
3174 cptr
= read_line (cbuf
, CBUFSIZE
, stdin
);
3175 if ((cptr
== NULL
) || (*cptr
== 0)) return deflt
;
3176 if ((*cptr
== 'Y') || (*cptr
== 'y')) return TRUE
;
3180 /* get_uint unsigned number
3183 cptr = pointer to input string
3185 max = maximum acceptable value
3186 *status = pointer to error status
3191 t_value
get_uint (char *cptr
, uint32 radix
, t_value max
, t_stat
*status
)
3197 val
= strtotv (cptr
, &tptr
, radix
);
3198 if ((cptr
== tptr
) || (val
> max
)) *status
= SCPE_ARG
;
3200 while (isspace (*tptr
)) tptr
++;
3201 if (*tptr
!= 0) *status
= SCPE_ARG
;
3206 /* get_range range specification
3209 dptr = pointer to device (NULL if none)
3210 cptr = pointer to input string
3211 *lo = pointer to low result
3212 *hi = pointer to high result
3214 max = default high value
3215 term = terminating character, 0 if none
3217 tptr = input pointer after processing
3221 char *get_range (DEVICE
*dptr
, char *cptr
, t_addr
*lo
, t_addr
*hi
,
3222 uint32 rdx
, t_addr max
, char term
)
3226 if (max
&& strncmp (cptr
, "ALL", strlen ("ALL")) == 0) { /* ALL? */
3227 tptr
= cptr
+ strlen ("ALL");
3232 if (dptr
&& sim_vm_parse_addr
) /* get low */
3233 *lo
= sim_vm_parse_addr (dptr
, cptr
, &tptr
);
3234 else *lo
= (t_addr
) strtotv (cptr
, &tptr
, rdx
);
3235 if (cptr
== tptr
) return NULL
; /* error? */
3236 if ((*tptr
== '-') || (*tptr
== ':')) { /* range? */
3238 if (dptr
&& sim_vm_parse_addr
) /* get high */
3239 *hi
= sim_vm_parse_addr (dptr
, cptr
, &tptr
);
3240 else *hi
= (t_addr
) strtotv (cptr
, &tptr
, rdx
);
3241 if (cptr
== tptr
) return NULL
;
3242 if (*lo
> *hi
) return NULL
;
3244 else if (*tptr
== '/') { /* relative? */
3246 *hi
= (t_addr
) strtotv (cptr
, &tptr
, rdx
); /* get high */
3247 if ((cptr
== tptr
) || (*hi
== 0)) return NULL
;
3248 *hi
= *lo
+ *hi
- 1;
3252 if (term
&& (*tptr
++ != term
)) return NULL
;
3256 /* get_ipaddr IP address:port
3259 cptr = pointer to input string
3261 ipa = pointer to IP address (may be NULL), 0 = none
3262 ipp = pointer to IP port (may be NULL), 0 = none
3266 t_stat
get_ipaddr (char *cptr
, uint32
*ipa
, uint32
*ipp
)
3268 char gbuf
[CBUFSIZE
];
3269 char *addrp
, *portp
, *octetp
;
3270 uint32 i
, addr
, port
, octet
;
3273 if ((cptr
== NULL
) || (*cptr
== 0))
3275 strncpy (gbuf
, cptr
, CBUFSIZE
);
3276 addrp
= gbuf
; /* default addr */
3277 if (portp
= strchr (gbuf
, ':')) *portp
++ = 0; /* x:y? split */
3278 else if (strchr (gbuf
, '.')) portp
= NULL
; /* x.y...? */
3280 portp
= gbuf
; /* port only */
3281 addrp
= NULL
; /* no addr */
3283 if (portp
) { /* port string? */
3284 if (ipp
== NULL
) return SCPE_ARG
; /* not wanted? */
3285 port
= (int32
) get_uint (portp
, 10, 65535, &r
);
3286 if ((r
!= SCPE_OK
) || (port
== 0)) return SCPE_ARG
;
3289 if (addrp
) { /* addr string? */
3290 if (ipa
== NULL
) return SCPE_ARG
; /* not wanted? */
3291 for (i
= addr
= 0; i
< 4; i
++) { /* four octets */
3292 octetp
= strchr (addrp
, '.'); /* find octet end */
3293 if (octetp
!= NULL
) *octetp
++ = 0; /* split string */
3294 else if (i
< 3) return SCPE_ARG
; /* except last */
3295 octet
= (int32
) get_uint (addrp
, 10, 255, &r
);
3296 if (r
!= SCPE_OK
) return SCPE_ARG
;
3297 addr
= (addr
<< 8) | octet
;
3300 if (((addr
& 0377) == 0) || ((addr
& 0377) == 255))
3304 if (ipp
) *ipp
= port
; /* return req values */
3305 if (ipa
) *ipa
= addr
;
3309 /* Find_device find device matching input string
3312 cptr = pointer to input string
3314 result = pointer to device
3317 DEVICE
*find_dev (char *cptr
)
3322 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++) {
3323 if ((strcmp (cptr
, dptr
->name
) == 0) ||
3325 (strcmp (cptr
, dptr
->lname
) == 0))) return dptr
;
3330 /* Find_unit find unit matching input string
3333 cptr = pointer to input string
3334 uptr = pointer to unit pointer
3336 result = pointer to device (null if no dev)
3337 *iptr = pointer to unit (null if nx unit)
3340 DEVICE
*find_unit (char *cptr
, UNIT
**uptr
)
3347 if (uptr
== NULL
) return NULL
; /* arg error? */
3348 if (dptr
= find_dev (cptr
)) { /* exact match? */
3349 if (qdisable (dptr
)) return NULL
; /* disabled? */
3350 *uptr
= dptr
->units
; /* unit 0 */
3354 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* base + unit#? */
3355 if (dptr
->numunits
&& /* any units? */
3356 (((nptr
= dptr
->name
) &&
3357 (strncmp (cptr
, nptr
, strlen (nptr
)) == 0)) ||
3358 ((nptr
= dptr
->lname
) &&
3359 (strncmp (cptr
, nptr
, strlen (nptr
)) == 0)))) {
3360 tptr
= cptr
+ strlen (nptr
);
3361 if (isdigit (*tptr
)) {
3362 if (qdisable (dptr
)) return NULL
; /* disabled? */
3363 u
= (uint32
) get_uint (tptr
, 10, dptr
->numunits
- 1, &r
);
3364 if (r
!= SCPE_OK
) *uptr
= NULL
; /* error? */
3365 else *uptr
= dptr
->units
+ u
;
3373 /* Find_dev_from_unit find device for unit
3376 uptr = pointer to unit
3378 result = pointer to device
3381 DEVICE
*find_dev_from_unit (UNIT
*uptr
)
3386 if (uptr
== NULL
) return NULL
;
3387 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++) {
3388 for (j
= 0; j
< dptr
->numunits
; j
++) {
3389 if (uptr
== (dptr
->units
+ j
)) return dptr
;
3395 /* Test for disabled device */
3397 t_bool
qdisable (DEVICE
*dptr
)
3399 return (dptr
->flags
& DEV_DIS
? TRUE
: FALSE
);
3402 /* find_reg_glob find globally unique register
3405 cptr = pointer to input string
3406 optr = pointer to output pointer (can be null)
3407 gdptr = pointer to global device
3409 result = pointer to register, NULL if error
3410 *optr = pointer to next character in input string
3411 *gdptr = pointer to device where found
3414 REG
*find_reg_glob (char *cptr
, char **optr
, DEVICE
**gdptr
)
3418 REG
*rptr
, *srptr
= NULL
;
3420 for (i
= 0; (dptr
= sim_devices
[i
]) != 0; i
++) { /* all dev */
3421 if (dptr
->flags
& DEV_DIS
) continue; /* skip disabled */
3422 if (rptr
= find_reg (cptr
, optr
, dptr
)) { /* found? */
3423 if (srptr
) return NULL
; /* ambig? err */
3424 srptr
= rptr
; /* save reg */
3425 *gdptr
= dptr
; /* save unit */
3431 /* find_reg find register matching input string
3434 cptr = pointer to input string
3435 optr = pointer to output pointer (can be null)
3436 dptr = pointer to device
3438 result = pointer to register, NULL if error
3439 *optr = pointer to next character in input string
3442 REG
*find_reg (char *cptr
, char **optr
, DEVICE
*dptr
)
3448 if ((cptr
== NULL
) || (dptr
== NULL
) ||
3449 (dptr
->registers
== NULL
)) return NULL
;
3453 } while (isalnum (*tptr
) || (*tptr
== '*') || (*tptr
== '_'));
3455 for (rptr
= dptr
->registers
; rptr
->name
!= NULL
; rptr
++) {
3456 if ((slnt
== strlen (rptr
->name
)) &&
3457 (strncmp (cptr
, rptr
->name
, slnt
) == 0)) {
3458 if (optr
!= NULL
) *optr
= tptr
;
3465 /* get_switches get switches from input string
3468 cptr = pointer to input string
3470 sw = switch bit mask
3471 0 if no switches, -1 if error
3474 int32
get_switches (char *cptr
)
3478 if (*cptr
!= '-') return 0;
3480 for (cptr
++; (isspace (*cptr
) == 0) && (*cptr
!= 0); cptr
++) {
3481 if (isalpha (*cptr
) == 0) return -1;
3482 sw
= sw
| SWMASK (toupper (*cptr
));
3487 /* get_sim_sw accumulate sim_switches
3490 cptr = pointer to input string
3492 ptr = pointer to first non-string glyph
3496 char *get_sim_sw (char *cptr
)
3499 char gbuf
[CBUFSIZE
];
3501 while (*cptr
== '-') { /* while switches */
3502 cptr
= get_glyph (cptr
, gbuf
, 0); /* get switch glyph */
3503 lsw
= get_switches (gbuf
); /* parse */
3504 if (lsw
<= 0) return NULL
; /* invalid? */
3505 sim_switches
= sim_switches
| lsw
; /* accumulate */
3510 /* get_sim_opt get simulator command options
3513 opt = command options
3514 cptr = pointer to input string
3516 ptr = pointer to next glypsh, NULL if error
3517 *stat = error status
3520 char *get_sim_opt (int32 opt
, char *cptr
, t_stat
*st
)
3523 char *svptr
, gbuf
[CBUFSIZE
];
3527 sim_switches
= 0; /* no switches */
3528 sim_ofile
= NULL
; /* no output file */
3529 sim_schptr
= NULL
; /* no search */
3530 sim_stab
.logic
= SCH_OR
; /* default search params */
3531 sim_stab
.boolop
= SCH_GE
;
3534 sim_dfdev
= sim_dflt_dev
;
3535 sim_dfunit
= sim_dfdev
->units
;
3536 sim_opt_out
= 0; /* no options yet */
3538 while (*cptr
) { /* loop through modifiers */
3539 svptr
= cptr
; /* save current position */
3540 if ((opt
& CMD_OPT_OF
) && (*cptr
== '@')) { /* output file spec? */
3541 if (sim_ofile
) { /* already got one? */
3542 fclose (sim_ofile
); /* one per customer */
3546 cptr
= get_glyph_nc (cptr
+ 1, gbuf
, 0);
3547 sim_ofile
= sim_fopen (gbuf
, "a"); /* open for append */
3548 if (sim_ofile
== NULL
) { /* open failed? */
3552 sim_opt_out
|= CMD_OPT_OF
; /* got output file */
3555 cptr
= get_glyph (cptr
, gbuf
, 0);
3556 if ((t
= get_switches (gbuf
)) != 0) { /* try for switches */
3557 if (t
< 0) { /* err if bad switch */
3561 sim_switches
= sim_switches
| t
; /* or in new switches */
3563 else if ((opt
& CMD_OPT_SCH
) && /* if allowed, */
3564 get_search (gbuf
, sim_dfdev
->dradix
, &sim_stab
)) { /* try for search */
3565 sim_schptr
= &sim_stab
; /* set search */
3566 sim_opt_out
|= CMD_OPT_SCH
; /* got search */
3568 else if ((opt
& CMD_OPT_DFT
) && /* default allowed? */
3569 ((sim_opt_out
& CMD_OPT_DFT
) == 0) && /* none yet? */
3570 (tdptr
= find_unit (gbuf
, &tuptr
)) && /* try for default */
3572 sim_dfdev
= tdptr
; /* set as default */
3574 sim_opt_out
|= CMD_OPT_DFT
; /* got default */
3576 else return svptr
; /* not rec, break out */
3581 /* Match file extension
3585 ext = extension, without period
3587 cp = pointer to final '.' if match, NULL if not
3590 char *match_ext (char *fnam
, char *ext
)
3592 char *pptr
, *fptr
, *eptr
;
3594 if ((fnam
== NULL
) || (ext
== NULL
)) /* bad arguments? */
3596 pptr
= strrchr (fnam
, '.'); /* find last . */
3597 if (pptr
) { /* any? */
3598 for (fptr
= pptr
+ 1, eptr
= ext
; /* match characters */
3599 #if defined (VMS) /* VMS: stop at ; or null */
3600 (*fptr
!= 0) && (*fptr
!= ';');
3602 *fptr
!= 0; /* others: stop at null */
3605 if (toupper (*fptr
) != toupper (*eptr
))
3608 if (*eptr
!= 0) return NULL
; /* ext exhausted? */
3613 /* Get search specification
3616 cptr = pointer to input string
3617 radix = radix for numbers
3618 schptr = pointer to search table
3620 return = NULL if error
3621 schptr if valid search specification
3624 SCHTAB
*get_search (char *cptr
, int32 radix
, SCHTAB
*schptr
)
3626 int32 c
, logop
, cmpop
;
3627 t_value logval
, cmpval
;
3629 const char logstr
[] = "|&^", cmpstr
[] = "=!><";
3631 logval
= cmpval
= 0;
3632 if (*cptr
== 0) return NULL
; /* check for clause */
3633 for (logop
= cmpop
= -1; c
= *cptr
++; ) { /* loop thru clauses */
3634 if (sptr
= strchr (logstr
, c
)) { /* check for mask */
3635 logop
= sptr
- logstr
;
3636 logval
= strtotv (cptr
, &tptr
, radix
);
3637 if (cptr
== tptr
) return NULL
;
3640 else if (sptr
= strchr (cmpstr
, c
)) { /* check for boolop */
3641 cmpop
= sptr
- cmpstr
;
3643 cmpop
= cmpop
+ strlen (cmpstr
);
3646 cmpval
= strtotv (cptr
, &tptr
, radix
);
3647 if (cptr
== tptr
) return NULL
;
3653 schptr
->logic
= logop
;
3654 schptr
->mask
= logval
;
3657 schptr
->boolop
= cmpop
;
3658 schptr
->comp
= cmpval
;
3663 /* Test value against search specification
3667 schptr = pointer to search table
3669 return = 1 if value passes search criteria, 0 if not
3672 int32
test_search (t_value val
, SCHTAB
*schptr
)
3674 if (schptr
== NULL
) return 0;
3676 switch (schptr
->logic
) { /* case on logical */
3679 val
= val
| schptr
->mask
;
3683 val
= val
& schptr
->mask
;
3687 val
= val
^ schptr
->mask
;
3691 switch (schptr
->boolop
) { /* case on comparison */
3693 case SCH_E
: case SCH_EE
:
3694 return (val
== schptr
->comp
);
3696 case SCH_N
: case SCH_NE
:
3697 return (val
!= schptr
->comp
);
3700 return (val
> schptr
->comp
);
3703 return (val
>= schptr
->comp
);
3706 return (val
< schptr
->comp
);
3709 return (val
<= schptr
->comp
);
3715 /* Radix independent input/output package
3717 strtotv - general radix input routine
3720 inptr = string to convert
3721 endptr = pointer to first unconverted character
3722 radix = radix for input
3724 value = converted value
3726 On an error, the endptr will equal the inptr.
3729 t_value
strtotv (char *inptr
, char **endptr
, uint32 radix
)
3735 *endptr
= inptr
; /* assume fails */
3736 if ((radix
< 2) || (radix
> 36)) return 0;
3737 while (isspace (*inptr
)) inptr
++; /* bypass white space */
3740 for (c
= *inptr
; isalnum(c
); c
= *++inptr
) { /* loop through char */
3741 if (islower (c
)) c
= toupper (c
);
3742 if (isdigit (c
)) digit
= c
- (uint32
) '0'; /* digit? */
3743 else if (radix
<= 10) break; /* stop if not expected */
3744 else digit
= c
+ 10 - (uint32
) 'A'; /* convert letter */
3745 if (digit
>= radix
) return 0; /* valid in radix? */
3746 val
= (val
* radix
) + digit
; /* add to value */
3749 if (nodigit
) return 0; /* no digits? */
3750 *endptr
= inptr
; /* result pointer */
3754 /* fprint_val - general radix printing routine
3757 stream = stream designator
3758 val = value to print
3759 radix = radix to print
3760 width = width to print
3761 format = leading zeroes format
3763 status = error status
3766 t_stat
fprint_val (FILE *stream
, t_value val
, uint32 radix
,
3767 uint32 width
, uint32 format
)
3769 #define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value)))
3770 t_value owtest
, wtest
;
3771 int32 d
, digit
, ndigits
;
3772 char dbuf
[MAX_WIDTH
+ 1];
3774 for (d
= 0; d
< MAX_WIDTH
; d
++) dbuf
[d
] = (format
== PV_RZRO
)? '0': ' ';
3775 dbuf
[MAX_WIDTH
] = 0;
3779 digit
= (int32
) (val
% radix
);
3781 dbuf
[d
] = (digit
<= 9)? '0' + digit
: 'A' + (digit
- 10);
3782 } while ((d
> 0) && (val
!= 0));
3784 if (format
!= PV_LEFT
) {
3785 wtest
= owtest
= radix
;
3787 while ((wtest
< width_mask
[width
]) && (wtest
>= owtest
)) {
3789 wtest
= wtest
* radix
;
3790 ndigits
= ndigits
+ 1;
3792 if ((MAX_WIDTH
- ndigits
) < d
) d
= MAX_WIDTH
- ndigits
;
3794 if (fputs (&dbuf
[d
], stream
) == EOF
) return SCPE_IOERR
;
3798 /* Event queue package
3800 sim_activate add entry to event queue
3801 sim_cancel remove entry from event queue
3802 sim_process_event process entries on event queue
3803 sim_is_active see if entry is on event queue
3804 sim_atime return absolute time for an entry
3805 sim_gtime return global time
3806 sim_qcount return event queue entry count
3808 Asynchronous events are set up by queueing a unit data structure
3809 to the event queue with a timeout (in simulator units, relative
3810 to the current time). Each simulator 'times' these events by
3811 counting down interval counter sim_interval. When this reaches
3812 zero the simulator calls sim_process_event to process the event
3813 and to see if further events need to be processed, or sim_interval
3814 reset to count the next one.
3816 The event queue is maintained in clock order; entry timeouts are
3817 RELATIVE to the time in the previous entry.
3819 sim_process_event - process event
3824 reason = reason code returned by any event processor,
3825 or 0 (SCPE_OK) if no exceptions
3828 t_stat
sim_process_event (void)
3833 if (stop_cpu
) return SCPE_STOP
; /* stop CPU? */
3834 if (sim_clock_queue
== NULL
) { /* queue empty? */
3835 UPDATE_SIM_TIME (noqueue_time
); /* update sim time */
3836 sim_interval
= noqueue_time
= NOQUEUE_WAIT
; /* flag queue empty */
3839 UPDATE_SIM_TIME (sim_clock_queue
->time
); /* update sim time */
3841 uptr
= sim_clock_queue
; /* get first */
3842 sim_clock_queue
= uptr
->next
; /* remove first */
3843 uptr
->next
= NULL
; /* hygiene */
3845 if (sim_clock_queue
!= NULL
) sim_interval
= sim_clock_queue
->time
;
3846 else sim_interval
= noqueue_time
= NOQUEUE_WAIT
;
3847 if (uptr
->action
!= NULL
) reason
= uptr
->action (uptr
);
3848 else reason
= SCPE_OK
;
3849 } while ((reason
== SCPE_OK
) && (sim_interval
== 0));
3851 /* Empty queue forces sim_interval != 0 */
3856 /* sim_activate - activate (queue) event
3859 uptr = pointer to unit
3860 event_time = relative timeout
3862 reason = result (SCPE_OK if ok)
3865 t_stat
sim_activate (UNIT
*uptr
, int32 event_time
)
3867 UNIT
*cptr
, *prvptr
;
3870 if (event_time
< 0) return SCPE_IERR
;
3871 if (sim_is_active (uptr
)) return SCPE_OK
; /* already active? */
3872 if (sim_clock_queue
== NULL
) { UPDATE_SIM_TIME (noqueue_time
); }
3873 else { UPDATE_SIM_TIME (sim_clock_queue
->time
); } /* update sim time */
3877 for (cptr
= sim_clock_queue
; cptr
!= NULL
; cptr
= cptr
->next
) {
3878 if (event_time
< (accum
+ cptr
->time
)) break;
3879 accum
= accum
+ cptr
->time
;
3882 if (prvptr
== NULL
) { /* insert at head */
3883 cptr
= uptr
->next
= sim_clock_queue
;
3884 sim_clock_queue
= uptr
;
3887 cptr
= uptr
->next
= prvptr
->next
; /* insert at prvptr */
3888 prvptr
->next
= uptr
;
3890 uptr
->time
= event_time
- accum
;
3891 if (cptr
!= NULL
) cptr
->time
= cptr
->time
- uptr
->time
;
3892 sim_interval
= sim_clock_queue
->time
;
3896 /* sim_activate_abs - activate (queue) event even if event already scheduled
3899 uptr = pointer to unit
3900 event_time = relative timeout
3902 reason = result (SCPE_OK if ok)
3905 t_stat
sim_activate_abs (UNIT
*uptr
, int32 event_time
)
3908 return sim_activate (uptr
, event_time
);
3911 /* sim_cancel - cancel (dequeue) event
3914 uptr = pointer to unit
3916 reason = result (SCPE_OK if ok)
3920 t_stat
sim_cancel (UNIT
*uptr
)
3924 if (sim_clock_queue
== NULL
) return SCPE_OK
;
3925 UPDATE_SIM_TIME (sim_clock_queue
->time
); /* update sim time */
3927 if (sim_clock_queue
== uptr
) nptr
= sim_clock_queue
= uptr
->next
;
3929 for (cptr
= sim_clock_queue
; cptr
!= NULL
; cptr
= cptr
->next
) {
3930 if (cptr
->next
== uptr
) {
3931 nptr
= cptr
->next
= uptr
->next
;
3932 break; /* end queue scan */
3936 if (nptr
!= NULL
) nptr
->time
= nptr
->time
+ uptr
->time
;
3937 uptr
->next
= NULL
; /* hygiene */
3939 if (sim_clock_queue
!= NULL
) sim_interval
= sim_clock_queue
->time
;
3940 else sim_interval
= noqueue_time
= NOQUEUE_WAIT
;
3944 /* sim_is_active - test for entry in queue, return activation time
3947 uptr = pointer to unit
3949 result = absolute activation time + 1, 0 if inactive
3952 int32
sim_is_active (UNIT
*uptr
)
3958 for (cptr
= sim_clock_queue
; cptr
!= NULL
; cptr
= cptr
->next
) {
3959 if (cptr
== sim_clock_queue
) {
3960 if (sim_interval
> 0) accum
= accum
+ sim_interval
;
3962 else accum
= accum
+ cptr
->time
;
3963 if (cptr
== uptr
) return accum
+ 1;
3968 /* sim_gtime - return global time
3969 sim_grtime - return global time with rollover
3976 double sim_gtime (void)
3978 if (sim_clock_queue
== NULL
) { UPDATE_SIM_TIME (noqueue_time
); }
3979 else { UPDATE_SIM_TIME (sim_clock_queue
->time
); }
3983 uint32
sim_grtime (void)
3985 if (sim_clock_queue
== NULL
) { UPDATE_SIM_TIME (noqueue_time
); }
3986 else { UPDATE_SIM_TIME (sim_clock_queue
->time
); }
3990 /* sim_qcount - return queue entry count
3994 count = number of entries on the queue
3997 int32
sim_qcount (void)
4003 for (uptr
= sim_clock_queue
; uptr
!= NULL
; uptr
= uptr
->next
) cnt
++;
4007 /* Breakpoint package. This module replaces the VM-implemented one
4008 instruction breakpoint capability.
4010 Breakpoints are stored in table sim_brk_tab, which is ordered by address for
4011 efficient binary searching. A breakpoint consists of a four entry structure:
4013 addr address of the breakpoint
4014 type types of breakpoints set on the address
4015 a bit mask representing letters A-Z
4016 cnt number of iterations before breakp is taken
4017 action pointer command string to be executed
4020 sim_brk_summ is a summary of the types of breakpoints that are currently set (it
4021 is the bitwise OR of all the type fields). A simulator need only check for
4022 a breakpoint of type X if bit SWMASK('X') is set in sim_brk_sum.
4024 The package contains the following public routines:
4026 sim_brk_init initialize
4027 sim_brk_set set breakpoint
4028 sim_brk_clr clear breakpoint
4029 sim_brk_clrall clear all breakpoints
4030 sim_brk_show show breakpoint
4031 sim_brk_showall show all breakpoints
4032 sim_brk_test test for breakpoint
4033 sim_brk_npc PC has been changed
4034 sim_brk_getact get next action
4035 sim_brk_clract clear pending actions
4037 Initialize breakpoint system.
4040 t_stat
sim_brk_init (void)
4042 sim_brk_lnt
= SIM_BRK_INILNT
;
4043 sim_brk_tab
= (BRKTAB
*) calloc (sim_brk_lnt
, sizeof (BRKTAB
));
4044 if (sim_brk_tab
== NULL
) return SCPE_MEM
;
4045 sim_brk_ent
= sim_brk_ins
= 0;
4051 /* Search for a breakpoint in the sorted breakpoint table */
4053 BRKTAB
*sim_brk_fnd (t_addr loc
)
4058 if (sim_brk_ent
== 0) { /* table empty? */
4059 sim_brk_ins
= 0; /* insrt at head */
4060 return NULL
; /* sch fails */
4062 lo
= 0; /* initial bounds */
4063 hi
= sim_brk_ent
- 1;
4065 p
= (lo
+ hi
) >> 1; /* probe */
4066 bp
= sim_brk_tab
+ p
; /* table addr */
4067 if (loc
== bp
->addr
) return bp
; /* match? */
4068 else if (loc
< bp
->addr
) hi
= p
- 1; /* go down? p is upper */
4069 else lo
= p
+ 1; /* go up? p is lower */
4071 if (loc
< bp
->addr
) sim_brk_ins
= p
; /* insrt before or */
4072 else sim_brk_ins
= p
+ 1; /* after last sch */
4076 /* Insert a breakpoint */
4078 BRKTAB
*sim_brk_new (t_addr loc
)
4083 if (sim_brk_ins
< 0) return NULL
;
4084 if (sim_brk_ent
>= sim_brk_lnt
) { /* out of space? */
4085 t
= sim_brk_lnt
+ SIM_BRK_INILNT
; /* new size */
4086 newp
= (BRKTAB
*) calloc (t
, sizeof (BRKTAB
)); /* new table */
4087 if (newp
== NULL
) return NULL
; /* can't extend */
4088 for (i
= 0; i
< sim_brk_lnt
; i
++) /* copy table */
4089 *(newp
+ i
) = *(sim_brk_tab
+ i
);
4090 free (sim_brk_tab
); /* free old table */
4091 sim_brk_tab
= newp
; /* new base, lnt */
4094 if (sim_brk_ins
!= sim_brk_ent
) { /* move needed? */
4095 for (bp
= sim_brk_tab
+ sim_brk_ent
;
4096 bp
> sim_brk_tab
+ sim_brk_ins
; bp
--)
4099 bp
= sim_brk_tab
+ sim_brk_ins
;
4104 sim_brk_ent
= sim_brk_ent
+ 1;
4108 /* Set a breakpoint of type sw */
4110 t_stat
sim_brk_set (t_addr loc
, int32 sw
, int32 ncnt
, char *act
)
4114 if (sw
== 0) sw
= sim_brk_dflt
;
4115 if ((sim_brk_types
& sw
) == 0) return SCPE_NOFNC
;
4116 bp
= sim_brk_fnd (loc
); /* present? */
4117 if (!bp
) bp
= sim_brk_new (loc
); /* no, allocate */
4118 if (!bp
) return SCPE_MEM
; /* still no? mem err */
4119 bp
->typ
= sw
; /* set type */
4120 bp
->cnt
= ncnt
; /* set count */
4121 if ((bp
->act
!= NULL
) && (act
!= NULL
)) { /* replace old action? */
4122 free (bp
->act
); /* deallocate */
4123 bp
->act
= NULL
; /* now no action */
4125 if ((act
!= NULL
) && (*act
!= 0)) { /* new action? */
4126 char *newp
= (char *) calloc (CBUFSIZE
, sizeof (char)); /* alloc buf */
4127 if (newp
== NULL
) return SCPE_MEM
; /* mem err? */
4128 strncpy (newp
, act
, CBUFSIZE
); /* copy action */
4129 bp
->act
= newp
; /* set pointer */
4131 sim_brk_summ
= sim_brk_summ
| sw
;
4135 /* Clear a breakpoint */
4137 t_stat
sim_brk_clr (t_addr loc
, int32 sw
)
4139 BRKTAB
*bp
= sim_brk_fnd (loc
);
4141 if (!bp
) return SCPE_OK
; /* not there? ok */
4142 if (sw
== 0) sw
= SIM_BRK_ALLTYP
;
4143 bp
->typ
= bp
->typ
& ~sw
;
4144 if (bp
->typ
) return SCPE_OK
; /* clear all types? */
4145 if (bp
->act
!= NULL
) free (bp
->act
); /* deallocate action */
4146 for ( ; bp
< (sim_brk_tab
+ sim_brk_ent
- 1); bp
++) /* erase entry */
4148 sim_brk_ent
= sim_brk_ent
- 1; /* decrement count */
4149 sim_brk_summ
= 0; /* recalc summary */
4150 for (bp
= sim_brk_tab
; bp
< (sim_brk_tab
+ sim_brk_ent
); bp
++)
4151 sim_brk_summ
= sim_brk_summ
| bp
->typ
;
4155 /* Clear all breakpoints */
4157 t_stat
sim_brk_clrall (int32 sw
)
4161 if (sw
== 0) sw
= SIM_BRK_ALLTYP
;
4162 for (bp
= sim_brk_tab
; bp
< (sim_brk_tab
+ sim_brk_ent
); ) {
4163 if (bp
->typ
& sw
) sim_brk_clr (bp
->addr
, sw
);
4169 /* Show a breakpoint */
4171 t_stat
sim_brk_show (FILE *st
, t_addr loc
, int32 sw
)
4173 BRKTAB
*bp
= sim_brk_fnd (loc
);
4177 if (sw
== 0) sw
= SIM_BRK_ALLTYP
;
4178 if (!bp
|| (!(bp
->typ
& sw
))) return SCPE_OK
;
4179 dptr
= sim_dflt_dev
;
4180 if (dptr
== NULL
) return SCPE_OK
;
4181 if (sim_vm_fprint_addr
) sim_vm_fprint_addr (st
, dptr
, loc
);
4182 else fprint_val (st
, loc
, dptr
->aradix
, dptr
->awidth
, PV_LEFT
);
4183 fprintf (st
, ":\t");
4184 for (i
= any
= 0; i
< 26; i
++) {
4185 if ((bp
->typ
>> i
) & 1) {
4186 if (any
) fprintf (st
, ", ");
4187 fputc (i
+ 'A', st
);
4191 if (bp
->cnt
> 0) fprintf (st
, " [%d]", bp
->cnt
);
4192 if (bp
->act
!= NULL
) fprintf (st
, "; %s", bp
->act
);
4197 /* Show all breakpoints */
4199 t_stat
sim_brk_showall (FILE *st
, int32 sw
)
4203 if (sw
== 0) sw
= SIM_BRK_ALLTYP
;
4204 for (bp
= sim_brk_tab
; bp
< (sim_brk_tab
+ sim_brk_ent
); bp
++) {
4205 if (bp
->typ
& sw
) sim_brk_show (st
, bp
->addr
, sw
);
4210 /* Test for breakpoint */
4212 uint32
sim_brk_test (t_addr loc
, uint32 btyp
)
4215 uint32 spc
= (btyp
>> SIM_BKPT_V_SPC
) & (SIM_BKPT_N_SPC
- 1);
4217 if ((bp
= sim_brk_fnd (loc
)) && (btyp
& bp
->typ
)) { /* in table, type match? */
4218 if ((sim_brk_pend
[spc
] && (loc
== sim_brk_ploc
[spc
])) || /* previous location? */
4219 (--bp
->cnt
> 0)) return 0; /* count > 0? */
4220 bp
->cnt
= 0; /* reset count */
4221 sim_brk_ploc
[spc
] = loc
; /* save location */
4222 sim_brk_pend
[spc
] = TRUE
; /* don't do twice */
4223 sim_brk_act
= bp
->act
; /* set up actions */
4224 return (btyp
& bp
->typ
);
4226 sim_brk_pend
[spc
] = FALSE
;
4230 /* Get next pending action, if any */
4232 char *sim_brk_getact (char *buf
, int32 size
)
4237 if (sim_brk_act
== NULL
) return NULL
; /* any action? */
4238 while (isspace (*sim_brk_act
)) sim_brk_act
++; /* skip spaces */
4239 if (*sim_brk_act
== 0) return (sim_brk_act
= NULL
); /* now empty? */
4240 if (ep
= strchr (sim_brk_act
, ';')) { /* cmd delimiter? */
4241 lnt
= ep
- sim_brk_act
; /* cmd length */
4242 memcpy (buf
, sim_brk_act
, lnt
+ 1); /* copy with ; */
4243 buf
[lnt
] = 0; /* erase ; */
4244 sim_brk_act
= sim_brk_act
+ lnt
+ 1; /* adv ptr */
4247 strncpy (buf
, sim_brk_act
, size
); /* copy action */
4248 sim_brk_act
= NULL
; /* no more */
4253 /* Clear pending actions */
4255 void sim_brk_clract (void)
4262 void sim_brk_npc (uint32 cnt
)
4266 if ((cnt
== 0) || (cnt
> SIM_BKPT_N_SPC
)) cnt
= SIM_BKPT_N_SPC
;
4267 for (i
= 0; i
< cnt
; i
++) {
4268 sim_brk_pend
[i
] = FALSE
;
4269 sim_brk_ploc
[i
] = 0;
4274 /* Clear breakpoint space */
4276 void sim_brk_clrspc (uint32 spc
)
4278 if (spc
< SIM_BKPT_N_SPC
) {
4279 sim_brk_pend
[spc
] = FALSE
;
4280 sim_brk_ploc
[spc
] = 0;
4285 /* Debug printout routines, from Dave Hittner */
4287 const char* debug_bstates
= "01_^";
4288 const char* debug_fmt
= "DBG> %s %s: ";
4289 int32 debug_unterm
= 0;
4291 /* Finds debug phrase matching bitmask from from device DEBTAB table */
4293 static char* get_dbg_verb (uint32 dbits
, DEVICE
* dptr
)
4295 static char* debtab_none
= "DEBTAB_ISNULL";
4296 static char* debtab_nomatch
= "DEBTAB_NOMATCH";
4299 if (dptr
->debflags
== 0) return debtab_none
;
4301 /* Find matching words for bitmask */
4303 while (dptr
->debflags
[offset
].name
&& (offset
< 32)) {
4304 if (dptr
->debflags
[offset
].mask
& dbits
)
4305 return dptr
->debflags
[offset
].name
;
4308 return debtab_nomatch
;
4311 /* Prints standard debug prefix unless previous call unterminated */
4313 static void sim_debug_prefix (uint32 dbits
, DEVICE
* dptr
)
4315 if (!debug_unterm
) {
4316 char* debug_type
= get_dbg_verb (dbits
, dptr
);
4317 fprintf(sim_deb
, debug_fmt
, dptr
->name
, debug_type
);
4321 /* Prints state of a register: bit translation + state (0,1,_,^)
4322 indicating the state and transition of the bit. States:
4323 0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
4325 void sim_debug_u16(uint32 dbits
, DEVICE
* dptr
, const char* const* bitdefs
,
4326 uint16 before
, uint16 after
, int terminate
)
4328 if (sim_deb
&& (dptr
->dctrl
& dbits
)) {
4331 sim_debug_prefix(dbits
, dptr
); /* print prefix if required */
4332 for (i
= 15; i
>= 0; i
--) { /* print xlation, transition */
4333 int off
= ((after
>> i
) & 1) + (((before
^ after
) >> i
) & 1) * 2;
4334 fprintf(sim_deb
, "%s%c ", bitdefs
[i
], debug_bstates
[off
]);
4336 if (terminate
) fprintf(sim_deb
, "\r\n");
4337 debug_unterm
= terminate
? 0 : 1; /* set unterm for next */
4341 #if defined (_WIN32)
4342 #define vsnprintf _vsnprintf
4344 #if defined (__DECC) && defined (__VMS)
4345 #define NO_vsnprintf
4347 #if defined( NO_vsnprintf)
4348 #define STACKBUFSIZE 16384
4350 #define STACKBUFSIZE 2048
4353 /* Inline debugging - will print debug message if debug file is
4354 set and the bitmask matches the current device debug options.
4355 Extra returns are added for un*x systems, since the output
4356 device is set into 'raw' mode when the cpu is booted,
4357 and the extra returns don't hurt any other systems. */
4359 void sim_debug (uint32 dbits
, DEVICE
* dptr
, const char* fmt
, ...)
4361 if (sim_deb
&& (dptr
->dctrl
& dbits
)) {
4363 char stackbuf
[STACKBUFSIZE
];
4364 int32 bufsize
= sizeof(stackbuf
);
4365 char *buf
= stackbuf
;
4369 buf
[bufsize
-1] = '\0';
4370 sim_debug_prefix(dbits
, dptr
); /* print prefix if required */
4372 while (1) { /* format passed string, args */
4373 va_start (arglist
, fmt
);
4374 #if defined(NO_vsnprintf)
4375 #if defined(HAS_vsprintf_void)
4377 /* Note, this could blow beyond the buffer, and we couldn't tell */
4378 /* That is a limitation of the C runtime library available on this platform */
4380 vsprintf (buf
, fmt
, arglist
);
4381 for (len
= 0; len
< bufsize
-1; len
++)
4382 if (buf
[len
] == 0) break;
4384 len
= vsprintf (buf
, fmt
, arglist
);
4385 #endif /* HAS_vsprintf_void */
4386 #else /* NO_vsnprintf */
4387 #if defined(HAS_vsnprintf_void)
4388 vsnprintf (buf
, bufsize
-1, fmt
, arglist
);
4389 for (len
= 0; len
< bufsize
-1; len
++)
4390 if (buf
[len
] == 0) break;
4392 len
= vsnprintf (buf
, bufsize
-1, fmt
, arglist
);
4393 #endif /* HAS_vsnprintf_void */
4394 #endif /* NO_vsnprintf */
4397 /* If it didn't fit into the buffer, then grow it and try again */
4399 if ((len
< 0) || (len
>= bufsize
-1)) {
4400 if (buf
!= stackbuf
) free (buf
);
4401 bufsize
= bufsize
* 2;
4402 buf
= (char *) malloc (bufsize
);
4403 if (buf
== NULL
) return; /* out of memory */
4404 buf
[bufsize
-1] = '\0';
4410 /* Output the formatted data expanding newlines where they exist */
4412 for (i
= j
= 0; i
< len
; ++i
) {
4413 if ('\n' == buf
[i
]) {
4414 if (i
> j
) fwrite (&buf
[j
], 1, i
-j
, sim_deb
);
4416 fputc('\r', sim_deb
);
4419 if (i
> j
) fwrite (&buf
[j
], 1, i
-j
, sim_deb
);
4421 /* Set unterminated flag for next time */
4423 debug_unterm
= (len
&& (buf
[len
-1]=='\n')) ? 0 : 1;
4424 if (buf
!= stackbuf
) free (buf
);