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