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