Changes from Andrew

This commit is contained in:
Michael Meissner 1995-12-15 20:20:13 +00:00
parent ee68a042d2
commit 93fac32455
28 changed files with 5033 additions and 3889 deletions

View File

@ -31,23 +31,29 @@ README.psim
basics.h
bits.c
bits.h
cap.c
cap.h
config.in
configure
configure.in
corefile-n.h
corefile.c
corefile.h
core_n.h
cpu.c
cpu.h
debug.c
debug.h
device_tree.c
device_tree.h
devices.c
devices.h
device.c
device.h
device_table.c
device_table.h
dgen.c
double.c
dp-bit.c
emul_bugapi.c
emul_bugapi.h
emul_chirp.c
emul_chirp.h
emul_generic.c
emul_generic.h
emul_netbsd.c
@ -71,29 +77,28 @@ misc.c
misc.h
mon.c
mon.h
os_emul.c
os_emul.h
options.c
options.h
os_emul.c
os_emul.h
ppc-cache-rules
ppc-instructions
ppc-opcode-complex
ppc-opcode-simple
ppc-opcode-stupid
ppc-opcode-test-1
ppc-opcode-test-2
ppc-spr-table
ppc.mt
psim.c
psim.h
registers.c
registers.h
sim_callbacks.h
sim_calls.c
sim-endian-n.h
sim-endian.c
sim-endian.h
sim-endian-n.h
spa-reporter.c
spa-system-calls.c
spa-system-calls.h
sim_callbacks.h
sim_calls.c
std-config.h
table.c
table.h

View File

@ -1,3 +1,208 @@
Thu Dec 14 18:49:34 1995 Andrew Cagney <cagney@highland.com.au>
* lf.c (lf_print_function_type): New function. Munges a function
type so that the prefix (eg INLINE...) is inserted after the type
but before any `*'.
* igen.c: Change to output functions using this.
Wed Dec 13 23:47:00 1995 Andrew Cagney <cagney@highland.com.au>
FIXME: Emul CHIRP does not correctly implement the find device
function.
FIXME: Emul CHIRP and device do not implement device instance
operations.
Wed Dec 13 23:47:00 1995 Andrew Cagney <cagney@highland.com.au>
* options.c (options_inline): Function to output meaningful
description of the INLINE options.
* configure.in (inline): Replace inline magic numbers with macro
names. Map 1->LOCALS_INLINE and 2->ALL_INLINE.
* inline.h, inline.c: update to use inline method.
* std-config.h (CPU_INLINE), cpu.h, inline.h, inline.c: make cpu.h
inline always.
* std-config.h (EVENTS_INLINE): Inline events in psim.
Wed Dec 13 22:01:21 1995 Andrew Cagney <cagney@highland.com.au>
* device_table.c (htab_sum_binary): DMA binaries to correct byte
within a page.
Tue Dec 12 22:51:18 1995 Andrew Cagney <cagney@highland.com.au>
* psim.c (psim_merge_device_file): Change `=' to `==', was this an
error?
Tue Dec 5 11:56:14 1995 Andrew Cagney <cagney@highland.com.au>
* ppc-instructions (ppc_nr_mtcrf_crs, ppc_branch_conditional_name,
ppc_function_unit_name): Simplify by declaring these arrays as
pure and simple static (instead of STATIC_MODEL).
Tue Dec 5 00:45:34 1995 Andrew Cagney <cagney@highland.com.au>
* sim_calls.c (sim_create, sim_load), main.c (main), psim.c: Pass
an options device into psim_create() so that options can be merged
into the tree.
* device.c (*add*): Change semantics so the add functions only add
when the new device (or property) doesn't already exist. This
allows merging of options and data.
Mon Dec 4 17:12:13 1995 Andrew Cagney <cagney@highland.com.au>
* Makefile.in (BASICS_H): Didn't include basics.h in the list of
header files to depend on.
Mon Dec 4 17:12:13 1995 Andrew Cagney <cagney@highland.com.au>
* std-config.h: (*_MODULE): Extend the <module>_inline macro's so
that they also allow control over static functions. Rewrite
document to reflect this.
* std-config.h: (INLINE): Simplify definition, the above and
earlier changes to igen.h eliminate the need to be defensive about
enabling the inline of static functions.
* std-config.h: (SIM_ENDIAN_INLINE, BITS_INLINE): Document limited
suport for inlineing of modules for all callers. Adjust relevant
macro's so that DEFAULT_INLINE will enable this.
* basics.h: Re-order #includes and definitions so that c-code for
basic include files does not call functions delcared in later
#includes.
* basics.h (__attribute__), sim_callbacks.h: Move attribute macro
to basics.h and add hack (include <stdio.h>) to try and bring that
and other possible conflicting macros into scope much earler.
* sim-endian.h,c (SIM_ENDIAN_INLINE) bits.h,c (BITS_INLINE):
Change to use the updated inline definitions. If enabled
immediatly include the corresponding c-code so that it will inline
for all modules.
* inline.h, inline.c (SIM_ENDIAN_INLINE, BITS_INLINE): Remove
these cases, moved to module specific header files.
Sat Dec 2 18:37:51 1995 Andrew Cagney <cagney@highland.com.au>
* vm.c, vm_n.c: Fix htab code.
* vm.c (vm_data_map_read_buffer): Was using EA not RA when reading
the data from core.
* device.c: Fix htab create code.
Fri Nov 24 23:10:09 1995 Andrew Cagney <cagney@highland.com.au>
* bits.h, bits.c (EXTRACTED): Convert to function, fix - had &&
instead of &.
* sim-endian.h (SWAP_N), sim-endian-n.h, sim-endian.c: How
embarasing - fix yet another bug in the swap code! Simplify
everything by using more functions. Add host to big-endian byte
swapping support.
Fri Nov 24 23:10:09 1995 Andrew Cagney <cagney@highland.com.au>
* devices.h, devices.c: delete, replaced by the files
device_table.[ch] and device.[ch].
* device_tree.h, device_tree.c: ditto
* device_table.h, device_table.c: New files. Contain a table of
devices.
* device.h, device.c, Makefile.in, std-config.h (DEVICE_INLINE),
options.c (print_options): New files. Define the device object
along with any attached properties.
* device_tree.h, device_tree.c: Update to use new device object.
For convenience, change the printd functions into device_tree_add
functions.
* psim.c (create_*_tree): Use new device_tree create functions.
* corefile.h, corefile.c corefile-n.h (core_n.h): Update to use
the new device.h / device_table.h interface. Rename core_n.h to
corefile-n.h to be consistent with other n files.
* Makefile.in (run): add corefile-n.h to dependencies for
corefile.
* basics.h (device_instance), device.h, device.c, device_table.h,
device_table.c: Add the concept of a device instance and operators
on these instances - corresponds to ihandle in OpenBoot speak.
Don't yet implement it.
Tue Nov 14 12:27:08 1995 Andrew Cagney <cagney@highland.com.au>
* emul_generic.h, emul_generic.c (emul_syscall_enter,
emul_syscall_exit): rename from emul_enter_call /
emul_exit_call. As only used by emul_do_system_call simplify
associated code.
* os_emul.h, os_emul.c, emul_generic.h: Correct and fill an
os_emul interface.
* os_emul.c, emul_bugapi.h, emul_bugapi.c, Makefile.in: Add
preliminary hooks for a kernel mode rom emulation.
* cap.h (new), cap.c (new): Capability data base. Some emulations
pass object identifiers (capabilities?) to/from the simulated code
(for instance the phandle in OpenBoot). The cap object is able to
check/map between internal and external (target program)
representations of each identifier.
* os_emul.c, emul_chirp.h, emul_chirp.c, Makefile.in: Add
preliminary hooks for a kernel mode IEEE-1275 emulation.
* cpu.h, cpu.c (cpu_create, cpu_os_emulation, cpu): Add os_emul to
list of arguments passed in when creating a cpu. Grant access to
the element.
* std-config.h (OS_EMUL_INLINE), options.c (print_options),
inline.h, inline.c: New to allow control over inline of
corresponding code files.
* ppc-instructions (instruction_call): Add illegal instruction to
call the instruction-call emulation handler.
* interrupts.c (system_call_interrupt): Call renamed
os_emul_system_call function().
* emul_netbsd.c: Update to interface to generic emulation. Since
all its functions are called via a table don't worry about any
inline.
* emul_generic.h, emul_generic.c, spa-*(delete): Remove references
and code for spa, no longer to be used.
* psim.c (create_chirp_device_tree): Fill out what was previously
the openboot create function so that it starts to create a full
OpenBoot device tree.
Tue Nov 28 21:48:06 1995 Andrew Cagney <cagney@highland.com.au>
* debug.h, debug.c: pte trace is made redundant by htab trace,
delete it. Add vm to list of options. Simplify tracing output so
lines are not as long.
Tue Nov 14 12:27:08 1995 Andrew Cagney <cagney@highland.com.au>
* events.h, events.c (event_queue_init), psim.c (psim_init): (re)
initialize the event queue.
Tue Nov 28 13:38:26 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* sim-endian.h: Look at WORDS_BIGENDIAN to determine if the host
@ -1020,9 +1225,6 @@ Mon Oct 23 23:48:59 1995 Andrew Cagney <cagney@highland.com.au>
DEVICE_TREE_INLINE or INTERRUPTS_INLINE as none of these are on
the instruction or data critical paths.
* FIXME: need to set up OS_EMUL_INLINE/EMUL_GENERIC_INLINE but
not on critical path.
* FIXME: devices.c/emul_netbsd.c would benefit (slightly) from
the inclusion of device_tree.c/emul_generic.c.
@ -1064,10 +1266,6 @@ Sun Oct 22 19:27:48 1995 Andrew Cagney <cagney@highland.com.au>
* NOTE: mon does not contain to count instruction loads as this
information is already available from the mon_issue() hook.
* FIXME: mon doesn't have access to register usage information.
This is needed if the user wants to monitor things like register
stalls.
* igen.c (lf_print_c_semantic), vm_n.h: Add counting code.
* psim.h, psim.c (psim_create), cpu.h, cpu.c (cpu_create): Attach
@ -1106,9 +1304,6 @@ Wed Oct 18 23:02:20 1995 Andrew Cagney <cagney@highland.com.au>
cache-rule and opcode-rule tables from macros found std-config.h.
Delete corresponding macro's from std-config.h.
* FIXME: under this new igen scheme, when playing around with igen
options, you'll find that depenencies don't work very well.
* igen.c (gen_itable_c, gen_itable_h), Makefile.in: code to output
an table of all the instructions. Code to output a type
enumerating all the instructin names.
@ -1141,9 +1336,6 @@ Mon Oct 16 00:31:20 1995 Andrew Cagney <cagney@highland.com.au>
doc in bits.h, remove dead code in bits.c, move ROTL32/ROTL64 into
bits.h.
* FIXME: the bits.h/bits.c macro's should be replaced with
(inline) c functions.
* cpu.c(cpu_add_commas), device_tree.h, device_tree.c(scand_*):
Add size of buffer argument to functions writing a string into a
buffer. Check for buffer overflow.

View File

@ -3,56 +3,52 @@
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
This directory contains the program PSIM that models the PowerPC(tm -
IBM) architecture. It can either be run stand alone (psim or run) or
This directory contains the program PSIM that models the PowerPC (tm -
IBM) architecture. It can be run either standalone (psim or run) or
used as part of GDB.
KNOWN FEATURES
KNOWN FEATURES:
SMP: A Symetric Multi-Processor configuration is suported. This
includes modeling of the PowerPC load word and reserve instructions
(if intending to use this feature you are well advised to read the the
source code for the reservation instructions so that you are aware of
any potential limitations in the model). The number of processors is
selected during startup.
SMP: It is possible to configure this simulator so that it implements
a restricted model of a Symetric Multi-Processor architecture. It is
important to note that the SMP model has limitations. In particular,
the PowerPC's load word and reserve (etc) instructions do not model
the behavour defined in the Architecture manual. People intending to
use this feature should read the code implementing those instructions.
DUAL-ENDIAN: Both little and big endian models are suported. The
execution of instruction sequences that switch between the two modes,
however, is not. The endianess is selected during startup.
ENDIAN SUPORT: Pure big, pure little and PowerPC little endian (xor
endian) models are suported.
UIEA, VEA and OEA: The PowerPC architecture defines three levels of
the PowerPC architecture. This simulator, to a reasonable degree, is
capable of modeling all three. That is the User Instruction Set
Architecture, the Virtual Environment Architecture and finally the
Operating Environment Architecture. The environment is selected
during startup. The OEA model is still under development.
Operating Environment Architecture.
HARDWARE DEVICE TREE: In the OEA, the model of the target machines
hardware is built from a tree of devices (bit like Open Boot).
Included in this is the ability to model bus hierachies and
runtime-configurable devices (eg PCI). The device tree used to create
the hardware model is created during startup. This device tree is
still under development.
runtime-configurable devices (eg PCI).
VEA SYSTEM CALLS: In user mode, basic system calls (read, write, open,
close ...) are emulated. Under NetBSD (simply because that is what my
machine at home runs) the list is more extensive.
OS EMULATION: Suport for os/firmware emulations (system or rom-calls)
is included. At present limited implemtations of two emulations are
included:NetBSD (UEA model) and OpenBoot (OEA model).
PEDANTIC VEA MEMORY MODEL: This model implements the break (brk, sbrk)
system calls. Further, the user model has very strict memory access
controls. User programs can not assume that they can stray off the
end of valid memory areas. This model defines valid memory addresses
in strict accordance to the executable and does not page allign their
values. At first this was a bug but since then has turned up several
problems in user code so it is now described as a feature.
PEDANTIC VEA MEMORY MODEL: In VEA/UEA NetBSD simulations, this model
implements the break (brk, sbrk) system calls. Further, the user
model has very strict memory access controls. User programs can not
assume that they can stray off the end of valid memory areas. This
model defines valid memory addresses in strict accordance to the
executable and does not page allign their values. At first this was a
bug but since then has turned up several problems in user code so it
is now described as a feature.
PROFILING: The simulation is able to count the number and type of
instructions issued and the number of loads and stores. This feature
is still under development.
PERFORMANCE MONITORING: This simulation is able to monitor things such
as cpu/io read/writes and register allocation.
PERFORMANCE: In its default configuration PSIM is constructed so that
PERFORMANCE: In its default configuration PSIM is configured so that
it will compile fast and run slow. Through the enabling of more
agressive compile options (and the disabling of unwanted features) the
build can be changed to compile slow and run fast.
@ -65,7 +61,14 @@ BUILDING PSIM:
To build PSIM you will need the following:
gdb-4.15.tar.gz From your favorite GNU ftp site
gdb-4.15.tar.gz From your favorite GNU ftp site.
I've also tested psim-951016 with
gdb-4.15.1.
ftp://ftp.ci.com.au/pub/clayton/README.pim
This file.
ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+psim-951016.diff.gz
@ -90,10 +93,32 @@ To build PSIM you will need the following:
empty files.
In the directory ftp.ci.com.au:pub/clayton you will also notice files
named psim-NNNNNN.tar.gz. Those, more recent snapshots, may or may
not work with gdb.
Since PSIM is still being developed, from time to time, further psim
snap shots are occasionally made available. These snapshots may or
may not work with GDB-4.15. Several of the more significant snap
shots are:
ftp://ftp.ci.com.au/pub/clayton/psim-951215.tar.gz
A dangerous snap shot
Hopefully merges in Michael stuff
with mine, adds multiple emulations
(OpenBoot and NetBSD), revamps
inline stuff, rearanges devices so
that phandls and ihandles can be
implemented.
ftp://ftp.ci.com.au/pub/clayton/psim-951203.tar.gz
A good snapshot
This includes extensions from Michael
Meissner that add monitoring of the
PowerPC's register and bus architectures.
Procedure:
0. A starting point
@ -148,7 +173,9 @@ not work with gdb.
5. Install
$ make CC=gcc install
or just
$ cp gdb/gdb ~/bin/powerpc-unknown-eabisim-gdb
$ cp sim/ppc/run ~/bin/powerpc-unknown-eabisim-run
@ -194,9 +221,9 @@ is almost never used) at:
powerpc-psim@ci.com.au
If I get the ftp archive updated I post a note to that news group. In
addition your welcome to send bugs or problems either to me or to that
e-mail list.
If I get the ftp archive updated I post a note to that mailing list.
In addition your welcome to send bugs or problems either to me or to
that e-mail list.
KNOWN PROBLEMS:
@ -209,17 +236,9 @@ best. It is intended to be functionaly correct rather than fast.
HTAB (page) code for OEA model untested. Some of the vm code
instructions unimplemented.
Flush instruction cache instructions do nothing. Perhaphs they should
(if there is an instruction cache) flush it.
Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups. The
PowerOpen worked until I added the ELF one.
OpenBoot and PR*P interfaces missing. Open boot could be implemented
by putting special instructions at the address of the OpenBoot
callback functions. Those instructions could than emulate OpenBoot
behavour.
Missing VEA system calls.
Missing or commented out instructions.
@ -247,49 +266,3 @@ Thanks go to the following who each helped in some way.
Allen Briggs, Bett Koch, David Edelsohn, Gordon Irlam,
Michael Meissner, Bob Mercier, Richard Perini,
Richard Stallman, Mitchele Walker
----------------------------------------------------------------
Random notes on performance:
$ cd test
time ../psim count `expr 10000000 / 2`
time ../psim volatile-count `expr 10000000 / 7`
Where 2 and 7 are the number of instructions in the main loop.
611/729 - baseline
Tests:
CFLAGS= -c -O2 -m486 -fomit-frame-pointer
o different first/second level table/switch combinations
0 - use a table
1 - use a simple switch
2 - use an expanded switch
i486DX4/100 - AMD
1/108/140 - switch=0/0/0,expand=2,inline=2,nia=1,cache=1
1/114/140 - switch=0/0/0,expand=2,inline=2,nia=1,cache=1
1/137/149 - switch=0/0,expand=2,inline=1,nia=1,cache=1
1/144/155 - switch=2/1,expand=2,inline=1,nia=1,cache=1
1/153/159 - switch=2/1,expand=0,inline=1,nia=1,cache=1
1/185/189 - switch=0/0,expand=0,inline=1,nia=1
i486DX2/66
1/572/695 - switch=1/1,expand=0,inline=0
1/579/729 - switch=0/0,expand=0,inline=0
1/570/682 - switch=2/2,expand=0,inline=0
1/431/492 - switch=0/0,expand=0,inline=1,nia=0
1/271/292 - switch=2/1,expand=0,inline=1,nia=0
1/270/316 - switch=2/2,expand=0,inline=1,nia=0
1/271/281 - switch=1/1,expand=0,inline=1,nia=1
1/267/274 - switch=2/1,expand=0,inline=1,nia=1

94
sim/ppc/cap.c Normal file
View File

@ -0,0 +1,94 @@
/* 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 _CAP_C_
#define _CAP_C_
#ifndef STATIC_INLINE_CAP
#define STATIC_INLINE_CAP STATIC_INLINE
#endif
#include "cap.h"
typedef struct _cap_mapping cap_mapping;
struct _cap_mapping {
unsigned32 external;
void *internal;
cap_mapping *next;
};
struct _cap {
int nr_mappings;
cap_mapping *mappings;
};
INLINE_CAP cap *
cap_create(const char *key)
{
return ZALLOC(cap);
}
INLINE_CAP void
cap_init(cap *map)
{
cap_mapping *current_mapping = map->mappings;
while (current_mapping != NULL) {
cap_mapping *tbd = current_mapping;
current_mapping = tbd->next;
zfree(tbd);
}
map->nr_mappings = 0;
map->mappings = (cap_mapping*)0;
}
INLINE_CAP void *
cap_internal(cap *db,
signed32 external)
{
cap_mapping *current_map = db->mappings;
while (current_map != NULL) {
if (current_map->external == external)
return current_map->internal;
current_map = current_map->next;
}
return (void*)0;
}
INLINE_CAP signed32
cap_external(cap *db,
void *internal)
{
cap_mapping *current_map = db->mappings;
while (current_map != NULL) {
if (current_map->internal == internal)
return current_map->external;
current_map = current_map->next;
}
current_map = ZALLOC(cap_mapping);
current_map->next = db->mappings;
current_map->internal = internal;
db->nr_mappings += 1;
current_map->external = db->nr_mappings;
db->mappings = current_map;
return current_map->external;
}
#endif

50
sim/ppc/cap.h Normal file
View File

@ -0,0 +1,50 @@
/* 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.
*/
/* Export a capability data base that maps between internal data
values and those given to a simulation */
#ifndef _CAP_H_
#define _CAP_H_
#ifndef INLINE_CAP
#define INLINE_CAP
#endif
#include "basics.h"
typedef struct _cap cap;
INLINE_CAP cap *cap_create
(const char *name);
INLINE_CAP void cap_init
(cap *db);
INLINE_CAP signed32 cap_external
(cap *db,
void *internal);
INLINE_CAP void *cap_internal
(cap *db,
signed32 external);
#endif

View File

@ -128,15 +128,15 @@ AC_ARG_ENABLE(sim-inline,
case "$enableval" in
no) sim_inline="-DDEFAULT_INLINE=0 -DINLINE=";;
0) sim_inline="-DDEFAULT_INLINE=0";;
yes | 2) sim_inline="-DDEFAULT_INLINE=2";;
1) sim_inline="-DDEFAULT_INLINE=1";;
yes | 2) sim_inline="-DDEFAULT_INLINE=ALL_INLINE";;
1) sim_inline="-DDEFAULT_INLINE=INLINE_LOCALS";;
*) for x in `echo "$enableval" | sed -e "s/,/ /g"`; do
new_flag=""
case "$x" in
*_INLINE=*) new_flag="-D$x";;
*_INLINE) new_flag="-D$x=2";;
*_INLINE) new_flag="-D$x=ALL_INLINE";;
*=*) new_flag=`echo "$x" | sed -e "s/=/_INLINE=/" -e "s/^/-D/"`;;
*) new_flag="-D$x""_INLINE=2";;
*) new_flag="-D$x""_INLINE=ALL_INLINE";;
esac
if test x"$sim_inline" = x""; then
sim_inline="$new_flag"
@ -148,7 +148,7 @@ esac
if test x"$silent" != x"yes" && test x"$sim_inline" != x""; then
echo "Setting inline flags = $sim_inline" 6>&1
fi],[if test x"$GCC" != ""; then
sim_inline="-DDEFAULT_INLINE=1"
sim_inline="-DDEFAULT_INLINE=INLINE_LOCALS"
if test x"$silent" != x"yes"; then
echo "Setting inline flags = $sim_inline" 6>&1
fi

View File

@ -23,19 +23,19 @@
#error "N must be #defined"
#endif
#undef unsigned_N
/* NOTE: see end of file for #undef of these macros */
#define unsigned_N XCONCAT2(unsigned_,N)
#undef T2H_N
#define T2H_N XCONCAT2(T2H_,N)
#undef H2T_N
#define H2T_N XCONCAT2(H2T_,N)
#define core_map_read_N XCONCAT2(core_map_read_,N)
#define core_map_write_N XCONCAT2(core_map_write_,N)
INLINE_CORE unsigned_N
XCONCAT2(core_map_read_,N)(core_map *map,
unsigned_word addr,
cpu *processor,
unsigned_word cia)
unsigned_N INLINE_CORE
core_map_read_N(core_map *map,
unsigned_word addr,
cpu *processor,
unsigned_word cia)
{
core_mapping *mapping = core_map_find_mapping(map,
addr,
@ -43,15 +43,15 @@ XCONCAT2(core_map_read_,N)(core_map *map,
processor,
cia,
1); /*abort*/
if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) {
if (WITH_CALLBACK_MEMORY && mapping->device != NULL) {
unsigned_N data;
if (mapping->reader(mapping->device,
&data,
mapping->space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
cia) != sizeof(unsigned_N))
if (device_io_read_buffer(mapping->device,
&data,
mapping->space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
cia) != sizeof(unsigned_N))
error("core_read_,N() reader should not fail\n");
return T2H_N(data);
}
@ -61,12 +61,12 @@ XCONCAT2(core_map_read_,N)(core_map *map,
INLINE_CORE void
XCONCAT2(core_map_write_,N)(core_map *map,
unsigned_word addr,
unsigned_N val,
cpu *processor,
unsigned_word cia)
void INLINE_CORE
core_map_write_N(core_map *map,
unsigned_word addr,
unsigned_N val,
cpu *processor,
unsigned_word cia)
{
core_mapping *mapping = core_map_find_mapping(map,
addr,
@ -74,18 +74,24 @@ XCONCAT2(core_map_write_,N)(core_map *map,
processor,
cia,
1); /*abort*/
if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) {
if (WITH_CALLBACK_MEMORY && mapping->device != NULL) {
unsigned_N data = H2T_N(val);
if (mapping->writer(mapping->device,
&data,
mapping->space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
cia) != sizeof(unsigned_N))
if (device_io_write_buffer(mapping->device,
&data,
mapping->space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
cia) != sizeof(unsigned_N))
error("core_read_,N() writer should not fail\n");
}
else
*(unsigned_N*)core_translate(mapping, addr) = H2T_N(val);
}
/* NOTE: see start of file for #define of these macros */
#undef unsigned_N
#undef T2H_N
#undef H2T_N
#undef core_map_read_N
#undef core_map_write_N

151
sim/ppc/corefile.h Normal file
View File

@ -0,0 +1,151 @@
/* 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 _CORE_H_
#define _CORE_H_
/* basic types */
typedef struct _core core;
typedef struct _core_map core_map;
/* constructor */
core INLINE_CORE *core_create
(void);
device INLINE_CORE *core_device_create
(core *);
/* the core has three sub mappings that the more efficient
read/write fixed quantity functions use */
core_map INLINE_CORE *core_readable
(core *memory);
core_map INLINE_CORE *core_writeable
(core *memory);
core_map INLINE_CORE *core_executable
(core *memory);
/* operators to add/remove a mapping in the core
callback-memory:
All access are passed onto the specified devices callback routines
after being `translated'. DEFAULT indicates that the specified
memory should be called if all other mappings fail.
For callback-memory, the device must be specified.
raw-memory:
While RAM could be implemented using the callback interface
core instead treats it as the common case including the code
directly in the read/write operators.
For raw-memory, the device is ignored and the core alloc's a
block to act as the memory.
default-memory:
Should, for the core, there be no defined mapping for a given
address then the default map (if present) is called.
For default-memory, the device must be specified. */
void INLINE_CORE core_attach
(core *map,
attach_type attach,
int address_space,
access_type access,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
device *device); /*callback/default*/
void INLINE_CORE core_detach
(core *map,
attach_type attach,
int address_space,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
access_type access,
device *device); /*callback/default*/
/* Variable sized read/write:
Transfer (zero) a variable size block of data between the host and
target (possibly byte swapping it). Should any problems occure,
the number of bytes actually transfered is returned. */
unsigned INLINE_CORE core_map_read_buffer
(core_map *map,
void *buffer,
unsigned_word addr,
unsigned nr_bytes);
unsigned INLINE_CORE core_map_write_buffer
(core_map *map,
const void *buffer,
unsigned_word addr,
unsigned nr_bytes);
/* Fixed sized read/write:
Transfer a fixed amout of memory between the host and target. The
memory always being translated and the operation always aborting
should a problem occure */
#define DECLARE_CORE_WRITE_N(N) \
void INLINE_CORE core_map_write_##N \
(core_map *map, \
unsigned_word addr, \
unsigned_##N val, \
cpu *processor, \
unsigned_word cia);
DECLARE_CORE_WRITE_N(1)
DECLARE_CORE_WRITE_N(2)
DECLARE_CORE_WRITE_N(4)
DECLARE_CORE_WRITE_N(8)
DECLARE_CORE_WRITE_N(word)
#define DECLARE_CORE_READ_N(N) \
unsigned_##N INLINE_CORE core_map_read_##N \
(core_map *map, \
unsigned_word addr, \
cpu *processor, \
unsigned_word cia);
DECLARE_CORE_READ_N(1)
DECLARE_CORE_READ_N(2)
DECLARE_CORE_READ_N(4)
DECLARE_CORE_READ_N(8)
DECLARE_CORE_READ_N(word)
#endif

1155
sim/ppc/device.c Normal file

File diff suppressed because it is too large Load Diff

660
sim/ppc/device.h Normal file
View File

@ -0,0 +1,660 @@
/* 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 _DEVICE_TREE_H_
#define _DEVICE_TREE_H_
#ifndef INLINE_DEVICE
#define INLINE_DEVICE
#endif
/* declared in basics.h, this object is used everywhere */
/* typedef struct _device device; */
/* Device Tree:
All the devices in this model live in a tree. The following allow
the location/manipulation of this tree */
device INLINE_DEVICE *device_sibling
(device *me);
device INLINE_DEVICE *device_child
(device *me);
device INLINE_DEVICE *device_parent
(device *me);
const char INLINE_DEVICE *device_name
(device *me);
void INLINE_DEVICE *device_data
(device *me);
/* Grow the device tree adding either a specific device or
alternativly a device found in the device table */
device INLINE_DEVICE *device_tree_add_device
(device *root,
const char *prefix,
device *new_sub_tree);
device INLINE_DEVICE *device_tree_add_found
(device *root,
const char *prefix,
const char *name);
device INLINE_DEVICE *device_tree_add_found_c
(device *root,
const char *prefix,
const char *name,
const char *c1);
device INLINE_DEVICE *device_tree_add_found_c_uw
(device *root,
const char *prefix,
const char *name,
const char *c1,
unsigned_word uw2);
device INLINE_DEVICE *device_tree_add_found_uw_u
(device *root,
const char *prefix,
const char *name,
unsigned_word uw1,
unsigned u2);
device INLINE_DEVICE *device_tree_add_found_uw_u_u
(device *root,
const char *prefix,
const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3);
device INLINE_DEVICE *device_tree_add_found_uw_u_u_c
(device *root,
const char *prefix,
const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3,
const char *c4);
device INLINE_DEVICE *device_tree_add_found_uw_uw_u_u_c
(device *root,
const char *prefix,
const char *name,
unsigned_word uw1,
unsigned_word uw2,
unsigned u3,
unsigned u4,
const char *c5);
device INLINE_DEVICE *device_tree_add_found_uw_uw_u_u_u
(device *root,
const char *prefix,
const char *name,
unsigned_word uw1,
unsigned_word uw2,
unsigned u3,
unsigned u4,
unsigned u5);
/* Query the device tree, null is returned if the specified device is
not found */
device INLINE_DEVICE *device_tree_find_device
(device *root,
const char *path);
/* traverse the device tree visiting all notes (either pre or post
fix) */
typedef void (device_tree_traverse_function)
(device *device,
void *data);
void INLINE_DEVICE device_tree_traverse
(device *root,
device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix,
void *data);
/* dump a node, this can be passed to the device_tree_traverse()
function to dump out the entire device tree */
void INLINE_DEVICE device_tree_dump
(device *device,
void *ignore_data_argument);
/* Device Properties:
Attached to a device (typically by open boot firmware) are
properties that profile the devices features. The below allow the
manipulation of device properties */
/* Each device can have associated properties. Internal to
psim those properties are strictly typed. Within the simulation,
no such control exists */
typedef enum {
integer_property,
boolean_property,
string_property,
array_property,
null_property,
} device_property_type;
typedef struct _device_property device_property;
struct _device_property {
device *owner;
device_property_type type;
unsigned sizeof_array;
const void *array;
};
/* Basic operations used by software */
const char INLINE_DEVICE *device_find_next_property
(device *me,
const char *previous);
void INLINE_DEVICE device_set_property
(device *me,
const char *property,
const void *array,
int sizeof_array);
/* INLINE_DEVICE void device_add_property
No such external function, all properties, when added are explictly
typed */
void INLINE_DEVICE device_add_array_property
(device *me,
const char *property,
const void *array,
int sizeof_array);
void INLINE_DEVICE device_add_integer_property
(device *me,
const char *property,
signed_word integer);
void INLINE_DEVICE device_add_boolean_property
(device *me,
const char *property,
int bool);
void INLINE_DEVICE device_add_null_property
(device *me,
const char *property);
void INLINE_DEVICE device_add_string_property
(device *me,
const char *property,
const char *string);
/* Locate a property returning its description. Return NULL if the
named property is not found */
const device_property INLINE_DEVICE *device_find_property
(device *me,
const char *property);
/* Process all properties attached to the named device */
typedef void (device_traverse_property_function)
(device *me,
const char *name,
void *data);
void INLINE_DEVICE device_traverse_properties
(device *me,
device_traverse_property_function *traverse,
void *data);
/* Similar to above except that the property *must* be in the device
tree and *must* be of the specified type. */
const device_property INLINE_DEVICE *device_find_array_property
(device *me,
const char *property);
signed_word INLINE_DEVICE device_find_integer_property
(device *me,
const char *property);
const char INLINE_DEVICE *device_find_string_property
(device *me,
const char *property);
int INLINE_DEVICE device_find_boolean_property
(device *me,
const char *property);
/* Device Hardware:
A device principaly is modeling real hardware that a processor can
directly interact with via load/stores dma's and interrupts. The
interface below is used by the hardware side of the device
model. */
/* Address access attributes that can be attached to a devices address
range */
typedef enum _access_type {
access_invalid = 0,
access_read = 1,
access_write = 2,
access_read_write = 3,
access_exec = 4,
access_read_exec = 5,
access_write_exec = 6,
access_read_write_exec = 7,
} access_type;
/* Address attachement types */
typedef enum _attach_type {
attach_invalid,
attach_callback,
attach_default,
attach_raw_memory,
} attach_type;
/* Initialization:
A device is made fully functional in two stages.
1. It is created. A device is created _before_ it is entered into
the device tree. During creation any permenant structures needed
by the device should be created/initialized.
2. It is initialized. Before a simulation run, each device in the
device tree is initialized in prefix order. As part of this
initialization, a device should (re)attach its self to its parent
as needed.
*/
device INLINE_DEVICE *device_create
(const char *name,
device *parent);
/* some external functions want to create things */
typedef struct _device_callbacks device_callbacks;
device INLINE_DEVICE *device_create_from
(const char *name,
void *data,
const device_callbacks *callbacks,
device *parent);
void INLINE_DEVICE device_init
(device *me,
psim *system);
/* initialize the entire tree */
void INLINE_DEVICE device_tree_init
(device *root,
psim *system);
/* Data transfers:
A device may permit the reading/writing (IO) of its registers in
one or more address spaces. For instance, a PCI device may have
config registers in its config space and control registers in both
the io and memory spaces of a PCI bus.
Similarly, a device may initiate a data transfer (DMA) by passing
such a request up to its parent.
Init:
As part of its initialization (not creation) and possibly also as a
consequence of IO a device may attach its self to one or more of
the address spaces of its parent device.
For instance, a PCI device, during initialization would attach its
config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
bridge. Later, due to a write to this config space, the same
device may in turn find it necessary to also attach its self to
it's parent's `memory' or `io' space.
To perform these operations, a device will call upon its parent
using either device_attach_address or device_detach_address.
* Any address specified is according to what the device expects to
see.
* Any detach operation must exactly match a previous attach.
* included with the attach or detach is the devices name, the
parent may use this as part of determining how to map map between a
child's address + space and its own.
* at any time, at most one device can have a default mapping
registered.
IO:
A device receives requests to perform reads/writes to its registers
or memory either A. from a processor or B. from a parent device.
The device may then in turn either A. resolve the IO request
locally by processing the data or trigering an exception or
B. re-mapping the access onto one of its local address spaces and
then in turn passing that on to one of its children.
* Any address passed is relative to the local device. Eg for PCI
config registers, the address would (normally) be in the range of 0
to 63.
* Any exception situtation triggered by an IO operation (processor
!= NULL) is handled in one of the following ways: 1. Machine check
(and similar): issued immediatly by restarting the cpu; 2. External
exception: issue delayed (using events.h) until the current
instruction execution cycle is completed; 3. Slave device (and
similar): the need for the interrupt is passed on to the devices
parent (which being an interrupt control unit will in turn take one
of the actions described here); 4. Forget it.
* Any exception situtation trigered by a non IO operation
(processor == NULL) is handled buy returning 0.
* Transfers of size <= 8 and of a power of 2 *must* be correctly
aligned and should be treated as a `single cycle' transfer.
DMA:
A device initiates a DMA transfer by calling its parent with the
request. At the top level (if not done earlier) this is reflected
back down the tree as io read/writes to the target device.
This function is subject to change ...
*/
void INLINE_DEVICE device_attach_address
(device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
device *who); /*callback/default*/
void INLINE_DEVICE device_detach_address
(device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
device *who); /*callback/default*/
unsigned INLINE_DEVICE device_io_read_buffer
(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
unsigned INLINE_DEVICE device_io_write_buffer
(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
unsigned INLINE_DEVICE device_dma_read_buffer
(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes);
unsigned INLINE_DEVICE device_dma_write_buffer
(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section);
/* Interrupts:
As mentioned above. Instead of handling an interrupt directly, a
device may instead pass the need to interrupt on to its parent.
Init:
Before passing interrupts up to is parent, a device must first
attach its interrupt lines to the parent device. To do this, the
device uses the parents attach/detach calls.
Interrupts:
A child notifies a parent of a change in an interrupt lines status
using the interrupt call. Similarly, a parent may notify a child
of any `interrupt ack' sequence using the interrupt_ack call.
*/
void INLINE_DEVICE device_attach_interrupt
(device *me,
device *who,
int interrupt_line,
const char *name);
void INLINE_DEVICE device_detach_interrupt
(device *me,
device *who,
int interrupt_line,
const char *name);
void INLINE_DEVICE device_interrupt
(device *me,
device *who,
int interrupt_line,
int interrupt_status,
cpu *processor,
unsigned_word cia);
void INLINE_DEVICE device_interrupt_ack
(device *me,
int interrupt_line,
int interrupt_status);
/* IOCTL:
Very simply, a catch all for any thing that turns up that until now
either hasn't been thought of or doesn't justify an extra function. */
void EXTERN_DEVICE device_ioctl
(device *me,
psim *system,
cpu *processor,
unsigned_word cia,
...);
/* Device software - the instance
Under development
In addition to the processor directly manipulating a device via
read/write operations. A program may manipulate a device
indirectly via OpenBoot calls. The following provide a higher
level software interface to the devices */
device_instance INLINE_DEVICE *device_instance_open
(device *me,
const char *device_specifier);
void INLINE_DEVICE device_instance_close
(device_instance *instance);
int INLINE_DEVICE device_instance_read
(device_instance *instance,
void *addr,
unsigned_word len);
int INLINE_DEVICE device_instance_write
(device_instance *instance,
const void *addr,
unsigned_word len);
int INLINE_DEVICE device_instance_seek
(device_instance *instance,
unsigned_word pos_hi,
unsigned_word pos_lo);
device INLINE_DEVICE *device_instance_device
(device_instance *instance);
const char INLINE_DEVICE *device_instance_name
(device_instance *instance);
/* Device dregs... */
/* Parse a device name */
void INLINE_DEVICE device_tree_parse_name
(const char *name,
const char **driver_name,
const char **unit_address,
const char **device_arguments,
const char **end);
/* Parse a device name, various formats:
uw: unsigned_word
u: unsigned
c: string */
int INLINE_DEVICE scand_c
(const char *name,
char *c1,
unsigned c1size);
int INLINE_DEVICE scand_c_uw_u
(const char *name,
char *c1,
unsigned c1size,
unsigned_word *uw2,
unsigned *u3);
int INLINE_DEVICE scand_uw
(const char *name,
unsigned_word *uw1);
int INLINE_DEVICE scand_uw_c
(const char *name,
unsigned_word *uw1,
char *c2,
unsigned c2size);
int INLINE_DEVICE scand_uw_u
(const char *name,
unsigned_word *uw1,
unsigned *u2);
int INLINE_DEVICE scand_uw_u_u
(const char *name,
unsigned_word *uw1,
unsigned *u2,
unsigned *u3);
int INLINE_DEVICE scand_uw_u_u_c
(const char *name,
unsigned_word *uw1,
unsigned *u2,
unsigned *u3,
char *c4,
unsigned c4size);
int INLINE_DEVICE scand_uw_uw
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2);
int INLINE_DEVICE scand_uw_uw_u
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3);
int INLINE_DEVICE scand_uw_uw_u_u_c
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3,
unsigned *u4,
char *c5,
unsigned c5size);
int INLINE_DEVICE scand_uw_uw_u_u_u
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3,
unsigned *u4,
unsigned *u5);
#endif /* _DEVICE_TREE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,817 +0,0 @@
/* 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 _DEVICE_TREE_C_
#define _DEVICE_TREE_C_
#ifndef STATIC_INLINE_DEVICE_TREE
#define STATIC_INLINE_DEVICE_TREE STATIC_INLINE
#endif
#include <stdio.h>
#include "basics.h"
#include "device_tree.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
typedef enum {
node_any = 0,
node_device,
node_integer,
node_boolean,
node_string
} node_type;
static char *node_type_names[] = {
"any",
"device",
"integer",
"boolean",
"string",
NULL,
};
struct _device_tree {
/* where i am */
device_tree *parent;
device_tree *children;
device_tree *sibling;
/* what i am */
node_type type;
const char *name;
/* the value */
const device *device;
int boolean;
const char *string;
signed_word integer;
};
STATIC_INLINE_DEVICE_TREE device_tree *
new_device_tree(device_tree *parent,
const char *name,
node_type type)
{
device_tree *new_node;
new_node = ZALLOC(device_tree);
new_node->parent = parent;
new_node->name = strdup(name);
new_node->type = type;
if (parent != NULL) {
device_tree **sibling = &parent->children;
while ((*sibling) != NULL)
sibling = &(*sibling)->sibling;
*sibling = new_node;
}
return new_node;
}
/* find/create a node in the device tree */
typedef enum {
device_tree_grow = 1,
device_tree_return_null = 2,
device_tree_abort = 3,
} device_tree_action;
STATIC_INLINE_DEVICE_TREE device_tree *
device_tree_find_node(device_tree *root,
const char *path,
const char *full_path,
node_type type,
device_tree_action action)
{
const char *chp;
int name_len;
device_tree *child;
/* strip off any leading `/', `../' or `./' */
while (1) {
if (strncmp(path, "/", strlen("/")) == 0) {
while (root != NULL && root->parent != NULL)
root = root->parent;
path += strlen("/");
}
else if (strncmp(path, "./", strlen("./")) == 0) {
root = root;
path += strlen("./");
}
else if (strncmp(path, "../", strlen("../")) == 0) {
if (root != NULL && root->parent != NULL)
root = root->parent;
path += strlen("../");
}
else {
break;
}
}
/* find the qualified (with @) and unqualified names in the path,
remembering to skip any "\/" */
chp = path;
do {
chp = strchr(chp+1, '/');
} while (chp != NULL && chp[-1] == '\\');
name_len = (chp == NULL
? strlen(path)
: chp - path);
/* leaf? and growing? */
if (root != NULL) {
for (child = root->children;
child != NULL;
child = child->sibling) {
if (strncmp(path, child->name, name_len) == 0
&& (strlen(child->name) == name_len
|| (strchr(child->name, '@')
== child->name + name_len))) {
if (path[name_len] == '\0') {
if (action == device_tree_grow)
error("device_tree_find_node() node %s already present\n",
full_path);
if (type != node_any && child->type != type) {
if (action == device_tree_return_null)
return NULL;
else
error("device_tree_find_node() node %s is not of type %s\n",
full_path, node_type_names[type]);
}
else
return child;
}
else
return device_tree_find_node(child,
path + name_len + 1,
full_path,
type,
action);
}
}
}
/* search failed, take default action */
switch (action) {
case device_tree_grow:
if (path[name_len] != '\0')
error("device_tree_find_node() a parent of %s missing\n",
full_path);
return new_device_tree(root, path, type);
case device_tree_return_null:
return NULL;
case device_tree_abort:
error("device_tree_find_node() could not find %s in tree\n",
full_path);
return NULL;
default:
error("device_tree_find_node() invalid default action %d\n", action);
return NULL;
}
}
/* grow the device tree */
INLINE_DEVICE_TREE device_tree *
device_tree_add_passthrough(device_tree *root,
const char *path)
{
device_tree *new_node;
TRACE(trace_device_tree,
("device_tree_add_passthrough(root=0x%lx, path=%s)\n", (long)root, path));
new_node = device_tree_find_node(root,
path,
path, /*full_path*/
node_device,
device_tree_grow);
new_node->device = device_create_from(new_node->name,
path,
NULL,
passthrough_device_callbacks(),
new_node->parent->device);
TRACE(trace_device_tree,
("device_tree_add_passthrough() = 0x%lx\n", (long)new_node));
return new_node;
}
INLINE_DEVICE_TREE device_tree *
device_tree_add_device(device_tree *root,
const char *path,
const device *dev)
{
device_tree *new_node;
TRACE(trace_device_tree,
("device_tree_add_device(root=0x%lx, path=%s, dev=0x%lx)\n",
(long)root, path, (long)dev));
new_node = device_tree_find_node(root,
path,
path, /* full-path */
node_device,
device_tree_grow);
new_node->device = dev;
TRACE(trace_device_tree,
("device_tree_add_device() = 0x%lx\n", (long)new_node));
return new_node;
}
INLINE_DEVICE_TREE device_tree *
device_tree_add_integer(device_tree *root,
const char *path,
signed_word integer)
{
device_tree *new_node;
TRACE(trace_device_tree,
("device_tree_add_integer(root=0x%lx, path=%s, integer=%ld)\n",
(long)root, path, (long)integer));
new_node = device_tree_find_node(root,
path,
path, /* full-name */
node_integer,
device_tree_grow);
new_node->integer = integer;
TRACE(trace_device_tree,
("device_tree_add_integer() = 0x%lx\n", (long)new_node));
return new_node;
}
INLINE_DEVICE_TREE device_tree *
device_tree_add_string(device_tree *root,
const char *path,
const char *string)
{
device_tree *new_node;
TRACE(trace_device_tree,
("device_tree_add_device(root=0x%lx, path=%s, string=%s)\n",
(long)root, path, string));
new_node = device_tree_find_node(root,
path,
path, /* full-name */
node_string,
device_tree_grow);
new_node->string = strdup(string);
TRACE(trace_device_tree,
("device_tree_add_string() = 0x%lx\n", (long)new_node));
return new_node;
}
INLINE_DEVICE_TREE device_tree *
device_tree_add_boolean(device_tree *root,
const char *path,
int boolean)
{
device_tree *new_node;
TRACE(trace_device_tree,
("device_tree_add_boolean(root=0x%lx, path=%s, boolean=%d)\n",
(long)root, path, boolean));
new_node = device_tree_find_node(root,
path,
path, /* full-name */
node_boolean,
device_tree_grow);
new_node->boolean = boolean;
TRACE(trace_device_tree,
("device_tree_add_boolean() = 0x%lx\n", (long)new_node));
return new_node;
}
INLINE_DEVICE_TREE device_tree *
device_tree_add_found_device(device_tree *root,
const char *path)
{
device_tree *new_node;
TRACE(trace_device_tree,
("device_tree_add_found_device(root=0x%lx, path=%s)\n",
(long)root, path));
new_node = device_tree_add_device(root, path, NULL);
new_node->device = device_create(new_node->name,
path,
new_node->parent->device);
TRACE(trace_device_tree,
("device_tree_add_found_device() = 0x%lx\n", (long)new_node));
return new_node;
}
/* look up the device tree */
INLINE_DEVICE_TREE const device *
device_tree_find_device(device_tree *root,
const char *path)
{
device_tree *node;
TRACE(trace_device_tree,
("device_tree_find_device(root=0x%lx, path=%s)\n", (long)root, path));
node = device_tree_find_node(root,
path,
path, /* full-name */
node_device,
device_tree_abort);
TRACE(trace_device_tree,
("device_tree_find_device() = 0x%lx\n", (long)node->device));
return node->device;
}
INLINE_DEVICE_TREE signed_word
device_tree_find_integer(device_tree *root,
const char *path)
{
device_tree *node;
TRACE(trace_device_tree,
("device_tree_find_integer(root=0x%lx, path=%s)\n", (long)root, path));
node = device_tree_find_node(root,
path,
path, /* full-name */
node_integer,
device_tree_abort);
TRACE(trace_device_tree,
("device_tree_find_integer() = %ld\n", (long)node->integer));
return node->integer;
}
INLINE_DEVICE_TREE const char *
device_tree_find_string(device_tree *root,
const char *path)
{
device_tree *node;
TRACE(trace_device_tree,
("device_tree_find_string(root=0x%lx, path=%s)\n", (long)root, path));
node = device_tree_find_node(root,
path,
path, /* full-name */
node_string,
device_tree_abort);
TRACE(trace_device_tree,
("device_tree_find_string() = 0x%lx\n", (long)node->string));
return node->string;
}
INLINE_DEVICE_TREE int
device_tree_find_boolean(device_tree *root,
const char *path)
{
device_tree *node;
TRACE(trace_device_tree,
("device_tree_find_boolean(root=0x%lx, path=%s)\n", (long)root, path));
node = device_tree_find_node(root,
path,
path, /* full-name */
node_boolean,
device_tree_abort);
TRACE(trace_device_tree,
("device_tree_find_boolean() = %ld\n", (long)node->boolean));
return node->boolean;
}
/* init all the devices */
STATIC_INLINE_DEVICE_TREE void
device_tree_init_device(device_tree *root,
void *data)
{
psim *system;
system = (psim*)data;
if (root->type == node_device) {
TRACE(trace_device_tree,
("device_tree_init() initializing device=0x%lx:%s\n",
(long)root->device, root->device->full_name));
root->device->callback->init(root->device, system);
}
}
INLINE_DEVICE_TREE void
device_tree_init(device_tree *root,
psim *system)
{
TRACE(trace_device_tree,
("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root, (long)system));
device_tree_traverse(root, device_tree_init_device, NULL, system);
TRACE(trace_device_tree,
("device_tree_init() = void\n"));
}
/* traverse a device tree applying prefix/postfix functions to it */
INLINE_DEVICE_TREE void
device_tree_traverse(device_tree *root,
device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix,
void *data)
{
device_tree *child;
if (prefix != NULL)
prefix(root, data);
for (child = root->children; child != NULL; child = child->sibling) {
device_tree_traverse(child, prefix, postfix, data);
}
if (postfix != NULL)
postfix(root, data);
}
/* dump out a device node and addresses */
INLINE_DEVICE_TREE void
device_tree_dump(device_tree *device,
void *ignore_data_argument)
{
printf_filtered("(device_tree@0x%lx\n", (long)device);
printf_filtered(" (parent 0x%lx)\n", (long)device->parent);
printf_filtered(" (children 0x%lx)\n", (long)device->children);
printf_filtered(" (sibling 0x%lx)\n", (long)device->sibling);
printf_filtered(" (type %ld)\n", (long)device->type);
printf_filtered(" (name %s)\n", device->name);
printf_filtered(" (device 0x%lx)\n", (long)device->device);
printf_filtered(" (boolean %ld)\n", (long)device->boolean);
printf_filtered(" (string %s)\n", device->string);
printf_filtered(" (integer %ld)\n", (long)device->integer);
printf_filtered(")\n");
}
/* Parse a device name, various formats */
#define SCAN_INIT(NAME) \
char *START = (char*)0; \
char *END = (char*)0; \
int COUNT = -1; \
/* find the first element */ \
END = strchr(NAME, '@'); \
if (END == (char*)0) \
return COUNT; \
COUNT += 1; \
START = END + 1
#define SCAN_END \
return COUNT
#define SCAN_U(U) \
do { \
*U = strtoul(START, &END, 0); \
if (START == END) \
return COUNT; \
COUNT += 1; \
if (*END != ',') \
return COUNT; \
START = END + 1; \
} while (0)
#define SCAN_P(P) \
do { \
*P = (void*)(unsigned)strtouq(START, END, 0); \
if (START == END) \
return COUNT; \
COUNT += 1; \
if (*END != ',') \
return COUNT; \
START = END + 1; \
} while (0)
#define SCAN_C(C, SIZE) \
do { \
char *chp = C; \
END = START; \
while (*END != '\0' && *END != ',') { \
if (*END == '\\') \
END += 1; \
*chp = *END; \
chp += 1; \
END += 1; \
if ((SIZE) <= ((END) - (START))) \
return COUNT; /* overflow */ \
} \
*chp = '\0'; \
if (START == END) \
return COUNT; \
COUNT += 1; \
if (*END != ',') \
return COUNT; \
START = END + 1; \
} while (0)
INLINE_DEVICE_TREE int
scand_c(const char *name,
char *c1,
unsigned c1size)
{
SCAN_INIT(name);
SCAN_C(c1, c1size);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_c_uw_u(const char *name,
char *c1,
unsigned c1size,
unsigned_word *uw2,
unsigned *u3)
{
SCAN_INIT(name);
SCAN_C(c1, c1size);
SCAN_U(uw2);
SCAN_U(u3);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw(const char *name,
unsigned_word *uw1)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_c(const char *name,
unsigned_word *uw1,
char *c2,
unsigned c2size)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_C(c2, c2size);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_u(const char *name,
unsigned_word *uw1,
unsigned *u2)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_U(u2);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_u_u(const char *name,
unsigned_word *uw1,
unsigned *u2,
unsigned *u3)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_U(u2);
SCAN_U(u3);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_uw(const char *name,
unsigned_word *uw1,
unsigned_word *uw2)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_U(uw2);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_uw_u(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_U(uw2);
SCAN_U(u3);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_uw_u_u_c(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3,
unsigned *u4,
char *c5,
unsigned c5size)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_U(uw2);
SCAN_U(u3);
SCAN_U(u4);
SCAN_C(c5, c5size);
SCAN_END;
}
INLINE_DEVICE_TREE int
scand_uw_uw_u_u_u(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3,
unsigned *u4,
unsigned *u5)
{
SCAN_INIT(name);
SCAN_U(uw1);
SCAN_U(uw2);
SCAN_U(u3);
SCAN_U(u4);
SCAN_U(u5);
SCAN_END;
}
STATIC_INLINE_DEVICE_TREE void
u_strcat(char *buf,
unsigned_word uw)
{
if (MASKED64(uw, 32, 63) == uw
|| WITH_HOST_WORD_BITSIZE == 64) {
char *end = strchr(buf, '\0');
sprintf(end, "0x%x", (unsigned)uw);
}
else {
char *end = strchr(buf, '\0');
sprintf(end, "0x%x%08x",
(unsigned)EXTRACTED64(uw, 0, 31),
(unsigned)EXTRACTED64(uw, 32, 63));
}
}
STATIC_INLINE_DEVICE_TREE void
c_strcat(char *buf,
const char *c)
{
char *end = strchr(buf, '\0');
while (*c) {
if (*c == '/' || *c == ',')
*end++ = '\\';
*end++ = *c++;
}
*end = '\0';
}
STATIC_INLINE_DEVICE_TREE int
c_strlen(const char *c)
{
int len = 0;
while (*c) {
if (*c == '/' || *c == ',')
len++;
len++;
c++;
}
return len;
}
enum {
strlen_unsigned = 10,
strlen_unsigned_word = 18,
};
INLINE_DEVICE_TREE char *
printd_c(const char *name,
const char *c1)
{
int sizeof_buf = (strlen(name)
+ strlen("@")
+ c_strlen(c1)
+ 1);
char *buf = (char*)zalloc(sizeof_buf);
strcpy(buf, name);
strcat(buf, "@");
c_strcat(buf, c1);
ASSERT(strlen(buf) < sizeof_buf);
return buf;
}
INLINE_DEVICE_TREE char *
printd_c_uw(const char *name,
const char *c1,
unsigned_word uw2)
{
int sizeof_buf = (strlen(name)
+ strlen("@")
+ c_strlen(c1)
+ strlen(",")
+ strlen_unsigned_word
+ 1);
char *buf = (char*)zalloc(sizeof_buf);
strcpy(buf, name);
strcat(buf, "@");
c_strcat(buf, c1);
strcat(buf, ",");
u_strcat(buf, uw2);
ASSERT(strlen(buf) < sizeof_buf);
return buf;
}
INLINE_DEVICE_TREE char *
printd_uw_u(const char *name,
unsigned_word uw1,
unsigned u2)
{
int sizeof_buf = (strlen(name)
+ strlen("@")
+ strlen_unsigned_word
+ strlen(",")
+ strlen_unsigned
+ 1);
char *buf = (char*)zalloc(sizeof_buf);
strcpy(buf, name);
strcat(buf, "@");
u_strcat(buf, uw1);
strcat(buf, ",");
u_strcat(buf, u2);
ASSERT(strlen(buf) < sizeof_buf);
return buf;
}
INLINE_DEVICE_TREE char *
printd_uw_u_u(const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3)
{
int sizeof_buf = (strlen(name)
+ strlen("@")
+ strlen_unsigned_word
+ strlen(",")
+ strlen_unsigned
+ strlen(",")
+ strlen_unsigned
+ 1);
char *buf = (char*)zalloc(sizeof_buf);
strcpy(buf, name);
strcat(buf, "@");
u_strcat(buf, uw1);
strcat(buf, ",");
u_strcat(buf, u2);
strcat(buf, ",");
u_strcat(buf, u3);
ASSERT(strlen(buf) < sizeof_buf);
return buf;
}
INLINE_DEVICE_TREE char *
printd_uw_u_u_c(const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3,
const char *c4)
{
int sizeof_buf = (strlen(name)
+ strlen("@")
+ strlen_unsigned_word
+ strlen(",")
+ strlen_unsigned
+ strlen(",")
+ strlen_unsigned
+ strlen(",")
+ c_strlen(c4)
+ 1);
char *buf = (char*)zalloc(sizeof_buf);
strcpy(buf, name);
strcat(buf, "@");
u_strcat(buf, uw1);
strcat(buf, ",");
u_strcat(buf, u2);
strcat(buf, ",");
u_strcat(buf, u3);
strcat(buf, ",");
c_strcat(buf, c4);
ASSERT(strlen(buf) < sizeof_buf);
return buf;
}
#endif /* _DEVICE_TREE_C_ */

View File

@ -1,207 +0,0 @@
/* 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 _DEVICE_TREE_H_
#define _DEVICE_TREE_H_
#ifndef INLINE_DEVICE_TREE
#define INLINE_DEVICE_TREE
#endif
#include "devices.h"
typedef struct _device_tree device_tree;
/* extend the device tree, each function returns the address of the
new node */
INLINE_DEVICE_TREE device_tree *device_tree_add_passthrough
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE device_tree *device_tree_add_device
(device_tree *root,
const char *path,
const device *dev);
INLINE_DEVICE_TREE device_tree *device_tree_add_integer
(device_tree *root,
const char *path,
signed_word integer);
INLINE_DEVICE_TREE device_tree *device_tree_add_string
(device_tree *root,
const char *path,
const char *string);
INLINE_DEVICE_TREE device_tree *device_tree_add_boolean
(device_tree *root,
const char *path,
int bool);
INLINE_DEVICE_TREE device_tree *device_tree_add_found_device
(device_tree *root,
const char *path);
/* query the device tree */
INLINE_DEVICE_TREE const device *device_tree_find_device
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE signed_word device_tree_find_integer
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE const char *device_tree_find_string
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE int device_tree_find_boolean
(device_tree *root,
const char *path);
/* initialize the entire tree */
INLINE_DEVICE_TREE void device_tree_init
(device_tree *root,
psim *system);
/* traverse the tree eiter pre or post fix */
typedef void (device_tree_traverse_function)
(device_tree *device,
void *data);
INLINE_DEVICE_TREE void device_tree_traverse
(device_tree *root,
device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix,
void *data);
/* dump a node, this can be passed to the device_tree_traverse()
function to dump out the entire device tree */
INLINE_DEVICE_TREE void device_tree_dump
(device_tree *device,
void *ignore_data_argument);
/* Parse a device name, various formats:
uw: unsigned_word
u: unsigned
c: string */
INLINE_DEVICE_TREE int scand_c
(const char *name,
char *c1,
unsigned c1size);
INLINE_DEVICE_TREE int scand_c_uw_u
(const char *name,
char *c1,
unsigned c1size,
unsigned_word *uw2,
unsigned *u3);
INLINE_DEVICE_TREE int scand_uw
(const char *name,
unsigned_word *uw1);
INLINE_DEVICE_TREE int scand_uw_c
(const char *name,
unsigned_word *uw1,
char *c2,
unsigned c2size);
INLINE_DEVICE_TREE int scand_uw_u
(const char *name,
unsigned_word *uw1,
unsigned *u2);
INLINE_DEVICE_TREE int scand_uw_u_u
(const char *name,
unsigned_word *uw1,
unsigned *u2,
unsigned *u3);
INLINE_DEVICE_TREE int scand_uw_uw
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2);
INLINE_DEVICE_TREE int scand_uw_uw_u
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3);
INLINE_DEVICE_TREE int scand_uw_uw_u_u_c
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3,
unsigned *u4,
char *c5,
unsigned c5size);
INLINE_DEVICE_TREE int scand_uw_uw_u_u_u
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3,
unsigned *u4,
unsigned *u5);
INLINE_DEVICE_TREE char *printd_c
(const char *name,
const char *c1);
INLINE_DEVICE_TREE char *printd_c_uw
(const char *name,
const char *c1,
unsigned_word uw2);
INLINE_DEVICE_TREE char *printd_uw_u
(const char *name,
unsigned_word uw1,
unsigned u2);
INLINE_DEVICE_TREE char *printd_uw_u_u
(const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3);
INLINE_DEVICE_TREE char *printd_uw_u_u_c
(const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3,
const char *c4);
#endif /* _DEVICE_TREE_H_ */

View File

@ -1,380 +0,0 @@
/* 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 _DEVICES_H_
#define _DEVICES_H_
#ifndef INLINE_DEVICES
#define INLINE_DEVICES
#endif
#ifndef STATIC_DEVICES
#define STATIC_DEVICES
#endif
/* forward declaration of types */
/* typedef struct _device device; -- in devices.h */
/* Address access attributes that can be attached to a devices address
range */
typedef enum _access_type {
access_invalid = 0,
access_read = 1,
access_write = 2,
access_read_write = 3,
access_exec = 4,
access_read_exec = 5,
access_write_exec = 6,
access_read_write_exec = 7,
} access_type;
/* Address attachement types */
typedef enum _attach_type {
attach_invalid,
attach_callback,
attach_default,
attach_raw_memory,
} attach_type;
/* Operators on devices: */
/* Initialization:
A device is made fully functional in two stages.
1. It is created. A device is created _before_ it is entered into
the device tree. During creation any permenant structures needed
by the device should be created/initialized.
2. It is initialized. Before a simulation run, each device in the
device tree is initialized in prefix order. As part of this
initialization, a device should (re)attach its self to its parent
as needed.
*/
typedef void (device_init_callback)
(const device *me,
psim *system);
#define DTRACE_INIT(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_init(me=0x%lx:%s system=0x%lx)\n", \
(long)me, me->full_name, (long)system))
/* Data transfers:
A device may permit the reading/writing (IO) of its registers in
one or more address spaces. For instance, a PCI device may have
config registers in its config space and control registers in both
the io and memory spaces of a PCI bus.
Similarly, a device may initiate a data transfer (DMA) by passing
such a request up to its parent.
Init:
As part of its initialization (not creation) and possibly also as a
consequence of IO a device may attach its self to one or more of
the address spaces of its parent device.
For instance, a PCI device, during initialization would attach its
config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
bridge. Later, due to a write to this config space, the same
device may in turn find it necessary to also attach its self to
it's parent's `memory' or `io' space.
To perform these operations, a device will call upon its parent
using either device_attach_address or device_detach_address.
* Any address specified is according to what the device expects to
see.
* Any detach operation must exactly match a previous attach.
* included with the attach or detach is the devices name, the
parent may use this as part of determining how to map map between a
child's address + space and its own.
* at any time, at most one device can have a default mapping
registered.
IO:
A device receives requests to perform reads/writes to its registers
or memory either A. from a processor or B. from a parent device.
The device may then in turn either A. resolve the IO request
locally by processing the data or trigering an exception or
B. re-mapping the access onto one of its local address spaces and
then in turn passing that on to one of its children.
* Any address passed is relative to the local device. Eg for PCI
config registers, the address would (normally) be in the range of 0
to 63.
* Any exception situtation triggered by an IO operation (processor
!= NULL) is handled in one of the following ways: 1. Machine check
(and similar): issued immediatly by restarting the cpu; 2. External
exception: issue delayed (using events.h) until the current
instruction execution cycle is completed; 3. Slave device (and
similar): the need for the interrupt is passed on to the devices
parent (which being an interrupt control unit will in turn take one
of the actions described here); 4. Forget it.
* Any exception situtation trigered by a non IO operation
(processor == NULL) is handled buy returning 0.
* Transfers of size <= 8 and of a power of 2 *must* be correctly
aligned and should be treated as a `single cycle' transfer.
DMA:
A device initiates a DMA transfer by calling its parent with the
request. At the top level (if not done earlier) this is reflected
back down the tree as io read/writes to the target device.
This function is subject to change ...
*/
typedef void (device_config_address_callback)
(const device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
const device *who); /*callback/default*/
#define DTRACE_ATTACH_ADDRESS(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_attach_address(me=0x%lx:%s, name=%s, attach=%ld, space=%ld, addr=0x%lx, nr_bytes=%ld, access=%ld, who=0x%lx)\n", \
(long)me, me->full_name, name, (long)attach, (long)space, \
(long)addr, (long)nr_bytes, (long)access, (long)who))
#define DTRACE_DETACH_ADDRESS(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_detach_address(me=0x%lx:%s, name=%s, attach=%ld, space=%ld, addr=0x%lx, nr_bytes=%ld, access=%ld, who=0x%lx)\n", \
(long)me, me->full_name, name, (long)attach, (long)space, \
(long)addr, (long)nr_bytes, (long)access, (long)who))
typedef unsigned (device_io_read_buffer_callback)
(const device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
typedef unsigned (device_io_write_buffer_callback)
(const device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
#define DTRACE_IO_READ_BUFFER(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_io_read_buffer(me=0x%lx:%s dest=0x%lx space=%ld addr=0x%lx nr_bytes=%ld processor=0x%lx cia=0x%lx)\n", \
(long)me, me->full_name, (long)dest, (long)space, (long)addr, \
(long)nr_bytes, (long)processor, (long)cia))
#define DTRACE_IO_WRITE_BUFFER(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_io_write_buffer(me=0x%lx:%s source=0x%lx space=%ld addr=0x%lx nr_bytes=%ld processor=0x%lx cia=0x%lx)\n", \
(long)me, me->full_name, (long)source, (long)space, (long)addr, \
(long)nr_bytes, (long)processor, (long)cia))
typedef unsigned (device_dma_read_buffer_callback)
(const device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes);
typedef unsigned (device_dma_write_buffer_callback)
(const device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section);
#define DTRACE_DMA_READ_BUFFER(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_dma_read_buffer(me=0x%lx:%s dest=0x%lx space=%ld addr=0x%lx nr_bytes=%ld)\n", \
(long)me, me->full_name, (long)dest, (long)space, (long)addr, (long)nr_bytes))
#define DTRACE_DMA_WRITE_BUFFER(OBJECT) \
DTRACE(OBJECT, \
(#OBJECT "_dma_write_buffer(me=0x%lx:%s source=0x%lx space=%ld addr=0x%lx nr_bytes=%ld)\n", \
(long)me, me->full_name, (long)source, (long)space, (long)addr, (long)nr_bytes))
/* Interrupts:
As mentioned above. Instead of handling an interrupt directly, a
device may instead pass the need to interrupt on to its parent.
Init:
Before passing interrupts up to is parent, a device must first
attach its interrupt lines to the parent device. To do this, the
device uses the parents attach/detach calls.
Interrupts:
A child notifies a parent of a change in an interrupt lines status
using the interrupt call. Similarly, a parent may notify a child
of any `interrupt ack' sequence using the interrupt_ack call.
*/
typedef void (device_config_interrupt_callback)
(const device *me,
const device *who,
int interrupt_line,
const char *name);
typedef void (device_interrupt_ack_callback)
(const device *me,
int interrupt_line,
int interrupt_status);
typedef void (device_interrupt_callback)
(const device *me,
const device *who,
int interrupt_line,
int interrupt_status,
cpu *processor,
unsigned_word cia);
/* IOCTL:
Very simply, a catch all for any thing that turns up that until now
either hasn't been thought of or doesn't justify an extra function. */
typedef void (device_ioctl_callback)
(const device *me,
psim *system,
cpu *processor,
unsigned_word cia,
...);
/* the callbacks */
typedef struct _device_callbacks {
/* initialization */
device_init_callback *init;
/* address/data config - from child */
device_config_address_callback *attach_address;
device_config_address_callback *detach_address;
/* address/data transfer - to child */
device_io_read_buffer_callback *io_read_buffer;
device_io_write_buffer_callback *io_write_buffer;
/* address/data transfer - from child */
device_dma_read_buffer_callback *dma_read_buffer;
device_dma_write_buffer_callback *dma_write_buffer;
/* interrupt config - from child */
device_config_interrupt_callback *attach_interrupt;
device_config_interrupt_callback *detach_interrupt;
/* interrupt transfer - from child */
device_interrupt_callback *interrupt;
/* interrupt transfer - to child */
device_interrupt_ack_callback *interrupt_ack;
/* back door to anything we've forgot */
device_ioctl_callback *ioctl;
} device_callbacks;
/* A device */
struct _device {
const char *name; /* eg rom@0x1234,0x400 */
const char *full_name; /* eg /isa/rom@0x1234,0x400 */
void *data; /* device specific data */
const device_callbacks *callback;
const device *parent;
};
/* Create a new device, finding it in the builtin device table */
INLINE_DEVICES const device *device_create
(const char *name,
const char *full_name,
const device *parent);
/* create a new device using the parameterized data */
INLINE_DEVICES const device *device_create_from
(const char *name,
const char *full_name,
void *data,
const device_callbacks *callback,
const device *parent);
/* Unimplemented call back functions. These abort the simulation */
INLINE_DEVICES device_init_callback unimp_device_init;
INLINE_DEVICES device_config_address_callback unimp_device_attach_address;
INLINE_DEVICES device_config_address_callback unimp_device_detach_address;
INLINE_DEVICES device_io_read_buffer_callback unimp_device_io_read_buffer;
INLINE_DEVICES device_io_write_buffer_callback unimp_device_io_write_buffer;
INLINE_DEVICES device_dma_read_buffer_callback unimp_device_dma_read_buffer;
INLINE_DEVICES device_dma_write_buffer_callback unimp_device_dma_write_buffer;
INLINE_DEVICES device_config_interrupt_callback unimp_device_attach_interrupt;
INLINE_DEVICES device_config_interrupt_callback unimp_device_detach_interrupt;
INLINE_DEVICES device_interrupt_callback unimp_device_interrupt;
INLINE_DEVICES device_interrupt_ack_callback unimp_device_interrupt_ack;
STATIC_DEVICES device_ioctl_callback unimp_device_ioctl;
/* Pass through and ignore callback functions. A call going towards
the root device are passed on up, local calls are ignored and call
downs abort */
INLINE_DEVICES device_init_callback ignore_device_init;
INLINE_DEVICES device_config_address_callback pass_device_attach_address;
INLINE_DEVICES device_config_address_callback pass_device_detach_address;
INLINE_DEVICES device_dma_read_buffer_callback pass_device_dma_read_buffer;
INLINE_DEVICES device_dma_write_buffer_callback pass_device_dma_write_buffer;
INLINE_DEVICES device_config_interrupt_callback pass_device_attach_interrupt;
INLINE_DEVICES device_config_interrupt_callback pass_device_detach_interrupt;
INLINE_DEVICES device_interrupt_callback pass_device_interrupt;
INLINE_DEVICES const device_callbacks *passthrough_device_callbacks
(void);
#endif /* _DEVICES_H_ */

156
sim/ppc/emul_bugapi.c Normal file
View File

@ -0,0 +1,156 @@
/* 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 _EMUL_BUGAPI_C_
#define _EMUL_BUGAPI_C_
/* Note: this module is called via a table. There is no benefit in
making it inline */
#include "emul_generic.h"
#include "emul_bugapi.h"
/* Any starting address less than this is assumed to be an OEA program
rather than VEA. */
#ifndef OEA_START_ADDRESS
#define OEA_START_ADDRESS 4096
#endif
#ifndef OEA_MEMORY_SIZE
#define OEA_MEMORY_SIZE 0x100000
#endif
static os_emul_data *
emul_bugapi_create(device *root,
bfd *image,
const char *name)
{
/* check it really is for us */
if (name != NULL
&& strcmp(name, "bugapi") != 0)
return NULL;
if (image != NULL
&& bfd_get_start_address(image) > OEA_START_ADDRESS)
return NULL;
{
const memory_size = OEA_MEMORY_SIZE;
const elf_binary = (image != NULL
&& image->xvec->flavour == bfd_target_elf_flavour);
const little_endian = (image != NULL
&& !image->xvec->byteorder_big_p);
{ /* options */
device *options = device_tree_add_found(root, "/", "options");
device_add_integer_property(options,
"smp",
MAX_NR_PROCESSORS);
device_add_boolean_property(options,
"little-endian?",
little_endian);
device_add_string_property(options,
"env",
"operating");
device_add_boolean_property(options,
"strict-alignment?",
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|| !image->xvec->byteorder_big_p));
device_add_boolean_property(options,
"floating-point?",
WITH_FLOATING_POINT);
device_add_string_property(options,
"os-emul",
"bugapi");
}
/* hardware */
device_tree_add_found_uw_u_u(root, "/", "memory",
0, memory_size, access_read_write_exec);
device_tree_add_found(root, "/", "iobus@0x400000");
device_tree_add_found(root, "/iobus", "console@0x000000,16");
device_tree_add_found(root, "/iobus", "halt@0x100000,4");
device_tree_add_found(root, "/iobus", "icu@0x200000,4");
{ /* initialization */
device *init = device_tree_add_found(root, "/", "init");
{
device *init_register = device_tree_add_found(init, "", "register");
device_add_integer_property(init_register,
"pc",
0);
device_add_integer_property(init_register,
"sp",
memory_size-16);
device_add_integer_property(init_register,
"msr",
(little_endian
? msr_little_endian_mode
: 0));
}
{
device *init_stack = device_tree_add_found(init, "", "stack");
device_add_null_property(init_stack,
(elf_binary
? "elf"
: "aix"));
}
{
device *init_load_binary = device_tree_add_found(init, "",
"load-binary");
device_add_null_property(init_load_binary,
bfd_get_filename(image));
}
}
}
return (os_emul_data*)-1;
}
static void
emul_bugapi_init(os_emul_data *emul_data,
int nr_cpus)
{
/* nothing happens here */
}
static int
emul_bugapi_instruction_call(cpu *processor,
unsigned_word cia,
unsigned_word ra,
os_emul_data *emul_data)
{
error("emul_bugapi_instruction_call() not implemented\n");
return 1;
}
const os_emul emul_bugapi = {
"bugapi",
emul_bugapi_create,
emul_bugapi_init,
0, /*system_call*/
emul_bugapi_instruction_call,
0 /*data*/
};
#endif

27
sim/ppc/emul_bugapi.h Normal file
View File

@ -0,0 +1,27 @@
/* 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 _EMUL_BUGAPI_H_
#define _EMUL_BUGAPI_H_
extern const os_emul emul_bugapi;
#endif

530
sim/ppc/emul_chirp.c Normal file
View File

@ -0,0 +1,530 @@
/* 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 _EMUL_CHIRP_C_
#define _EMUL_CHIRP_C_
/* Note: this module is called via a table. There is no benefit in
making it inline */
#include "emul_generic.h"
#include "emul_chirp.h"
#include "cap.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include <unistd.h>
#ifndef STATIC_INLINE_EMUL_CHIRP
#define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE
#endif
/* Descriptor of the open boot services being emulated */
typedef unsigned_word (chirp_handler)
(os_emul_data *data,
cpu *processor,
unsigned_word cia);
typedef struct _chirp_services {
const char *name;
chirp_handler *handler;
} chirp_services;
/* The OpenBoot emulation is, at any time either waiting for a client
request or waiting on a client callback */
typedef enum {
serving,
catching,
} chirp_emul_state;
struct _os_emul_data {
chirp_emul_state state;
unsigned_word return_address;
unsigned_word arguments;
chirp_services *service;
unsigned_word serving_instruction_ea;
unsigned_word catching_instruction_ea;
cap *phandles;
device *root;
};
/* OpenBoot emulation functions */
static unsigned_word
chirp_emul_finddevice(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
struct finddevice_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
unsigned32 device_specifier;
/*out*/
unsigned32 phandle;
} args;
char device_specifier[1024];
device *dev;
emul_read_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
if (T2H_4(args.n_args) != 1 || T2H_4(args.n_returns) != 1)
return -1;
emul_read_string(device_specifier,
T2H_4(args.device_specifier),
sizeof(device_specifier),
processor, cia);
dev = device_tree_find_device(data->root,
device_specifier);
if (dev == (device*)0)
args.phandle = -1;
else
args.phandle = cap_external(data->phandles, dev);
emul_write_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
return 0;
}
static unsigned_word
chirp_emul_getprop(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
struct getprop_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
unsigned32 phandle;
unsigned32 name;
unsigned32 buf;
unsigned32 buflen;
/*out*/
unsigned32 size;
} args;
char name[32];
device *dev;
const device_property *prop;
emul_read_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
if (T2H_4(args.n_args) != 4 || T2H_4(args.n_returns) != 1)
return -1;
/* read in the arguments */
dev = cap_internal(data->phandles, args.phandle);
if (dev == (device*)0)
return -1;
emul_read_string(name,
T2H_4(args.name),
sizeof(name),
processor, cia);
prop = device_find_property(dev, name);
if (prop == (device_property*)0) {
args.size = -1;
}
else {
int size = T2H_4(args.buflen);
if (size > prop->sizeof_array)
size = prop->sizeof_array;
emul_write_buffer(prop->array, T2H_4(args.buf),
size,
processor, cia);
args.size = H2T_4(size);
}
emul_write_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
return 0;
}
static unsigned_word
chirp_emul_write(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
struct write_args {
unsigned32 service;
unsigned32 n_args;
unsigned32 n_returns;
/*in*/
unsigned32 ihandle;
unsigned32 addr;
unsigned32 len;
/*out*/
unsigned32 actual;
} args;
char buf[1024];
int actual;
emul_read_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
if (T2H_4(args.n_args) != 3 || T2H_4(args.n_returns) != 1)
return -1;
/* read in the arguments */
actual = T2H_4(args.len);
if (actual > sizeof(buf))
actual = sizeof(buf);
emul_read_buffer(buf,
T2H_4(args.addr),
actual,
processor, cia);
/* write it out */
write(BE2H_4(args.ihandle), buf, actual);
args.actual = H2T_4(actual);
emul_write_buffer(&args, data->arguments,
sizeof(args),
processor, cia);
return 0;
}
static unsigned_word
chirp_emul_exit(os_emul_data *data,
cpu *processor,
unsigned_word cia)
{
error("chirp_emul_exit not implemnented\n");
return 0;
}
chirp_services services[] = {
{ "finddevice", chirp_emul_finddevice },
{ "getprop", chirp_emul_getprop },
{ "write", chirp_emul_write },
{ "exit", chirp_emul_exit },
{ 0, /* sentinal */ },
};
/* main handlers */
/* Any starting address greater than this is assumed to be an Chirp
rather than VEA */
#ifndef CHIRP_START_ADDRESS
#define CHIRP_START_ADDRESS 0x80000000
#endif
typedef struct _chirp_note_desc {
signed32 real_mode;
signed32 real_base;
signed32 real_size;
signed32 virt_base;
signed32 virt_size;
} chirp_note_desc;
typedef struct _chirp_note {
chirp_note_desc desc;
int found;
} chirp_note;
typedef struct _chirp_note_head {
unsigned32 namesz;
unsigned32 descsz;
unsigned32 type;
} chirp_note_head;
static void
map_over_chirp_note(bfd *image,
asection *sect,
PTR obj)
{
chirp_note *note = (chirp_note*)obj;
if (strcmp(sect->name, ".note") == 0) {
chirp_note_head head;
char name[16];
/* check the head */
if (!bfd_get_section_contents(image, sect,
&head, 0, sizeof(head)))
return;
head.namesz = bfd_get_32(image, (void*)&head.namesz);
head.descsz = bfd_get_32(image, (void*)&head.descsz);
head.type = bfd_get_32(image, (void*)&head.type);
if (head.type != 0x1275)
return;
note->found = 1;
/* check the name field */
if (head.namesz > sizeof(name))
return;
if (!bfd_get_section_contents(image, sect,
name, sizeof(head), head.namesz))
return;
if (strcmp(name, "PowerPC") != 0)
return;
/* get the contents */
if (!bfd_get_section_contents(image, sect,
&note->desc, sizeof(head) + head.namesz,
head.descsz))
return;
note->desc.real_mode = bfd_get_32(image, (void*)&note->desc.real_mode);
note->desc.real_base = bfd_get_32(image, (void*)&note->desc.real_base);
note->desc.real_size = bfd_get_32(image, (void*)&note->desc.real_size);
note->desc.virt_base = bfd_get_32(image, (void*)&note->desc.virt_base);
note->desc.virt_size = bfd_get_32(image, (void*)&note->desc.virt_size);
note->found = 2;
}
}
static os_emul_data *
emul_chirp_create(device *root,
bfd *image,
const char *name)
{
os_emul_data *data;
chirp_note note;
/* Sanity check that this really is the chosen emulation */
if (name == NULL && image == NULL)
return NULL;
if (name != NULL
&& strcmp(name, "ob") != 0
&& strcmp(name, "ieee1274") != 0
&& strcmp(name, "chrp") != 0
&& strcmp(name, "chirp") != 0
&& strcmp(name, "openboot") != 0)
return NULL;
/* look for an elf note section */
memset(&note, 0, sizeof(note));
if (image != NULL)
bfd_map_over_sections(image, map_over_chirp_note, &note);
if (name == NULL && image != NULL && !note.found)
return NULL;
{
const unsigned_word memory_size = 0x200000;
/* the hash table */
const unsigned nr_page_table_entry_groups = (memory_size < 0x800000
? 1024 /* min allowed */
: (memory_size / 4096 / 2));
const unsigned sizeof_htab = nr_page_table_entry_groups * 64;
const unsigned_word htab_ra = memory_size - sizeof_htab;
/* a page for firmware calls */
const unsigned_word sizeof_code = 4096;
const unsigned_word code_ra = htab_ra - sizeof_code;
/* the stack */
const unsigned sizeof_stack = 32 * 1024;
const unsigned_word stack_ra = code_ra - sizeof_stack;
/* the firmware's home */
const int real_mode = 0;
/* const unsigned_word real_base = stack_ra; */
/* const unsigned real_size = memory_size - real_base; */
const unsigned_word virt_base = CHIRP_START_ADDRESS;
/* const unsigned virt_size = real_size;*/
/* the virtual addresses */
const unsigned_word stack_va = virt_base;
const unsigned_word code_va = stack_va + sizeof_stack;
const unsigned_word htab_va = code_va + sizeof_code;
/* options */
{
device *options = device_tree_add_found(root, "/", "options");
device_add_integer_property(options,
"smp",
MAX_NR_PROCESSORS);
device_add_boolean_property(options,
"little-endian?",
!image->xvec->byteorder_big_p);
device_add_string_property(options,
"env",
"operating");
device_add_boolean_property(options,
"strict-alignment?",
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|| !image->xvec->byteorder_big_p));
device_add_boolean_property(options,
"floating-point?",
WITH_FLOATING_POINT);
device_add_string_property(options,
"os-emul",
"chirp");
}
/* hardware */
device_tree_add_found_uw_u_u(root, "/", "memory",
0, memory_size, access_read_write_exec);
/* initialization */
{
device *init = device_tree_add_found(root, "/", "init");
{
device *init_register = device_tree_add_found(init, "", "register");
device_add_integer_property(init_register,
"pc",
bfd_get_start_address(image));
device_add_integer_property(init_register,
"sp",
stack_va + sizeof_stack - 16);
/* init the code callback */
device_add_integer_property(init_register,
"r5",
code_va);
device_tree_add_found_uw_u_u(init, "", "data", code_ra, 4, 0x1);
device_tree_add_found_uw_u_u(init, "", "data", code_ra+16, 4, 0x1);
device_add_integer_property(init_register,
"msr",
(msr_machine_check_enable
| (real_mode
? 0
: (msr_instruction_relocate
| msr_data_relocate))
| (image->xvec->byteorder_big_p
? 0
: (msr_little_endian_mode
| msr_interrupt_little_endian_mode
))));
device_add_integer_property(init_register,
"sdr1",
(htab_ra
| MASK32(16, 22)
| ((sizeof_htab - 1) >> 16)));
/* FIXME */
device_add_integer_property(init_register,
"sr8",
0x00fffff8);
device_add_integer_property(init_register,
"sr9",
0x00fffff9);
{ /* hash table and vm */
device *htab_root = device_tree_add_found_uw_u(init, "", "htab",
htab_ra, sizeof_htab);
device_tree_add_found_uw_uw_u_u_u(htab_root, "", "pte",
stack_ra, stack_va, sizeof_stack,
0x7/*wimg*/, 0x2/*pp*/);
device_tree_add_found_uw_uw_u_u_u(htab_root, "", "pte",
code_ra, code_va, sizeof_code,
0x7/*wimg*/, 0x2/*pp*/);
device_tree_add_found_uw_uw_u_u_u(htab_root, "", "pte",
htab_ra, htab_va, sizeof_htab,
0x7/*wimg*/, 0x2/*pp*/);
device_tree_add_found_uw_u_u_c(htab_root, "", "pte",
0x4000, /*magic*/
0x7/*wimg*/, 0x2/*pp*/,
bfd_get_filename (image));
}
}
}
{ /* chosen options */
device *chosen = device_tree_add_found(root, "/", "chosen");
device_add_integer_property(chosen,
"stdout",
1);
}
/* FIXME - should come from the device tree */
data = ZALLOC(os_emul_data);
data->serving_instruction_ea = CHIRP_START_ADDRESS + sizeof_stack;;
data->catching_instruction_ea = CHIRP_START_ADDRESS + sizeof_stack + 16;
data->phandles = cap_create("chirp");
data->root = root;
return data;
}
}
static void
emul_chirp_init(os_emul_data *emul_data,
int nr_cpus)
{
emul_data->state = serving;
cap_init(emul_data->phandles);
}
static int
emul_chirp_instruction_call(cpu *processor,
unsigned_word cia,
unsigned_word ra,
os_emul_data *emul_data)
{
unsigned_word service_name_addr;
unsigned_word result;
char service_buf[32];
char *service_name;
chirp_services *service;
switch (emul_data->state) {
case serving:
/* verify then capture the current request */
if (cia != emul_data->serving_instruction_ea)
return 0;
emul_data->return_address = LR;
emul_data->arguments = cpu_registers(processor)->gpr[3];
/* try to determine what to do */
service_name_addr = emul_read_word(cpu_registers(processor)->gpr[3],
processor, cia);
service_name = emul_read_string(service_buf, service_name_addr,
sizeof(service_buf), processor, cia);
/* look it up */
service = services;
while (service->name != NULL && strcmp(service->name, service_name) != 0)
service++;
if (service->name == NULL) {
cpu_registers(processor)->gpr[3] = 0;
cpu_restart(processor, emul_data->return_address);
}
emul_data->service = service;
TRACE(trace_os_emul, ("%s called from 0x%lx\n",
service->name, emul_data->return_address));
/* call upon it */
result = service->handler(emul_data, processor, cia);
break;
default:
error("emul_chirp_instruction_call() unknown internal state\n");
result = -1;
break;
}
/* return to caller */
cpu_registers(processor)->gpr[3] = result;
cpu_restart(processor, emul_data->return_address);
return 1;
}
const os_emul emul_chirp = {
"chirp",
emul_chirp_create,
emul_chirp_init,
NULL, /*system_call*/
emul_chirp_instruction_call,
0 /*data*/
};
#endif

27
sim/ppc/emul_chirp.h Normal file
View File

@ -0,0 +1,27 @@
/* 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 _EMUL_CHIRP_H_
#define _EMUL_CHIRP_H_
extern const os_emul emul_chirp;
#endif

View File

@ -22,7 +22,12 @@
#ifndef _EMUL_NETBSD_C_
#define _EMUL_NETBSD_C_
/* Note: this module is called via a table. There is no benefit in
making it inline */
#include "emul_generic.h"
#include "emul_netbsd.h"
#ifdef HAVE_STRING_H
#include <string.h>
@ -41,6 +46,8 @@
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
int getrusage();
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/dirent.h>
@ -82,6 +89,14 @@ extern int errno;
#endif
/* NetBSD's idea of what is needed to implement emulations */
struct _os_emul_data {
emul_syscall *syscalls;
};
STATIC_INLINE_EMUL_NETBSD void
write_stat(unsigned_word addr,
struct stat buf,
@ -177,7 +192,7 @@ write_direntries(unsigned_word addr,
struct dirent *in = (struct dirent*)buf;
ASSERT(in->d_reclen <= nbytes);
out = (struct dirent*)zalloc(in->d_reclen);
bcopy(in, out, in->d_reclen);
memcpy(out/*dest*/, in/*src*/, in->d_reclen);
H2T(out->d_fileno);
H2T(out->d_reclen);
H2T(out->d_type);
@ -220,8 +235,8 @@ write_rusage(unsigned_word addr,
}
STATIC_INLINE_EMUL_NETBSD void
do_exit(emulation *emul,
static void
do_exit(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -236,8 +251,8 @@ do_exit(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_read(emulation *emul,
static void
do_read(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -282,8 +297,8 @@ do_read(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_write(emulation *emul,
static void
do_write(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -321,8 +336,8 @@ do_write(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_open(emulation *emul,
static void
do_open(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -342,8 +357,8 @@ do_open(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_close(emulation *emul,
static void
do_close(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -359,8 +374,8 @@ do_close(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_break(emulation *emul,
static void
do_break(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -368,23 +383,23 @@ do_break(emulation *emul,
/* just pass this onto the `vm' device */
{
psim *system = cpu_system(processor);
const device *vm = psim_device(system, "/vm");
device *vm = psim_device(system, "/vm");
if (WITH_TRACE && ppc_trace[trace_os_emul])
printf_filtered ("0x%lx", (long)cpu_registers(processor)->gpr[arg0]);
SYS(break);
vm->callback->ioctl(vm,
system,
processor,
cia,
0, /*ioctl*/
NULL); /*ioctl-data*/
device_ioctl(vm,
system,
processor,
cia,
0, /*ioctl*/
NULL); /*ioctl-data*/
}
STATIC_INLINE_EMUL_NETBSD void
do_getpid(emulation *emul,
static void
do_getpid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -395,8 +410,8 @@ do_getpid(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_getuid(emulation *emul,
static void
do_getuid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -407,8 +422,8 @@ do_getuid(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_geteuid(emulation *emul,
static void
do_geteuid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -419,8 +434,8 @@ do_geteuid(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_kill(emulation *emul,
static void
do_kill(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -433,14 +448,14 @@ do_kill(emulation *emul,
printf_filtered ("%d, %d", (int)pid, sig);
SYS(kill);
printf_filtered("SYS_kill at 0x%x - more to this than just being killed\n",
cia);
printf_filtered("SYS_kill at 0x%lx - more to this than just being killed\n",
(long)cia);
cpu_halt(processor, cia, was_signalled, sig);
}
STATIC_INLINE_EMUL_NETBSD void
do_dup(emulation *emul,
static void
do_dup(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -457,8 +472,8 @@ do_dup(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_getegid(emulation *emul,
static void
do_getegid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -469,8 +484,8 @@ do_getegid(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_getgid(emulation *emul,
static void
do_getgid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -481,8 +496,8 @@ do_getgid(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_sigprocmask(emulation *emul,
static void
do_sigprocmask(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -501,8 +516,8 @@ do_sigprocmask(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_ioctl(emulation *emul,
static void
do_ioctl(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -515,11 +530,7 @@ do_ioctl(emulation *emul,
#if !WITH_NetBSD_HOST
cpu_registers(processor)->gpr[arg0] = 0; /* just succeed */
#else
unsigned param_len = IOCPARM_LEN(request);
unsigned basecmd = IOCBASECMD(request);
unsigned group = IOCGROUP(request);
unsigned dir = request & IOC_DIRMASK;
char *argp = NULL;
int status;
SYS(ioctl);
/* what we haven't done */
@ -536,8 +547,8 @@ do_ioctl(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_umask(emulation *emul,
static void
do_umask(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -553,8 +564,8 @@ do_umask(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_dup2(emulation *emul,
static void
do_dup2(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -572,8 +583,8 @@ do_dup2(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_fcntl(emulation *emul,
static void
do_fcntl(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -593,8 +604,8 @@ do_fcntl(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_gettimeofday(emulation *emul,
static void
do_gettimeofday(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -621,8 +632,8 @@ do_gettimeofday(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_getrusage(emulation *emul,
static void
do_getrusage(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -648,8 +659,8 @@ do_getrusage(emulation *emul,
#if !WITH_NetBSD_HOST
#define do_fstatfs 0
#else
STATIC_INLINE_EMUL_NETBSD void
do_fstatfs(emulation *emul,
static void
do_fstatfs(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -674,8 +685,8 @@ do_fstatfs(emulation *emul,
#endif
STATIC_INLINE_EMUL_NETBSD void
do_stat(emulation *emul,
static void
do_stat(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -695,8 +706,8 @@ do_stat(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_fstat(emulation *emul,
static void
do_fstat(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -711,8 +722,8 @@ do_fstat(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do_lstat(emulation *emul,
static void
do_lstat(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -732,8 +743,8 @@ do_lstat(emulation *emul,
#if !WITH_NetBSD_HOST
#define do_getdirentries 0
#else
STATIC_INLINE_EMUL_NETBSD void
do_getdirentries(emulation *emul,
static void
do_getdirentries(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -766,24 +777,25 @@ do_getdirentries(emulation *emul,
#endif
STATIC_INLINE_EMUL_NETBSD void
do___syscall(emulation *emul,
static void
do___syscall(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
unsigned_word cia)
{
SYS(__syscall);
emul_do_call(emul,
cpu_registers(processor)->gpr[arg0],
arg0 + 1,
processor,
cia);
emul_do_system_call(emul,
emul->syscalls,
cpu_registers(processor)->gpr[arg0],
arg0 + 1,
processor,
cia);
}
STATIC_INLINE_EMUL_NETBSD void
do_lseek(emulation *emul,
static void
do_lseek(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -803,8 +815,8 @@ do_lseek(emulation *emul,
}
STATIC_INLINE_EMUL_NETBSD void
do___sysctl(emulation *emul,
static void
do___sysctl(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
@ -830,7 +842,7 @@ do___sysctl(emulation *emul,
name += sizeof(mib);
/* see what to do with it ... */
switch (mib) {
switch ((int)mib) {
case 6/*CTL_HW*/:
#if WITH_NetBSD_HOST && (CTL_HW != 6)
# error "CTL_HW"
@ -842,7 +854,7 @@ do___sysctl(emulation *emul,
processor,
cia);
name += sizeof(mib);
switch (mib) {
switch ((int)mib) {
case 7/*HW_PAGESIZE*/:
#if WITH_NetBSD_HOST && (HW_PAGESIZE != 7)
# error "HW_PAGESIZE"
@ -864,7 +876,7 @@ do___sysctl(emulation *emul,
}
break;
default:
error("sysctl() name[0]=%s unknown\n", (int)mib);
error("sysctl() name[0]=%d unknown\n", (int)mib);
break;
}
cpu_registers(processor)->gpr[3] = 0;
@ -872,179 +884,179 @@ do___sysctl(emulation *emul,
static emul_call_descriptor netbsd_descriptors[] = {
/* 0 */ { 0, "syscall", { 0, }, 0 },
/* 1 */ { do_exit, "exit", { 0, }, 0 },
/* 2 */ { 0, "fork", { 0, }, 0 },
/* 3 */ { do_read, "read", { 0, }, 0 },
/* 4 */ { do_write, "write", { 0, }, 0 },
/* 5 */ { do_open, "open", { 0, }, 0 },
/* 6 */ { do_close, "close", { 0, }, 0 },
/* 7 */ { 0, "wait4", { 0, }, 0 },
static emul_syscall_descriptor netbsd_descriptors[] = {
/* 0 */ { 0, "syscall" },
/* 1 */ { do_exit, "exit" },
/* 2 */ { 0, "fork" },
/* 3 */ { do_read, "read" },
/* 4 */ { do_write, "write" },
/* 5 */ { do_open, "open" },
/* 6 */ { do_close, "close" },
/* 7 */ { 0, "wait4" },
{ 0, }, /* 8 is old creat */
/* 9 */ { 0, "link", { 0, }, 0 },
/* 10 */ { 0, "unlink", { 0, }, 0 },
/* 9 */ { 0, "link" },
/* 10 */ { 0, "unlink" },
{ 0, }, /* 11 is obsolete execv */
/* 12 */ { 0, "chdir", { 0, }, 0 },
/* 13 */ { 0, "fchdir", { 0, }, 0 },
/* 14 */ { 0, "mknod", { 0, }, 0 },
/* 15 */ { 0, "chmod", { 0, }, 0 },
/* 16 */ { 0, "chown", { 0, }, 0 },
/* 17 */ { do_break, "break", { 0, }, 0 },
/* 18 */ { 0, "getfsstat", { 0, }, 0 },
/* 12 */ { 0, "chdir" },
/* 13 */ { 0, "fchdir" },
/* 14 */ { 0, "mknod" },
/* 15 */ { 0, "chmod" },
/* 16 */ { 0, "chown" },
/* 17 */ { do_break, "break" },
/* 18 */ { 0, "getfsstat" },
{ 0, }, /* 19 is old lseek */
/* 20 */ { do_getpid, "getpid", { 0, }, 0 },
/* 21 */ { 0, "mount", { 0, }, 0 },
/* 22 */ { 0, "unmount", { 0, }, 0 },
/* 23 */ { 0, "setuid", { 0, }, 0 },
/* 24 */ { do_getuid, "getuid", { 0, }, 0 },
/* 25 */ { do_geteuid, "geteuid", { 0, }, 0 },
/* 26 */ { 0, "ptrace", { 0, }, 0 },
/* 27 */ { 0, "recvmsg", { 0, }, 0 },
/* 28 */ { 0, "sendmsg", { 0, }, 0 },
/* 29 */ { 0, "recvfrom", { 0, }, 0 },
/* 30 */ { 0, "accept", { 0, }, 0 },
/* 31 */ { 0, "getpeername", { 0, }, 0 },
/* 32 */ { 0, "getsockname", { 0, }, 0 },
/* 33 */ { 0, "access", { 0, }, 0 },
/* 34 */ { 0, "chflags", { 0, }, 0 },
/* 35 */ { 0, "fchflags", { 0, }, 0 },
/* 36 */ { 0, "sync", { 0, }, 0 },
/* 37 */ { do_kill, "kill", { 0, }, 0 },
/* 20 */ { do_getpid, "getpid" },
/* 21 */ { 0, "mount" },
/* 22 */ { 0, "unmount" },
/* 23 */ { 0, "setuid" },
/* 24 */ { do_getuid, "getuid" },
/* 25 */ { do_geteuid, "geteuid" },
/* 26 */ { 0, "ptrace" },
/* 27 */ { 0, "recvmsg" },
/* 28 */ { 0, "sendmsg" },
/* 29 */ { 0, "recvfrom" },
/* 30 */ { 0, "accept" },
/* 31 */ { 0, "getpeername" },
/* 32 */ { 0, "getsockname" },
/* 33 */ { 0, "access" },
/* 34 */ { 0, "chflags" },
/* 35 */ { 0, "fchflags" },
/* 36 */ { 0, "sync" },
/* 37 */ { do_kill, "kill" },
{ 0, }, /* 38 is old stat */
/* 39 */ { 0, "getppid", { 0, }, 0 },
/* 39 */ { 0, "getppid" },
{ 0, }, /* 40 is old lstat */
/* 41 */ { do_dup, "dup", { 0, }, 0 },
/* 42 */ { 0, "pipe", { 0, }, 0 },
/* 43 */ { do_getegid, "getegid", { 0, }, 0 },
/* 44 */ { 0, "profil", { 0, }, 0 },
/* 45 */ { 0, "ktrace", { 0, }, 0 },
/* 46 */ { 0, "sigaction", { 0, }, 0 },
/* 47 */ { do_getgid, "getgid", { 0, }, 0 },
/* 48 */ { do_sigprocmask, "sigprocmask", { 0, }, 0 },
/* 49 */ { 0, "getlogin", { 0, }, 0 },
/* 50 */ { 0, "setlogin", { 0, }, 0 },
/* 51 */ { 0, "acct", { 0, }, 0 },
/* 52 */ { 0, "sigpending", { 0, }, 0 },
/* 53 */ { 0, "sigaltstack", { 0, }, 0 },
/* 54 */ { do_ioctl, "ioctl", { 0, }, 0 },
/* 55 */ { 0, "reboot", { 0, }, 0 },
/* 56 */ { 0, "revoke", { 0, }, 0 },
/* 57 */ { 0, "symlink", { 0, }, 0 },
/* 58 */ { 0, "readlink", { 0, }, 0 },
/* 59 */ { 0, "execve", { 0, }, 0 },
/* 60 */ { do_umask, "umask", { 0, }, 0 },
/* 61 */ { 0, "chroot", { 0, }, 0 },
/* 41 */ { do_dup, "dup" },
/* 42 */ { 0, "pipe" },
/* 43 */ { do_getegid, "getegid" },
/* 44 */ { 0, "profil" },
/* 45 */ { 0, "ktrace" },
/* 46 */ { 0, "sigaction" },
/* 47 */ { do_getgid, "getgid" },
/* 48 */ { do_sigprocmask, "sigprocmask" },
/* 49 */ { 0, "getlogin" },
/* 50 */ { 0, "setlogin" },
/* 51 */ { 0, "acct" },
/* 52 */ { 0, "sigpending" },
/* 53 */ { 0, "sigaltstack" },
/* 54 */ { do_ioctl, "ioctl" },
/* 55 */ { 0, "reboot" },
/* 56 */ { 0, "revoke" },
/* 57 */ { 0, "symlink" },
/* 58 */ { 0, "readlink" },
/* 59 */ { 0, "execve" },
/* 60 */ { do_umask, "umask" },
/* 61 */ { 0, "chroot" },
{ 0, }, /* 62 is old fstat */
{ 0, }, /* 63 is old getkerninfo */
{ 0, }, /* 64 is old getpagesize */
/* 65 */ { 0, "msync", { 0, }, 0 },
/* 66 */ { 0, "vfork", { 0, }, 0 },
/* 65 */ { 0, "msync" },
/* 66 */ { 0, "vfork" },
{ 0, }, /* 67 is obsolete vread */
{ 0, }, /* 68 is obsolete vwrite */
/* 69 */ { 0, "sbrk", { 0, }, 0 },
/* 70 */ { 0, "sstk", { 0, }, 0 },
/* 69 */ { 0, "sbrk" },
/* 70 */ { 0, "sstk" },
{ 0, }, /* 71 is old mmap */
/* 72 */ { 0, "vadvise", { 0, }, 0 },
/* 73 */ { 0, "munmap", { 0, }, 0 },
/* 74 */ { 0, "mprotect", { 0, }, 0 },
/* 75 */ { 0, "madvise", { 0, }, 0 },
/* 72 */ { 0, "vadvise" },
/* 73 */ { 0, "munmap" },
/* 74 */ { 0, "mprotect" },
/* 75 */ { 0, "madvise" },
{ 0, }, /* 76 is obsolete vhangup */
{ 0, }, /* 77 is obsolete vlimit */
/* 78 */ { 0, "mincore", { 0, }, 0 },
/* 79 */ { 0, "getgroups", { 0, }, 0 },
/* 80 */ { 0, "setgroups", { 0, }, 0 },
/* 81 */ { 0, "getpgrp", { 0, }, 0 },
/* 82 */ { 0, "setpgid", { 0, }, 0 },
/* 83 */ { 0, "setitimer", { 0, }, 0 },
/* 78 */ { 0, "mincore" },
/* 79 */ { 0, "getgroups" },
/* 80 */ { 0, "setgroups" },
/* 81 */ { 0, "getpgrp" },
/* 82 */ { 0, "setpgid" },
/* 83 */ { 0, "setitimer" },
{ 0, }, /* 84 is old wait */
/* 85 */ { 0, "swapon", { 0, }, 0 },
/* 86 */ { 0, "getitimer", { 0, }, 0 },
/* 85 */ { 0, "swapon" },
/* 86 */ { 0, "getitimer" },
{ 0, }, /* 87 is old gethostname */
{ 0, }, /* 88 is old sethostname */
{ 0, }, /* 89 is old getdtablesize */
{ do_dup2, "dup2", { 0, }, 0 },
{ do_dup2, "dup2" },
{ 0, }, /* 91 */
/* 92 */ { do_fcntl, "fcntl", { 0, }, 0 },
/* 93 */ { 0, "select", { 0, }, 0 },
/* 92 */ { do_fcntl, "fcntl" },
/* 93 */ { 0, "select" },
{ 0, }, /* 94 */
/* 95 */ { 0, "fsync", { 0, }, 0 },
/* 96 */ { 0, "setpriority", { 0, }, 0 },
/* 97 */ { 0, "socket", { 0, }, 0 },
/* 98 */ { 0, "connect", { 0, }, 0 },
/* 95 */ { 0, "fsync" },
/* 96 */ { 0, "setpriority" },
/* 97 */ { 0, "socket" },
/* 98 */ { 0, "connect" },
{ 0, }, /* 99 is old accept */
/* 100 */ { 0, "getpriority", { 0, }, 0 },
/* 100 */ { 0, "getpriority" },
{ 0, }, /* 101 is old send */
{ 0, }, /* 102 is old recv */
/* 103 */ { 0, "sigreturn", { 0, }, 0 },
/* 104 */ { 0, "bind", { 0, }, 0 },
/* 105 */ { 0, "setsockopt", { 0, }, 0 },
/* 106 */ { 0, "listen", { 0, }, 0 },
/* 103 */ { 0, "sigreturn" },
/* 104 */ { 0, "bind" },
/* 105 */ { 0, "setsockopt" },
/* 106 */ { 0, "listen" },
{ 0, }, /* 107 is obsolete vtimes */
{ 0, }, /* 108 is old sigvec */
{ 0, }, /* 109 is old sigblock */
{ 0, }, /* 110 is old sigsetmask */
/* 111 */ { 0, "sigsuspend", { 0, }, 0 },
/* 111 */ { 0, "sigsuspend" },
{ 0, }, /* 112 is old sigstack */
{ 0, }, /* 113 is old recvmsg */
{ 0, }, /* 114 is old sendmsg */
/* - is obsolete vtrace */ { 0, "vtrace 115", { 0, }, 0 },
/* 116 */ { do_gettimeofday, "gettimeofday", { 0, }, 0 },
/* 117 */ { do_getrusage, "getrusage", { 0, }, 0 },
/* 118 */ { 0, "getsockopt", { 0, }, 0 },
/* 119 */ { 0, "resuba", { 0, }, 0 },
/* 120 */ { 0, "readv", { 0, }, 0 },
/* 121 */ { 0, "writev", { 0, }, 0 },
/* 122 */ { 0, "settimeofday", { 0, }, 0 },
/* 123 */ { 0, "fchown", { 0, }, 0 },
/* 124 */ { 0, "fchmod", { 0, }, 0 },
/* - is obsolete vtrace */ { 0, "vtrace 115" },
/* 116 */ { do_gettimeofday, "gettimeofday" },
/* 117 */ { do_getrusage, "getrusage" },
/* 118 */ { 0, "getsockopt" },
/* 119 */ { 0, "resuba" },
/* 120 */ { 0, "readv" },
/* 121 */ { 0, "writev" },
/* 122 */ { 0, "settimeofday" },
/* 123 */ { 0, "fchown" },
/* 124 */ { 0, "fchmod" },
{ 0, }, /* 125 is old recvfrom */
{ 0, }, /* 126 is old setreuid */
{ 0, }, /* 127 is old setregid */
/* 128 */ { 0, "rename", { 0, }, 0 },
/* 128 */ { 0, "rename" },
{ 0, }, /* 129 is old truncate */
{ 0, }, /* 130 is old ftruncate */
/* 131 */ { 0, "flock", { 0, }, 0 },
/* 132 */ { 0, "mkfifo", { 0, }, 0 },
/* 133 */ { 0, "sendto", { 0, }, 0 },
/* 134 */ { 0, "shutdown", { 0, }, 0 },
/* 135 */ { 0, "socketpair", { 0, }, 0 },
/* 136 */ { 0, "mkdir", { 0, }, 0 },
/* 137 */ { 0, "rmdir", { 0, }, 0 },
/* 138 */ { 0, "utimes", { 0, }, 0 },
/* 131 */ { 0, "flock" },
/* 132 */ { 0, "mkfifo" },
/* 133 */ { 0, "sendto" },
/* 134 */ { 0, "shutdown" },
/* 135 */ { 0, "socketpair" },
/* 136 */ { 0, "mkdir" },
/* 137 */ { 0, "rmdir" },
/* 138 */ { 0, "utimes" },
{ 0, }, /* 139 is obsolete 4.2 sigreturn */
/* 140 */ { 0, "adjtime", { 0, }, 0 },
/* 140 */ { 0, "adjtime" },
{ 0, }, /* 141 is old getpeername */
{ 0, }, /* 142 is old gethostid */
{ 0, }, /* 143 is old sethostid */
{ 0, }, /* 144 is old getrlimit */
{ 0, }, /* 145 is old setrlimit */
{ 0, }, /* 146 is old killpg */
/* 147 */ { 0, "setsid", { 0, }, 0 },
/* 148 */ { 0, "quotactl", { 0, }, 0 },
/* 147 */ { 0, "setsid" },
/* 148 */ { 0, "quotactl" },
{ 0, }, /* 149 is old quota */
{ 0, }, /* 150 is old getsockname */
{ 0, }, /* 151 */
{ 0, }, /* 152 */
{ 0, }, /* 153 */
{ 0, }, /* 154 */
/* 155 */ { 0, "nfssvc", { 0, }, 0 },
/* 155 */ { 0, "nfssvc" },
{ 0, }, /* 156 is old getdirentries */
/* 157 */ { 0, "statfs", { 0, }, 0 },
/* 158 */ { do_fstatfs, "fstatfs", { 0, }, 0 },
/* 157 */ { 0, "statfs" },
/* 158 */ { do_fstatfs, "fstatfs" },
{ 0, }, /* 159 */
{ 0, }, /* 160 */
/* 161 */ { 0, "getfh", { 0, }, 0 },
/* 161 */ { 0, "getfh" },
{ 0, }, /* 162 is old getdomainname */
{ 0, }, /* 163 is old setdomainname */
{ 0, }, /* 164 is old uname */
/* 165 */ { 0, "sysarch", { 0, }, 0 },
/* 165 */ { 0, "sysarch" },
{ 0, }, /* 166 */
{ 0, }, /* 167 */
{ 0, }, /* 168 */
/* 169 */ { 0, "semsys", { 0, }, 0 },
/* 170 */ { 0, "msgsys", { 0, }, 0 },
/* 171 */ { 0, "shmsys", { 0, }, 0 },
/* 169 */ { 0, "semsys" },
/* 170 */ { 0, "msgsys" },
/* 171 */ { 0, "shmsys" },
{ 0, }, /* 172 */
{ 0, }, /* 173 */
{ 0, }, /* 174 */
@ -1054,30 +1066,30 @@ static emul_call_descriptor netbsd_descriptors[] = {
{ 0, }, /* 178 */
{ 0, }, /* 179 */
{ 0, }, /* 180 */
/* 181 */ { 0, "setgid", { 0, }, 0 },
/* 182 */ { 0, "setegid", { 0, }, 0 },
/* 183 */ { 0, "seteuid", { 0, }, 0 },
/* 184 */ { 0, "lfs_bmapv", { 0, }, 0 },
/* 185 */ { 0, "lfs_markv", { 0, }, 0 },
/* 186 */ { 0, "lfs_segclean", { 0, }, 0 },
/* 187 */ { 0, "lfs_segwait", { 0, }, 0 },
/* 188 */ { do_stat, "stat", { 0, }, 0 },
/* 189 */ { do_fstat, "fstat", { 0, }, 0 },
/* 190 */ { do_lstat, "lstat", { 0, }, 0 },
/* 191 */ { 0, "pathconf", { 0, }, 0 },
/* 192 */ { 0, "fpathconf", { 0, }, 0 },
/* 181 */ { 0, "setgid" },
/* 182 */ { 0, "setegid" },
/* 183 */ { 0, "seteuid" },
/* 184 */ { 0, "lfs_bmapv" },
/* 185 */ { 0, "lfs_markv" },
/* 186 */ { 0, "lfs_segclean" },
/* 187 */ { 0, "lfs_segwait" },
/* 188 */ { do_stat, "stat" },
/* 189 */ { do_fstat, "fstat" },
/* 190 */ { do_lstat, "lstat" },
/* 191 */ { 0, "pathconf" },
/* 192 */ { 0, "fpathconf" },
{ 0, }, /* 193 */
/* 194 */ { 0, "getrlimit", { 0, }, 0 },
/* 195 */ { 0, "setrlimit", { 0, }, 0 },
/* 196 */ { do_getdirentries, "getdirentries", { 0, }, 0 },
/* 197 */ { 0, "mmap", { 0, }, 0 },
/* 198 */ { do___syscall, "__syscall", { 0, }, 0 },
/* 199 */ { do_lseek, "lseek", { 0, }, 0 },
/* 200 */ { 0, "truncate", { 0, }, 0 },
/* 201 */ { 0, "ftruncate", { 0, }, 0 },
/* 202 */ { do___sysctl, "__sysctl", { 0, }, 0 },
/* 203 */ { 0, "mlock", { 0, }, 0 },
/* 204 */ { 0, "munlock", { 0, }, 0 },
/* 194 */ { 0, "getrlimit" },
/* 195 */ { 0, "setrlimit" },
/* 196 */ { do_getdirentries, "getdirentries" },
/* 197 */ { 0, "mmap" },
/* 198 */ { do___syscall, "__syscall" },
/* 199 */ { do_lseek, "lseek" },
/* 200 */ { 0, "truncate" },
/* 201 */ { 0, "ftruncate" },
/* 202 */ { do___sysctl, "__sysctl" },
/* 203 */ { 0, "mlock" },
/* 204 */ { 0, "munlock" },
};
static char *(netbsd_error_names[]) = {
@ -1201,7 +1213,7 @@ static char *(netbsd_signal_names[]) = {
/* 31 */ "SIGUSR2",
};
emulation emul_netbsd = {
static emul_syscall emul_netbsd_syscalls = {
netbsd_descriptors,
sizeof(netbsd_descriptors) / sizeof(netbsd_descriptors[0]),
netbsd_error_names,
@ -1210,4 +1222,127 @@ emulation emul_netbsd = {
sizeof(netbsd_signal_names) / sizeof(netbsd_signal_names[0]),
};
#endif /* _EMUL_NETBSD_C_ */
/* NetBSD's os_emul interface, most are just passed on to the generic
syscall stuff */
static os_emul_data *
emul_netbsd_create(device *root,
bfd *image,
const char *name)
{
unsigned_word top_of_stack;
unsigned stack_size;
int elf_binary;
os_emul_data *bsd_data;
/* check that this emulation is really for us */
if (name != NULL && strcmp(name, "netbsd") != 0)
return NULL;
if (image == NULL)
return NULL;
/* merge any emulation specific entries into the device tree */
/* establish a few defaults */
if (image->xvec->flavour == bfd_target_elf_flavour) {
elf_binary = 1;
top_of_stack = 0xe0000000;
stack_size = 0x00100000;
}
else {
elf_binary = 0;
top_of_stack = 0x20000000;
stack_size = 0x00100000;
}
/* options */
{
device *options = device_tree_add_found(root, "/", "options");
device_add_integer_property(options, "smp", 1); /* always */
device_add_boolean_property(options, "little-endian?",
!image->xvec->byteorder_big_p);
device_add_string_property(options, "env",
(WITH_ENVIRONMENT == USER_ENVIRONMENT
? "user" : "virtual"));
device_add_boolean_property(options, "strict-alignment?",
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|| !image->xvec->byteorder_big_p));
device_add_boolean_property(options, "floating-point?",
WITH_FLOATING_POINT);
device_add_string_property(options, "os-emul", "netbsd");
}
/* virtual memory - handles growth of stack/heap */
{
device *vm_node = device_tree_add_found_uw_u(root, "/", "vm",
top_of_stack - stack_size,
stack_size);
device *vm_map_binary = device_tree_add_found(vm_node, "", "map-binary");
device_add_null_property(vm_map_binary,
bfd_get_filename(image));
}
/* finish the init */
{
device *init = device_tree_add_found(root, "/", "init");
{
device *init_register = device_tree_add_found(init, "", "register");
device_add_integer_property(init_register,
"pc",
bfd_get_start_address(image));
device_add_integer_property(init_register,
"sp",
top_of_stack);
device_add_integer_property(init_register,
"msr",
(image->xvec->byteorder_big_p
? 0
: msr_little_endian_mode));
}
{
device *init_stack = device_tree_add_found(init, "", "stack");
device_add_null_property(init_stack,
(elf_binary
? "elf"
: "xcoff"));
}
}
/* finally our emulation data */
bsd_data = ZALLOC(os_emul_data);
bsd_data->syscalls = &emul_netbsd_syscalls;
return bsd_data;
}
static void
emul_netbsd_init(os_emul_data *emul_data,
int nr_cpus)
{
/* nothing yet */
}
static void
emul_netbsd_system_call(cpu *processor,
unsigned_word cia,
os_emul_data *emul_data)
{
emul_do_system_call(emul_data,
emul_data->syscalls,
cpu_registers(processor)->gpr[0],
3, /*r3 contains arg0*/
processor,
cia);
}
const os_emul emul_netbsd = {
"netbsd",
emul_netbsd_create,
emul_netbsd_init,
emul_netbsd_system_call,
0, /*instruction_call*/
0 /*data*/
};
#endif _EMUL_NETBSD_C_

View File

@ -22,10 +22,6 @@
#ifndef _INTERRUPTS_C_
#define _INTERRUPTS_C_
#ifndef STATIC_INLINE_INTERRUPTS
#define STATIC_INLINE_INTERRUPTS STATIC_INLINE
#endif
#include <signal.h>
#include "cpu.h"
@ -42,7 +38,7 @@
interrupts */
STATIC_INLINE_INTERRUPTS msreg
msreg STATIC_INLINE_INTERRUPTS
interrupt_msr(msreg old_msr,
msreg msr_clear,
msreg msr_set)
@ -67,7 +63,7 @@ interrupt_msr(msreg old_msr,
}
STATIC_INLINE_INTERRUPTS msreg
msreg STATIC_INLINE_INTERRUPTS
interrupt_srr1(msreg old_msr,
msreg srr1_clear,
msreg srr1_set)
@ -80,7 +76,7 @@ interrupt_srr1(msreg old_msr,
}
STATIC_INLINE_INTERRUPTS unsigned_word
unsigned_word STATIC_INLINE_INTERRUPTS
interrupt_base_ea(msreg msr)
{
if (msr & msr_interrupt_prefix)
@ -93,7 +89,7 @@ interrupt_base_ea(msreg msr)
/* finish off an interrupt for the OEA model, updating all registers
and forcing a restart of the processor */
STATIC_INLINE_INTERRUPTS unsigned_word
unsigned_word STATIC_INLINE_INTERRUPTS
perform_oea_interrupt(cpu *processor,
unsigned_word cia,
unsigned_word vector_offset,
@ -117,9 +113,9 @@ perform_oea_interrupt(cpu *processor,
}
INLINE_INTERRUPTS void machine_check_interrupt
(cpu *processor,
unsigned_word cia)
void INLINE_INTERRUPTS
machine_check_interrupt(cpu *processor,
unsigned_word cia)
{
switch (CURRENT_ENVIRONMENT) {
@ -139,7 +135,7 @@ INLINE_INTERRUPTS void machine_check_interrupt
}
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
data_storage_interrupt(cpu *processor,
unsigned_word cia,
unsigned_word ea,
@ -190,7 +186,7 @@ data_storage_interrupt(cpu *processor,
}
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
instruction_storage_interrupt(cpu *processor,
unsigned_word cia,
storage_interrupt_reasons reason)
@ -204,7 +200,6 @@ instruction_storage_interrupt(cpu *processor,
case OPERATING_ENVIRONMENT:
{
unsigned_word nia;
msreg srr1_set;
switch(reason) {
case hash_table_miss_storage_interrupt:
@ -236,10 +231,10 @@ instruction_storage_interrupt(cpu *processor,
INLINE_INTERRUPTS void alignment_interrupt
(cpu *processor,
unsigned_word cia,
unsigned_word ra)
void INLINE_INTERRUPTS
alignment_interrupt(cpu *processor,
unsigned_word cia,
unsigned_word ra)
{
switch (CURRENT_ENVIRONMENT) {
@ -263,7 +258,7 @@ INLINE_INTERRUPTS void alignment_interrupt
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
program_interrupt(cpu *processor,
unsigned_word cia,
program_interrupt_reasons reason)
@ -307,7 +302,7 @@ program_interrupt(cpu *processor,
}
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
floating_point_unavailable_interrupt(cpu *processor,
unsigned_word cia)
{
@ -329,7 +324,7 @@ floating_point_unavailable_interrupt(cpu *processor,
}
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
system_call_interrupt(cpu *processor,
unsigned_word cia)
{
@ -337,7 +332,7 @@ system_call_interrupt(cpu *processor,
case USER_ENVIRONMENT:
case VIRTUAL_ENVIRONMENT:
os_emul_call(processor, cia);
os_emul_system_call(processor, cia);
cpu_restart(processor, cia+4);
case OPERATING_ENVIRONMENT:
@ -350,11 +345,11 @@ system_call_interrupt(cpu *processor,
}
}
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
trace_interrupt(cpu *processor,
unsigned_word cia);
INLINE_INTERRUPTS void
void INLINE_INTERRUPTS
floating_point_assist_interrupt(cpu *processor,
unsigned_word cia)
{
@ -379,7 +374,7 @@ floating_point_assist_interrupt(cpu *processor,
/* handle an externally generated event */
INLINE_INTERRUPTS int
int INLINE_INTERRUPTS
decrementer_interrupt(cpu *processor)
{
if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
@ -394,7 +389,7 @@ decrementer_interrupt(cpu *processor)
}
}
INLINE_INTERRUPTS int
int INLINE_INTERRUPTS
external_interrupt(cpu *processor)
{
if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {

152
sim/ppc/interrupts.h Normal file
View File

@ -0,0 +1,152 @@
/* 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 _INTERRUPTS_H_
#define _INTERRUPTS_H_
/* Interrupts:
The code below handles two different types of interrupts.
Synchronous and Asynchronous.
Synchronous:
Interrupts that must immediately force either an abort or restart
of a current instruction are implemented by forcing an instruction
restart. (or to put it another way, long jump). In looking at the
code it may occure to you that, for some interrupts, they could
return instead of restarting the cpu (eg system_call). While true
(it once was like that) I've decided to make the behavour of all
interrupt routines roughly identical.
Because, a cpu's recorded state (ie what is in the cpu structure)
is allowed to lag behind the cpu's true current state (eg PC not
updated) sycnronous interrupt handers are parameterized with the
the cpu being interrupted so that, as part of moddeling the
interrupt, the cpu's state can be updated.
Asynchronous:
Interrupts such as reset or external exception are delivered using
more normal (returning) functions. It is assumed that these
functions are called out side of the normal processor execution
cycle. */
/* Software generated interrupts.
The below are generated by software driven events. For instance,
an invalid instruction or access (virtual or physical) to an
invalid address */
typedef enum {
direct_store_storage_interrupt,
hash_table_miss_storage_interrupt,
protection_violation_storage_interrupt,
earwax_violation_storage_interrupt,
segment_table_miss_storage_interrupt,
earwax_disabled_storage_interrupt,
vea_storage_interrupt,
} storage_interrupt_reasons;
void INLINE_INTERRUPTS data_storage_interrupt
(cpu *processor,
unsigned_word cia,
unsigned_word ea,
storage_interrupt_reasons reason,
int is_store);
void INLINE_INTERRUPTS instruction_storage_interrupt
(cpu *processor,
unsigned_word cia,
storage_interrupt_reasons reason);
void INLINE_INTERRUPTS alignment_interrupt
(cpu *processor,
unsigned_word cia,
unsigned_word ra);
typedef enum {
floating_point_enabled_program_interrupt,
illegal_instruction_program_interrupt,
privileged_instruction_program_interrupt,
trap_program_interrupt,
nr_program_interrupt_reasons
} program_interrupt_reasons;
void INLINE_INTERRUPTS program_interrupt
(cpu *processor,
unsigned_word cia,
program_interrupt_reasons reason);
void INLINE_INTERRUPTS floating_point_unavailable_interrupt
(cpu *processor,
unsigned_word cia);
void INLINE_INTERRUPTS system_call_interrupt
(cpu *processor,
unsigned_word cia);
void INLINE_INTERRUPTS trace_interrupt
(cpu *processor,
unsigned_word cia);
void INLINE_INTERRUPTS floating_point_assist_interrupt
(cpu *processor,
unsigned_word cia);
void INLINE_INTERRUPTS machine_check_interrupt
(cpu *processor,
unsigned_word cia);
/* Bit of a funny one. One of the trap instructions has been marked
as the breakpoint instruction. This special case calls this
interrupt routine */
void INLINE_INTERRUPTS breakpoint_interrupt
(cpu *processor,
unsigned_word cia);
/* Hardware generated interrupts
These hardware generated interrupt routines are called outside of
the instruction execution cycle and so return normally.
More importantly, they assume that the current instruction address
held within the processor is correct.
Return a non zero value if the interrupt was not successfully
delivered */
int INLINE_INTERRUPTS decrementer_interrupt
(cpu *processor);
int INLINE_INTERRUPTS hard_system_reset
(cpu *processor);
int INLINE_INTERRUPTS soft_system_reset
(cpu *processor);
int INLINE_INTERRUPTS external_interrupt
(cpu *processor);
#endif /* _INTERRUPTS_H_ */

95
sim/ppc/ppc-opcode-test-1 Normal file
View File

@ -0,0 +1,95 @@
#
# 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.
#
# Instruction decode:
#
# The table that follows is used by gen to construct a decision tree
# that can identify each possible instruction. Gen then outputs this
# decision tree as (according to config) a table or switch statement
# as the function idecode.
#
# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS
# determines of the semantic functions themselves should be expanded
# in a similar way.
#
# The table contains the following entries:
#
# <valid>
#
# Must be 1 for the entry to be considered. The last entry must be
# zero.
#
# <first>
# <last>
#
# Range of bits (within the instruction) that should be searched for
# an instruction field. Within such ranges, gen looks for opcodes
# (constants), registers (strings) and reserved bits (slash) and
# according to the rules that follows includes or excludes them from
# a possible instruction field.
#
# <force_first>
# <force_last>
#
# If an instructioin field was found, enlarge the field size so that
# it is forced to at least include bits starting from <force_first>
# (<force_last>). To stop this occuring, use <force_first> = <last>
# + 1 and <force_last> = <first> - 1.
#
# <force_slash>
#
# Treat `/' fields as a constant instead of variable when looking for
# an instruction field.
#
# <force_expansion>
#
# Treat any contained register (string) fields as constant when
# determining the instruction field. For the instruction decode (and
# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of
# what would otherwize be non constant bits of an instruction.
#
# <use_switch>
#
# Should this table be expanded using a switch statement (val 1) and
# if so, should it be padded with entries so as to force the compiler
# to generate a jump table (val 2).
#
# <special_mask>
# <special_value>
# <special_rule>
#
# Special rule to fine tune how specific (or groups) of instructions
# are expanded. The applicability of the rule is determined by
#
# <special_mask> != 0 && (instruction> & <special_mask>) == <special_value>
#
# Where <instruction> is obtained by looking only at constant fields
# with in an instructions spec. When determining an expansion, the
# rule is only considered when a node contains a single instruction.
# <special_rule> can be any of:
#
# 0: for this instruction, expand by earlier rules
# 1: expand bits <force_low> .. <force_hi> only
# 2: boolean expansion of only zero/non-zero cases
#
0: 5: 0: 5:0:: 2:0x00000000:0x00000000:0
21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0
6: 9: 6: 9:0:BO: 0:0xfc000000:0x40000000:1
11:15:11:15:0:RA: 1:0xfc000000:0x38000000:2
11:15:11:15:0:RA: 1:0xfc000000:0x3c000000:2

95
sim/ppc/ppc-opcode-test-2 Normal file
View File

@ -0,0 +1,95 @@
#
# 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.
#
# Instruction decode:
#
# The table that follows is used by gen to construct a decision tree
# that can identify each possible instruction. Gen then outputs this
# decision tree as (according to config) a table or switch statement
# as the function idecode.
#
# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS
# determines of the semantic functions themselves should be expanded
# in a similar way.
#
# The table contains the following entries:
#
# <valid>
#
# Must be 1 for the entry to be considered. The last entry must be
# zero.
#
# <first>
# <last>
#
# Range of bits (within the instruction) that should be searched for
# an instruction field. Within such ranges, gen looks for opcodes
# (constants), registers (strings) and reserved bits (slash) and
# according to the rules that follows includes or excludes them from
# a possible instruction field.
#
# <force_first>
# <force_last>
#
# If an instructioin field was found, enlarge the field size so that
# it is forced to at least include bits starting from <force_first>
# (<force_last>). To stop this occuring, use <force_first> = <last>
# + 1 and <force_last> = <first> - 1.
#
# <force_slash>
#
# Treat `/' fields as a constant instead of variable when looking for
# an instruction field.
#
# <force_expansion>
#
# Treat any contained register (string) fields as constant when
# determining the instruction field. For the instruction decode (and
# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of
# what would otherwize be non constant bits of an instruction.
#
# <use_switch>
#
# Should this table be expanded using a switch statement (val 1) and
# if so, should it be padded with entries so as to force the compiler
# to generate a jump table (val 2).
#
# <special_mask>
# <special_value>
# <special_rule>
#
# Special rule to fine tune how specific (or groups) of instructions
# are expanded. The applicability of the rule is determined by
#
# <special_mask> != 0 && (instruction> & <special_mask>) == <special_value>
#
# Where <instruction> is obtained by looking only at constant fields
# with in an instructions spec. When determining an expansion, the
# rule is only considered when a node contains a single instruction.
# <special_rule> can be any of:
#
# 0: for this instruction, expand by earlier rules
# 1: expand bits <force_low> .. <force_hi> only
# 2: boolean expansion of only zero/non-zero cases
#
0: 5: 0: 5:0:: 0:0x00000000:0x00000000:0
21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0
6: 9: 6: 9:0:BO: 0:0xfc000000:0x40000000:1
11:15:11:15:0:RA: 1:0xfc000000:0x38000000:2
11:15:11:15:0:RA: 1:0xfc000000:0x3c000000:2

View File

@ -1,772 +0,0 @@
/*
* Copyright (C) 1991 Gordon Irlam. All rights reserved.
*/
/*
* Sparc trace generator.
*
* Generate a Sparc address trace.
*
* Report system calls.
*
* We want to display the system call and the return value at the same time
* (so that other output does not appear between the two) but also want to
* identify system calls that block without having to wait for them to
* return. Whenever a system call is performed we store the name of the
* call and the parameters. If we don't see a return within a certain time
* period we display the call regardless, and assume it has blocked.
*/
/*
* Imported declarations.
*/
#include "config.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <malloc.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/trap.h>
/*
* sigcleanup is not defined in a system header file.
*/
#define SYS_sigcleanup 139
#include "prototype.h"
#include "error.h"
#include "spy.h"
#include "system_calls.h"
/*
* Forward declarations.
*/
PROTOTYPE(void report_trap,
(int pid, void *addr, int trap, int g1, syscall_params *params));
PROTOTYPE(void report_trap_result, (int pid, int error, int o0, int o1));
PROTOTYPE(void display_trap_msg, (void));
PROTOTYPE(void delayed_trap_msg, (void));
PROTOTYPE(void discard_trap_msg, (void));
PROTOTYPE(int copy_memory, (int pid, void *addr, int size, char *data));
PROTOTYPE(char *snarf_string, (int pid, void *addr));
PROTOTYPE(char *snarf_data, (int pid, void *addr, int size));
PROTOTYPE(char *format_value,
(int pid, fmt_type format, unsigned long value, int opt));
PROTOTYPE(int printable_data, (char *data, int size));
PROTOTYPE(char *print_string, (char *data, int size));
/*
* Global definitions.
*/
static char *trap_msg = NULL;
static fmt_type result_format;
static int no_return;
static fmt_type post_fmt;
static unsigned long post_value;
static int post_size;
/*
* Report the occurence of the specified trap.
*/
void report_trap(pid, addr, trap, g1, params_addr)
int pid;
void *addr;
int trap;
int g1;
syscall_params *params_addr;
{
syscall_params params;
call_desc *call;
int i;
fmt_type arg_format;
char *arg_str;
/*
* Display any previous trap message that is still pending (it might have
* been a trap that did not return a value, and so has not yet been
* displayed).
*/
display_trap_msg();
/*
* Read the parameters, and construct a string describing the system call.
*/
ensure(ptrace(PTRACE_READDATA, pid,
(char *) params_addr, sizeof(syscall_params),
(char *) params) != -1);
no_return = 0;
if (trap != T_SOFTWARE_TRAP) {
/*
* Not a system call trap.
*/
no_return = 1;
ensure((trap_msg = malloc(17 + 20 + 1)) != NULL);
sprintf(trap_msg, "0x%08lx: trap %d", (unsigned long) addr, trap);
result_format = fmt_unknown;
} if ((g1 < 0) || (g1 >= no_system_calls)) {
/*
* An unknown system call.
*/
ensure((trap_msg = malloc(21 + 20 + 1)) != NULL);
sprintf(trap_msg, "0x%08lx: _unknown_%d(",
(unsigned long) addr, g1);
arg_str = format_value(pid, fmt_unknown, params[0], 0);
ensure((trap_msg = realloc(trap_msg, strlen(trap_msg)
+ strlen(arg_str) + 1 + 1))
!= NULL);
sprintf(trap_msg + sizeof(trap_msg), "%s)", arg_str);
free(arg_str);
result_format = fmt_unknown;
} else {
/*
* A known system call.
*/
call = &system_calls[g1];
switch (g1) {
case SYS_open :
if (!(params[1] & O_CREAT)) {
call = &system_call_open_simple;
}
break;
case SYS_exit :
case SYS_execve :
case SYS_sigcleanup :
no_return = 1;
break;
default :
break;
}
ensure((trap_msg = malloc(13 + strlen(call->name) + 1 + 1))
!= NULL);
sprintf(trap_msg, "0x%08lx: %s(",
(unsigned long) addr, call->name);
/*
* Display each of the arguments.
*/
for (i = 0; i < NO_PARAMS; i++) {
if ((arg_format = call->arg[i]) == fmt_none) {
break;
}
if (i > 0) {
strcat(trap_msg, ", ");
}
if (arg_format == fmt_data) {
assert(((i + 1) < NO_PARAMS) &&
(call->arg[i + 1] == fmt_data_size));
arg_str = format_value(pid, arg_format,
params[i], (int) params[i + 1]);
} else {
arg_str = format_value(pid, arg_format, params[i], 0);
}
ensure((trap_msg = realloc(trap_msg, strlen(trap_msg) +
strlen(arg_str) + 2 + 1))
!= NULL);
strcat(trap_msg, arg_str);
free(arg_str);
}
strcat(trap_msg, ")");
result_format = call->result;
}
/*
* Set alarm so that name of call will be displayed even if it blocks.
*/
alarm((unsigned int) 1);
}
/*
* Report the value returned as a result of the most recent trap.
*/
void report_trap_result(pid, error, o0, o1)
int pid;
int error;
int o0;
int o1;
{
char *result, *eno, *emsg, *addr;
/*
* Turn off alarm used to ensure we print the call promptly - we are about
* to print it now.
*/
alarm((unsigned int) 0);
/*
* See if previous call blocked.
*/
if (trap_msg == NULL) {
ensure((trap_msg = strdup(" [previous call]")) != NULL);
}
/*
* Work out error message (if any) to be printed following return value.
*/
if (error) {
eno = format_value(pid, fmt_error, o0, 0);
ensure((emsg = malloc(9 + strlen(eno) + 1)) != NULL);
sprintf(emsg, " [error %s]", eno);
free(eno);
o0 = -1;
post_fmt = fmt_none;
} else {
ensure((emsg = strdup("")) != NULL);
}
/*
* Print out all the details of the system call.
*/
if (result_format == fmt_none) {
ensure(fprintf(msgfile, "%s: %s%s\n", trace_progname, trap_msg, emsg)
!= EOF);
} else {
result = format_value(pid, result_format, o0, 0);
ensure(fprintf(msgfile, "%s: %s -> %s%s\n",
trace_progname, trap_msg, result, emsg) != EOF);
free(result);
}
free(emsg);
/*
* Display any string or buffer modified by the system call if required.
* And providing it can be displayed as a (non-null) string.
*/
if (post_fmt != fmt_none) {
result = format_value(pid, post_fmt, post_value, post_size);
if ((result[0] == '"') && (strlen(result) > 2)) {
addr = format_value(pid, fmt_ptr, post_value, 0);
ensure(fprintf(msgfile, "%s: %s: %s\n",
trace_progname, addr, result) != EOF);
free(addr);
}
free(result);
post_fmt = fmt_none;
}
free(trap_msg);
trap_msg = NULL;
}
/*
* Report any trap messages that haven't been reported yet.
*/
void display_trap_msg() {
/*
* Clear the alarm - we are about to print the message.
*/
alarm((unsigned int) 0);
if (trap_msg != NULL) {
ensure(fprintf(msgfile, "%s: %s\n", trace_progname, trap_msg) != EOF);
free(trap_msg);
trap_msg = NULL;
}
}
/*
* Report the completion of a trap message as being delayed.
*
* This routine is invoked when a SIGALRM is received.
*/
void delayed_trap_msg() {
assert(trap_msg != NULL);
/*
* If the call was not expected to return a value, think nothing of it,
* otherwise assume the call has blocked.
*/
ensure(fprintf(msgfile, "%s: %s%s\n",
trace_progname, trap_msg, (no_return ? "" : " [pending]"))
!= EOF);
free(trap_msg);
trap_msg = NULL;
}
/*
* Discard any pending trap messages.
*
* This routine is used by the child of a fork to discard the fork system call
* record.
*/
void discard_trap_msg() {
trap_msg = NULL;
}
/*
* Attempt to copy size bytes from the target process to data. The number of
* bytes successfully copied is returned.
*/
int copy_memory(pid, addr, size, data)
int pid;
void *addr;
int size;
char *data;
{
int lo, hi, try;
assert(size >= 0);
/*
* Common cases first.
*/
if (ptrace(PTRACE_READDATA, pid, (char *) addr, size, data) != -1) {
return size;
} else if (ptrace(PTRACE_READDATA, pid, (char *) addr, 1, data) == -1) {
return 0;
}
/*
* Binary search.
*/
lo = 1;
hi = size - 1;
while (lo < hi) {
try = (lo + hi + 1) / 2;
if (ptrace(PTRACE_READDATA, pid, (char *) addr, try, data) != -1) {
lo = try;
} else {
hi = try - 1;
}
}
ensure(ptrace(PTRACE_READDATA, pid, (char *) addr, lo, data) != -1);
return lo;
}
/*
* Create a string representing the contents of the indicated null termintated
* region of memory.
*/
char *snarf_string(pid, addr)
int pid;
void *addr;
{
char data[STRING_SIZE_LIMIT + 1];
int size, len;
char *result = NULL;
int too_long = 0;
size = copy_memory(pid, addr, STRING_SIZE_LIMIT, data);
data[size] = '\0';
len = strlen(data);
too_long = (len == STRING_SIZE_LIMIT);
if ((len < size) || too_long) {
if (printable_data(data, len)) {
result = print_string(data, len);
if (too_long) {
ensure((result = realloc(result, strlen(result) + 2 + 1))
!= NULL);
strcat(result, "..");
}
}
}
return result;
}
/*
* Create a string representing the contents of the indicated length delimited
* region of memory.
*/
char *snarf_data(pid, addr, size)
int pid;
void *addr;
int size;
{
char data[DATA_SIZE_LIMIT];
char *result = NULL;
int too_long = 0;
if (size > DATA_SIZE_LIMIT) {
size = DATA_SIZE_LIMIT;
too_long = 1;
}
if ((size >= 0) && (copy_memory(pid, addr, size, data) == size)) {
if (printable_data(data, size)) {
result = print_string(data, size);
if (too_long) {
ensure((result = realloc(result, strlen(result) + 2 + 1))
!= NULL);
strcat(result, "..");
}
}
}
return result;
}
/*
* Create a string representing the contents of the indicated null termintated
* array of pointers to null terminated regions of memory.
*/
char *snarf_string_array(pid, addr)
int pid;
void *addr;
{
char *data[ARRAY_SIZE_LIMIT + 1];
int size, len, i;
char *result = NULL;
char *s;
int too_long = 0;
size = copy_memory(pid, addr, ARRAY_SIZE_LIMIT * sizeof(char *),
(char *) data) / sizeof(char *);
data[size] = NULL;
for (len = 0; data[len] != NULL; len++) {
}
too_long = (len == ARRAY_SIZE_LIMIT);
if ((len < size) || too_long) {
ensure((result = strdup("{")) != NULL);
for (i = 0; i < len; i++) {
if (i > 0) {
strcat(result, ", ");
}
s = format_value(pid, fmt_string, (unsigned long) data[i], 0);
ensure((result = realloc(result,
strlen(result) + strlen(s) + 2 + 5 + 1))
!= NULL);
strcat(result, s);
}
if (too_long) {
strcat(result, ", ..");
}
strcat(result, "}");
}
return result;
}
/*
* Return a string containing a value printed in a specific format. Opt is a
* second optional parameter currently only used to contain the size to be used
* with fmt_data.
*/
char *format_value(pid, format, value, opt)
int pid;
fmt_type format;
unsigned long value;
int opt;
{
char *str;
int sig, error;
/*
* See if we are meant to hang on to the value for later use.
*/
switch (format) {
case fmt_post_string :
post_fmt = fmt_string ;
post_value = value;
format = fmt_ptr;
break;
case fmt_post_data :
post_fmt = fmt_data;
post_value = value;
format = fmt_ptr;
break;
case fmt_data_size :
format = FMT_SIZE;
break;
case fmt_post_data_size :
post_size = (int) value;
format = FMT_SIZE;
break;
default :
break;
}
/*
* Display the value.
*/
switch (format) {
case fmt_dec :
ensure((str = malloc(20 + 1)) != NULL);
sprintf(str, "%d", (int) value);
break;
case fmt_hex :
ensure((str = malloc(2 + 20 + 1)) != NULL);
sprintf(str, "0x%lx", value);
break;
case fmt_ptr :
if (value == 0) {
ensure((str = strdup("NULL")) != NULL);
} else {
ensure((str = malloc(10 + 1)) != NULL);
sprintf(str, "0x%08lx", value);
}
break;
case fmt_fd :
ensure((str = malloc(2 + 20 + 1)) != NULL);
sprintf(str, "fd%d", (int) value);
break;
case fmt_signal :
sig = (int) value;
if ((sig < 0) || (sig >= no_signal_names)) {
ensure((str = malloc(20 + 1)) != NULL);
sprintf(str, "%d", sig);
} else {
ensure((str = strdup(signal_names[sig])) != NULL);
}
break;
case fmt_error :
error = (int) value;
if ((error < 0) || (error >= no_error_names)) {
ensure((str = malloc(20 + 1)) != NULL);
sprintf(str, "%d", error);
} else {
ensure((str = strdup(error_names[error])) != NULL);
}
break;
case fmt_open_flags :
ensure((str = malloc(8 + 3 + 20 + 1)) != NULL);
switch (value & 3) {
case O_RDONLY :
sprintf(str, "O_RDONLY");
value -= O_RDONLY;
break;
case O_WRONLY :
sprintf(str, "O_WRONLY");
value -= O_WRONLY;
break;
case O_RDWR :
sprintf(str, "O_RDWR");
value -= O_RDWR;
break;
default :
sprintf(str, "0x%lx", value);
value = 0;
break;
}
if (value != 0) {
sprintf(str + strlen(str), "|0x%lx", value);
}
break;
case fmt_unknown :
ensure((str = strdup("..")) != NULL);
break;
case fmt_string :
if ((str = snarf_string(pid, (void *) value)) == NULL) {
str = format_value(pid, fmt_ptr, value, 0);
}
break;
case fmt_data :
if ((str = snarf_data(pid, (void *) value, opt)) == NULL) {
str = format_value(pid, fmt_ptr, value, 0);
}
break;
case fmt_string_array :
if ((str = snarf_string_array(pid, (void *) value)) == NULL) {
str = format_value(pid, fmt_ptr, value, 0);
}
break;
default :
diagnose("Unexpected display format");
break;
}
return str;
}
/*
* Determine whether size bytes of data are printable.
*/
int printable_data(data, size)
char *data;
int size;
{
int i;
for (i = 0; i < size; i++) {
if (!(isprint(data[i]))) {
switch (data[i]) {
case '\0' :
case '\t' :
case '\n' :
case '\f' :
case '\r' :
break;
default :
return 0;
break;
}
}
}
return 1;
}
/*
* Create a string representing size bytes of data.
*/
char *print_string(data, size)
char *data;
int size;
{
char *str, *s;
int i;
assert(size >= 0);
ensure((str = malloc(1 + size * 2 + 1 + 1)) != NULL);
s = str;
*(s++) = '"';
for (i = 0; i < size; i++) {
if ((!(isprint(data[i]))) || (data[i] == '"') || (data[i] == '\\')) {
*(s++) = '\\';
switch (data[i]) {
case '\0' :
*(s++) = '0';
break;
case '\t' :
*(s++) = 't';
break;
case '\n' :
*(s++) = 'n';
break;
case '\f' :
*(s++) = 'f';
break;
case '\r' :
*(s++) = 'r';
break;
case '"' :
case '\\' :
*(s++) = data[i];
break;
default :
diagnose("Attempted to display illegal character");
}
} else {
*(s++) = data[i];
}
}
*(s++) = '"';
*s = '\0';
return str;
}

View File

@ -1,499 +0,0 @@
/*
* Copyright (C) 1991 Gordon Irlam. All rights reserved.
*/
/*
* Definition of system calls for sparc trace generator.
*/
/*
* Imported declarations.
*/
#include "system_calls.h"
/*
* Table containing system calls, and their parameter profile.
*/
call_desc system_calls[] = {
/* 0 */ {"syscall", {fmt_dec, fmt_unknown}, fmt_dec},
/* 1 */ {"_exit", {fmt_dec}, fmt_none},
/* 2 */ {"fork", {fmt_none}, fmt_dec},
/* 3 */ {"read", {fmt_fd, fmt_post_data, FMT_SIZE}, fmt_post_data_size},
/* 4 */ {"write", {fmt_fd, fmt_data, fmt_data_size}, FMT_SIZE},
/* 5 */ {"open", {fmt_string, fmt_open_flags, FMT_FLAGS}, fmt_fd},
/* 6 */ {"close", {fmt_fd}, FMT_STATUS},
/* 7 */ {"wait4", {fmt_dec, fmt_ptr, FMT_FLAGS, fmt_ptr}, fmt_dec},
/* 8 */ {"creat", {fmt_string, FMT_FLAGS}, fmt_fd},
/* 9 */ {"link", {fmt_string, fmt_string}, FMT_STATUS},
/* 10 */ {"unlink", {fmt_string}, FMT_STATUS},
/* 11 */ {"_unknown_11[\"old execv\"]", {fmt_unknown}, fmt_unknown},
/*
* execv is now a library routine which calls execve, although
* Sun have not officially declared execv obsolete.
*/
/* 12 */ {"chdir", {fmt_string}, FMT_STATUS},
/* 13 */ {"_unknown_13[\"old time\"]", {fmt_unknown}, fmt_unknown},
/* 14 */ {"mknod", {fmt_string, FMT_FLAGS, FMT_FLAGS}, FMT_STATUS},
/* 15 */ {"chmod", {fmt_string, FMT_FLAGS}, FMT_STATUS},
/* 16 */ {"chown", {fmt_string, fmt_dec, fmt_dec}, FMT_STATUS},
/* 17 */ {"_brk", {fmt_ptr}, FMT_STATUS},
/* 18 */ {"_unknown_18[\"old stat\"]", {fmt_unknown}, fmt_unknown},
/* 19 */ {"lseek", {fmt_fd, FMT_SIZE, fmt_dec}, FMT_SIZE},
/* 20 */ {"getpid", {fmt_none}, fmt_dec},
/* 21 */ {"_unknown_21", {fmt_unknown}, fmt_unknown},
/* 22 */ {"umount[\"System V\"]", {fmt_string}, FMT_STATUS},
/* 23 */ {"_unknown_23[\"old setuid\"]", {fmt_unknown}, fmt_unknown},
/* 24 */ {"getuid", {fmt_none}, fmt_dec},
/* 25 */ {"_unknown_25[\"old System V stime\"]",
{fmt_unknown},
fmt_unknown},
/* 26 */ {"ptrace",
{fmt_dec, fmt_dec, fmt_ptr, fmt_dec, fmt_ptr},
fmt_dec},
/* 27 */ {"_unknown_27[\"old alarm\"]", {fmt_unknown}, fmt_unknown},
/* 28 */ {"_unknown_28[\"old fstat\"]", {fmt_unknown}, fmt_unknown},
/* 29 */ {"_unknown_29[\"old pause\"]", {fmt_unknown}, fmt_unknown},
/* 30 */ {"_unknown_30[\"old utime\"]", {fmt_unknown}, fmt_unknown},
/* 31 */ {"_unknown_31", {fmt_unknown}, fmt_unknown},
/* 32 */ {"_unknown_32", {fmt_unknown}, fmt_unknown},
/* 33 */ {"access", {fmt_string, FMT_FLAGS}, FMT_STATUS},
/* 34 */ {"_unknown_34[\"old nice\"]", {fmt_unknown}, fmt_unknown},
/* 35 */ {"_unknown_35[\"old ftime\"]", {fmt_unknown}, fmt_unknown},
/* 36 */ {"sync", {fmt_none}, fmt_none},
/* 37 */ {"kill", {fmt_dec, fmt_signal}, FMT_STATUS},
/* 38 */ {"stat", {fmt_string, fmt_ptr}, FMT_STATUS},
/* 39 */ {"_unknown_39[\"old setpgrp\"]", {fmt_unknown}, fmt_unknown},
/* 40 */ {"lstat", {fmt_string, fmt_ptr}, FMT_STATUS},
/* 41 */ {"dup", {fmt_fd}, fmt_fd},
/*
* Sun sometimes claim dup has 2 parameters.
*/
/* 42 */ {"pipe", {fmt_ptr}, FMT_STATUS},
/* 43 */ {"_unknown_43[\"old times\"]", {fmt_unknown}, fmt_unknown},
/* 44 */ {"profil", {fmt_ptr, FMT_SIZE, fmt_ptr, fmt_dec}, FMT_STATUS},
/* 45 */ {"_unknown_45", {fmt_unknown}, fmt_unknown},
/* 46 */ {"_unknown_46[\"old setgid\"]", {fmt_unknown}, fmt_unknown},
/* 47 */ {"getgid", {fmt_none}, fmt_dec},
/* 48 */ {"_unknown_48[\"old signal\"]", {fmt_unknown}, fmt_unknown},
/* 49 */ {"_unknown_49", {fmt_unknown}, fmt_unknown},
/* 50 */ {"_unknown_50", {fmt_unknown}, fmt_unknown},
/* 51 */ {"acct", {fmt_string}, FMT_STATUS},
/* 52 */ {"_unknown_52", {fmt_unknown}, fmt_unknown},
/* 53 */ {"mctl", {fmt_ptr, FMT_SIZE, fmt_dec, FMT_FLAGS}, FMT_STATUS},
/* 54 */ {"ioctl", {fmt_fd, FMT_FLAGS, fmt_ptr}, fmt_dec},
/* 55 */ {"reboot", {FMT_FLAGS, fmt_string}, FMT_STATUS},
/* 56 */ {"_unknown_56[\"old wait3\"]", {fmt_unknown}, fmt_unknown},
/* 57 */ {"symlink", {fmt_string, fmt_string}, FMT_STATUS},
/* 58 */ {"readlink",
{fmt_string, fmt_post_data, FMT_SIZE},
fmt_post_data_size},
/* 59 */ {"execve",
{fmt_string, fmt_string_array, fmt_string_array},
FMT_STATUS},
/* 60 */ {"umask", {FMT_FLAGS}, FMT_FLAGS},
/* 61 */ {"chroot", {fmt_string}, FMT_STATUS},
/* 62 */ {"fstat", {fmt_fd, fmt_ptr}, FMT_STATUS},
/* 63 */ {"_unknown_63", {fmt_unknown}, fmt_unknown},
/* 64 */ {"getpagesize", {fmt_none}, FMT_SIZE},
/* 65 */ {"_unknown_65[\"old msync\"]", {fmt_unknown}, fmt_unknown},
/*
* msync is now a library routine which calls mctl, although
* Sun have not officially declared msync obsolete.
*/
/* 66 */ {"vfork", {fmt_none}, fmt_dec},
/* 67 */ {"_unknown_67[\"old vread\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think vread can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 68 */ {"_unknown_68[\"old vwrite\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think vwrite can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 69 */ {"_unknown_69[\"old brk\"]", {fmt_unknown}, fmt_unknown},
/*
* Also referred to as sbrk. I don't think it can be generated
* by the standard libararies, although Sun have not officially
* declared it obsolete.
*/
/* 70 */ {"_unknown_70[\"old sstk\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think sstk can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 71 */ {"mmap",
{fmt_ptr, fmt_post_data_size, FMT_FLAGS, FMT_FLAGS, fmt_fd,
FMT_SIZE},
fmt_post_data},
/* 72 */ {"vadvise", {fmt_dec}, FMT_STATUS},
/*
* vadvise is currently still a valid system call, although Sun
* have said it is likely to disappear in the future.
*/
/* 73 */ {"munmap", {fmt_ptr, FMT_SIZE}, FMT_STATUS},
/* 74 */ {"mprotect", {fmt_ptr, FMT_SIZE, FMT_FLAGS}, FMT_STATUS},
/* 75 */ {"_unknown_75[\"old madvise\"]", {fmt_unknown}, fmt_unknown},
/*
* madvise is now a library routine which calls mctl, although
* Sun have not officially declared madvise obsolete.
*/
/* 76 */ {"vhangup", {fmt_none}, FMT_STATUS},
/*
* Sun sometimes claim vhangup has 1 parameter.
*/
/* 77 */ {"_unknown_77[\"old vlimit\"]", {fmt_unknown}, fmt_unknown},
/* 78 */ {"mincore", {fmt_ptr, FMT_SIZE, fmt_ptr}, FMT_STATUS},
/* 79 */ {"getgroups", {fmt_dec, fmt_ptr}, fmt_dec},
/* 80 */ {"setgroups", {fmt_dec, fmt_ptr}, FMT_STATUS},
/* 81 */ {"getpgrp", {fmt_dec}, fmt_dec},
/* 82 */ {"setpgrp", {fmt_dec, fmt_dec}, FMT_STATUS},
/* 83 */ {"setitimer", {fmt_dec, fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 84 */ {"_unknown_84[\"old wait\"]", {fmt_unknown}, fmt_unknown},
/*
* wait is now a library routine which calls wait4, although Sun
* have not officially declared wait obsolete.
*/
/* 85 */ {"swapon", {fmt_string}, FMT_STATUS},
/* 86 */ {"getitimer", {fmt_dec, fmt_ptr}, FMT_STATUS},
/* 87 */ {"gethostname", {fmt_post_string, FMT_SIZE}, FMT_STATUS},
/* 88 */ {"sethostname", {fmt_data, fmt_data_size}, FMT_STATUS},
/* 89 */ {"getdtablesize", {fmt_none}, fmt_dec},
/* 90 */ {"dup2", {fmt_fd, fmt_dec}, fmt_fd},
/* 91 */ {"_unknown_91[\"old getdopt\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think getdopt can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 92 */ {"fcntl", {fmt_fd, fmt_dec, fmt_dec}, fmt_dec},
/* 93 */ {"select",
{fmt_dec, fmt_ptr, fmt_ptr, fmt_ptr, fmt_ptr},
fmt_dec},
/* 94 */ {"_unknown_94[\"old setdopt\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think setdopt can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 95 */ {"fsync", {fmt_fd}, FMT_STATUS},
/* 96 */ {"setpriority", {fmt_dec, fmt_dec, fmt_dec}, FMT_STATUS},
/* 97 */ {"socket", {fmt_dec, fmt_dec, fmt_dec}, fmt_fd},
/* 98 */ {"connect", {fmt_fd, fmt_ptr, FMT_SIZE}, FMT_STATUS},
/* 99 */ {"accept", {fmt_fd, fmt_ptr, fmt_ptr}, fmt_fd},
/* 100 */ {"getpriority", {fmt_dec, fmt_dec}, fmt_dec},
/* 101 */ {"send", {fmt_fd, fmt_data, fmt_data_size, FMT_FLAGS}, FMT_SIZE},
/* 102 */ {"recv",
{fmt_fd, fmt_post_data, FMT_SIZE, FMT_FLAGS},
fmt_post_data_size},
/* 103 */ {"_unknown_103", {fmt_unknown}, fmt_unknown},
/* 104 */ {"bind", {fmt_fd, fmt_ptr, FMT_SIZE}, FMT_STATUS},
/* 105 */ {"setsockopt",
{fmt_fd, fmt_dec, fmt_dec, fmt_ptr, FMT_SIZE},
FMT_STATUS},
/* 106 */ {"listen", {fmt_fd, fmt_dec}, FMT_STATUS},
/* 107 */ {"_unknown_107[\"old vtimes\"]", {fmt_unknown}, fmt_unknown},
/* 108 */ {"_sigvec", {fmt_signal, fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 109 */ {"sigblock", {fmt_hex}, fmt_hex},
/* 110 */ {"sigsetmask", {fmt_hex}, fmt_hex},
/* 111 */ {"sigpause", {fmt_hex}, FMT_STATUS},
/* 112 */ {"sigstack", {fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 113 */ {"recvmsg", {fmt_fd, fmt_ptr, FMT_FLAGS}, FMT_SIZE},
/* 114 */ {"sendmsg", {fmt_fd, fmt_ptr, FMT_FLAGS}, FMT_SIZE},
/* 115 */ {"_unknown_115[\"vtrace\"]",
{fmt_dec, fmt_hex, fmt_hex},
fmt_unknown},
/*
* I am unsure of the parameters for vtrace.
*/
/* 116 */ {"gettimeofday", {fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 117 */ {"getrusage", {fmt_dec, fmt_ptr}, FMT_STATUS},
/* 118 */ {"getsockopt",
{fmt_fd, fmt_dec, fmt_dec, fmt_ptr, fmt_ptr},
FMT_STATUS},
/* 119 */ {"_unknown_119", {fmt_unknown}, fmt_unknown},
/* 120 */ {"readv", {fmt_fd, fmt_ptr, fmt_dec}, FMT_SIZE},
/* 121 */ {"writev", {fmt_fd, fmt_ptr, fmt_dec}, FMT_SIZE},
/* 122 */ {"settimeofday", {fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 123 */ {"fchown", {fmt_fd, fmt_dec, fmt_dec}, FMT_STATUS},
/* 124 */ {"fchmod", {fmt_fd, FMT_FLAGS}, FMT_STATUS},
/* 125 */ {"recvfrom",
{fmt_fd, fmt_post_data, FMT_SIZE, FMT_FLAGS, fmt_ptr, fmt_ptr},
fmt_post_data_size},
/* 126 */ {"setreuid", {fmt_dec, fmt_dec}, FMT_STATUS},
/* 127 */ {"setregid", {fmt_dec, fmt_dec}, FMT_STATUS},
/* 128 */ {"rename", {fmt_string, fmt_string}, FMT_STATUS},
/* 129 */ {"truncate", {fmt_string, FMT_SIZE}, FMT_STATUS},
/* 130 */ {"ftruncate", {fmt_fd, FMT_SIZE}, FMT_STATUS},
/* 131 */ {"flock", {fmt_fd, FMT_FLAGS}, FMT_STATUS},
/* 132 */ {"_unknown_132", {fmt_unknown}, fmt_unknown},
/* 133 */ {"sendto",
{fmt_fd, fmt_data, fmt_data_size, FMT_FLAGS, fmt_ptr, FMT_SIZE},
FMT_SIZE},
/* 134 */ {"shutdown", {fmt_fd, fmt_dec}, FMT_STATUS},
/* 135 */ {"socketpair", {fmt_dec, fmt_dec, fmt_dec, fmt_ptr}, FMT_STATUS},
/*
* Sun sometimes claim socketpair has 5 parameters.
*/
/* 136 */ {"mkdir", {fmt_string, FMT_FLAGS}, FMT_STATUS},
/* 137 */ {"rmdir", {fmt_string}, FMT_STATUS},
/* 138 */ {"utimes", {fmt_string, fmt_ptr}, FMT_STATUS},
/* 139 */ {"_sigcleanup", {fmt_ptr}, FMT_STATUS},
/* 140 */ {"adjtime", {fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 141 */ {"getpeername", {fmt_fd, fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 142 */ {"gethostid", {fmt_none}, fmt_hex},
/*
* Sun sometimes claim gethostid has 2 parameters.
*/
/* 143 */ {"_unknown_143", {fmt_unknown}, fmt_unknown},
/* 144 */ {"getrlimit", {fmt_dec, fmt_ptr}, FMT_STATUS},
/* 145 */ {"setrlimit", {fmt_dec, fmt_ptr}, FMT_STATUS},
/* 146 */ {"killpg", {fmt_dec, fmt_signal}, FMT_STATUS},
/* 147 */ {"_unknown_147", {fmt_unknown}, fmt_unknown},
/* 148 */ {"_unknown_148[\"old quota\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think quota can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 149 */ {"_unknown_149[\"old qquota\"]", {fmt_unknown}, fmt_unknown},
/*
* I don't think qquota can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 150 */ {"getsockname", {fmt_fd, fmt_ptr, fmt_ptr}, FMT_STATUS},
/* 151 */ {"getmsg", {fmt_fd, fmt_ptr, fmt_ptr, fmt_ptr}, fmt_dec},
/* 152 */ {"putmsg", {fmt_fd, fmt_ptr, fmt_ptr, FMT_FLAGS}, FMT_STATUS},
/* 153 */ {"poll", {fmt_ptr, fmt_dec, fmt_dec}, fmt_dec},
/* 154 */ {"_unknown_154", {fmt_unknown}, fmt_unknown},
/* 155 */ {"nfssvc", {fmt_fd}, FMT_STATUS},
/* 156 */ {"_unknown_156[\"old getdirentries\"]",
{fmt_unknown},
fmt_unknown},
/*
* I don't think getdirentries can be generated by the standard
* libararies, although Sun have not officially declared it
* obsolete.
*/
/* 157 */ {"statfs", {fmt_string, fmt_ptr}, FMT_STATUS},
/* 158 */ {"fstatfs", {fmt_fd, fmt_ptr}, FMT_STATUS},
/* 159 */ {"unmount", {fmt_string}, FMT_STATUS},
/* 160 */ {"async_daemon", {fmt_none}, fmt_none},
/* 161 */ {"nfs_getfh", {fmt_hex, fmt_hex}, fmt_unknown},
/*
* I am unsure of the parameters for nfs_getfh.
*/
/* 162 */ {"getdomainname", {fmt_post_string, FMT_SIZE}, FMT_STATUS},
/* 163 */ {"setdomainname", {fmt_data, fmt_data_size}, FMT_STATUS},
/* 164 */ {"rtschedule",
{fmt_hex, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
fmt_unknown},
/*
* I am unsure of the parameters for rtschedule.
*/
/* 165 */ {"quotactl",
{fmt_dec, fmt_string, fmt_dec, fmt_ptr},
FMT_STATUS},
/* 166 */ {"_exportfs", {fmt_string, fmt_ptr}, FMT_STATUS},
/* 167 */ {"mount",
{fmt_string, fmt_string, FMT_FLAGS, fmt_ptr},
FMT_STATUS},
/* 168 */ {"ustat", {fmt_hex, fmt_ptr}, FMT_STATUS},
/* 169 */ {"_semsys",
{fmt_dec, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
fmt_dec},
/* 170 */ {"_msgsys",
{fmt_dec, fmt_hex, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
fmt_dec},
/* 171 */ {"_shmsys", {fmt_dec, fmt_hex, fmt_hex, fmt_hex}, fmt_dec},
/* 172 */ {"_auditsys", {fmt_dec, fmt_hex, fmt_hex, fmt_hex}, fmt_dec},
/* 173 */ {"_rfssys",
{fmt_dec, fmt_hex, fmt_hex, fmt_hex, fmt_hex},
fmt_dec},
/* 174 */ {"getdents",
{fmt_fd, fmt_post_data, FMT_SIZE},
fmt_post_data_size},
/* 175 */ {"_setsid", {fmt_dec}, fmt_dec},
/* 176 */ {"fchdir", {fmt_fd}, FMT_STATUS},
/* 177 */ {"fchroot", {fmt_fd}, FMT_STATUS},
/* 178 */ {"vpixsys", {fmt_hex, fmt_hex}, fmt_unknown},
/*
* I am unsure of the parameters for vpixsys.
*/
/* 179 */ {"aioread",
{fmt_fd, fmt_ptr, FMT_SIZE, FMT_SIZE, fmt_dec, fmt_ptr},
FMT_STATUS},
/* 180 */ {"aiowrite",
{fmt_fd, fmt_data, fmt_data_size, FMT_SIZE, fmt_dec, fmt_ptr},
FMT_STATUS},
/* 181 */ {"aiowait", {fmt_ptr}, fmt_ptr},
/* 182 */ {"aiocancel", {fmt_ptr}, FMT_STATUS},
/* 183 */ {"sigpending", {fmt_ptr}, FMT_STATUS},
/* 184 */ {"_unknown_184", {fmt_unknown}, fmt_unknown},
/* 185 */ {"setpgid", {fmt_dec, fmt_dec}, FMT_STATUS},
/* 186 */ {"_pathconf", {fmt_string, fmt_dec}, fmt_dec},
/* 187 */ {"fpathconf", {fmt_fd, fmt_dec}, fmt_dec},
/* 188 */ {"sysconf", {fmt_dec}, fmt_dec},
/* 189 */ {"uname", {fmt_ptr}, FMT_STATUS}
/*
* Next 8 system calls are for loadable system calls. Not declared since
* they are likely to change from one O/S release to the next.
*/
};
int no_system_calls = sizeof(system_calls) / sizeof(call_desc);
call_desc system_call_open_simple =
/* 5 */ {"open", {fmt_string, fmt_open_flags}, fmt_fd};
/*
* Table containing signal names.
*/
char *signal_names[] = {
/* 0 */ "0",
/* 1 */ "SIGHUP",
/* 2 */ "SIGINT",
/* 3 */ "SIGQUIT",
/* 4 */ "SIGILL",
/* 5 */ "SIGTRAP",
/* 6 */ "SIGABRT",
/* 7 */ "SIGEMT",
/* 8 */ "SIGFPE",
/* 9 */ "SIGKILL",
/* 10 */ "SIGBUS",
/* 11 */ "SIGSEGV",
/* 12 */ "SIGSYS",
/* 13 */ "SIGPIPE",
/* 14 */ "SIGALRM",
/* 15 */ "SIGTERM",
/* 16 */ "SIGURG",
/* 17 */ "SIGSTOP",
/* 18 */ "SIGTSTP",
/* 19 */ "SIGCONT",
/* 20 */ "SIGCHLD",
/* 21 */ "SIGTTIN",
/* 22 */ "SIGTTOU",
/* 23 */ "SIGIO",
/* 24 */ "SIGXCPU",
/* 25 */ "SIGXFSZ",
/* 26 */ "SIGVTALRM",
/* 27 */ "SIGPROF",
/* 28 */ "SIGWINCH",
/* 29 */ "SIGLOST",
/* 30 */ "SIGUSR1",
/* 31 */ "SIGUSR2"
};
int no_signal_names = sizeof(signal_names) / sizeof(char *);
/*
* Table containing error messages.
*/
char *error_names[] = {
/* 0 */ "0",
/* 1 */ "EPERM",
/* 2 */ "ENOENT",
/* 3 */ "ESRCH",
/* 4 */ "EINTR",
/* 5 */ "EIO",
/* 6 */ "ENXIO",
/* 7 */ "E2BIG",
/* 8 */ "ENOEXEC",
/* 9 */ "EBADF",
/* 10 */ "ECHILD",
/* 11 */ "EAGAIN",
/* 12 */ "ENOMEM",
/* 13 */ "EACCES",
/* 14 */ "EFAULT",
/* 15 */ "ENOTBLK",
/* 16 */ "EBUSY",
/* 17 */ "EEXIST",
/* 18 */ "EXDEV",
/* 19 */ "ENODEV",
/* 20 */ "ENOTDIR",
/* 21 */ "EISDIR",
/* 22 */ "EINVAL",
/* 23 */ "ENFILE",
/* 24 */ "EMFILE",
/* 25 */ "ENOTTY",
/* 26 */ "ETXTBSY",
/* 27 */ "EFBIG",
/* 28 */ "ENOSPC",
/* 29 */ "ESPIPE",
/* 30 */ "EROFS",
/* 31 */ "EMLINK",
/* 32 */ "EPIPE",
/* 33 */ "EDOM",
/* 34 */ "ERANGE",
/* 35 */ "EWOULDBLOCK",
/* 36 */ "EINPROGRESS",
/* 37 */ "EALREADY",
/* 38 */ "ENOTSOCK",
/* 39 */ "EDESTADDRREQ",
/* 40 */ "EMSGSIZE",
/* 41 */ "EPROTOTYPE",
/* 42 */ "ENOPROTOOPT",
/* 43 */ "EPROTONOSUPPORT",
/* 44 */ "ESOCKTNOSUPPORT",
/* 45 */ "EOPNOTSUPP",
/* 46 */ "EPFNOSUPPORT",
/* 47 */ "EAFNOSUPPORT",
/* 48 */ "EADDRINUSE",
/* 49 */ "EADDRNOTAVAIL",
/* 50 */ "ENETDOWN",
/* 51 */ "ENETUNREACH",
/* 52 */ "ENETRESET",
/* 53 */ "ECONNABORTED",
/* 54 */ "ECONNRESET",
/* 55 */ "ENOBUFS",
/* 56 */ "EISCONN",
/* 57 */ "ENOTCONN",
/* 58 */ "ESHUTDOWN",
/* 59 */ "ETOOMANYREFS",
/* 60 */ "ETIMEDOUT",
/* 61 */ "ECONNREFUSED",
/* 62 */ "ELOOP",
/* 63 */ "ENAMETOOLONG",
/* 64 */ "EHOSTDOWN",
/* 65 */ "EHOSTUNREACH",
/* 66 */ "ENOTEMPTY",
/* 67 */ "EPROCLIM",
/* 68 */ "EUSERS",
/* 69 */ "EDQUOT",
/* 70 */ "ESTALE",
/* 71 */ "EREMOTE",
/* 72 */ "ENOSTR",
/* 73 */ "ETIME",
/* 74 */ "ENOSR",
/* 75 */ "ENOMSG",
/* 76 */ "EBADMSG",
/* 77 */ "EIDRM",
/* 78 */ "EDEADLK",
/* 79 */ "ENOLCK",
/* 80 */ "ENONET",
/* 81 */ "ERREMOTE",
/* 82 */ "ENOLINK",
/* 83 */ "EADV",
/* 84 */ "ESRMNT",
/* 85 */ "ECOMM",
/* 86 */ "EPROTO",
/* 87 */ "EMULTIHOP",
/* 88 */ "EDOTDOT",
/* 89 */ "EREMCHG",
/* 90 */ "ENOSYS"
};
int no_error_names = sizeof(error_names) / sizeof(char *);

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 1991 Gordon Irlam. All rights reserved.
*/
/*
* Declaration of system calls for sparc trace generator.
*/
#if !defined(SYSCALLS_H)
#define SYSCALLS_H 1
/*
* Imported declarations.
*/
#include "agent_msg.h"
/*
* Declaration of table containing system calls, and their parameter profile.
*/
/*
* Words, such as the parameters and results of system calls, are capable of
* being displayed in a number of different formats.
*
* fmt_none - indicates the absense of further arguments, functions that don't
* return a value, etc.
*
* The function format_value(..) can be used to display a word in one of the
* following formats.
*
* fmt_dec - a signed decimal number : 0, 21, -1
* fmt_hex - a unsigned hex number : 0x0, 0x15, 0xffffffff
* fmt_ptr - a pointer : NULL, 0x00000015, 0xffffffff
* fmt_fd - a file descriptor : fd0, fd15, fd-1
* fmt_signal - the name of a signal : 0, SIGTTIN, -1
* fmt_error - the name of an error : 0, EISDIR, -1
* fmt_open_flags - the flags to open : O_RDONLY, O_WRONLY|0x14, 0xffffffff
* fmt_unknown - representation unknown : .., .., ..
* fmt_string - if the null termintated string at word is printable displays
* the string within quotes, otherwise displays like fmt_ptr
* fmt_post_string - displays like fmt_ptr, value of word is also saved,
* following the system call a printable string exists at
* address word the address and the string will be displayed
* fmt_data - only permitted in argument lists, next argument must be
* format_data_size, if printable data exists at word having length
* specified by the next argument it is printed, otherwise displays
* like fmt_ptr
* fmt_data_size - displays like FMT_SIZE
* fmt_post_data - displays like fmt_ptr, value of word is also saved,
* following call if a printable length delimited string exists
* it will be displayed
* fmt_post_data_size - displays like FMT_SIZE, value is saved for use as
* length for fmt_post_data display format
* fmt_string_array - word is the address of a null terminted array of strings
* to be printed if possible
*
* Unlike the string formats which typically represent filenames it is not so
* important that length delimited data be fully displayed. When printable,
* it will be truncate much more harshly than the string formats.
*
* Only one item can be pending for display at the end of a system call.
*
* At a later date this program may be extended to display length delimited
* data as a hex dump if it is not printable.
*
* The following macros are employed to make it easy to alter how a whole
* class of values is displayed by changing their definition.
*
* FMT_STATUS - function calls that return 0 on success and -1 on error
* FMT_FLAGS - bit field objects
* FMT_SIZE - length of an object in bytes
*/
typedef enum fmt_type {fmt_none = 0, fmt_dec, fmt_hex, fmt_ptr, fmt_fd,
fmt_signal, fmt_error, fmt_open_flags, fmt_unknown, fmt_string,
fmt_post_string, fmt_data, fmt_post_data, fmt_data_size,
fmt_post_data_size, fmt_string_array} fmt_type;
#define FMT_STATUS fmt_none
#define FMT_FLAGS fmt_hex
#define FMT_SIZE fmt_dec
typedef struct _spa_call_desc {
char *name;
fmt_type arg[NO_PARAMS];
fmt_type result;
} spa_call_desc;
extern spa_call_desc spa_system_calls[];
extern int no_system_calls;
extern spa_call_desc spa_system_call_open_simple;
#define SPA_DATA_SIZE_LIMIT 20
#define SPA_STRING_SIZE_LIMIT 201
#define SPA_ARRAY_SIZE_LIMIT 21
/*
* Declaration of table containing signal names.
*/
extern char *spa_signal_names[];
extern int spa_no_signal_names;
/*
* Declaration of table containing error messages.
*/
char *spa_error_names[];
extern int spa_no_error_names;
#endif

View File

@ -19,8 +19,8 @@
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#ifndef _PSIM_CONFIG_H_
#define _PSIM_CONFIG_H_
/* endianness of the host/target:
@ -292,47 +292,141 @@ extern int current_model_issue;
GCC -O3 attempts to inline any function or procedure in scope. The
options below facilitate fine grained control over what is and what
isn't made inline. For instance it can control things down to a
specific modules static routines. This control is implemented in
two parts. Doing this allows the compiler to both eliminate the
overhead of function calls and (as a consequence) also eliminate
further dead code.
specific modules static routines. Doing this allows the compiler
to both eliminate the overhead of function calls and (as a
consequence) also eliminate further dead code.
Experementing with CISC (x86) I've found that I can achieve an
order of magintude speed improvement (x3-x5). In the case of RISC
(sparc) while the performance gain isn't as great it is still
significant.
On a CISC (x86) I've found that I can achieve an order of magintude
speed improvement (x3-x5). In the case of RISC (sparc) while the
performance gain isn't as great it is still significant.
Part One - Static functions: It is possible to control how static
functions within each module are to be compiled. On a per module
or global basis, it is possible to specify that a modules static
functions should be compiled inline. This is controled by the the
macro's STATIC_INLINE and INLINE_STATIC_<module>.
Each module is controled by the macro <module>_INLINE which can
have the values described below
Part Two - External functions: Again it is possible to allow the
inlining of calls to external functions. This is far more
complicated and much heaver on the compiler. In this case, it is
controled by the <module>_INLINE macro's. Where each can have a
value:
0 Do not inline any thing for the given module
0 Make a normal external call to functions in the module.
The following additional values are `bit fields' and can be
combined.
1 Include the module but to not inline functions within it.
This allows functions within the module to inline functions
from other modules that have been included.
1 Include the C file for the module into the file being compiled
but do not make the functions within the module inline.
2 Both include the module and inline functions contained within
it.
While of no apparent benefit, this makes it possible for the
included module, when compiled to inline its calls to what
would otherwize be external functions.
Finally, this is not for the faint harted. I've seen GCC get up to
200mb trying to compile what this can create */
2 Make external functions within the module `inline'. Thus if
the module is included into a file being compiled, calls to
its funtions can be eliminated. 2 implies 1.
4 Make internal (static) functions within the module `inline'.
In addition to this, modules have been put into two categories.
Simple modules - eg sim-endian.h bits.h
Because these modules are small and simple and do not have
any complex interpendencies they are configured, if
<module>_INLINE is so enabled, to inline themselves in all
modules that include those files.
For the default build, this is a real win as all byte
conversion and bit manipulation functions are inlined.
Complex modules - the rest
These are all handled using the files inline.h and inline.c.
psim.c includes the above which in turn include any remaining
code.
IMPLEMENTATION:
The inline ability is enabled by prefixing every data / function
declaration and definition with one of the following:
INLINE_<module>
Prefix to any global function that is a candidate for being
inline.
values - `', `static', `static INLINE'
EXTERN_<module>
Prefix to any global data structures for the module. Global
functions that are not to be inlined shall also be prefixed
with this.
values - `', `static', `static'
STATIC_INLINE_<module>
Prefix to any local (static) function that is a candidate for
being made inline.
values - `static', `static INLINE'
static
Prefix all local data structures. Local functions that are not
to be inlined shall also be prefixed with this.
values - `static', `static'
nb: will not work for modules that are being inlined for every
use (white lie).
extern
#ifndef _INLINE_C_
#endif
Prefix to any declaration of a global object (function or
variable) that should not be inlined and should have only one
definition. The #ifndef wrapper goes around the definition
propper to ensure that only one copy is generated.
nb: this will not work when a module is being inlined for every
use.
STATIC_<module>
Replaced by either `static' or `EXTERN_MODULE'.
REALITY CHECK:
This is not for the faint hearted. I've seen GCC get up to 200mb
trying to compile what this can create.
Some of the modules do not yet implement the WITH_INLINE_STATIC
option. Instead they use the macro STATIC_INLINE to control their
local function.
Because of the way that GCC parses __attribute__(), the macro's
need to be adjacent to the functioin name rather then at the start
of the line vis:
int STATIC_INLINE_MODULE f(void);
void INLINE_MODULE *g(void);
*/
#define REVEAL_MODULE 1
#define INLINE_MODULE 2
#define INCLUDE_MODULE (INLINE_MODULE | REVEAL_MODULE)
#define INLINE_LOCALS 4
#define ALL_INLINE 7
/* Your compilers inline reserved word */
#ifndef INLINE
#if defined(__GNUC__) && defined(__OPTIMIZE__) && \
(DEFAULT_INLINE || SIM_ENDIAN_INLINE || BITS_INLINE || CPU_INLINE || VM_INLINE || CORE_INLINE \
|| EVENTS_INLINE || MON_INLINE || INTERRUPTS_INLINE || REGISTERS_INLINE || DEVICE_TREE_INLINE \
|| DEVICES_INLINE || SPREG_INLINE || SEMANTICS_INLINE || IDECODE_INLINE || MODEL_INLINE)
#if defined(__GNUC__) && defined(__OPTIMIZE__)
#define INLINE __inline__
#else
#define INLINE /*inline*/
@ -348,29 +442,30 @@ extern int current_model_issue;
/* Default macro to simplify control several of key the inlines */
#ifndef DEFAULT_INLINE
#define DEFAULT_INLINE 0
#define DEFAULT_INLINE INLINE_LOCALS
#endif
/* Code that converts between hosts and target byte order. Used on
every memory access (instruction and data). (See sim-endian.h for
additional byte swapping configuration information) */
every memory access (instruction and data). See sim-endian.h for
additional byte swapping configuration information. This module
can inline for all callers */
#ifndef SIM_ENDIAN_INLINE
#define SIM_ENDIAN_INLINE DEFAULT_INLINE
#define SIM_ENDIAN_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
#endif
/* Low level bit manipulation routines used to work around a compiler
bug in 2.6.3. */
/* Low level bit manipulation routines. This module can inline for all
callers */
#ifndef BITS_INLINE
#define BITS_INLINE DEFAULT_INLINE
#define BITS_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
#endif
/* Code that gives access to various CPU internals such as registers.
Used every time an instruction is executed */
#ifndef CPU_INLINE
#define CPU_INLINE DEFAULT_INLINE
#define CPU_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
#endif
/* Code that translates between an effective and real address. Used
@ -391,27 +486,27 @@ extern int current_model_issue;
Called once per instruction cycle */
#ifndef EVENTS_INLINE
#define EVENTS_INLINE DEFAULT_INLINE
#define EVENTS_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
#endif
/* Code monotoring the processors performance. It counts events on
every instruction cycle */
#ifndef MON_INLINE
#define MON_INLINE DEFAULT_INLINE
#define MON_INLINE (DEFAULT_INLINE ? ALL_INLINE : 0)
#endif
/* Code called on the rare occasions that an interrupt occures. */
#ifndef INTERRUPTS_INLINE
#define INTERRUPTS_INLINE 0
#define INTERRUPTS_INLINE DEFAULT_INLINE
#endif
/* Code called on the rare occasion that either gdb or the device tree
need to manipulate a register within a processor */
#ifndef REGISTERS_INLINE
#define REGISTERS_INLINE 0
#define REGISTERS_INLINE DEFAULT_INLINE
#endif
/* Code called on the rare occasion that a processor is manipulating
@ -424,12 +519,8 @@ extern int current_model_issue;
devices inline. It reports the message: device_tree_find_node()
not a leaf */
#ifndef DEVICE_TREE_INLINE
#define DEVICE_TREE_INLINE 0
#endif
#ifndef DEVICES_INLINE
#define DEVICES_INLINE 0
#ifndef DEVICE_INLINE
#define DEVICE_INLINE DEFAULT_INLINE
#endif
/* Code called whenever information on a Special Purpose Register is
@ -452,7 +543,7 @@ extern int current_model_issue;
inline all of their called functions */
#ifndef SEMANTICS_INLINE
#define SEMANTICS_INLINE (DEFAULT_INLINE ? 1 : 0)
#define SEMANTICS_INLINE DEFAULT_INLINE
#endif
/* Code to decode an instruction. Normally called on every instruction
@ -468,7 +559,7 @@ extern int current_model_issue;
of the code, which is not friendly to the cache. */
#ifndef MODEL_INLINE
#define MODEL_INLINE (DEFAULT_INLINE ? 1 : 0)
#define MODEL_INLINE DEFAULT_INLINE
#endif
/* Code to print out what options we were compiled with. Because this
@ -477,7 +568,14 @@ extern int current_model_issue;
routines will be pulled in twice. */
#ifndef OPTIONS_INLINE
#define OPTIONS_INLINE (DEFAULT_INLINE ? 1 : 0)
#define OPTIONS_INLINE DEFAULT_INLINE
#endif
#endif /* _CONFIG_H */
/* Code to emulate os or rom compatibility. Called on the rare
occasion that the OS or ROM code is being emulated. */
#ifndef OS_EMUL_INLINE
#define OS_EMUL_INLINE 0
#endif
#endif /* _PSIM_CONFIG_H */

View File

@ -22,22 +22,12 @@
#ifndef _VM_C_
#define _VM_C_
#ifndef STATIC_INLINE_VM
#define STATIC_INLINE_VM STATIC_INLINE
#endif
#include "basics.h"
#include "registers.h"
#include "device_tree.h"
#include "device.h"
#include "corefile.h"
#include "vm.h"
#include "interrupts.h"
#include "mon.h"
/* OEA vs VEA
@ -64,7 +54,10 @@
structures is maintained by updating the structures at
`synchronization' points. Of particular note is that (at the time
of writing) the memory data types for BAT registers are rebuilt
when ever the processor moves between problem and system states */
when ever the processor moves between problem and system states.
Unpacked values are stored in the OEA so that they correctly align
to where they will be needed by the PTE address. */
/* Protection table:
@ -145,7 +138,7 @@ enum _om_segment_tlb_constants {
typedef struct _om_segment_tlb_entry {
int key[nr_om_modes];
om_access_types invalid_access; /* set to instruction if no_execute bit */
unsigned_word masked_virtual_segment_id;
unsigned_word masked_virtual_segment_id; /* aligned ready for pte addr */
#if (WITH_TARGET_WORD_BITSIZE == 64)
int is_valid;
unsigned_word masked_effective_segment_id;
@ -178,9 +171,14 @@ enum _om_page_tlb_constants {
nr_om_page_tlb_constants
};
enum {
invalid_tlb_vsid = MASK(0, 63),
};
typedef struct _om_page_tlb_entry {
int valid;
int protection;
int changed;
unsigned_word real_address_of_pte_1;
unsigned_word masked_virtual_segment_id;
unsigned_word masked_page;
unsigned_word masked_real_page_number;
@ -219,6 +217,9 @@ typedef struct _om_map {
/* physical memory for fetching page table entries */
core_map *physical;
/* address xor for PPC endian */
unsigned xor[WITH_XOR_ENDIAN];
} om_map;
@ -274,7 +275,7 @@ struct _vm {
/* OEA Support procedures */
STATIC_INLINE_VM unsigned_word
unsigned_word STATIC_INLINE_VM
om_segment_tlb_index(unsigned_word ea)
{
unsigned_word index = EXTRACTED(ea,
@ -283,7 +284,7 @@ om_segment_tlb_index(unsigned_word ea)
return index;
}
STATIC_INLINE_VM unsigned_word
unsigned_word STATIC_INLINE_VM
om_page_tlb_index(unsigned_word ea)
{
unsigned_word index = EXTRACTED(ea,
@ -292,23 +293,131 @@ om_page_tlb_index(unsigned_word ea)
return index;
}
STATIC_INLINE_VM unsigned_word
om_masked_page(unsigned_word ea)
unsigned_word STATIC_INLINE_VM
om_hash_page(unsigned_word masked_vsid,
unsigned_word ea)
{
unsigned_word masked_page = MASKED(ea, 36, 51);
return masked_page;
unsigned_word extracted_ea = EXTRACTED(ea, 36, 51);
#if (WITH_TARGET_WORD_BITSIZE == 32)
return masked_vsid ^ INSERTED32(extracted_ea, 7, 31-6);
#endif
#if (WITH_TARGET_WORD_BITSIZE == 64)
return masked_vsid ^ INSERTED64(extracted_ea, 18, 63-7);
#endif
}
STATIC_INLINE_VM unsigned_word
om_masked_byte(unsigned_word ea)
unsigned_word STATIC_INLINE_VM
om_pte_0_api(unsigned_word pte_0)
{
unsigned_word masked_byte = MASKED(ea, 52, 63);
return masked_byte;
#if (WITH_TARGET_WORD_BITSIZE == 32)
return EXTRACTED32(pte_0, 26, 31);
#endif
#if (WITH_TARGET_WORD_BITSIZE == 64)
return EXTRACTED64(pte_0, 52, 56);
#endif
}
unsigned_word STATIC_INLINE_VM
om_pte_0_hash(unsigned_word pte_0)
{
#if (WITH_TARGET_WORD_BITSIZE == 32)
return EXTRACTED32(pte_0, 25, 25);
#endif
#if (WITH_TARGET_WORD_BITSIZE == 64)
return EXTRACTED64(pte_0, 62, 62);
#endif
}
int STATIC_INLINE_VM
om_pte_0_valid(unsigned_word pte_0)
{
#if (WITH_TARGET_WORD_BITSIZE == 32)
return MASKED32(pte_0, 0, 0) != 0;
#endif
#if (WITH_TARGET_WORD_BITSIZE == 64)
return MASKED64(pte_0, 63, 63) != 0;
#endif
}
unsigned_word STATIC_INLINE_VM
om_ea_masked_page(unsigned_word ea)
{
return MASKED(ea, 36, 51);
}
unsigned_word STATIC_INLINE_VM
om_ea_masked_byte(unsigned_word ea)
{
return MASKED(ea, 52, 63);
}
unsigned_word STATIC_INLINE_VM
om_pte_0_masked_vsid(unsigned_word pte_0)
{
return INSERTED32(EXTRACTED32(pte_0, 1, 24), 7-5, 31-6);
}
unsigned_word STATIC_INLINE_VM
om_pte_1_pp(unsigned_word pte_1)
{
return MASKED(pte_1, 62, 63); /*PP*/
}
int STATIC_INLINE_VM
om_pte_1_referenced(unsigned_word pte_1)
{
return EXTRACTED(pte_1, 55, 55);
}
int STATIC_INLINE_VM
om_pte_1_changed(unsigned_word pte_1)
{
return EXTRACTED(pte_1, 56, 56);
}
int STATIC_INLINE_VM
om_pte_1_masked_rpn(unsigned_word pte_1)
{
return MASKED(pte_1, 0, 51); /*RPN*/
}
unsigned_word STATIC_INLINE_VM
om_ea_api(unsigned_word ea)
{
return EXTRACTED(ea, 36, 41);
}
/* Page and Segment table read/write operators, these need to still
account for the PPC's XOR operation */
INLINE_VM vm *
unsigned_word STATIC_INLINE_VM
om_read_word(om_map *map,
unsigned_word ra,
cpu *processor,
unsigned_word cia)
{
if (WITH_XOR_ENDIAN)
ra ^= map->xor[sizeof(instruction_word) - 1];
return core_map_read_word(map->physical, ra, processor, cia);
}
void STATIC_INLINE_VM
om_write_word(om_map *map,
unsigned_word ra,
unsigned_word val,
cpu *processor,
unsigned_word cia)
{
if (WITH_XOR_ENDIAN)
ra ^= map->xor[sizeof(instruction_word) - 1];
core_map_write_word(map->physical, ra, val, processor, cia);
}
/* Bring things into existance */
vm INLINE_VM *
vm_create(core *physical)
{
vm *virtual;
@ -351,7 +460,7 @@ vm_create(core *physical)
}
STATIC_INLINE_VM om_bat *
om_bat STATIC_INLINE_VM *
om_effective_to_bat(om_map *map,
unsigned_word ea)
{
@ -371,7 +480,7 @@ om_effective_to_bat(om_map *map,
}
STATIC_INLINE_VM om_segment_tlb_entry *
om_segment_tlb_entry STATIC_INLINE_VM *
om_effective_to_virtual(om_map *map,
unsigned_word ea,
cpu *processor,
@ -407,9 +516,10 @@ om_effective_to_virtual(om_map *map,
segment_table_entry += sizeof_segment_table_entry) {
/* byte order? */
unsigned_word segment_table_entry_dword_0 =
core_map_read_8(map->physical, segment_table_entry, processor, cia);
om_read_word(map->physical, segment_table_entry, processor, cia);
unsigned_word segment_table_entry_dword_1 =
core_map_read_8(map->physical, segment_table_entry + 8, processor, cia);
om_read_word(map->physical, segment_table_entry + 8,
processor, cia);
int is_valid = MASKED64(segment_table_entry_dword_0, 56, 56) != 0;
unsigned_word masked_effective_segment_id =
MASKED64(segment_table_entry_dword_0, 0, 35);
@ -430,7 +540,8 @@ om_effective_to_virtual(om_map *map,
? om_instruction_read
: om_access_any);
segment_tlb_entry->masked_virtual_segment_id =
MASKED(segment_table_entry_dword_1, 0, 51);
INSERTED64(EXTRACTED64(segment_table_entry_dword_1, 0, 51),
18-13, 63-7); /* align ready for pte addr */
return segment_tlb_entry;
}
}
@ -443,7 +554,7 @@ om_effective_to_virtual(om_map *map,
STATIC_INLINE_VM om_page_tlb_entry *
om_page_tlb_entry STATIC_INLINE_VM *
om_virtual_to_real(om_map *map,
unsigned_word ea,
om_segment_tlb_entry *segment_tlb_entry,
@ -455,46 +566,69 @@ om_virtual_to_real(om_map *map,
+ om_page_tlb_index(ea));
/* is it a tlb hit? */
if (page_tlb_entry->valid
&& (page_tlb_entry->masked_virtual_segment_id ==
segment_tlb_entry->masked_virtual_segment_id)
&& (page_tlb_entry->masked_page == om_masked_page(ea))) {
error("fixme - it is not a hit if direction/update bits do not match\n");
if ((page_tlb_entry->masked_virtual_segment_id
== segment_tlb_entry->masked_virtual_segment_id)
&& (page_tlb_entry->masked_page
== om_ea_masked_page(ea))) {
TRACE(trace_vm, ("ea=0x%lx - tlb hit - tlb=0x%lx\n",
(long)ea, (long)page_tlb_entry));
return page_tlb_entry;
}
/* drats, it is a tlb miss */
{
unsigned_word page_hash = (segment_tlb_entry->masked_virtual_segment_id
^ om_masked_page(ea));
unsigned_word page_hash =
om_hash_page(segment_tlb_entry->masked_virtual_segment_id, ea);
int current_hash;
for (current_hash = 0; current_hash < 2; current_hash += 1) {
unsigned_word real_address_of_pte_group =
(map->real_address_of_page_table
| (page_hash & map->page_table_hash_mask));
unsigned_word real_address_of_pte;
for (real_address_of_pte = real_address_of_pte_group;
real_address_of_pte < (real_address_of_pte_group
+ sizeof_pte_group);
real_address_of_pte += sizeof_pte) {
unsigned_word pte_word_0 =
core_map_read_word(map->physical,
real_address_of_pte,
processor, cia);
unsigned_word pte_word_1 =
core_map_read_word(map->physical,
real_address_of_pte + sizeof_pte / 2,
processor, cia);
error("fixme - check pte hit %ld %ld\n",
(long)pte_word_0,
(long)pte_word_1);
if (1) {
error("fixme - update the page_tlb\n");
page_tlb_entry->valid = 1;
page_tlb_entry->protection = 0;
page_tlb_entry->masked_virtual_segment_id = 0;
page_tlb_entry->masked_page = 0;
page_tlb_entry->masked_real_page_number = 0;
unsigned_word real_address_of_pte_0;
TRACE(trace_vm,
("ea=0x%lx - htab search - pteg=0x%lx htab=0x%lx mask=0x%lx hash=0x%lx\n",
(long)ea, (long)real_address_of_pte_group,
map->real_address_of_page_table,
map->page_table_hash_mask,
page_hash));
for (real_address_of_pte_0 = real_address_of_pte_group;
real_address_of_pte_0 < (real_address_of_pte_group
+ sizeof_pte_group);
real_address_of_pte_0 += sizeof_pte) {
unsigned_word pte_0 = om_read_word(map,
real_address_of_pte_0,
processor, cia);
/* did we hit? */
if (om_pte_0_valid(pte_0)
&& (current_hash == om_pte_0_hash(pte_0))
&& (segment_tlb_entry->masked_virtual_segment_id
== om_pte_0_masked_vsid(pte_0))
&& (om_ea_api(ea) == om_pte_0_api(pte_0))) {
unsigned_word real_address_of_pte_1 = (real_address_of_pte_0
+ sizeof_pte / 2);
unsigned_word pte_1 = om_read_word(map,
real_address_of_pte_1,
processor, cia);
page_tlb_entry->protection = om_pte_1_pp(pte_1);
page_tlb_entry->changed = om_pte_1_changed(pte_1);
page_tlb_entry->masked_virtual_segment_id = segment_tlb_entry->masked_virtual_segment_id;
page_tlb_entry->masked_page = om_ea_masked_page(ea);
page_tlb_entry->masked_real_page_number = om_pte_1_masked_rpn(pte_1);
page_tlb_entry->real_address_of_pte_1 = real_address_of_pte_1;
if (!om_pte_1_referenced(pte_1)) {
om_write_word(map,
real_address_of_pte_1,
pte_1 | BIT(55),
processor, cia);
TRACE(trace_vm,
("ea=0x%lx - htab hit - set ref - tlb=0x%lx &pte1=0x%lx\n",
(long)ea, page_tlb_entry, (long)real_address_of_pte_1));
}
else {
TRACE(trace_vm,
("ea=0x%lx - htab hit - tlb=0x%lx &pte1=0x%lx\n",
(long)ea, page_tlb_entry, (long)real_address_of_pte_1));
}
return page_tlb_entry;
}
}
@ -505,7 +639,7 @@ om_virtual_to_real(om_map *map,
}
static void
void STATIC_INLINE_VM
om_interrupt(cpu *processor,
unsigned_word cia,
unsigned_word ea,
@ -529,7 +663,7 @@ om_interrupt(cpu *processor,
}
STATIC_INLINE_VM unsigned_word
unsigned_word STATIC_INLINE_VM
om_translate_effective_to_real(om_map *map,
unsigned_word ea,
om_access_types access,
@ -544,9 +678,7 @@ om_translate_effective_to_real(om_map *map,
if (!map->is_relocate) {
ra = ea;
TRACE(trace_vm, ("%s, direct map, ea=0x%x\n",
"om_translate_effective_to_real",
ea));
TRACE(trace_vm, ("ea=0x%lx - direct map - ra=0x%lx", (long)ea, (long)ra));
return ra;
}
@ -554,9 +686,7 @@ om_translate_effective_to_real(om_map *map,
bat = om_effective_to_bat(map, ea);
if (bat != NULL) {
if (!om_valid_access[1][bat->protection_bits][access]) {
TRACE(trace_vm, ("%s, bat protection violation, ea=0x%x\n",
"om_translate_effective_to_real",
ea));
TRACE(trace_vm, ("ea=0x%lx - bat access violation\n", (long)ea));
if (abort)
om_interrupt(processor, cia, ea, access,
protection_violation_storage_interrupt);
@ -565,9 +695,8 @@ om_translate_effective_to_real(om_map *map,
}
ra = ((ea & bat->block_length_mask) | bat->block_real_page_number);
TRACE(trace_vm, ("%s, bat translation, ea=0x%x, ra=0x%x\n",
"om_translate_effective_to_real",
ea, ra));
TRACE(trace_vm, ("ea=0x%lx - bat translation - ra=0x%lx\n",
(long)ea, (long)ra));
return ra;
}
@ -575,9 +704,7 @@ om_translate_effective_to_real(om_map *map,
segment_tlb_entry = om_effective_to_virtual(map, ea, processor, cia);
#if (WITH_TARGET_WORD_BITSIZE == 64)
if (segment_tlb_entry == NULL) {
TRACE(trace_vm, ("%s, segment tlb lookup failed - ea=0x%x\n",
"om_translate_effective_to_real",
ea));
TRACE(trace_vm, ("ea=0x%lx - segment tlb miss\n", (long)ea));
if (abort)
om_interrupt(processor, cia, ea, access,
segment_table_miss_storage_interrupt);
@ -587,9 +714,7 @@ om_translate_effective_to_real(om_map *map,
#endif
/* check for invalid segment access type */
if (segment_tlb_entry->invalid_access == access) {
TRACE(trace_vm, ("%s, segment tlb access invalid - ea=0x%x\n",
"om_translate_effective_to_real",
ea));
TRACE(trace_vm, ("ea=0x%lx - segment access invalid\n", (long)ea));
if (abort)
om_interrupt(processor, cia, ea, access,
protection_violation_storage_interrupt);
@ -602,9 +727,7 @@ om_translate_effective_to_real(om_map *map,
access,
processor, cia);
if (page_tlb_entry == NULL) {
TRACE(trace_vm, ("%s, page tlb lookup failed - ea=0x%x\n",
"om_translate_effective_to_real",
ea));
TRACE(trace_vm, ("ea=0x%lx - page tlb miss\n", (long)ea));
if (abort)
om_interrupt(processor, cia, ea, access,
hash_table_miss_storage_interrupt);
@ -615,9 +738,7 @@ om_translate_effective_to_real(om_map *map,
[segment_tlb_entry->key[map->is_problem_state]]
[page_tlb_entry->protection]
[access])) {
TRACE(trace_vm, ("%s, page tlb access invalid - ea=0x%x\n",
"om_translate_effective_to_real",
ea));
TRACE(trace_vm, ("ea=0x%lx - page tlb access violation\n", (long)ea));
if (abort)
om_interrupt(processor, cia, ea, access,
protection_violation_storage_interrupt);
@ -625,11 +746,23 @@ om_translate_effective_to_real(om_map *map,
return MASK(0, 63);
}
ra = (page_tlb_entry->masked_real_page_number
| om_masked_byte(ea));
TRACE(trace_vm, ("%s, page - ea=0x%x, ra=0x%x\n",
"om_translate_effective_to_real",
ea, ra));
/* update change bit as needed */
if (access == om_data_write &&!page_tlb_entry->changed) {
unsigned_word pte_1 = om_read_word(map,
page_tlb_entry->real_address_of_pte_1,
processor, cia);
om_write_word(map,
page_tlb_entry->real_address_of_pte_1,
pte_1 | BIT(56),
processor, cia);
TRACE(trace_vm, ("ea=0x%lx - set change bit - tlb=0x%lx &pte1=0x%lx\n",
(long)ea, (long)page_tlb_entry,
(long)page_tlb_entry->real_address_of_pte_1));
}
ra = (page_tlb_entry->masked_real_page_number | om_ea_masked_byte(ea));
TRACE(trace_vm, ("ea=0x%lx - page translation - ra=0x%lx\n",
(long)ea, (long)ra));
return ra;
}
@ -640,7 +773,7 @@ om_translate_effective_to_real(om_map *map,
/* rebuild all the relevant bat information */
STATIC_INLINE_VM void
void STATIC_INLINE_VM
om_unpack_bat(om_bat *bat,
spreg ubat,
spreg lbat)
@ -660,7 +793,7 @@ om_unpack_bat(om_bat *bat,
/* rebuild the given bat table */
STATIC_INLINE_VM void
void STATIC_INLINE_VM
om_unpack_bats(om_bats *bats,
spreg *raw_bats,
msreg msr)
@ -682,7 +815,7 @@ om_unpack_bats(om_bats *bats,
#if (WITH_TARGET_WORD_BITSIZE == 32)
STATIC_INLINE_VM void
void STATIC_INLINE_VM
om_unpack_sr(vm *virtual,
sreg *srs,
int which_sr)
@ -709,13 +842,15 @@ om_unpack_sr(vm *virtual,
segment_tlb_entry->invalid_access = (MASKED32(new_sr_value, 3, 3)
? om_instruction_read
: om_access_any);
segment_tlb_entry->masked_virtual_segment_id = MASKED32(new_sr_value, 8, 31);
segment_tlb_entry->masked_virtual_segment_id =
INSERTED32(EXTRACTED32(new_sr_value, 8, 31),
7-5, 31-6); /* align ready for pte address */
}
#endif
#if (WITH_TARGET_WORD_BITSIZE == 32)
STATIC_INLINE_VM void
void STATIC_INLINE_VM
om_unpack_srs(vm *virtual,
sreg *srs)
{
@ -729,7 +864,7 @@ om_unpack_srs(vm *virtual,
/* Rebuild all the data structures for the new context as specifed by
the passed registers */
INLINE_VM void
void INLINE_VM
vm_synchronize_context(vm *virtual,
spreg *sprs,
sreg *srs,
@ -740,33 +875,32 @@ vm_synchronize_context(vm *virtual,
int problem_state = (msr & msr_problem_state) != 0;
int data_relocate = (msr & msr_data_relocate) != 0;
int instruction_relocate = (msr & msr_instruction_relocate) != 0;
int little_endian = (msr & msr_little_endian_mode) != 0;
unsigned_word page_table_hash_mask;
unsigned_word real_address_of_page_table;
/* update current processor mode */
virtual->instruction_map.translation.is_relocate = instruction_relocate;
virtual->instruction_map.translation.is_problem_state = problem_state;
virtual->data_map.translation.is_relocate = data_relocate;
virtual->data_map.translation.is_problem_state = problem_state;
/* update bat registers for the new context */
om_unpack_bats(&virtual->ibats, &sprs[spr_ibat0u], msr);
om_unpack_bats(&virtual->dbats, &sprs[spr_dbat0u], msr);
/* unpack SDR1 - the storage description register 1 */
#if (WITH_TARGET_WORD_BITSIZE == 64)
real_address_of_page_table = EXTRACTED64(sprs[spr_sdr1], 0, 45);
page_table_hash_mask = MASK64(47-EXTRACTED64(sprs[spr_sdr1], 59, 63),
57);
real_address_of_page_table = MASKED64(sprs[spr_sdr1], 0, 45);
page_table_hash_mask = MASK64(18+28-EXTRACTED64(sprs[spr_sdr1], 59, 63),
63-7);
#endif
#if (WITH_TARGET_WORD_BITSIZE == 32)
real_address_of_page_table = EXTRACTED32(sprs[spr_sdr1], 0, 15);
page_table_hash_mask = ((EXTRACTED32(sprs[spr_sdr1], 23, 31) << (10+6))
| MASK32(16, 25));
real_address_of_page_table = MASKED32(sprs[spr_sdr1], 0, 15);
page_table_hash_mask = (INSERTED32(EXTRACTED32(sprs[spr_sdr1], 23, 31),
7, 7+9-1)
| MASK32(7+9, 31-6));
#endif
virtual->instruction_map.translation.real_address_of_page_table = real_address_of_page_table;
virtual->instruction_map.translation.page_table_hash_mask = page_table_hash_mask;
@ -774,28 +908,52 @@ vm_synchronize_context(vm *virtual,
virtual->data_map.translation.page_table_hash_mask = page_table_hash_mask;
#if (WITH_TARGET_WORD_BITSIZE == 32)
/* unpack the segment tlb registers */
#if (WITH_TARGET_WORD_BITSIZE == 32)
om_unpack_srs(virtual, srs);
#endif
/* set up the XOR registers if the current endian mode conflicts
with what is in the MSR */
if (WITH_XOR_ENDIAN) {
int i = 1;
unsigned mask;
if ((little_endian && CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
|| (!little_endian && CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN))
mask = 0;
else
mask = WITH_XOR_ENDIAN - 1;
while (i - 1 < WITH_XOR_ENDIAN) {
virtual->instruction_map.translation.xor[i-1] = mask;
virtual->data_map.translation.xor[i-1] = mask;
mask = (mask << 1) & (WITH_XOR_ENDIAN - 1);
i = i * 2;
}
}
else {
/* don't allow the processor to change endian modes */
if ((little_endian && CURRENT_TARGET_BYTE_ORDER != LITTLE_ENDIAN)
|| (!little_endian && CURRENT_TARGET_BYTE_ORDER != LITTLE_ENDIAN))
error("vm_synchronize_context() - unsuported change of byte order\n");
}
}
INLINE_VM vm_data_map *
vm_data_map INLINE_VM *
vm_create_data_map(vm *memory)
{
return &memory->data_map;
}
INLINE_VM vm_instruction_map *
vm_instruction_map INLINE_VM *
vm_create_instruction_map(vm *memory)
{
return &memory->instruction_map;
}
STATIC_INLINE_VM unsigned_word
unsigned_word STATIC_INLINE_VM
vm_translate(om_map *map,
unsigned_word ea,
om_access_types access,
@ -818,7 +976,7 @@ vm_translate(om_map *map,
}
INLINE_VM unsigned_word
unsigned_word INLINE_VM
vm_real_data_addr(vm_data_map *map,
unsigned_word ea,
int is_read,
@ -834,7 +992,7 @@ vm_real_data_addr(vm_data_map *map,
}
INLINE_VM unsigned_word
unsigned_word INLINE_VM
vm_real_instruction_addr(vm_instruction_map *map,
cpu *processor,
unsigned_word cia)
@ -847,18 +1005,20 @@ vm_real_instruction_addr(vm_instruction_map *map,
1); /*abort*/
}
INLINE_VM instruction_word
instruction_word INLINE_VM
vm_instruction_map_read(vm_instruction_map *map,
cpu *processor,
unsigned_word cia)
{
unsigned_word ra = vm_real_instruction_addr(map, processor, cia);
ASSERT((cia & 0x3) == 0); /* always aligned */
if (WITH_XOR_ENDIAN)
ra ^= map->translation.xor[sizeof(instruction_word) - 1];
return core_map_read_4(map->code, ra, processor, cia);
}
INLINE_VM int
int INLINE_VM
vm_data_map_read_buffer(vm_data_map *map,
void *target,
unsigned_word addr,
@ -875,7 +1035,9 @@ vm_data_map_read_buffer(vm_data_map *map,
0); /*dont-abort*/
if (ra == MASK(0, 63))
break;
if (core_map_read_buffer(map->read, &byte, ea, sizeof(byte))
if (WITH_XOR_ENDIAN)
ra ^= map->translation.xor[0];
if (core_map_read_buffer(map->read, &byte, ra, sizeof(byte))
!= sizeof(byte))
break;
((unsigned_1*)target)[count] = T2H_1(byte);
@ -884,7 +1046,7 @@ vm_data_map_read_buffer(vm_data_map *map,
}
INLINE_VM int
int INLINE_VM
vm_data_map_write_buffer(vm_data_map *map,
const void *source,
unsigned_word addr,
@ -902,6 +1064,8 @@ vm_data_map_write_buffer(vm_data_map *map,
0); /*dont-abort*/
if (ra == MASK(0, 63))
break;
if (WITH_XOR_ENDIAN)
ra ^= map->translation.xor[0];
byte = T2H_1(((unsigned_1*)source)[count]);
if (core_map_write_buffer((violate_read_only_section
? map->read
@ -915,25 +1079,25 @@ vm_data_map_write_buffer(vm_data_map *map,
/* define the read/write 1/2/4/8/word functions */
#undef N
#define N 1
#include "vm_n.h"
#undef N
#define N 2
#include "vm_n.h"
#undef N
#define N 4
#include "vm_n.h"
#undef N
#define N 8
#include "vm_n.h"
#undef N
#define N word
#include "vm_n.h"
#undef N