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