OSDN Git Service

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