mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-24 10:35:12 +08:00
Update to new config scheme
This commit is contained in:
parent
ed753c2049
commit
8b3797aa18
@ -31,6 +31,7 @@ README.psim
|
||||
basics.h
|
||||
bits.c
|
||||
bits.h
|
||||
config.in
|
||||
configure
|
||||
configure.in
|
||||
core.c
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ppc-config.h"
|
||||
|
||||
#undef WITH_ASSERT
|
||||
#define WITH_ASSERT 1
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "ppc-config.h"
|
||||
#include "words.h"
|
||||
#include "ppc-endian.h"
|
||||
#include "sim_callbacks.h"
|
||||
|
904
sim/ppc/psim.c
Normal file
904
sim/ppc/psim.c
Normal file
@ -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*)(¤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:
|
||||
|
||||
<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_ */
|
Loading…
Reference in New Issue
Block a user