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