xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/psim.c (revision d9030711976e533fb52cfed73ebd1a865ef88911)
1 /*  This file is part of the program psim.
2 
3     Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, see <http://www.gnu.org/licenses/>.
17 
18     */
19 
20 
21 #ifndef _PSIM_C_
22 #define _PSIM_C_
23 
24 #include "cpu.h" /* includes psim.h */
25 #include "idecode.h"
26 #include "options.h"
27 
28 #include "tree.h"
29 
30 #include <signal.h>
31 
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <setjmp.h>
36 #include <string.h>
37 
38 #include "bfd.h"
39 #include "libiberty.h"
40 #include "gdb/signals.h"
41 
42 /* system structure, actual size of processor array determined at
43    runtime */
44 
45 struct _psim {
46   event_queue *events;
47   device *devices;
48   mon *monitor;
49   os_emul *os_emulation;
50   core *memory;
51 
52   /* escape routine for inner functions */
53   void *path_to_halt;
54   void *path_to_restart;
55 
56   /* status from last halt */
57   psim_status halt_status;
58 
59   /* the processors proper */
60   int nr_cpus;
61   int last_cpu; /* CPU that last (tried to) execute an instruction */
62   cpu *processors[MAX_NR_PROCESSORS];
63 };
64 
65 
66 enum bfd_endian current_target_byte_order;
67 int current_environment;
68 int current_alignment;
69 int current_floating_point;
70 int current_model_issue = MODEL_ISSUE_IGNORE;
71 int current_stdio = DO_USE_STDIO;
72 model_enum current_model = WITH_DEFAULT_MODEL;
73 
74 
75 /* create the device tree */
76 
77 INLINE_PSIM\
78 (device *)
79 psim_tree(void)
80 {
81   device *root = tree_parse(NULL, "core");
82   tree_parse(root, "/aliases");
83   tree_parse(root, "/options");
84   tree_parse(root, "/chosen");
85   tree_parse(root, "/packages");
86   tree_parse(root, "/cpus");
87   tree_parse(root, "/openprom");
88   tree_parse(root, "/openprom/init");
89   tree_parse(root, "/openprom/trace");
90   tree_parse(root, "/openprom/options");
91   return root;
92 }
93 
94 STATIC_INLINE_PSIM\
95 (const char *)
96 find_arg(const char *err_msg,
97 	 int *ptr_to_argp,
98 	 char * const *argv)
99 {
100   *ptr_to_argp += 1;
101   if (argv[*ptr_to_argp] == NULL)
102     error("%s", err_msg);
103   return argv[*ptr_to_argp];
104 }
105 
106 INLINE_PSIM\
107 (void)
108 psim_usage (int verbose, int help, SIM_OPEN_KIND kind)
109 {
110   printf_filtered("Usage:\n");
111   printf_filtered("\n");
112   printf_filtered("\tpsim [ <psim-option> ... ] <image> [ <image-arg> ... ]\n");
113   printf_filtered("\n");
114   printf_filtered("Where\n");
115   printf_filtered("\n");
116   printf_filtered("\t<image>         Name of the PowerPC program to run.\n");
117   if (verbose) {
118   printf_filtered("\t                This can either be a PowerPC binary or\n");
119   printf_filtered("\t                a text file containing a device tree\n");
120   printf_filtered("\t                specification.\n");
121   printf_filtered("\t                PSIM will attempt to determine from the\n");
122   printf_filtered("\t                specified <image> the intended emulation\n");
123   printf_filtered("\t                environment.\n");
124   printf_filtered("\t                If PSIM gets it wrong, the emulation\n");
125   printf_filtered("\t                environment can be specified using the\n");
126   printf_filtered("\t                `-e' option (described below).\n");
127   printf_filtered("\n"); }
128   printf_filtered("\t<image-arg>     Argument to be passed to <image>\n");
129   if (verbose) {
130   printf_filtered("\t                These arguments will be passed to\n");
131   printf_filtered("\t                <image> (as standard C argv, argc)\n");
132   printf_filtered("\t                when <image> is started.\n");
133   printf_filtered("\n"); }
134   printf_filtered("\t<psim-option>   See below\n");
135   printf_filtered("\n");
136   printf_filtered("The following are valid <psim-option>s:\n");
137   printf_filtered("\n");
138 
139   printf_filtered("\t-c <count>      Limit the simulation to <count> iterations\n");
140   if (verbose) {
141   printf_filtered("\n");
142   }
143 
144   printf_filtered("\t-i or -i2       Print instruction counting statistics\n");
145   if (verbose) {
146   printf_filtered("\t                Specify -i2 for a more detailed display\n");
147   printf_filtered("\n");
148   }
149 
150   printf_filtered("\t-I              Print execution unit statistics\n");
151   if (verbose) { printf_filtered("\n"); }
152 
153   printf_filtered("\t-e <os-emul>    specify an OS or platform to model\n");
154   if (verbose) {
155   printf_filtered("\t                Can be any of the following:\n");
156   printf_filtered("\t                bug - OEA + MOTO BUG ROM calls\n");
157   printf_filtered("\t                netbsd - UEA + NetBSD system calls\n");
158   printf_filtered("\t                solaris - UEA + Solaris system calls\n");
159   printf_filtered("\t                linux - UEA + Linux system calls\n");
160   printf_filtered("\t                chirp - OEA + a few OpenBoot calls\n");
161   printf_filtered("\n"); }
162 
163   printf_filtered("\t-E <endian>     Specify the endianness of the target\n");
164   if (verbose) {
165   printf_filtered("\t                Can be any of the following:\n");
166   printf_filtered("\t                big - big endian target\n");
167   printf_filtered("\t                little - little endian target\n");
168   printf_filtered("\n"); }
169 
170   printf_filtered("\t-f <file>       Merge <file> into the device tree\n");
171   if (verbose) { printf_filtered("\n"); }
172 
173   printf_filtered("\t-h -? -H        give more detailed usage\n");
174   if (verbose) { printf_filtered("\n"); }
175 
176   printf_filtered("\t-m <model>      Specify the processor to model (604)\n");
177   if (verbose) {
178   printf_filtered("\t                Selects the processor to use when\n");
179   printf_filtered("\t                modeling execution units.  Includes:\n");
180   printf_filtered("\t                604, 603 and 603e\n");
181   printf_filtered("\n"); }
182 
183   printf_filtered("\t-n <nr-smp>     Specify the number of processors in SMP simulations\n");
184   if (verbose) {
185   printf_filtered("\t                Specifies the number of processors that are\n");
186   printf_filtered("\t                to be modeled in a symetric multi-processor (SMP)\n");
187   printf_filtered("\t                simulation\n");
188   printf_filtered("\n"); }
189 
190   printf_filtered("\t-o <dev-spec>   Add device <dev-spec> to the device tree\n");
191   if (verbose) { printf_filtered("\n"); }
192 
193   printf_filtered("\t-r <ram-size>   Set RAM size in bytes (OEA environments)\n");
194   if (verbose) { printf_filtered("\n"); }
195 
196   printf_filtered("\t-t [!]<trace>   Enable (disable) <trace> option\n");
197   if (verbose) { printf_filtered("\n"); }
198 
199   printf_filtered("\n");
200   trace_usage(verbose);
201   device_usage(verbose);
202   if (verbose > 1) {
203     printf_filtered("\n");
204     print_options();
205   }
206 
207   if (kind == SIM_OPEN_STANDALONE)
208     {
209       if (REPORT_BUGS_TO[0])
210 	printf ("Report bugs to %s\n", REPORT_BUGS_TO);
211       exit (help ? 0 : 1);
212     }
213 }
214 
215 /* Test "string" for containing a string of digits that form a number
216 between "min" and "max".  The return value is the number or "err". */
217 static
218 int is_num(const char *string, int min, int max, int err)
219 {
220   int result = 0;
221 
222   for ( ; *string; ++string)
223   {
224     if (!isdigit(*string))
225     {
226       result = err;
227       break;
228     }
229     result = result * 10 + (*string - '0');
230   }
231   if (result < min || result > max)
232     result = err;
233 
234   return result;
235 }
236 
237 INLINE_PSIM\
238 (char * const *)
239 psim_options(device *root,
240 	     char * const *argv,
241 	     SIM_OPEN_KIND kind)
242 {
243   device *current = root;
244   int argp;
245   if (argv == NULL)
246     return NULL;
247   argp = 0;
248   while (argv[argp] != NULL && argv[argp][0] == '-') {
249     const char *p = argv[argp] + 1;
250     const char *param;
251     while (*p != '\0') {
252       switch (*p) {
253       default:
254 	printf_filtered ("Invalid Option: %s\n", argv[argp]);
255 	psim_usage (0, 0, kind);
256 	return NULL;
257       case 'c':
258 	param = find_arg("Missing <count> option for -c (max-iterations)\n", &argp, argv);
259 	tree_parse(root, "/openprom/options/max-iterations %s", param);
260 	break;
261       case 'e':
262 	param = find_arg("Missing <emul> option for -e (os-emul)\n", &argp, argv);
263 	tree_parse(root, "/openprom/options/os-emul %s", param);
264 	break;
265       case 'E':
266 	/* endian spec, ignored for now */
267 	param = find_arg("Missing <endian> option for -E (target-endian)\n", &argp, argv);
268 	if (strcmp (param, "big") == 0)
269 	  tree_parse (root, "/options/little-endian? false");
270 	else if (strcmp (param, "little") == 0)
271 	  tree_parse (root, "/options/little-endian? true");
272 	else
273 	  {
274 	    printf_filtered ("Invalid <endian> option for -E (target-endian)\n");
275 	    psim_usage (0, 0, kind);
276 	    return NULL;
277 	  }
278 	break;
279       case 'f':
280 	param = find_arg("Missing <file> option for -f\n", &argp, argv);
281 	psim_merge_device_file(root, param);
282 	break;
283       case 'h':
284       case '?':
285 	psim_usage (1, 1, kind);
286 	return NULL;
287       case 'H':
288 	psim_usage (2, 1, kind);
289 	return NULL;
290       case 'i':
291 	if (isdigit(p[1])) {
292 	  tree_parse(root, "/openprom/trace/print-info %c", p[1]);
293 	  p++;
294 	}
295 	else {
296 	  tree_parse(root, "/openprom/trace/print-info 1");
297 	}
298 	break;
299       case 'I':
300 	tree_parse(root, "/openprom/trace/print-info 2");
301 	tree_parse(root, "/openprom/options/model-issue %d",
302 		   MODEL_ISSUE_PROCESS);
303 	break;
304       case 'm':
305 	param = find_arg("Missing <model> option for -m (model)\n", &argp, argv);
306 	tree_parse(root, "/openprom/options/model \"%s", param);
307 	break;
308       case 'n':
309 	param = find_arg("Missing <nr-smp> option for -n (smp)\n", &argp, argv);
310 	tree_parse(root, "/openprom/options/smp %s", param);
311 	break;
312       case 'o':
313 	param = find_arg("Missing <dev-spec> option for -o\n", &argp, argv);
314 	if (memcmp(param, "mpc860c0", 8) == 0)
315         {
316           if (param[8] == '\0')
317             tree_parse(root, "/options/mpc860c0 5");
318           else if (param[8] == '=' && is_num(param+9, 1, 10, 0))
319           {
320             tree_parse(root, "/options/mpc860c0 %s", param+9);
321           }
322           else error("Invalid mpc860c0 option for -o\n");
323         }
324 	else
325           current = tree_parse(current, "%s", param);
326 	break;
327       case 'r':
328 	param = find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp, argv);
329 	tree_parse(root, "/openprom/options/oea-memory-size %s",
330 			       param);
331 	break;
332       case 't':
333 	param = find_arg("Missing <trace> option for -t (trace/*)\n", &argp, argv);
334 	if (param[0] == '!')
335 	  tree_parse(root, "/openprom/trace/%s 0", param+1);
336 	else
337 	  tree_parse(root, "/openprom/trace/%s 1", param);
338 	break;
339       case '-':
340 	/* it's a long option of the form --optionname=optionvalue.
341 	   Such options can be passed through if we are invoked by
342 	   gdb.  */
343 	if (strstr(argv[argp], "architecture") != NULL) {
344           /* we must consume the argument here, so that we get out
345              of the loop.  */
346 	  p = argv[argp] + strlen(argv[argp]) - 1;
347 	  printf_filtered("Warning - architecture parameter ignored\n");
348         }
349 	else if (strcmp (argv[argp], "--help") == 0)
350 	  {
351 	    psim_usage (0, 1, kind);
352 	    return NULL;
353 	  }
354 	else if (strncmp (argv[argp], "--sysroot=",
355 			  sizeof ("--sysroot=") - 1) == 0)
356 	  /* Ignore this option.  */
357 	  p = argv[argp] + strlen(argv[argp]) - 1;
358 	else if (strcmp (argv[argp], "--version") == 0)
359 	  {
360 	    extern const char version[];
361 	    printf ("GNU simulator %s%s\n", PKGVERSION, version);
362 	    printf ("Copyright (C) 2024 Free Software Foundation, Inc.\n");
363 	    printf ( "\
364 License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\
365 \nThis is free software: you are free to change and redistribute it.\n\
366 There is NO WARRANTY, to the extent permitted by law.\n");
367 	    if (kind == SIM_OPEN_STANDALONE)
368 	      exit (0);
369 	    else
370 	      return NULL;
371 	  }
372 	else
373 	  {
374 	    printf_filtered ("Invalid option: %s\n", argv[argp]);
375 	    psim_usage (0, 0, kind);
376 	    return NULL;
377 	  }
378 	break;
379       }
380       p += 1;
381     }
382     argp += 1;
383   }
384   /* force the trace node to process its options now *before* the tree
385      initialization occures */
386   device_ioctl(tree_find_device(root, "/openprom/trace"),
387 	       NULL, 0,
388 	       device_ioctl_set_trace);
389 
390   {
391     void semantic_init(device* root);
392     semantic_init(root);
393   }
394 
395   /* return where the options end */
396   return argv + argp;
397 }
398 
399 INLINE_PSIM\
400 (void)
401 psim_command(device *root,
402 	     char * const *argv)
403 {
404   int argp = 0;
405   if (argv[argp] == NULL) {
406     return;
407   }
408   else if (strcmp(argv[argp], "trace") == 0) {
409     const char *opt = find_arg("Missing <trace> option", &argp, argv);
410     if (opt[0] == '!')
411       trace_option(opt + 1, 0);
412     else
413       trace_option(opt, 1);
414   }
415   else if (strcmp(*argv, "change-media") == 0) {
416     const char *device = find_arg("Missing device name", &argp, argv);
417     const char *media = argv[++argp];
418     device_ioctl(tree_find_device(root, device), NULL, 0,
419 		 device_ioctl_change_media, media);
420   }
421   else {
422     printf_filtered("Unknown PSIM command %s, try\n", argv[argp]);
423     printf_filtered("    trace <trace-option>\n");
424     printf_filtered("    change-media <device> [ <new-image> ]\n");
425   }
426 }
427 
428 
429 /* create the simulator proper from the device tree and executable */
430 
431 INLINE_PSIM\
432 (psim *)
433 psim_create(const char *file_name,
434 	    device *root)
435 {
436   int cpu_nr;
437   const char *env;
438   psim *system;
439   os_emul *os_emulation;
440   int nr_cpus;
441 
442   /* given this partially populated device tree, os_emul_create() uses
443      it and file_name to determine the selected emulation and hence
444      further populate the tree with any other required nodes. */
445 
446   os_emulation = os_emul_create(file_name, root);
447   if (os_emulation == NULL)
448     error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
449 
450   /* fill in the missing real number of CPU's */
451   nr_cpus = tree_find_integer_property(root, "/openprom/options/smp");
452   if (MAX_NR_PROCESSORS < nr_cpus)
453     error("target and configured number of cpus conflict\n");
454 
455   /* fill in the missing TARGET BYTE ORDER information */
456   current_target_byte_order
457     = (tree_find_boolean_property(root, "/options/little-endian?")
458        ? BFD_ENDIAN_LITTLE
459        : BFD_ENDIAN_BIG);
460   if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
461     error("target and configured byte order conflict\n");
462 
463   /* fill in the missing OEA/VEA information */
464   env = tree_find_string_property(root, "/openprom/options/env");
465   current_environment = ((strcmp(env, "user") == 0
466 			  || strcmp(env, "uea") == 0)
467 			 ? USER_ENVIRONMENT
468 			 : (strcmp(env, "virtual") == 0
469 			    || strcmp(env, "vea") == 0)
470 			 ? VIRTUAL_ENVIRONMENT
471 			 : (strcmp(env, "operating") == 0
472 			    || strcmp(env, "oea") == 0)
473 			 ? OPERATING_ENVIRONMENT
474 			 : 0);
475   if (current_environment == 0)
476     error("unreconized /options env property\n");
477   if (CURRENT_ENVIRONMENT != current_environment)
478     error("target and configured environment conflict\n");
479 
480   /* fill in the missing ALLIGNMENT information */
481   current_alignment
482     = (tree_find_boolean_property(root, "/openprom/options/strict-alignment?")
483        ? STRICT_ALIGNMENT
484        : NONSTRICT_ALIGNMENT);
485   if (CURRENT_ALIGNMENT != current_alignment)
486     error("target and configured alignment conflict\n");
487 
488   /* fill in the missing FLOATING POINT information */
489   current_floating_point
490     = (tree_find_boolean_property(root, "/openprom/options/floating-point?")
491        ? HARD_FLOATING_POINT
492        : SOFT_FLOATING_POINT);
493   if (CURRENT_FLOATING_POINT != current_floating_point)
494     error("target and configured floating-point conflict\n");
495 
496   /* fill in the missing STDIO information */
497   current_stdio
498     = (tree_find_boolean_property(root, "/openprom/options/use-stdio?")
499        ? DO_USE_STDIO
500        : DONT_USE_STDIO);
501   if (CURRENT_STDIO != current_stdio)
502     error("target and configured stdio interface conflict\n");
503 
504   /* sort out the level of detail for issue modeling */
505   current_model_issue
506     = tree_find_integer_property(root, "/openprom/options/model-issue");
507   if (CURRENT_MODEL_ISSUE != current_model_issue)
508     error("target and configured model-issue conflict\n");
509 
510   /* sort out our model architecture - wrong.
511 
512      FIXME: this should be obtaining the required information from the
513      device tree via the "/chosen" property "cpu" which is an instance
514      (ihandle) for the only executing processor. By converting that
515      ihandle into the corresponding cpu's phandle and then querying
516      the "name" property, the cpu type can be determined. Ok? */
517 
518   model_set(tree_find_string_property(root, "/openprom/options/model"));
519 
520   /* create things */
521   system = ZALLOC(psim);
522   system->events = event_queue_create();
523   system->memory = core_from_device(root);
524   system->monitor = mon_create();
525   system->nr_cpus = nr_cpus;
526   system->os_emulation = os_emulation;
527   system->devices = root;
528 
529   /* now all the processors attaching to each their per-cpu information */
530   for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
531     system->processors[cpu_nr] = cpu_create(system,
532 					    system->memory,
533 					    mon_cpu(system->monitor,
534 						    cpu_nr),
535 					    system->os_emulation,
536 					    cpu_nr);
537   }
538 
539   /* dump out the contents of the device tree */
540   if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
541     tree_print(root);
542   if (ppc_trace[trace_dump_device_tree])
543     error("%s", "");
544 
545   return system;
546 }
547 
548 
549 /* allow the simulation to stop/restart abnormaly */
550 
551 INLINE_PSIM\
552 (void)
553 psim_set_halt_and_restart(psim *system,
554 			  void *halt_jmp_buf,
555 			  void *restart_jmp_buf)
556 {
557   system->path_to_halt = halt_jmp_buf;
558   system->path_to_restart = restart_jmp_buf;
559 }
560 
561 INLINE_PSIM\
562 (void)
563 psim_clear_halt_and_restart(psim *system)
564 {
565   system->path_to_halt = NULL;
566   system->path_to_restart = NULL;
567 }
568 
569 INLINE_PSIM\
570 (void)
571 psim_restart(psim *system,
572 	     int current_cpu)
573 {
574   ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus);
575   ASSERT(system->path_to_restart != NULL);
576   system->last_cpu = current_cpu;
577   longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
578 }
579 
580 
581 static ATTRIBUTE_NORETURN void
582 cntrl_c_simulation(void *data)
583 {
584   psim *system = data;
585   psim_halt(system,
586 	    psim_nr_cpus(system),
587 	    was_continuing,
588 	    GDB_SIGNAL_INT);
589 }
590 
591 INLINE_PSIM\
592 (void)
593 psim_stop(psim *system)
594 {
595   event_queue_schedule_after_signal(psim_event_queue(system),
596 				    0 /*NOW*/,
597 				    cntrl_c_simulation,
598 				    system);
599 }
600 
601 INLINE_PSIM\
602 (void)
603 psim_halt(psim *system,
604 	  int current_cpu,
605 	  stop_reason reason,
606 	  int signal)
607 {
608   ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus);
609   ASSERT(system->path_to_halt != NULL);
610   system->last_cpu = current_cpu;
611   system->halt_status.reason = reason;
612   system->halt_status.signal = signal;
613   if (current_cpu == system->nr_cpus) {
614     system->halt_status.cpu_nr = 0;
615     system->halt_status.program_counter =
616       cpu_get_program_counter(system->processors[0]);
617   }
618   else {
619     system->halt_status.cpu_nr = current_cpu;
620     system->halt_status.program_counter =
621       cpu_get_program_counter(system->processors[current_cpu]);
622   }
623   longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
624 }
625 
626 
627 INLINE_PSIM\
628 (int)
629 psim_last_cpu(psim *system)
630 {
631   return system->last_cpu;
632 }
633 
634 INLINE_PSIM\
635 (int)
636 psim_nr_cpus(psim *system)
637 {
638   return system->nr_cpus;
639 }
640 
641 INLINE_PSIM\
642 (psim_status)
643 psim_get_status(psim *system)
644 {
645   return system->halt_status;
646 }
647 
648 
649 INLINE_PSIM\
650 (cpu *)
651 psim_cpu(psim *system,
652 	 int cpu_nr)
653 {
654   if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
655     return NULL;
656   else
657     return system->processors[cpu_nr];
658 }
659 
660 
661 INLINE_PSIM\
662 (device *)
663 psim_device(psim *system,
664 	    const char *path)
665 {
666   return tree_find_device(system->devices, path);
667 }
668 
669 INLINE_PSIM\
670 (event_queue *)
671 psim_event_queue(psim *system)
672 {
673   return system->events;
674 }
675 
676 
677 
678 STATIC_INLINE_PSIM\
679 (void)
680 psim_max_iterations_exceeded(void *data)
681 {
682   psim *system = data;
683   psim_halt(system,
684 	    system->nr_cpus, /* halted during an event */
685 	    was_signalled,
686 	    -1);
687 }
688 
689 
690 INLINE_PSIM\
691 (void)
692 psim_init(psim *system)
693 {
694   int cpu_nr;
695 
696   /* scrub the monitor */
697   mon_init(system->monitor, system->nr_cpus);
698 
699   /* trash any pending events */
700   event_queue_init(system->events);
701 
702   /* if needed, schedule a halt event.  FIXME - In the future this
703      will be replaced by a more generic change to psim_command().  A
704      new command `schedule NNN halt' being added. */
705   if (tree_find_property(system->devices, "/openprom/options/max-iterations")) {
706     event_queue_schedule(system->events,
707 			 tree_find_integer_property(system->devices,
708 						    "/openprom/options/max-iterations") - 2,
709 			 psim_max_iterations_exceeded,
710 			 system);
711   }
712 
713   /* scrub all the cpus */
714   for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
715     cpu_init(system->processors[cpu_nr]);
716 
717   /* init all the devices (which updates the cpus) */
718   tree_init(system->devices, system);
719 
720   /* and the emulation (which needs an initialized device tree) */
721   os_emul_init(system->os_emulation, system->nr_cpus);
722 
723   /* now sync each cpu against the initialized state of its registers */
724   for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
725     cpu *processor = system->processors[cpu_nr];
726     cpu_synchronize_context(processor, cpu_get_program_counter(processor));
727     cpu_page_tlb_invalidate_all(processor);
728   }
729 
730   /* force loop to start with first cpu */
731   system->last_cpu = -1;
732 }
733 
734 INLINE_PSIM\
735 (void)
736 psim_stack(psim *system,
737 	   char * const *argv,
738 	   char * const *envp)
739 {
740   /* pass the stack device the argv/envp and let it work out what to
741      do with it */
742   device *stack_device = tree_find_device(system->devices,
743 					  "/openprom/init/stack");
744   if (stack_device != (device*)0) {
745     unsigned_word stack_pointer;
746     ASSERT (psim_read_register(system, 0, &stack_pointer, "sp",
747 			       cooked_transfer) > 0);
748     device_ioctl(stack_device,
749 		 NULL, /*cpu*/
750 		 0, /*cia*/
751 		 device_ioctl_create_stack,
752 		 stack_pointer,
753 		 argv,
754 		 envp);
755   }
756 }
757 
758 
759 
760 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
761    thing */
762 
763 INLINE_PSIM\
764 (void)
765 psim_step(psim *system)
766 {
767   volatile int keep_running = 0;
768   idecode_run_until_stop(system, &keep_running,
769 			 system->events, system->processors, system->nr_cpus);
770 }
771 
772 INLINE_PSIM\
773 (void)
774 psim_run(psim *system)
775 {
776   idecode_run(system,
777 	      system->events, system->processors, system->nr_cpus);
778 }
779 
780 
781 /* storage manipulation functions */
782 
783 INLINE_PSIM\
784 (int)
785 psim_read_register(psim *system,
786 		   int which_cpu,
787 		   void *buf,
788 		   const char reg[],
789 		   transfer_mode mode)
790 {
791   register_descriptions description;
792   union {
793     uint8_t bytes[16];
794     unsigned_word unsigned_word;
795     unsigned_1 unsigned_1;
796     unsigned_2 unsigned_2;
797     unsigned_4 unsigned_4;
798     unsigned_8 unsigned_8;
799     unsigned_16 unsigned_16;
800     creg creg;
801     fpreg fpreg;
802     fpscreg fpscreg;
803     gpreg gpreg;
804     msreg msreg;
805     spreg spreg;
806     sreg sreg;
807   } cooked_buf;
808   cpu *processor;
809 
810   /* find our processor */
811   if (which_cpu == MAX_NR_PROCESSORS) {
812     if (system->last_cpu == system->nr_cpus
813 	|| system->last_cpu == -1)
814       which_cpu = 0;
815     else
816       which_cpu = system->last_cpu;
817   }
818   ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
819 
820   processor = system->processors[which_cpu];
821 
822   /* find the register description */
823   description = register_description(reg);
824   if (description.type == reg_invalid)
825     return 0;
826 
827   /* get the cooked value */
828   switch (description.type) {
829 
830   case reg_gpr:
831     cooked_buf.gpreg = cpu_registers(processor)->gpr[description.index];
832     break;
833 
834   case reg_spr:
835     cooked_buf.spreg = cpu_registers(processor)->spr[description.index];
836     break;
837 
838   case reg_sr:
839     cooked_buf.sreg = cpu_registers(processor)->sr[description.index];
840     break;
841 
842   case reg_fpr:
843     cooked_buf.fpreg = cpu_registers(processor)->fpr[description.index];
844     break;
845 
846   case reg_pc:
847     cooked_buf.unsigned_word = cpu_get_program_counter(processor);
848     break;
849 
850   case reg_cr:
851     cooked_buf.creg = cpu_registers(processor)->cr;
852     break;
853 
854   case reg_msr:
855     cooked_buf.msreg = cpu_registers(processor)->msr;
856     break;
857 
858   case reg_fpscr:
859     cooked_buf.fpscreg = cpu_registers(processor)->fpscr;
860     break;
861 
862   case reg_insns:
863     cooked_buf.unsigned_word = mon_get_number_of_insns(system->monitor,
864 							  which_cpu);
865     break;
866 
867   case reg_stalls:
868     if (cpu_model(processor) == NULL)
869       error("$stalls only valid if processor unit model enabled (-I)\n");
870     cooked_buf.unsigned_word = model_get_number_of_stalls(cpu_model(processor));
871     break;
872 
873   case reg_cycles:
874     if (cpu_model(processor) == NULL)
875       error("$cycles only valid if processor unit model enabled (-I)\n");
876     cooked_buf.unsigned_word = model_get_number_of_cycles(cpu_model(processor));
877     break;
878 
879 #ifdef WITH_ALTIVEC
880   case reg_vr:
881     cooked_buf.vreg = cpu_registers(processor)->altivec.vr[description.index];
882     break;
883 
884   case reg_vscr:
885     cooked_buf.vscreg = cpu_registers(processor)->altivec.vscr;
886     break;
887 #endif
888 
889 #ifdef WITH_E500
890   case reg_gprh:
891     cooked_buf.gpreg = cpu_registers(processor)->e500.gprh[description.index];
892     break;
893 
894   case reg_evr:
895     cooked_buf.uint64_t = EVR(description.index);
896     break;
897 
898   case reg_acc:
899     cooked_buf.accreg = cpu_registers(processor)->e500.acc;
900     break;
901 #endif
902 
903   default:
904     printf_filtered("psim_read_register(processor=%p,buf=%p,reg=%s) %s\n",
905 		    processor, buf, reg, "read of this register unimplemented");
906     return 0;
907   }
908 
909   /* the PSIM internal values are in host order.  To fetch raw data,
910      they need to be converted into target order and then returned */
911   if (mode == raw_transfer) {
912     /* FIXME - assumes that all registers are simple integers */
913     switch (description.size) {
914     case 1:
915       *(unsigned_1*)buf = H2T_1(cooked_buf.unsigned_1);
916       break;
917     case 2:
918       *(unsigned_2*)buf = H2T_2(cooked_buf.unsigned_2);
919       break;
920     case 4:
921       *(unsigned_4*)buf = H2T_4(cooked_buf.unsigned_4);
922       break;
923     case 8:
924       *(unsigned_8*)buf = H2T_8(cooked_buf.unsigned_8);
925       break;
926     case 16:
927       {
928 	unsigned_16 v = H2T_16(cooked_buf.unsigned_16);
929 	memcpy(buf/*dest*/, &v, description.size);
930       }
931       break;
932     }
933   }
934   else {
935     memcpy(buf/*dest*/, cooked_buf.bytes/*src*/, description.size);
936   }
937 
938   return description.size;
939 }
940 
941 
942 
943 INLINE_PSIM\
944 (int)
945 psim_write_register(psim *system,
946 		    int which_cpu,
947 		    const void *buf,
948 		    const char reg[],
949 		    transfer_mode mode)
950 {
951   cpu *processor;
952   register_descriptions description;
953   union {
954     uint8_t bytes[16];
955     unsigned_word unsigned_word;
956     unsigned_1 unsigned_1;
957     unsigned_2 unsigned_2;
958     unsigned_4 unsigned_4;
959     unsigned_8 unsigned_8;
960     unsigned_16 unsigned_16;
961     creg creg;
962     fpreg fpreg;
963     fpscreg fpscreg;
964     gpreg gpreg;
965     msreg msreg;
966     spreg spreg;
967     sreg sreg;
968   } cooked_buf;
969 
970   /* find our processor */
971   if (which_cpu == MAX_NR_PROCESSORS) {
972     if (system->last_cpu == system->nr_cpus
973 	|| system->last_cpu == -1)
974       which_cpu = 0;
975     else
976       which_cpu = system->last_cpu;
977   }
978 
979   /* find the description of the register */
980   description = register_description(reg);
981   if (description.type == reg_invalid)
982     return 0;
983 
984   if (which_cpu == -1) {
985     int i;
986     for (i = 0; i < system->nr_cpus; i++)
987       psim_write_register(system, i, buf, reg, mode);
988     return description.size;
989   }
990   ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
991 
992   processor = system->processors[which_cpu];
993 
994   /* If the data is comming in raw (target order), need to cook it
995      into host order before putting it into PSIM's internal structures */
996   if (mode == raw_transfer) {
997     switch (description.size) {
998     case 1:
999       cooked_buf.unsigned_1 = T2H_1(*(unsigned_1*)buf);
1000       break;
1001     case 2:
1002       cooked_buf.unsigned_2 = T2H_2(*(unsigned_2*)buf);
1003       break;
1004     case 4:
1005       cooked_buf.unsigned_4 = T2H_4(*(unsigned_4*)buf);
1006       break;
1007     case 8:
1008       cooked_buf.unsigned_8 = T2H_8(*(unsigned_8*)buf);
1009       break;
1010     case 16:
1011       cooked_buf.unsigned_16 = T2H_16(*(unsigned_16*)buf);
1012       break;
1013     }
1014   }
1015   else {
1016     memcpy(cooked_buf.bytes/*dest*/, buf/*src*/, description.size);
1017   }
1018 
1019   /* put the cooked value into the register */
1020   switch (description.type) {
1021 
1022   case reg_gpr:
1023     cpu_registers(processor)->gpr[description.index] = cooked_buf.gpreg;
1024     break;
1025 
1026   case reg_fpr:
1027     cpu_registers(processor)->fpr[description.index] = cooked_buf.fpreg;
1028     break;
1029 
1030   case reg_pc:
1031     cpu_set_program_counter(processor, cooked_buf.unsigned_word);
1032     break;
1033 
1034   case reg_spr:
1035     cpu_registers(processor)->spr[description.index] = cooked_buf.spreg;
1036     break;
1037 
1038   case reg_sr:
1039     cpu_registers(processor)->sr[description.index] = cooked_buf.sreg;
1040     break;
1041 
1042   case reg_cr:
1043     cpu_registers(processor)->cr = cooked_buf.creg;
1044     break;
1045 
1046   case reg_msr:
1047     cpu_registers(processor)->msr = cooked_buf.msreg;
1048     break;
1049 
1050   case reg_fpscr:
1051     cpu_registers(processor)->fpscr = cooked_buf.fpscreg;
1052     break;
1053 
1054 #ifdef WITH_E500
1055   case reg_gprh:
1056     cpu_registers(processor)->e500.gprh[description.index] = cooked_buf.gpreg;
1057     break;
1058 
1059   case reg_evr:
1060     {
1061       uint64_t v;
1062       v = cooked_buf.uint64_t;
1063       cpu_registers(processor)->e500.gprh[description.index] = v >> 32;
1064       cpu_registers(processor)->gpr[description.index] = v;
1065       break;
1066     }
1067 
1068   case reg_acc:
1069     cpu_registers(processor)->e500.acc = cooked_buf.accreg;
1070     break;
1071 #endif
1072 
1073 #ifdef WITH_ALTIVEC
1074   case reg_vr:
1075     cpu_registers(processor)->altivec.vr[description.index] = cooked_buf.vreg;
1076     break;
1077 
1078   case reg_vscr:
1079     cpu_registers(processor)->altivec.vscr = cooked_buf.vscreg;
1080     break;
1081 #endif
1082 
1083   default:
1084     printf_filtered("psim_write_register(processor=%p,buf=%p,reg=%s) %s\n",
1085 		    processor, buf, reg, "read of this register unimplemented");
1086     return 0;
1087   }
1088 
1089   return description.size;
1090 }
1091 
1092 
1093 
1094 INLINE_PSIM\
1095 (unsigned)
1096 psim_read_memory(psim *system,
1097 		 int which_cpu,
1098 		 void *buffer,
1099 		 unsigned_word vaddr,
1100 		 unsigned nr_bytes)
1101 {
1102   cpu *processor;
1103   if (which_cpu == MAX_NR_PROCESSORS) {
1104     if (system->last_cpu == system->nr_cpus
1105 	|| system->last_cpu == -1)
1106       which_cpu = 0;
1107     else
1108       which_cpu = system->last_cpu;
1109   }
1110   processor = system->processors[which_cpu];
1111   return vm_data_map_read_buffer(cpu_data_map(processor),
1112 				 buffer, vaddr, nr_bytes,
1113 				 NULL, -1);
1114 }
1115 
1116 
1117 INLINE_PSIM\
1118 (unsigned)
1119 psim_write_memory(psim *system,
1120 		  int which_cpu,
1121 		  const void *buffer,
1122 		  unsigned_word vaddr,
1123 		  unsigned nr_bytes,
1124 		  int violate_read_only_section)
1125 {
1126   cpu *processor;
1127   if (which_cpu == MAX_NR_PROCESSORS) {
1128     if (system->last_cpu == system->nr_cpus
1129 	|| system->last_cpu == -1)
1130       which_cpu = 0;
1131     else
1132       which_cpu = system->last_cpu;
1133   }
1134   ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
1135   processor = system->processors[which_cpu];
1136   return vm_data_map_write_buffer(cpu_data_map(processor),
1137 				  buffer, vaddr, nr_bytes, 1/*violate-read-only*/,
1138 				  NULL, -1);
1139 }
1140 
1141 
1142 INLINE_PSIM\
1143 (void)
1144 psim_print_info(psim *system,
1145 		int verbose)
1146 {
1147   mon_print_info(system, system->monitor, verbose);
1148 }
1149 
1150 
1151 /* Merge a device tree and a device file. */
1152 
1153 INLINE_PSIM\
1154 (void)
1155 psim_merge_device_file(device *root,
1156 		       const char *file_name)
1157 {
1158   FILE *description;
1159   int line_nr;
1160   char device_path[1000];
1161   device *current;
1162 
1163   /* try opening the file */
1164   description = fopen(file_name, "r");
1165   if (description == NULL) {
1166     perror(file_name);
1167     error("Invalid file %s specified", file_name);
1168   }
1169 
1170   line_nr = 0;
1171   current = root;
1172   while (fgets(device_path, sizeof(device_path), description)) {
1173     char *device;
1174     /* check that the full line was read */
1175     if (strchr(device_path, '\n') == NULL) {
1176       fclose(description);
1177       error("%s:%d: line to long - %s",
1178 	    file_name, line_nr, device_path);
1179     }
1180     else
1181       *strchr(device_path, '\n') = '\0';
1182     line_nr++;
1183     /* skip comments ("#" or ";") and blank lines lines */
1184     for (device = device_path;
1185 	 *device != '\0' && isspace(*device);
1186 	 device++);
1187     if (device[0] == '#'
1188 	|| device[0] == ';'
1189 	|| device[0] == '\0')
1190       continue;
1191     /* merge any appended lines */
1192     while (device_path[strlen(device_path) - 1] == '\\') {
1193       int curlen = strlen(device_path) - 1;
1194       /* zap \ */
1195       device_path[curlen] = '\0';
1196       /* append the next line */
1197       if (!fgets(device_path + curlen, sizeof(device_path) - curlen, description)) {
1198 	fclose(description);
1199 	error("%s:%d: unexpected eof in line continuation - %s",
1200 	      file_name, line_nr, device_path);
1201       }
1202       if (strchr(device_path, '\n') == NULL) {
1203 	fclose(description);
1204 	error("%s:%d: line to long - %s",
1205 	    file_name, line_nr, device_path);
1206       }
1207       else
1208 	*strchr(device_path, '\n') = '\0';
1209       line_nr++;
1210     }
1211     /* parse this line */
1212     current = tree_parse(current, "%s", device);
1213   }
1214   fclose(description);
1215 }
1216 
1217 
1218 #endif /* _PSIM_C_ */
1219