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