Update to new config scheme

This commit is contained in:
Michael Meissner 1995-09-08 23:56:38 +00:00
parent ed753c2049
commit 8b3797aa18
7 changed files with 978 additions and 32 deletions

View File

@ -31,6 +31,7 @@ README.psim
basics.h
bits.c
bits.h
config.in
configure
configure.in
core.c

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -42,6 +42,7 @@
#include <string.h>
#include "config.h"
#include "ppc-config.h"
#undef WITH_ASSERT
#define WITH_ASSERT 1

View File

@ -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
View 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*)(&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_ */