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