]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/ppc/psim.c
Update copyright year range in header of all files managed by GDB
[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
3fd725ef 7 the Free Software Foundation; either version 3 of the License, or
c906108c
SS
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
51b318de 16 along with this program; if not, see <http://www.gnu.org/licenses/>.
c906108c
SS
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>
c906108c 34#include <stdlib.h>
c906108c 35#include <setjmp.h>
c906108c 36#include <string.h>
c906108c
SS
37
38#include "bfd.h"
c55c7ff1 39#include "libiberty.h"
3a611ef5 40#include "gdb/signals.h"
c906108c
SS
41
42/* system structure, actual size of processor array determined at
43 runtime */
44
45struct _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
956f0bab 66enum bfd_endian current_target_byte_order;
c906108c
SS
67int current_environment;
68int current_alignment;
69int current_floating_point;
70int current_model_issue = MODEL_ISSUE_IGNORE;
71int current_stdio = DO_USE_STDIO;
72model_enum current_model = WITH_DEFAULT_MODEL;
73
74
75/* create the device tree */
76
77INLINE_PSIM\
78(device *)
79psim_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
94STATIC_INLINE_PSIM\
be2bc30f
MF
95(const char *)
96find_arg(const char *err_msg,
c906108c 97 int *ptr_to_argp,
be2bc30f 98 char * const *argv)
c906108c
SS
99{
100 *ptr_to_argp += 1;
101 if (argv[*ptr_to_argp] == NULL)
182421c9 102 error("%s", err_msg);
c906108c
SS
103 return argv[*ptr_to_argp];
104}
105
106INLINE_PSIM\
107(void)
dea827fc 108psim_usage (int verbose, int help, SIM_OPEN_KIND kind)
c906108c
SS
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 }
6efef468 206
dea827fc
MF
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 }
c906108c
SS
213}
214
215/* Test "string" for containing a string of digits that form a number
7a292a7a 216between "min" and "max". The return value is the number or "err". */
c906108c 217static
be2bc30f 218int is_num(const char *string, int min, int max, int err)
c906108c
SS
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
237INLINE_PSIM\
be2bc30f 238(char * const *)
c906108c 239psim_options(device *root,
be2bc30f 240 char * const *argv,
dea827fc 241 SIM_OPEN_KIND kind)
c906108c
SS
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] == '-') {
be2bc30f
MF
249 const char *p = argv[argp] + 1;
250 const char *param;
c906108c
SS
251 while (*p != '\0') {
252 switch (*p) {
253 default:
11eef9ed 254 printf_filtered ("Invalid Option: %s\n", argv[argp]);
dea827fc
MF
255 psim_usage (0, 0, kind);
256 return NULL;
c906108c
SS
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");
dea827fc
MF
275 psim_usage (0, 0, kind);
276 return NULL;
c906108c
SS
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 '?':
dea827fc
MF
285 psim_usage (1, 1, kind);
286 return NULL;
c906108c 287 case 'H':
dea827fc
MF
288 psim_usage (2, 1, kind);
289 return NULL;
c906108c
SS
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);
c906108c
SS
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
c906108c
SS
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;
47243d69
EZ
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 }
6efef468 349 else if (strcmp (argv[argp], "--help") == 0)
dea827fc
MF
350 {
351 psim_usage (0, 1, kind);
352 return NULL;
353 }
8294052c 354 else if (strncmp (argv[argp], "--sysroot=",
94e4274d 355 sizeof ("--sysroot=") - 1) == 0)
8294052c
JB
356 /* Ignore this option. */
357 p = argv[argp] + strlen(argv[argp]) - 1;
6efef468
JM
358 else if (strcmp (argv[argp], "--version") == 0)
359 {
360 extern const char version[];
361 printf ("GNU simulator %s%s\n", PKGVERSION, version);
1d506c26 362 printf ("Copyright (C) 2024 Free Software Foundation, Inc.\n");
75bed973
MF
363 printf ( "\
364License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\
365\nThis is free software: you are free to change and redistribute it.\n\
366There is NO WARRANTY, to the extent permitted by law.\n");
dea827fc
MF
367 if (kind == SIM_OPEN_STANDALONE)
368 exit (0);
369 else
370 return NULL;
6efef468 371 }
47243d69 372 else
11eef9ed
JB
373 {
374 printf_filtered ("Invalid option: %s\n", argv[argp]);
dea827fc
MF
375 psim_usage (0, 0, kind);
376 return NULL;
11eef9ed 377 }
47243d69 378 break;
c906108c
SS
379 }
380 p += 1;
381 }
382 argp += 1;
383 }
384 /* force the trace node to process its options now *before* the tree
385 initialization occures */
386 device_ioctl(tree_find_device(root, "/openprom/trace"),
387 NULL, 0,
388 device_ioctl_set_trace);
389
7a292a7a
SS
390 {
391 void semantic_init(device* root);
392 semantic_init(root);
393 }
c906108c
SS
394
395 /* return where the options end */
396 return argv + argp;
397}
398
399INLINE_PSIM\
400(void)
401psim_command(device *root,
be2bc30f 402 char * const *argv)
c906108c
SS
403{
404 int argp = 0;
405 if (argv[argp] == NULL) {
406 return;
407 }
408 else if (strcmp(argv[argp], "trace") == 0) {
409 const char *opt = find_arg("Missing <trace> option", &argp, argv);
410 if (opt[0] == '!')
411 trace_option(opt + 1, 0);
412 else
413 trace_option(opt, 1);
414 }
415 else if (strcmp(*argv, "change-media") == 0) {
be2bc30f
MF
416 const char *device = find_arg("Missing device name", &argp, argv);
417 const char *media = argv[++argp];
c906108c
SS
418 device_ioctl(tree_find_device(root, device), NULL, 0,
419 device_ioctl_change_media, media);
420 }
421 else {
422 printf_filtered("Unknown PSIM command %s, try\n", argv[argp]);
423 printf_filtered(" trace <trace-option>\n");
424 printf_filtered(" change-media <device> [ <new-image> ]\n");
425 }
426}
427
428
429/* create the simulator proper from the device tree and executable */
430
431INLINE_PSIM\
432(psim *)
433psim_create(const char *file_name,
434 device *root)
435{
436 int cpu_nr;
437 const char *env;
438 psim *system;
439 os_emul *os_emulation;
440 int nr_cpus;
441
442 /* given this partially populated device tree, os_emul_create() uses
443 it and file_name to determine the selected emulation and hence
444 further populate the tree with any other required nodes. */
445
446 os_emulation = os_emul_create(file_name, root);
447 if (os_emulation == NULL)
448 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
449
450 /* fill in the missing real number of CPU's */
451 nr_cpus = tree_find_integer_property(root, "/openprom/options/smp");
452 if (MAX_NR_PROCESSORS < nr_cpus)
453 error("target and configured number of cpus conflict\n");
454
455 /* fill in the missing TARGET BYTE ORDER information */
456 current_target_byte_order
457 = (tree_find_boolean_property(root, "/options/little-endian?")
956f0bab
MF
458 ? BFD_ENDIAN_LITTLE
459 : BFD_ENDIAN_BIG);
c906108c
SS
460 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
461 error("target and configured byte order conflict\n");
462
c906108c
SS
463 /* fill in the missing OEA/VEA information */
464 env = tree_find_string_property(root, "/openprom/options/env");
465 current_environment = ((strcmp(env, "user") == 0
466 || strcmp(env, "uea") == 0)
467 ? USER_ENVIRONMENT
468 : (strcmp(env, "virtual") == 0
469 || strcmp(env, "vea") == 0)
470 ? VIRTUAL_ENVIRONMENT
471 : (strcmp(env, "operating") == 0
472 || strcmp(env, "oea") == 0)
473 ? OPERATING_ENVIRONMENT
474 : 0);
475 if (current_environment == 0)
476 error("unreconized /options env property\n");
477 if (CURRENT_ENVIRONMENT != current_environment)
478 error("target and configured environment conflict\n");
479
480 /* fill in the missing ALLIGNMENT information */
481 current_alignment
482 = (tree_find_boolean_property(root, "/openprom/options/strict-alignment?")
483 ? STRICT_ALIGNMENT
484 : NONSTRICT_ALIGNMENT);
485 if (CURRENT_ALIGNMENT != current_alignment)
486 error("target and configured alignment conflict\n");
487
488 /* fill in the missing FLOATING POINT information */
489 current_floating_point
490 = (tree_find_boolean_property(root, "/openprom/options/floating-point?")
491 ? HARD_FLOATING_POINT
492 : SOFT_FLOATING_POINT);
493 if (CURRENT_FLOATING_POINT != current_floating_point)
494 error("target and configured floating-point conflict\n");
495
496 /* fill in the missing STDIO information */
497 current_stdio
498 = (tree_find_boolean_property(root, "/openprom/options/use-stdio?")
499 ? DO_USE_STDIO
500 : DONT_USE_STDIO);
501 if (CURRENT_STDIO != current_stdio)
502 error("target and configured stdio interface conflict\n");
503
504 /* sort out the level of detail for issue modeling */
505 current_model_issue
506 = tree_find_integer_property(root, "/openprom/options/model-issue");
507 if (CURRENT_MODEL_ISSUE != current_model_issue)
508 error("target and configured model-issue conflict\n");
509
510 /* sort out our model architecture - wrong.
511
512 FIXME: this should be obtaining the required information from the
513 device tree via the "/chosen" property "cpu" which is an instance
514 (ihandle) for the only executing processor. By converting that
515 ihandle into the corresponding cpu's phandle and then querying
516 the "name" property, the cpu type can be determined. Ok? */
517
518 model_set(tree_find_string_property(root, "/openprom/options/model"));
519
520 /* create things */
521 system = ZALLOC(psim);
522 system->events = event_queue_create();
523 system->memory = core_from_device(root);
524 system->monitor = mon_create();
525 system->nr_cpus = nr_cpus;
526 system->os_emulation = os_emulation;
527 system->devices = root;
528
529 /* now all the processors attaching to each their per-cpu information */
530 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
531 system->processors[cpu_nr] = cpu_create(system,
532 system->memory,
533 mon_cpu(system->monitor,
534 cpu_nr),
535 system->os_emulation,
536 cpu_nr);
537 }
538
539 /* dump out the contents of the device tree */
540 if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
541 tree_print(root);
542 if (ppc_trace[trace_dump_device_tree])
182421c9 543 error("%s", "");
c906108c
SS
544
545 return system;
546}
547
548
549/* allow the simulation to stop/restart abnormaly */
550
551INLINE_PSIM\
552(void)
553psim_set_halt_and_restart(psim *system,
554 void *halt_jmp_buf,
555 void *restart_jmp_buf)
556{
557 system->path_to_halt = halt_jmp_buf;
558 system->path_to_restart = restart_jmp_buf;
559}
560
561INLINE_PSIM\
562(void)
563psim_clear_halt_and_restart(psim *system)
564{
565 system->path_to_halt = NULL;
566 system->path_to_restart = NULL;
567}
568
569INLINE_PSIM\
570(void)
571psim_restart(psim *system,
572 int current_cpu)
573{
574 ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus);
575 ASSERT(system->path_to_restart != NULL);
576 system->last_cpu = current_cpu;
577 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
578}
579
580
5eba9ae8 581static ATTRIBUTE_NORETURN void
c906108c
SS
582cntrl_c_simulation(void *data)
583{
584 psim *system = data;
585 psim_halt(system,
586 psim_nr_cpus(system),
587 was_continuing,
a493e3e2 588 GDB_SIGNAL_INT);
c906108c
SS
589}
590
591INLINE_PSIM\
592(void)
593psim_stop(psim *system)
594{
595 event_queue_schedule_after_signal(psim_event_queue(system),
596 0 /*NOW*/,
597 cntrl_c_simulation,
598 system);
599}
600
601INLINE_PSIM\
602(void)
603psim_halt(psim *system,
604 int current_cpu,
605 stop_reason reason,
606 int signal)
607{
608 ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus);
609 ASSERT(system->path_to_halt != NULL);
610 system->last_cpu = current_cpu;
611 system->halt_status.reason = reason;
612 system->halt_status.signal = signal;
613 if (current_cpu == system->nr_cpus) {
614 system->halt_status.cpu_nr = 0;
615 system->halt_status.program_counter =
616 cpu_get_program_counter(system->processors[0]);
617 }
618 else {
619 system->halt_status.cpu_nr = current_cpu;
620 system->halt_status.program_counter =
621 cpu_get_program_counter(system->processors[current_cpu]);
622 }
623 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
624}
625
626
627INLINE_PSIM\
628(int)
629psim_last_cpu(psim *system)
630{
631 return system->last_cpu;
632}
633
634INLINE_PSIM\
635(int)
636psim_nr_cpus(psim *system)
637{
638 return system->nr_cpus;
639}
640
641INLINE_PSIM\
642(psim_status)
643psim_get_status(psim *system)
644{
645 return system->halt_status;
646}
647
648
649INLINE_PSIM\
650(cpu *)
651psim_cpu(psim *system,
652 int cpu_nr)
653{
654 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
655 return NULL;
656 else
657 return system->processors[cpu_nr];
658}
659
660
661INLINE_PSIM\
662(device *)
663psim_device(psim *system,
664 const char *path)
665{
666 return tree_find_device(system->devices, path);
667}
668
669INLINE_PSIM\
670(event_queue *)
671psim_event_queue(psim *system)
672{
673 return system->events;
674}
675
676
677
678STATIC_INLINE_PSIM\
679(void)
680psim_max_iterations_exceeded(void *data)
681{
682 psim *system = data;
683 psim_halt(system,
684 system->nr_cpus, /* halted during an event */
685 was_signalled,
686 -1);
687}
688
689
690INLINE_PSIM\
691(void)
692psim_init(psim *system)
693{
694 int cpu_nr;
695
696 /* scrub the monitor */
697 mon_init(system->monitor, system->nr_cpus);
698
699 /* trash any pending events */
700 event_queue_init(system->events);
701
702 /* if needed, schedule a halt event. FIXME - In the future this
703 will be replaced by a more generic change to psim_command(). A
704 new command `schedule NNN halt' being added. */
705 if (tree_find_property(system->devices, "/openprom/options/max-iterations")) {
706 event_queue_schedule(system->events,
707 tree_find_integer_property(system->devices,
708 "/openprom/options/max-iterations") - 2,
709 psim_max_iterations_exceeded,
710 system);
711 }
712
713 /* scrub all the cpus */
714 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
715 cpu_init(system->processors[cpu_nr]);
716
717 /* init all the devices (which updates the cpus) */
718 tree_init(system->devices, system);
719
720 /* and the emulation (which needs an initialized device tree) */
721 os_emul_init(system->os_emulation, system->nr_cpus);
722
723 /* now sync each cpu against the initialized state of its registers */
724 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
725 cpu *processor = system->processors[cpu_nr];
726 cpu_synchronize_context(processor, cpu_get_program_counter(processor));
727 cpu_page_tlb_invalidate_all(processor);
728 }
729
730 /* force loop to start with first cpu */
731 system->last_cpu = -1;
732}
733
734INLINE_PSIM\
735(void)
736psim_stack(psim *system,
be2bc30f
MF
737 char * const *argv,
738 char * const *envp)
c906108c
SS
739{
740 /* pass the stack device the argv/envp and let it work out what to
741 do with it */
742 device *stack_device = tree_find_device(system->devices,
743 "/openprom/init/stack");
744 if (stack_device != (device*)0) {
745 unsigned_word stack_pointer;
601cecf0
AC
746 ASSERT (psim_read_register(system, 0, &stack_pointer, "sp",
747 cooked_transfer) > 0);
c906108c
SS
748 device_ioctl(stack_device,
749 NULL, /*cpu*/
750 0, /*cia*/
751 device_ioctl_create_stack,
752 stack_pointer,
753 argv,
754 envp);
755 }
756}
757
758
759
760/* SIMULATE INSTRUCTIONS, various different ways of achieving the same
761 thing */
762
763INLINE_PSIM\
764(void)
765psim_step(psim *system)
766{
767 volatile int keep_running = 0;
768 idecode_run_until_stop(system, &keep_running,
769 system->events, system->processors, system->nr_cpus);
770}
771
772INLINE_PSIM\
773(void)
774psim_run(psim *system)
775{
776 idecode_run(system,
777 system->events, system->processors, system->nr_cpus);
778}
779
780
781/* storage manipulation functions */
782
783INLINE_PSIM\
601cecf0 784(int)
c906108c
SS
785psim_read_register(psim *system,
786 int which_cpu,
787 void *buf,
788 const char reg[],
789 transfer_mode mode)
790{
791 register_descriptions description;
601cecf0 792 char *cooked_buf;
c906108c
SS
793 cpu *processor;
794
795 /* find our processor */
796 if (which_cpu == MAX_NR_PROCESSORS) {
797 if (system->last_cpu == system->nr_cpus
798 || system->last_cpu == -1)
799 which_cpu = 0;
800 else
801 which_cpu = system->last_cpu;
802 }
803 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
804
805 processor = system->processors[which_cpu];
806
807 /* find the register description */
808 description = register_description(reg);
809 if (description.type == reg_invalid)
601cecf0
AC
810 return 0;
811 cooked_buf = alloca (description.size);
c906108c
SS
812
813 /* get the cooked value */
814 switch (description.type) {
815
816 case reg_gpr:
817 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
818 break;
819
820 case reg_spr:
821 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
822 break;
823
824 case reg_sr:
825 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
826 break;
827
828 case reg_fpr:
829 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
830 break;
831
832 case reg_pc:
833 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
834 break;
835
836 case reg_cr:
837 *(creg*)cooked_buf = cpu_registers(processor)->cr;
838 break;
839
840 case reg_msr:
841 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
842 break;
843
844 case reg_fpscr:
845 *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr;
846 break;
847
848 case reg_insns:
849 *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
850 which_cpu);
851 break;
852
853 case reg_stalls:
854 if (cpu_model(processor) == NULL)
855 error("$stalls only valid if processor unit model enabled (-I)\n");
856 *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
857 break;
858
859 case reg_cycles:
860 if (cpu_model(processor) == NULL)
861 error("$cycles only valid if processor unit model enabled (-I)\n");
862 *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
863 break;
864
345d88d9
AC
865#ifdef WITH_ALTIVEC
866 case reg_vr:
867 *(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index];
868 break;
869
870 case reg_vscr:
871 *(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr;
872 break;
873#endif
874
875#ifdef WITH_E500
876 case reg_gprh:
877 *(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index];
878 break;
879
880 case reg_evr:
95e40d77 881 *(uint64_t*)cooked_buf = EVR(description.index);
345d88d9
AC
882 break;
883
884 case reg_acc:
885 *(accreg*)cooked_buf = cpu_registers(processor)->e500.acc;
886 break;
887#endif
888
c906108c 889 default:
fad7f13a
MF
890 printf_filtered("psim_read_register(processor=%p,buf=%p,reg=%s) %s\n",
891 processor, buf, reg, "read of this register unimplemented");
20617191 892 return 0;
c906108c
SS
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:
430456e3 914 if (HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
345d88d9
AC
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:
430456e3 993 if (HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
345d88d9
AC
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 {
95e40d77
MF
1053 uint64_t v;
1054 v = *(uint64_t*)cooked_buf;
345d88d9
AC
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 1075 default:
fad7f13a
MF
1076 printf_filtered("psim_write_register(processor=%p,cooked_buf=%p,reg=%s) %s\n",
1077 processor, cooked_buf, reg,
c906108c 1078 "read of this register unimplemented");
20617191 1079 return 0;
c906108c
SS
1080 }
1081
601cecf0 1082 return description.size;
c906108c
SS
1083}
1084
1085
1086
1087INLINE_PSIM\
1088(unsigned)
1089psim_read_memory(psim *system,
1090 int which_cpu,
1091 void *buffer,
1092 unsigned_word vaddr,
1093 unsigned nr_bytes)
1094{
1095 cpu *processor;
1096 if (which_cpu == MAX_NR_PROCESSORS) {
1097 if (system->last_cpu == system->nr_cpus
1098 || system->last_cpu == -1)
1099 which_cpu = 0;
1100 else
1101 which_cpu = system->last_cpu;
1102 }
1103 processor = system->processors[which_cpu];
1104 return vm_data_map_read_buffer(cpu_data_map(processor),
1105 buffer, vaddr, nr_bytes,
1106 NULL, -1);
1107}
1108
1109
1110INLINE_PSIM\
1111(unsigned)
1112psim_write_memory(psim *system,
1113 int which_cpu,
1114 const void *buffer,
1115 unsigned_word vaddr,
1116 unsigned nr_bytes,
1117 int violate_read_only_section)
1118{
1119 cpu *processor;
1120 if (which_cpu == MAX_NR_PROCESSORS) {
1121 if (system->last_cpu == system->nr_cpus
1122 || system->last_cpu == -1)
1123 which_cpu = 0;
1124 else
1125 which_cpu = system->last_cpu;
1126 }
1127 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
1128 processor = system->processors[which_cpu];
1129 return vm_data_map_write_buffer(cpu_data_map(processor),
1130 buffer, vaddr, nr_bytes, 1/*violate-read-only*/,
1131 NULL, -1);
1132}
1133
1134
1135INLINE_PSIM\
1136(void)
1137psim_print_info(psim *system,
1138 int verbose)
1139{
1140 mon_print_info(system, system->monitor, verbose);
1141}
1142
1143
1144/* Merge a device tree and a device file. */
1145
1146INLINE_PSIM\
1147(void)
1148psim_merge_device_file(device *root,
1149 const char *file_name)
1150{
1151 FILE *description;
1152 int line_nr;
1153 char device_path[1000];
1154 device *current;
1155
1156 /* try opening the file */
1157 description = fopen(file_name, "r");
1158 if (description == NULL) {
1159 perror(file_name);
1160 error("Invalid file %s specified", file_name);
1161 }
1162
1163 line_nr = 0;
1164 current = root;
1165 while (fgets(device_path, sizeof(device_path), description)) {
1166 char *device;
1167 /* check that the full line was read */
1168 if (strchr(device_path, '\n') == NULL) {
1169 fclose(description);
1170 error("%s:%d: line to long - %s",
1171 file_name, line_nr, device_path);
1172 }
1173 else
1174 *strchr(device_path, '\n') = '\0';
1175 line_nr++;
1176 /* skip comments ("#" or ";") and blank lines lines */
1177 for (device = device_path;
1178 *device != '\0' && isspace(*device);
1179 device++);
1180 if (device[0] == '#'
1181 || device[0] == ';'
1182 || device[0] == '\0')
1183 continue;
1184 /* merge any appended lines */
1185 while (device_path[strlen(device_path) - 1] == '\\') {
1186 int curlen = strlen(device_path) - 1;
1187 /* zap \ */
1188 device_path[curlen] = '\0';
1189 /* append the next line */
1190 if (!fgets(device_path + curlen, sizeof(device_path) - curlen, description)) {
1191 fclose(description);
182421c9 1192 error("%s:%d: unexpected eof in line continuation - %s",
c906108c
SS
1193 file_name, line_nr, device_path);
1194 }
1195 if (strchr(device_path, '\n') == NULL) {
1196 fclose(description);
1197 error("%s:%d: line to long - %s",
1198 file_name, line_nr, device_path);
1199 }
1200 else
1201 *strchr(device_path, '\n') = '\0';
1202 line_nr++;
1203 }
1204 /* parse this line */
1205 current = tree_parse(current, "%s", device);
1206 }
1207 fclose(description);
1208}
1209
1210
1211#endif /* _PSIM_C_ */