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