]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/ppc/psim.c
sim:
[thirdparty/binutils-gdb.git] / sim / ppc / psim.c
CommitLineData
c906108c
SS
1/* This file is part of the program psim.
2
601cecf0 3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
c906108c
SS
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"
c55c7ff1 52#include "libiberty.h"
3a611ef5 53#include "gdb/signals.h"
c906108c
SS
54
55/* system structure, actual size of processor array determined at
56 runtime */
57
58struct _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
79int current_target_byte_order;
80int current_host_byte_order;
81int current_environment;
82int current_alignment;
83int current_floating_point;
84int current_model_issue = MODEL_ISSUE_IGNORE;
85int current_stdio = DO_USE_STDIO;
86model_enum current_model = WITH_DEFAULT_MODEL;
87
88
89/* create the device tree */
90
91INLINE_PSIM\
92(device *)
93psim_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
108STATIC_INLINE_PSIM\
109(char *)
110find_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
120INLINE_PSIM\
121(void)
6efef468 122psim_usage(int verbose, int help)
c906108c
SS
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 }
6efef468
JM
220
221 if (REPORT_BUGS_TO[0])
222 printf ("Report bugs to %s\n", REPORT_BUGS_TO);
223 exit (help ? 0 : 1);
c906108c
SS
224}
225
226/* Test "string" for containing a string of digits that form a number
7a292a7a 227between "min" and "max". The return value is the number or "err". */
c906108c
SS
228static
229int 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
248INLINE_PSIM\
249(char **)
250psim_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:
6efef468 264 psim_usage(0, 0);
c906108c
SS
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");
6efef468 285 psim_usage (0, 0);
c906108c
SS
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 '?':
6efef468 294 psim_usage(1, 1);
c906108c
SS
295 break;
296 case 'H':
6efef468 297 psim_usage(2, 1);
c906108c
SS
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);
c906108c
SS
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
c906108c
SS
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;
47243d69
EZ
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 }
6efef468
JM
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 }
47243d69
EZ
366 else
367 error("Unrecognized option");
368 break;
c906108c
SS
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
7a292a7a
SS
380 {
381 void semantic_init(device* root);
382 semantic_init(root);
383 }
c906108c
SS
384
385 /* return where the options end */
386 return argv + argp;
387}
388
389INLINE_PSIM\
390(void)
391psim_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
421INLINE_PSIM\
422(psim *)
423psim_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
549INLINE_PSIM\
550(void)
551psim_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
559INLINE_PSIM\
560(void)
561psim_clear_halt_and_restart(psim *system)
562{
563 system->path_to_halt = NULL;
564 system->path_to_restart = NULL;
565}
566
567INLINE_PSIM\
568(void)
569psim_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
579static void
580cntrl_c_simulation(void *data)
581{
582 psim *system = data;
583 psim_halt(system,
584 psim_nr_cpus(system),
585 was_continuing,
aba6488e 586 TARGET_SIGNAL_INT);
c906108c
SS
587}
588
589INLINE_PSIM\
590(void)
591psim_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
599INLINE_PSIM\
600(void)
601psim_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
625INLINE_PSIM\
626(int)
627psim_last_cpu(psim *system)
628{
629 return system->last_cpu;
630}
631
632INLINE_PSIM\
633(int)
634psim_nr_cpus(psim *system)
635{
636 return system->nr_cpus;
637}
638
639INLINE_PSIM\
640(psim_status)
641psim_get_status(psim *system)
642{
643 return system->halt_status;
644}
645
646
647INLINE_PSIM\
648(cpu *)
649psim_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
659INLINE_PSIM\
660(device *)
661psim_device(psim *system,
662 const char *path)
663{
664 return tree_find_device(system->devices, path);
665}
666
667INLINE_PSIM\
668(event_queue *)
669psim_event_queue(psim *system)
670{
671 return system->events;
672}
673
674
675
676STATIC_INLINE_PSIM\
677(void)
678psim_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
688INLINE_PSIM\
689(void)
690psim_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
732INLINE_PSIM\
733(void)
734psim_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;
601cecf0
AC
744 ASSERT (psim_read_register(system, 0, &stack_pointer, "sp",
745 cooked_transfer) > 0);
c906108c
SS
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
761INLINE_PSIM\
762(void)
763psim_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
770INLINE_PSIM\
771(void)
772psim_run(psim *system)
773{
774 idecode_run(system,
775 system->events, system->processors, system->nr_cpus);
776}
777
778
779/* storage manipulation functions */
780
781INLINE_PSIM\
601cecf0 782(int)
c906108c
SS
783psim_read_register(psim *system,
784 int which_cpu,
785 void *buf,
786 const char reg[],
787 transfer_mode mode)
788{
789 register_descriptions description;
601cecf0 790 char *cooked_buf;
c906108c
SS
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)
601cecf0
AC
808 return 0;
809 cooked_buf = alloca (description.size);
c906108c
SS
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
345d88d9
AC
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
c906108c
SS
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;
345d88d9
AC
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
c906108c
SS
927 }
928 }
929 else {
930 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
931 }
932
601cecf0 933 return description.size;
c906108c
SS
934}
935
936
937
938INLINE_PSIM\
601cecf0 939(int)
c906108c
SS
940psim_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;
601cecf0 948 char *cooked_buf;
c906108c
SS
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 }
601cecf0
AC
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
c906108c
SS
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);
601cecf0 969 return description.size;
c906108c
SS
970 }
971 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
972
973 processor = system->processors[which_cpu];
974
c906108c
SS
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;
345d88d9
AC
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
c906108c
SS
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
345d88d9
AC
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
c906108c
SS
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
601cecf0 1083 return description.size;
c906108c
SS
1084}
1085
1086
1087
1088INLINE_PSIM\
1089(unsigned)
1090psim_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
1111INLINE_PSIM\
1112(unsigned)
1113psim_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
1136INLINE_PSIM\
1137(void)
1138psim_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
1147INLINE_PSIM\
1148(void)
1149psim_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_ */