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