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