]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/psim.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / sim / ppc / psim.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
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 of "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 #ifdef WITH_OPTION_MPC860C0
320 if (memcmp(param, "mpc860c0", 8) == 0)
321 {
322 if (param[8] == '\0')
323 tree_parse(root, "/options/mpc860c0 5");
324 else if (param[8] == '=' && is_num(param+9, 1, 10, 0))
325 {
326 tree_parse(root, "/options/mpc860c0 %s", param+9);
327 }
328 else error("Invalid mpc860c0 option for -o\n");
329 }
330 else
331 #endif // WITH_OPTION_MPC860C0
332 current = tree_parse(current, "%s", param);
333 break;
334 case 'r':
335 param = find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp, argv);
336 tree_parse(root, "/openprom/options/oea-memory-size %s",
337 param);
338 break;
339 case 't':
340 param = find_arg("Missing <trace> option for -t (trace/*)\n", &argp, argv);
341 if (param[0] == '!')
342 tree_parse(root, "/openprom/trace/%s 0", param+1);
343 else
344 tree_parse(root, "/openprom/trace/%s 1", param);
345 break;
346 }
347 p += 1;
348 }
349 argp += 1;
350 }
351 /* force the trace node to process its options now *before* the tree
352 initialization occures */
353 device_ioctl(tree_find_device(root, "/openprom/trace"),
354 NULL, 0,
355 device_ioctl_set_trace);
356
357 #ifdef WITH_OPTION_MPC860C0
358 semantic_init(root);
359 #endif // WITH_OPTION_MPC860C0
360
361 /* return where the options end */
362 return argv + argp;
363 }
364
365 INLINE_PSIM\
366 (void)
367 psim_command(device *root,
368 char **argv)
369 {
370 int argp = 0;
371 if (argv[argp] == NULL) {
372 return;
373 }
374 else if (strcmp(argv[argp], "trace") == 0) {
375 const char *opt = find_arg("Missing <trace> option", &argp, argv);
376 if (opt[0] == '!')
377 trace_option(opt + 1, 0);
378 else
379 trace_option(opt, 1);
380 }
381 else if (strcmp(*argv, "change-media") == 0) {
382 char *device = find_arg("Missing device name", &argp, argv);
383 char *media = argv[++argp];
384 device_ioctl(tree_find_device(root, device), NULL, 0,
385 device_ioctl_change_media, media);
386 }
387 else {
388 printf_filtered("Unknown PSIM command %s, try\n", argv[argp]);
389 printf_filtered(" trace <trace-option>\n");
390 printf_filtered(" change-media <device> [ <new-image> ]\n");
391 }
392 }
393
394
395 /* create the simulator proper from the device tree and executable */
396
397 INLINE_PSIM\
398 (psim *)
399 psim_create(const char *file_name,
400 device *root)
401 {
402 int cpu_nr;
403 const char *env;
404 psim *system;
405 os_emul *os_emulation;
406 int nr_cpus;
407
408 /* given this partially populated device tree, os_emul_create() uses
409 it and file_name to determine the selected emulation and hence
410 further populate the tree with any other required nodes. */
411
412 os_emulation = os_emul_create(file_name, root);
413 if (os_emulation == NULL)
414 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
415
416 /* fill in the missing real number of CPU's */
417 nr_cpus = tree_find_integer_property(root, "/openprom/options/smp");
418 if (MAX_NR_PROCESSORS < nr_cpus)
419 error("target and configured number of cpus conflict\n");
420
421 /* fill in the missing TARGET BYTE ORDER information */
422 current_target_byte_order
423 = (tree_find_boolean_property(root, "/options/little-endian?")
424 ? LITTLE_ENDIAN
425 : BIG_ENDIAN);
426 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
427 error("target and configured byte order conflict\n");
428
429 /* fill in the missing HOST BYTE ORDER information */
430 current_host_byte_order = (current_host_byte_order = 1,
431 (*(char*)(&current_host_byte_order)
432 ? LITTLE_ENDIAN
433 : BIG_ENDIAN));
434 if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
435 error("host and configured byte order conflict\n");
436
437 /* fill in the missing OEA/VEA information */
438 env = tree_find_string_property(root, "/openprom/options/env");
439 current_environment = ((strcmp(env, "user") == 0
440 || strcmp(env, "uea") == 0)
441 ? USER_ENVIRONMENT
442 : (strcmp(env, "virtual") == 0
443 || strcmp(env, "vea") == 0)
444 ? VIRTUAL_ENVIRONMENT
445 : (strcmp(env, "operating") == 0
446 || strcmp(env, "oea") == 0)
447 ? OPERATING_ENVIRONMENT
448 : 0);
449 if (current_environment == 0)
450 error("unreconized /options env property\n");
451 if (CURRENT_ENVIRONMENT != current_environment)
452 error("target and configured environment conflict\n");
453
454 /* fill in the missing ALLIGNMENT information */
455 current_alignment
456 = (tree_find_boolean_property(root, "/openprom/options/strict-alignment?")
457 ? STRICT_ALIGNMENT
458 : NONSTRICT_ALIGNMENT);
459 if (CURRENT_ALIGNMENT != current_alignment)
460 error("target and configured alignment conflict\n");
461
462 /* fill in the missing FLOATING POINT information */
463 current_floating_point
464 = (tree_find_boolean_property(root, "/openprom/options/floating-point?")
465 ? HARD_FLOATING_POINT
466 : SOFT_FLOATING_POINT);
467 if (CURRENT_FLOATING_POINT != current_floating_point)
468 error("target and configured floating-point conflict\n");
469
470 /* fill in the missing STDIO information */
471 current_stdio
472 = (tree_find_boolean_property(root, "/openprom/options/use-stdio?")
473 ? DO_USE_STDIO
474 : DONT_USE_STDIO);
475 if (CURRENT_STDIO != current_stdio)
476 error("target and configured stdio interface conflict\n");
477
478 /* sort out the level of detail for issue modeling */
479 current_model_issue
480 = tree_find_integer_property(root, "/openprom/options/model-issue");
481 if (CURRENT_MODEL_ISSUE != current_model_issue)
482 error("target and configured model-issue conflict\n");
483
484 /* sort out our model architecture - wrong.
485
486 FIXME: this should be obtaining the required information from the
487 device tree via the "/chosen" property "cpu" which is an instance
488 (ihandle) for the only executing processor. By converting that
489 ihandle into the corresponding cpu's phandle and then querying
490 the "name" property, the cpu type can be determined. Ok? */
491
492 model_set(tree_find_string_property(root, "/openprom/options/model"));
493
494 /* create things */
495 system = ZALLOC(psim);
496 system->events = event_queue_create();
497 system->memory = core_from_device(root);
498 system->monitor = mon_create();
499 system->nr_cpus = nr_cpus;
500 system->os_emulation = os_emulation;
501 system->devices = root;
502
503 /* now all the processors attaching to each their per-cpu information */
504 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
505 system->processors[cpu_nr] = cpu_create(system,
506 system->memory,
507 mon_cpu(system->monitor,
508 cpu_nr),
509 system->os_emulation,
510 cpu_nr);
511 }
512
513 /* dump out the contents of the device tree */
514 if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
515 tree_print(root);
516 if (ppc_trace[trace_dump_device_tree])
517 error("");
518
519 return system;
520 }
521
522
523 /* allow the simulation to stop/restart abnormaly */
524
525 INLINE_PSIM\
526 (void)
527 psim_set_halt_and_restart(psim *system,
528 void *halt_jmp_buf,
529 void *restart_jmp_buf)
530 {
531 system->path_to_halt = halt_jmp_buf;
532 system->path_to_restart = restart_jmp_buf;
533 }
534
535 INLINE_PSIM\
536 (void)
537 psim_clear_halt_and_restart(psim *system)
538 {
539 system->path_to_halt = NULL;
540 system->path_to_restart = NULL;
541 }
542
543 INLINE_PSIM\
544 (void)
545 psim_restart(psim *system,
546 int current_cpu)
547 {
548 ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus);
549 ASSERT(system->path_to_restart != NULL);
550 system->last_cpu = current_cpu;
551 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
552 }
553
554
555 static void
556 cntrl_c_simulation(void *data)
557 {
558 psim *system = data;
559 psim_halt(system,
560 psim_nr_cpus(system),
561 was_continuing,
562 SIGINT);
563 }
564
565 INLINE_PSIM\
566 (void)
567 psim_stop(psim *system)
568 {
569 event_queue_schedule_after_signal(psim_event_queue(system),
570 0 /*NOW*/,
571 cntrl_c_simulation,
572 system);
573 }
574
575 INLINE_PSIM\
576 (void)
577 psim_halt(psim *system,
578 int current_cpu,
579 stop_reason reason,
580 int signal)
581 {
582 ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus);
583 ASSERT(system->path_to_halt != NULL);
584 system->last_cpu = current_cpu;
585 system->halt_status.reason = reason;
586 system->halt_status.signal = signal;
587 if (current_cpu == system->nr_cpus) {
588 system->halt_status.cpu_nr = 0;
589 system->halt_status.program_counter =
590 cpu_get_program_counter(system->processors[0]);
591 }
592 else {
593 system->halt_status.cpu_nr = current_cpu;
594 system->halt_status.program_counter =
595 cpu_get_program_counter(system->processors[current_cpu]);
596 }
597 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
598 }
599
600
601 INLINE_PSIM\
602 (int)
603 psim_last_cpu(psim *system)
604 {
605 return system->last_cpu;
606 }
607
608 INLINE_PSIM\
609 (int)
610 psim_nr_cpus(psim *system)
611 {
612 return system->nr_cpus;
613 }
614
615 INLINE_PSIM\
616 (psim_status)
617 psim_get_status(psim *system)
618 {
619 return system->halt_status;
620 }
621
622
623 INLINE_PSIM\
624 (cpu *)
625 psim_cpu(psim *system,
626 int cpu_nr)
627 {
628 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
629 return NULL;
630 else
631 return system->processors[cpu_nr];
632 }
633
634
635 INLINE_PSIM\
636 (device *)
637 psim_device(psim *system,
638 const char *path)
639 {
640 return tree_find_device(system->devices, path);
641 }
642
643 INLINE_PSIM\
644 (event_queue *)
645 psim_event_queue(psim *system)
646 {
647 return system->events;
648 }
649
650
651
652 STATIC_INLINE_PSIM\
653 (void)
654 psim_max_iterations_exceeded(void *data)
655 {
656 psim *system = data;
657 psim_halt(system,
658 system->nr_cpus, /* halted during an event */
659 was_signalled,
660 -1);
661 }
662
663
664 INLINE_PSIM\
665 (void)
666 psim_init(psim *system)
667 {
668 int cpu_nr;
669
670 /* scrub the monitor */
671 mon_init(system->monitor, system->nr_cpus);
672
673 /* trash any pending events */
674 event_queue_init(system->events);
675
676 /* if needed, schedule a halt event. FIXME - In the future this
677 will be replaced by a more generic change to psim_command(). A
678 new command `schedule NNN halt' being added. */
679 if (tree_find_property(system->devices, "/openprom/options/max-iterations")) {
680 event_queue_schedule(system->events,
681 tree_find_integer_property(system->devices,
682 "/openprom/options/max-iterations") - 2,
683 psim_max_iterations_exceeded,
684 system);
685 }
686
687 /* scrub all the cpus */
688 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
689 cpu_init(system->processors[cpu_nr]);
690
691 /* init all the devices (which updates the cpus) */
692 tree_init(system->devices, system);
693
694 /* and the emulation (which needs an initialized device tree) */
695 os_emul_init(system->os_emulation, system->nr_cpus);
696
697 /* now sync each cpu against the initialized state of its registers */
698 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
699 cpu *processor = system->processors[cpu_nr];
700 cpu_synchronize_context(processor, cpu_get_program_counter(processor));
701 cpu_page_tlb_invalidate_all(processor);
702 }
703
704 /* force loop to start with first cpu */
705 system->last_cpu = -1;
706 }
707
708 INLINE_PSIM\
709 (void)
710 psim_stack(psim *system,
711 char **argv,
712 char **envp)
713 {
714 /* pass the stack device the argv/envp and let it work out what to
715 do with it */
716 device *stack_device = tree_find_device(system->devices,
717 "/openprom/init/stack");
718 if (stack_device != (device*)0) {
719 unsigned_word stack_pointer;
720 psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
721 device_ioctl(stack_device,
722 NULL, /*cpu*/
723 0, /*cia*/
724 device_ioctl_create_stack,
725 stack_pointer,
726 argv,
727 envp);
728 }
729 }
730
731
732
733 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
734 thing */
735
736 INLINE_PSIM\
737 (void)
738 psim_step(psim *system)
739 {
740 volatile int keep_running = 0;
741 idecode_run_until_stop(system, &keep_running,
742 system->events, system->processors, system->nr_cpus);
743 }
744
745 INLINE_PSIM\
746 (void)
747 psim_run(psim *system)
748 {
749 idecode_run(system,
750 system->events, system->processors, system->nr_cpus);
751 }
752
753
754 /* storage manipulation functions */
755
756 INLINE_PSIM\
757 (void)
758 psim_read_register(psim *system,
759 int which_cpu,
760 void *buf,
761 const char reg[],
762 transfer_mode mode)
763 {
764 register_descriptions description;
765 char cooked_buf[sizeof(unsigned_8)];
766 cpu *processor;
767
768 /* find our processor */
769 if (which_cpu == MAX_NR_PROCESSORS) {
770 if (system->last_cpu == system->nr_cpus
771 || system->last_cpu == -1)
772 which_cpu = 0;
773 else
774 which_cpu = system->last_cpu;
775 }
776 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
777
778 processor = system->processors[which_cpu];
779
780 /* find the register description */
781 description = register_description(reg);
782 if (description.type == reg_invalid)
783 error("psim_read_register() invalid register name `%s'\n", reg);
784
785 /* get the cooked value */
786 switch (description.type) {
787
788 case reg_gpr:
789 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
790 break;
791
792 case reg_spr:
793 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
794 break;
795
796 case reg_sr:
797 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
798 break;
799
800 case reg_fpr:
801 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
802 break;
803
804 case reg_pc:
805 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
806 break;
807
808 case reg_cr:
809 *(creg*)cooked_buf = cpu_registers(processor)->cr;
810 break;
811
812 case reg_msr:
813 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
814 break;
815
816 case reg_fpscr:
817 *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr;
818 break;
819
820 case reg_insns:
821 *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
822 which_cpu);
823 break;
824
825 case reg_stalls:
826 if (cpu_model(processor) == NULL)
827 error("$stalls only valid if processor unit model enabled (-I)\n");
828 *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
829 break;
830
831 case reg_cycles:
832 if (cpu_model(processor) == NULL)
833 error("$cycles only valid if processor unit model enabled (-I)\n");
834 *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
835 break;
836
837 default:
838 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
839 (unsigned long)processor, (unsigned long)buf, reg,
840 "read of this register unimplemented");
841 break;
842
843 }
844
845 /* the PSIM internal values are in host order. To fetch raw data,
846 they need to be converted into target order and then returned */
847 if (mode == raw_transfer) {
848 /* FIXME - assumes that all registers are simple integers */
849 switch (description.size) {
850 case 1:
851 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
852 break;
853 case 2:
854 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
855 break;
856 case 4:
857 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
858 break;
859 case 8:
860 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
861 break;
862 }
863 }
864 else {
865 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
866 }
867
868 }
869
870
871
872 INLINE_PSIM\
873 (void)
874 psim_write_register(psim *system,
875 int which_cpu,
876 const void *buf,
877 const char reg[],
878 transfer_mode mode)
879 {
880 cpu *processor;
881 register_descriptions description;
882 char cooked_buf[sizeof(unsigned_8)];
883
884 /* find our processor */
885 if (which_cpu == MAX_NR_PROCESSORS) {
886 if (system->last_cpu == system->nr_cpus
887 || system->last_cpu == -1)
888 which_cpu = 0;
889 else
890 which_cpu = system->last_cpu;
891 }
892 if (which_cpu == -1) {
893 int i;
894 for (i = 0; i < system->nr_cpus; i++)
895 psim_write_register(system, i, buf, reg, mode);
896 return;
897 }
898 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
899
900 processor = system->processors[which_cpu];
901
902 /* find the description of the register */
903 description = register_description(reg);
904 if (description.type == reg_invalid)
905 error("psim_write_register() invalid register name %s\n", reg);
906
907 /* If the data is comming in raw (target order), need to cook it
908 into host order before putting it into PSIM's internal structures */
909 if (mode == raw_transfer) {
910 switch (description.size) {
911 case 1:
912 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
913 break;
914 case 2:
915 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
916 break;
917 case 4:
918 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
919 break;
920 case 8:
921 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
922 break;
923 }
924 }
925 else {
926 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
927 }
928
929 /* put the cooked value into the register */
930 switch (description.type) {
931
932 case reg_gpr:
933 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
934 break;
935
936 case reg_fpr:
937 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
938 break;
939
940 case reg_pc:
941 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
942 break;
943
944 case reg_spr:
945 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
946 break;
947
948 case reg_sr:
949 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
950 break;
951
952 case reg_cr:
953 cpu_registers(processor)->cr = *(creg*)cooked_buf;
954 break;
955
956 case reg_msr:
957 cpu_registers(processor)->msr = *(msreg*)cooked_buf;
958 break;
959
960 case reg_fpscr:
961 cpu_registers(processor)->fpscr = *(fpscreg*)cooked_buf;
962 break;
963
964 default:
965 printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
966 (unsigned long)processor, (unsigned long)cooked_buf, reg,
967 "read of this register unimplemented");
968 break;
969
970 }
971
972 }
973
974
975
976 INLINE_PSIM\
977 (unsigned)
978 psim_read_memory(psim *system,
979 int which_cpu,
980 void *buffer,
981 unsigned_word vaddr,
982 unsigned nr_bytes)
983 {
984 cpu *processor;
985 if (which_cpu == MAX_NR_PROCESSORS) {
986 if (system->last_cpu == system->nr_cpus
987 || system->last_cpu == -1)
988 which_cpu = 0;
989 else
990 which_cpu = system->last_cpu;
991 }
992 processor = system->processors[which_cpu];
993 return vm_data_map_read_buffer(cpu_data_map(processor),
994 buffer, vaddr, nr_bytes,
995 NULL, -1);
996 }
997
998
999 INLINE_PSIM\
1000 (unsigned)
1001 psim_write_memory(psim *system,
1002 int which_cpu,
1003 const void *buffer,
1004 unsigned_word vaddr,
1005 unsigned nr_bytes,
1006 int violate_read_only_section)
1007 {
1008 cpu *processor;
1009 if (which_cpu == MAX_NR_PROCESSORS) {
1010 if (system->last_cpu == system->nr_cpus
1011 || system->last_cpu == -1)
1012 which_cpu = 0;
1013 else
1014 which_cpu = system->last_cpu;
1015 }
1016 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
1017 processor = system->processors[which_cpu];
1018 return vm_data_map_write_buffer(cpu_data_map(processor),
1019 buffer, vaddr, nr_bytes, 1/*violate-read-only*/,
1020 NULL, -1);
1021 }
1022
1023
1024 INLINE_PSIM\
1025 (void)
1026 psim_print_info(psim *system,
1027 int verbose)
1028 {
1029 mon_print_info(system, system->monitor, verbose);
1030 }
1031
1032
1033 /* Merge a device tree and a device file. */
1034
1035 INLINE_PSIM\
1036 (void)
1037 psim_merge_device_file(device *root,
1038 const char *file_name)
1039 {
1040 FILE *description;
1041 int line_nr;
1042 char device_path[1000];
1043 device *current;
1044
1045 /* try opening the file */
1046 description = fopen(file_name, "r");
1047 if (description == NULL) {
1048 perror(file_name);
1049 error("Invalid file %s specified", file_name);
1050 }
1051
1052 line_nr = 0;
1053 current = root;
1054 while (fgets(device_path, sizeof(device_path), description)) {
1055 char *device;
1056 /* check that the full line was read */
1057 if (strchr(device_path, '\n') == NULL) {
1058 fclose(description);
1059 error("%s:%d: line to long - %s",
1060 file_name, line_nr, device_path);
1061 }
1062 else
1063 *strchr(device_path, '\n') = '\0';
1064 line_nr++;
1065 /* skip comments ("#" or ";") and blank lines lines */
1066 for (device = device_path;
1067 *device != '\0' && isspace(*device);
1068 device++);
1069 if (device[0] == '#'
1070 || device[0] == ';'
1071 || device[0] == '\0')
1072 continue;
1073 /* merge any appended lines */
1074 while (device_path[strlen(device_path) - 1] == '\\') {
1075 int curlen = strlen(device_path) - 1;
1076 /* zap \ */
1077 device_path[curlen] = '\0';
1078 /* append the next line */
1079 if (!fgets(device_path + curlen, sizeof(device_path) - curlen, description)) {
1080 fclose(description);
1081 error("%s:%s: unexpected eof in line continuation - %s",
1082 file_name, line_nr, device_path);
1083 }
1084 if (strchr(device_path, '\n') == NULL) {
1085 fclose(description);
1086 error("%s:%d: line to long - %s",
1087 file_name, line_nr, device_path);
1088 }
1089 else
1090 *strchr(device_path, '\n') = '\0';
1091 line_nr++;
1092 }
1093 /* parse this line */
1094 current = tree_parse(current, "%s", device);
1095 }
1096 fclose(description);
1097 }
1098
1099
1100 #endif /* _PSIM_C_ */