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
58struct _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
79int current_target_byte_order;
80int current_host_byte_order;
81int current_environment;
82int current_alignment;
83int current_floating_point;
84int current_model_issue = MODEL_ISSUE_IGNORE;
85int current_stdio = DO_USE_STDIO;
86model_enum current_model = WITH_DEFAULT_MODEL;
87
88
89/* create the device tree */
90
91INLINE_PSIM\
92(device *)
93psim_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
108STATIC_INLINE_PSIM\
109(char *)
110find_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
120INLINE_PSIM\
121(void)
122psim_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
224between "min" and "max".  The return value is the number or "err". */
225static
226int 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
245INLINE_PSIM\
246(char **)
247psim_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
378INLINE_PSIM\
379(void)
380psim_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
410INLINE_PSIM\
411(psim *)
412psim_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
538INLINE_PSIM\
539(void)
540psim_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
548INLINE_PSIM\
549(void)
550psim_clear_halt_and_restart(psim *system)
551{
552  system->path_to_halt = NULL;
553  system->path_to_restart = NULL;
554}
555
556INLINE_PSIM\
557(void)
558psim_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
568static void
569cntrl_c_simulation(void *data)
570{
571  psim *system = data;
572  psim_halt(system,
573	    psim_nr_cpus(system),
574	    was_continuing,
575	    TARGET_SIGNAL_INT);
576}
577
578INLINE_PSIM\
579(void)
580psim_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
588INLINE_PSIM\
589(void)
590psim_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
614INLINE_PSIM\
615(int)
616psim_last_cpu(psim *system)
617{
618  return system->last_cpu;
619}
620
621INLINE_PSIM\
622(int)
623psim_nr_cpus(psim *system)
624{
625  return system->nr_cpus;
626}
627
628INLINE_PSIM\
629(psim_status)
630psim_get_status(psim *system)
631{
632  return system->halt_status;
633}
634
635
636INLINE_PSIM\
637(cpu *)
638psim_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
648INLINE_PSIM\
649(device *)
650psim_device(psim *system,
651	    const char *path)
652{
653  return tree_find_device(system->devices, path);
654}
655
656INLINE_PSIM\
657(event_queue *)
658psim_event_queue(psim *system)
659{
660  return system->events;
661}
662
663
664
665STATIC_INLINE_PSIM\
666(void)
667psim_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
677INLINE_PSIM\
678(void)
679psim_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
721INLINE_PSIM\
722(void)
723psim_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
750INLINE_PSIM\
751(void)
752psim_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
759INLINE_PSIM\
760(void)
761psim_run(psim *system)
762{
763  idecode_run(system,
764	      system->events, system->processors, system->nr_cpus);
765}
766
767
768/* storage manipulation functions */
769
770INLINE_PSIM\
771(int)
772psim_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
927INLINE_PSIM\
928(int)
929psim_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
1077INLINE_PSIM\
1078(unsigned)
1079psim_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
1100INLINE_PSIM\
1101(unsigned)
1102psim_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
1125INLINE_PSIM\
1126(void)
1127psim_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
1136INLINE_PSIM\
1137(void)
1138psim_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_ */
1202