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