mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-21 02:24:17 +08:00
Update to new config scheme
This commit is contained in:
@ -31,6 +31,7 @@ README.psim
|
|||||||
basics.h
|
basics.h
|
||||||
bits.c
|
bits.c
|
||||||
bits.h
|
bits.h
|
||||||
|
config.in
|
||||||
configure
|
configure
|
||||||
configure.in
|
configure.in
|
||||||
core.c
|
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>
|
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
|
* configure{,.in}: Don't include sysdep.h from bfd, since bfd no
|
||||||
|
@ -49,19 +49,23 @@ docdir = $(datadir)/doc
|
|||||||
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
# FIXME: use autoconf's AC_PROG_INSTALL
|
|
||||||
INSTALL = $(srcroot)/install.sh -c
|
INSTALL = $(srcroot)/install.sh -c
|
||||||
INSTALL_PROGRAM = $(INSTALL)
|
INSTALL_PROGRAM = $(INSTALL)
|
||||||
INSTALL_DATA = $(INSTALL)
|
INSTALL_DATA = $(INSTALL)
|
||||||
INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)'
|
INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)'
|
||||||
INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1
|
INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1
|
||||||
|
|
||||||
AR = ar
|
AR = @AR@
|
||||||
AR_FLAGS = rc
|
AR_FLAGS = rc
|
||||||
CFLAGS = -g
|
CC = @CC@
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
|
CC_FOR_BUILD = @CC_FOR_BUILD@
|
||||||
BISON = bison
|
BISON = bison
|
||||||
MAKEINFO = makeinfo
|
MAKEINFO = makeinfo
|
||||||
RANLIB = ranlib
|
RANLIB = @RANLIB@
|
||||||
|
|
||||||
|
HDEFINES = @HDEFINES@
|
||||||
|
TDEFINES =
|
||||||
|
|
||||||
.NOEXPORT:
|
.NOEXPORT:
|
||||||
MAKEOVERRIDES=
|
MAKEOVERRIDES=
|
||||||
@ -76,10 +80,6 @@ CONFIG_FILE = std-config.h
|
|||||||
LIBIBERTY_LIB = ../../libiberty/libiberty.a
|
LIBIBERTY_LIB = ../../libiberty/libiberty.a
|
||||||
BFD_LIB = ../../bfd/libbfd.a
|
BFD_LIB = ../../bfd/libbfd.a
|
||||||
|
|
||||||
#### Makefile fragments come in here.
|
|
||||||
# @host_makefile_frag@
|
|
||||||
###
|
|
||||||
|
|
||||||
TARGETLIB = libsim.a
|
TARGETLIB = libsim.a
|
||||||
|
|
||||||
all: run libsim.a $(GDB_OBJ)
|
all: run libsim.a $(GDB_OBJ)
|
||||||
@ -91,6 +91,7 @@ all: run libsim.a $(GDB_OBJ)
|
|||||||
|
|
||||||
BASICS_H = \
|
BASICS_H = \
|
||||||
config.h \
|
config.h \
|
||||||
|
ppc-config.h \
|
||||||
words.h \
|
words.h \
|
||||||
ppc-endian.h \
|
ppc-endian.h \
|
||||||
debug.h \
|
debug.h \
|
||||||
@ -136,7 +137,8 @@ BUILT_SRC = \
|
|||||||
idecode.h idecode.c \
|
idecode.h idecode.c \
|
||||||
semantics.h semantics.c \
|
semantics.h semantics.c \
|
||||||
spreg.h spreg.c \
|
spreg.h spreg.c \
|
||||||
config.h
|
config.h \
|
||||||
|
ppc-config.h
|
||||||
|
|
||||||
LIB_SRC = \
|
LIB_SRC = \
|
||||||
psim.c \
|
psim.c \
|
||||||
@ -201,7 +203,7 @@ bits.o: bits.c bits.h
|
|||||||
debug.o: debug.c $(BASICS_H)
|
debug.o: debug.c $(BASICS_H)
|
||||||
|
|
||||||
ppc-endian.o: ppc-endian.c ppc-endian.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)
|
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
|
# Rules to create the built c source code files
|
||||||
#
|
#
|
||||||
|
|
||||||
config.h: $(CONFIG_FILE)
|
ppc-config.h: $(CONFIG_FILE)
|
||||||
cp $(srcdir)/$(CONFIG_FILE) config.h
|
cp $(srcdir)/$(CONFIG_FILE) ppc-config.h
|
||||||
|
|
||||||
|
|
||||||
tmp-gencode: gen ppc-instructions ppc-spr-table $(srcdir)/../../move-if-change
|
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
|
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)
|
gen: gen.o config.h ppc-config.h $(LIBIBERTY_LIB) $(LIBS)
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o gen gen.o $(LIBIBERTY_LIB) $(LIBS)
|
$(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o gen gen.o $(LIBIBERTY_LIB) $(LIBS)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
||||||
tags etags: TAGS
|
tags etags: TAGS
|
||||||
|
|
||||||
TAGS: tmp-gencode config.h
|
TAGS: tmp-gencode config.h ppc-config.h
|
||||||
etags $(srcdir)/*.h $(srcdir)/*.c $(BUILT_SRC)
|
etags $(srcdir)/*.h $(srcdir)/*.c $(BUILT_SRC)
|
||||||
|
|
||||||
clean:
|
clean mostlyclean:
|
||||||
rm -f tmp-* *.[oas] core psim run gen
|
rm -f tmp-* *.[oas] core psim run gen config.log
|
||||||
|
|
||||||
distclean mostlyclean realclean: clean
|
distclean realclean: clean
|
||||||
rm -f TAGS $(BUILT_SRC) Makefile config.cache config.log config.status
|
rm -f TAGS $(BUILT_SRC) Makefile config.cache config.status config.h stamp-h
|
||||||
|
|
||||||
Makefile: Makefile.in config.status @frags@
|
Makefile: Makefile.in config.status
|
||||||
$(SHELL) ./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
|
config.status: configure
|
||||||
$(SHELL) ./config.status --recheck
|
$(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_PREREQ(2.3)dnl
|
||||||
AC_INIT(Makefile.in)
|
AC_INIT(Makefile.in)
|
||||||
|
|
||||||
|
AC_CONFIG_HEADER(config.h:config.in)
|
||||||
|
|
||||||
AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..)
|
AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..)
|
||||||
AC_CANONICAL_SYSTEM
|
AC_CANONICAL_SYSTEM
|
||||||
AC_ARG_PROGRAM
|
AC_ARG_PROGRAM
|
||||||
|
|
||||||
. ${srcdir}/../../bfd/configure.host
|
. ${srcdir}/../../bfd/configure.host
|
||||||
|
|
||||||
if test -f ${srcdir}/../../bfd/config/${my_host}.mh; then
|
AC_PROG_CC
|
||||||
host_makefile_frag=../../bfd/config/${my_host}.mh
|
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
|
else
|
||||||
host_makefile_frag=/dev/null
|
CC_FOR_BUILD=gcc
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST(CC_FOR_BUILD)
|
||||||
|
|
||||||
frags=
|
AC_CHECK_HEADERS(string.h strings.h stdlib.h time.h sys/times.h)
|
||||||
if test $host_makefile_frag != /dev/null; then
|
|
||||||
frags="$frags $host_makefile_frag"
|
|
||||||
fi
|
|
||||||
AC_SUBST_FILE(host_makefile_frag)
|
|
||||||
AC_SUBST(frags)
|
|
||||||
|
|
||||||
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 <string.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "ppc-config.h"
|
||||||
|
|
||||||
#undef WITH_ASSERT
|
#undef WITH_ASSERT
|
||||||
#define WITH_ASSERT 1
|
#define WITH_ASSERT 1
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "ppc-config.h"
|
||||||
#include "words.h"
|
#include "words.h"
|
||||||
#include "ppc-endian.h"
|
#include "ppc-endian.h"
|
||||||
#include "sim_callbacks.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_ */
|
Reference in New Issue
Block a user