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