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