1 /* Simulator control program
2 
3    Copyright (c) 1993-1997,
4    Robert M Supnik, Digital Equipment Corporation
5    Commercial use prohibited
6 
7    25-Jan-97	RMS	Revised data types
8    23-Jan-97	RMS 	Added bi-endian I/O
9    06-Sep-96	RMS	Fixed bug in variable length IEXAMINE
10    16-Jun-96	RMS	Changed interface to parse/print_sym
11    06-Apr-96	RMS	Added error checking in reset all
12    07-Jan-96	RMS	Added register buffers in save/restore
13    11-Dec-95	RMS	Fixed ordering bug in save/restore
14    22-May-95	RMS	Added symbolic input
15    13-Apr-95	RMS	Added symbolic printouts
16 */
17 
18 #define SCP		1					/* defining module */
19 #include "sim_defs.h"
20 #include <limits.h>
21 #include <signal.h>
22 #include <ctype.h>
23 
24 #ifdef SUNOS
25 /* XXX Not sure if this is always ok, but old SunOS does not have strtoul
26  * so using signed instead.
27  */
28 #define strtoul (unsigned)strtol
29 #endif
30 
31 #define EX_D	0					/* deposit */
32 #define EX_E	1					/* examine */
33 #define EX_I	2					/* interactive */
34 #define SWHIDE	(1u << 26)				/* enable hiding */
35 #define RU_RUN	0					/* run */
36 #define RU_GO	1					/* go */
37 #define RU_STEP 2					/* step */
38 #define RU_CONT 3					/* continue */
39 #define RU_BOOT 4					/* boot */
40 #define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \
41 	x = sim_interval
42 
43 #ifdef PRO
44 #include "pro_defs.h"
45 #endif
46 extern char sim_name[];
47 extern DEVICE *sim_devices[];
48 extern REG *sim_PC;
49 extern char *sim_stop_messages[];
50 extern t_stat sim_instr (void);
51 extern t_stat sim_load (FILE *ptr);
52 extern int32 sim_emax;
53 extern t_stat print_sym (t_addr addr, t_value *val, UNIT *uptr, int32 sw);
54 extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val,
55 	int32 sw);
56 extern t_stat ttinit (void);
57 extern t_stat ttrunstate (void);
58 extern t_stat ttcmdstate (void);
59 extern t_stat ttclose (void);
60 UNIT *sim_clock_queue = NULL;
61 int32 sim_interval = 0;
62 static double sim_time;
63 static int32 noqueue_time;
64 volatile int32 stop_cpu = 0;
65 t_value *sim_eval = NULL;
66 t_value k1 = 1;
67 int32 sim_end = 1;				/* 1 = little, 0 = big */
68 unsigned char sim_flip[FLIP_SIZE];
69 
70 #define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d))
71 #define SZ_D(dp) (size_map[((dp) -> dwidth + CHAR_BIT - 1) / CHAR_BIT])
72 #define SZ_R(rp) \
73 	(size_map[((rp) -> width + (rp) -> offset + CHAR_BIT - 1) / CHAR_BIT])
74 
75 int32 get_switches (char *cptr);
76 t_value get_rval (REG *rptr, int idx);
77 void put_rval (REG *rptr, int idx, t_value val, t_value mask);
78 t_stat fprint_val (FILE *stream, t_value val, int rdx, int wid, int fmt);
79 char *read_line (char *ptr, int size, FILE *stream);
80 DEVICE *find_device (char *ptr, int32 *iptr);
81 DEVICE *find_dev_from_unit (UNIT *uptr);
82 REG *find_reg (char *ptr, char **optr, DEVICE *dptr);
83 t_stat detach_all (int start_device);
84 t_stat ex_reg (int flag, int32 sw, REG *rptr);
85 t_stat dep_reg (int flag, int32 sw, char *cptr, REG *rptr);
86 t_stat ex_addr (int flag, int32 sw, t_addr addr, DEVICE *dptr, UNIT *uptr);
87 t_stat dep_addr (int flag, int32 sw, char *cptr, t_addr addr, DEVICE *dptr,
88 	UNIT *uptr, int dfltinc);
89 t_stat step_svc (UNIT *ptr);
90 
91 UNIT step_unit = { UDATA (&step_svc, 0, 0)  };
92 const char *scp_error_messages[] = {
93 	"Address space exceeded",
94 	"Unit not attached",
95 	"I/O error",
96 	"Checksum error",
97 	"Format error",
98 	"Unit not attachable",
99 	"File open error",
100 	"Memory exhausted",
101 	"Invalid argument",
102 	"Step expired",
103 	"Unknown command",
104 	"Read only argument",
105 	"Command not completed",
106 	"Simulation stopped",
107 	"Goodbye",
108 	"Console input I/O error",
109 	"Console output I/O error",
110 	"End of file",
111 	"Relocation error",
112 	"No settable parameters",
113 	"Unit already attached"  };
114 
115 const size_t size_map[] = { sizeof (int8),
116 	sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
117 #if defined (int64)
118 	, sizeof (int64), sizeof (int64), sizeof (int64), sizeof (int64)
119 #endif
120 };
121 
main(int argc,char * argv[])122 int main (int argc, char *argv[])
123 {
124 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr;
125 int32 i, stat;
126 FILE *fpin;
127 union {int32 i; char c[sizeof (int32)]; } end_test;
128 t_stat reset_cmd (int flag, char *ptr);
129 t_stat exdep_cmd (int flag, char *ptr);
130 t_stat load_cmd (int flag, char *ptr);
131 t_stat run_cmd (int flag, char *ptr);
132 t_stat attach_cmd (int flag, char *ptr);
133 t_stat detach_cmd (int flag, char *ptr);
134 t_stat save_cmd (int flag, char *ptr);
135 t_stat restore_cmd (int flag, char *ptr);
136 t_stat exit_cmd (int flag, char *ptr);
137 t_stat set_cmd (int flag, char *ptr);
138 t_stat show_cmd (int flag, char *ptr);
139 t_stat add_cmd (int flag, char *ptr);
140 t_stat remove_cmd (int flag, char *ptr);
141 t_stat help_cmd (int flag, char *ptr);
142 
143 static CTAB cmd_table[] = {
144 	{ "RESET", &reset_cmd, 0 },
145 	{ "EXAMINE", &exdep_cmd, EX_E },
146 	{ "IEXAMINE", &exdep_cmd, EX_E+EX_I },
147 	{ "DEPOSIT", &exdep_cmd, EX_D },
148 	{ "IDEPOSIT", &exdep_cmd, EX_D+EX_I },
149 	{ "RUN", &run_cmd, RU_RUN },
150 	{ "GO", &run_cmd, RU_GO },
151 	{ "STEP", &run_cmd, RU_STEP },
152 	{ "CONT", &run_cmd, RU_CONT },
153 	{ "BOOT", &run_cmd, RU_BOOT },
154 	{ "ATTACH", &attach_cmd, 0 },
155 	{ "DETACH", &detach_cmd, 0 },
156 	{ "SAVE", &save_cmd, 0 },
157 	{ "RESTORE", &restore_cmd, 0 },
158 	{ "GET", &restore_cmd, 0 },
159 	{ "LOAD", &load_cmd, 0 },
160 	{ "EXIT", &exit_cmd, 0 },
161 	{ "QUIT", &exit_cmd, 0 },
162 	{ "BYE", &exit_cmd, 0 },
163 	{ "SET", &set_cmd, 0 },
164 	{ "SHOW", &show_cmd, 0 },
165 	{ "ADD", &add_cmd, 0 },
166 	{ "REMOVE", &remove_cmd, 0 },
167 	{ "HELP", &help_cmd, 0 },
168 	{ NULL, NULL, 0 }  };
169 
170 /* Main command loop */
171 
172 #ifndef PRO
173 printf ("\n%s simulator V2.3\n", sim_name);
174 #endif
175 end_test.i = 1;					/* test endian-ness */
176 sim_end = end_test.c[0];
177 if (sim_emax <= 0) sim_emax = 1;
178 if ((sim_eval = calloc (sim_emax, sizeof (t_value))) == NULL) {
179 	printf ("Unable to allocate examine buffer\n");
180 	return 0;  };
181 if ((stat = ttinit ()) != SCPE_OK) {
182 	printf ("Fatal terminal initialization error\n%s\n",
183 		scp_error_messages[stat - SCPE_BASE]);
184 	return 0;  }
185 stop_cpu = 0;
186 sim_interval = 0;
187 sim_time = 0;
188 noqueue_time = 0;
189 sim_clock_queue = NULL;
190 if ((stat = reset_all (0)) != SCPE_OK) {
191 	printf ("Fatal simulator initialization error\n%s\n",
192 		scp_error_messages[stat - SCPE_BASE]);
193 	return 0;  }
194 
195 if ((argc > 1) && (argv[1] != NULL) &&
196     ((fpin = fopen (argv[1], "r")) != NULL)) {		/* command file? */
197 	do {	cptr = read_line (cbuf, CBUFSIZE, fpin);
198 		if (cptr == NULL) break;		/* exit on eof */
199 		if (*cptr == 0) continue;		/* ignore blank */
200 		cptr = get_glyph (cptr, gbuf, 0);	/* get command glyph */
201 		for (i = 0; cmd_table[i].name != NULL; i++) {
202 		    if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) {
203 			stat = cmd_table[i].action (cmd_table[i].arg, cptr);
204 			break;  }  }
205 		if (stat >= SCPE_BASE)
206 			printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);
207 	} while (stat != SCPE_EXIT);  }			/* end if cmd file */
208 #ifdef PRO
209 else
210 {
211 	/* Jump to 160000 on startup if in PRO mode */
212 
213 	sprintf(cbuf, "g 160000");
214 	cptr = get_glyph (cbuf, gbuf, 0);	/* get command glyph */
215 	run_cmd(RU_GO, cptr);
216 }
217 #endif
218 
219 do {	printf ("sim> ");				/* prompt */
220 	cptr = read_line (cbuf, CBUFSIZE, stdin);	/* read command line */
221 	stat = SCPE_UNK;
222 	if (cptr == NULL) continue;			/* ignore EOF */
223 	if (*cptr == 0) continue;			/* ignore blank */
224 	cptr = get_glyph (cptr, gbuf, 0);		/* get command glyph */
225 	for (i = 0; cmd_table[i].name != NULL; i++) {
226 		if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) {
227 			stat = cmd_table[i].action (cmd_table[i].arg, cptr);
228 			break;  }  }
229 	if (stat >= SCPE_BASE)
230 		printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);
231 } while (stat != SCPE_EXIT);
232 
233 detach_all (0);
234 ttclose ();
235 return 0;
236 }
237 
238 /* Exit command */
239 
exit_cmd(int flag,char * cptr)240 t_stat exit_cmd (int flag, char *cptr)
241 {
242 #ifdef PRO
243 pro_exit();
244 #endif
245 return SCPE_EXIT;
246 }
247 
248 /* Help command */
249 
help_cmd(int flag,char * cptr)250 t_stat help_cmd (int flag, char *cptr)
251 {
252 printf ("r{eset} {ALL|<device>}   reset simulator\n");
253 printf ("e{xamine} <list>         examine memory or registers\n");
254 printf ("ie{xamine} <list>        interactive examine memory or registers\n");
255 printf ("d{eposit} <list> <val>   deposit in memory or registers\n");
256 printf ("id{eposit} <list>        interactive deposit in memory or registers\n");
257 printf ("l{oad} <file>            load binary file\n");
258 printf ("ru{n} {new PC}           reset and start simulation\n");
259 printf ("go {new PC}              start simulation\n");
260 printf ("c{ont}                   continue simulation\n");
261 printf ("s{tep} {n}               simulate n instructions\n");
262 printf ("b{oot} <device>|<unit>   bootstrap device\n");
263 printf ("at{tach} <unit> <file>   attach file to simulated unit\n");
264 printf ("det{ach} <unit>          detach file from simulated unit\n");
265 printf ("sa{ve} <file>            save simulator to file\n");
266 printf ("rest{ore}|ge{t} <file>   restore simulator from file\n");
267 printf ("exi{t}|q{uit}|by{e}      exit from simulation\n");
268 printf ("set <unit> <val>         set unit parameter\n");
269 printf ("show <device>            show device parameters\n");
270 printf ("sh{ow} c{onfiguration}   show configuration\n");
271 printf ("sh{ow} q{ueue}           show event queue\n");
272 printf ("sh{ow} t{ime}            show simulated time\n");
273 printf ("ad{d} <unit>             add unit to configuration\n");
274 printf ("rem{ove} <unit>          remove unit from configuration\n");
275 printf ("h{elp}                   type this message\n");
276 return SCPE_OK;
277 }
278 
279 /* Set command */
280 
set_cmd(int flag,char * cptr)281 t_stat set_cmd (int flag, char *cptr)
282 {
283 int32 unitno;
284 t_stat r;
285 char gbuf[CBUFSIZE];
286 DEVICE *dptr;
287 UNIT *uptr;
288 MTAB *mptr;
289 
290 cptr = get_glyph (cptr, gbuf, 0);			/* get glyph */
291 dptr = find_device (gbuf, &unitno);			/* find device */
292 if ((dptr == NULL) || (*cptr == 0)) return SCPE_ARG;	/* argument? */
293 cptr = get_glyph (cptr, gbuf, 0);			/* get glyph */
294 if (*cptr != 0) return SCPE_ARG;			/* now eol? */
295 uptr = dptr -> units + unitno;
296 if (uptr -> flags & UNIT_DIS) return SCPE_ARG;		/* disabled? */
297 if (dptr -> modifiers == NULL) return SCPE_NOPARAM;	/* any modifiers? */
298 for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) {
299 	if ((mptr -> mstring != NULL) &&
300 	    (MATCH_CMD (gbuf, mptr -> mstring) == 0)) {
301 		if ((mptr -> valid != NULL) &&
302 		   ((r = mptr -> valid (uptr, mptr -> match)) != SCPE_OK))
303 			return r;			/* invalid? */
304 		uptr -> flags = (uptr -> flags & ~(mptr -> mask)) |
305 			(mptr -> match & mptr -> mask);	/* set new value */
306 		return SCPE_OK;  }  }
307 return SCPE_ARG;					/* no match */
308 }
309 
310 /* Show command */
311 
show_cmd(int flag,char * cptr)312 t_stat show_cmd (int flag, char *cptr)
313 {
314 int32 i;
315 char gbuf[CBUFSIZE];
316 DEVICE *dptr;
317 t_stat show_config (int flag);
318 t_stat show_queue (int flag);
319 t_stat show_time (int flag);
320 t_stat show_device (DEVICE *dptr);
321 static CTAB show_table[] = {
322 	{ "CONFIGURATION", &show_config, 0 },
323 	{ "QUEUE", &show_queue, 0 },
324 	{ "TIME", &show_time, 0 },
325 	{ NULL, NULL, 0 }  };
326 
327 cptr = get_glyph (cptr, gbuf, 0);			/* get glyph */
328 if (*cptr != 0) return SCPE_ARG;			/* now eol? */
329 for (i = 0; show_table[i].name != NULL; i++) {		/* find command */
330 	if (MATCH_CMD (gbuf, show_table[i].name) == 0)
331 		return show_table[i].action (show_table[i].arg);  }
332 dptr = find_device (gbuf, NULL);			/* find device */
333 if (dptr == NULL) return SCPE_ARG;
334 return show_device (dptr);
335 }
336 
337 /* Show processors */
338 
show_device(DEVICE * dptr)339 t_stat show_device (DEVICE *dptr)
340 {
341 int32 j, ucnt;
342 UNIT *uptr;
343 MTAB *mptr;
344 
345 printf ("%s", dptr -> name);
346 for (j = ucnt = 0; j < dptr -> numunits; j++) {
347 	uptr = (dptr -> units) + j;
348 	if (!(uptr -> flags & UNIT_DIS)) ucnt++;  }
349 if (ucnt == 0) printf (", all units disabled\n");
350 if (ucnt > 1) printf (", %d units\n", ucnt);
351 for (j = 0; j < dptr -> numunits; j++) {
352 	uptr = (dptr -> units) + j;
353 	if (uptr -> flags & UNIT_DIS) continue;
354 	if (ucnt > 1) printf ("  unit %d", j);
355 	if (uptr -> flags & UNIT_FIX)
356 		printf (", %dK%s",
357 		uptr -> capac / ((uptr -> flags & UNIT_BINK)? 1024: 1000),
358 		((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B");
359 	if (uptr -> flags & UNIT_ATT)
360 		printf (", attached to %s", uptr -> filename);
361 	else if (uptr -> flags & UNIT_ATTABLE) printf (", not attached");
362 	if (dptr -> modifiers != NULL) {
363 		for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) {
364 			if ((mptr -> pstring != NULL) &&
365 			   ((uptr -> flags & mptr -> mask) == mptr -> match))
366 				printf (", %s", mptr -> pstring);  }  }
367 	printf ("\n");  }
368 return SCPE_OK;
369 }
370 
show_config(int flag)371 t_stat show_config (int flag)
372 {
373 int32 i;
374 DEVICE *dptr;
375 
376 printf ("%s simulator configuration\n\n", sim_name);
377 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) show_device (dptr);
378 return SCPE_OK;
379 }
380 
show_queue(int flag)381 t_stat show_queue (int flag)
382 {
383 DEVICE *dptr;
384 UNIT *uptr;
385 int32 accum;
386 
387 if (sim_clock_queue == NULL) {
388 	printf ("%s event queue empty, time = %-16.0f\n", sim_name, sim_time);
389 	return SCPE_OK;  }
390 printf ("%s event queue status, time = %-16.0f\n", sim_name, sim_time);
391 accum = 0;
392 for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) {
393 	if (uptr == &step_unit) printf ("  Step timer");
394 	else if ((dptr = find_dev_from_unit (uptr)) != NULL) {
395 		printf ("  %s", dptr -> name);
396 		if (dptr -> numunits > 1) printf (" unit %d",
397 			uptr - dptr -> units);  }
398 	else printf ("  Unknown");
399 	printf (" at %d\n", accum + uptr -> time);
400 	accum = accum + uptr -> time;  }
401 return SCPE_OK;
402 }
403 
show_time(int flag)404 t_stat show_time (int flag)
405 {
406 printf ("Time:	%-16.0f\n", sim_time);
407 return SCPE_OK;
408 }
409 
410 /* Add and remove commands and routines
411 
412    ad[d]		add unit to configuration
413    rem[ove]		remove unit from configuration
414 */
415 
add_cmd(int flag,char * cptr)416 t_stat add_cmd (int flag, char *cptr)
417 {
418 int32 unitno;
419 char gbuf[CBUFSIZE];
420 DEVICE *dptr;
421 UNIT *uptr;
422 
423 cptr = get_glyph (cptr, gbuf, 0);			/* get name */
424 dptr = find_device (gbuf, &unitno);			/* locate device */
425 if ((dptr == NULL) || (*cptr != 0)) return SCPE_ARG;	/* found it? */
426 uptr = dptr -> units + unitno;				/* locate unit */
427 if ((uptr -> flags & UNIT_DISABLE) && (uptr -> flags & UNIT_DIS)) {
428 	uptr -> flags = uptr -> flags & ~UNIT_DIS;	/* enable it */
429 	return SCPE_OK;  }
430 return SCPE_ARG;					/* not valid */
431 }
432 
remove_cmd(int flag,char * cptr)433 t_stat remove_cmd (int flag, char *cptr)
434 {
435 int32 unitno;
436 char gbuf[CBUFSIZE];
437 DEVICE *dptr;
438 UNIT *uptr;
439 
440 cptr = get_glyph (cptr, gbuf, 0);			/* get name */
441 dptr = find_device (gbuf, &unitno);			/* locate device */
442 if ((dptr == NULL) || (*cptr != 0)) return SCPE_ARG;	/* found it? */
443 uptr = dptr -> units + unitno;				/* locate unit */
444 if ((uptr -> flags & UNIT_DISABLE) && !(uptr -> flags & UNIT_DIS) &&
445    !(uptr -> flags & UNIT_ATT) && !sim_is_active (uptr)) {
446 	uptr -> flags = uptr -> flags | UNIT_DIS;	/* disable it */
447 	return SCPE_OK;  }
448 return SCPE_ARG;					/* not valid */
449 }
450 
451 /* Reset command and routines
452 
453    re[set]		reset all devices
454    re[set] all		reset all devices
455    re[set] device	reset specific device
456 */
457 
reset_cmd(int flag,char * cptr)458 t_stat reset_cmd (int flag, char *cptr)
459 {
460 char gbuf[CBUFSIZE];
461 DEVICE *dptr;
462 
463 if (*cptr == 0) return (reset_all (0));			/* reset(cr) */
464 cptr = get_glyph (cptr, gbuf, 0);			/* get next glyph */
465 if (*cptr != 0) return SCPE_ARG;			/* now (cr)? */
466 if (strcmp (gbuf, "ALL") == 0) return (reset_all (0));
467 if ((dptr = find_device (gbuf, NULL)) == NULL) return SCPE_ARG;
468 if (dptr -> reset != NULL) return dptr -> reset (dptr);
469 else return SCPE_OK;
470 }
471 
472 /* Reset devices start..end
473 
474    Inputs:
475 	start	=	number of starting device
476    Outputs:
477 	status	=	error status
478 */
479 
reset_all(int start)480 t_stat reset_all (int start)
481 {
482 DEVICE *dptr;
483 int32 i;
484 t_stat reason;
485 
486 #ifdef PRO
487 /* Don't reset PRO peripherals due to a RESET instruction */
488 
489 if (start == 0)
490   pro_reset();
491 #endif
492 
493 if ((start < 0) || (start > 1)) return SCPE_ARG;
494 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
495 	if (dptr -> reset != NULL) {
496 		reason = dptr -> reset (dptr);
497 		if (reason != SCPE_OK) return reason;  }  }
498 return SCPE_OK;
499 }
500 
501 /* Load command
502 
503    lo[ad] filename		load specified file
504 */
505 
load_cmd(int flag,char * cptr)506 t_stat load_cmd (int flag, char *cptr)
507 {
508 FILE *loadfile;
509 t_stat reason;
510 
511 if (*cptr == 0) return SCPE_ARG;
512 loadfile = fopen (cptr, "rb");
513 if (loadfile == NULL) return SCPE_OPENERR;
514 reason = sim_load (loadfile);
515 fclose (loadfile);
516 return reason;
517 }
518 
519 /* Attach command
520 
521    at[tach] unit file	attach specified unit to file
522 */
523 
attach_cmd(int flag,char * cptr)524 t_stat attach_cmd (int flag, char *cptr)
525 {
526 char gbuf[CBUFSIZE];
527 int32 unitno;
528 DEVICE *dptr;
529 UNIT *uptr;
530 
531 if (*cptr == 0) return SCPE_ARG;
532 cptr = get_glyph (cptr, gbuf, 0);
533 if (*cptr == 0) return SCPE_ARG;
534 if ((dptr = find_device (gbuf, &unitno)) == NULL) return SCPE_ARG;
535 uptr = (dptr -> units) + unitno;
536 if (dptr -> attach != NULL) return dptr -> attach (uptr, cptr);
537 return attach_unit (uptr, cptr);
538 }
539 
attach_unit(UNIT * uptr,char * cptr)540 t_stat attach_unit (UNIT *uptr, char *cptr)
541 {
542 DEVICE *dptr;
543 t_stat reason;
544 
545 if (uptr -> flags & UNIT_DIS) return SCPE_ARG;		/* disabled? */
546 if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT;	/* not attachable? */
547 if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT;
548 if (uptr -> flags & UNIT_ATT) {				/* already attached? */
549 	reason = detach_unit (uptr);
550 	if (reason != SCPE_OK) return reason;  }
551 uptr -> filename = calloc (CBUFSIZE, sizeof (char));
552 if (uptr -> filename == NULL) return SCPE_MEM;
553 strncpy (uptr -> filename, cptr, CBUFSIZE);
554 uptr -> fileref = fopen (cptr, "rb+");
555 if (uptr -> fileref == NULL) {
556 	uptr -> fileref = fopen (cptr, "wb+");
557 	if (uptr -> fileref == NULL) return SCPE_OPENERR;
558 	printf ("%s: creating new file\n", dptr -> name);  }
559 if (uptr -> flags & UNIT_BUFABLE) {
560 	if ((uptr -> filebuf = calloc (uptr -> capac, SZ_D (dptr))) != NULL) {
561 		printf ("%s: buffering file in memory\n", dptr -> name);
562 		uptr -> hwmark = fxread (uptr -> filebuf, SZ_D (dptr),
563 					uptr -> capac, uptr -> fileref);
564 		uptr -> flags = uptr -> flags | UNIT_BUF;  }
565 	else if (uptr -> flags & UNIT_MUSTBUF) return SCPE_MEM;  }
566 uptr -> flags = uptr -> flags | UNIT_ATT;
567 uptr -> pos = 0;
568 return SCPE_OK;
569 }
570 
571 /* Detach command
572 
573    det[ach] all		detach all units
574    det[ach] unit	detach specified unit
575 */
576 
detach_cmd(int flag,char * cptr)577 t_stat detach_cmd (int flag, char *cptr)
578 {
579 char gbuf[CBUFSIZE];
580 int32 unitno;
581 DEVICE *dptr;
582 UNIT *uptr;
583 
584 if (*cptr == 0) return SCPE_ARG;
585 cptr = get_glyph (cptr, gbuf, 0);
586 if (*cptr != 0) return SCPE_ARG;
587 if (strcmp (gbuf, "ALL") == 0) return (detach_all (0));
588 if ((dptr = find_device (gbuf, &unitno)) == NULL) return SCPE_ARG;
589 uptr = (dptr -> units) + unitno;
590 if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT;
591 if (dptr -> detach != NULL) return dptr -> detach (uptr);
592 return detach_unit (uptr);
593 }
594 
595 /* Detach devices start..end
596 
597    Inputs:
598 	start	=	number of starting device
599    Outputs:
600 	status	=	error status
601 */
602 
detach_all(int start)603 t_stat detach_all (int start)
604 {
605 int32 i, j;
606 t_stat reason;
607 DEVICE *dptr;
608 UNIT *uptr;
609 
610 if ((start < 0) || (start > 1)) return SCPE_ARG;
611 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
612 	for (j = 0; j < dptr -> numunits; j++) {
613 		uptr = (dptr -> units) + j;
614 		if (dptr -> detach != NULL) reason = dptr -> detach (uptr);
615 		else reason = detach_unit (uptr);
616 		if (reason != SCPE_OK) return reason;  }  }
617 return SCPE_OK;
618 }
619 
detach_unit(UNIT * uptr)620 t_stat detach_unit (UNIT *uptr)
621 {
622 DEVICE *dptr;
623 
624 if (uptr == NULL) return SCPE_ARG;
625 if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK;
626 if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK;
627 uptr -> flags = uptr -> flags & ~UNIT_ATT;
628 if (uptr -> flags & UNIT_BUF) {
629 	printf ("%s: writing buffer to file\n", dptr -> name);
630 	uptr -> flags = uptr -> flags & ~UNIT_BUF;
631 	rewind (uptr -> fileref);
632 	fxwrite (uptr -> filebuf, SZ_D (dptr), uptr -> hwmark, uptr -> fileref);
633 	if (ferror (uptr -> fileref)) perror ("I/O error");
634 	free (uptr -> filebuf);
635 	uptr -> filebuf = NULL;  }
636 free (uptr -> filename);
637 uptr -> filename = NULL;
638 return (fclose (uptr -> fileref) == EOF)? SCPE_IOERR: SCPE_OK;
639 }
640 
641 /* Save command
642 
643    sa[ve] filename		save state to specified file
644 */
645 
save_cmd(int flag,char * cptr)646 t_stat save_cmd (int flag, char *cptr)
647 {
648 FILE *sfile;
649 int32 i, j, t, zerocnt;
650 t_addr k, high;
651 t_value val;
652 t_stat reason;
653 DEVICE *dptr;
654 UNIT *uptr;
655 REG *rptr;
656 
657 #define WRITE_I(xx) fxwrite (&(xx), sizeof (xx), 1, sfile)
658 
659 if (*cptr == 0) return SCPE_ARG;
660 if ((sfile = fopen (cptr, "wb")) == NULL) return SCPE_OPENERR;
661 fputs (sim_name, sfile);				/* sim name */
662 fputc ('\n', sfile);
663 WRITE_I (sim_time);					/* sim time */
664 
665 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {	/* loop thru devices */
666 	fputs (dptr -> name, sfile);			/* device name */
667 	fputc ('\n', sfile);
668 	for (j = 0; j < dptr -> numunits; j++) {
669 		uptr = (dptr -> units) + j;
670 		t = sim_is_active (uptr);
671 		WRITE_I (j);				/* unit number */
672 		WRITE_I (t);				/* activation time */
673 		WRITE_I (uptr -> u3);			/* unit specific */
674 		WRITE_I (uptr -> u4);
675 		if (uptr -> flags & UNIT_ATT) fputs (uptr -> filename, sfile);
676 		fputc ('\n', sfile);
677 		if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) &&
678 		     (dptr -> examine != NULL) &&
679 		    ((high = uptr -> capac) != 0)) {	/* memory-like unit? */
680 			WRITE_I (high);			/* memory limit */
681 			zerocnt = 0;
682 			for (k = 0; k < high; k = k + (dptr -> aincr)) {
683 				reason = dptr -> examine (&val, k, uptr, 0);
684 				if (reason != SCPE_OK) return reason;
685 				if (val == 0) zerocnt = zerocnt - 1;
686 				else {	if (zerocnt) WRITE_I (zerocnt);
687 					zerocnt = 0;
688 					WRITE_I (val);  }  }
689 			if (zerocnt) WRITE_I (zerocnt);  }
690 		else {	k = 0;				/* no memory */
691 			WRITE_I (k);  }  }
692 	j = -1;
693 	WRITE_I (j);					/* end units */
694 	for (rptr = dptr -> registers;			/* loop thru regs */
695 		(rptr != NULL) && (rptr -> name != NULL); rptr++) {
696 		fputs (rptr -> name, sfile);		/* name */
697 		fputc ('\n', sfile);
698 		for (j = 0; j < rptr -> depth; j++) {	/* loop thru values */
699 			val = get_rval (rptr, j);	/* get value */
700 			WRITE_I (val);  }  }		/* store */
701 	fputc ('\n', sfile);  }				/* end registers */
702 fputc ('\n', sfile);					/* end devices */
703 reason = (ferror (sfile))? SCPE_IOERR: SCPE_OK;		/* error during save? */
704 fclose (sfile);
705 return reason;
706 }
707 
708 /* Restore command
709 
710    re[store] filename		restore state from specified file
711 */
712 
restore_cmd(int flag,char * cptr)713 t_stat restore_cmd (int flag, char *cptr)
714 {
715 char buf[CBUFSIZE];
716 FILE *rfile;
717 int32 j, data, unitno, time;
718 t_addr k, high;
719 t_value val, mask;
720 t_stat reason;
721 DEVICE *dptr;
722 UNIT *uptr;
723 REG *rptr;
724 
725 #define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \
726 	{ fclose (rfile); return SCPE_IOERR;  }
727 #define READ_I(xx) if (fxread (&xx, sizeof (xx), 1, rfile) <= 0) \
728 	{ fclose (rfile); return SCPE_IOERR;  }
729 
730 if (*cptr == 0) return SCPE_ARG;
731 if ((rfile = fopen (cptr, "rb")) == NULL) return SCPE_OPENERR;
732 READ_S (buf);						/* sim name */
733 if (strcmp (buf, sim_name)) {
734 	printf ("Wrong system type: %s\n", buf);
735 	fclose (rfile);
736 	return SCPE_OK;  }
737 READ_I (sim_time);					/* sim time */
738 
739 for ( ;; ) {						/* device loop */
740 	READ_S (buf);					/* read device name */
741 	if (buf[0] == 0) break;				/* last? */
742 	if ((dptr = find_device (buf, NULL)) == NULL) {
743 		printf ("Invalid device name: %s\n", buf);
744 		fclose (rfile);
745 		return SCPE_INCOMP;  }
746 	for ( ;; ) {					/* unit loop */
747 		READ_I (unitno);			/* unit number */
748 		if (unitno < 0) break;
749 		if (unitno >= dptr -> numunits) {
750 			printf ("Invalid unit number %s%d\n", dptr -> name,
751 				unitno);
752 			fclose (rfile);
753 			return SCPE_INCOMP;  }
754 		READ_I (time);				/* event time */
755 		uptr = (dptr -> units) + unitno;
756 		sim_cancel (uptr);
757 		if (time > 0) sim_activate (uptr, time - 1);
758 		READ_I (uptr -> u3);			/* device specific */
759 		READ_I (uptr -> u4);
760 		READ_S (buf);				/* attached file */
761 		if (buf[0] != 0) {
762 			uptr -> flags = uptr -> flags & ~UNIT_DIS;
763 			reason = attach_unit (uptr, buf);
764 			if (reason != SCPE_OK) return reason;  }
765 		READ_I (high);				/* memory capacity */
766 		if ((high > 0) &&			/* validate if > 0 */
767 		   (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) ||
768 		     (high > uptr -> capac) || (dptr -> deposit == NULL))) {
769 			printf ("Invalid memory bound: %u\n", high);
770 			fclose (rfile);
771 			return SCPE_INCOMP;  }
772 		for (k = 0; k < high; k = k + (dptr -> aincr)) {
773 			READ_I (data);
774 			if (data < 0) {
775 				for (j = data + 1; j < 0; j++) {
776 					reason = dptr -> deposit (0, k, uptr, 0);
777 					if (reason != SCPE_OK) return reason;
778 					k = k + (dptr -> aincr);  }
779 				data = 0;  }
780 			reason = dptr -> deposit (data, k, uptr, 0);
781 			if (reason != SCPE_OK) return reason;  }
782 		}					/* end unit loop */
783 	for ( ;; ) {					/* register loop */
784 		READ_S (buf);				/* read reg name */
785 		if (buf[0] == 0) break;			/* last? */
786 		if ((rptr = find_reg (buf, NULL, dptr)) == NULL) {
787 			printf ("Invalid register name: %s\n", buf);
788 			fclose (rfile);
789 			return SCPE_INCOMP;  }
790 		mask = (k1 << rptr -> width) - 1;
791 		for (j = 0; j < rptr -> depth; j++) {	/* loop thru values */
792 			READ_I (val);			/* read value */
793 			if (val > mask)
794 				printf ("Invalid register value: %s\n", buf);
795 			else put_rval (rptr, j, val, mask);  }  }
796 	}						/* end device loop */
797 fclose (rfile);
798 return SCPE_OK;
799 }
800 
801 /* Run, go, cont, step commands
802 
803    ru[n] [new PC]	reset and start simulation
804    go [new PC]		start simulation
805    co[nt]		start simulation
806    s[tep] [step limit]	start simulation for 'limit' instructions
807    b[oot] device	bootstrap from device and start simulation
808 */
809 
run_cmd(int flag,char * cptr)810 t_stat run_cmd (int flag, char *cptr)
811 {
812 char gbuf[CBUFSIZE];
813 int32 i, j, step, unitno;
814 t_stat r;
815 t_addr addr, k;
816 DEVICE *dptr;
817 UNIT *uptr;
818 void int_handler (int signal);
819 
820 step = 0;
821 if (((flag == RU_RUN) || (flag == RU_GO)) && (*cptr != 0)) {	/* run or go */
822 	cptr = get_glyph (cptr, gbuf, 0);		/* get PC, store */
823 	if ((r = dep_reg (0, 0, gbuf, sim_PC)) != SCPE_OK) return r;  }
824 
825 if (flag == RU_STEP) {					/* step */
826 	if (*cptr == 0) step = 1;
827 	else {	cptr = get_glyph (cptr, gbuf, 0);
828 		step = get_uint (gbuf, 10, INT_MAX, &r);
829 		if ((r != SCPE_OK) || (step == 0)) return SCPE_ARG;  }  }
830 
831 if (flag == RU_BOOT) {					/* boot */
832 	if (*cptr == 0) return SCPE_ARG;
833 	cptr = get_glyph (cptr, gbuf, 0);
834 	if ((dptr = find_device (gbuf, &unitno)) == NULL) return SCPE_ARG;
835 	if (dptr -> boot == NULL) return SCPE_ARG;
836 	uptr = dptr -> units + unitno;
837 	if (uptr -> flags & UNIT_DIS) return SCPE_ARG;	/* disabled? */
838 	if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT;
839 	if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT;
840 	if ((r = dptr -> boot (unitno)) != SCPE_OK) return r;  }
841 
842 if (*cptr != 0) return SCPE_ARG;
843 
844 if ((flag == RU_RUN) || (flag == RU_BOOT)) {		/* run or boot */
845 	sim_interval = 0;				/* reset queue */
846 	sim_time = 0;
847 	noqueue_time = 0;
848 	sim_clock_queue = NULL;
849 	if ((r = reset_all (0)) != SCPE_OK) return r;  }
850 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
851 	for (j = 0; j < dptr -> numunits; j++) {
852 		uptr = (dptr -> units) + j;
853 		if ((uptr -> flags & (UNIT_ATT + UNIT_SEQ)) ==
854 		    (UNIT_ATT + UNIT_SEQ))
855 			fseek (uptr -> fileref, uptr -> pos, SEEK_SET);  }  }
856 stop_cpu = 0;
857 if ((int) signal (SIGINT, int_handler) == -1) {		/* set WRU */
858 	printf ("Simulator interrupt handler setup failed\n");
859 	return SCPE_OK;  }
860 if (ttrunstate () != SCPE_OK) {				/* set console */
861 	ttcmdstate ();
862 	printf ("Simulator terminal setup failed\n");
863 	return SCPE_OK;  }
864 if (step) sim_activate (&step_unit, step);		/* set step timer */
865 r = sim_instr();
866 
867 ttcmdstate ();						/* restore console */
868 signal (SIGINT, SIG_DFL);				/* cancel WRU */
869 sim_cancel (&step_unit);				/* cancel step timer */
870 if (sim_clock_queue != NULL) {				/* update sim time */
871 	UPDATE_SIM_TIME (sim_clock_queue -> time);  }
872 else {	UPDATE_SIM_TIME (noqueue_time);  }
873 #ifdef VMS
874 printf ("\n");
875 #endif
876 if (r >= SCPE_BASE) printf ("\n%s, %s: ", scp_error_messages[r - SCPE_BASE],
877 	sim_PC -> name);
878 else printf ("\n%s, %s: ", sim_stop_messages[r], sim_PC -> name);
879 print_val (addr = get_rval (sim_PC, 0), sim_PC -> radix,
880 	sim_PC -> width, sim_PC -> flags & REG_FMT);
881 if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) {
882 	for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;
883 	for (i = 0, k = addr; i < sim_emax; i++, k = k + dptr -> aincr) {
884 		if ((r = dptr -> examine (&sim_eval[i], k, dptr -> units,
885 			 SWMASK ('V'))) != SCPE_OK) break;  }
886 	if ((r == SCPE_OK) || (i > 0)) {
887 		printf (" (");
888 		if (print_sym (addr, sim_eval, NULL, SWMASK('M')) > 0)
889 			print_val (sim_eval[0], dptr -> dradix,
890 				dptr -> dwidth, PV_RZRO);
891 		printf (")");  }  }
892 printf ("\n");
893 return SCPE_OK;
894 }
895 
896 /* Run time routines */
897 
898 /* Unit service for step timeout, originally scheduled by STEP n command
899 
900    Return step timeout SCP code, will cause simulation to stop
901 */
902 
step_svc(UNIT * uptr)903 t_stat step_svc (UNIT *uptr)
904 {
905 return SCPE_STEP;
906 }
907 
908 /* Signal handler for ^C signal
909 
910    Set stop simulation flag
911 */
912 
int_handler(int sig)913 void int_handler (int sig)
914 {
915 stop_cpu = 1;
916 return;
917 }
918 
919 /* Examine/deposit commands
920 
921    ex[amine] [unit] list		examine
922    de[posit] [unit] list val		deposit
923    ie[xamine] [unit] list		interactive examine
924    id[eposit] [unit] list		interactive deposit
925 
926    list					list of addresses and registers
927 	addr[:addr|-addr]		address range
928 	ALL				all addresses
929 	register[:register|-register]	register range
930 	STATE				all registers
931 */
932 
exdep_cmd(int flag,char * cptr)933 t_stat exdep_cmd (int flag, char *cptr)
934 {
935 char gbuf[CBUFSIZE], *gptr, *tptr;
936 int32 unitno, sw;
937 t_addr low, high;
938 t_stat reason;
939 DEVICE *dptr;
940 UNIT *uptr;
941 REG *lowr, *highr;
942 t_stat exdep_addr_loop (int flag, int32 sw, char *ptr, t_addr low,
943 	t_addr high, DEVICE *dptr, UNIT *uptr);
944 t_stat exdep_reg_loop (int flag, int32 sw, char *ptr, REG *lptr, REG *hptr);
945 
946 if (*cptr == 0) return SCPE_ARG;			/* err if no args */
947 cptr = get_glyph (cptr, gbuf, 0);
948 if ((sw = get_switches (gbuf)) != 0) {			/* try for switches */
949 	if ((sw < 0) || (*cptr == 0)) return SCPE_ARG;	/* err if no args */
950 	cptr = get_glyph (cptr, gbuf, 0);  }		/* if found, advance */
951 if ((dptr = find_device (gbuf, &unitno)) != NULL) {	/* try for unit */
952 	if (*cptr == 0) return SCPE_ARG;		/* err if no args */
953 	cptr = get_glyph (cptr, gbuf, 0);  }		/* if found, advance */
954 else {	dptr = sim_devices[0];				/* CPU is default */
955 	unitno = 0;  }
956 if ((*cptr == 0) == (flag == 0)) return SCPE_ARG;	/* eol if needed? */
957 
958 gptr = gbuf;
959 uptr = (dptr -> units) + unitno;
960 while (*gptr != 0) {
961 	errno = 0;
962 	low = strtoul (gptr, &tptr, dptr -> aradix);
963 	if ((errno == 0) && (gptr != tptr)) {
964 		high = low;
965 		if ((*tptr == '-') || (*tptr == ':')) {
966 			gptr = tptr + 1;
967 			errno = 0;
968 			high = strtoul (gptr, &tptr, dptr -> aradix);
969 			if (errno || (gptr == tptr)) return SCPE_ARG;  }
970 		if (*tptr == ',') tptr++;
971 		else if (*tptr != 0) return SCPE_ARG;
972 		reason = exdep_addr_loop (flag, sw, cptr, low, high,
973 			dptr, uptr);
974 		if (reason != SCPE_OK) return reason; }
975 
976 	else if (strncmp (gptr, "ALL", strlen ("ALL")) == 0) {
977 		tptr = gptr + strlen ("ALL");
978 		if (*tptr == ',') tptr++;
979 		else if (*tptr != 0) return SCPE_ARG;
980 		if ((uptr -> capac == 0) | (flag == EX_E)) return SCPE_ARG;
981 		high = (uptr -> capac) - (dptr -> aincr);
982 		reason = exdep_addr_loop (flag, sw, cptr, 0, high, dptr, uptr);
983 		if (reason != SCPE_OK) return reason; }
984 
985 	else if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
986 		tptr = gptr + strlen ("STATE");
987 		if (*tptr == ',') tptr++;
988 		else if (*tptr != 0) return SCPE_ARG;
989 		if ((lowr = dptr -> registers) == NULL) return SCPE_ARG;
990 		for (highr = lowr; highr -> name != NULL; highr++) ;
991 		reason = exdep_reg_loop (flag, sw+SWHIDE, cptr, lowr, --highr);
992 		if (reason != SCPE_OK) return reason; }
993 
994 	else {	lowr = find_reg (gptr, &tptr, dptr);
995 		if (lowr == NULL) return SCPE_ARG;
996 		highr = lowr;
997 		if ((*tptr == '-') || (*tptr == ':')) {
998 			highr = find_reg (tptr + 1, &tptr, dptr);
999 			if (highr == NULL) return SCPE_ARG;  }
1000 		if (*tptr == ',') tptr++;
1001 		else if (*tptr != 0) return SCPE_ARG;
1002 		reason = exdep_reg_loop (flag, sw, cptr, lowr, highr);
1003 		if (reason != SCPE_OK) return reason; }
1004 
1005 	gptr = tptr;  }					/* end while */
1006 return SCPE_OK;
1007 }
1008 
1009 /* Loop controllers for examine/deposit
1010 
1011    exdep_reg_loop	examine/deposit range of registers
1012    exdep_addr_loop	examine/deposit range of addresses
1013 */
1014 
exdep_reg_loop(int flag,int32 sw,char * cptr,REG * lowr,REG * highr)1015 t_stat exdep_reg_loop (int flag, int32 sw, char *cptr, REG *lowr, REG *highr)
1016 {
1017 t_stat reason;
1018 REG *rptr;
1019 
1020 if ((lowr == NULL) || (highr == NULL)) return SCPE_ARG;
1021 if (lowr > highr) return SCPE_ARG;
1022 for (rptr = lowr; rptr <= highr; rptr++) {
1023 	if ((sw & SWHIDE) && (rptr -> flags & REG_HIDDEN)) continue;
1024 	if (flag != EX_D) {
1025 		reason = ex_reg (flag, sw, rptr);
1026 		if (reason != SCPE_OK) return reason; }
1027 	if (flag != EX_E) {
1028 		reason = dep_reg (flag, sw, cptr, rptr);
1029 		if (reason != SCPE_OK) return reason;  }  }
1030 return SCPE_OK;
1031 }
1032 
exdep_addr_loop(int flag,int32 sw,char * cptr,t_addr low,t_addr high,DEVICE * dptr,UNIT * uptr)1033 t_stat exdep_addr_loop (int flag, int32 sw, char *cptr, t_addr low,
1034 	t_addr high, DEVICE *dptr, UNIT *uptr)
1035 {
1036 int32 i;
1037 t_addr mask;
1038 t_stat reason;
1039 
1040 if (uptr -> flags & UNIT_DIS) return SCPE_ARG;		/* disabled? */
1041 reason = 0;
1042 mask = (1u << dptr -> awidth) - 1;
1043 if ((low < 0) || (low > mask) || (high < 0) || (high > mask) ||
1044     (low > high)) return SCPE_ARG;
1045 for (i = low; i <= high; i = i + (dptr -> aincr)) {
1046 	if (flag != EX_D) {
1047 		reason = ex_addr (flag, sw, i, dptr, uptr);
1048 		if (reason > SCPE_OK) return reason;  }
1049 	if (flag != EX_E) {
1050 		reason = dep_addr (flag, sw, cptr, i, dptr, uptr, reason);
1051 		if (reason > SCPE_OK) return reason;  }
1052 	if (reason < SCPE_OK) i = i - (reason * dptr -> aincr);  }
1053 return SCPE_OK;
1054 }
1055 
1056 /* Examine register routine
1057 
1058    Inputs:
1059 	flag	=	type of ex/mod command (ex, iex, idep)
1060 	sw	=	switches
1061 	rptr	=	pointer to register descriptor
1062    Outputs:
1063 	return	=	error status
1064 */
1065 
ex_reg(int flag,int32 sw,REG * rptr)1066 t_stat ex_reg (int flag, int32 sw, REG *rptr)
1067 {
1068 t_value val;
1069 
1070 if (rptr == NULL) return SCPE_ARG;
1071 printf ("%s:	", rptr -> name);
1072 if (!(flag & EX_E)) return SCPE_OK;
1073 val = get_rval (rptr, 0);
1074 print_val (val, rptr -> radix, rptr -> width, rptr -> flags & REG_FMT);
1075 if (flag & EX_I) printf ("	");
1076 else printf ("\n");
1077 return SCPE_OK;
1078 }
1079 
1080 /* Get register value
1081 
1082    Inputs:
1083 	rptr	=	pointer to register descriptor
1084 	idx	=	index (SAVE register buffers only)
1085    Outputs:
1086 	return	=	register value
1087 */
1088 
get_rval(REG * rptr,int idx)1089 t_value get_rval (REG *rptr, int idx)
1090 {
1091 size_t sz;
1092 t_value val;
1093 
1094 sz = SZ_R (rptr);
1095 if ((rptr -> depth > 1) && (sz == sizeof (int8)))
1096 	val = *(((unsigned int8 *) rptr -> loc) + idx);
1097 else if ((rptr -> depth > 1) && (sz == sizeof (int16)))
1098 	val = *(((unsigned int16 *) rptr -> loc) + idx);
1099 #if !defined (int64)
1100 else val = *(((unsigned int32 *) rptr -> loc) + idx);
1101 #else
1102 else if (sz <= sizeof (int32))
1103 	 val = *(((unsigned int32 *) rptr -> loc) + idx);
1104 else val = *(((unsigned int64 *) rptr -> loc) + idx);
1105 #endif
1106 val = (val >> rptr -> offset) & ((k1 << rptr -> width) - 1);
1107 return val;
1108 }
1109 
1110 /* Deposit register routine
1111 
1112    Inputs:
1113 	flag	=	type of deposit (normal/interactive)
1114 	sw	=	switches
1115 	cptr	=	pointer to input string
1116 	rptr	=	pointer to register descriptor
1117    Outputs:
1118 	return	=	error status
1119 */
1120 
dep_reg(int flag,int32 sw,char * cptr,REG * rptr)1121 t_stat dep_reg (int flag, int32 sw, char *cptr, REG *rptr)
1122 {
1123 t_stat r;
1124 t_value val, mask;
1125 char gbuf[CBUFSIZE];
1126 
1127 if ((cptr == NULL) || (rptr == NULL)) return SCPE_ARG;
1128 if (rptr -> flags & REG_RO) return SCPE_RO;
1129 if (flag & EX_I) {
1130 	cptr = read_line (gbuf, CBUFSIZE, stdin);
1131 	if (cptr == NULL) return 1;			/* force exit */
1132 	if (*cptr == 0) return SCPE_OK;	 }		/* success */
1133 errno = 0;
1134 mask = (k1 << rptr -> width) - 1;
1135 val = get_uint (cptr, rptr -> radix, mask, &r);
1136 if (r != SCPE_OK) return SCPE_ARG;
1137 if ((rptr -> flags & REG_NZ) && (val == 0)) return SCPE_ARG;
1138 put_rval (rptr, 0, val, mask);
1139 return SCPE_OK;
1140 }
1141 
1142 /* Put register value
1143 
1144    Inputs:
1145 	rptr	=	pointer to register descriptor
1146 	idx	=	index (RESTORE reg buffers only)
1147 	val	=	new value
1148 	mask	=	mask
1149    Outputs:
1150 	none
1151 */
1152 
put_rval(REG * rptr,int idx,t_value val,t_value mask)1153 void put_rval (REG *rptr, int idx, t_value val, t_value mask)
1154 {
1155 size_t sz;
1156 
1157 #define PUT_RVAL(sz,rp,id,val,msk) \
1158 	*(((unsigned sz *) rp -> loc) + id) = \
1159 		(*(((unsigned sz *) rp -> loc) + id) & \
1160 		~((msk) << (rp) -> offset)) | ((val) << (rp) -> offset)
1161 
1162 sz = SZ_R (rptr);
1163 if ((rptr -> depth > 1) && (sz == sizeof (int8)))
1164 	PUT_RVAL (int8, rptr, idx, val, mask);
1165 else if ((rptr -> depth > 1) && (sz == sizeof (int16)))
1166 	PUT_RVAL (int16, rptr, idx, val, mask);
1167 #if !defined (int64)
1168 else PUT_RVAL (int32, rptr, idx, val, mask);
1169 #else
1170 if (sz <= sizeof (int32)) PUT_RVAL (int32, rptr, idx, val, mask);
1171 else PUT_RVAL (int64, rptr, idx, val, mask);
1172 #endif
1173 return;
1174 }
1175 
1176 /* Examine address routine
1177 
1178    Inputs:
1179 	flag	=	type of ex/mod command (ex, iex, idep)
1180 	sw	=	switches
1181 	addr	=	address to examine
1182 	dptr	=	pointer to device
1183 	uptr	=	pointer to unit
1184    Outputs:
1185 	return	=	if >= 0, error status
1186 			if < 0, number of extra words retired
1187 */
1188 
ex_addr(int flag,int32 sw,t_addr addr,DEVICE * dptr,UNIT * uptr)1189 t_stat ex_addr (int flag, int32 sw, t_addr addr, DEVICE *dptr, UNIT *uptr)
1190 {
1191 int32 i;
1192 t_value mask;
1193 t_addr j, loc;
1194 t_stat reason;
1195 size_t sz;
1196 
1197 if (dptr == NULL) return SCPE_ARG;
1198 print_val (addr, dptr -> aradix, dptr -> awidth, PV_LEFT);
1199 printf (":	");
1200 if (!(flag & EX_E)) return SCPE_OK;
1201 
1202 mask = (k1 << dptr -> dwidth) - 1;
1203 for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;
1204 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr -> aincr) {
1205 	if (dptr -> examine != NULL) {
1206 		reason = dptr -> examine (&sim_eval[i], j, uptr, sw);
1207 		if (reason != SCPE_OK) break;  }
1208 	else {	if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT;
1209 		if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) {
1210 			reason = SCPE_NXM;
1211 			break;  }
1212 		sz = SZ_D (dptr);
1213 		loc = j / dptr -> aincr;
1214 		if (uptr -> flags & UNIT_BUF) {
1215 			if (sz == sizeof (int8)) sim_eval[i] =
1216 				*(((unsigned int8 *) uptr -> filebuf) + loc);
1217 			else if (sz == sizeof (int16)) sim_eval[i] =
1218 				*(((unsigned int16 *) uptr -> filebuf) + loc);
1219 #if !defined (int64)
1220 		    	else sim_eval[i] =
1221 				*(((unsigned int32 *) uptr -> filebuf) + loc);
1222 #else
1223 		    	else if (sz == sizeof (int32)) sim_eval[i] =
1224 				*(((unsigned int32 *) uptr -> filebuf) + loc);
1225 			else sim_eval[i] =
1226 				*(((unsigned int64 *) uptr -> filebuf) + loc);
1227 #endif
1228 		}
1229 		else {	fseek (uptr -> fileref, sz * loc, SEEK_SET);
1230 			fxread (&sim_eval[i], sz, 1, uptr -> fileref);
1231 			if ((feof (uptr -> fileref)) &&
1232 			   !(uptr -> flags & UNIT_FIX)) {
1233 				reason = SCPE_EOF;
1234 				break;  }
1235 		 	else if (ferror (uptr -> fileref)) {
1236 				clearerr (uptr -> fileref);
1237 				reason = SCPE_IOERR;
1238 				break;  }  }  }
1239 	sim_eval[i] = sim_eval[i] & mask;  }
1240 if ((reason != SCPE_OK) && (i == 0)) return reason;
1241 
1242 if ((reason = print_sym (addr, sim_eval, uptr, sw)) > 0)
1243     reason = print_val (sim_eval[0], dptr -> dradix, dptr -> dwidth, PV_RZRO);
1244 if (flag & EX_I) printf ("	");
1245 else printf ("\n");
1246 return reason;
1247 }
1248 
1249 /* Deposit address routine
1250 
1251    Inputs:
1252 	flag	=	type of deposit (normal/interactive)
1253 	sw	=	switches
1254 	cptr	=	pointer to input string
1255 	addr	=	address to examine
1256 	dptr	=	pointer to device
1257 	uptr	=	pointer to unit
1258 	dfltinc	=	value to return on cr input
1259    Outputs:
1260 	return	=	if >= 0, error status
1261 			if < 0, number of extra words retired
1262 */
1263 
dep_addr(int flag,int32 sw,char * cptr,t_addr addr,DEVICE * dptr,UNIT * uptr,int dfltinc)1264 t_stat dep_addr (int flag, int32 sw, char *cptr, t_addr addr, DEVICE *dptr,
1265 	UNIT *uptr, int dfltinc)
1266 {
1267 int32 i, count;
1268 t_addr j, loc;
1269 t_stat r, reason;
1270 t_value mask;
1271 size_t sz;
1272 char gbuf[CBUFSIZE];
1273 
1274 if (dptr == NULL) return SCPE_ARG;
1275 if (flag & EX_I) {
1276 	cptr = read_line (gbuf, CBUFSIZE, stdin);
1277 	if (cptr == NULL) return 1;			/* force exit */
1278 	if (*cptr == 0) return dfltinc;	 }		/* success */
1279 mask = (k1 << dptr -> dwidth) - 1;
1280 
1281 if ((reason = parse_sym (cptr, addr, uptr, sim_eval, sw)) > 0) {
1282 	sim_eval[0] = get_uint (cptr, dptr -> dradix, mask, &reason);
1283 	if (reason != SCPE_OK) return reason;  }
1284 count = 1 - reason;
1285 
1286 for (i = 0, j = addr; i < count; i++, j = j + dptr -> aincr) {
1287 	sim_eval[i] = sim_eval[i] & mask;
1288 	if (dptr -> deposit != NULL) {
1289 		r = dptr -> deposit (sim_eval[i], j, uptr, sw);
1290 		if (r != SCPE_OK) return r;  }
1291 	else {	if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT;
1292 		if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac))
1293 			return SCPE_NXM;
1294 		sz = SZ_D (dptr);
1295 		loc = j / dptr -> aincr;
1296 		if (uptr -> flags & UNIT_BUF) {
1297 			if (sz == sizeof (int8)) *(((unsigned int8 *)
1298 				uptr -> filebuf) + loc) = sim_eval[i];
1299 			else if (sz == sizeof (int16)) *(((unsigned int16 *)
1300 				uptr -> filebuf) + loc) = sim_eval[i];
1301 #if !defined (int64)
1302 			else *(((unsigned int32 *) uptr -> filebuf) + loc) =
1303 				sim_eval[i];
1304 #else
1305 			else if (sz == sizeof (int32)) *(((unsigned int32 *)
1306 				uptr -> filebuf) + loc) = sim_eval[i];
1307 			else *(((unsigned int64 *) uptr -> filebuf) + loc) =
1308 				sim_eval[i];
1309 #endif
1310 			if (loc >= uptr -> hwmark) uptr -> hwmark = loc + 1;  }
1311 		else {	fseek (uptr -> fileref, sz * loc, SEEK_SET);
1312 			fxwrite (sim_eval, sz, 1, uptr -> fileref);
1313 			if (ferror (uptr -> fileref)) {
1314 				clearerr (uptr -> fileref);
1315 				return SCPE_IOERR;  }  }  }  }
1316 return reason;
1317 }
1318 
1319 /* String processing routines
1320 
1321    read_line		read line
1322 
1323    Inputs:
1324 	cptr	=	pointer to buffer
1325 	size	=	maximum size
1326 	stream	=	pointer to input stream
1327    Outputs:
1328 	optr	=	pointer to first non-blank character
1329 			NULL if EOF
1330 */
1331 
read_line(char * cptr,int size,FILE * stream)1332 char *read_line (char *cptr, int size, FILE *stream)
1333 {
1334 int len;
1335 
1336 cptr = fgets (cptr, size, stream);			/* get cmd line */
1337 if (cptr == NULL) return NULL;				/* ignore EOF */
1338 len = strlen(cptr);
1339 if (cptr[len-1]=='\n') cptr[len-1]='\0';		/* remove cr */
1340 while (isspace (*cptr)) cptr++;				/* absorb spaces */
1341 return cptr;
1342 }
1343 
1344 /* get_glyph		get next glyph
1345 
1346    Inputs:
1347 	iptr	=	pointer to input string
1348 	optr	=	pointer to output string
1349 	mchar	=	optional end of glyph character
1350    Outputs
1351 	result	=	pointer to next character in input string
1352 */
1353 
get_glyph(char * iptr,char * optr,char mchar)1354 char *get_glyph (char *iptr, char *optr, char mchar)
1355 {
1356 while ((isspace (*iptr) == 0) && (*iptr != 0) && (*iptr != mchar)) {
1357 	if (islower (*iptr)) *optr = toupper (*iptr);
1358 	else *optr = *iptr;
1359 	iptr++; optr++;  }
1360 *optr = 0;
1361 if (mchar && (*iptr == mchar)) iptr++;			/* skip terminator */
1362 while (isspace (*iptr)) iptr++;				/* absorb spaces */
1363 return iptr;
1364 }
1365 
1366 /* get_yn		yes/no question
1367 
1368    Inputs:
1369 	cptr	=	pointer to question
1370 	deflt	=	default answer
1371    Outputs:
1372 	result	=	true if yes, false if no
1373 */
1374 
get_yn(char * ques,t_stat deflt)1375 t_stat get_yn (char *ques, t_stat deflt)
1376 {
1377 char cbuf[CBUFSIZE], *cptr;
1378 
1379 printf ("%s ", ques);
1380 cptr = read_line (cbuf, CBUFSIZE, stdin);
1381 if ((cptr == NULL) || (*cptr == 0)) return deflt;
1382 if ((*cptr == 'Y') || (*cptr == 'y')) return TRUE;
1383 return FALSE;
1384 }
1385 
1386 /* get_uint		unsigned number
1387 
1388    Inputs:
1389 	cptr	=	pointer to input string
1390 	radix	=	input radix
1391 	max	=	maximum acceptable value
1392 	*status	=	pointer to error status
1393    Outputs:
1394 	val	=	value
1395 */
1396 
get_uint(char * cptr,int radix,t_value max,t_stat * status)1397 t_value get_uint (char *cptr, int radix, t_value max, t_stat *status)
1398 {
1399 t_value val;
1400 char *tptr;
1401 
1402 errno = 0;
1403 val = strtoul (cptr, &tptr, radix);
1404 if (errno || (cptr == tptr) || (val > max) || (*tptr != 0)) *status = SCPE_ARG;
1405 else *status = SCPE_OK;
1406 return val;
1407 }
1408 
1409 /* Find_device		find device matching input string
1410 
1411    Inputs:
1412 	cptr	=	pointer to input string
1413 	iptr	=	pointer to unit number (can be null)
1414    Outputs:
1415 	result	=	pointer to device
1416 	*iptr	=	unit number, if valid
1417 */
1418 
find_device(char * cptr,int32 * iptr)1419 DEVICE *find_device (char *cptr, int32 *iptr)
1420 {
1421 int32 i, lenn, unitno;
1422 t_stat r;
1423 DEVICE *dptr;
1424 
1425 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
1426 	lenn = strlen (dptr -> name);
1427 	if (strncmp (cptr, dptr -> name, lenn) != 0) continue;
1428 	cptr = cptr + lenn;
1429 	if (*cptr == 0) unitno = 0;
1430 	else {	unitno = get_uint (cptr, 10, dptr -> numunits - 1, &r);
1431 		if (r != SCPE_OK) return NULL;  }
1432 	if (iptr != NULL) *iptr = unitno;
1433 	return sim_devices[i];  }
1434 return NULL;
1435 }
1436 
1437 /* Find_dev_from_unit	find device for unit
1438 
1439    Inputs:
1440 	uptr	=	pointer to unit
1441    Outputs:
1442 	result	=	pointer to device
1443 */
1444 
find_dev_from_unit(UNIT * uptr)1445 DEVICE *find_dev_from_unit (UNIT *uptr)
1446 {
1447 DEVICE *dptr;
1448 int32 i, j;
1449 
1450 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
1451 	for (j = 0; j < dptr -> numunits; j++) {
1452 		if (uptr == (dptr -> units + j)) return dptr;  }  }
1453 return NULL;
1454 }
1455 
1456 /* find_reg		find register matching input string
1457 
1458    Inputs:
1459 	cptr	=	pointer to input string
1460 	optr	=	pointer to output pointer (can be null)
1461 	dptr	=	pointer to device
1462    Outputs:
1463 	result	=	pointer to register, NULL if error
1464 	*optr	=	pointer to next character in input string
1465 */
1466 
find_reg(char * cptr,char ** optr,DEVICE * dptr)1467 REG *find_reg (char *cptr, char **optr, DEVICE *dptr)
1468 {
1469 char *tptr;
1470 REG *rptr;
1471 
1472 if ((cptr == NULL) || (dptr == NULL)) return NULL;
1473 if (dptr -> registers == NULL) return NULL;
1474 tptr = cptr;
1475 do { tptr++; } while (isalnum (*tptr) || (*tptr == '_'));
1476 for (rptr = dptr -> registers; rptr -> name != NULL; rptr++) {
1477 	if (strncmp (cptr, rptr -> name, tptr - cptr) == 0) {
1478 		if (optr != NULL) *optr = tptr;
1479 		return rptr;  }  }
1480 return NULL;
1481 }
1482 
1483 /* get_switches		get switches from input string
1484 
1485    Inputs:
1486 	cptr	=	pointer to input string
1487    Outputs:
1488 	sw	=	switch bit mask
1489 			0 if no switches, -1 if error
1490 */
1491 
get_switches(char * cptr)1492 int32 get_switches (char *cptr)
1493 {
1494 int32 sw;
1495 
1496 if (*cptr != '-') return 0;
1497 sw = 0;
1498 for (cptr++; (isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
1499 	if (isalpha (*cptr) == 0) return -1;
1500 	sw = sw | SWMASK (*cptr);  }
1501 return sw;
1502 }
1503 
1504 /* General radix printing routine
1505 
1506    Inputs:
1507 	stream	=	stream designator
1508 	val	=	value to print
1509 	radix	=	radix to print
1510 	width	=	width to print
1511 	format	=	leading zeroes format
1512    Outputs:
1513 	status	=	error status
1514 */
1515 
fprint_val(FILE * stream,t_value val,int radix,int width,int format)1516 t_stat fprint_val (FILE *stream, t_value val, int radix,
1517 	int width, int format)
1518 {
1519 #define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value)))
1520 t_value mask, digit;
1521 int32 d, ndigits;
1522 double fptest;
1523 char dbuf[MAX_WIDTH + 1];
1524 
1525 for (d = 0; d < MAX_WIDTH; d++) dbuf[d] = (format == PV_RZRO)? '0': ' ';
1526 dbuf[MAX_WIDTH] = 0;
1527 d = MAX_WIDTH;
1528 do {	d = d - 1;
1529 	digit = val % (unsigned) radix;
1530 	val = val / (unsigned) radix;
1531 	dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10);
1532    } while ((d > 0) && (val != 0));
1533 
1534 if (format != PV_LEFT) {
1535 	mask = (k1 << width) - 1;
1536 	fptest = (double) radix;
1537 	ndigits = 1;
1538 	while (fptest < (double) mask) {
1539 		fptest = fptest * (double) radix;
1540 		ndigits = ndigits + 1; }
1541 	if ((MAX_WIDTH - ndigits) < d) d = MAX_WIDTH - ndigits;  }
1542 if (fputs (&dbuf[d], stream) == EOF) return SCPE_IOERR;
1543 return SCPE_OK;
1544 }
1545 
1546 /* Event queue routines
1547 
1548 	sim_activate		add entry to event queue
1549 	sim_cancel		remove entry from event queue
1550 	sim_process_event	process entries on event queue
1551 	sim_is_active		see if entry is on event queue
1552 	sim_atime		return absolute time for an entry
1553 	sim_gtime		return global time
1554 
1555    Asynchronous events are set up by queueing a unit data structure
1556    to the event queue with a timeout (in simulator units, relative
1557    to the current time).  Each simulator 'times' these events by
1558    counting down interval counter sim_interval.  When this reaches
1559    zero the simulator calls sim_process_event to process the event
1560    and to see if further events need to be processed, or sim_interval
1561    reset to count the next one.
1562 
1563    The event queue is maintained in clock order; entry timeouts are
1564    RELATIVE to the time in the previous entry.
1565 
1566    Sim_process_event - process event
1567 
1568    Inputs:
1569 	none
1570    Outputs:
1571 	reason		reason code returned by any event processor,
1572 			or 0 (SCPE_OK) if no exceptions
1573 */
1574 
sim_process_event(void)1575 t_stat sim_process_event (void)
1576 {
1577 UNIT *uptr;
1578 t_stat reason;
1579 
1580 if (stop_cpu) return SCPE_STOP;				/* stop CPU? */
1581 if (sim_clock_queue == NULL) {				/* queue empty? */
1582 	UPDATE_SIM_TIME (noqueue_time);			/* update sim time */
1583 	sim_interval = noqueue_time = NOQUEUE_WAIT;	/* flag queue empty */
1584 	return SCPE_OK;  }
1585 UPDATE_SIM_TIME (sim_clock_queue -> time);		/* update sim time */
1586 do {	uptr = sim_clock_queue;				/* get first */
1587 	sim_clock_queue = uptr -> next;			/* remove first */
1588 	uptr -> next = NULL;				/* hygiene */
1589 	uptr -> time = 0;
1590 	if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time;
1591 	else sim_interval = noqueue_time = NOQUEUE_WAIT;
1592 	if (uptr -> action != NULL) reason = uptr -> action (uptr);
1593 	else reason = SCPE_OK;
1594    } while ((reason == SCPE_OK) && (sim_interval == 0));
1595 
1596 /* Empty queue forces sim_interval != 0 */
1597 
1598 return reason;
1599 }
1600 
1601 /* Activate (queue) event
1602 
1603    Inputs:
1604 	uptr	=	pointer to unit
1605 	event_time =	relative timeout
1606    Outputs:
1607 	reason	=	result (SCPE_OK if ok)
1608 */
1609 
sim_activate(UNIT * uptr,int32 event_time)1610 t_stat sim_activate (UNIT *uptr, int32 event_time)
1611 {
1612 UNIT *cptr, *prvptr;
1613 int32 accum;
1614 
1615 if (event_time < 0) return SCPE_ARG;
1616 if (sim_is_active (uptr)) return SCPE_OK;		/* already active? */
1617 if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time);  }
1618 else  {	UPDATE_SIM_TIME (sim_clock_queue -> time);  }	/* update sim time */
1619 
1620 prvptr = NULL;
1621 accum = 0;
1622 for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) {
1623 	if (event_time < accum + cptr -> time) break;
1624 	accum = accum + cptr -> time;
1625 	prvptr = cptr;  }
1626 if (prvptr == NULL) {					/* insert at head */
1627 	cptr = uptr -> next = sim_clock_queue;
1628 	sim_clock_queue = uptr;  }
1629 else {	cptr = uptr -> next = prvptr -> next;		/* insert at prvptr */
1630 	prvptr -> next = uptr;  }
1631 uptr -> time = event_time - accum;
1632 if (cptr != NULL) cptr -> time = cptr -> time - uptr -> time;
1633 sim_interval = sim_clock_queue -> time;
1634 return SCPE_OK;
1635 }
1636 
1637 /* Cancel (dequeue) event
1638 
1639    Inputs:
1640 	uptr	=	pointer to unit
1641    Outputs:
1642 	reason	=	result (SCPE_OK if ok)
1643 
1644 */
1645 
sim_cancel(UNIT * uptr)1646 t_stat sim_cancel (UNIT *uptr)
1647 {
1648 UNIT *cptr, *nptr;
1649 
1650 if (sim_clock_queue == NULL) return SCPE_OK;
1651 UPDATE_SIM_TIME (sim_clock_queue -> time);		/* update sim time */
1652 nptr = NULL;
1653 if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr -> next;
1654 else {	for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) {
1655 		if (cptr -> next == uptr) {
1656 			nptr = cptr -> next = uptr -> next;
1657 			break;  }  }  }			/* end queue scan */
1658 if (nptr != NULL) nptr -> time = nptr -> time + uptr -> time;
1659 uptr -> next = NULL;					/* hygiene */
1660 uptr -> time = 0;
1661 if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time;
1662 else sim_interval = noqueue_time = NOQUEUE_WAIT;
1663 return SCPE_OK;
1664 }
1665 
1666 /* Test for entry in queue, return activation time
1667 
1668    Inputs:
1669 	uptr	=	pointer to unit
1670    Outputs:
1671 	result =	absolute activation time + 1, 0 if inactive
1672 */
1673 
sim_is_active(UNIT * uptr)1674 int32 sim_is_active (UNIT *uptr)
1675 {
1676 UNIT *cptr;
1677 int32 accum;
1678 
1679 accum = 0;
1680 for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) {
1681 	accum = accum + cptr -> time;
1682 	if (cptr == uptr) return accum + 1;  }
1683 return 0;
1684 }
1685 
1686 /* Return global time
1687 
1688    Inputs: none
1689    Outputs:
1690 	time	=	global time
1691 */
1692 
sim_gtime(void)1693 double sim_gtime (void)
1694 {
1695 if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time);  }
1696 else  {	UPDATE_SIM_TIME (sim_clock_queue -> time);  }
1697 return sim_time;
1698 }
1699 
1700 /* Endian independent binary I/O package
1701 
1702    For consistency, all binary data read and written by the simulator
1703    is stored in little endian data order.  That is, in a multi-byte
1704    data item, the bytes are written out right to left, low order byte
1705    to high order byte.  On a big endian host, data is read and written
1706    from high byte to low byte.  Consequently, data written on a little
1707    endian system must be byte reversed to be usable on a big endian
1708    system, and vice versa.
1709 
1710    These routines are analogs of the standard C runtime routines
1711    fread and fwrite.  If the host is little endian, or the data items
1712    are size char, then the calls are passed directly to fread or
1713    fwrite.  Otherwise, these routines perform the necessary byte swaps
1714    using an intermediate buffer.
1715 */
1716 
fxread(void * bptr,size_t size,size_t count,FILE * fptr)1717 size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr)
1718 {
1719 size_t c, j, nelem, nbuf, lcnt, total;
1720 int32 i, k;
1721 unsigned char *sptr, *dptr;
1722 
1723 if (sim_end || (size == sizeof (char)))
1724 	return fread (bptr, size, count, fptr);
1725 if ((size == 0) || (count == 0)) return 0;
1726 nelem = FLIP_SIZE / size;				/* elements in buffer */
1727 nbuf = count / nelem;					/* number buffers */
1728 lcnt = count % nelem;					/* count in last buf */
1729 if (lcnt) nbuf = nbuf + 1;
1730 else lcnt = nelem;
1731 total = 0;
1732 for (i = nbuf; i > 0; i--) {
1733 	c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr);
1734 	if (c == 0) return total;
1735 	total = total + c;
1736 	for (j = 0, sptr = sim_flip, dptr = bptr; j < c; j++) {
1737 		for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++;
1738 		dptr = dptr + size;  }  }
1739 return total;
1740 }
1741 
fxwrite(void * bptr,size_t size,size_t count,FILE * fptr)1742 size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr)
1743 {
1744 size_t c, j, nelem, nbuf, lcnt, total;
1745 int32 i, k;
1746 unsigned char *sptr, *dptr;
1747 
1748 if (sim_end || (size == sizeof (char)))
1749 	return fwrite (bptr, size, count, fptr);
1750 if ((size == 0) || (count == 0)) return 0;
1751 nelem = FLIP_SIZE / size;				/* elements in buffer */
1752 nbuf = count / nelem;					/* number buffers */
1753 lcnt = count % nelem;					/* count in last buf */
1754 if (lcnt) nbuf = nbuf + 1;
1755 else lcnt = nelem;
1756 total = 0;
1757 for (i = nbuf; i > 0; i--) {
1758 	c = (i == 1)? lcnt: nelem;
1759 	for (j = 0, sptr = bptr, dptr = sim_flip; j < c; j++) {
1760 		for (k = size - 1; k >= 0; k--)
1761 			*(dptr + k) = *sptr++;
1762 		dptr = dptr + size;  }
1763 	c = fwrite (sim_flip, size, c, fptr);
1764 	if (c == 0) return total;
1765 	total = total + c;  }
1766 return total;
1767 }
1768 
1769