sim: ppc: do not exit when parsing args w/gdb
[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 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_ */