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