Use autoconf correctly; provide more stats with -I
[deliverable/binutils-gdb.git] / sim / ppc / psim.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1995, 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 <stdio.h>
26 #include <ctype.h>
27
28 #include "config.h"
29 #include "ppc-config.h"
30 #include "inline.h"
31
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35
36 #ifndef STATIC_INLINE_PSIM
37 #define STATIC_INLINE_PSIM STATIC_INLINE
38 #endif
39
40 #include <setjmp.h>
41
42 #include "cpu.h" /* includes psim.h */
43 #include "idecode.h"
44
45 #ifdef HAVE_STRING_H
46 #include <string.h>
47 #else
48 #ifdef HAVE_STRINGS_H
49 #include <strings.h>
50 #endif
51 #endif
52
53 #include "bfd.h"
54
55
56 #include "inline.c"
57
58 /* Any starting address less than this is assumed to be an OEA program
59 rather than VEA. */
60 #ifndef OEA_START_ADDRESS
61 #define OEA_START_ADDRESS 4096
62 #endif
63
64 /* Any starting address greater than this is assumed to be an OpenBoot
65 rather than VEA */
66 #ifndef OPENBOOT_START_ADDRESS
67 #define OPENBOOT_START_ADDRESS 0x80000000
68 #endif
69
70 #ifndef OEA_MEMORY_SIZE
71 #define OEA_MEMORY_SIZE 0x100000
72 #endif
73
74
75 /* system structure, actual size of processor array determined at
76 runtime */
77
78 struct _psim {
79 event_queue *events;
80 device_tree *devices;
81 mon *monitor;
82 core *memory;
83 /* escape routine for inner functions */
84 void *path_to_halt;
85 void *path_to_restart;
86 /* status from last halt */
87 psim_status halt_status;
88 /* the processes proper */
89 int nr_cpus;
90 int last_cpu; /* CPU that last (tried to) execute an instruction */
91 cpu *processors[MAX_NR_PROCESSORS];
92 };
93
94
95 int current_target_byte_order;
96 int current_host_byte_order;
97 int current_environment;
98 int current_alignment;
99 int current_floating_point;
100
101
102 /* create a device tree from the image */
103
104
105
106 /* Raw hardware tree:
107
108 A small default set of devices are configured. Each section of the
109 image is loaded directly into physical memory. */
110
111 STATIC_INLINE_PSIM void
112 create_hardware_device_tree(bfd *image,
113 device_tree *root)
114 {
115 char *name;
116 const memory_size = OEA_MEMORY_SIZE;
117
118 /* options */
119 device_tree_add_passthrough(root, "/options");
120 device_tree_add_integer(root, "/options/smp",
121 MAX_NR_PROCESSORS);
122 device_tree_add_boolean(root, "/options/little-endian?",
123 !image->xvec->byteorder_big_p);
124 device_tree_add_string(root, "/options/environment-architecture",
125 "operating");
126 device_tree_add_boolean(root, "/options/strict-alignment?",
127 (WITH_ALIGNMENT == STRICT_ALIGNMENT
128 || !image->xvec->byteorder_big_p));
129 device_tree_add_boolean(root, "/options/floating-point?",
130 WITH_FLOATING_POINT);
131
132 /* hardware */
133 name = printd_uw_u_u("/memory", 0, memory_size, access_read_write_exec);
134 device_tree_add_found_device(root, name);
135 zfree(name);
136 device_tree_add_found_device(root, "/iobus@0x400000");
137 device_tree_add_found_device(root, "/iobus/console@0x000000,16");
138 device_tree_add_found_device(root, "/iobus/halt@0x100000,4");
139 device_tree_add_found_device(root, "/iobus/icu@0x200000,4");
140
141 /* initialization */
142 device_tree_add_passthrough(root, "/init");
143 device_tree_add_found_device(root, "/init/register@pc,0x0");
144 name = printd_c_uw("/init/register", "sp", memory_size);
145 device_tree_add_found_device(root, name);
146 zfree(name);
147 name = printd_c_uw("/init/register", "msr",
148 (image->xvec->byteorder_big_p
149 ? 0
150 : msr_little_endian_mode));
151 device_tree_add_found_device(root, name);
152 zfree(name);
153 /* AJC puts the PC at zero and wants a stack while MM puts it above
154 zero and doesn't. Really there should be no stack *but* this
155 makes testing easier */
156 device_tree_add_found_device(root,
157 (bfd_get_start_address(image) == 0
158 ? "/init/stack@elf"
159 : "/init/stack@none"));
160 name = printd_c("/init/load-binary", bfd_get_filename(image));
161 device_tree_add_found_device(root, name);
162 zfree(name);
163 }
164
165
166 /* Openboot model (under development):
167
168 An extension of the hardware model. The image is read into memory
169 as a single block. Sections of the image are then mapped as
170 required using a HTAB. */
171
172 STATIC_INLINE_PSIM void
173 create_openboot_device_tree(bfd *image,
174 device_tree *root)
175 {
176 create_hardware_device_tree(image, root);
177 }
178
179
180 /* User mode model:
181
182 Image sections loaded into virtual addresses as specified. A
183 (large) stack is reserved (but only allocated as needed). System
184 calls that include suport for heap growth are attached. */
185
186 STATIC_INLINE_PSIM void
187 create_vea_device_tree(bfd *image,
188 device_tree *root)
189 {
190 unsigned_word top_of_stack;
191 unsigned stack_size;
192 int elf_binary;
193 char *name;
194
195 /* establish a few defaults */
196 if (image->xvec->flavour == bfd_target_elf_flavour) {
197 elf_binary = 1;
198 top_of_stack = 0xe0000000;
199 stack_size = 0x00100000;
200 }
201 else {
202 elf_binary = 0;
203 top_of_stack = 0x20000000;
204 stack_size = 0x00100000;
205 }
206
207 /* options */
208 device_tree_add_passthrough(root, "/options");
209 device_tree_add_integer(root, "/options/smp", 1); /* always */
210 device_tree_add_boolean(root, "/options/little-endian?",
211 !image->xvec->byteorder_big_p);
212 device_tree_add_string(root, "/options/environment-architecture",
213 (WITH_ENVIRONMENT == USER_ENVIRONMENT
214 ? "user" : "virtual"));
215 device_tree_add_boolean(root, "/options/strict-alignment?",
216 (WITH_ALIGNMENT == STRICT_ALIGNMENT
217 || !image->xvec->byteorder_big_p));
218 device_tree_add_boolean(root, "/options/floating-point?",
219 WITH_FLOATING_POINT);
220
221 /* virtual memory - handles growth of stack/heap */
222 name = printd_uw_u("/vm", top_of_stack - stack_size, stack_size);
223 device_tree_add_found_device(root, name);
224 zfree(name);
225 name = printd_c("/vm/map-binary", bfd_get_filename(image));
226 device_tree_add_found_device(root, name);
227 zfree(name);
228
229 /* finish the init */
230 device_tree_add_passthrough(root, "/init");
231 name = printd_c_uw("/init/register", "pc", bfd_get_start_address(image));
232 device_tree_add_found_device(root, name); /*pc*/
233 zfree(name);
234 name = printd_c_uw("/init/register", "sp", top_of_stack);
235 device_tree_add_found_device(root, name);
236 zfree(name);
237 name = printd_c_uw("/init/register", "msr",
238 (image->xvec->byteorder_big_p
239 ? 0
240 : msr_little_endian_mode));
241 device_tree_add_found_device(root, name);
242 zfree(name);
243 device_tree_add_found_device(root, (elf_binary
244 ? "/init/stack@elf"
245 : "/init/stack@xcoff"));
246 }
247
248
249 /* File device:
250
251 The file contains lines that specify the describe the device tree
252 to be created, read them in and load them into the tree */
253
254 STATIC_INLINE_PSIM void
255 create_filed_device_tree(const char *file_name,
256 device_tree *root)
257 {
258 FILE *description = fopen(file_name, "r");
259 int line_nr = 0;
260 char device_path[1000];
261 while (fgets(device_path, sizeof(device_path), description)) {
262 /* check all of line was read */
263 {
264 char *end = strchr(device_path, '\n');
265 if (end == NULL) {
266 fclose(description);
267 error("create_filed_device_tree() line %d to long: %s\n",
268 line_nr, device_path);
269 }
270 line_nr++;
271 *end = '\0';
272 }
273 /* check for leading comment */
274 if (device_path[0] != '/')
275 continue;
276 /* enter it in varying ways */
277 if (strchr(device_path, '@') != NULL) {
278 device_tree_add_found_device(root, device_path);
279 }
280 else {
281 char *space = strchr(device_path, ' ');
282 if (space == NULL) {
283 /* intermediate node */
284 device_tree_add_passthrough(root, device_path);
285 }
286 else if (space[-1] == '?') {
287 /* boolean */
288 *space = '\0';
289 device_tree_add_boolean(root, device_path, space[1] != '0');
290 }
291 else if (isdigit(space[1])) {
292 /* integer */
293 *space = '\0';
294 device_tree_add_integer(root, device_path, strtoul(space+1, 0, 0));
295 }
296 else if (space[1] == '"') {
297 /* quoted string */
298 char *end = strchr(space+2, '\0');
299 if (end[-1] == '"')
300 end[-1] = '\0';
301 *space = '\0';
302 device_tree_add_string(root, device_path, space + 2);
303 }
304 else {
305 /* any thing else */
306 space = '\0';
307 device_tree_add_string(root, device_path, space + 1);
308 }
309 }
310 }
311 fclose(description);
312 }
313
314
315 /* Given the file containing the `image', create a device tree that
316 defines the machine to be modeled */
317
318 STATIC_INLINE_PSIM device_tree *
319 create_device_tree(const char *file_name,
320 core *memory)
321 {
322 bfd *image;
323 const device *core_device = core_device_create(memory);
324 device_tree *root = device_tree_add_device(NULL, "/", core_device);
325
326 bfd_init(); /* could be redundant but ... */
327
328 /* open the file */
329 image = bfd_openr(file_name, NULL);
330 if (image == NULL) {
331 bfd_perror("open failed:");
332 error("nothing loaded\n");
333 }
334
335 /* check it is valid */
336 if (!bfd_check_format(image, bfd_object)) {
337 printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
338 printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
339 bfd_close(image);
340 image = NULL;
341 }
342
343 /* depending on what was found about the file, load it */
344 if (image != NULL) {
345 if (bfd_get_start_address(image) < OEA_START_ADDRESS) {
346 TRACE(trace_device_tree, ("create_device_tree() - hardware image\n"));
347 create_hardware_device_tree(image, root);
348 }
349 else if (bfd_get_start_address(image) < OPENBOOT_START_ADDRESS) {
350 TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
351 create_vea_device_tree(image, root);
352 }
353 else {
354 TRACE(trace_device_tree, ("create_device_tree() - openboot? image\n"));
355 create_openboot_device_tree(image, root);
356 }
357 bfd_close(image);
358 }
359 else {
360 TRACE(trace_device_tree, ("create_device_tree() - text image\n"));
361 create_filed_device_tree(file_name, root);
362 }
363
364 return root;
365 }
366
367
368
369 INLINE_PSIM psim *
370 psim_create(const char *file_name)
371 {
372 int cpu_nr;
373 const char *env;
374 psim *system;
375
376 /* create things */
377 system = ZALLOC(psim);
378 system->events = event_queue_create();
379 system->memory = core_create();
380 system->monitor = mon_create();
381 system->devices = create_device_tree(file_name, system->memory);
382 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
383 system->processors[cpu_nr] = cpu_create(system,
384 system->memory,
385 system->events,
386 mon_cpu(system->monitor,
387 cpu_nr),
388 cpu_nr);
389 }
390
391 /* fill in the missing real number of CPU's */
392 system->nr_cpus = device_tree_find_integer(system->devices,
393 "/options/smp");
394
395 /* fill in the missing TARGET BYTE ORDER information */
396 current_target_byte_order = (device_tree_find_boolean(system->devices,
397 "/options/little-endian?")
398 ? LITTLE_ENDIAN
399 : BIG_ENDIAN);
400 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
401 error("target byte order conflict\n");
402
403 /* fill in the missing HOST BYTE ORDER information */
404 current_host_byte_order = (current_host_byte_order = 1,
405 (*(char*)(&current_host_byte_order)
406 ? LITTLE_ENDIAN
407 : BIG_ENDIAN));
408 if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
409 error("host byte order conflict\n");
410
411 /* fill in the missing OEA/VEA information */
412 env = device_tree_find_string(system->devices,
413 "/options/environment-architecture");
414 current_environment = (strcmp(env, "user") == 0
415 ? USER_ENVIRONMENT
416 : strcmp(env, "virtual") == 0
417 ? VIRTUAL_ENVIRONMENT
418 : strcmp(env, "operating") == 0
419 ? OPERATING_ENVIRONMENT
420 : 0);
421 if (current_environment == 0)
422 error("unreconized /options/environment-architecture\n");
423 if (CURRENT_ENVIRONMENT != current_environment)
424 error("target environment conflict\n");
425
426 /* fill in the missing ALLIGNMENT information */
427 current_alignment = (device_tree_find_boolean(system->devices,
428 "/options/strict-alignment?")
429 ? STRICT_ALIGNMENT
430 : NONSTRICT_ALIGNMENT);
431 if (CURRENT_ALIGNMENT != current_alignment)
432 error("target alignment conflict\n");
433
434 /* fill in the missing FLOATING POINT information */
435 current_floating_point = (device_tree_find_boolean(system->devices,
436 "/options/floating-point?")
437 ? HARD_FLOATING_POINT
438 : SOFT_FLOATING_POINT);
439 if (CURRENT_FLOATING_POINT != current_floating_point)
440 error("target floating-point conflict\n");
441
442 return system;
443 }
444
445
446 /* allow the simulation to stop/restart abnormaly */
447
448 STATIC_INLINE_PSIM void
449 psim_set_halt_and_restart(psim *system,
450 void *halt_jmp_buf,
451 void *restart_jmp_buf)
452 {
453 system->path_to_halt = halt_jmp_buf;
454 system->path_to_restart = restart_jmp_buf;
455 }
456
457 STATIC_INLINE_PSIM void
458 psim_clear_halt_and_restart(psim *system)
459 {
460 system->path_to_halt = NULL;
461 system->path_to_restart = NULL;
462 }
463
464 INLINE_PSIM void
465 psim_restart(psim *system,
466 int current_cpu)
467 {
468 system->last_cpu = current_cpu;
469 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
470 }
471
472
473 INLINE_PSIM void
474 psim_halt(psim *system,
475 int current_cpu,
476 unsigned_word cia,
477 stop_reason reason,
478 int signal)
479 {
480 system->last_cpu = current_cpu;
481 system->halt_status.cpu_nr = current_cpu;
482 system->halt_status.reason = reason;
483 system->halt_status.signal = signal;
484 system->halt_status.program_counter = cia;
485 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
486 }
487
488 INLINE_PSIM psim_status
489 psim_get_status(psim *system)
490 {
491 return system->halt_status;
492 }
493
494
495 cpu *
496 psim_cpu(psim *system,
497 int cpu_nr)
498 {
499 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
500 return NULL;
501 else
502 return system->processors[cpu_nr];
503 }
504
505
506 const device *
507 psim_device(psim *system,
508 const char *path)
509 {
510 return device_tree_find_device(system->devices, path);
511 }
512
513
514
515 INLINE_PSIM void
516 psim_init(psim *system)
517 {
518 int cpu_nr;
519
520 /* scrub the monitor */
521 mon_init(system->monitor, system->nr_cpus);
522
523 /* scrub all the cpus */
524 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
525 cpu_init(system->processors[cpu_nr]);
526
527 /* init all the devices */
528 device_tree_init(system->devices, system);
529
530 /* force loop to restart */
531 system->last_cpu = system->nr_cpus - 1;
532 }
533
534 INLINE_PSIM void
535 psim_stack(psim *system,
536 char **argv,
537 char **envp)
538 {
539 /* pass the stack device the argv/envp and let it work out what to
540 do with it */
541 const device *stack_device = device_tree_find_device(system->devices,
542 "/init/stack");
543 unsigned_word stack_pointer;
544 psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
545 stack_device->callback->ioctl(stack_device,
546 system,
547 NULL, /*cpu*/
548 0, /*cia*/
549 stack_pointer,
550 argv,
551 envp);
552 }
553
554
555
556 /* EXECUTE REAL CODE:
557
558 Unfortunatly, there are multiple cases to consider vis:
559
560 <icache> X <smp> X <events> X <keep-running-flag> X ...
561
562 Consequently this function is written in multiple different ways */
563
564 STATIC_INLINE_PSIM void
565 run_until_stop(psim *system,
566 volatile int *keep_running)
567 {
568 jmp_buf halt;
569 jmp_buf restart;
570 int cpu_nr;
571 #if WITH_IDECODE_CACHE_SIZE
572 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
573 cpu_flush_icache(system->processors[cpu_nr]);
574 #endif
575 psim_set_halt_and_restart(system, &halt, &restart);
576
577 #if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
578
579 /* CASE 1: No instruction cache and no SMP.
580
581 In this case, we can take advantage of the fact that the current
582 instruction address does not need to be returned to the cpu
583 object after every execution of an instruction. Instead it only
584 needs to be saved when either A. the main loop exits or B. a
585 cpu-{halt,restart} call forces the loop to be re-entered. The
586 later functions always save the current cpu instruction
587 address. */
588
589 if (!setjmp(halt)) {
590 do {
591 if (!setjmp(restart)) {
592 cpu *const processor = system->processors[0];
593 unsigned_word cia = cpu_get_program_counter(processor);
594 do {
595 if (WITH_EVENTS) {
596 if (event_queue_tick(system->events)) {
597 cpu_set_program_counter(processor, cia);
598 event_queue_process(system->events);
599 cia = cpu_get_program_counter(processor);
600 }
601 }
602 {
603 instruction_word const instruction
604 = vm_instruction_map_read(cpu_instruction_map(processor),
605 processor, cia);
606 cia = idecode_issue(processor, instruction, cia);
607 }
608 } while (keep_running == NULL || *keep_running);
609 cpu_set_program_counter(processor, cia);
610 }
611 } while(keep_running == NULL || *keep_running);
612 }
613 #endif
614
615
616 #if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
617
618 /* CASE 2: Instruction case but no SMP
619
620 Here, the additional complexity comes from there being two
621 different cache implementations. A simple function address cache
622 or a full cracked instruction cache */
623
624 if (!setjmp(halt)) {
625 do {
626 if (!setjmp(restart)) {
627 cpu *const processor = system->processors[0];
628 unsigned_word cia = cpu_get_program_counter(processor);
629 do {
630 if (WITH_EVENTS)
631 if (event_queue_tick(system->events)) {
632 cpu_set_program_counter(processor, cia);
633 event_queue_process(system->events);
634 cia = cpu_get_program_counter(processor);
635 }
636 {
637 idecode_cache *const cache_entry = cpu_icache_entry(processor,
638 cia);
639 if (cache_entry->address == cia) {
640 idecode_semantic *const semantic = cache_entry->semantic;
641 cia = semantic(processor, cache_entry, cia);
642 }
643 else {
644 instruction_word const instruction
645 = vm_instruction_map_read(cpu_instruction_map(processor),
646 processor,
647 cia);
648 idecode_semantic *const semantic = idecode(processor,
649 instruction,
650 cia,
651 cache_entry);
652 cache_entry->address = cia;
653 cache_entry->semantic = semantic;
654 cia = semantic(processor, cache_entry, cia);
655 }
656 }
657 } while (keep_running == NULL || *keep_running);
658 cpu_set_program_counter(processor, cia);
659 }
660 } while(keep_running == NULL || *keep_running);
661 }
662 #endif
663
664
665 #if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
666
667 /* CASE 3: No ICACHE but SMP
668
669 The complexity here comes from needing to correctly restart the
670 system when it is aborted. In particular if cpu0 requests a
671 restart, the next cpu is still cpu1. Cpu0 being restarted after
672 all the other CPU's and the event queue have been processed */
673
674 if (!setjmp(halt)) {
675 int first_cpu = setjmp(restart);
676 if (first_cpu == 0)
677 first_cpu = system->last_cpu + 1;
678 do {
679 int current_cpu;
680 for (current_cpu = first_cpu, first_cpu = 0;
681 current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
682 current_cpu++) {
683 if (WITH_EVENTS && current_cpu == system->nr_cpus) {
684 if (event_queue_tick(system->events))
685 event_queue_process(system->events);
686 }
687 else {
688 cpu *const processor = system->processors[current_cpu];
689 unsigned_word const cia = cpu_get_program_counter(processor);
690 instruction_word instruction =
691 vm_instruction_map_read(cpu_instruction_map(processor),
692 processor,
693 cia);
694 cpu_set_program_counter(processor,
695 idecode_issue(processor, instruction, cia));
696 }
697 if (!(keep_running == NULL || *keep_running)) {
698 system->last_cpu = current_cpu;
699 break;
700 }
701 }
702 } while (keep_running == NULL || *keep_running);
703 }
704 #endif
705
706 #if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
707
708 /* CASE 4: ICACHE and SMP ...
709
710 This time, everything goes wrong. Need to restart loops
711 correctly, need to save the program counter and finally need to
712 keep track of each processors current address! */
713
714 if (!setjmp(halt)) {
715 int first_cpu = setjmp(restart);
716 if (!first_cpu)
717 first_cpu = system->last_cpu + 1;
718 do {
719 int current_cpu;
720 for (current_cpu = first_cpu, first_cpu = 0;
721 current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
722 current_cpu++) {
723 if (WITH_EVENTS && current_cpu == system->nr_cpus) {
724 if (event_queue_tick(system->events))
725 event_queue_process(system->events);
726 }
727 else {
728 cpu *processor = system->processors[current_cpu];
729 unsigned_word const cia = cpu_get_program_counter(processor);
730 idecode_cache *cache_entry = cpu_icache_entry(processor, cia);
731 if (cache_entry->address == cia) {
732 idecode_semantic *semantic = cache_entry->semantic;
733 cpu_set_program_counter(processor,
734 semantic(processor, cache_entry, cia));
735 }
736 else {
737 instruction_word instruction =
738 vm_instruction_map_read(cpu_instruction_map(processor),
739 processor,
740 cia);
741 idecode_semantic *semantic = idecode(processor,
742 instruction,
743 cia,
744 cache_entry);
745 cache_entry->address = cia;
746 cache_entry->semantic = semantic;
747 cpu_set_program_counter(processor,
748 semantic(processor, cache_entry, cia));
749 }
750 }
751 if (!(keep_running == NULL || *keep_running))
752 break;
753 }
754 } while (keep_running == NULL || *keep_running);
755 }
756 #endif
757
758 psim_clear_halt_and_restart(system);
759 }
760
761
762 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
763 thing */
764
765 INLINE_PSIM void
766 psim_step(psim *system)
767 {
768 volatile int keep_running = 0;
769 run_until_stop(system, &keep_running);
770 }
771
772 INLINE_PSIM void
773 psim_run(psim *system)
774 {
775 run_until_stop(system, NULL);
776 }
777
778 INLINE_PSIM void
779 psim_run_until_stop(psim *system,
780 volatile int *keep_running)
781 {
782 run_until_stop(system, keep_running);
783 }
784
785
786
787 /* storage manipulation functions */
788
789 INLINE_PSIM void
790 psim_read_register(psim *system,
791 int which_cpu,
792 void *buf,
793 const char reg[],
794 transfer_mode mode)
795 {
796 register_descriptions description;
797 char cooked_buf[sizeof(natural_word)];
798 cpu *processor;
799
800 /* find our processor */
801 if (which_cpu == MAX_NR_PROCESSORS)
802 which_cpu = system->last_cpu;
803 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
804 error("psim_read_register() - invalid processor %d\n", which_cpu);
805 processor = system->processors[which_cpu];
806
807 /* find the register description */
808 description = register_description(reg);
809 if (description.type == reg_invalid)
810 error("psim_read_register() invalid register name `%s'\n", reg);
811
812 /* get the cooked value */
813 switch (description.type) {
814
815 case reg_gpr:
816 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
817 break;
818
819 case reg_spr:
820 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
821 break;
822
823 case reg_sr:
824 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
825 break;
826
827 case reg_fpr:
828 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
829 break;
830
831 case reg_pc:
832 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
833 break;
834
835 case reg_cr:
836 *(creg*)cooked_buf = cpu_registers(processor)->cr;
837 break;
838
839 case reg_msr:
840 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
841 break;
842
843 default:
844 printf_filtered("psim_read_register(processor=0x%x,buf=0x%x,reg=%s) %s\n",
845 processor, buf, reg,
846 "read of this register unimplemented");
847 break;
848
849 }
850
851 /* the PSIM internal values are in host order. To fetch raw data,
852 they need to be converted into target order and then returned */
853 if (mode == raw_transfer) {
854 /* FIXME - assumes that all registers are simple integers */
855 switch (description.size) {
856 case 1:
857 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
858 break;
859 case 2:
860 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
861 break;
862 case 4:
863 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
864 break;
865 case 8:
866 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
867 break;
868 }
869 }
870 else {
871 bcopy(cooked_buf, buf, description.size);
872 }
873
874 }
875
876
877
878 INLINE_PSIM void
879 psim_write_register(psim *system,
880 int which_cpu,
881 const void *buf,
882 const char reg[],
883 transfer_mode mode)
884 {
885 cpu *processor;
886 register_descriptions description;
887 char cooked_buf[sizeof(natural_word)];
888
889 /* find our processor */
890 if (which_cpu == MAX_NR_PROCESSORS)
891 which_cpu = system->last_cpu;
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 else if (which_cpu < 0 || which_cpu >= system->nr_cpus) {
899 error("psim_read_register() - invalid processor %d\n", which_cpu);
900 }
901
902 processor = system->processors[which_cpu];
903
904 /* find the description of the register */
905 description = register_description(reg);
906 if (description.type == reg_invalid)
907 error("psim_write_register() invalid register name %s\n", reg);
908
909 /* If the data is comming in raw (target order), need to cook it
910 into host order before putting it into PSIM's internal structures */
911 if (mode == raw_transfer) {
912 switch (description.size) {
913 case 1:
914 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
915 break;
916 case 2:
917 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
918 break;
919 case 4:
920 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
921 break;
922 case 8:
923 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
924 break;
925 }
926 }
927 else {
928 bcopy(buf, cooked_buf, description.size);
929 }
930
931 /* put the cooked value into the register */
932 switch (description.type) {
933
934 case reg_gpr:
935 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
936 break;
937
938 case reg_fpr:
939 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
940 break;
941
942 case reg_pc:
943 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
944 break;
945
946 case reg_spr:
947 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
948 break;
949
950 case reg_sr:
951 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
952 break;
953
954 case reg_cr:
955 cpu_registers(processor)->cr = *(creg*)cooked_buf;
956 break;
957
958 case reg_msr:
959 cpu_registers(processor)->msr = *(msreg*)cooked_buf;
960 break;
961
962 default:
963 printf_filtered("psim_write_register(processor=0x%x,cooked_buf=0x%x,reg=%s) %s\n",
964 processor, cooked_buf, reg,
965 "read of this register unimplemented");
966 break;
967
968 }
969
970 }
971
972
973
974 INLINE_PSIM unsigned
975 psim_read_memory(psim *system,
976 int which_cpu,
977 void *buffer,
978 unsigned_word vaddr,
979 unsigned nr_bytes)
980 {
981 cpu *processor;
982 if (which_cpu == MAX_NR_PROCESSORS)
983 which_cpu = system->last_cpu;
984 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
985 error("psim_read_memory() invalid cpu\n");
986 processor = system->processors[which_cpu];
987 return vm_data_map_read_buffer(cpu_data_map(processor),
988 buffer, vaddr, nr_bytes);
989 }
990
991
992 INLINE_PSIM unsigned
993 psim_write_memory(psim *system,
994 int which_cpu,
995 const void *buffer,
996 unsigned_word vaddr,
997 unsigned nr_bytes,
998 int violate_read_only_section)
999 {
1000 cpu *processor;
1001 if (which_cpu == MAX_NR_PROCESSORS)
1002 which_cpu = system->last_cpu;
1003 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
1004 error("psim_read_memory() invalid cpu\n");
1005 processor = system->processors[which_cpu];
1006 return vm_data_map_write_buffer(cpu_data_map(processor),
1007 buffer, vaddr, nr_bytes, 1);
1008 }
1009
1010
1011 INLINE_PSIM void
1012 psim_print_info(psim *system,
1013 int verbose)
1014 {
1015 mon_print_info(system->monitor, verbose);
1016 }
1017
1018
1019 #endif /* _PSIM_C_ */
This page took 0.095582 seconds and 5 git commands to generate.