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
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
+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
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.
* 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
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.
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.
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.
-
-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.
-
-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.
-
-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: In its default configuration PSIM is constructed so that
+runtime-configurable devices (eg PCI).
+
+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: 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.
+
+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 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.
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
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
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
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:
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.
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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
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"
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
+++ /dev/null
-/* 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 N
-#error "N must be #defined"
-#endif
-
-#undef unsigned_N
-#define unsigned_N XCONCAT2(unsigned_,N)
-#undef T2H_N
-#define T2H_N XCONCAT2(T2H_,N)
-#undef H2T_N
-#define H2T_N XCONCAT2(H2T_,N)
-
-
-INLINE_CORE unsigned_N
-XCONCAT2(core_map_read_,N)(core_map *map,
- unsigned_word addr,
- cpu *processor,
- unsigned_word cia)
-{
- core_mapping *mapping = core_map_find_mapping(map,
- addr,
- sizeof(unsigned_N),
- processor,
- cia,
- 1); /*abort*/
- if (WITH_CALLBACK_MEMORY && mapping->reader != 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))
- error("core_read_,N() reader should not fail\n");
- return T2H_N(data);
- }
- else
- return T2H_N(*(unsigned_N*)core_translate(mapping, addr));
-}
-
-
-
-INLINE_CORE void
-XCONCAT2(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,
- sizeof(unsigned_N),
- processor,
- cia,
- 1); /*abort*/
- if (WITH_CALLBACK_MEMORY && mapping->writer != 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))
- error("core_read_,N() writer should not fail\n");
- }
- else
- *(unsigned_N*)core_translate(mapping, addr) = H2T_N(val);
-}
-
--- /dev/null
+/* 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 N
+#error "N must be #defined"
+#endif
+
+/* NOTE: see end of file for #undef of these macros */
+#define unsigned_N XCONCAT2(unsigned_,N)
+#define T2H_N XCONCAT2(T2H_,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)
+
+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,
+ sizeof(unsigned_N),
+ processor,
+ cia,
+ 1); /*abort*/
+ if (WITH_CALLBACK_MEMORY && mapping->device != NULL) {
+ unsigned_N data;
+ 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);
+ }
+ else
+ return T2H_N(*(unsigned_N*)core_translate(mapping, addr));
+}
+
+
+
+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,
+ sizeof(unsigned_N),
+ processor,
+ cia,
+ 1); /*abort*/
+ if (WITH_CALLBACK_MEMORY && mapping->device != NULL) {
+ unsigned_N data = H2T_N(val);
+ 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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_C_
+#define _DEVICE_C_
+
+#include <stdio.h>
+
+#include "device_table.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
+
+#include <ctype.h>
+
+
+
+typedef struct _device_property_entry device_property_entry;
+struct _device_property_entry {
+ const char *name;
+ device_property_entry *next;
+ device_property *value;
+};
+
+
+/* A device */
+struct _device {
+ /* my name is ... */
+ const char *name;
+ const char *full_name;
+ /* device tree */
+ device *parent;
+ device *children;
+ device *sibling;
+ /* hw/sw callbacks */
+ void *data; /* device specific data */
+ const device_callbacks *callback;
+ /* device properties */
+ device_property_entry *properties;
+};
+
+
+device INLINE_DEVICE *
+device_create(const char *name,
+ device *parent)
+{
+ device_descriptor *descr;
+ int name_len;
+ char *chp;
+ chp = strchr(name, '@');
+ name_len = (chp == NULL ? strlen(name) : chp - name);
+ for (descr = device_table; descr->name != NULL; descr++) {
+ if (strncmp(name, descr->name, name_len) == 0
+ && (descr->name[name_len] == '\0'
+ || descr->name[name_len] == '@')) {
+ void *data = (descr->creator != NULL
+ ? descr->creator(name, parent)
+ : NULL);
+ return device_create_from(name, data, descr->callbacks, parent);
+ }
+ }
+ error("device_create() unknown device %s\n", name);
+ return NULL;
+}
+
+device INLINE_DEVICE *
+device_create_from(const char *name,
+ void *data,
+ const device_callbacks *callbacks,
+ device *parent)
+{
+ device *new_device = ZALLOC(device);
+ new_device->data = data;
+ new_device->name = strdup(name);
+ new_device->callback = callbacks;
+ new_device->parent = parent;
+ return new_device;
+}
+
+
+device INLINE_DEVICE *
+device_parent(device *me)
+{
+ return me->parent;
+}
+
+const char INLINE_DEVICE *
+device_name(device *me)
+{
+ return me->name;
+}
+
+void INLINE_DEVICE *
+device_data(device *me)
+{
+ return me->data;
+}
+
+void INLINE_DEVICE
+device_traverse_properties(device *me,
+ device_traverse_property_function *traverse,
+ void *data)
+{
+ device_property_entry *entry = me->properties;
+ while (entry != NULL) {
+ traverse(me, entry->name, data);
+ entry = entry->next;
+ }
+}
+
+void INLINE_DEVICE
+device_init(device *me,
+ psim *system)
+{
+ me->callback->init(me, system);
+}
+
+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*/
+{
+ me->callback->attach_address(me, name, attach, space,
+ addr, nr_bytes, access, who);
+}
+
+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*/
+{
+ me->callback->detach_address(me, name, attach, space,
+ addr, nr_bytes, access, who);
+}
+
+unsigned INLINE_DEVICE
+device_io_read_buffer(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ return me->callback->io_read_buffer(me, dest, space,
+ addr, nr_bytes,
+ processor, 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)
+{
+ return me->callback->io_write_buffer(me, source, space,
+ addr, nr_bytes,
+ processor, cia);
+}
+
+unsigned INLINE_DEVICE
+device_dma_read_buffer(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ return me->callback->dma_read_buffer(me, dest, space,
+ addr, 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)
+{
+ return me->callback->dma_write_buffer(me, source, space,
+ addr, nr_bytes,
+ violate_read_only_section);
+}
+
+void INLINE_DEVICE
+device_attach_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ const char *name)
+{
+ me->callback->attach_interrupt(me, who, interrupt_line, name);
+}
+
+void INLINE_DEVICE
+device_detach_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ const char *name)
+{
+ me->callback->detach_interrupt(me, who, interrupt_line, name);
+}
+
+void INLINE_DEVICE
+device_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
+{
+ me->callback->interrupt(me, who, interrupt_line, interrupt_status,
+ processor, cia);
+}
+
+void INLINE_DEVICE
+device_interrupt_ack(device *me,
+ int interrupt_line,
+ int interrupt_status)
+{
+ me->callback->interrupt_ack(me, interrupt_line, interrupt_status);
+}
+
+void EXTERN_DEVICE
+device_ioctl(device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ ...)
+{
+ va_list ap;
+ va_start(ap, cia);
+ me->callback->ioctl(me, system, processor, cia, ap);
+ va_end(ap);
+}
+
+
+/* Manipulate properties attached to devices */
+
+device_property STATIC_INLINE_DEVICE *
+device_add_property(device *me,
+ const char *property,
+ device_property_type type,
+ const void *array,
+ int sizeof_array)
+{
+ device_property_entry *new_entry = 0;
+ device_property *new_value = 0;
+ void *new_array = 0;
+ /* find the list end */
+ device_property_entry **insertion_point = &me->properties;
+ while (*insertion_point != NULL) {
+ if (strcmp((**insertion_point).name, property) == 0)
+ return (**insertion_point).value;
+ insertion_point = &(**insertion_point).next;
+ }
+ /* alloc data for the new property */
+ new_entry = ZALLOC(device_property_entry);
+ new_value = ZALLOC(device_property);
+ new_array = (sizeof_array > 0
+ ? zalloc(sizeof_array)
+ : (void*)0);
+ /* insert the new property into the list */
+ *insertion_point = new_entry;
+ new_entry->name = strdup(property);
+ new_entry->value = new_value;
+ new_value->type = type;
+ new_value->sizeof_array = sizeof_array;
+ new_value->array = new_array;
+ if (sizeof_array > 0)
+ memcpy(new_array, array, sizeof_array);
+ return new_value;
+}
+
+void INLINE_DEVICE
+device_add_array_property(device *me,
+ const char *property,
+ const void *array,
+ int sizeof_array)
+{
+ TRACE(trace_devices,
+ ("device_add_array_property(me=0x%lx, property=%s, ...)\n",
+ (long)me, property));
+ device_add_property(me, property,
+ array_property, array, sizeof_array);
+}
+
+void INLINE_DEVICE
+device_add_integer_property(device *me,
+ const char *property,
+ signed32 integer)
+{
+ TRACE(trace_devices,
+ ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
+ (long)me, property, (long)integer));
+ H2BE(integer);
+ device_add_property(me, property, integer_property,
+ &integer, sizeof(integer));
+}
+
+void INLINE_DEVICE
+device_add_boolean_property(device *me,
+ const char *property,
+ int boolean)
+{
+ signed32 new_boolean = (boolean ? -1 : 0);
+ TRACE(trace_devices,
+ ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n",
+ (long)me, property, boolean));
+ device_add_property(me, property, boolean_property,
+ &new_boolean, sizeof(new_boolean));
+}
+
+void INLINE_DEVICE
+device_add_null_property(device *me,
+ const char *property)
+{
+ TRACE(trace_devices,
+ ("device_add_null(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ device_add_property(me, property, null_property,
+ NULL, 0);
+}
+
+void INLINE_DEVICE
+device_add_string_property(device *me,
+ const char *property,
+ const char *string)
+{
+
+ TRACE(trace_devices,
+ ("device_add_property(me=0x%lx, property=%s, string=%s)\n",
+ (long)me, property, string));
+ device_add_property(me, property, string_property,
+ string, strlen(string) + 1);
+}
+
+const device_property INLINE_DEVICE *
+device_find_property(device *me,
+ const char *property)
+{
+ if (me != (device*)0) {
+ device_property_entry *entry = me->properties;
+ while (entry != (device_property_entry*)0) {
+ if (strcmp(entry->name, property) == 0)
+ return entry->value;
+ entry = entry->next;
+ }
+ }
+ return (device_property*)0;
+}
+
+const char INLINE_DEVICE *
+device_find_next_property(device *me,
+ const char *property)
+{
+ if (me != NULL) {
+ if (property == NULL || strcmp(property, "") == 0) {
+ return (me->properties != NULL
+ ? me->properties->name
+ : NULL);
+ }
+ else {
+ device_property_entry *entry = me->properties;
+ while (entry != NULL) {
+ if (strcmp(entry->name, property) == 0)
+ return (entry->next != NULL
+ ? entry->next->name
+ : NULL);
+ entry = entry->next;
+ }
+ }
+ }
+ return NULL;
+}
+
+const device_property INLINE_DEVICE *
+device_find_array_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ TRACE(trace_devices,
+ ("device_find_integer(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != array_property)
+ error("%s property %s not found or of wrong type\n",
+ me->name, property);
+ return node;
+}
+
+signed_word INLINE_DEVICE
+device_find_integer_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ signed32 integer;
+ TRACE(trace_devices,
+ ("device_find_integer(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != integer_property)
+ error("%s property %s not found or of wrong type\n",
+ me->name, property);
+ ASSERT(sizeof(integer) == node->sizeof_array);
+ memcpy(&integer, node->array, sizeof(integer));
+ BE2H(integer);
+ return integer;
+}
+
+int INLINE_DEVICE
+device_find_boolean_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ unsigned32 boolean;
+ TRACE(trace_devices,
+ ("device_find_boolean(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != boolean_property)
+ error("%s property %s not found or of wrong type\n",
+ me->name, property);
+ ASSERT(sizeof(boolean) == node->sizeof_array);
+ memcpy(&boolean, node->array, sizeof(boolean));
+ return boolean;
+}
+
+const char INLINE_DEVICE *
+device_find_string_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ const char *string;
+ TRACE(trace_devices,
+ ("device_find_string(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != string_property)
+ error("%s property %s not found or of wrong type\n",
+ me->name, property);
+ string = node->array;
+ ASSERT(strlen(string) + 1 == node->sizeof_array);
+ return string;
+}
+
+
+/* determine the full name of the device. If buf is specified it is
+ stored in there. Failing that, a safe area of memory is allocated */
+const char STATIC_INLINE_DEVICE *
+device_tree_full_name(device *leaf,
+ char *buf,
+ unsigned sizeof_buf)
+{
+ /* get a buffer */
+ char full_name[1024];
+ if (buf == (char*)0) {
+ buf = full_name;
+ sizeof_buf = sizeof(full_name);
+ }
+
+ /* construct a name */
+ if (leaf->parent == NULL) {
+ if (sizeof_buf < 1)
+ error("device_full_name() buffer overflow\n");
+ *buf = '\0';
+ }
+ else {
+ device_tree_full_name(leaf->parent, buf, sizeof_buf);
+ if (strlen(buf) + strlen("/") + strlen(leaf->name) + 1 > sizeof_buf)
+ error("device_full_name() buffer overflow\n");
+ strcat(buf, "/");
+ strcat(buf, leaf->name);
+ }
+
+ /* return it usefully */
+ if (buf == full_name)
+ buf = strdup(full_name);
+ return buf;
+}
+
+
+/* find/create a node in the device tree */
+
+typedef enum {
+ device_tree_return_null = 2,
+ device_tree_abort = 3,
+} device_tree_action;
+
+device STATIC_INLINE_DEVICE *
+device_tree_find_node(device *root,
+ const char *path,
+ const char *full_path,
+ device_tree_action action)
+{
+ const char *name;
+ int strlen_name;
+ device *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;
+ }
+ }
+
+ /* parse the driver_name/unit-address */
+ ASSERT(*path != '/');
+ name = path;
+ while (isalnum(*path)
+ || *path == ',' || *path == ',' || *path == '_'
+ || *path == '+' || *path == '-')
+ path++;
+ if ((*path != '/' && *path != '@' && *path != ':' && *path != '\0')
+ || (name == path && *name != '\0'))
+ error("device_tree: path %s invalid at %s\n", full_path, path);
+
+ /* parse the unit-address */
+ if (*path == '@') {
+ path++;
+ while ((*path != '\0' && *path != ':' && *path != '/')
+ || (*path == ':' && path[-1] == '\\')
+ || (*path == '/' && path[-1] == '\\'))
+ path++;
+ }
+ strlen_name = path - name;
+
+ /* skip the device-arguments */
+ if (*path == ':') {
+ path++;
+ while ((*path != '\0' && *path != '/' && *path != ':' && *path != '@')
+ || (*path == '/' && path[-1] == '\\')
+ || (*path == ':' && path[-1] == '\\')
+ || (*path == '@' && path[-1] == '\\'))
+ path++;
+ }
+
+ /* sanity checks */
+ if (*path != '\0' && *path != '/')
+ error("device_tree: path %s invalid at %s\n", full_path, path);
+
+ /* leaf? and growing? */
+ if (name[0] == '\0') {
+ return root;
+ }
+ else if (root != NULL) {
+ for (child = root->children;
+ child != NULL;
+ child = child->sibling) {
+ if (strncmp(name, child->name, strlen_name) == 0
+ && strlen(child->name) == strlen_name) {
+ if (*path == '\0')
+ return child;
+ else
+ return device_tree_find_node(child,
+ path + 1/* / */,
+ full_path,
+ action);
+ }
+ }
+ }
+
+ /* search failed, take default action */
+ switch (action) {
+ 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 */
+
+device INLINE_DEVICE *
+device_tree_add_device(device *root,
+ const char *prefix,
+ device *new_sub_tree)
+{
+ device *parent;
+ TRACE(trace_device_tree,
+ ("device_tree_add_device(root=0x%lx, prefix=%s, dev=0x%lx)\n",
+ (long)root, prefix, (long)new_sub_tree));
+
+ /* find our parent */
+ parent = device_tree_find_node(root,
+ prefix,
+ prefix, /* full-path */
+ device_tree_abort);
+
+ /* create/insert a new child */
+ new_sub_tree->parent = parent;
+ if (parent != NULL) {
+ device **sibling = &parent->children;
+ while ((*sibling) != NULL)
+ sibling = &(*sibling)->sibling;
+ *sibling = new_sub_tree;
+ }
+
+ return new_sub_tree;
+}
+
+device INLINE_DEVICE *
+device_tree_find_device(device *root,
+ const char *path)
+{
+ device *node;
+ TRACE(trace_device_tree,
+ ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
+ (long)root, path));
+ node = device_tree_find_node(root,
+ path,
+ path, /* full-name */
+ device_tree_return_null);
+ return node;
+}
+
+
+/* init all the devices */
+
+void STATIC_INLINE_DEVICE
+device_tree_init_device(device *root,
+ void *data)
+{
+ psim *system;
+ system = (psim*)data;
+ TRACE(trace_device_tree,
+ ("device_tree_init() initializing device=0x%lx:%s\n",
+ (long)root, root->full_name));
+ device_init(root, system);
+}
+
+
+void INLINE_DEVICE
+device_tree_init(device *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 */
+
+void INLINE_DEVICE
+device_tree_traverse(device *root,
+ device_tree_traverse_function *prefix,
+ device_tree_traverse_function *postfix,
+ void *data)
+{
+ device *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 */
+
+void INLINE_DEVICE
+device_tree_dump(device *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(" (name %s)\n", device->name);
+ error("FIXME - need to print out properties\n");
+ printf_filtered(")\n");
+}
+
+
+/* lookup/create a device various formats */
+
+void STATIC_INLINE_DEVICE
+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));
+ }
+}
+
+void STATIC_INLINE_DEVICE
+c_strcat(char *buf,
+ const char *c)
+{
+ char *end = strchr(buf, '\0');
+ while (*c) {
+ if (*c == '/' || *c == ',')
+ *end++ = '\\';
+ *end++ = *c++;
+ }
+ *end = '\0';
+}
+
+device INLINE_DEVICE *
+device_tree_add_found(device *root,
+ const char *prefix,
+ const char *name)
+{
+ device *parent;
+ device *new_device;
+ device *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_found(root=0x%lx, prefix=%s, name=%x)\n",
+ (long)root, prefix, name));
+ parent = device_tree_find_node(root, prefix, prefix,
+ device_tree_abort);
+ new_device = device_tree_find_device(parent, name);
+ if (new_device != NULL)
+ return new_device;
+ else {
+ new_device = device_create(name, parent);
+ new_node = device_tree_add_device(parent, "", new_device);
+ ASSERT(new_device == new_node);
+ return new_node;
+ }
+}
+
+device INLINE_DEVICE *
+device_tree_add_found_c(device *root,
+ const char *prefix,
+ const char *name,
+ const char *c1)
+{
+ char buf[1024];
+ strcpy(buf, name);
+ strcat(buf, "@");
+ c_strcat(buf, c1);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_c - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+device INLINE_DEVICE *
+device_tree_add_found_c_uw(device *root,
+ const char *prefix,
+ const char *name,
+ const char *c1,
+ unsigned_word uw2)
+{
+ char buf[1024];
+ strcpy(buf, name);
+ strcat(buf, "@");
+ c_strcat(buf, c1);
+ strcat(buf, ",");
+ u_strcat(buf, uw2);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_* - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+device INLINE_DEVICE *
+device_tree_add_found_uw_u(device *root,
+ const char *prefix,
+ const char *name,
+ unsigned_word uw1,
+ unsigned u2)
+{
+ char buf[1024];
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, u2);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_* - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+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)
+{
+ char buf[1024];
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, u2);
+ strcat(buf, ",");
+ u_strcat(buf, u3);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_* - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+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)
+{
+ char buf[1024];
+ 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);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_* - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+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)
+{
+ char buf[1024];
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, uw2);
+ strcat(buf, ",");
+ u_strcat(buf, u3);
+ strcat(buf, ",");
+ u_strcat(buf, u4);
+ strcat(buf, ",");
+ c_strcat(buf, c5);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_* - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+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)
+{
+ char buf[1024];
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, uw2);
+ strcat(buf, ",");
+ u_strcat(buf, u3);
+ strcat(buf, ",");
+ u_strcat(buf, u4);
+ strcat(buf, ",");
+ u_strcat(buf, u5);
+ if (strlen(buf) + 1 >= sizeof(buf))
+ error("device_tree_add_found_* - buffer overflow\n");
+ return device_tree_add_found(root, prefix, buf);
+}
+
+
+/* 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)
+
+int INLINE_DEVICE
+scand_c(const char *name,
+ char *c1,
+ unsigned c1size)
+{
+ SCAN_INIT(name);
+ SCAN_C(c1, c1size);
+ SCAN_END;
+}
+
+int INLINE_DEVICE
+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;
+}
+
+int INLINE_DEVICE
+scand_uw(const char *name,
+ unsigned_word *uw1)
+{
+ SCAN_INIT(name);
+ SCAN_U(uw1);
+ SCAN_END;
+}
+
+int INLINE_DEVICE
+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;
+}
+
+int INLINE_DEVICE
+scand_uw_u(const char *name,
+ unsigned_word *uw1,
+ unsigned *u2)
+{
+ SCAN_INIT(name);
+ SCAN_U(uw1);
+ SCAN_U(u2);
+ SCAN_END;
+}
+
+int INLINE_DEVICE
+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;
+}
+
+int INLINE_DEVICE
+scand_uw_u_u_c(const char *name,
+ unsigned_word *uw1,
+ unsigned *u2,
+ unsigned *u3,
+ char *c4,
+ unsigned c4size)
+{
+ SCAN_INIT(name);
+ SCAN_U(uw1);
+ SCAN_U(u2);
+ SCAN_U(u3);
+ SCAN_C(c4, c4size);
+ SCAN_END;
+}
+
+int INLINE_DEVICE
+scand_uw_uw(const char *name,
+ unsigned_word *uw1,
+ unsigned_word *uw2)
+{
+ SCAN_INIT(name);
+ SCAN_U(uw1);
+ SCAN_U(uw2);
+ SCAN_END;
+}
+
+int INLINE_DEVICE
+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;
+}
+
+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)
+{
+ SCAN_INIT(name);
+ SCAN_U(uw1);
+ SCAN_U(uw2);
+ SCAN_U(u3);
+ SCAN_U(u4);
+ SCAN_C(c5, c5size);
+ SCAN_END;
+}
+
+int INLINE_DEVICE
+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;
+}
+
+
+#endif /* _DEVICE_C_ */
--- /dev/null
+/* 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; */
+
+
+
+\f
+/* 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);
+
+
+
+\f
+/* 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);
+
+
+\f
+/* 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,
+ ...);
+
+
+\f
+/* 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);
+
+
+
+
+\f
+/* 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_ */
--- /dev/null
+/* 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_TABLE_C_
+#define _DEVICE_TABLE_C_
+
+#ifndef STATIC_INLINE_DEVICE_TABLE
+#define STATIC_INLINE_DEVICE_TABLE STATIC_INLINE
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+
+#include "device_table.h"
+
+#include "events.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#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
+
+#include "cpu.h"
+
+#include "bfd.h"
+
+/* Helper functions */
+
+/* Generic device init: Attaches the device of size <nr_bytes> (taken
+ from <name>@<int>,<nr_bytes>) to its parent at address zero and
+ with read/write access. */
+
+STATIC_INLINE_DEVICE_TABLE void
+generic_init_callback(device *me,
+ psim *system)
+{
+ unsigned_word addr;
+ unsigned nr_bytes;
+ if (scand_uw_u(device_name(me), &addr, &nr_bytes) != 2)
+ error("generic_init_callback() invalid nr_bytes in %s\n", device_name(me));
+ device_attach_address(device_parent(me),
+ device_name(me),
+ attach_callback,
+ 0 /*space*/,
+ addr,
+ nr_bytes,
+ access_read_write,
+ me);
+}
+
+
+/* DMA a file into memory */
+STATIC_INLINE_DEVICE_TABLE int
+dma_file(device *me,
+ const char *file_name,
+ unsigned_word addr)
+{
+ int count;
+ int inc;
+ FILE *image;
+ char buf[1024];
+
+ /* get it open */
+ image = fopen(file_name, "r");
+ if (image == NULL)
+ return -1;
+
+ /* read it in slowly */
+ count = 0;
+ while (1) {
+ inc = fread(buf, 1, sizeof(buf), image);
+ if (feof(image) || ferror(image))
+ break;
+ if (device_dma_write_buffer(device_parent(me),
+ buf,
+ 0 /*address-space*/,
+ addr+count,
+ inc /*nr-bytes*/,
+ 1 /*violate ro*/) != inc) {
+ fclose(image);
+ return -1;
+ }
+ count += inc;
+ }
+
+ /* close down again */
+ fclose(image);
+
+ return count;
+}
+
+
+\f
+/* inimplemented versions of each function */
+
+void
+unimp_device_init(device *me,
+ psim *system)
+{
+ error("device_init_callback for %s not implemented\n", device_name(me));
+}
+
+void
+unimp_device_attach_address(device *me,
+ const char *name,
+ attach_type type,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ access_type access,
+ device *who) /*callback/default*/
+{
+ error("device_attach_address_callback for %s not implemented\n", device_name(me));
+}
+
+void
+unimp_device_detach_address(device *me,
+ const char *name,
+ attach_type type,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ access_type access,
+ device *who) /*callback/default*/
+{
+ error("device_detach_address_callback for %s not implemented\n", device_name(me));
+}
+
+unsigned
+unimp_device_io_read_buffer(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("device_io_read_buffer_callback for %s not implemented\n", device_name(me));
+ return 0;
+}
+
+unsigned
+unimp_device_io_write_buffer(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("device_io_write_buffer_callback for %s not implemented\n", device_name(me));
+ return 0;
+}
+
+unsigned
+unimp_device_dma_read_buffer(device *me,
+ void *target,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ error("device_dma_read_buffer_callback for %s not implemented\n", device_name(me));
+ return 0;
+}
+
+unsigned
+unimp_device_dma_write_buffer(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ error("device_dma_write_buffer_callback for %s not implemented\n", device_name(me));
+ return 0;
+}
+
+void
+unimp_device_attach_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ const char *name)
+{
+ error("device_attach_interrupt_callback for %s not implemented\n", device_name(me));
+}
+
+void
+unimp_device_detach_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ const char *name)
+{
+ error("device_detach_interrupt_callback for %s not implemented\n", device_name(me));
+}
+
+void
+unimp_device_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("device_interrupt_callback for %s not implemented\n", device_name(me));
+}
+
+void
+unimp_device_interrupt_ack(device *me,
+ int interrupt_line,
+ int interrupt_status)
+{
+ error("device_interrupt_ack_callback for %s not implemented\n", device_name(me));
+}
+
+void
+unimp_device_ioctl(device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ va_list ap)
+{
+ error("device_ioctl_callback for %s not implemented\n", device_name(me));
+}
+
+
+\f
+/* ignore/passthrough versions of each function */
+
+void
+ignore_device_init(device *me,
+ psim *system)
+{
+ /*null*/
+}
+
+void
+passthrough_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*/
+{
+ device_attach_address(device_parent(me), name, attach,
+ space, addr, nr_bytes,
+ access,
+ who);
+}
+
+void
+passthrough_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*/
+{
+ device_detach_address(device_parent(me), name, attach,
+ space, addr, nr_bytes, access,
+ who);
+}
+
+unsigned
+passthrough_device_dma_read_buffer(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ return device_dma_read_buffer(device_parent(me), dest,
+ space, addr, nr_bytes);
+}
+
+unsigned
+passthrough_device_dma_write_buffer(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ return device_dma_write_buffer(device_parent(me), source,
+ space, addr,
+ nr_bytes,
+ violate_read_only_section);
+}
+
+void
+passthrough_device_attach_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ const char *name)
+{
+ device_attach_interrupt(device_parent(me), who,
+ interrupt_line, name);
+}
+
+void
+passthrough_device_detach_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ const char *name)
+{
+ device_detach_interrupt(device_parent(me), who,
+ interrupt_line, name);
+}
+
+
+void
+passthrough_device_interrupt(device *me,
+ device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
+{
+ device_interrupt(device_parent(me), who,
+ interrupt_line, interrupt_status,
+ processor, cia);
+}
+
+
+static const device_callbacks passthrough_callbacks = {
+ ignore_device_init,
+ passthrough_device_attach_address,
+ passthrough_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ passthrough_device_dma_read_buffer,
+ passthrough_device_dma_write_buffer,
+ passthrough_device_attach_interrupt,
+ passthrough_device_detach_interrupt,
+ passthrough_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* Simple console device: console@<address>,16
+
+ Input characters are taken from the keyboard, output characters
+ sent to the terminal. Echoing of characters is not disabled.
+
+ The device has four registers:
+
+ 0x0: read
+ 0x4: read-status
+ 0x8: write
+ 0xC: write-status
+
+ Where a nonzero status register indicates that the device is ready
+ (input fifo contains a character or output fifo has space). */
+
+typedef struct _console_buffer {
+ char buffer;
+ int status;
+ event_entry_tag event_tag;
+} console_buffer;
+
+typedef struct _console_device {
+ console_buffer input;
+ console_buffer output;
+} console_device;
+
+typedef enum {
+ console_read_buffer = 0,
+ console_read_status = 4,
+ console_write_buffer = 8,
+ console_write_status = 12,
+ console_offset_mask = 0xc,
+ console_size = 16,
+} console_offsets;
+
+
+static unsigned
+console_io_read_buffer_callback(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ console_device *console = (console_device*)device_data(me);
+ unsigned_1 val;
+
+ /* determine what was read */
+
+ switch ((int)addr) {
+
+ case console_read_buffer:
+ val = console->input.buffer;
+ break;
+
+ case console_read_status:
+ { /* check for input */
+ int flags;
+ int status;
+ /* get the old status */
+ flags = fcntl(0, F_GETFL, 0);
+ if (flags == -1) {
+ perror("console");
+ val = 0;
+ break;
+ }
+ /* temp, disable blocking IO */
+ status = fcntl(0, F_SETFL, flags | O_NDELAY);
+ if (status == -1) {
+ perror("console");
+ val = 0;
+ break;
+ }
+ /* try for input */
+ status = read(0, &console->input.buffer, 1);
+ if (status == 1) {
+ console->input.status = 1;
+ }
+ else {
+ console->input.status = 0;
+ }
+ /* return to regular vewing */
+ fcntl(0, F_SETFL, flags);
+ }
+ val = console->input.status;
+ break;
+
+ case console_write_buffer:
+ val = console->output.buffer;
+ break;
+
+ case console_write_status:
+ val = console->output.status;
+ break;
+
+ default:
+ error("console_read_callback() internal error\n");
+ val = 0;
+ break;
+
+ }
+
+ memset(dest, 0, nr_bytes);
+ *(unsigned_1*)dest = val;
+ return nr_bytes;
+}
+
+static unsigned
+console_io_write_buffer_callback(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ console_device *console = (console_device*)device_data(me);
+ unsigned_1 val = *(unsigned_1*)source;
+
+ switch ((int)addr) {
+ case console_read_buffer:
+ console->input.buffer = val;
+ break;
+ case console_read_status:
+ console->input.status = val;
+ break;
+ case console_write_buffer:
+ DTRACE(console, ("<%c:%d>", val, val));
+ printf_filtered("%c",val) ;
+ console->output.buffer = val;
+ console->output.status = 1;
+ break;
+ case console_write_status:
+ console->output.status = val;
+ break;
+ default:
+ error("console_write_callback() internal error\n");
+ }
+
+ return nr_bytes;
+}
+
+
+static device_callbacks const console_callbacks = {
+ generic_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ console_io_read_buffer_callback,
+ console_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+static void *
+console_create(const char *name,
+ device *parent)
+{
+ /* create the descriptor */
+ console_device *console = ZALLOC(console_device);
+ console->output.status = 1;
+ console->output.buffer = '\0';
+ console->input.status = 0;
+ console->input.buffer = '\0';
+ return console;
+}
+
+
+\f
+/* ICU device: icu@0x<address>,4
+
+ Single 4 byte register. Read returns processor number. Write
+ interrupts specified processor.
+
+ Illustrates passing of events to parent device. Passing of
+ interrupts to parent bus.
+
+ NB: For the sake of illustrating the passing of interrupts. This
+ device doesn't pass interrupt events to its parent. Instead it
+ passes them back to its self. */
+
+static unsigned
+icu_io_read_buffer_callback(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ unsigned_1 val;
+ val = cpu_nr(processor);
+ memset(dest, 0, nr_bytes);
+ *(unsigned_1*)dest = val;
+ return nr_bytes;
+}
+
+
+static unsigned
+icu_io_write_buffer_callback(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ unsigned_1 val = H2T_1(*(unsigned_1*)source);
+ /* tell the parent device that the interrupt lines have changed.
+ For this fake ICU. The interrupt lines just indicate the cpu to
+ interrupt next */
+ device_interrupt(device_parent(me), me,
+ val, val,
+ processor, cia);
+ return nr_bytes;
+}
+
+
+static device_callbacks const icu_callbacks = {
+ generic_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ icu_io_read_buffer_callback,
+ icu_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* HALT device: halt@0x<address>,4
+
+ With real hardware, the processor operation is normally terminated
+ through a reset. This device illustrates how a reset device could
+ be attached to an address */
+
+
+static unsigned
+halt_io_read_buffer_callback(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ cpu_halt(processor, cia, was_exited, 0);
+ return 0;
+}
+
+
+static unsigned
+halt_io_write_buffer_callback(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ cpu_halt(processor, cia, was_exited, *(unsigned_1*)source);
+ return 0;
+}
+
+
+static device_callbacks const halt_callbacks = {
+ generic_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ halt_io_read_buffer_callback,
+ halt_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* Register init device: register
+
+ Properties attached to the register device specify the name/value
+ initialization pair for cpu registers. */
+
+static void
+register_init(device *me,
+ const char *name,
+ void *data)
+{
+ psim *system = (psim*)data;
+ unsigned32 value = device_find_integer_property(me, name);
+ DTRACE(register, ("%s=0x%lx\n", name, (unsigned long)value));
+ psim_write_register(system, -1, /* all processors */
+ &value,
+ name,
+ cooked_transfer);
+}
+
+
+static void
+register_init_callback(device *me,
+ psim *system)
+{
+ device_traverse_properties(me, register_init, system);
+}
+
+
+static device_callbacks const register_callbacks = {
+ register_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* VEA VM device: vm@0x<stack-base>,<nr_bytes>
+
+ A VEA mode device. This sets its self up as the default memory
+ device capturing all accesses (reads/writes) to currently unmapped
+ addresses. If the unmaped access falls within unallocated stack or
+ heap address ranges then memory is allocated and the access is
+ allowed to continue.
+
+ During init phase, this device expects to receive `attach' requests
+ from its children for the text/data/bss memory areas. Typically,
+ this would be done by the binary device.
+
+ STACK: The location of the stack in memory is specified as part of
+ the devices name. Unmaped accesses that fall within the stack
+ space result in the allocated stack being grown downwards so that
+ it includes the page of the culprit access.
+
+ HEAP: During initialization, the vm device monitors all `attach'
+ operations from its children using this to determine the initial
+ location of the heap. The heap is then extended by system calls
+ that frob the heap upper bound variable (see system.c). */
+
+
+typedef struct _vm_device {
+ /* area of memory valid for stack addresses */
+ unsigned_word stack_base; /* min possible stack value */
+ unsigned_word stack_bound;
+ unsigned_word stack_lower_limit;
+ /* area of memory valid for heap addresses */
+ unsigned_word heap_base;
+ unsigned_word heap_bound;
+ unsigned_word heap_upper_limit;
+} vm_device;
+
+
+static void
+vm_init_callback(device *me,
+ psim *system)
+{
+ vm_device *vm = (vm_device*)device_data(me);
+
+ /* revert the stack/heap variables to their defaults */
+ vm->stack_lower_limit = vm->stack_bound;
+ vm->heap_base = 0;
+ vm->heap_bound = 0;
+ vm->heap_upper_limit = 0;
+
+ /* establish this device as the default memory handler */
+ device_attach_address(device_parent(me),
+ device_name(me),
+ attach_default,
+ 0 /*address space - ignore*/,
+ 0 /*addr - ignore*/,
+ 0 /*nr_bytes - ignore*/,
+ access_read_write /*access*/,
+ me);
+}
+
+
+static void
+vm_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*/
+{
+ vm_device *vm = (vm_device*)device_data(me);
+ /* update end of bss if necessary */
+ if (vm->heap_base < addr + nr_bytes) {
+ vm->heap_base = addr + nr_bytes;
+ vm->heap_bound = addr + nr_bytes;
+ vm->heap_upper_limit = addr + nr_bytes;
+ }
+ device_attach_address(device_parent(me),
+ "vm@0x0,0", /* stop remap */
+ attach_raw_memory,
+ 0 /*address space*/,
+ addr,
+ nr_bytes,
+ access,
+ me);
+}
+
+
+STATIC_INLINE_DEVICE_TABLE unsigned
+add_vm_space(device *me,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ vm_device *vm = (vm_device*)device_data(me);
+ unsigned_word block_addr;
+ unsigned block_nr_bytes;
+
+ /* an address in the stack area, allocate just down to the addressed
+ page */
+ if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
+ block_addr = FLOOR_PAGE(addr);
+ block_nr_bytes = vm->stack_lower_limit - block_addr;
+ vm->stack_lower_limit = block_addr;
+ }
+ /* an address in the heap area, allocate all of the required heap */
+ else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
+ block_addr = vm->heap_upper_limit;
+ block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
+ vm->heap_upper_limit = vm->heap_bound;
+ }
+ /* oops - an invalid address - abort the cpu */
+ else if (processor != NULL) {
+ cpu_halt(processor, cia, was_signalled, SIGSEGV);
+ return 0;
+ }
+ /* 2*oops - an invalid address and no processor */
+ else {
+ return 0;
+ }
+
+ /* got the parameters, allocate the space */
+ device_attach_address(device_parent(me),
+ "vm@0x0,0", /* stop remap */
+ attach_raw_memory,
+ 0 /*address space*/,
+ block_addr,
+ block_nr_bytes,
+ access_read_write,
+ me);
+ return block_nr_bytes;
+}
+
+
+static unsigned
+vm_io_read_buffer_callback(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
+ memset(dest, 0, nr_bytes); /* always initialized to zero */
+ return nr_bytes;
+ }
+ else
+ return 0;
+}
+
+
+static unsigned
+vm_io_write_buffer_callback(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
+ return device_dma_write_buffer(device_parent(me), source,
+ space, addr,
+ nr_bytes,
+ 0/*violate_read_only*/);
+ }
+ else
+ return 0;
+}
+
+
+static void
+vm_ioctl_callback(device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ va_list ap)
+{
+ /* While the caller is notified that the heap has grown by the
+ requested amount, the heap is infact extended out to a page
+ boundary. */
+ vm_device *vm = (vm_device*)device_data(me);
+ unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
+ unsigned_word old_break = vm->heap_bound;
+ signed_word delta = new_break - old_break;
+ if (delta > 0)
+ vm->heap_bound = ALIGN_PAGE(new_break);
+ cpu_registers(processor)->gpr[0] = 0;
+ cpu_registers(processor)->gpr[3] = new_break;
+}
+
+
+static device_callbacks const vm_callbacks = {
+ vm_init_callback,
+ vm_attach_address,
+ passthrough_device_detach_address,
+ vm_io_read_buffer_callback,
+ vm_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ passthrough_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ vm_ioctl_callback,
+};
+
+
+static void *
+vea_vm_create(const char *name,
+ device *parent)
+{
+ vm_device *vm = ZALLOC(vm_device);
+ unsigned_word addr;
+ unsigned nr_bytes;
+
+ /* extract out the stack parameters */
+ if (scand_uw_u(name, &addr, &nr_bytes) != 2)
+ error("vm_device_create() invalid vm device %s\n", name);
+ vm->stack_base = addr;
+ vm->stack_bound = addr + nr_bytes;
+ return vm;
+}
+
+
+\f
+/* Memory init device: memory@0x<addr>,<size>,<access>
+
+ This strange device is used create sections of memory */
+
+static void
+memory_init_callback(device *me,
+ psim *system)
+{
+ unsigned_word addr;
+ unsigned nr_bytes;
+ unsigned access;
+ int nr_args;
+
+ nr_args = scand_uw_u_u(device_name(me), &addr, &nr_bytes, &access);
+ switch (nr_args) {
+ case 2:
+ access = access_read_write_exec;
+ break;
+ case 3:
+ break;
+ default:
+ error("memory_init_callback() invalid memory device %s\n", device_name(me));
+ break;
+ }
+
+ device_attach_address(device_parent(me),
+ device_name(me),
+ attach_raw_memory,
+ 0 /*address space*/,
+ addr,
+ nr_bytes,
+ (access_type)access,
+ me);
+}
+
+
+static device_callbacks const memory_callbacks = {
+ memory_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* IOBUS device: iobus@<address>
+
+ Simple bus on which some IO devices live */
+
+static void
+iobus_attach_address_callback(device *me,
+ const char *name,
+ attach_type type,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ access_type access,
+ device *who) /*callback/default*/
+{
+ unsigned_word iobus_addr;
+ /* sanity check */
+ if (type == attach_default)
+ error("iobus_attach_address_callback() no default for %s/%s\n",
+ device_name(me), name);
+ if (space != 0)
+ error("iobus_attach_address_callback() no space for %s/%s\n",
+ device_name(me), name);
+ /* get the bus address */
+ if (scand_uw(device_name(me), &iobus_addr) != 1)
+ error("iobus_attach_address_callback() invalid address for %s\n",
+ device_name(me));
+ device_attach_address(device_parent(me),
+ device_name(me),
+ type,
+ 0 /*space*/,
+ iobus_addr + addr,
+ nr_bytes,
+ access,
+ who);
+}
+
+
+STATIC_INLINE_DEVICE_TABLE void
+iobus_do_interrupt(event_queue *queue,
+ void *data)
+{
+ cpu *target = (cpu*)data;
+ /* try to interrupt the processor. If the attempt fails, try again
+ on the next tick */
+ if (!external_interrupt(target))
+ event_queue_schedule(queue, 1, iobus_do_interrupt, target);
+}
+
+
+static void
+iobus_interrupt_callback(device *me,
+ device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
+{
+ /* the interrupt controler can't interrupt a cpu at any time.
+ Rather it must synchronize with the system clock before
+ performing an interrupt on the given processor */
+ psim *system = cpu_system(processor);
+ cpu *target = psim_cpu(system, interrupt_status);
+ if (target != NULL) {
+ event_queue *events = cpu_event_queue(target);
+ event_queue_schedule(events, 1, iobus_do_interrupt, target);
+ }
+}
+
+
+static device_callbacks const iobus_callbacks = {
+ ignore_device_init,
+ iobus_attach_address_callback,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ iobus_interrupt_callback,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* FILE device: file@0x<address>,<file-name>
+ (later - file@0x<address>,<size>,<file-offset>,<file-name>)
+
+ Specifies a file to read directly into memory starting at <address> */
+
+
+static void
+file_init_callback(device *me,
+ psim *system)
+{
+ unsigned_word addr;
+ int count;
+ char file_name[1024];
+
+ if (scand_uw_c(device_name(me), &addr, file_name, sizeof(file_name)) != 2)
+ error("devices/file - Usage: file@<address>,<file-name>\n");
+
+ /* load the file */
+ count = dma_file(me, file_name, addr);
+ if (count < 0)
+ error("device_table/%s - Problem loading file %s\n", device_name(me), file_name);
+}
+
+
+static device_callbacks const file_callbacks = {
+ file_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* DATA device: data@<address>,<count>,<value>
+
+ Store <value> at <address> using <count> size transfer */
+
+static void
+data_init_callback(device *me,
+ psim *system)
+{
+ unsigned_word addr;
+ unsigned count;
+ unsigned value;
+ union {
+ unsigned_1 v1;
+ unsigned_2 v2;
+ unsigned_4 v4;
+ unsigned_8 v8;
+ } buf;
+
+ if (scand_uw_u_u(device_name(me), &addr, &count, &value) != 3)
+ error("devices/data - Usage: data@<address>,<count>,<value>\n");
+
+ /* store the data value */
+ switch (count) {
+ case 1:
+ buf.v1 = H2T_1(value);
+ break;
+ case 2:
+ buf.v2 = H2T_2(value);
+ break;
+ case 4:
+ buf.v4 = H2T_4(value);
+ break;
+ case 8:
+ buf.v8 = H2T_8(value);
+ break;
+ }
+ if (device_dma_write_buffer(device_parent(me),
+ &buf,
+ 0 /*address-space*/,
+ addr,
+ count, /*nr-bytes*/
+ 1 /*violate ro*/) != count) {
+ error("devices/%s - Problem storing 0x%x at 0x%lx\n",
+ device_name(me), value, (long)addr);
+ }
+}
+
+
+static device_callbacks const data_callbacks = {
+ data_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* HTAB: htab@<address>,<nr_bytes>
+ PTE: pte@<real-address>,<virtual-address>,<nr_bytes>,<wimg>,<pp>
+ PTE: pte@<real-address>,<wimg>,<pp>,<binary>
+
+ HTAB defines the location (in physical memory) of a HASH table.
+ PTE (as a child of HTAB) defines a mapping that is to be entered
+ into that table.
+
+ NB: All the work in this device is done during init by the PTE.
+ The pte, looks up its parent to determine the address of the HTAB
+ and then uses DMA calls to establish the required mapping. */
+
+
+STATIC_INLINE_DEVICE_TABLE void
+htab_decode_hash_table(device *parent,
+ unsigned32 *htaborg,
+ unsigned32 *htabmask)
+{
+ unsigned_word htab_ra;
+ unsigned htab_nr_bytes;
+ unsigned n;
+ /* determine the location/size of the hash table */
+ if (parent == NULL
+ || strncmp(device_name(parent), "htab@", strlen("htab@")) != 0)
+ error("devices/htab - missing htab device\n");
+ if (scand_uw_u(device_name(parent), &htab_ra, &htab_nr_bytes) != 2)
+ error("devices/%s - Usage: htab@<real-addr>,<nr_bytes>\n",
+ device_name(parent));
+ for (n = htab_nr_bytes; n > 1; n = n / 2) {
+ if (n % 2 != 0)
+ error("devices/%s - htab size 0x%x not a power of two\n",
+ device_name(parent), htab_nr_bytes);
+ }
+ *htaborg = htab_ra;
+ *htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
+ if ((htab_ra & INSERTED32(*htabmask, 7, 15)) != 0) {
+ error("devices/%s - htaborg 0x%x not aligned to htabmask 0x%x\n",
+ device_name(parent), *htaborg, *htabmask);
+ }
+ DTRACE(htab, ("htab - htaborg=0x%x htabmask=0x%x\n",
+ *htaborg, *htabmask));
+}
+
+
+STATIC_INLINE void
+htab_map_page(device *me,
+ unsigned_word ra,
+ unsigned64 va,
+ unsigned wimg,
+ unsigned pp,
+ unsigned32 htaborg,
+ unsigned32 htabmask)
+{
+ unsigned64 vpn = va << 12;
+ unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
+ unsigned32 page = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
+ unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
+ ^ EXTRACTED32(page, 0, 15),
+ 7, 31-6);
+ int h;
+ for (h = 0; h < 2; h++) {
+ unsigned32 pteg = (htaborg | (hash & htabmask));
+ int pti;
+ for (pti = 0; pti < 8; pti++, pteg += 8) {
+ unsigned32 pte0;
+ if (device_dma_read_buffer(device_parent(me),
+ &pte0,
+ 0, /*space*/
+ pteg,
+ sizeof(pte0)) != 4)
+ error("htab_init_callback() failed to read a pte at 0x%x\n",
+ pteg);
+ if (!MASKED32(pte0, 0, 0)) {
+ /* empty pte fill it */
+ unsigned32 pte0 = (MASK32(0, 0)
+ | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
+ | INSERTED32(h, 25, 25)
+ | INSERTED32(EXTRACTED32(page, 0, 5), 26, 31));
+ unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
+ | INSERTED32(wimg, 25, 28)
+ | INSERTED32(pp, 30, 31));
+ if (device_dma_write_buffer(device_parent(me),
+ &pte0,
+ 0, /*space*/
+ pteg,
+ sizeof(pte0),
+ 1/*ro?*/) != 4
+ || device_dma_write_buffer(device_parent(me),
+ &pte1,
+ 0, /*space*/
+ pteg + 4,
+ sizeof(pte1),
+ 1/*ro?*/) != 4)
+ error("htab_init_callback() failed to write a pte a 0x%x\n",
+ pteg);
+ DTRACE(htab, ("map - va=0x%lx ra=0x%lx &pte0=0x%lx pte0=0x%lx pte1=0x%lx\n",
+ (unsigned long)va, (unsigned long)ra,
+ (unsigned long)pteg,
+ (unsigned long)pte0, (unsigned long)pte1));
+ return;
+ }
+ }
+ /* re-hash */
+ hash = MASKED32(~hash, 0, 18);
+ }
+}
+
+STATIC_INLINE_DEVICE_TABLE void
+htab_map_region(device *me,
+ unsigned_word pte_ra,
+ unsigned_word pte_va,
+ unsigned nr_bytes,
+ unsigned wimg,
+ unsigned pp,
+ unsigned32 htaborg,
+ unsigned32 htabmask)
+{
+ unsigned_word ra;
+ unsigned64 va;
+ /* go through all pages and create a pte for each */
+ for (ra = pte_ra, va = (signed_word)pte_va;
+ ra < pte_ra + nr_bytes;
+ ra += 0x1000, va += 0x1000) {
+ htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
+ }
+}
+
+typedef struct _htab_binary_sizes {
+ unsigned_word text_ra;
+ unsigned_word text_base;
+ unsigned_word text_bound;
+ unsigned_word data_ra;
+ unsigned_word data_base;
+ unsigned data_bound;
+ device *me;
+} htab_binary_sizes;
+
+STATIC_INLINE_DEVICE_TABLE void
+htab_sum_binary(bfd *abfd,
+ sec_ptr sec,
+ PTR data)
+{
+ htab_binary_sizes *sizes = (htab_binary_sizes*)data;
+ unsigned_word size = bfd_get_section_size_before_reloc (sec);
+ unsigned_word vma = bfd_get_section_vma (abfd, sec);
+
+ /* skip the section if no memory to allocate */
+ if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
+ return;
+
+ if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
+ || (bfd_get_section_flags (abfd, sec) & SEC_READONLY)) {
+ if (sizes->text_bound < vma + size)
+ sizes->text_bound = ALIGN_PAGE(vma + size);
+ if (sizes->text_base > vma)
+ sizes->text_base = FLOOR_PAGE(vma);
+ }
+ else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA)
+ || (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) {
+ if (sizes->data_bound < vma + size)
+ sizes->data_bound = ALIGN_PAGE(vma + size);
+ if (sizes->data_base > vma)
+ sizes->data_base = FLOOR_PAGE(vma);
+ }
+}
+
+STATIC_INLINE_DEVICE_TABLE void
+htab_dma_binary(bfd *abfd,
+ sec_ptr sec,
+ PTR data)
+{
+ htab_binary_sizes *sizes = (htab_binary_sizes*)data;
+ void *section_init;
+ unsigned_word section_vma;
+ unsigned_word section_size;
+ unsigned_word section_ra;
+ device *me = sizes->me;
+
+ /* skip the section if no memory to allocate */
+ if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
+ return;
+
+ /* check/ignore any sections of size zero */
+ section_size = bfd_get_section_size_before_reloc(sec);
+ if (section_size == 0)
+ return;
+
+ /* if nothing to load, ignore this one */
+ if (! (bfd_get_section_flags(abfd, sec) & SEC_LOAD))
+ return;
+
+ /* find where it is to go */
+ section_vma = bfd_get_section_vma(abfd, sec);
+ section_ra = 0;
+ if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
+ || (bfd_get_section_flags (abfd, sec) & SEC_READONLY))
+ section_ra = (section_vma - sizes->text_base + sizes->text_ra);
+ else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA))
+ section_ra = (section_vma - sizes->data_base + sizes->data_ra);
+ else
+ return; /* just ignore it */
+
+ DTRACE(htab,
+ ("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
+ bfd_get_section_name(abfd, sec),
+ (long)section_vma,
+ (long)section_size,
+ (long)section_ra,
+ (long)bfd_get_section_flags(abfd, sec),
+ bfd_get_section_flags(abfd, sec) & SEC_LOAD ? " LOAD" : "",
+ bfd_get_section_flags(abfd, sec) & SEC_CODE ? " CODE" : "",
+ bfd_get_section_flags(abfd, sec) & SEC_DATA ? " DATA" : "",
+ bfd_get_section_flags(abfd, sec) & SEC_ALLOC ? " ALLOC" : "",
+ bfd_get_section_flags(abfd, sec) & SEC_READONLY ? " READONLY" : ""
+ ));
+
+ /* dma in the sections data */
+ section_init = zalloc(section_size);
+ if (!bfd_get_section_contents(abfd,
+ sec,
+ section_init, 0,
+ section_size)) {
+ bfd_perror("devices/pte");
+ error("devices/%s - no data loaded\n", device_name(me));
+ }
+ if (device_dma_write_buffer(device_parent(me),
+ section_init,
+ 0 /*space*/,
+ section_ra,
+ section_size,
+ 1 /*violate_read_only*/)
+ != section_size)
+ error("devices/%s - broken dma transfer\n", device_name(me));
+ zfree(section_init); /* only free if load */
+}
+
+
+STATIC_INLINE_DEVICE_TABLE void
+htab_map_binary(device *me,
+ unsigned_word ra,
+ unsigned wimg,
+ unsigned pp,
+ char *file_name,
+ unsigned32 htaborg,
+ unsigned32 htabmask)
+{
+ htab_binary_sizes sizes;
+ bfd *image;
+ sizes.text_base = -1;
+ sizes.data_base = -1;
+ sizes.text_bound = 0;
+ sizes.data_bound = 0;
+ sizes.me = me;
+
+ /* open the file */
+ image = bfd_openr(file_name, NULL);
+ if (image == NULL) {
+ bfd_perror("devices/pte");
+ error("devices/%s - the file %s not loaded\n", device_name(me), file_name);
+ }
+
+ /* check it is valid */
+ if (!bfd_check_format(image, bfd_object)) {
+ bfd_close(image);
+ error("devices/%s - the file %s has an invalid binary format\n",
+ device_name(me), file_name);
+ }
+
+ /* determine the size of each of the files regions */
+ bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
+
+ /* determine the real addresses of the sections */
+ sizes.text_ra = ra;
+ sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
+ (sizes.text_bound - sizes.text_base));
+
+ DTRACE(htab, ("text map - base=0x%lx bound=0x%lx ra=0x%lx\n",
+ sizes.text_base, sizes.text_bound, sizes.text_ra));
+ DTRACE(htab, ("data map - base=0x%lx bound=0x%lx ra=0x%lx\n",
+ sizes.data_base, sizes.data_bound, sizes.data_ra));
+
+ /* set up virtual memory maps for each of the regions */
+ htab_map_region(me, sizes.text_ra, sizes.text_base,
+ sizes.text_bound - sizes.text_base,
+ wimg, pp,
+ htaborg, htabmask);
+ htab_map_region(me, sizes.data_ra, sizes.data_base,
+ sizes.data_bound - sizes.data_base,
+ wimg, pp,
+ htaborg, htabmask);
+
+ /* dma the sections into physical memory */
+ bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
+}
+
+static void
+htab_init_callback(device *me,
+ psim *system)
+{
+ if (WITH_TARGET_WORD_BITSIZE != 32)
+ error("devices/htab: only 32bit targets currently suported\n");
+
+ /* only the pte does work */
+ if (strncmp(device_name(me), "pte@", strlen("pte@")) == 0) {
+ unsigned32 htaborg;
+ unsigned32 htabmask;
+ signed32 pte_va; /* so that 0xff...0 is make 0xffffff00 */
+ unsigned32 pte_ra;
+ unsigned pte_nr_bytes;
+ unsigned pte_wimg;
+ unsigned pte_pp;
+ char file_name[1024];
+
+ htab_decode_hash_table(device_parent(me), &htaborg, &htabmask);
+
+ /* handle a normal mapping definition */
+ if (scand_uw_uw_u_u_u(device_name(me), &pte_ra, &pte_va, &pte_nr_bytes,
+ &pte_wimg, &pte_pp) == 5) {
+ DTRACE(htab, ("pte - ra=0x%x, wimg=%d, pp=%d, va=0x%x, nr_bytes=%d\n",
+ pte_ra, pte_wimg, pte_pp, pte_va, pte_nr_bytes));
+ htab_map_region(me, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
+ htaborg, htabmask);
+ }
+ else if (scand_uw_u_u_c(device_name(me), &pte_ra, &pte_wimg, &pte_pp,
+ file_name, sizeof(file_name)) == 4) {
+ DTRACE(htab, ("pte - ra=0x%x, wimg=%d, pp=%d, binary=%s\n",
+ pte_ra, pte_wimg, pte_pp, file_name));
+ htab_map_binary(me, pte_ra, pte_wimg, pte_pp, file_name,
+ htaborg, htabmask);
+ }
+ else {
+ error("devices/%s - Usage: %s\nor\t%s\n",
+ device_name(me),
+ "pte@,<real-addr>,<virtual-addr>,<nr-bytes>,<wimg>,<pp>",
+ "pte@<real-addr>,<wimg>,<pp>,<binary>");
+ }
+ }
+}
+
+
+static device_callbacks const htab_callbacks = {
+ htab_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ passthrough_device_dma_read_buffer,
+ passthrough_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* Simulator device: sim@0x<address>,<nr_bytes>
+
+ Eventually gives access to the hardware configuration. For
+ instance, it could allow the setting (on the fly) of variables such
+ as hardware floating-point or strict-alignment.
+
+ It's intended use is as part of testing the simulators
+ functionality */
+
+static device_callbacks const sim_callbacks = {
+ ignore_device_init,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* Load device: binary
+
+ Single property the name of which specifies the file (understood by
+ BFD) that is to be DMAed into memory as part of init */
+
+STATIC_INLINE_DEVICE_TABLE void
+update_for_binary_section(bfd *abfd,
+ asection *the_section,
+ PTR obj)
+{
+ unsigned_word section_vma;
+ unsigned_word section_size;
+ access_type access;
+ device *me = (device*)obj;
+
+ /* skip the section if no memory to allocate */
+ if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
+ return;
+
+ /* check/ignore any sections of size zero */
+ section_size = bfd_get_section_size_before_reloc(the_section);
+ if (section_size == 0)
+ return;
+
+ /* find where it is to go */
+ section_vma = bfd_get_section_vma(abfd, the_section);
+
+ DTRACE(binary,
+ ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
+ bfd_get_section_name(abfd, the_section),
+ (long)section_vma,
+ (long)section_size,
+ (long)bfd_get_section_flags(abfd, the_section),
+ bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
+ ));
+
+ /* determine the devices access */
+ access = access_read;
+ if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
+ access |= access_exec;
+ if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
+ access |= access_write;
+
+ /* if a map, pass up a request to create the memory in core */
+ if (strncmp(device_name(me), "map-binary", strlen("map-binary")) == 0)
+ device_attach_address(device_parent(me),
+ device_name(me),
+ attach_raw_memory,
+ 0 /*address space*/,
+ section_vma,
+ section_size,
+ access,
+ me);
+
+ /* if a load dma in the required data */
+ if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
+ void *section_init = zalloc(section_size);
+ if (!bfd_get_section_contents(abfd,
+ the_section,
+ section_init, 0,
+ section_size)) {
+ bfd_perror("core:load_section()");
+ error("load of data failed");
+ return;
+ }
+ if (device_dma_write_buffer(device_parent(me),
+ section_init,
+ 0 /*space*/,
+ section_vma,
+ section_size,
+ 1 /*violate_read_only*/)
+ != section_size)
+ error("data_init_callback() broken transfer for %s\n", device_name(me));
+ zfree(section_init); /* only free if load */
+ }
+}
+
+
+static void
+binary_init_callback(device *me,
+ psim *system)
+{
+ const char *file_name;
+ bfd *image;
+
+
+ /* get the property specifying the file name */
+ file_name = device_find_next_property(me, NULL);
+
+ /* open the file */
+ image = bfd_openr(file_name, NULL);
+ if (image == NULL) {
+ bfd_perror("devices/binary");
+ error("devices/%s - the file %s not loaded\n", device_name(me), file_name);
+ }
+
+ /* check it is valid */
+ if (!bfd_check_format(image, bfd_object)) {
+ bfd_close(image);
+ error("devices/%s - the file %s has an invalid binary format\n",
+ device_name(me), file_name);
+ }
+
+ /* and the data sections */
+ bfd_map_over_sections(image,
+ update_for_binary_section,
+ (PTR)me);
+
+ bfd_close(image);
+}
+
+
+static device_callbacks const binary_callbacks = {
+ binary_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* Stack device: stack@<type>
+
+ Has a single IOCTL to create a stack frame of the specified type.
+ If <type> is elf or xcoff then a corresponding stack is created.
+ Any other value of type is ignored.
+
+ The IOCTL takes the additional arguments:
+
+ unsigned_word stack_end -- where the stack should come down from
+ char **argv -- ...
+ char **envp -- ...
+
+ */
+
+STATIC_INLINE_DEVICE_TABLE int
+sizeof_argument_strings(char **arg)
+{
+ int sizeof_strings = 0;
+
+ /* robust */
+ if (arg == NULL)
+ return 0;
+
+ /* add up all the string sizes (padding as we go) */
+ for (; *arg != NULL; arg++) {
+ int len = strlen(*arg) + 1;
+ sizeof_strings += ALIGN_8(len);
+ }
+
+ return sizeof_strings;
+}
+
+STATIC_INLINE_DEVICE_TABLE int
+number_of_arguments(char **arg)
+{
+ int nr;
+ if (arg == NULL)
+ return 0;
+ for (nr = 0; *arg != NULL; arg++, nr++);
+ return nr;
+}
+
+STATIC_INLINE_DEVICE_TABLE int
+sizeof_arguments(char **arg)
+{
+ return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
+}
+
+STATIC_INLINE_DEVICE_TABLE void
+write_stack_arguments(psim *system,
+ char **arg,
+ unsigned_word start_block,
+ unsigned_word end_block,
+ unsigned_word start_arg,
+ unsigned_word end_arg)
+{
+ DTRACE(stack,
+ ("write_stack_arguments(system=0x%lx, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
+ (long)system, (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
+ if (arg == NULL)
+ error("write_arguments: character array NULL\n");
+ /* only copy in arguments, memory is already zero */
+ for (; *arg != NULL; arg++) {
+ int len = strlen(*arg)+1;
+ unsigned_word target_start_block;
+ DTRACE(stack,
+ ("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
+ "**arg", *arg, "start_block", (long)start_block,
+ "len", (long)len, "start_arg", (long)start_arg));
+ if (psim_write_memory(system, 0, *arg,
+ start_block, len,
+ 0/*violate_readonly*/) != len)
+ error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
+ *arg, start_block);
+ target_start_block = H2T_word(start_block);
+ if (psim_write_memory(system, 0, &target_start_block,
+ start_arg, sizeof(target_start_block),
+ 0) != sizeof(target_start_block))
+ error("write_stack_arguments() - write of *arg failed\n");
+ start_block += ALIGN_8(len);
+ start_arg += sizeof(start_block);
+ }
+ start_arg += sizeof(start_block); /*the null at the end*/
+ if (start_block != end_block
+ || ALIGN_8(start_arg) != end_arg)
+ error("write_stack_arguments - possible corruption\n");
+ DTRACE(stack,
+ ("write_stack_arguments() = void\n"));
+}
+
+STATIC_INLINE_DEVICE_TABLE void
+create_elf_stack_frame(psim *system,
+ unsigned_word bottom_of_stack,
+ char **argv,
+ char **envp)
+{
+ /* fixme - this is over aligned */
+
+ /* information block */
+ const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
+ const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
+ const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
+ const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
+
+ /* auxiliary vector - contains only one entry */
+ const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
+ const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
+
+ /* environment points (including null sentinal) */
+ const unsigned sizeof_envp = sizeof_arguments(envp);
+ const unsigned_word start_envp = start_aux - sizeof_envp;
+
+ /* argument pointers (including null sentinal) */
+ const int argc = number_of_arguments(argv);
+ const unsigned sizeof_argv = sizeof_arguments(argv);
+ const unsigned_word start_argv = start_envp - sizeof_argv;
+
+ /* link register save address - alligned to a 16byte boundary */
+ const unsigned_word top_of_stack = ((start_argv
+ - 2 * sizeof(unsigned_word))
+ & ~0xf);
+
+ /* install arguments on stack */
+ write_stack_arguments(system, envp,
+ start_envp_block, bottom_of_stack,
+ start_envp, start_aux);
+ write_stack_arguments(system, argv,
+ start_argv_block, start_envp_block,
+ start_argv, start_envp);
+
+ /* set up the registers */
+ psim_write_register(system, -1,
+ &top_of_stack, "sp", cooked_transfer);
+ psim_write_register(system, -1,
+ &argc, "r3", cooked_transfer);
+ psim_write_register(system, -1,
+ &start_argv, "r4", cooked_transfer);
+ psim_write_register(system, -1,
+ &start_envp, "r5", cooked_transfer);
+ psim_write_register(system, -1,
+ &start_aux, "r6", cooked_transfer);
+}
+
+STATIC_INLINE_DEVICE_TABLE void
+create_aix_stack_frame(psim *system,
+ unsigned_word bottom_of_stack,
+ char **argv,
+ char **envp)
+{
+ unsigned_word core_envp;
+ unsigned_word core_argv;
+ unsigned_word core_argc;
+ unsigned_word core_aux;
+ unsigned_word top_of_stack;
+
+ /* cheat - create an elf stack frame */
+ create_elf_stack_frame(system, bottom_of_stack, argv, envp);
+
+ /* extract argument addresses from registers */
+ psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer);
+ psim_read_register(system, 0, &core_argc, "r3", cooked_transfer);
+ psim_read_register(system, 0, &core_argv, "r4", cooked_transfer);
+ psim_read_register(system, 0, &core_envp, "r5", cooked_transfer);
+ psim_read_register(system, 0, &core_aux, "r6", cooked_transfer);
+
+ /* extract arguments from registers */
+ error("create_aix_stack_frame() - what happens next?\n");
+}
+
+
+
+static void
+stack_ioctl_callback(device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ va_list ap)
+{
+ unsigned_word stack_pointer;
+ const char *stack_type;
+ char **argv;
+ char **envp;
+ stack_pointer = va_arg(ap, unsigned_word);
+ argv = va_arg(ap, char **);
+ envp = va_arg(ap, char **);
+ DTRACE(stack,
+ ("stack_ioctl_callback(me=0x%lx:%s, system=0x%lx, processor=0x%lx, cia=0x%lx, argv=0x%lx, envp=0x%lx)\n",
+ (long)me, device_name(me), (long)system, (long)processor, (long)cia, (long)argv, (long)envp));
+ stack_type = device_find_next_property(me, NULL);
+ if (stack_type != NULL) {
+ if (strcmp(stack_type, "elf") == 0)
+ create_elf_stack_frame(system, stack_pointer, argv, envp);
+ else if (strcmp(stack_type, "xcoff") == 0)
+ create_aix_stack_frame(system, stack_pointer, argv, envp);
+ }
+ DTRACE(stack,
+ ("stack_ioctl_callback() = void\n"));
+}
+
+\f
+
+
+static device_callbacks const stack_callbacks = {
+ ignore_device_init,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ stack_ioctl_callback,
+};
+
+
+\f
+device_descriptor device_table[] = {
+ { "console", console_create, &console_callbacks },
+ { "memory", NULL, &memory_callbacks },
+ { "vm", vea_vm_create, &vm_callbacks },
+ { "halt", NULL, &halt_callbacks },
+ { "icu", NULL, &icu_callbacks },
+ { "register", NULL, ®ister_callbacks },
+ { "iobus", NULL, &iobus_callbacks },
+ { "file", NULL, &file_callbacks },
+ { "data", NULL, &data_callbacks },
+ { "htab", NULL, &htab_callbacks },
+ { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
+ { "stack", NULL, &stack_callbacks },
+ { "sim", NULL, &sim_callbacks },
+ { "load-binary", NULL, &binary_callbacks },
+ { "map-binary", NULL, &binary_callbacks },
+ { "options", NULL, &passthrough_callbacks },
+ { "init", NULL, &passthrough_callbacks },
+ { "chosen", NULL, &passthrough_callbacks },
+ { NULL },
+};
+
+#endif /* _DEVICE_TABLE_C_ */
+++ /dev/null
-/* 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_ */
+++ /dev/null
-/* 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_ */
+++ /dev/null
-/* 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_C_
-#define _DEVICES_C_
-
-#ifndef STATIC_INLINE_DEVICES
-#define STATIC_INLINE_DEVICES STATIC_INLINE
-#endif
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-
-#include "basics.h"
-#include "devices.h"
-#include "events.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#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
-
-#include "cpu.h"
-
-#include "bfd.h"
-
-/* Helper functions */
-
-/* Generic device init: Attaches the device of size <nr_bytes> (taken
- from <name>@<int>,<nr_bytes>) to its parent at address zero and
- with read/write access. */
-
-STATIC_INLINE_DEVICES void
-generic_init_callback(const device *me,
- psim *system)
-{
- unsigned_word addr;
- unsigned nr_bytes;
- if (scand_uw_u(me->name, &addr, &nr_bytes) != 2)
- error("generic_init_callback() invalid nr_bytes in %s\n", me->name);
- me->parent->callback->attach_address(me->parent,
- me->name,
- attach_callback,
- 0 /*space*/,
- addr,
- nr_bytes,
- access_read_write,
- me);
-}
-
-
-/* DMA a file into memory */
-STATIC_INLINE_DEVICES int
-dma_file(const device *me,
- const char *file_name,
- unsigned_word addr)
-{
- int count;
- int inc;
- FILE *image;
- char buf[1024];
-
- /* get it open */
- image = fopen(file_name, "r");
- if (image == NULL)
- return -1;
-
- /* read it in slowly */
- count = 0;
- while (1) {
- inc = fread(buf, sizeof(buf), 1, image);
- if (inc <= 0)
- break;
- if (me->parent->callback->dma_write_buffer(me->parent,
- buf,
- 0 /*address-space*/,
- addr+count,
- inc /*nr-bytes*/,
- 1 /*violate ro*/) != inc) {
- fclose(image);
- return -1;
- }
- count += inc;
- }
-
- /* close down again */
- fclose(image);
-
- return count;
-}
-
-
-\f
-/* inimplemented versions of each function */
-
-INLINE_DEVICES void
-unimp_device_init(const device *me,
- psim *system)
-{
- error("device_init_callback for %s not implemented\n", me->name);
-}
-
-INLINE_DEVICES void
-unimp_device_attach_address(const device *me,
- const char *name,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- const device *who) /*callback/default*/
-{
- error("device_attach_address_callback for %s not implemented\n", me->name);
-}
-
-INLINE_DEVICES void
-unimp_device_detach_address(const device *me,
- const char *name,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- const device *who) /*callback/default*/
-{
- error("device_detach_address_callback for %s not implemented\n", me->name);
-}
-
-INLINE_DEVICES unsigned
-unimp_device_io_read_buffer(const device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- error("device_io_read_buffer_callback for %s not implemented\n", me->name);
- return 0;
-}
-
-INLINE_DEVICES unsigned
-unimp_device_io_write_buffer(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- error("device_io_write_buffer_callback for %s not implemented\n", me->name);
- return 0;
-}
-
-INLINE_DEVICES unsigned
-unimp_device_dma_read_buffer(const device *me,
- void *target,
- int space,
- unsigned_word addr,
- unsigned nr_bytes)
-{
- error("device_dma_read_buffer_callback for %s not implemented\n", me->name);
- return 0;
-}
-
-INLINE_DEVICES unsigned
-unimp_device_dma_write_buffer(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- int violate_read_only_section)
-{
- error("device_dma_write_buffer_callback for %s not implemented\n", me->name);
- return 0;
-}
-
-INLINE_DEVICES void
-unimp_device_attach_interrupt(const device *me,
- const device *who,
- int interrupt_line,
- const char *name)
-{
- error("device_attach_interrupt_callback for %s not implemented\n", me->name);
-}
-
-INLINE_DEVICES void
-unimp_device_detach_interrupt(const device *me,
- const device *who,
- int interrupt_line,
- const char *name)
-{
- error("device_detach_interrupt_callback for %s not implemented\n", me->name);
-}
-
-INLINE_DEVICES void
-unimp_device_interrupt(const device *me,
- const device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
-{
- error("device_interrupt_callback for %s not implemented\n", me->name);
-}
-
-INLINE_DEVICES void
-unimp_device_interrupt_ack(const device *me,
- int interrupt_line,
- int interrupt_status)
-{
- error("device_interrupt_ack_callback for %s not implemented\n", me->name);
-}
-
-STATIC_DEVICES void
-unimp_device_ioctl(const device *me,
- psim *system,
- cpu *processor,
- unsigned_word cia,
- ...)
-{
- error("device_ioctl_callback for %s not implemented\n", me->name);
-}
-
-
-\f
-/* ignore/passthrough versions of each function */
-
-INLINE_DEVICES void
-ignore_device_init(const device *me,
- psim *system)
-{
- /*null*/
-}
-
-INLINE_DEVICES void
-pass_device_attach_address(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*/
-{
- DTRACE_ATTACH_ADDRESS(pass);
- me->parent->callback->attach_address(me->parent, name, attach,
- space, addr, nr_bytes,
- access,
- who);
-}
-
-INLINE_DEVICES void
-pass_device_detach_address(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*/
-{
- DTRACE_DETACH_ADDRESS(pass);
- me->parent->callback->detach_address(me->parent, name, attach,
- space, addr, nr_bytes, access,
- who);
-}
-
-INLINE_DEVICES unsigned
-pass_device_dma_read_buffer(const device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes)
-{
- DTRACE_DMA_READ_BUFFER(pass);
- return me->parent->callback->dma_read_buffer(me->parent, dest,
- space, addr, nr_bytes);
-}
-
-INLINE_DEVICES unsigned
-pass_device_dma_write_buffer(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- int violate_read_only_section)
-{
- DTRACE_DMA_WRITE_BUFFER(pass);
- return me->parent->callback->dma_write_buffer(me->parent, source,
- space, addr,
- nr_bytes,
- violate_read_only_section);
-}
-
-INLINE_DEVICES void
-pass_device_attach_interrupt(const device *me,
- const device *who,
- int interrupt_line,
- const char *name)
-{
- me->parent->callback->attach_interrupt(me->parent, who,
- interrupt_line, name);
-}
-
-INLINE_DEVICES void
-pass_device_detach_interrupt(const device *me,
- const device *who,
- int interrupt_line,
- const char *name)
-{
- me->parent->callback->detach_interrupt(me->parent, who,
- interrupt_line, name);
-}
-
-
-INLINE_DEVICES void
-pass_device_interrupt(const device *me,
- const device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
-{
- me->parent->callback->interrupt(me->parent, who,
- interrupt_line, interrupt_status,
- processor, cia);
-}
-
-
-\f
-/* Simple console device: console@<address>,16
-
- Input characters are taken from the keyboard, output characters
- sent to the terminal. Echoing of characters is not disabled.
-
- The device has four registers:
-
- 0x0: read
- 0x4: read-status
- 0x8: write
- 0xC: write-status
-
- Where a nonzero status register indicates that the device is ready
- (input fifo contains a character or output fifo has space). */
-
-typedef struct _console_buffer {
- char buffer;
- int status;
- event_entry_tag event_tag;
-} console_buffer;
-
-typedef struct _console_device {
- console_buffer input;
- console_buffer output;
-} console_device;
-
-typedef enum {
- console_read_buffer = 0,
- console_read_status = 4,
- console_write_buffer = 8,
- console_write_status = 12,
- console_offset_mask = 0xc,
- console_size = 16,
-} console_offsets;
-
-
-STATIC_INLINE_DEVICES unsigned
-console_io_read_buffer_callback(const device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- console_device *console = (console_device*)me->data;
- unsigned_1 val;
- DTRACE_IO_READ_BUFFER(console);
-
- /* determine what was read */
-
- switch ((int)addr) {
-
- case console_read_buffer:
- val = console->input.buffer;
- break;
-
- case console_read_status:
- { /* check for input */
- int flags;
- int status;
- /* get the old status */
- flags = fcntl(0, F_GETFL, 0);
- if (flags == -1) {
- perror("console");
- val = 0;
- break;
- }
- /* temp, disable blocking IO */
- status = fcntl(0, F_SETFL, flags | O_NDELAY);
- if (status == -1) {
- perror("console");
- val = 0;
- break;
- }
- /* try for input */
- status = read(0, &console->input.buffer, 1);
- if (status == 1) {
- console->input.status = 1;
- }
- else {
- console->input.status = 0;
- }
- /* return to regular vewing */
- fcntl(0, F_SETFL, flags);
- }
- val = console->input.status;
- break;
-
- case console_write_buffer:
- val = console->output.buffer;
- break;
-
- case console_write_status:
- val = console->output.status;
- break;
-
- default:
- error("console_read_callback() internal error\n");
- val = 0;
- break;
-
- }
-
- memset(dest, 0, nr_bytes);
- *(unsigned_1*)dest = val;
- return nr_bytes;
-}
-
-STATIC_INLINE_DEVICES unsigned
-console_io_write_buffer_callback(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- console_device *console = (console_device*)me->data;
- unsigned_1 val = *(unsigned_1*)source;
- DTRACE_IO_WRITE_BUFFER(console);
-
- switch ((int)addr) {
- case console_read_buffer:
- console->input.buffer = val;
- break;
- case console_read_status:
- console->input.status = val;
- break;
- case console_write_buffer:
- DTRACE(console, ("<%c:%d>", val, val));
- printf_filtered("%c",val) ;
- console->output.buffer = val;
- console->output.status = 1;
- break;
- case console_write_status:
- console->output.status = val;
- break;
- default:
- error("console_write_callback() internal error\n");
- }
-
- return nr_bytes;
-}
-
-
-static device_callbacks const console_callbacks = {
- generic_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- console_io_read_buffer_callback,
- console_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-STATIC_INLINE_DEVICES const device *
-console_create(const char *name,
- const char *full_name,
- const device *parent)
-{
- /* create the descriptor */
- console_device *console = ZALLOC(console_device);
-
- /* fill in the details */
- console->output.status = 1;
- console->output.buffer = '\0';
- console->input.status = 0;
- console->input.buffer = '\0';
-
- /* insert into the device tree along with its address info */
- return device_create_from(name,
- full_name,
- console, /* data */
- &console_callbacks,
- parent);
-}
-
-
-\f
-/* ICU device: icu@0x<address>,4
-
- Single 4 byte register. Read returns processor number. Write
- interrupts specified processor.
-
- Illustrates passing of events to parent device. Passing of
- interrupts to parent bus.
-
- NB: For the sake of illustrating the passing of interrupts. This
- device doesn't pass interrupt events to its parent. Instead it
- passes them back to its self. */
-
-STATIC_INLINE_DEVICES unsigned
-icu_io_read_buffer_callback(const device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- unsigned_1 val;
- DTRACE_IO_READ_BUFFER(icu);
- val = cpu_nr(processor);
- memset(dest, 0, nr_bytes);
- *(unsigned_1*)dest = val;
- return nr_bytes;
-}
-
-
-STATIC_INLINE_DEVICES unsigned
-icu_io_write_buffer_callback(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- unsigned_1 val = H2T_1(*(unsigned_1*)source);
- DTRACE_IO_WRITE_BUFFER(icu);
- /* tell the parent device that the interrupt lines have changed.
- For this fake ICU. The interrupt lines just indicate the cpu to
- interrupt next */
- me->parent->callback->interrupt(me->parent, me,
- val, val,
- processor, cia);
- return nr_bytes;
-}
-
-
-static device_callbacks const icu_callbacks = {
- generic_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- icu_io_read_buffer_callback,
- icu_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* HALT device: halt@0x<address>,4
-
- With real hardware, the processor operation is normally terminated
- through a reset. This device illustrates how a reset device could
- be attached to an address */
-
-
-STATIC_INLINE_DEVICES unsigned
-halt_io_read_buffer_callback(const device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- DTRACE_IO_READ_BUFFER(halt);
- cpu_halt(processor, cia, was_exited, 0);
- return 0;
-}
-
-
-STATIC_INLINE_DEVICES unsigned
-halt_io_write_buffer_callback(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- DTRACE_IO_WRITE_BUFFER(halt);
- cpu_halt(processor, cia, was_exited, *(unsigned_1*)source);
- return 0;
-}
-
-
-static device_callbacks const halt_callbacks = {
- generic_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- halt_io_read_buffer_callback,
- halt_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Register init device: register@<name>,0x<value>[,<processor>]
-
- This strange device is used to initialize the processors registers
- as part of the initialization. */
-
-STATIC_INLINE_DEVICES void
-register_init_callback(const device *me,
- psim *system)
-{
- char name[100];
- unsigned_word value;
- unsigned which_cpu;
- int status;
- DTRACE_INIT(register);
- status = scand_c_uw_u(me->name, name, sizeof(name), &value, &which_cpu);
- switch (status) {
- case 2: /* register@<name>,<value> */
- psim_write_register(system, -1, &value, name, cooked_transfer);
- break;
- case 3: /* register@<name>,<value>,<processor> */
- psim_write_register(system, which_cpu, &value, name, cooked_transfer);
- break;
- default:
- error("register_init_callback() invalid register init %s\n", me->name);
- break;
- }
-}
-
-
-static device_callbacks const register_callbacks = {
- register_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* VEA VM device: vm@0x<stack-base>,<nr_bytes>
-
- A VEA mode device. This sets its self up as the default memory
- device capturing all accesses (reads/writes) to currently unmapped
- addresses. If the unmaped access falls within unallocated stack or
- heap address ranges then memory is allocated and the access is
- allowed to continue.
-
- During init phase, this device expects to receive `attach' requests
- from its children for the text/data/bss memory areas. Typically,
- this would be done by the binary device.
-
- STACK: The location of the stack in memory is specified as part of
- the devices name. Unmaped accesses that fall within the stack
- space result in the allocated stack being grown downwards so that
- it includes the page of the culprit access.
-
- HEAP: During initialization, the vm device monitors all `attach'
- operations from its children using this to determine the initial
- location of the heap. The heap is then extended by system calls
- that frob the heap upper bound variable (see system.c). */
-
-
-typedef struct _vm_device {
- /* area of memory valid for stack addresses */
- unsigned_word stack_base; /* min possible stack value */
- unsigned_word stack_bound;
- unsigned_word stack_lower_limit;
- /* area of memory valid for heap addresses */
- unsigned_word heap_base;
- unsigned_word heap_bound;
- unsigned_word heap_upper_limit;
-} vm_device;
-
-
-STATIC_INLINE_DEVICES void
-vm_init_callback(const device *me,
- psim *system)
-{
- vm_device *vm = (vm_device*)me->data;
- DTRACE_INIT(vm);
-
- /* revert the stack/heap variables to their defaults */
- vm->stack_lower_limit = vm->stack_bound;
- vm->heap_base = 0;
- vm->heap_bound = 0;
- vm->heap_upper_limit = 0;
-
- /* establish this device as the default memory handler */
- me->parent->callback->attach_address(me->parent,
- me->name,
- attach_default,
- 0 /*address space - ignore*/,
- 0 /*addr - ignore*/,
- 0 /*nr_bytes - ignore*/,
- access_read_write /*access*/,
- me);
-}
-
-
-STATIC_INLINE_DEVICES void
-vm_attach_address(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*/
-{
- vm_device *vm = (vm_device*)me->data;
- DTRACE_ATTACH_ADDRESS(vm);
- /* update end of bss if necessary */
- if (vm->heap_base < addr + nr_bytes) {
- vm->heap_base = addr + nr_bytes;
- vm->heap_bound = addr + nr_bytes;
- vm->heap_upper_limit = addr + nr_bytes;
- }
- me->parent->callback->attach_address(me->parent,
- "vm@0x0,0", /* stop remap */
- attach_raw_memory,
- 0 /*address space*/,
- addr,
- nr_bytes,
- access,
- me);
-}
-
-
-STATIC_INLINE_DEVICES unsigned
-add_vm_space(const device *me,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- vm_device *vm = (vm_device*)me->data;
- unsigned_word block_addr;
- unsigned block_nr_bytes;
-
- /* an address in the stack area, allocate just down to the addressed
- page */
- if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
- block_addr = FLOOR_PAGE(addr);
- block_nr_bytes = vm->stack_lower_limit - block_addr;
- vm->stack_lower_limit = block_addr;
- }
- /* an address in the heap area, allocate all of the required heap */
- else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
- block_addr = vm->heap_upper_limit;
- block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
- vm->heap_upper_limit = vm->heap_bound;
- }
- /* oops - an invalid address - abort the cpu */
- else if (processor != NULL) {
- cpu_halt(processor, cia, was_signalled, SIGSEGV);
- return 0;
- }
- /* 2*oops - an invalid address and no processor */
- else {
- return 0;
- }
-
- /* got the parameters, allocate the space */
- me->parent->callback->attach_address(me->parent,
- "vm@0x0,0", /* stop remap */
- attach_raw_memory,
- 0 /*address space*/,
- block_addr,
- block_nr_bytes,
- access_read_write,
- me);
- return block_nr_bytes;
-}
-
-
-STATIC_INLINE_DEVICES unsigned
-vm_io_read_buffer_callback(const device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- DTRACE_IO_READ_BUFFER(vm);
- if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
- memset(dest, 0, nr_bytes); /* always initialized to zero */
- return nr_bytes;
- }
- else
- return 0;
-}
-
-
-STATIC_INLINE_DEVICES unsigned
-vm_io_write_buffer_callback(const device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
-{
- DTRACE_IO_WRITE_BUFFER(vm);
- if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
- return me->parent->callback->dma_write_buffer(me->parent, source,
- space, addr,
- nr_bytes,
- 0/*violate_read_only*/);
- }
- else
- return 0;
-}
-
-
-static void
-vm_ioctl_callback(const device *me,
- psim *system,
- cpu *processor,
- unsigned_word cia,
- ...)
-{
- /* While the caller is notified that the heap has grown by the
- requested amount, the heap is infact extended out to a page
- boundary. */
- vm_device *vm = (vm_device*)me->data;
- unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
- unsigned_word old_break = vm->heap_bound;
- signed_word delta = new_break - old_break;
- if (delta > 0)
- vm->heap_bound = ALIGN_PAGE(new_break);
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = new_break;
-}
-
-
-static device_callbacks const vm_callbacks = {
- vm_init_callback,
- vm_attach_address,
- pass_device_detach_address,
- vm_io_read_buffer_callback,
- vm_io_write_buffer_callback,
- unimp_device_dma_read_buffer,
- pass_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- vm_ioctl_callback,
-};
-
-
-STATIC_INLINE_DEVICES const device *
-vea_vm_create(const char *name,
- const char *full_name,
- const device *parent)
-{
- vm_device *vm = ZALLOC(vm_device);
- unsigned_word addr;
- unsigned nr_bytes;
-
- /* extract out the stack parameters */
- if (scand_uw_u(name, &addr, &nr_bytes) != 2)
- error("vm_device_create() invalid vm device %s\n", name);
- vm->stack_base = addr;
- vm->stack_bound = addr + nr_bytes;
-
- /* insert in the tree including the buffer */
- return device_create_from(name,
- full_name,
- vm, /* data */
- &vm_callbacks,
- parent);
-}
-
-
-\f
-/* Memory init device: memory@0x<addr>,<size>,<access>
-
- This strange device is used create sections of memory */
-
-STATIC_INLINE_DEVICES void
-memory_init_callback(const device *me,
- psim *system)
-{
- unsigned_word addr;
- unsigned nr_bytes;
- unsigned access;
- int nr_args;
- DTRACE_INIT(memory);
-
- nr_args = scand_uw_u_u(me->name, &addr, &nr_bytes, &access);
- switch (nr_args) {
- case 2:
- access = access_read_write_exec;
- break;
- case 3:
- break;
- default:
- error("memory_init_callback() invalid memory device %s\n", me->name);
- break;
- }
-
- me->parent->callback->attach_address(me->parent,
- me->name,
- attach_raw_memory,
- 0 /*address space*/,
- addr,
- nr_bytes,
- (access_type)access,
- me);
-}
-
-
-static device_callbacks const memory_callbacks = {
- memory_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* IOBUS device: iobus@<address>
-
- Simple bus on which some IO devices live */
-
-STATIC_INLINE_DEVICES void
-iobus_attach_address_callback(const device *me,
- const char *name,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- const device *who) /*callback/default*/
-{
- unsigned_word iobus_addr;
- /* sanity check */
- if (type == attach_default)
- error("iobus_attach_address_callback() no default for %s/%s\n",
- me->name, name);
- if (space != 0)
- error("iobus_attach_address_callback() no space for %s/%s\n",
- me->name, name);
- /* get the bus address */
- if (scand_uw(me->name, &iobus_addr) != 1)
- error("iobus_attach_address_callback() invalid address for %s\n",
- me->name);
- me->parent->callback->attach_address(me->parent,
- me->name,
- type,
- 0 /*space*/,
- iobus_addr + addr,
- nr_bytes,
- access,
- who);
-}
-
-
-STATIC_INLINE_DEVICES void
-iobus_do_interrupt(event_queue *queue,
- void *data)
-{
- cpu *target = (cpu*)data;
- /* try to interrupt the processor. If the attempt fails, try again
- on the next tick */
- if (!external_interrupt(target))
- event_queue_schedule(queue, 1, iobus_do_interrupt, target);
-}
-
-
-STATIC_INLINE_DEVICES void
-iobus_interrupt_callback(const device *me,
- const device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
-{
- /* the interrupt controler can't interrupt a cpu at any time.
- Rather it must synchronize with the system clock before
- performing an interrupt on the given processor */
- psim *system = cpu_system(processor);
- cpu *target = psim_cpu(system, interrupt_status);
- if (target != NULL) {
- event_queue *events = cpu_event_queue(target);
- event_queue_schedule(events, 1, iobus_do_interrupt, target);
- }
-}
-
-
-static device_callbacks const iobus_callbacks = {
- ignore_device_init,
- iobus_attach_address_callback,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- iobus_interrupt_callback,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* FILE device: file@0x<address>,<file-name>
- (later - file@0x<address>,<size>,<file-offset>,<file-name>)
-
- Specifies a file to read directly into memory starting at <address> */
-
-
-STATIC_INLINE_DEVICES void
-file_init_callback(const device *me,
- psim *system)
-{
- unsigned_word addr;
- int count;
- char file_name[1024];
- DTRACE_INIT(file);
-
- if (scand_uw_c(me->name, &addr, file_name, sizeof(file_name)) != 2)
- error("devices/file - Usage: file@<address>,<file-name>\n");
-
- /* load the file */
- count = dma_file(me, file_name, addr);
- if (count < 0)
- error("devices/%s - Problem loading file %s\n", me->name, file_name);
-}
-
-
-static device_callbacks const file_callbacks = {
- file_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* HTAB: htab@<address>,<nr_bytes>
- PTE: pte@<virtual-address>,<real-address>,<wimg>,<pp>,<nr_bytes>
- PTE: pte@<virtual-address>,<real-address>,<wimg>,<pp>,<file>
-
- HTAB defines the location (in physical memory) of a HASH table.
- PTE (as a child of HTAB) defines a mapping that is to be entered
- into that table.
-
- NB: All the work in this device is done during init by the PTE.
- The pte, looks up its parent to determine the address of the HTAB
- and then uses DMA calls to establish the required mapping. */
-
-
-STATIC_INLINE_DEVICES void
-htab_init_callback(const device *me,
- psim *system)
-{
- DTRACE_INIT(htab);
- if (WITH_TARGET_WORD_BITSIZE != 32)
- error("devices/htab: only 32bit targets currently suported\n");
- /* only the pte does work */
- if (strncmp(me->name, "pte@", strlen("pte@")) == 0) {
- unsigned32 htab_ra;
- unsigned htab_nr_bytes;
- signed32 pte_va; /* so that 0xff...0 is make 0xffffff00 */
- unsigned32 pte_ra;
- unsigned pte_nr_bytes;
- unsigned pte_wimg;
- unsigned pte_pp;
- unsigned32 ra;
- unsigned64 va;
- unsigned32 htaborg;
- unsigned32 htabmask;
- unsigned32 n;
-
- /* determine the location/size of the hash table */
- if (me->parent == NULL
- || strncmp(me->parent->name, "htab@", strlen("htab@")) != 0)
- error("devices/%s - Parent is not a htab device\n", me->name);
- if (scand_uw_u(me->parent->name, &htab_ra, &htab_nr_bytes) != 2)
- error("devices/%s - Usage: htab@<real-addr>,<nr_bytes>\n",
- me->parent->name);
- htabmask = EXTRACTED32(htab_nr_bytes - 1, 7, 15);
- for (n = htab_nr_bytes; n > 1; n = n / 2) {
- if (n % 2 != 0)
- error("devices/%s - htabmask 0x%x (size 0x%x) not a power of two\n",
- me->parent->name, htabmask, htab_nr_bytes);
- }
- htaborg = htab_ra;
- if ((htaborg & INSERTED32(htabmask, 7, 15)) != 0) {
- error("devices/%s - htaborg 0x%x not aligned to htabmask 0x%x\n",
- me->parent->name, htaborg, htabmask);
- }
-
- /* determine the location/size of the mapping */
- if (scand_uw_uw_u_u_u(me->name, &pte_va, &pte_ra,
- &pte_wimg, &pte_pp, &pte_nr_bytes) != 5) {
- int nr_bytes;
- char file_name[1024];
- if (scand_uw_uw_u_u_c(me->name, &pte_va, &pte_ra, &pte_wimg, &pte_pp,
- file_name, sizeof(file_name)) != 5)
- error("devices/%s - Usage: %s\nor\t%s\n",
- me->name,
- "pte@<virtual-addr>,<real-addr>,<wimg>,<pp>,<nr-bytes>",
- "pte@<virtual-addr>,<real-addr>,<wimg>,<pp>,<file>");
- /* load/validate it */
- nr_bytes = dma_file(me, file_name, pte_ra);
- if (nr_bytes < 0)
- error("devices/%s - problem loading file %s\n", me->name, file_name);
- pte_nr_bytes = nr_bytes;
- }
-
- /* go through all pages and create a pte for each */
- for (ra = pte_ra, va = (signed32)pte_va;
- ra < pte_ra + pte_nr_bytes;
- ra += 1024, va += 1024) {
- unsigned64 vpn = va << 12;
- unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
- unsigned32 page = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
- unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
- ^ EXTRACTED32(page, 0, 15),
- 0, 18);
- int h;
- for (h = 0; h < 2; h++) {
- unsigned32 pteg = (htaborg
- | INSERTED32(EXTRACTED32(hash, 0, 8) & htabmask, 7, 15)
- | INSERTED32(EXTRACTED32(hash, 9, 18), 16, 25));
- int pti;
- for (pti = 0; pti < 8; pti++, pteg += 8) {
- unsigned32 pte0;
- if (me->parent->callback->dma_read_buffer(me->parent,
- &pte0,
- 0, /*space*/
- pteg,
- sizeof(pte0)) != 4)
- error("htab_init_callback() failed to read a pte at 0x%x\n",
- pteg);
- if (!MASKED32(pte0, 0, 0)) {
- /* empty pte fill it */
- unsigned32 pte0 = (MASK32(0, 0)
- | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
- | INSERTED32(h, 25, 25)
- | INSERTED32(EXTRACTED32(page, 0, 5), 26, 31));
- unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
- | INSERTED32(pte_wimg, 25, 28)
- | INSERTED32(pte_pp, 30, 31));
- if (me->parent->callback->dma_write_buffer(me->parent,
- &pte0,
- 0, /*space*/
- pteg,
- sizeof(pte0),
- 1/*ro?*/) != 4
- || me->parent->callback->dma_write_buffer(me->parent,
- &pte1,
- 0, /*space*/
- pteg + 4,
- sizeof(pte1),
- 1/*ro?*/) != 4)
- error("htab_init_callback() failed to write a pte a 0x%x\n",
- pteg);
- return;
- }
- }
- /* re-hash */
- hash = MASKED32(~hash, 0, 18);
- }
- }
- }
-}
-
-
-static device_callbacks const htab_callbacks = {
- htab_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Simulator device: sim@0x<address>,<nr_bytes>
-
- Eventually gives access to the hardware configuration. For
- instance, it could allow the setting (on the fly) of variables such
- as hardware floating-point or strict-alignment.
-
- It's intended use is as part of testing the simulators
- functionality */
-
-static device_callbacks const sim_callbacks = {
- ignore_device_init,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Load device: binary@<file-name>
-
- Assuming that <file-name> is an executable file understood by BFD,
- this device loads or maps the relevant text/data segments into
- memory using dma. */
-
-STATIC_INLINE_DEVICES void
-update_for_binary_section(bfd *abfd,
- asection *the_section,
- PTR obj)
-{
- unsigned_word section_vma;
- unsigned_word section_size;
- access_type access;
- device *me = (device*)obj;
-
- /* skip the section if no memory to allocate */
- if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
- return;
-
- /* check/ignore any sections of size zero */
- section_size = bfd_get_section_size_before_reloc(the_section);
- if (section_size == 0)
- return;
-
- /* find where it is to go */
- section_vma = bfd_get_section_vma(abfd, the_section);
-
- DTRACE(binary,
- ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
- bfd_get_section_name(abfd, the_section),
- (long)section_vma,
- (long)section_size,
- (long)bfd_get_section_flags(abfd, the_section),
- bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
- ));
-
- /* determine the devices access */
- access = access_read;
- if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
- access |= access_exec;
- if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
- access |= access_write;
-
- /* if a map, pass up a request to create the memory in core */
- if (strncmp(me->name, "map-binary@", strlen("map-binary@")) == 0)
- me->parent->callback->attach_address(me->parent,
- me->name,
- attach_raw_memory,
- 0 /*address space*/,
- section_vma,
- section_size,
- access,
- me);
-
- /* if a load dma in the required data */
- if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
- void *section_init = zalloc(section_size);
- if (!bfd_get_section_contents(abfd,
- the_section,
- section_init, 0,
- section_size)) {
- bfd_perror("core:load_section()");
- error("load of data failed");
- return;
- }
- if (me->parent->callback->dma_write_buffer(me->parent,
- section_init,
- 0 /*space*/,
- section_vma,
- section_size,
- 1 /*violate_read_only*/)
- != section_size)
- error("data_init_callback() broken transfer for %s\n", me->name);
- zfree(section_init); /* only free if load */
- }
-}
-
-
-STATIC_INLINE_DEVICES void
-binary_init_callback(const device *me,
- psim *system)
-{
- char file_name[1024];
- bfd *image;
- DTRACE_INIT(binary);
-
- /* get a file name */
- if (scand_c(me->name, file_name, sizeof(file_name)) != 1)
- error("devices/binary - Usage: binary@<file-name>\n");
-
- /* open the file */
- image = bfd_openr(file_name, NULL);
- if (image == NULL) {
- bfd_perror("devices/binary");
- error("devices/%s - the file %s not loaded\n", me->name, file_name);
- }
-
- /* check it is valid */
- if (!bfd_check_format(image, bfd_object)) {
- printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
- printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
- bfd_close(image);
- image = NULL;
- }
-
- /* and the data sections */
- bfd_map_over_sections(image,
- update_for_binary_section,
- (PTR)me);
-
- bfd_close(image);
-}
-
-
-static device_callbacks const binary_callbacks = {
- binary_init_callback,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
-};
-
-
-\f
-/* Stack device: stack@<type>
-
- Has a single IOCTL to create a stack frame of the specified type.
- If <type> is elf or xcoff then a corresponding stack is created.
- Any other value of type is ignored.
-
- The IOCTL takes the additional arguments:
-
- unsigned_word stack_end -- where the stack should come down from
- char **argv -- ...
- char **envp -- ...
-
- */
-
-STATIC_INLINE_DEVICES int
-sizeof_argument_strings(char **arg)
-{
- int sizeof_strings = 0;
-
- /* robust */
- if (arg == NULL)
- return 0;
-
- /* add up all the string sizes (padding as we go) */
- for (; *arg != NULL; arg++) {
- int len = strlen(*arg) + 1;
- sizeof_strings += ALIGN_8(len);
- }
-
- return sizeof_strings;
-}
-
-STATIC_INLINE_DEVICES int
-number_of_arguments(char **arg)
-{
- int nr;
- if (arg == NULL)
- return 0;
- for (nr = 0; *arg != NULL; arg++, nr++);
- return nr;
-}
-
-STATIC_INLINE_DEVICES int
-sizeof_arguments(char **arg)
-{
- return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
-}
-
-STATIC_INLINE_DEVICES void
-write_stack_arguments(psim *system,
- char **arg,
- unsigned_word start_block,
- unsigned_word end_block,
- unsigned_word start_arg,
- unsigned_word end_arg)
-{
- DTRACE(stack,
- ("write_stack_arguments(system=0x%lx, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
- (long)system, (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
- if (arg == NULL)
- error("write_arguments: character array NULL\n");
- /* only copy in arguments, memory is already zero */
- for (; *arg != NULL; arg++) {
- int len = strlen(*arg)+1;
- unsigned_word target_start_block;
- DTRACE(stack,
- ("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
- "**arg", *arg, "start_block", (long)start_block,
- "len", (long)len, "start_arg", (long)start_arg));
- if (psim_write_memory(system, 0, *arg,
- start_block, len,
- 0/*violate_readonly*/) != len)
- error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
- *arg, start_block);
- target_start_block = H2T_word(start_block);
- if (psim_write_memory(system, 0, &target_start_block,
- start_arg, sizeof(target_start_block),
- 0) != sizeof(target_start_block))
- error("write_stack_arguments() - write of *arg failed\n");
- start_block += ALIGN_8(len);
- start_arg += sizeof(start_block);
- }
- start_arg += sizeof(start_block); /*the null at the end*/
- if (start_block != end_block
- || ALIGN_8(start_arg) != end_arg)
- error("write_stack_arguments - possible corruption\n");
- DTRACE(stack,
- ("write_stack_arguments() = void\n"));
-}
-
-STATIC_INLINE_DEVICES void
-create_elf_stack_frame(psim *system,
- unsigned_word bottom_of_stack,
- char **argv,
- char **envp)
-{
- /* fixme - this is over aligned */
-
- /* information block */
- const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
- const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
- const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
- const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
-
- /* auxiliary vector - contains only one entry */
- const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
- const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
-
- /* environment points (including null sentinal) */
- const unsigned sizeof_envp = sizeof_arguments(envp);
- const unsigned_word start_envp = start_aux - sizeof_envp;
-
- /* argument pointers (including null sentinal) */
- const int argc = number_of_arguments(argv);
- const unsigned sizeof_argv = sizeof_arguments(argv);
- const unsigned_word start_argv = start_envp - sizeof_argv;
-
- /* link register save address - alligned to a 16byte boundary */
- const unsigned_word top_of_stack = ((start_argv
- - 2 * sizeof(unsigned_word))
- & ~0xf);
-
- /* install arguments on stack */
- write_stack_arguments(system, envp,
- start_envp_block, bottom_of_stack,
- start_envp, start_aux);
- write_stack_arguments(system, argv,
- start_argv_block, start_envp_block,
- start_argv, start_envp);
-
- /* set up the registers */
- psim_write_register(system, -1,
- &top_of_stack, "sp", cooked_transfer);
- psim_write_register(system, -1,
- &argc, "r3", cooked_transfer);
- psim_write_register(system, -1,
- &start_argv, "r4", cooked_transfer);
- psim_write_register(system, -1,
- &start_envp, "r5", cooked_transfer);
- psim_write_register(system, -1,
- &start_aux, "r6", cooked_transfer);
-}
-
-STATIC_INLINE_DEVICES void
-create_aix_stack_frame(psim *system,
- unsigned_word bottom_of_stack,
- char **argv,
- char **envp)
-{
- unsigned_word core_envp;
- unsigned_word core_argv;
- unsigned_word core_argc;
- unsigned_word core_aux;
- unsigned_word top_of_stack;
-
- /* cheat - create an elf stack frame */
- create_elf_stack_frame(system, bottom_of_stack, argv, envp);
-
- /* extract argument addresses from registers */
- psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer);
- psim_read_register(system, 0, &core_argc, "r3", cooked_transfer);
- psim_read_register(system, 0, &core_argv, "r4", cooked_transfer);
- psim_read_register(system, 0, &core_envp, "r5", cooked_transfer);
- psim_read_register(system, 0, &core_aux, "r6", cooked_transfer);
-
- /* extract arguments from registers */
- error("create_aix_stack_frame() - what happens next?\n");
-}
-
-
-
-static void
-stack_ioctl_callback(const device *me,
- psim *system,
- cpu *processor,
- unsigned_word cia,
- ...)
-{
- va_list ap;
- unsigned_word stack_pointer;
- char **argv;
- char **envp;
- va_start(ap, cia);
- stack_pointer = va_arg(ap, unsigned_word);
- argv = va_arg(ap, char **);
- envp = va_arg(ap, char **);
- va_end(ap);
- DTRACE(stack,
- ("stack_ioctl_callback(me=0x%lx:%s, system=0x%lx, processor=0x%lx, cia=0x%lx, argv=0x%lx, envp=0x%lx)\n",
- (long)me, me->full_name, (long)system, (long)processor, (long)cia, (long)argv, (long)envp));
- if (strcmp(me->name, "stack@elf") == 0)
- create_elf_stack_frame(system, stack_pointer, argv, envp);
- else if (strcmp(me->name, "stack@xcoff") == 0)
- create_aix_stack_frame(system, stack_pointer, argv, envp);
- DTRACE(stack,
- ("stack_ioctl_callback() = void\n"));
-}
-
-
-static device_callbacks const stack_callbacks = {
- ignore_device_init,
- unimp_device_attach_address,
- unimp_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- unimp_device_dma_read_buffer,
- unimp_device_dma_write_buffer,
- unimp_device_attach_interrupt,
- unimp_device_detach_interrupt,
- unimp_device_interrupt,
- unimp_device_interrupt_ack,
- stack_ioctl_callback,
-};
-
-
-\f
-/* Table of all the devices and a function to lookup/create a device
- from its name */
-
-typedef const device *(device_creator)
- (const char *name,
- const char *full_name,
- const device *parent);
-
-typedef struct _device_descriptor device_descriptor;
-struct _device_descriptor {
- const char *name;
- device_creator *creator;
- const device_callbacks *callbacks;
-};
-
-static device_descriptor devices[] = {
- { "console", console_create, NULL },
- { "memory", NULL, &memory_callbacks },
- { "vm", vea_vm_create, NULL },
- { "halt", NULL, &halt_callbacks },
- { "icu", NULL, &icu_callbacks },
- { "register", NULL, ®ister_callbacks },
- { "iobus", NULL, &iobus_callbacks },
- { "file", NULL, &file_callbacks },
- { "htab", NULL, &htab_callbacks },
- { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
- { "stack", NULL, &stack_callbacks },
- { "sim", NULL, &sim_callbacks },
- { "load-binary", NULL, &binary_callbacks },
- { "map-binary", NULL, &binary_callbacks },
- { NULL },
-};
-
-
-INLINE_DEVICES const device *
-device_create(const char *name,
- const char *full_name,
- const device *parent)
-{
- device_descriptor *device;
- int name_len;
- char *chp;
- chp = strchr(name, '@');
- name_len = (chp == NULL ? strlen(name) : chp - name);
- for (device = devices; device->name != NULL; device++) {
- if (strncmp(name, device->name, name_len) == 0
- && (device->name[name_len] == '\0'
- || device->name[name_len] == '@'))
- if (device->creator != NULL)
- return device->creator(name, full_name, parent);
- else
- return device_create_from(name,
- full_name,
- NULL /* data */,
- device->callbacks,
- parent);
- }
- error("device_create() unknown device %s\n", name);
- return NULL;
-}
-
-
-INLINE_DEVICES const device *
-device_create_from(const char *name,
- const char *full_name,
- void *data,
- const device_callbacks *callback,
- const device *parent)
-{
- device *me = ZALLOC(device);
- me->name = strdup(name);
- me->full_name = strdup(full_name);
- me->data = data;
- me->callback = callback;
- me->parent = parent;
- return me;
-}
-
-
-INLINE_DEVICES const device_callbacks *
-passthrough_device_callbacks(void)
-{
- static const device_callbacks callbacks = {
- ignore_device_init,
- pass_device_attach_address,
- pass_device_detach_address,
- unimp_device_io_read_buffer,
- unimp_device_io_write_buffer,
- pass_device_dma_read_buffer,
- pass_device_dma_write_buffer,
- pass_device_attach_interrupt,
- pass_device_detach_interrupt,
- pass_device_interrupt,
- unimp_device_interrupt_ack,
- unimp_device_ioctl,
- };
- return &callbacks;
-}
-
-
-
-#endif /* _DEVICES_C_ */
+++ /dev/null
-/* 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_ */
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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,
+ ¬e->desc, sizeof(head) + head.namesz,
+ head.descsz))
+ return;
+ note->desc.real_mode = bfd_get_32(image, (void*)¬e->desc.real_mode);
+ note->desc.real_base = bfd_get_32(image, (void*)¬e->desc.real_base);
+ note->desc.real_size = bfd_get_32(image, (void*)¬e->desc.real_size);
+ note->desc.virt_base = bfd_get_32(image, (void*)¬e->desc.virt_base);
+ note->desc.virt_size = bfd_get_32(image, (void*)¬e->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(¬e, 0, sizeof(note));
+ if (image != NULL)
+ bfd_map_over_sections(image, map_over_chirp_note, ¬e);
+ 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
--- /dev/null
+/* 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
#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>
#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>
#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,
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);
}
-STATIC_INLINE_EMUL_NETBSD void
-do_exit(emulation *emul,
+static void
+do_exit(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_read(emulation *emul,
+static void
+do_read(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_write(emulation *emul,
+static void
+do_write(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_open(emulation *emul,
+static void
+do_open(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_close(emulation *emul,
+static void
+do_close(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_break(emulation *emul,
+static void
+do_break(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
/* 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,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_getuid(emulation *emul,
+static void
+do_getuid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_geteuid(emulation *emul,
+static void
+do_geteuid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_kill(emulation *emul,
+static void
+do_kill(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
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,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_getegid(emulation *emul,
+static void
+do_getegid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_getgid(emulation *emul,
+static void
+do_getgid(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_sigprocmask(emulation *emul,
+static void
+do_sigprocmask(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_ioctl(emulation *emul,
+static void
+do_ioctl(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
#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 */
}
-STATIC_INLINE_EMUL_NETBSD void
-do_umask(emulation *emul,
+static void
+do_umask(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_dup2(emulation *emul,
+static void
+do_dup2(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_fcntl(emulation *emul,
+static void
+do_fcntl(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_gettimeofday(emulation *emul,
+static void
+do_gettimeofday(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_getrusage(emulation *emul,
+static void
+do_getrusage(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
#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,
#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,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_fstat(emulation *emul,
+static void
+do_fstat(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
}
-STATIC_INLINE_EMUL_NETBSD void
-do_lstat(emulation *emul,
+static void
+do_lstat(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
#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,
#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,
}
-STATIC_INLINE_EMUL_NETBSD void
-do___sysctl(emulation *emul,
+static void
+do___sysctl(os_emul_data *emul,
unsigned call,
const int arg0,
cpu *processor,
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"
processor,
cia);
name += sizeof(mib);
- switch (mib) {
+ switch ((int)mib) {
case 7/*HW_PAGESIZE*/:
#if WITH_NetBSD_HOST && (HW_PAGESIZE != 7)
# error "HW_PAGESIZE"
}
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;
-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 */
{ 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[]) = {
/* 31 */ "SIGUSR2",
};
-emulation emul_netbsd = {
+static emul_syscall emul_netbsd_syscalls = {
netbsd_descriptors,
sizeof(netbsd_descriptors) / sizeof(netbsd_descriptors[0]),
netbsd_error_names,
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_
#ifndef _INTERRUPTS_C_
#define _INTERRUPTS_C_
-#ifndef STATIC_INLINE_INTERRUPTS
-#define STATIC_INLINE_INTERRUPTS STATIC_INLINE
-#endif
-
#include <signal.h>
#include "cpu.h"
interrupts */
-STATIC_INLINE_INTERRUPTS msreg
+msreg STATIC_INLINE_INTERRUPTS
interrupt_msr(msreg old_msr,
msreg msr_clear,
msreg msr_set)
}
-STATIC_INLINE_INTERRUPTS msreg
+msreg STATIC_INLINE_INTERRUPTS
interrupt_srr1(msreg old_msr,
msreg srr1_clear,
msreg srr1_set)
}
-STATIC_INLINE_INTERRUPTS unsigned_word
+unsigned_word STATIC_INLINE_INTERRUPTS
interrupt_base_ea(msreg msr)
{
if (msr & msr_interrupt_prefix)
/* 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,
}
-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) {
}
-INLINE_INTERRUPTS void
+void INLINE_INTERRUPTS
data_storage_interrupt(cpu *processor,
unsigned_word cia,
unsigned_word ea,
}
-INLINE_INTERRUPTS void
+void INLINE_INTERRUPTS
instruction_storage_interrupt(cpu *processor,
unsigned_word cia,
storage_interrupt_reasons reason)
case OPERATING_ENVIRONMENT:
{
- unsigned_word nia;
msreg srr1_set;
switch(reason) {
case hash_table_miss_storage_interrupt:
-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) {
-INLINE_INTERRUPTS void
+void INLINE_INTERRUPTS
program_interrupt(cpu *processor,
unsigned_word cia,
program_interrupt_reasons reason)
}
-INLINE_INTERRUPTS void
+void INLINE_INTERRUPTS
floating_point_unavailable_interrupt(cpu *processor,
unsigned_word cia)
{
}
-INLINE_INTERRUPTS void
+void INLINE_INTERRUPTS
system_call_interrupt(cpu *processor,
unsigned_word cia)
{
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:
}
}
-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)
{
/* handle an externally generated event */
-INLINE_INTERRUPTS int
+int INLINE_INTERRUPTS
decrementer_interrupt(cpu *processor)
{
if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
}
}
-INLINE_INTERRUPTS int
+int INLINE_INTERRUPTS
external_interrupt(cpu *processor)
{
if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
--- /dev/null
+/* 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_ */
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 *);
-
+++ /dev/null
-/*
- * 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
*/
-#ifndef _CONFIG_H_
-#define _CONFIG_H_
+#ifndef _PSIM_CONFIG_H_
+#define _PSIM_CONFIG_H_
/* endianness of the host/target:
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*/
/* 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
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
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
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
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
routines will be pulled in twice. */
#ifndef OPTIONS_INLINE
-#define OPTIONS_INLINE (DEFAULT_INLINE ? 1 : 0)
+#define OPTIONS_INLINE DEFAULT_INLINE
+#endif
+
+/* 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 /* _CONFIG_H */
+#endif /* _PSIM_CONFIG_H */
#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
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:
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;
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;
/* physical memory for fetching page table entries */
core_map *physical;
+ /* address xor for PPC endian */
+ unsigned xor[WITH_XOR_ENDIAN];
+
} om_map;
/* 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,
return index;
}
-STATIC_INLINE_VM unsigned_word
+unsigned_word STATIC_INLINE_VM
om_page_tlb_index(unsigned_word ea)
{
unsigned_word index = EXTRACTED(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 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
+}
+
+unsigned_word STATIC_INLINE_VM
+om_pte_0_api(unsigned_word pte_0)
+{
+#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)
{
- unsigned_word masked_page = MASKED(ea, 36, 51);
- return masked_page;
+ return EXTRACTED(pte_1, 56, 56);
}
-STATIC_INLINE_VM unsigned_word
-om_masked_byte(unsigned_word ea)
+int STATIC_INLINE_VM
+om_pte_1_masked_rpn(unsigned_word pte_1)
{
- unsigned_word masked_byte = MASKED(ea, 52, 63);
- return masked_byte;
+ return MASKED(pte_1, 0, 51); /*RPN*/
}
+unsigned_word STATIC_INLINE_VM
+om_ea_api(unsigned_word ea)
+{
+ return EXTRACTED(ea, 36, 41);
+}
-INLINE_VM vm *
+/* Page and Segment table read/write operators, these need to still
+ account for the PPC's XOR operation */
+
+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;
}
-STATIC_INLINE_VM om_bat *
+om_bat STATIC_INLINE_VM *
om_effective_to_bat(om_map *map,
unsigned_word ea)
{
}
-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,
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);
? 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;
}
}
-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,
+ 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;
}
}
}
-static void
+void STATIC_INLINE_VM
om_interrupt(cpu *processor,
unsigned_word cia,
unsigned_word ea,
}
-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,
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;
}
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);
}
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;
}
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);
#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);
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);
[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);
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;
}
/* rebuild all the relevant bat information */
-STATIC_INLINE_VM void
+void STATIC_INLINE_VM
om_unpack_bat(om_bat *bat,
spreg ubat,
spreg lbat)
/* rebuild the given bat table */
-STATIC_INLINE_VM void
+void STATIC_INLINE_VM
om_unpack_bats(om_bats *bats,
spreg *raw_bats,
msreg msr)
#if (WITH_TARGET_WORD_BITSIZE == 32)
-STATIC_INLINE_VM void
+void STATIC_INLINE_VM
om_unpack_sr(vm *virtual,
sreg *srs,
int which_sr)
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)
{
/* 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,
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;
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,
}
-INLINE_VM unsigned_word
+unsigned_word INLINE_VM
vm_real_data_addr(vm_data_map *map,
unsigned_word ea,
int is_read,
}
-INLINE_VM unsigned_word
+unsigned_word INLINE_VM
vm_real_instruction_addr(vm_instruction_map *map,
cpu *processor,
unsigned_word cia)
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,
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);
}
-INLINE_VM int
+int INLINE_VM
vm_data_map_write_buffer(vm_data_map *map,
const void *source,
unsigned_word addr,
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
/* 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