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