aboutsummaryrefslogtreecommitdiff
path: root/sim/ppc
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1995-09-08 23:56:38 +0000
committerMichael Meissner <gnu@the-meissners.org>1995-09-08 23:56:38 +0000
commit8b3797aa18a91157c0aaa1012cf31e3d5ea025b7 (patch)
treedc9d33523b84fa048955970fc057252f4ec4fa5f /sim/ppc
parented753c20492aad05a0bd210970412c6e333dd09c (diff)
downloadgdb-8b3797aa18a91157c0aaa1012cf31e3d5ea025b7.zip
gdb-8b3797aa18a91157c0aaa1012cf31e3d5ea025b7.tar.gz
gdb-8b3797aa18a91157c0aaa1012cf31e3d5ea025b7.tar.bz2
Update to new config scheme
Diffstat (limited to 'sim/ppc')
-rw-r--r--sim/ppc/.Sanitize1
-rw-r--r--sim/ppc/ChangeLog24
-rw-r--r--sim/ppc/Makefile.in51
-rw-r--r--sim/ppc/configure.in28
-rw-r--r--sim/ppc/gen.c1
-rw-r--r--sim/ppc/ppc-endian.c1
-rw-r--r--sim/ppc/psim.c904
7 files changed, 978 insertions, 32 deletions
diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize
index 625fd36..e99ca8a 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 6ba9a81..fdc580e 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 <meissner@tiktok.cygnus.com>
* 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 c4b1b5f..2756751 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 realclean: clean
+ rm -f TAGS $(BUILT_SRC) Makefile config.cache config.status config.h stamp-h
-distclean mostlyclean realclean: clean
- rm -f TAGS $(BUILT_SRC) Makefile config.cache config.log config.status
+Makefile: Makefile.in config.status
+ CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status
-Makefile: Makefile.in config.status @frags@
- $(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 19c4648..b964ece 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 e6e5c16..9341cd8 100644
--- a/sim/ppc/gen.c
+++ b/sim/ppc/gen.c
@@ -42,6 +42,7 @@
#include <string.h>
#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 0158116..734ea21 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 0000000..45fb821
--- /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 <cagney@highland.com.au>
+
+ 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 <string.h>
+#include <setjmp.h>
+
+#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*)(&current_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:
+
+ <icache> X <smp> X <events> X <keep-running-flag> 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_ */