Fix: symbols eliminated by --gc-sections still trigger warnings for gnu.warning.SYM
[binutils-gdb.git] / sim / ppc / psim.c
blob2a823616faeaad6dc08511a0245bbbd5a8d80490
1 /* This file is part of the program psim.
3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
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.
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.
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/>.
21 #ifndef _PSIM_C_
22 #define _PSIM_C_
24 #include "cpu.h" /* includes psim.h */
25 #include "idecode.h"
26 #include "options.h"
28 #include "tree.h"
30 #include <signal.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <setjmp.h>
36 #include <string.h>
38 #include "bfd.h"
39 #include "libiberty.h"
40 #include "gdb/signals.h"
42 /* system structure, actual size of processor array determined at
43 runtime */
45 struct _psim {
46 event_queue *events;
47 device *devices;
48 mon *monitor;
49 os_emul *os_emulation;
50 core *memory;
52 /* escape routine for inner functions */
53 void *path_to_halt;
54 void *path_to_restart;
56 /* status from last halt */
57 psim_status halt_status;
59 /* the processors proper */
60 int nr_cpus;
61 int last_cpu; /* CPU that last (tried to) execute an instruction */
62 cpu *processors[MAX_NR_PROCESSORS];
66 enum bfd_endian current_target_byte_order;
67 int current_environment;
68 int current_alignment;
69 int current_floating_point;
70 int current_model_issue = MODEL_ISSUE_IGNORE;
71 int current_stdio = DO_USE_STDIO;
72 model_enum current_model = WITH_DEFAULT_MODEL;
75 /* create the device tree */
77 INLINE_PSIM\
78 (device *)
79 psim_tree(void)
81 device *root = tree_parse(NULL, "core");
82 tree_parse(root, "/aliases");
83 tree_parse(root, "/options");
84 tree_parse(root, "/chosen");
85 tree_parse(root, "/packages");
86 tree_parse(root, "/cpus");
87 tree_parse(root, "/openprom");
88 tree_parse(root, "/openprom/init");
89 tree_parse(root, "/openprom/trace");
90 tree_parse(root, "/openprom/options");
91 return root;
94 STATIC_INLINE_PSIM\
95 (const char *)
96 find_arg(const char *err_msg,
97 int *ptr_to_argp,
98 char * const *argv)
100 *ptr_to_argp += 1;
101 if (argv[*ptr_to_argp] == NULL)
102 error("%s", err_msg);
103 return argv[*ptr_to_argp];
106 INLINE_PSIM\
107 (void)
108 psim_usage (int verbose, int help, SIM_OPEN_KIND kind)
110 printf_filtered("Usage:\n");
111 printf_filtered("\n");
112 printf_filtered("\tpsim [ <psim-option> ... ] <image> [ <image-arg> ... ]\n");
113 printf_filtered("\n");
114 printf_filtered("Where\n");
115 printf_filtered("\n");
116 printf_filtered("\t<image> Name of the PowerPC program to run.\n");
117 if (verbose) {
118 printf_filtered("\t This can either be a PowerPC binary or\n");
119 printf_filtered("\t a text file containing a device tree\n");
120 printf_filtered("\t specification.\n");
121 printf_filtered("\t PSIM will attempt to determine from the\n");
122 printf_filtered("\t specified <image> the intended emulation\n");
123 printf_filtered("\t environment.\n");
124 printf_filtered("\t If PSIM gets it wrong, the emulation\n");
125 printf_filtered("\t environment can be specified using the\n");
126 printf_filtered("\t `-e' option (described below).\n");
127 printf_filtered("\n"); }
128 printf_filtered("\t<image-arg> Argument to be passed to <image>\n");
129 if (verbose) {
130 printf_filtered("\t These arguments will be passed to\n");
131 printf_filtered("\t <image> (as standard C argv, argc)\n");
132 printf_filtered("\t when <image> is started.\n");
133 printf_filtered("\n"); }
134 printf_filtered("\t<psim-option> See below\n");
135 printf_filtered("\n");
136 printf_filtered("The following are valid <psim-option>s:\n");
137 printf_filtered("\n");
139 printf_filtered("\t-c <count> Limit the simulation to <count> iterations\n");
140 if (verbose) {
141 printf_filtered("\n");
144 printf_filtered("\t-i or -i2 Print instruction counting statistics\n");
145 if (verbose) {
146 printf_filtered("\t Specify -i2 for a more detailed display\n");
147 printf_filtered("\n");
150 printf_filtered("\t-I Print execution unit statistics\n");
151 if (verbose) { printf_filtered("\n"); }
153 printf_filtered("\t-e <os-emul> specify an OS or platform to model\n");
154 if (verbose) {
155 printf_filtered("\t Can be any of the following:\n");
156 printf_filtered("\t bug - OEA + MOTO BUG ROM calls\n");
157 printf_filtered("\t netbsd - UEA + NetBSD system calls\n");
158 printf_filtered("\t solaris - UEA + Solaris system calls\n");
159 printf_filtered("\t linux - UEA + Linux system calls\n");
160 printf_filtered("\t chirp - OEA + a few OpenBoot calls\n");
161 printf_filtered("\n"); }
163 printf_filtered("\t-E <endian> Specify the endianness of the target\n");
164 if (verbose) {
165 printf_filtered("\t Can be any of the following:\n");
166 printf_filtered("\t big - big endian target\n");
167 printf_filtered("\t little - little endian target\n");
168 printf_filtered("\n"); }
170 printf_filtered("\t-f <file> Merge <file> into the device tree\n");
171 if (verbose) { printf_filtered("\n"); }
173 printf_filtered("\t-h -? -H give more detailed usage\n");
174 if (verbose) { printf_filtered("\n"); }
176 printf_filtered("\t-m <model> Specify the processor to model (604)\n");
177 if (verbose) {
178 printf_filtered("\t Selects the processor to use when\n");
179 printf_filtered("\t modeling execution units. Includes:\n");
180 printf_filtered("\t 604, 603 and 603e\n");
181 printf_filtered("\n"); }
183 printf_filtered("\t-n <nr-smp> Specify the number of processors in SMP simulations\n");
184 if (verbose) {
185 printf_filtered("\t Specifies the number of processors that are\n");
186 printf_filtered("\t to be modeled in a symetric multi-processor (SMP)\n");
187 printf_filtered("\t simulation\n");
188 printf_filtered("\n"); }
190 printf_filtered("\t-o <dev-spec> Add device <dev-spec> to the device tree\n");
191 if (verbose) { printf_filtered("\n"); }
193 printf_filtered("\t-r <ram-size> Set RAM size in bytes (OEA environments)\n");
194 if (verbose) { printf_filtered("\n"); }
196 printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n");
197 if (verbose) { printf_filtered("\n"); }
199 printf_filtered("\n");
200 trace_usage(verbose);
201 device_usage(verbose);
202 if (verbose > 1) {
203 printf_filtered("\n");
204 print_options();
207 if (kind == SIM_OPEN_STANDALONE)
209 if (REPORT_BUGS_TO[0])
210 printf ("Report bugs to %s\n", REPORT_BUGS_TO);
211 exit (help ? 0 : 1);
215 /* Test "string" for containing a string of digits that form a number
216 between "min" and "max". The return value is the number or "err". */
217 static
218 int is_num(const char *string, int min, int max, int err)
220 int result = 0;
222 for ( ; *string; ++string)
224 if (!isdigit(*string))
226 result = err;
227 break;
229 result = result * 10 + (*string - '0');
231 if (result < min || result > max)
232 result = err;
234 return result;
237 INLINE_PSIM\
238 (char * const *)
239 psim_options(device *root,
240 char * const *argv,
241 SIM_OPEN_KIND kind)
243 device *current = root;
244 int argp;
245 if (argv == NULL)
246 return NULL;
247 argp = 0;
248 while (argv[argp] != NULL && argv[argp][0] == '-') {
249 const char *p = argv[argp] + 1;
250 const char *param;
251 while (*p != '\0') {
252 switch (*p) {
253 default:
254 printf_filtered ("Invalid Option: %s\n", argv[argp]);
255 psim_usage (0, 0, kind);
256 return NULL;
257 case 'c':
258 param = find_arg("Missing <count> option for -c (max-iterations)\n", &argp, argv);
259 tree_parse(root, "/openprom/options/max-iterations %s", param);
260 break;
261 case 'e':
262 param = find_arg("Missing <emul> option for -e (os-emul)\n", &argp, argv);
263 tree_parse(root, "/openprom/options/os-emul %s", param);
264 break;
265 case 'E':
266 /* endian spec, ignored for now */
267 param = find_arg("Missing <endian> option for -E (target-endian)\n", &argp, argv);
268 if (strcmp (param, "big") == 0)
269 tree_parse (root, "/options/little-endian? false");
270 else if (strcmp (param, "little") == 0)
271 tree_parse (root, "/options/little-endian? true");
272 else
274 printf_filtered ("Invalid <endian> option for -E (target-endian)\n");
275 psim_usage (0, 0, kind);
276 return NULL;
278 break;
279 case 'f':
280 param = find_arg("Missing <file> option for -f\n", &argp, argv);
281 psim_merge_device_file(root, param);
282 break;
283 case 'h':
284 case '?':
285 psim_usage (1, 1, kind);
286 return NULL;
287 case 'H':
288 psim_usage (2, 1, kind);
289 return NULL;
290 case 'i':
291 if (isdigit(p[1])) {
292 tree_parse(root, "/openprom/trace/print-info %c", p[1]);
293 p++;
295 else {
296 tree_parse(root, "/openprom/trace/print-info 1");
298 break;
299 case 'I':
300 tree_parse(root, "/openprom/trace/print-info 2");
301 tree_parse(root, "/openprom/options/model-issue %d",
302 MODEL_ISSUE_PROCESS);
303 break;
304 case 'm':
305 param = find_arg("Missing <model> option for -m (model)\n", &argp, argv);
306 tree_parse(root, "/openprom/options/model \"%s", param);
307 break;
308 case 'n':
309 param = find_arg("Missing <nr-smp> option for -n (smp)\n", &argp, argv);
310 tree_parse(root, "/openprom/options/smp %s", param);
311 break;
312 case 'o':
313 param = find_arg("Missing <dev-spec> option for -o\n", &argp, argv);
314 if (memcmp(param, "mpc860c0", 8) == 0)
316 if (param[8] == '\0')
317 tree_parse(root, "/options/mpc860c0 5");
318 else if (param[8] == '=' && is_num(param+9, 1, 10, 0))
320 tree_parse(root, "/options/mpc860c0 %s", param+9);
322 else error("Invalid mpc860c0 option for -o\n");
324 else
325 current = tree_parse(current, "%s", param);
326 break;
327 case 'r':
328 param = find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp, argv);
329 tree_parse(root, "/openprom/options/oea-memory-size %s",
330 param);
331 break;
332 case 't':
333 param = find_arg("Missing <trace> option for -t (trace/*)\n", &argp, argv);
334 if (param[0] == '!')
335 tree_parse(root, "/openprom/trace/%s 0", param+1);
336 else
337 tree_parse(root, "/openprom/trace/%s 1", param);
338 break;
339 case '-':
340 /* it's a long option of the form --optionname=optionvalue.
341 Such options can be passed through if we are invoked by
342 gdb. */
343 if (strstr(argv[argp], "architecture") != NULL) {
344 /* we must consume the argument here, so that we get out
345 of the loop. */
346 p = argv[argp] + strlen(argv[argp]) - 1;
347 printf_filtered("Warning - architecture parameter ignored\n");
349 else if (strcmp (argv[argp], "--help") == 0)
351 psim_usage (0, 1, kind);
352 return NULL;
354 else if (strncmp (argv[argp], "--sysroot=",
355 sizeof ("--sysroot=") - 1) == 0)
356 /* Ignore this option. */
357 p = argv[argp] + strlen(argv[argp]) - 1;
358 else if (strcmp (argv[argp], "--version") == 0)
360 extern const char version[];
361 printf ("GNU simulator %s%s\n", PKGVERSION, version);
362 printf ("Copyright (C) 2023 Free Software Foundation, Inc.\n");
363 printf ( "\
364 License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\
365 \nThis is free software: you are free to change and redistribute it.\n\
366 There is NO WARRANTY, to the extent permitted by law.\n");
367 if (kind == SIM_OPEN_STANDALONE)
368 exit (0);
369 else
370 return NULL;
372 else
374 printf_filtered ("Invalid option: %s\n", argv[argp]);
375 psim_usage (0, 0, kind);
376 return NULL;
378 break;
380 p += 1;
382 argp += 1;
384 /* force the trace node to process its options now *before* the tree
385 initialization occures */
386 device_ioctl(tree_find_device(root, "/openprom/trace"),
387 NULL, 0,
388 device_ioctl_set_trace);
391 void semantic_init(device* root);
392 semantic_init(root);
395 /* return where the options end */
396 return argv + argp;
399 INLINE_PSIM\
400 (void)
401 psim_command(device *root,
402 char * const *argv)
404 int argp = 0;
405 if (argv[argp] == NULL) {
406 return;
408 else if (strcmp(argv[argp], "trace") == 0) {
409 const char *opt = find_arg("Missing <trace> option", &argp, argv);
410 if (opt[0] == '!')
411 trace_option(opt + 1, 0);
412 else
413 trace_option(opt, 1);
415 else if (strcmp(*argv, "change-media") == 0) {
416 const char *device = find_arg("Missing device name", &argp, argv);
417 const char *media = argv[++argp];
418 device_ioctl(tree_find_device(root, device), NULL, 0,
419 device_ioctl_change_media, media);
421 else {
422 printf_filtered("Unknown PSIM command %s, try\n", argv[argp]);
423 printf_filtered(" trace <trace-option>\n");
424 printf_filtered(" change-media <device> [ <new-image> ]\n");
429 /* create the simulator proper from the device tree and executable */
431 INLINE_PSIM\
432 (psim *)
433 psim_create(const char *file_name,
434 device *root)
436 int cpu_nr;
437 const char *env;
438 psim *system;
439 os_emul *os_emulation;
440 int nr_cpus;
442 /* given this partially populated device tree, os_emul_create() uses
443 it and file_name to determine the selected emulation and hence
444 further populate the tree with any other required nodes. */
446 os_emulation = os_emul_create(file_name, root);
447 if (os_emulation == NULL)
448 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
450 /* fill in the missing real number of CPU's */
451 nr_cpus = tree_find_integer_property(root, "/openprom/options/smp");
452 if (MAX_NR_PROCESSORS < nr_cpus)
453 error("target and configured number of cpus conflict\n");
455 /* fill in the missing TARGET BYTE ORDER information */
456 current_target_byte_order
457 = (tree_find_boolean_property(root, "/options/little-endian?")
458 ? BFD_ENDIAN_LITTLE
459 : BFD_ENDIAN_BIG);
460 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
461 error("target and configured byte order conflict\n");
463 /* fill in the missing OEA/VEA information */
464 env = tree_find_string_property(root, "/openprom/options/env");
465 current_environment = ((strcmp(env, "user") == 0
466 || strcmp(env, "uea") == 0)
467 ? USER_ENVIRONMENT
468 : (strcmp(env, "virtual") == 0
469 || strcmp(env, "vea") == 0)
470 ? VIRTUAL_ENVIRONMENT
471 : (strcmp(env, "operating") == 0
472 || strcmp(env, "oea") == 0)
473 ? OPERATING_ENVIRONMENT
474 : 0);
475 if (current_environment == 0)
476 error("unreconized /options env property\n");
477 if (CURRENT_ENVIRONMENT != current_environment)
478 error("target and configured environment conflict\n");
480 /* fill in the missing ALLIGNMENT information */
481 current_alignment
482 = (tree_find_boolean_property(root, "/openprom/options/strict-alignment?")
483 ? STRICT_ALIGNMENT
484 : NONSTRICT_ALIGNMENT);
485 if (CURRENT_ALIGNMENT != current_alignment)
486 error("target and configured alignment conflict\n");
488 /* fill in the missing FLOATING POINT information */
489 current_floating_point
490 = (tree_find_boolean_property(root, "/openprom/options/floating-point?")
491 ? HARD_FLOATING_POINT
492 : SOFT_FLOATING_POINT);
493 if (CURRENT_FLOATING_POINT != current_floating_point)
494 error("target and configured floating-point conflict\n");
496 /* fill in the missing STDIO information */
497 current_stdio
498 = (tree_find_boolean_property(root, "/openprom/options/use-stdio?")
499 ? DO_USE_STDIO
500 : DONT_USE_STDIO);
501 if (CURRENT_STDIO != current_stdio)
502 error("target and configured stdio interface conflict\n");
504 /* sort out the level of detail for issue modeling */
505 current_model_issue
506 = tree_find_integer_property(root, "/openprom/options/model-issue");
507 if (CURRENT_MODEL_ISSUE != current_model_issue)
508 error("target and configured model-issue conflict\n");
510 /* sort out our model architecture - wrong.
512 FIXME: this should be obtaining the required information from the
513 device tree via the "/chosen" property "cpu" which is an instance
514 (ihandle) for the only executing processor. By converting that
515 ihandle into the corresponding cpu's phandle and then querying
516 the "name" property, the cpu type can be determined. Ok? */
518 model_set(tree_find_string_property(root, "/openprom/options/model"));
520 /* create things */
521 system = ZALLOC(psim);
522 system->events = event_queue_create();
523 system->memory = core_from_device(root);
524 system->monitor = mon_create();
525 system->nr_cpus = nr_cpus;
526 system->os_emulation = os_emulation;
527 system->devices = root;
529 /* now all the processors attaching to each their per-cpu information */
530 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
531 system->processors[cpu_nr] = cpu_create(system,
532 system->memory,
533 mon_cpu(system->monitor,
534 cpu_nr),
535 system->os_emulation,
536 cpu_nr);
539 /* dump out the contents of the device tree */
540 if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
541 tree_print(root);
542 if (ppc_trace[trace_dump_device_tree])
543 error("%s", "");
545 return system;
549 /* allow the simulation to stop/restart abnormaly */
551 INLINE_PSIM\
552 (void)
553 psim_set_halt_and_restart(psim *system,
554 void *halt_jmp_buf,
555 void *restart_jmp_buf)
557 system->path_to_halt = halt_jmp_buf;
558 system->path_to_restart = restart_jmp_buf;
561 INLINE_PSIM\
562 (void)
563 psim_clear_halt_and_restart(psim *system)
565 system->path_to_halt = NULL;
566 system->path_to_restart = NULL;
569 INLINE_PSIM\
570 (void)
571 psim_restart(psim *system,
572 int current_cpu)
574 ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus);
575 ASSERT(system->path_to_restart != NULL);
576 system->last_cpu = current_cpu;
577 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
581 static void
582 cntrl_c_simulation(void *data)
584 psim *system = data;
585 psim_halt(system,
586 psim_nr_cpus(system),
587 was_continuing,
588 GDB_SIGNAL_INT);
591 INLINE_PSIM\
592 (void)
593 psim_stop(psim *system)
595 event_queue_schedule_after_signal(psim_event_queue(system),
596 0 /*NOW*/,
597 cntrl_c_simulation,
598 system);
601 INLINE_PSIM\
602 (void)
603 psim_halt(psim *system,
604 int current_cpu,
605 stop_reason reason,
606 int signal)
608 ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus);
609 ASSERT(system->path_to_halt != NULL);
610 system->last_cpu = current_cpu;
611 system->halt_status.reason = reason;
612 system->halt_status.signal = signal;
613 if (current_cpu == system->nr_cpus) {
614 system->halt_status.cpu_nr = 0;
615 system->halt_status.program_counter =
616 cpu_get_program_counter(system->processors[0]);
618 else {
619 system->halt_status.cpu_nr = current_cpu;
620 system->halt_status.program_counter =
621 cpu_get_program_counter(system->processors[current_cpu]);
623 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
627 INLINE_PSIM\
628 (int)
629 psim_last_cpu(psim *system)
631 return system->last_cpu;
634 INLINE_PSIM\
635 (int)
636 psim_nr_cpus(psim *system)
638 return system->nr_cpus;
641 INLINE_PSIM\
642 (psim_status)
643 psim_get_status(psim *system)
645 return system->halt_status;
649 INLINE_PSIM\
650 (cpu *)
651 psim_cpu(psim *system,
652 int cpu_nr)
654 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
655 return NULL;
656 else
657 return system->processors[cpu_nr];
661 INLINE_PSIM\
662 (device *)
663 psim_device(psim *system,
664 const char *path)
666 return tree_find_device(system->devices, path);
669 INLINE_PSIM\
670 (event_queue *)
671 psim_event_queue(psim *system)
673 return system->events;
678 STATIC_INLINE_PSIM\
679 (void)
680 psim_max_iterations_exceeded(void *data)
682 psim *system = data;
683 psim_halt(system,
684 system->nr_cpus, /* halted during an event */
685 was_signalled,
686 -1);
690 INLINE_PSIM\
691 (void)
692 psim_init(psim *system)
694 int cpu_nr;
696 /* scrub the monitor */
697 mon_init(system->monitor, system->nr_cpus);
699 /* trash any pending events */
700 event_queue_init(system->events);
702 /* if needed, schedule a halt event. FIXME - In the future this
703 will be replaced by a more generic change to psim_command(). A
704 new command `schedule NNN halt' being added. */
705 if (tree_find_property(system->devices, "/openprom/options/max-iterations")) {
706 event_queue_schedule(system->events,
707 tree_find_integer_property(system->devices,
708 "/openprom/options/max-iterations") - 2,
709 psim_max_iterations_exceeded,
710 system);
713 /* scrub all the cpus */
714 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
715 cpu_init(system->processors[cpu_nr]);
717 /* init all the devices (which updates the cpus) */
718 tree_init(system->devices, system);
720 /* and the emulation (which needs an initialized device tree) */
721 os_emul_init(system->os_emulation, system->nr_cpus);
723 /* now sync each cpu against the initialized state of its registers */
724 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
725 cpu *processor = system->processors[cpu_nr];
726 cpu_synchronize_context(processor, cpu_get_program_counter(processor));
727 cpu_page_tlb_invalidate_all(processor);
730 /* force loop to start with first cpu */
731 system->last_cpu = -1;
734 INLINE_PSIM\
735 (void)
736 psim_stack(psim *system,
737 char * const *argv,
738 char * const *envp)
740 /* pass the stack device the argv/envp and let it work out what to
741 do with it */
742 device *stack_device = tree_find_device(system->devices,
743 "/openprom/init/stack");
744 if (stack_device != (device*)0) {
745 unsigned_word stack_pointer;
746 ASSERT (psim_read_register(system, 0, &stack_pointer, "sp",
747 cooked_transfer) > 0);
748 device_ioctl(stack_device,
749 NULL, /*cpu*/
750 0, /*cia*/
751 device_ioctl_create_stack,
752 stack_pointer,
753 argv,
754 envp);
760 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
761 thing */
763 INLINE_PSIM\
764 (void)
765 psim_step(psim *system)
767 volatile int keep_running = 0;
768 idecode_run_until_stop(system, &keep_running,
769 system->events, system->processors, system->nr_cpus);
772 INLINE_PSIM\
773 (void)
774 psim_run(psim *system)
776 idecode_run(system,
777 system->events, system->processors, system->nr_cpus);
781 /* storage manipulation functions */
783 INLINE_PSIM\
784 (int)
785 psim_read_register(psim *system,
786 int which_cpu,
787 void *buf,
788 const char reg[],
789 transfer_mode mode)
791 register_descriptions description;
792 char *cooked_buf;
793 cpu *processor;
795 /* find our processor */
796 if (which_cpu == MAX_NR_PROCESSORS) {
797 if (system->last_cpu == system->nr_cpus
798 || system->last_cpu == -1)
799 which_cpu = 0;
800 else
801 which_cpu = system->last_cpu;
803 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
805 processor = system->processors[which_cpu];
807 /* find the register description */
808 description = register_description(reg);
809 if (description.type == reg_invalid)
810 return 0;
811 cooked_buf = alloca (description.size);
813 /* get the cooked value */
814 switch (description.type) {
816 case reg_gpr:
817 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
818 break;
820 case reg_spr:
821 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
822 break;
824 case reg_sr:
825 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
826 break;
828 case reg_fpr:
829 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
830 break;
832 case reg_pc:
833 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
834 break;
836 case reg_cr:
837 *(creg*)cooked_buf = cpu_registers(processor)->cr;
838 break;
840 case reg_msr:
841 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
842 break;
844 case reg_fpscr:
845 *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr;
846 break;
848 case reg_insns:
849 *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
850 which_cpu);
851 break;
853 case reg_stalls:
854 if (cpu_model(processor) == NULL)
855 error("$stalls only valid if processor unit model enabled (-I)\n");
856 *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
857 break;
859 case reg_cycles:
860 if (cpu_model(processor) == NULL)
861 error("$cycles only valid if processor unit model enabled (-I)\n");
862 *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
863 break;
865 #ifdef WITH_ALTIVEC
866 case reg_vr:
867 *(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index];
868 break;
870 case reg_vscr:
871 *(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr;
872 break;
873 #endif
875 #ifdef WITH_E500
876 case reg_gprh:
877 *(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index];
878 break;
880 case reg_evr:
881 *(uint64_t*)cooked_buf = EVR(description.index);
882 break;
884 case reg_acc:
885 *(accreg*)cooked_buf = cpu_registers(processor)->e500.acc;
886 break;
887 #endif
889 default:
890 printf_filtered("psim_read_register(processor=%p,buf=%p,reg=%s) %s\n",
891 processor, buf, reg, "read of this register unimplemented");
892 break;
896 /* the PSIM internal values are in host order. To fetch raw data,
897 they need to be converted into target order and then returned */
898 if (mode == raw_transfer) {
899 /* FIXME - assumes that all registers are simple integers */
900 switch (description.size) {
901 case 1:
902 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
903 break;
904 case 2:
905 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
906 break;
907 case 4:
908 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
909 break;
910 case 8:
911 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
912 break;
913 #ifdef WITH_ALTIVEC
914 case 16:
915 if (HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
917 union { vreg v; unsigned_8 d[2]; } h, t;
918 memcpy(&h.v/*dest*/, cooked_buf/*src*/, description.size);
919 { _SWAP_8(t.d[0] =, h.d[1]); }
920 { _SWAP_8(t.d[1] =, h.d[0]); }
921 memcpy(buf/*dest*/, &t/*src*/, description.size);
922 break;
924 else
925 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
926 break;
927 #endif
930 else {
931 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
934 return description.size;
939 INLINE_PSIM\
940 (int)
941 psim_write_register(psim *system,
942 int which_cpu,
943 const void *buf,
944 const char reg[],
945 transfer_mode mode)
947 cpu *processor;
948 register_descriptions description;
949 char *cooked_buf;
951 /* find our processor */
952 if (which_cpu == MAX_NR_PROCESSORS) {
953 if (system->last_cpu == system->nr_cpus
954 || system->last_cpu == -1)
955 which_cpu = 0;
956 else
957 which_cpu = system->last_cpu;
960 /* find the description of the register */
961 description = register_description(reg);
962 if (description.type == reg_invalid)
963 return 0;
964 cooked_buf = alloca (description.size);
966 if (which_cpu == -1) {
967 int i;
968 for (i = 0; i < system->nr_cpus; i++)
969 psim_write_register(system, i, buf, reg, mode);
970 return description.size;
972 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
974 processor = system->processors[which_cpu];
976 /* If the data is comming in raw (target order), need to cook it
977 into host order before putting it into PSIM's internal structures */
978 if (mode == raw_transfer) {
979 switch (description.size) {
980 case 1:
981 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
982 break;
983 case 2:
984 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
985 break;
986 case 4:
987 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
988 break;
989 case 8:
990 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
991 break;
992 #ifdef WITH_ALTIVEC
993 case 16:
994 if (HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
996 union { vreg v; unsigned_8 d[2]; } h, t;
997 memcpy(&t.v/*dest*/, buf/*src*/, description.size);
998 { _SWAP_8(h.d[0] =, t.d[1]); }
999 { _SWAP_8(h.d[1] =, t.d[0]); }
1000 memcpy(cooked_buf/*dest*/, &h/*src*/, description.size);
1001 break;
1003 else
1004 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
1005 #endif
1008 else {
1009 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
1012 /* put the cooked value into the register */
1013 switch (description.type) {
1015 case reg_gpr:
1016 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
1017 break;
1019 case reg_fpr:
1020 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
1021 break;
1023 case reg_pc:
1024 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
1025 break;
1027 case reg_spr:
1028 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
1029 break;
1031 case reg_sr:
1032 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
1033 break;
1035 case reg_cr:
1036 cpu_registers(processor)->cr = *(creg*)cooked_buf;
1037 break;
1039 case reg_msr:
1040 cpu_registers(processor)->msr = *(msreg*)cooked_buf;
1041 break;
1043 case reg_fpscr:
1044 cpu_registers(processor)->fpscr = *(fpscreg*)cooked_buf;
1045 break;
1047 #ifdef WITH_E500
1048 case reg_gprh:
1049 cpu_registers(processor)->e500.gprh[description.index] = *(gpreg*)cooked_buf;
1050 break;
1052 case reg_evr:
1054 uint64_t v;
1055 v = *(uint64_t*)cooked_buf;
1056 cpu_registers(processor)->e500.gprh[description.index] = v >> 32;
1057 cpu_registers(processor)->gpr[description.index] = v;
1058 break;
1061 case reg_acc:
1062 cpu_registers(processor)->e500.acc = *(accreg*)cooked_buf;
1063 break;
1064 #endif
1066 #ifdef WITH_ALTIVEC
1067 case reg_vr:
1068 cpu_registers(processor)->altivec.vr[description.index] = *(vreg*)cooked_buf;
1069 break;
1071 case reg_vscr:
1072 cpu_registers(processor)->altivec.vscr = *(vscreg*)cooked_buf;
1073 break;
1074 #endif
1076 default:
1077 printf_filtered("psim_write_register(processor=%p,cooked_buf=%p,reg=%s) %s\n",
1078 processor, cooked_buf, reg,
1079 "read of this register unimplemented");
1080 break;
1084 return description.size;
1089 INLINE_PSIM\
1090 (unsigned)
1091 psim_read_memory(psim *system,
1092 int which_cpu,
1093 void *buffer,
1094 unsigned_word vaddr,
1095 unsigned nr_bytes)
1097 cpu *processor;
1098 if (which_cpu == MAX_NR_PROCESSORS) {
1099 if (system->last_cpu == system->nr_cpus
1100 || system->last_cpu == -1)
1101 which_cpu = 0;
1102 else
1103 which_cpu = system->last_cpu;
1105 processor = system->processors[which_cpu];
1106 return vm_data_map_read_buffer(cpu_data_map(processor),
1107 buffer, vaddr, nr_bytes,
1108 NULL, -1);
1112 INLINE_PSIM\
1113 (unsigned)
1114 psim_write_memory(psim *system,
1115 int which_cpu,
1116 const void *buffer,
1117 unsigned_word vaddr,
1118 unsigned nr_bytes,
1119 int violate_read_only_section)
1121 cpu *processor;
1122 if (which_cpu == MAX_NR_PROCESSORS) {
1123 if (system->last_cpu == system->nr_cpus
1124 || system->last_cpu == -1)
1125 which_cpu = 0;
1126 else
1127 which_cpu = system->last_cpu;
1129 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
1130 processor = system->processors[which_cpu];
1131 return vm_data_map_write_buffer(cpu_data_map(processor),
1132 buffer, vaddr, nr_bytes, 1/*violate-read-only*/,
1133 NULL, -1);
1137 INLINE_PSIM\
1138 (void)
1139 psim_print_info(psim *system,
1140 int verbose)
1142 mon_print_info(system, system->monitor, verbose);
1146 /* Merge a device tree and a device file. */
1148 INLINE_PSIM\
1149 (void)
1150 psim_merge_device_file(device *root,
1151 const char *file_name)
1153 FILE *description;
1154 int line_nr;
1155 char device_path[1000];
1156 device *current;
1158 /* try opening the file */
1159 description = fopen(file_name, "r");
1160 if (description == NULL) {
1161 perror(file_name);
1162 error("Invalid file %s specified", file_name);
1165 line_nr = 0;
1166 current = root;
1167 while (fgets(device_path, sizeof(device_path), description)) {
1168 char *device;
1169 /* check that the full line was read */
1170 if (strchr(device_path, '\n') == NULL) {
1171 fclose(description);
1172 error("%s:%d: line to long - %s",
1173 file_name, line_nr, device_path);
1175 else
1176 *strchr(device_path, '\n') = '\0';
1177 line_nr++;
1178 /* skip comments ("#" or ";") and blank lines lines */
1179 for (device = device_path;
1180 *device != '\0' && isspace(*device);
1181 device++);
1182 if (device[0] == '#'
1183 || device[0] == ';'
1184 || device[0] == '\0')
1185 continue;
1186 /* merge any appended lines */
1187 while (device_path[strlen(device_path) - 1] == '\\') {
1188 int curlen = strlen(device_path) - 1;
1189 /* zap \ */
1190 device_path[curlen] = '\0';
1191 /* append the next line */
1192 if (!fgets(device_path + curlen, sizeof(device_path) - curlen, description)) {
1193 fclose(description);
1194 error("%s:%d: unexpected eof in line continuation - %s",
1195 file_name, line_nr, device_path);
1197 if (strchr(device_path, '\n') == NULL) {
1198 fclose(description);
1199 error("%s:%d: line to long - %s",
1200 file_name, line_nr, device_path);
1202 else
1203 *strchr(device_path, '\n') = '\0';
1204 line_nr++;
1206 /* parse this line */
1207 current = tree_parse(current, "%s", device);
1209 fclose(description);
1213 #endif /* _PSIM_C_ */