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