]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/psim.c
sim: clean up C11 header includes
[thirdparty/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 #include <stdlib.h>
35 #include <setjmp.h>
36 #include <string.h>
37
38 #include "bfd.h"
39 #include "libiberty.h"
40 #include "gdb/signals.h"
41
42 /* system structure, actual size of processor array determined at
43 runtime */
44
45 struct _psim {
46 event_queue *events;
47 device *devices;
48 mon *monitor;
49 os_emul *os_emulation;
50 core *memory;
51
52 /* escape routine for inner functions */
53 void *path_to_halt;
54 void *path_to_restart;
55
56 /* status from last halt */
57 psim_status halt_status;
58
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];
63 };
64
65
66 int current_target_byte_order;
67 int current_host_byte_order;
68 int current_environment;
69 int current_alignment;
70 int current_floating_point;
71 int current_model_issue = MODEL_ISSUE_IGNORE;
72 int current_stdio = DO_USE_STDIO;
73 model_enum current_model = WITH_DEFAULT_MODEL;
74
75
76 /* create the device tree */
77
78 INLINE_PSIM\
79 (device *)
80 psim_tree(void)
81 {
82 device *root = tree_parse(NULL, "core");
83 tree_parse(root, "/aliases");
84 tree_parse(root, "/options");
85 tree_parse(root, "/chosen");
86 tree_parse(root, "/packages");
87 tree_parse(root, "/cpus");
88 tree_parse(root, "/openprom");
89 tree_parse(root, "/openprom/init");
90 tree_parse(root, "/openprom/trace");
91 tree_parse(root, "/openprom/options");
92 return root;
93 }
94
95 STATIC_INLINE_PSIM\
96 (char *)
97 find_arg(char *err_msg,
98 int *ptr_to_argp,
99 char **argv)
100 {
101 *ptr_to_argp += 1;
102 if (argv[*ptr_to_argp] == NULL)
103 error(err_msg);
104 return argv[*ptr_to_argp];
105 }
106
107 INLINE_PSIM\
108 (void)
109 psim_usage (int verbose, int help, SIM_OPEN_KIND kind)
110 {
111 printf_filtered("Usage:\n");
112 printf_filtered("\n");
113 printf_filtered("\tpsim [ <psim-option> ... ] <image> [ <image-arg> ... ]\n");
114 printf_filtered("\n");
115 printf_filtered("Where\n");
116 printf_filtered("\n");
117 printf_filtered("\t<image> Name of the PowerPC program to run.\n");
118 if (verbose) {
119 printf_filtered("\t This can either be a PowerPC binary or\n");
120 printf_filtered("\t a text file containing a device tree\n");
121 printf_filtered("\t specification.\n");
122 printf_filtered("\t PSIM will attempt to determine from the\n");
123 printf_filtered("\t specified <image> the intended emulation\n");
124 printf_filtered("\t environment.\n");
125 printf_filtered("\t If PSIM gets it wrong, the emulation\n");
126 printf_filtered("\t environment can be specified using the\n");
127 printf_filtered("\t `-e' option (described below).\n");
128 printf_filtered("\n"); }
129 printf_filtered("\t<image-arg> Argument to be passed to <image>\n");
130 if (verbose) {
131 printf_filtered("\t These arguments will be passed to\n");
132 printf_filtered("\t <image> (as standard C argv, argc)\n");
133 printf_filtered("\t when <image> is started.\n");
134 printf_filtered("\n"); }
135 printf_filtered("\t<psim-option> See below\n");
136 printf_filtered("\n");
137 printf_filtered("The following are valid <psim-option>s:\n");
138 printf_filtered("\n");
139
140 printf_filtered("\t-c <count> Limit the simulation to <count> iterations\n");
141 if (verbose) {
142 printf_filtered("\n");
143 }
144
145 printf_filtered("\t-i or -i2 Print instruction counting statistics\n");
146 if (verbose) {
147 printf_filtered("\t Specify -i2 for a more detailed display\n");
148 printf_filtered("\n");
149 }
150
151 printf_filtered("\t-I Print execution unit statistics\n");
152 if (verbose) { printf_filtered("\n"); }
153
154 printf_filtered("\t-e <os-emul> specify an OS or platform to model\n");
155 if (verbose) {
156 printf_filtered("\t Can be any of the following:\n");
157 printf_filtered("\t bug - OEA + MOTO BUG ROM calls\n");
158 printf_filtered("\t netbsd - UEA + NetBSD system calls\n");
159 printf_filtered("\t solaris - UEA + Solaris system calls\n");
160 printf_filtered("\t linux - UEA + Linux system calls\n");
161 printf_filtered("\t chirp - OEA + a few OpenBoot calls\n");
162 printf_filtered("\n"); }
163
164 printf_filtered("\t-E <endian> Specify the endianness of the target\n");
165 if (verbose) {
166 printf_filtered("\t Can be any of the following:\n");
167 printf_filtered("\t big - big endian target\n");
168 printf_filtered("\t little - little endian target\n");
169 printf_filtered("\n"); }
170
171 printf_filtered("\t-f <file> Merge <file> into the device tree\n");
172 if (verbose) { printf_filtered("\n"); }
173
174 printf_filtered("\t-h -? -H give more detailed usage\n");
175 if (verbose) { printf_filtered("\n"); }
176
177 printf_filtered("\t-m <model> Specify the processor to model (604)\n");
178 if (verbose) {
179 printf_filtered("\t Selects the processor to use when\n");
180 printf_filtered("\t modeling execution units. Includes:\n");
181 printf_filtered("\t 604, 603 and 603e\n");
182 printf_filtered("\n"); }
183
184 printf_filtered("\t-n <nr-smp> Specify the number of processors in SMP simulations\n");
185 if (verbose) {
186 printf_filtered("\t Specifies the number of processors that are\n");
187 printf_filtered("\t to be modeled in a symetric multi-processor (SMP)\n");
188 printf_filtered("\t simulation\n");
189 printf_filtered("\n"); }
190
191 printf_filtered("\t-o <dev-spec> Add device <dev-spec> to the device tree\n");
192 if (verbose) { printf_filtered("\n"); }
193
194 printf_filtered("\t-r <ram-size> Set RAM size in bytes (OEA environments)\n");
195 if (verbose) { printf_filtered("\n"); }
196
197 printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n");
198 if (verbose) { printf_filtered("\n"); }
199
200 printf_filtered("\n");
201 trace_usage(verbose);
202 device_usage(verbose);
203 if (verbose > 1) {
204 printf_filtered("\n");
205 print_options();
206 }
207
208 if (kind == SIM_OPEN_STANDALONE)
209 {
210 if (REPORT_BUGS_TO[0])
211 printf ("Report bugs to %s\n", REPORT_BUGS_TO);
212 exit (help ? 0 : 1);
213 }
214 }
215
216 /* Test "string" for containing a string of digits that form a number
217 between "min" and "max". The return value is the number or "err". */
218 static
219 int is_num( char *string, int min, int max, int err)
220 {
221 int result = 0;
222
223 for ( ; *string; ++string)
224 {
225 if (!isdigit(*string))
226 {
227 result = err;
228 break;
229 }
230 result = result * 10 + (*string - '0');
231 }
232 if (result < min || result > max)
233 result = err;
234
235 return result;
236 }
237
238 INLINE_PSIM\
239 (char **)
240 psim_options(device *root,
241 char **argv,
242 SIM_OPEN_KIND kind)
243 {
244 device *current = root;
245 int argp;
246 if (argv == NULL)
247 return NULL;
248 argp = 0;
249 while (argv[argp] != NULL && argv[argp][0] == '-') {
250 char *p = argv[argp] + 1;
251 char *param;
252 while (*p != '\0') {
253 switch (*p) {
254 default:
255 printf_filtered ("Invalid Option: %s\n", argv[argp]);
256 psim_usage (0, 0, kind);
257 return NULL;
258 case 'c':
259 param = find_arg("Missing <count> option for -c (max-iterations)\n", &argp, argv);
260 tree_parse(root, "/openprom/options/max-iterations %s", param);
261 break;
262 case 'e':
263 param = find_arg("Missing <emul> option for -e (os-emul)\n", &argp, argv);
264 tree_parse(root, "/openprom/options/os-emul %s", param);
265 break;
266 case 'E':
267 /* endian spec, ignored for now */
268 param = find_arg("Missing <endian> option for -E (target-endian)\n", &argp, argv);
269 if (strcmp (param, "big") == 0)
270 tree_parse (root, "/options/little-endian? false");
271 else if (strcmp (param, "little") == 0)
272 tree_parse (root, "/options/little-endian? true");
273 else
274 {
275 printf_filtered ("Invalid <endian> option for -E (target-endian)\n");
276 psim_usage (0, 0, kind);
277 return NULL;
278 }
279 break;
280 case 'f':
281 param = find_arg("Missing <file> option for -f\n", &argp, argv);
282 psim_merge_device_file(root, param);
283 break;
284 case 'h':
285 case '?':
286 psim_usage (1, 1, kind);
287 return NULL;
288 case 'H':
289 psim_usage (2, 1, kind);
290 return NULL;
291 case 'i':
292 if (isdigit(p[1])) {
293 tree_parse(root, "/openprom/trace/print-info %c", p[1]);
294 p++;
295 }
296 else {
297 tree_parse(root, "/openprom/trace/print-info 1");
298 }
299 break;
300 case 'I':
301 tree_parse(root, "/openprom/trace/print-info 2");
302 tree_parse(root, "/openprom/options/model-issue %d",
303 MODEL_ISSUE_PROCESS);
304 break;
305 case 'm':
306 param = find_arg("Missing <model> option for -m (model)\n", &argp, argv);
307 tree_parse(root, "/openprom/options/model \"%s", param);
308 break;
309 case 'n':
310 param = find_arg("Missing <nr-smp> option for -n (smp)\n", &argp, argv);
311 tree_parse(root, "/openprom/options/smp %s", param);
312 break;
313 case 'o':
314 param = find_arg("Missing <dev-spec> option for -o\n", &argp, argv);
315 if (memcmp(param, "mpc860c0", 8) == 0)
316 {
317 if (param[8] == '\0')
318 tree_parse(root, "/options/mpc860c0 5");
319 else if (param[8] == '=' && is_num(param+9, 1, 10, 0))
320 {
321 tree_parse(root, "/options/mpc860c0 %s", param+9);
322 }
323 else error("Invalid mpc860c0 option for -o\n");
324 }
325 else
326 current = tree_parse(current, "%s", param);
327 break;
328 case 'r':
329 param = find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp, argv);
330 tree_parse(root, "/openprom/options/oea-memory-size %s",
331 param);
332 break;
333 case 't':
334 param = find_arg("Missing <trace> option for -t (trace/*)\n", &argp, argv);
335 if (param[0] == '!')
336 tree_parse(root, "/openprom/trace/%s 0", param+1);
337 else
338 tree_parse(root, "/openprom/trace/%s 1", param);
339 break;
340 case '-':
341 /* it's a long option of the form --optionname=optionvalue.
342 Such options can be passed through if we are invoked by
343 gdb. */
344 if (strstr(argv[argp], "architecture") != NULL) {
345 /* we must consume the argument here, so that we get out
346 of the loop. */
347 p = argv[argp] + strlen(argv[argp]) - 1;
348 printf_filtered("Warning - architecture parameter ignored\n");
349 }
350 else if (strcmp (argv[argp], "--help") == 0)
351 {
352 psim_usage (0, 1, kind);
353 return NULL;
354 }
355 else if (strncmp (argv[argp], "--sysroot=",
356 sizeof ("--sysroot=") - 1) == 0)
357 /* Ignore this option. */
358 p = argv[argp] + strlen(argv[argp]) - 1;
359 else if (strcmp (argv[argp], "--version") == 0)
360 {
361 extern const char version[];
362 printf ("GNU simulator %s%s\n", PKGVERSION, version);
363 if (kind == SIM_OPEN_STANDALONE)
364 exit (0);
365 else
366 return NULL;
367 }
368 else
369 {
370 printf_filtered ("Invalid option: %s\n", argv[argp]);
371 psim_usage (0, 0, kind);
372 return NULL;
373 }
374 break;
375 }
376 p += 1;
377 }
378 argp += 1;
379 }
380 /* force the trace node to process its options now *before* the tree
381 initialization occures */
382 device_ioctl(tree_find_device(root, "/openprom/trace"),
383 NULL, 0,
384 device_ioctl_set_trace);
385
386 {
387 void semantic_init(device* root);
388 semantic_init(root);
389 }
390
391 /* return where the options end */
392 return argv + argp;
393 }
394
395 INLINE_PSIM\
396 (void)
397 psim_command(device *root,
398 char **argv)
399 {
400 int argp = 0;
401 if (argv[argp] == NULL) {
402 return;
403 }
404 else if (strcmp(argv[argp], "trace") == 0) {
405 const char *opt = find_arg("Missing <trace> option", &argp, argv);
406 if (opt[0] == '!')
407 trace_option(opt + 1, 0);
408 else
409 trace_option(opt, 1);
410 }
411 else if (strcmp(*argv, "change-media") == 0) {
412 char *device = find_arg("Missing device name", &argp, argv);
413 char *media = argv[++argp];
414 device_ioctl(tree_find_device(root, device), NULL, 0,
415 device_ioctl_change_media, media);
416 }
417 else {
418 printf_filtered("Unknown PSIM command %s, try\n", argv[argp]);
419 printf_filtered(" trace <trace-option>\n");
420 printf_filtered(" change-media <device> [ <new-image> ]\n");
421 }
422 }
423
424
425 /* create the simulator proper from the device tree and executable */
426
427 INLINE_PSIM\
428 (psim *)
429 psim_create(const char *file_name,
430 device *root)
431 {
432 int cpu_nr;
433 const char *env;
434 psim *system;
435 os_emul *os_emulation;
436 int nr_cpus;
437
438 /* given this partially populated device tree, os_emul_create() uses
439 it and file_name to determine the selected emulation and hence
440 further populate the tree with any other required nodes. */
441
442 os_emulation = os_emul_create(file_name, root);
443 if (os_emulation == NULL)
444 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
445
446 /* fill in the missing real number of CPU's */
447 nr_cpus = tree_find_integer_property(root, "/openprom/options/smp");
448 if (MAX_NR_PROCESSORS < nr_cpus)
449 error("target and configured number of cpus conflict\n");
450
451 /* fill in the missing TARGET BYTE ORDER information */
452 current_target_byte_order
453 = (tree_find_boolean_property(root, "/options/little-endian?")
454 ? LITTLE_ENDIAN
455 : BIG_ENDIAN);
456 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
457 error("target and configured byte order conflict\n");
458
459 /* fill in the missing HOST BYTE ORDER information */
460 current_host_byte_order = (current_host_byte_order = 1,
461 (*(char*)(&current_host_byte_order)
462 ? LITTLE_ENDIAN
463 : BIG_ENDIAN));
464 if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
465 error("host and configured byte order conflict\n");
466
467 /* fill in the missing OEA/VEA information */
468 env = tree_find_string_property(root, "/openprom/options/env");
469 current_environment = ((strcmp(env, "user") == 0
470 || strcmp(env, "uea") == 0)
471 ? USER_ENVIRONMENT
472 : (strcmp(env, "virtual") == 0
473 || strcmp(env, "vea") == 0)
474 ? VIRTUAL_ENVIRONMENT
475 : (strcmp(env, "operating") == 0
476 || strcmp(env, "oea") == 0)
477 ? OPERATING_ENVIRONMENT
478 : 0);
479 if (current_environment == 0)
480 error("unreconized /options env property\n");
481 if (CURRENT_ENVIRONMENT != current_environment)
482 error("target and configured environment conflict\n");
483
484 /* fill in the missing ALLIGNMENT information */
485 current_alignment
486 = (tree_find_boolean_property(root, "/openprom/options/strict-alignment?")
487 ? STRICT_ALIGNMENT
488 : NONSTRICT_ALIGNMENT);
489 if (CURRENT_ALIGNMENT != current_alignment)
490 error("target and configured alignment conflict\n");
491
492 /* fill in the missing FLOATING POINT information */
493 current_floating_point
494 = (tree_find_boolean_property(root, "/openprom/options/floating-point?")
495 ? HARD_FLOATING_POINT
496 : SOFT_FLOATING_POINT);
497 if (CURRENT_FLOATING_POINT != current_floating_point)
498 error("target and configured floating-point conflict\n");
499
500 /* fill in the missing STDIO information */
501 current_stdio
502 = (tree_find_boolean_property(root, "/openprom/options/use-stdio?")
503 ? DO_USE_STDIO
504 : DONT_USE_STDIO);
505 if (CURRENT_STDIO != current_stdio)
506 error("target and configured stdio interface conflict\n");
507
508 /* sort out the level of detail for issue modeling */
509 current_model_issue
510 = tree_find_integer_property(root, "/openprom/options/model-issue");
511 if (CURRENT_MODEL_ISSUE != current_model_issue)
512 error("target and configured model-issue conflict\n");
513
514 /* sort out our model architecture - wrong.
515
516 FIXME: this should be obtaining the required information from the
517 device tree via the "/chosen" property "cpu" which is an instance
518 (ihandle) for the only executing processor. By converting that
519 ihandle into the corresponding cpu's phandle and then querying
520 the "name" property, the cpu type can be determined. Ok? */
521
522 model_set(tree_find_string_property(root, "/openprom/options/model"));
523
524 /* create things */
525 system = ZALLOC(psim);
526 system->events = event_queue_create();
527 system->memory = core_from_device(root);
528 system->monitor = mon_create();
529 system->nr_cpus = nr_cpus;
530 system->os_emulation = os_emulation;
531 system->devices = root;
532
533 /* now all the processors attaching to each their per-cpu information */
534 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
535 system->processors[cpu_nr] = cpu_create(system,
536 system->memory,
537 mon_cpu(system->monitor,
538 cpu_nr),
539 system->os_emulation,
540 cpu_nr);
541 }
542
543 /* dump out the contents of the device tree */
544 if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
545 tree_print(root);
546 if (ppc_trace[trace_dump_device_tree])
547 error("");
548
549 return system;
550 }
551
552
553 /* allow the simulation to stop/restart abnormaly */
554
555 INLINE_PSIM\
556 (void)
557 psim_set_halt_and_restart(psim *system,
558 void *halt_jmp_buf,
559 void *restart_jmp_buf)
560 {
561 system->path_to_halt = halt_jmp_buf;
562 system->path_to_restart = restart_jmp_buf;
563 }
564
565 INLINE_PSIM\
566 (void)
567 psim_clear_halt_and_restart(psim *system)
568 {
569 system->path_to_halt = NULL;
570 system->path_to_restart = NULL;
571 }
572
573 INLINE_PSIM\
574 (void)
575 psim_restart(psim *system,
576 int current_cpu)
577 {
578 ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus);
579 ASSERT(system->path_to_restart != NULL);
580 system->last_cpu = current_cpu;
581 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
582 }
583
584
585 static void
586 cntrl_c_simulation(void *data)
587 {
588 psim *system = data;
589 psim_halt(system,
590 psim_nr_cpus(system),
591 was_continuing,
592 GDB_SIGNAL_INT);
593 }
594
595 INLINE_PSIM\
596 (void)
597 psim_stop(psim *system)
598 {
599 event_queue_schedule_after_signal(psim_event_queue(system),
600 0 /*NOW*/,
601 cntrl_c_simulation,
602 system);
603 }
604
605 INLINE_PSIM\
606 (void)
607 psim_halt(psim *system,
608 int current_cpu,
609 stop_reason reason,
610 int signal)
611 {
612 ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus);
613 ASSERT(system->path_to_halt != NULL);
614 system->last_cpu = current_cpu;
615 system->halt_status.reason = reason;
616 system->halt_status.signal = signal;
617 if (current_cpu == system->nr_cpus) {
618 system->halt_status.cpu_nr = 0;
619 system->halt_status.program_counter =
620 cpu_get_program_counter(system->processors[0]);
621 }
622 else {
623 system->halt_status.cpu_nr = current_cpu;
624 system->halt_status.program_counter =
625 cpu_get_program_counter(system->processors[current_cpu]);
626 }
627 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
628 }
629
630
631 INLINE_PSIM\
632 (int)
633 psim_last_cpu(psim *system)
634 {
635 return system->last_cpu;
636 }
637
638 INLINE_PSIM\
639 (int)
640 psim_nr_cpus(psim *system)
641 {
642 return system->nr_cpus;
643 }
644
645 INLINE_PSIM\
646 (psim_status)
647 psim_get_status(psim *system)
648 {
649 return system->halt_status;
650 }
651
652
653 INLINE_PSIM\
654 (cpu *)
655 psim_cpu(psim *system,
656 int cpu_nr)
657 {
658 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
659 return NULL;
660 else
661 return system->processors[cpu_nr];
662 }
663
664
665 INLINE_PSIM\
666 (device *)
667 psim_device(psim *system,
668 const char *path)
669 {
670 return tree_find_device(system->devices, path);
671 }
672
673 INLINE_PSIM\
674 (event_queue *)
675 psim_event_queue(psim *system)
676 {
677 return system->events;
678 }
679
680
681
682 STATIC_INLINE_PSIM\
683 (void)
684 psim_max_iterations_exceeded(void *data)
685 {
686 psim *system = data;
687 psim_halt(system,
688 system->nr_cpus, /* halted during an event */
689 was_signalled,
690 -1);
691 }
692
693
694 INLINE_PSIM\
695 (void)
696 psim_init(psim *system)
697 {
698 int cpu_nr;
699
700 /* scrub the monitor */
701 mon_init(system->monitor, system->nr_cpus);
702
703 /* trash any pending events */
704 event_queue_init(system->events);
705
706 /* if needed, schedule a halt event. FIXME - In the future this
707 will be replaced by a more generic change to psim_command(). A
708 new command `schedule NNN halt' being added. */
709 if (tree_find_property(system->devices, "/openprom/options/max-iterations")) {
710 event_queue_schedule(system->events,
711 tree_find_integer_property(system->devices,
712 "/openprom/options/max-iterations") - 2,
713 psim_max_iterations_exceeded,
714 system);
715 }
716
717 /* scrub all the cpus */
718 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
719 cpu_init(system->processors[cpu_nr]);
720
721 /* init all the devices (which updates the cpus) */
722 tree_init(system->devices, system);
723
724 /* and the emulation (which needs an initialized device tree) */
725 os_emul_init(system->os_emulation, system->nr_cpus);
726
727 /* now sync each cpu against the initialized state of its registers */
728 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
729 cpu *processor = system->processors[cpu_nr];
730 cpu_synchronize_context(processor, cpu_get_program_counter(processor));
731 cpu_page_tlb_invalidate_all(processor);
732 }
733
734 /* force loop to start with first cpu */
735 system->last_cpu = -1;
736 }
737
738 INLINE_PSIM\
739 (void)
740 psim_stack(psim *system,
741 char **argv,
742 char **envp)
743 {
744 /* pass the stack device the argv/envp and let it work out what to
745 do with it */
746 device *stack_device = tree_find_device(system->devices,
747 "/openprom/init/stack");
748 if (stack_device != (device*)0) {
749 unsigned_word stack_pointer;
750 ASSERT (psim_read_register(system, 0, &stack_pointer, "sp",
751 cooked_transfer) > 0);
752 device_ioctl(stack_device,
753 NULL, /*cpu*/
754 0, /*cia*/
755 device_ioctl_create_stack,
756 stack_pointer,
757 argv,
758 envp);
759 }
760 }
761
762
763
764 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
765 thing */
766
767 INLINE_PSIM\
768 (void)
769 psim_step(psim *system)
770 {
771 volatile int keep_running = 0;
772 idecode_run_until_stop(system, &keep_running,
773 system->events, system->processors, system->nr_cpus);
774 }
775
776 INLINE_PSIM\
777 (void)
778 psim_run(psim *system)
779 {
780 idecode_run(system,
781 system->events, system->processors, system->nr_cpus);
782 }
783
784
785 /* storage manipulation functions */
786
787 INLINE_PSIM\
788 (int)
789 psim_read_register(psim *system,
790 int which_cpu,
791 void *buf,
792 const char reg[],
793 transfer_mode mode)
794 {
795 register_descriptions description;
796 char *cooked_buf;
797 cpu *processor;
798
799 /* find our processor */
800 if (which_cpu == MAX_NR_PROCESSORS) {
801 if (system->last_cpu == system->nr_cpus
802 || system->last_cpu == -1)
803 which_cpu = 0;
804 else
805 which_cpu = system->last_cpu;
806 }
807 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
808
809 processor = system->processors[which_cpu];
810
811 /* find the register description */
812 description = register_description(reg);
813 if (description.type == reg_invalid)
814 return 0;
815 cooked_buf = alloca (description.size);
816
817 /* get the cooked value */
818 switch (description.type) {
819
820 case reg_gpr:
821 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
822 break;
823
824 case reg_spr:
825 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
826 break;
827
828 case reg_sr:
829 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
830 break;
831
832 case reg_fpr:
833 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
834 break;
835
836 case reg_pc:
837 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
838 break;
839
840 case reg_cr:
841 *(creg*)cooked_buf = cpu_registers(processor)->cr;
842 break;
843
844 case reg_msr:
845 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
846 break;
847
848 case reg_fpscr:
849 *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr;
850 break;
851
852 case reg_insns:
853 *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
854 which_cpu);
855 break;
856
857 case reg_stalls:
858 if (cpu_model(processor) == NULL)
859 error("$stalls only valid if processor unit model enabled (-I)\n");
860 *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
861 break;
862
863 case reg_cycles:
864 if (cpu_model(processor) == NULL)
865 error("$cycles only valid if processor unit model enabled (-I)\n");
866 *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
867 break;
868
869 #ifdef WITH_ALTIVEC
870 case reg_vr:
871 *(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index];
872 break;
873
874 case reg_vscr:
875 *(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr;
876 break;
877 #endif
878
879 #ifdef WITH_E500
880 case reg_gprh:
881 *(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index];
882 break;
883
884 case reg_evr:
885 *(unsigned64*)cooked_buf = EVR(description.index);
886 break;
887
888 case reg_acc:
889 *(accreg*)cooked_buf = cpu_registers(processor)->e500.acc;
890 break;
891 #endif
892
893 default:
894 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
895 (unsigned long)processor, (unsigned long)buf, reg,
896 "read of this register unimplemented");
897 break;
898
899 }
900
901 /* the PSIM internal values are in host order. To fetch raw data,
902 they need to be converted into target order and then returned */
903 if (mode == raw_transfer) {
904 /* FIXME - assumes that all registers are simple integers */
905 switch (description.size) {
906 case 1:
907 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
908 break;
909 case 2:
910 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
911 break;
912 case 4:
913 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
914 break;
915 case 8:
916 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
917 break;
918 #ifdef WITH_ALTIVEC
919 case 16:
920 if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
921 {
922 union { vreg v; unsigned_8 d[2]; } h, t;
923 memcpy(&h.v/*dest*/, cooked_buf/*src*/, description.size);
924 { _SWAP_8(t.d[0] =, h.d[1]); }
925 { _SWAP_8(t.d[1] =, h.d[0]); }
926 memcpy(buf/*dest*/, &t/*src*/, description.size);
927 break;
928 }
929 else
930 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
931 break;
932 #endif
933 }
934 }
935 else {
936 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
937 }
938
939 return description.size;
940 }
941
942
943
944 INLINE_PSIM\
945 (int)
946 psim_write_register(psim *system,
947 int which_cpu,
948 const void *buf,
949 const char reg[],
950 transfer_mode mode)
951 {
952 cpu *processor;
953 register_descriptions description;
954 char *cooked_buf;
955
956 /* find our processor */
957 if (which_cpu == MAX_NR_PROCESSORS) {
958 if (system->last_cpu == system->nr_cpus
959 || system->last_cpu == -1)
960 which_cpu = 0;
961 else
962 which_cpu = system->last_cpu;
963 }
964
965 /* find the description of the register */
966 description = register_description(reg);
967 if (description.type == reg_invalid)
968 return 0;
969 cooked_buf = alloca (description.size);
970
971 if (which_cpu == -1) {
972 int i;
973 for (i = 0; i < system->nr_cpus; i++)
974 psim_write_register(system, i, buf, reg, mode);
975 return description.size;
976 }
977 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
978
979 processor = system->processors[which_cpu];
980
981 /* If the data is comming in raw (target order), need to cook it
982 into host order before putting it into PSIM's internal structures */
983 if (mode == raw_transfer) {
984 switch (description.size) {
985 case 1:
986 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
987 break;
988 case 2:
989 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
990 break;
991 case 4:
992 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
993 break;
994 case 8:
995 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
996 break;
997 #ifdef WITH_ALTIVEC
998 case 16:
999 if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
1000 {
1001 union { vreg v; unsigned_8 d[2]; } h, t;
1002 memcpy(&t.v/*dest*/, buf/*src*/, description.size);
1003 { _SWAP_8(h.d[0] =, t.d[1]); }
1004 { _SWAP_8(h.d[1] =, t.d[0]); }
1005 memcpy(cooked_buf/*dest*/, &h/*src*/, description.size);
1006 break;
1007 }
1008 else
1009 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
1010 #endif
1011 }
1012 }
1013 else {
1014 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
1015 }
1016
1017 /* put the cooked value into the register */
1018 switch (description.type) {
1019
1020 case reg_gpr:
1021 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
1022 break;
1023
1024 case reg_fpr:
1025 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
1026 break;
1027
1028 case reg_pc:
1029 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
1030 break;
1031
1032 case reg_spr:
1033 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
1034 break;
1035
1036 case reg_sr:
1037 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
1038 break;
1039
1040 case reg_cr:
1041 cpu_registers(processor)->cr = *(creg*)cooked_buf;
1042 break;
1043
1044 case reg_msr:
1045 cpu_registers(processor)->msr = *(msreg*)cooked_buf;
1046 break;
1047
1048 case reg_fpscr:
1049 cpu_registers(processor)->fpscr = *(fpscreg*)cooked_buf;
1050 break;
1051
1052 #ifdef WITH_E500
1053 case reg_gprh:
1054 cpu_registers(processor)->e500.gprh[description.index] = *(gpreg*)cooked_buf;
1055 break;
1056
1057 case reg_evr:
1058 {
1059 unsigned64 v;
1060 v = *(unsigned64*)cooked_buf;
1061 cpu_registers(processor)->e500.gprh[description.index] = v >> 32;
1062 cpu_registers(processor)->gpr[description.index] = v;
1063 break;
1064 }
1065
1066 case reg_acc:
1067 cpu_registers(processor)->e500.acc = *(accreg*)cooked_buf;
1068 break;
1069 #endif
1070
1071 #ifdef WITH_ALTIVEC
1072 case reg_vr:
1073 cpu_registers(processor)->altivec.vr[description.index] = *(vreg*)cooked_buf;
1074 break;
1075
1076 case reg_vscr:
1077 cpu_registers(processor)->altivec.vscr = *(vscreg*)cooked_buf;
1078 break;
1079 #endif
1080
1081 default:
1082 printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
1083 (unsigned long)processor, (unsigned long)cooked_buf, reg,
1084 "read of this register unimplemented");
1085 break;
1086
1087 }
1088
1089 return description.size;
1090 }
1091
1092
1093
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)
1101 {
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;
1109 }
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);
1114 }
1115
1116
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)
1125 {
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;
1133 }
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);
1139 }
1140
1141
1142 INLINE_PSIM\
1143 (void)
1144 psim_print_info(psim *system,
1145 int verbose)
1146 {
1147 mon_print_info(system, system->monitor, verbose);
1148 }
1149
1150
1151 /* Merge a device tree and a device file. */
1152
1153 INLINE_PSIM\
1154 (void)
1155 psim_merge_device_file(device *root,
1156 const char *file_name)
1157 {
1158 FILE *description;
1159 int line_nr;
1160 char device_path[1000];
1161 device *current;
1162
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);
1168 }
1169
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);
1179 }
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:%s: unexpected eof in line continuation - %s",
1200 file_name, line_nr, device_path);
1201 }
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);
1206 }
1207 else
1208 *strchr(device_path, '\n') = '\0';
1209 line_nr++;
1210 }
1211 /* parse this line */
1212 current = tree_parse(current, "%s", device);
1213 }
1214 fclose(description);
1215 }
1216
1217
1218 #endif /* _PSIM_C_ */