Automatic date update in version.in
[binutils-gdb.git] / sim / ppc / psim.c
blobb2fff6ad837cfc724bb89262c22918b5b642aae7
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) 2024 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 recognized 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 ATTRIBUTE_NORETURN 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 union {
793 uint8_t bytes[16];
794 unsigned_word unsigned_word;
795 unsigned_1 unsigned_1;
796 unsigned_2 unsigned_2;
797 unsigned_4 unsigned_4;
798 unsigned_8 unsigned_8;
799 unsigned_16 unsigned_16;
800 creg creg;
801 fpreg fpreg;
802 fpscreg fpscreg;
803 gpreg gpreg;
804 msreg msreg;
805 spreg spreg;
806 sreg sreg;
807 } cooked_buf;
808 cpu *processor;
810 /* find our processor */
811 if (which_cpu == MAX_NR_PROCESSORS) {
812 if (system->last_cpu == system->nr_cpus
813 || system->last_cpu == -1)
814 which_cpu = 0;
815 else
816 which_cpu = system->last_cpu;
818 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
820 processor = system->processors[which_cpu];
822 /* find the register description */
823 description = register_description(reg);
824 if (description.type == reg_invalid)
825 return 0;
827 /* get the cooked value */
828 switch (description.type) {
830 case reg_gpr:
831 cooked_buf.gpreg = cpu_registers(processor)->gpr[description.index];
832 break;
834 case reg_spr:
835 cooked_buf.spreg = cpu_registers(processor)->spr[description.index];
836 break;
838 case reg_sr:
839 cooked_buf.sreg = cpu_registers(processor)->sr[description.index];
840 break;
842 case reg_fpr:
843 cooked_buf.fpreg = cpu_registers(processor)->fpr[description.index];
844 break;
846 case reg_pc:
847 cooked_buf.unsigned_word = cpu_get_program_counter(processor);
848 break;
850 case reg_cr:
851 cooked_buf.creg = cpu_registers(processor)->cr;
852 break;
854 case reg_msr:
855 cooked_buf.msreg = cpu_registers(processor)->msr;
856 break;
858 case reg_fpscr:
859 cooked_buf.fpscreg = cpu_registers(processor)->fpscr;
860 break;
862 case reg_insns:
863 cooked_buf.unsigned_word = mon_get_number_of_insns(system->monitor,
864 which_cpu);
865 break;
867 case reg_stalls:
868 if (cpu_model(processor) == NULL)
869 error("$stalls only valid if processor unit model enabled (-I)\n");
870 cooked_buf.unsigned_word = model_get_number_of_stalls(cpu_model(processor));
871 break;
873 case reg_cycles:
874 if (cpu_model(processor) == NULL)
875 error("$cycles only valid if processor unit model enabled (-I)\n");
876 cooked_buf.unsigned_word = model_get_number_of_cycles(cpu_model(processor));
877 break;
879 #ifdef WITH_ALTIVEC
880 case reg_vr:
881 cooked_buf.vreg = cpu_registers(processor)->altivec.vr[description.index];
882 break;
884 case reg_vscr:
885 cooked_buf.vscreg = cpu_registers(processor)->altivec.vscr;
886 break;
887 #endif
889 #ifdef WITH_E500
890 case reg_gprh:
891 cooked_buf.gpreg = cpu_registers(processor)->e500.gprh[description.index];
892 break;
894 case reg_evr:
895 cooked_buf.uint64_t = EVR(description.index);
896 break;
898 case reg_acc:
899 cooked_buf.accreg = cpu_registers(processor)->e500.acc;
900 break;
901 #endif
903 default:
904 printf_filtered("psim_read_register(processor=%p,buf=%p,reg=%s) %s\n",
905 processor, buf, reg, "read of this register unimplemented");
906 return 0;
909 /* the PSIM internal values are in host order. To fetch raw data,
910 they need to be converted into target order and then returned */
911 if (mode == raw_transfer) {
912 /* FIXME - assumes that all registers are simple integers */
913 switch (description.size) {
914 case 1:
915 *(unsigned_1*)buf = H2T_1(cooked_buf.unsigned_1);
916 break;
917 case 2:
918 *(unsigned_2*)buf = H2T_2(cooked_buf.unsigned_2);
919 break;
920 case 4:
921 *(unsigned_4*)buf = H2T_4(cooked_buf.unsigned_4);
922 break;
923 case 8:
924 *(unsigned_8*)buf = H2T_8(cooked_buf.unsigned_8);
925 break;
926 case 16:
928 unsigned_16 v = H2T_16(cooked_buf.unsigned_16);
929 memcpy(buf/*dest*/, &v, description.size);
931 break;
934 else {
935 memcpy(buf/*dest*/, cooked_buf.bytes/*src*/, description.size);
938 return description.size;
943 INLINE_PSIM\
944 (int)
945 psim_write_register(psim *system,
946 int which_cpu,
947 const void *buf,
948 const char reg[],
949 transfer_mode mode)
951 cpu *processor;
952 register_descriptions description;
953 union {
954 uint8_t bytes[16];
955 unsigned_word unsigned_word;
956 unsigned_1 unsigned_1;
957 unsigned_2 unsigned_2;
958 unsigned_4 unsigned_4;
959 unsigned_8 unsigned_8;
960 unsigned_16 unsigned_16;
961 creg creg;
962 fpreg fpreg;
963 fpscreg fpscreg;
964 gpreg gpreg;
965 msreg msreg;
966 spreg spreg;
967 sreg sreg;
968 } cooked_buf;
970 /* find our processor */
971 if (which_cpu == MAX_NR_PROCESSORS) {
972 if (system->last_cpu == system->nr_cpus
973 || system->last_cpu == -1)
974 which_cpu = 0;
975 else
976 which_cpu = system->last_cpu;
979 /* find the description of the register */
980 description = register_description(reg);
981 if (description.type == reg_invalid)
982 return 0;
984 if (which_cpu == -1) {
985 int i;
986 for (i = 0; i < system->nr_cpus; i++)
987 psim_write_register(system, i, buf, reg, mode);
988 return description.size;
990 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
992 processor = system->processors[which_cpu];
994 /* If the data is coming in raw (target order), need to cook it
995 into host order before putting it into PSIM's internal structures */
996 if (mode == raw_transfer) {
997 switch (description.size) {
998 case 1:
999 cooked_buf.unsigned_1 = T2H_1(*(unsigned_1*)buf);
1000 break;
1001 case 2:
1002 cooked_buf.unsigned_2 = T2H_2(*(unsigned_2*)buf);
1003 break;
1004 case 4:
1005 cooked_buf.unsigned_4 = T2H_4(*(unsigned_4*)buf);
1006 break;
1007 case 8:
1008 cooked_buf.unsigned_8 = T2H_8(*(unsigned_8*)buf);
1009 break;
1010 case 16:
1011 cooked_buf.unsigned_16 = T2H_16(*(unsigned_16*)buf);
1012 break;
1015 else {
1016 memcpy(cooked_buf.bytes/*dest*/, buf/*src*/, description.size);
1019 /* put the cooked value into the register */
1020 switch (description.type) {
1022 case reg_gpr:
1023 cpu_registers(processor)->gpr[description.index] = cooked_buf.gpreg;
1024 break;
1026 case reg_fpr:
1027 cpu_registers(processor)->fpr[description.index] = cooked_buf.fpreg;
1028 break;
1030 case reg_pc:
1031 cpu_set_program_counter(processor, cooked_buf.unsigned_word);
1032 break;
1034 case reg_spr:
1035 cpu_registers(processor)->spr[description.index] = cooked_buf.spreg;
1036 break;
1038 case reg_sr:
1039 cpu_registers(processor)->sr[description.index] = cooked_buf.sreg;
1040 break;
1042 case reg_cr:
1043 cpu_registers(processor)->cr = cooked_buf.creg;
1044 break;
1046 case reg_msr:
1047 cpu_registers(processor)->msr = cooked_buf.msreg;
1048 break;
1050 case reg_fpscr:
1051 cpu_registers(processor)->fpscr = cooked_buf.fpscreg;
1052 break;
1054 #ifdef WITH_E500
1055 case reg_gprh:
1056 cpu_registers(processor)->e500.gprh[description.index] = cooked_buf.gpreg;
1057 break;
1059 case reg_evr:
1061 uint64_t v;
1062 v = cooked_buf.uint64_t;
1063 cpu_registers(processor)->e500.gprh[description.index] = v >> 32;
1064 cpu_registers(processor)->gpr[description.index] = v;
1065 break;
1068 case reg_acc:
1069 cpu_registers(processor)->e500.acc = cooked_buf.accreg;
1070 break;
1071 #endif
1073 #ifdef WITH_ALTIVEC
1074 case reg_vr:
1075 cpu_registers(processor)->altivec.vr[description.index] = cooked_buf.vreg;
1076 break;
1078 case reg_vscr:
1079 cpu_registers(processor)->altivec.vscr = cooked_buf.vscreg;
1080 break;
1081 #endif
1083 default:
1084 printf_filtered("psim_write_register(processor=%p,buf=%p,reg=%s) %s\n",
1085 processor, buf, reg, "read of this register unimplemented");
1086 return 0;
1089 return description.size;
1094 INLINE_PSIM\
1095 (unsigned)
1096 psim_read_memory(psim *system,
1097 int which_cpu,
1098 void *buffer,
1099 unsigned_word vaddr,
1100 unsigned nr_bytes)
1102 cpu *processor;
1103 if (which_cpu == MAX_NR_PROCESSORS) {
1104 if (system->last_cpu == system->nr_cpus
1105 || system->last_cpu == -1)
1106 which_cpu = 0;
1107 else
1108 which_cpu = system->last_cpu;
1110 processor = system->processors[which_cpu];
1111 return vm_data_map_read_buffer(cpu_data_map(processor),
1112 buffer, vaddr, nr_bytes,
1113 NULL, -1);
1117 INLINE_PSIM\
1118 (unsigned)
1119 psim_write_memory(psim *system,
1120 int which_cpu,
1121 const void *buffer,
1122 unsigned_word vaddr,
1123 unsigned nr_bytes,
1124 int violate_read_only_section)
1126 cpu *processor;
1127 if (which_cpu == MAX_NR_PROCESSORS) {
1128 if (system->last_cpu == system->nr_cpus
1129 || system->last_cpu == -1)
1130 which_cpu = 0;
1131 else
1132 which_cpu = system->last_cpu;
1134 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
1135 processor = system->processors[which_cpu];
1136 return vm_data_map_write_buffer(cpu_data_map(processor),
1137 buffer, vaddr, nr_bytes, 1/*violate-read-only*/,
1138 NULL, -1);
1142 INLINE_PSIM\
1143 (void)
1144 psim_print_info(psim *system,
1145 int verbose)
1147 mon_print_info(system, system->monitor, verbose);
1151 /* Merge a device tree and a device file. */
1153 INLINE_PSIM\
1154 (void)
1155 psim_merge_device_file(device *root,
1156 const char *file_name)
1158 FILE *description;
1159 int line_nr;
1160 char device_path[1000];
1161 device *current;
1163 /* try opening the file */
1164 description = fopen(file_name, "r");
1165 if (description == NULL) {
1166 perror(file_name);
1167 error("Invalid file %s specified", file_name);
1170 line_nr = 0;
1171 current = root;
1172 while (fgets(device_path, sizeof(device_path), description)) {
1173 char *device;
1174 /* check that the full line was read */
1175 if (strchr(device_path, '\n') == NULL) {
1176 fclose(description);
1177 error("%s:%d: line to long - %s",
1178 file_name, line_nr, device_path);
1180 else
1181 *strchr(device_path, '\n') = '\0';
1182 line_nr++;
1183 /* skip comments ("#" or ";") and blank lines lines */
1184 for (device = device_path;
1185 *device != '\0' && isspace(*device);
1186 device++);
1187 if (device[0] == '#'
1188 || device[0] == ';'
1189 || device[0] == '\0')
1190 continue;
1191 /* merge any appended lines */
1192 while (device_path[strlen(device_path) - 1] == '\\') {
1193 int curlen = strlen(device_path) - 1;
1194 /* zap \ */
1195 device_path[curlen] = '\0';
1196 /* append the next line */
1197 if (!fgets(device_path + curlen, sizeof(device_path) - curlen, description)) {
1198 fclose(description);
1199 error("%s:%d: unexpected eof in line continuation - %s",
1200 file_name, line_nr, device_path);
1202 if (strchr(device_path, '\n') == NULL) {
1203 fclose(description);
1204 error("%s:%d: line to long - %s",
1205 file_name, line_nr, device_path);
1207 else
1208 *strchr(device_path, '\n') = '\0';
1209 line_nr++;
1211 /* parse this line */
1212 current = tree_parse(current, "%s", device);
1214 fclose(description);
1218 #endif /* _PSIM_C_ */