diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize index 625fd3695d4..e99ca8a0fb5 100644 --- a/sim/ppc/.Sanitize +++ b/sim/ppc/.Sanitize @@ -31,6 +31,7 @@ README.psim basics.h bits.c bits.h +config.in configure configure.in core.c diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index 6ba9a81f620..fdc580e152b 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,3 +1,27 @@ + * configure.in: Call AC_CONFIG_HEADER. Don't try to use + bfd/hosts/*.h file or bfd/config/*.mh file. Call AC_PROG_CC and + AC_PROG_RANLIB. Substitute in values for CFLAGS, HDEFINES, AR, + and CC_FOR_BUILD. Call AC_CHECK_HEADERS for various header files. + Touch stamp.h if creating config.h. + * configure: Rebuild. + * config.in: New file, created by autoheader. + * Makefile.in (AR): Define as @AR@. + (CC): New variable, defined as @CC@. + (CFLAGS): Define as @CFLAGS@. + (CC_FOR_BUILD): New variable, defined as @CC_FOR_BUILD@. + (RANLIB): Define as @RANLIB@. + (HDEFINES, TDEFINES): New variables. + (@host_makefile_frag@): Remove. + (mostlyclean): Make the same as clean, not distclean. + (clean): Remove config.log. + (distclean): Remove config.h and stamp-h. + (Makefile): Don't depend upon @frags@. Just rebuild Makefile when + invoking config.status. + (config.h, stamp-h): New targets. + (gen, gen.o): Build with CC_FOR_BUILD, not CC. + (ppc-config.h): Rename from old config.h build. + * (basics.h,gen.c,ppc-endian.c,psim.c): Include ppc-config.h. + Fri Sep 8 09:51:03 1995 Michael Meissner * configure{,.in}: Don't include sysdep.h from bfd, since bfd no diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in index c4b1b5fe349..2756751cc0b 100644 --- a/sim/ppc/Makefile.in +++ b/sim/ppc/Makefile.in @@ -49,19 +49,23 @@ docdir = $(datadir)/doc SHELL = /bin/sh -# FIXME: use autoconf's AC_PROG_INSTALL INSTALL = $(srcroot)/install.sh -c INSTALL_PROGRAM = $(INSTALL) INSTALL_DATA = $(INSTALL) INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1 -AR = ar +AR = @AR@ AR_FLAGS = rc -CFLAGS = -g +CC = @CC@ +CFLAGS = @CFLAGS@ +CC_FOR_BUILD = @CC_FOR_BUILD@ BISON = bison MAKEINFO = makeinfo -RANLIB = ranlib +RANLIB = @RANLIB@ + +HDEFINES = @HDEFINES@ +TDEFINES = .NOEXPORT: MAKEOVERRIDES= @@ -76,10 +80,6 @@ CONFIG_FILE = std-config.h LIBIBERTY_LIB = ../../libiberty/libiberty.a BFD_LIB = ../../bfd/libbfd.a -#### Makefile fragments come in here. -# @host_makefile_frag@ -### - TARGETLIB = libsim.a all: run libsim.a $(GDB_OBJ) @@ -91,6 +91,7 @@ all: run libsim.a $(GDB_OBJ) BASICS_H = \ config.h \ + ppc-config.h \ words.h \ ppc-endian.h \ debug.h \ @@ -136,7 +137,8 @@ BUILT_SRC = \ idecode.h idecode.c \ semantics.h semantics.c \ spreg.h spreg.c \ - config.h + config.h \ + ppc-config.h LIB_SRC = \ psim.c \ @@ -201,7 +203,7 @@ bits.o: bits.c bits.h debug.o: debug.c $(BASICS_H) ppc-endian.o: ppc-endian.c ppc-endian.h \ - config.h words.h sim_callbacks.h + config.h ppc-config.h words.h sim_callbacks.h system.o: system.c system.h $(CPU_H) $(IDECODE_H) @@ -243,8 +245,8 @@ semantics.o: semantics.c semantics.h $(CPU_H) $(IDECODE_H) # Rules to create the built c source code files # -config.h: $(CONFIG_FILE) - cp $(srcdir)/$(CONFIG_FILE) config.h +ppc-config.h: $(CONFIG_FILE) + cp $(srcdir)/$(CONFIG_FILE) ppc-config.h tmp-gencode: gen ppc-instructions ppc-spr-table $(srcdir)/../../move-if-change @@ -268,26 +270,31 @@ tmp-gencode: gen ppc-instructions ppc-spr-table $(srcdir)/../../move-if-change icache.h idecode.h idecode.c semantics.h semantics.c spreg.h spreg.c: tmp-gencode -gen.o: gen.c config.h +gen.o: gen.c config.h ppc-config.h + $(CC_FOR_BUILD) -c $(CFLAGS) $(HDEFINES) $(CSEARCH) $(CSWITCHES) $(srcdir)/gen.c -gen: gen.o config.h $(LIBIBERTY_LIB) $(LIBS) - $(CC) $(CFLAGS) $(LDFLAGS) -o gen gen.o $(LIBIBERTY_LIB) $(LIBS) +gen: gen.o config.h ppc-config.h $(LIBIBERTY_LIB) $(LIBS) + $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o gen gen.o $(LIBIBERTY_LIB) $(LIBS) # tags etags: TAGS -TAGS: tmp-gencode config.h +TAGS: tmp-gencode config.h ppc-config.h etags $(srcdir)/*.h $(srcdir)/*.c $(BUILT_SRC) -clean: - rm -f tmp-* *.[oas] core psim run gen +clean mostlyclean: + rm -f tmp-* *.[oas] core psim run gen config.log -distclean mostlyclean realclean: clean - rm -f TAGS $(BUILT_SRC) Makefile config.cache config.log config.status +distclean realclean: clean + rm -f TAGS $(BUILT_SRC) Makefile config.cache config.status config.h stamp-h -Makefile: Makefile.in config.status @frags@ - $(SHELL) ./config.status +Makefile: Makefile.in config.status + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status config.status: configure $(SHELL) ./config.status --recheck diff --git a/sim/ppc/configure.in b/sim/ppc/configure.in index 19c46485bca..b964ece066a 100644 --- a/sim/ppc/configure.in +++ b/sim/ppc/configure.in @@ -2,23 +2,31 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.3)dnl AC_INIT(Makefile.in) +AC_CONFIG_HEADER(config.h:config.in) + AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..) AC_CANONICAL_SYSTEM AC_ARG_PROGRAM . ${srcdir}/../../bfd/configure.host -if test -f ${srcdir}/../../bfd/config/${my_host}.mh; then - host_makefile_frag=../../bfd/config/${my_host}.mh +AC_PROG_CC +AC_SUBST(CFLAGS) +AC_SUBST(HDEFINES) +AR=${AR-ar} +AC_SUBST(AR) +AC_PROG_RANLIB + +# Put a plausible default for CC_FOR_BUILD in Makefile. +AC_C_CROSS +if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' else - host_makefile_frag=/dev/null + CC_FOR_BUILD=gcc fi +AC_SUBST(CC_FOR_BUILD) -frags= -if test $host_makefile_frag != /dev/null; then - frags="$frags $host_makefile_frag" -fi -AC_SUBST_FILE(host_makefile_frag) -AC_SUBST(frags) +AC_CHECK_HEADERS(string.h strings.h stdlib.h time.h sys/times.h) -AC_OUTPUT(Makefile) +AC_OUTPUT(Makefile, +[case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac]) diff --git a/sim/ppc/gen.c b/sim/ppc/gen.c index e6e5c161e10..9341cd81486 100644 --- a/sim/ppc/gen.c +++ b/sim/ppc/gen.c @@ -42,6 +42,7 @@ #include #include "config.h" +#include "ppc-config.h" #undef WITH_ASSERT #define WITH_ASSERT 1 diff --git a/sim/ppc/ppc-endian.c b/sim/ppc/ppc-endian.c index 0158116eb41..734ea213e52 100644 --- a/sim/ppc/ppc-endian.c +++ b/sim/ppc/ppc-endian.c @@ -28,6 +28,7 @@ #include "config.h" +#include "ppc-config.h" #include "words.h" #include "ppc-endian.h" #include "sim_callbacks.h" diff --git a/sim/ppc/psim.c b/sim/ppc/psim.c new file mode 100644 index 00000000000..45fb821bcaf --- /dev/null +++ b/sim/ppc/psim.c @@ -0,0 +1,904 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _PSIM_C_ +#define _PSIM_C_ + +#include "config.h" +#include "ppc-config.h" +#include "inline.h" + +#ifndef STATIC_INLINE_PSIM +#define STATIC_INLINE_PSIM STATIC_INLINE +#endif + +#include +#include + +#include "cpu.h" /* includes psim.h */ +#include "idecode.h" + +#include "inline.c" + + +/* system structure, actual size of processor array determined at + runtime */ + +struct _psim { + event_queue *events; + device_node *devices; + core *memory; + /* escape routine for inner functions */ + void *path_to_halt; + void *path_to_restart; + /* status from last halt */ + psim_status halt_status; + /* the processes proper */ + int nr_cpus; + int last_cpu; /* CPU that last (tried to) execute an instruction */ + cpu *processors[0]; +}; + + +int current_target_byte_order; +int current_host_byte_order; +int current_environment; +int current_alignment; + +INLINE_PSIM psim * +psim_create(const char *file_name, + int nr_processors) +{ + int cpu_nr; + psim *system; + + /* sanity check */ + if (nr_processors <= 0 + || (!WITH_SMP && nr_processors != 1)) + error("psim_create() invalid number of cpus\n"); + + /* create things */ + system = (psim*)zalloc(sizeof(psim) + + sizeof(cpu*) * (nr_processors + 1)); + system->nr_cpus = nr_processors; + system->events = event_queue_create(); + system->devices = device_tree_create(file_name); + system->memory = core_create(system->devices, 0); + for (cpu_nr = 0; cpu_nr < nr_processors; cpu_nr++) { + system->processors[cpu_nr] = cpu_create(system, + system->memory, + system->events, + cpu_nr); + } + + /* fill in the missing endian information */ + current_target_byte_order + = (device_tree_find_boolean(system->devices, "/options/little-endian?") + ? LITTLE_ENDIAN + : BIG_ENDIAN); + if (WITH_TARGET_BYTE_ORDER + && WITH_TARGET_BYTE_ORDER != current_target_byte_order) + error("target byte order conflict\n"); + + current_host_byte_order = 1; + current_host_byte_order = (*(char*)(¤t_host_byte_order) + ? LITTLE_ENDIAN + : BIG_ENDIAN); + if (WITH_HOST_BYTE_ORDER + && WITH_HOST_BYTE_ORDER != current_host_byte_order) + error("host byte order conflict\n"); + + /* fill in the missing OEA/VEA information */ + current_environment = (device_tree_find_boolean(system->devices, + "/options/vea?") + ? VIRTUAL_ENVIRONMENT + : OPERATING_ENVIRONMENT); + + /* fill in the missing ALLIGNMENT information */ + current_alignment = (device_tree_find_boolean(system->devices, + "/options/aligned?") + ? STRICT_ALIGNMENT + : NONSTRICT_ALIGNMENT); + if (WITH_ALIGNMENT + && CURRENT_ALIGNMENT != WITH_ALIGNMENT) + error("target alignment support conflict\n"); + + return system; +} + + +/* allow the simulation to stop/restart abnormaly */ + +STATIC_INLINE_PSIM void +psim_set_halt_and_restart(psim *system, + void *halt_jmp_buf, + void *restart_jmp_buf) +{ + system->path_to_halt = halt_jmp_buf; + system->path_to_restart = restart_jmp_buf; +} + +STATIC_INLINE_PSIM void +psim_clear_halt_and_restart(psim *system) +{ + system->path_to_halt = NULL; + system->path_to_restart = NULL; +} + +INLINE_PSIM void +psim_restart(psim *system, + int current_cpu) +{ + system->last_cpu = current_cpu; + longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1); +} + + +INLINE_PSIM void +psim_halt(psim *system, + int current_cpu, + unsigned_word cia, + stop_reason reason, + int signal) +{ + system->last_cpu = current_cpu; + system->halt_status.cpu_nr = current_cpu; + system->halt_status.reason = reason; + system->halt_status.signal = signal; + system->halt_status.program_counter = cia; + longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1); +} + +INLINE_PSIM psim_status +psim_get_status(psim *system) +{ + return system->halt_status; +} + + +cpu * +psim_cpu(psim *system, + int cpu_nr) +{ + if (cpu_nr < 0 || cpu_nr >= system->nr_cpus) + return NULL; + else + return system->processors[cpu_nr]; +} + + + +STATIC_INLINE_PSIM int +sizeof_argument_strings(char **arg) +{ + int sizeof_strings = 0; + + /* robust */ + if (arg == NULL) + return 0; + + /* add up all the string sizes (padding as we go) */ + for (; *arg != NULL; arg++) { + int len = strlen(*arg) + 1; + sizeof_strings += ALIGN_8(len); + } + + return sizeof_strings; +} + +STATIC_INLINE_PSIM int +number_of_arguments(char **arg) +{ + int nr; + if (arg == NULL) + return 0; + for (nr = 0; *arg != NULL; arg++, nr++); + return nr; +} + +STATIC_INLINE_PSIM int +sizeof_arguments(char **arg) +{ + return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word)); +} + +STATIC_INLINE_PSIM void +write_stack_arguments(psim *system, + char **arg, + unsigned_word start_block, + unsigned_word start_arg) +{ + TRACE(trace_create_stack, + ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n", + "system", system, "arg", arg, + "start_block", start_block, "start_arg", start_arg)); + if (arg == NULL) + error("write_arguments: character array NULL\n"); + /* only copy in arguments, memory is already zero */ + for (; *arg != NULL; arg++) { + int len = strlen(*arg)+1; + TRACE(trace_create_stack, + ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n", + "**arg", *arg, "start_block", start_block, + "len", len, "start_arg", start_arg)); + if (psim_write_memory(system, 0, *arg, + start_block, len, + raw_transfer, 0) != len) + error("write_arguments() - write of **arg (%s) at 0x%x failed\n", + *arg, start_block); + if (psim_write_memory(system, 0, &start_block, + start_arg, sizeof(start_block), + cooked_transfer, 0) != sizeof(start_block)) + error("write_arguments() - write of *arg failed\n"); + start_block += ALIGN_8(len); + start_arg += sizeof(start_block); + } +} + +STATIC_INLINE_PSIM void +create_elf_stack_frame(psim *system, + unsigned_word bottom_of_stack, + char **argv, + char **envp) +{ + /* fixme - this is over aligned */ + + /* information block */ + const unsigned sizeof_envp_block = sizeof_argument_strings(envp); + const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block; + const unsigned sizeof_argv_block = sizeof_argument_strings(argv); + const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block; + + /* auxiliary vector - contains only one entry */ + const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */ + const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry); + + /* environment points (including null sentinal) */ + const unsigned sizeof_envp = sizeof_arguments(envp); + const unsigned_word start_envp = start_aux - sizeof_envp; + + /* argument pointers (including null sentinal) */ + const int argc = number_of_arguments(argv); + const unsigned sizeof_argv = sizeof_arguments(argv); + const unsigned_word start_argv = start_envp - sizeof_argv; + + /* link register save address - alligned to a 16byte boundary */ + const unsigned_word top_of_stack = ((start_argv + - 2 * sizeof(unsigned_word)) + & ~0xf); + + /* force some stack space */ + if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT + && core_stack_lower_bound(system->memory) > top_of_stack) { + unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory) + - FLOOR_PAGE(top_of_stack)); + TRACE(trace_create_stack, + ("create_elf_stack_frame() - growing stack by 0x%x\n", + extra_stack_space)); + core_add_stack(system->memory, extra_stack_space); + } + + /* install arguments on stack */ + write_stack_arguments(system, envp, start_envp_block, start_envp); + write_stack_arguments(system, argv, start_argv_block, start_argv); + + /* set up the registers */ + psim_write_register(system, -1, + &top_of_stack, "r1", cooked_transfer); + psim_write_register(system, -1, + &argc, "r3", cooked_transfer); + psim_write_register(system, -1, + &start_argv, "r4", cooked_transfer); + psim_write_register(system, -1, + &start_envp, "r5", cooked_transfer); + psim_write_register(system, -1, + &start_aux, "r6", cooked_transfer); +} + +STATIC_INLINE_PSIM void +create_aix_stack_frame(psim *system, + unsigned_word bottom_of_stack, + char **argv, + char **envp) +{ + unsigned_word core_envp; + unsigned_word core_argv; + unsigned_word core_argc; + unsigned_word core_aux; + unsigned_word top_of_stack; + + /* cheat - create an elf stack frame */ + create_elf_stack_frame(system, bottom_of_stack, argv, envp); + + /* extract argument addresses from registers */ + psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer); + psim_read_register(system, 0, &core_argc, "r3", cooked_transfer); + psim_read_register(system, 0, &core_argv, "r4", cooked_transfer); + psim_read_register(system, 0, &core_envp, "r5", cooked_transfer); + psim_read_register(system, 0, &core_aux, "r6", cooked_transfer); + + /* check stack fits at least this much */ + if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT + && core_stack_lower_bound(system->memory) > top_of_stack) { + unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory) + - FLOOR_PAGE(top_of_stack)); + TRACE(trace_create_stack, + ("create_aix_stack_frame() - growing stack by 0x%x\n", + extra_stack_space)); + core_add_stack(system->memory, extra_stack_space); + } + + /* extract arguments from registers */ + error("create_aix_stack_frame() - what happens next?\n"); +} + + +INLINE_PSIM void +psim_load(psim *system) +{ + unsigned_word program_counter; + msreg msr; + + /* load in core data */ + core_init(system->memory); + + /* set up all processor entry points (to same thing). Maybe + someday, the device tree could include information specifying the + entry point for each processor, one day */ + TRACE(trace_tbd, + ("TBD - device tree specifying entry point of each processor\n")); + program_counter = device_tree_find_int(system->devices, + "/options/program-counter"); + psim_write_register(system, -1, + &program_counter, + "pc", cooked_transfer); + system->last_cpu = system->nr_cpus - 1; /* force loop to restart */ + + /* set up the MSR for at least be/le mode */ + msr = (device_tree_find_boolean(system->devices, + "/options/little-endian?") + ? msr_little_endian_mode + : 0); + psim_write_register(system, -1, + &msr, + "msr", cooked_transfer); +} + +INLINE_PSIM void +psim_stack(psim *system, + char **argv, + char **envp) +{ + unsigned_word stack_pointer = device_tree_find_int(system->devices, + "/options/stack-pointer"); + if (device_tree_find_boolean(system->devices, + "/options/elf?")) + create_elf_stack_frame(system, stack_pointer, argv, envp); + else + create_aix_stack_frame(system, stack_pointer, argv, envp); +} + + + +/* EXECUTE REAL CODE: + + Unfortunatly, there are multiple cases to consider vis: + + X X X X ... + + Consequently this function is written in multiple different ways */ + +STATIC_INLINE_PSIM void +run_until_stop(psim *system, + volatile int *keep_running) +{ + +#if (WITH_IDECODE_CACHE == 0 && WITH_SMP == 0) + + /* CASE 1: No instruction cache and no SMP. + + In this case, we can take advantage of the fact that the current + instruction address does not need to be returned to the cpu + object after every execution of an instruction. Instead it only + needs to be saved when either A. the main loop exits or B. a + cpu-{halt,restart} call forces the loop to be re-entered. The + later functions always save the current cpu instruction + address. */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + if (!setjmp(halt)) { + do { + if (!setjmp(restart)) { + cpu *const processor = system->processors[0]; + unsigned_word cia = cpu_get_program_counter(processor); + do { + if (WITH_EVENTS) { + if (event_queue_tick(system->events)) { + cpu_set_program_counter(processor, cia); + event_queue_process(system->events); + cia = cpu_get_program_counter(processor); + } + } + { + instruction_word const instruction + = vm_instruction_map_read(cpu_instruction_map(processor), + processor, cia); + cia = idecode_issue(processor, instruction, cia); + } + } while (keep_running == NULL || *keep_running); + cpu_set_program_counter(processor, cia); + } + } while(keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif + + +#if (WITH_IDECODE_CACHE > 0 && WITH_SMP == 0) + + /* CASE 2: Instruction case but no SMP + + Here, the additional complexity comes from there being two + different cache implementations. A simple function address cache + or a full cracked instruction cache */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + if (!setjmp(halt)) { + do { + if (!setjmp(restart)) { + cpu *const processor = system->processors[0]; + unsigned_word cia = cpu_get_program_counter(processor); + do { + if (WITH_EVENTS) + if (event_queue_tick(system->events)) { + cpu_set_program_counter(processor, cia); + event_queue_process(system->events); + cia = cpu_get_program_counter(processor); + } + { + idecode_cache *const cache_entry + = cpu_icache(processor) + (cia / 4 % IDECODE_CACHE_SIZE); + if (cache_entry->address == cia) { + idecode_semantic *const semantic = cache_entry->semantic; +#if WITH_IDECODE_CACHE == 1 + cia = semantic(processor, cache_entry->instruction, cia); +#else + cia = semantic(processor, cache_entry, cia); +#endif + } + else { + instruction_word const instruction + = vm_instruction_map_read(cpu_instruction_map(processor), + processor, + cia); +#if WITH_IDECODE_CACHE == 1 + idecode_semantic *const semantic = idecode(processor, + instruction, + cia); +#else + idecode_semantic *const semantic = idecode(processor, + instruction, + cia, + cache_entry); +#endif + cache_entry->address = cia; + cache_entry->semantic = semantic; +#if WITH_IDECODE_CACHE == 1 + cache_entry->instruction = instruction; + cia = semantic(processor, instruction, cia); +#else + cia = semantic(processor, cache_entry, cia); +#endif + } + } + } while (keep_running == NULL || *keep_running); + cpu_set_program_counter(processor, cia); + } + } while(keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif + + +#if (WITH_IDECODE_CACHE == 0 && WITH_SMP > 0) + + /* CASE 3: No ICACHE but SMP + + The complexity here comes from needing to correctly restart the + system when it is aborted. In particular if cpu0 requests a + restart, the next cpu is still cpu1. Cpu0 being restarted after + all the other CPU's and the event queue have been processed */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + + if (!setjmp(halt)) { + int first_cpu = setjmp(restart); + if (first_cpu == 0) + first_cpu = system->last_cpu + 1; + do { + int current_cpu; + for (current_cpu = first_cpu, first_cpu = 0; + current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0); + current_cpu++) { + if (WITH_EVENTS && current_cpu == system->nr_cpus) { + if (event_queue_tick(system->events)) + event_queue_process(system->events); + } + else { + cpu *const processor = system->processors[current_cpu]; + unsigned_word const cia = cpu_get_program_counter(processor); + instruction_word instruction = + vm_instruction_map_read(cpu_instruction_map(processor), + processor, + cia); + cpu_set_program_counter(processor, + idecode_issue(processor, instruction, cia)); + } + if (!(keep_running == NULL || *keep_running)) { + system->last_cpu = current_cpu; + break; + } + } + } while (keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif + +#if (WITH_IDECODE_CACHE > 0 && WITH_SMP > 0) + + /* CASE 4: ICACHE and SMP ... + + This time, everything goes wrong. Need to restart loops + correctly, need to save the program counter and finally need to + keep track of each processors current address! */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + + if (!setjmp(halt)) { + int first_cpu = setjmp(restart); + if (!first_cpu) + first_cpu = system->last_cpu + 1; + do { + int current_cpu; + for (current_cpu = first_cpu, first_cpu = 0; + current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0); + current_cpu++) { + if (WITH_EVENTS && current_cpu == system->nr_cpus) { + if (event_queue_tick(system->events)) + event_queue_process(system->events); + } + else { + cpu *processor = system->processors[current_cpu]; + unsigned_word const cia = cpu_get_program_counter(processor); + idecode_cache *cache_entry + = (cpu_icache(processor) + (cia / 4 % IDECODE_CACHE_SIZE)); + if (cache_entry->address == cia) { + idecode_semantic *semantic = cache_entry->semantic; +#if WITH_IDECODE_CACHE == 1 + cpu_set_program_counter(processor, + semantic(processor, + cache_entry->instruction, + cia); +#else + cpu_set_program_counter(processor, + semantic(processor, + cache_entry, + cia); +#endif + } + else { + instruction_word instruction = + vm_instruction_map_read(cpu_instruction_map(processor), + processor, + cia); +#if WITH_IDECODE_CACHE == 1 + idecode_semantic *semantic = idecode(processor, + instruction, + cia); +#else + idecode_semantic *semantic = idecode(processor, + instruction, + cia, + cache_entry); +#endif + cache_entry->address = cia; + cache_entry->semantic = semantic; +#if WITH_IDECODE_CACHE == 1 + cache_entry->instruction = instruction; + cpu_set_program_counter(processor, + semantic(processor, instruction, cia)); +#else + cpu_set_program_counter(processor, + semantic(processor, cache_entry, cia); +#endif + } + } + if (!(keep_running == NULL || *keep_running)) + break; + } + } while (keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif +} + + +/* SIMULATE INSTRUCTIONS, various different ways of achieving the same + thing */ + +INLINE_PSIM void +psim_step(psim *system) +{ + volatile int keep_running = 0; + psim_run_until_stop(system, &keep_running); +} + +INLINE_PSIM void +psim_run(psim *system) +{ + run_until_stop(system, NULL); +} + +INLINE_PSIM void +psim_run_until_stop(psim *system, + volatile int *keep_running) +{ + run_until_stop(system, keep_running); +} + + + +/* storage manipulation functions */ + +INLINE_PSIM void +psim_read_register(psim *system, + int which_cpu, + void *buf, + const char reg[], + transfer_mode mode) +{ + register_descriptions description; + char cooked_buf[sizeof(natural_word)]; + cpu *processor; + + /* find our processor */ + if (which_cpu < 0 || which_cpu > system->nr_cpus) + error("psim_read_register() - invalid processor %d\n", which_cpu); + if (which_cpu == system->nr_cpus) + which_cpu = system->last_cpu; + processor = system->processors[which_cpu]; + + /* find the register description */ + description = register_description(reg); + if (description.type == reg_invalid) + error("psim_read_register() invalid register name `%s'\n", reg); + + /* get the cooked value */ + switch (description.type) { + + case reg_gpr: + *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index]; + break; + + case reg_spr: + *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index]; + break; + + case reg_sr: + *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index]; + break; + + case reg_fpr: + *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index]; + break; + + case reg_pc: + *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor); + break; + + case reg_cr: + *(creg*)cooked_buf = cpu_registers(processor)->cr; + break; + + case reg_msr: + *(msreg*)cooked_buf = cpu_registers(processor)->msr; + break; + + default: + printf_filtered("psim_read_register(processor=0x%x,buf=0x%x,reg=%s) %s\n", + processor, buf, reg, + "read of this register unimplemented"); + break; + + } + + /* the PSIM internal values are in host order. To fetch raw data, + they need to be converted into target order and then returned */ + if (mode == raw_transfer) { + /* FIXME - assumes that all registers are simple integers */ + switch (description.size) { + case 1: + *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf); + break; + case 2: + *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf); + break; + case 4: + *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf); + break; + case 8: + *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf); + break; + } + } + else { + bcopy(cooked_buf, buf, description.size); + } + +} + + + +INLINE_PSIM void +psim_write_register(psim *system, + int which_cpu, + const void *buf, + const char reg[], + transfer_mode mode) +{ + cpu *processor; + register_descriptions description; + char cooked_buf[sizeof(natural_word)]; + + /* find our processor */ + if (which_cpu == -1) { + int i; + for (i = 0; i < system->nr_cpus; i++) + psim_write_register(system, i, buf, reg, mode); + return; + } + else if (which_cpu == system->nr_cpus) { + which_cpu = system->last_cpu; + } + else if (which_cpu < 0 || which_cpu >= system->nr_cpus) { + error("psim_read_register() - invalid processor %d\n", which_cpu); + } + + processor = system->processors[which_cpu]; + + /* find the description of the register */ + description = register_description(reg); + if (description.type == reg_invalid) + error("psim_write_register() invalid register name %s\n", reg); + + /* If the data is comming in raw (target order), need to cook it + into host order before putting it into PSIM's internal structures */ + if (mode == raw_transfer) { + switch (description.size) { + case 1: + *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf); + break; + case 2: + *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf); + break; + case 4: + *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf); + break; + case 8: + *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf); + break; + } + } + else { + bcopy(buf, cooked_buf, description.size); + } + + /* put the cooked value into the register */ + switch (description.type) { + + case reg_gpr: + cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf; + break; + + case reg_fpr: + cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf; + break; + + case reg_pc: + cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf); + break; + + case reg_spr: + cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf; + break; + + case reg_sr: + cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf; + break; + + case reg_cr: + cpu_registers(processor)->cr = *(creg*)cooked_buf; + break; + + case reg_msr: + cpu_registers(processor)->msr = *(msreg*)cooked_buf; + break; + + default: + printf_filtered("psim_write_register(processor=0x%x,cooked_buf=0x%x,reg=%s) %s\n", + processor, cooked_buf, reg, + "read of this register unimplemented"); + break; + + } + +} + + + +INLINE_PSIM unsigned +psim_read_memory(psim *system, + int which_cpu, + void *buffer, + unsigned_word vaddr, + unsigned len, + transfer_mode mode) +{ + cpu *processor; + if (which_cpu < 0 || which_cpu > system->nr_cpus) + error("psim_read_memory() invalid cpu\n"); + if (which_cpu == system->nr_cpus) + which_cpu = system->last_cpu; + processor = system->processors[which_cpu]; + return vm_data_map_read_buffer(cpu_data_map(processor), + buffer, vaddr, len, mode); +} + + +INLINE_PSIM unsigned +psim_write_memory(psim *system, + int which_cpu, + const void *buffer, + unsigned_word vaddr, + unsigned len, + transfer_mode mode, + int violate_read_only_section) +{ + cpu *processor; + if (which_cpu < 0 || which_cpu > system->nr_cpus) + error("psim_read_memory() invalid cpu\n"); + if (which_cpu == system->nr_cpus) + which_cpu = system->last_cpu; + processor = system->processors[which_cpu]; + return vm_data_map_write_buffer(cpu_data_map(processor), + buffer, vaddr, len, mode, 1); +} + + +#endif /* _PSIM_C_ */