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