basics.h
bits.c
bits.h
+build-psim
config.in
configure
configure.in
device_tree.h
devices.c
devices.h
+dgen.c
double.c
dp-bit.c
+emul_generic.c
+emul_generic.h
+emul_netbsd.c
+emul_netbsd.h
events.c
events.h
-gen.c
idecode_branch.h
idecode_expression.h
idecode_fields.h
+igen.c
inline.c
inline.h
interrupts.c
interrupts.h
+lf.c
+lf.h
main.c
+misc.c
+misc.h
+mon.c
+mon.h
+os_emul.c
+os_emul.h
+ppc-cache-rules
ppc-endian.c
ppc-endian.h
ppc-instructions
+ppc-opcode-complex
+ppc-opcode-simple
ppc-spr-table
ppc.mt
psim.c
registers.h
sim_callbacks.h
sim_calls.c
+spa-reporter.c
+spa-system-calls.c
+spa-system-calls.h
std-config.h
-system.c
-system.h
+table.c
+table.h
vm.c
vm.h
vm_n.h
+Fri Oct 27 19:26:27 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * bits.h (ROTL32, ROTL64): Were functions, made them macros, now
+ make them functions again. Appears 2.6.3 is confused by just a
+ macro.
+
+Thu Oct 26 18:31:58 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * ppc-endian.c (SWAP_8): Fix 8 byte swap!
+
+ * psim.c (psim_create): Not correctly checking that runtime
+ configuration of things like ENDIAN, ENVIRONMENT and ALIGNMENT
+ matched the compiled in ones.
+
+ * debug.h (ITRACE), igen.c: Tidy up more tracing flags -
+ trace_semantics is now different to trace_idecode, the former
+ checks the cache.
+
+Tue Oct 24 21:54:13 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * ppc-instructions (mtsrin): Missing instruction
+ * ppc-instructions (mfsrin): Missing instruction
+ * ppc-instructions (eieio): Missing instruction
+
+Tue Oct 24 20:55:29 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * build-psim: New shell script - see internals for usage,
+ simplifies the process of building custom simulators.
+
+Mon Oct 23 23:48:59 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * std-config.h (SEMANTICS_INLINE): Tidy up notes on each of the
+ INLINE macros. Make SEMANTICS_INLINE == 1 if DEFAULT_INLINE == 2.
+ Don't use DEFAULT_INLINE to define REGISTERS_INLINE DEVICES_INLINE
+ 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.
+
+Mon Oct 23 00:31:50 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * os_emul.[hc], emul_generic.[hc], emul_netbsd.[hc]: replace
+ system.[hc]. Start of suport for multiple emulations and
+ emulation state (os_emul object).
+
+ * emul_generic.[hc]: Start of code to implement proper system call
+ tracing (from spy).
+
+Sun Oct 22 21:33:51 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * cpu.h, cpu.c (cpu_init): New function, zero the registers before
+ the processor is started. Fixes problem of registers being
+ undefined when restarting from within gdb.
+
+ * cpu.h, cpu.c (cpu_flush_icache): New function, flushes the
+ instruction cache (if present). Fixes problem of cpu caching gdb
+ breakpoint instructions.
+
+ FIXME: PSIM sometimes aborts calling error(), it should instead
+ call sim_error() say which takes care of housekeeping such as
+ saving the CIA before calling error.
+
+ * NOTE: cpu_flush_cache() instead of cpu_synchronize_context() is
+ used when restarting a simulation because the latter has the
+ unwanted side effect (well I as a kernel hacker think it is) of
+ performing an isync when the instruction stream doesn't contain
+ one.
+
+Sun Oct 22 19:27:48 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * mon.h (new), mon.c (new), std-config.h (WITH_MON): Performance
+ monitoring module. Counts both instructions issued and
+ load/stores.
+
+ * 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
+ a common monitor to each of the cpus. Delete
+ cpu_increment_number_of_insns() and cpu_get_number_of_insns()
+ replaced by copied code in mon.[hc].
+
+Sun Oct 22 18:42:45 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * sim_calls.c, main.c, psim.c (psim_create): always create
+ `WITH_SMP' cpus. The actual number of CPU's active in a
+ simulation run is taken from the device node: /init/smp (an
+ integer). WITH_SMP changed to 2 (remember to put it back to 0).
+
+Fri Oct 20 17:26:54 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * system.c: More system call emulation. If code appears NetBSD
+ specific, make conditional to being compiled on a NetBSD system
+ (sigh).
+
+Wed Oct 18 23:02:20 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * Makefile.in, gen.c(delete), igen.c(new), dgen.c(new),
+ lf.[ch](new), table.[ch](new): Split into two generators - igen
+ that outputs the instruction tables and dgen that outputs the spr
+ tables. Add -f (filter out) flag to igen to filter out certain
+ instructions (ex 64 bit ones) from the created tables. Include
+ $(LIBIBERTY_LIB) in link options in case host lacks some libc
+ functions.
+
+ * NOTE: igen, since it was originally written for the
+ PowerPC/RS6000, things the MSB is 0 and the LSB is 63{31}.
+
+ * Makefile.in, std-config.h, ppc-cache-rules(new),
+ ppc-opcode-complex(new), ppc-opcode-simple(new): (for igen) Create
+ 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.
+
+ * igen.c(lf_print_c_semantic): Move call to increment instruction
+ counter so that it occures _after_ the instruction has been fully
+ validated, was double counting illegal/invalid instructions. Add
+ conditional so only compiled in when WITH_PROFILE enabled (enabled
+ by default).
+
+ * igen.c, cpu.h, cpu.c(cpu_increment_number_of_insns): Include
+ itable.h, count individual instruction types not just total,
+ adjust reporting functions to output this.
+
+ * ppc-instructions (64 bit Load Doubleword with Update Indexed):
+ Had 32./ instead of 31./
+
+ * ppc-instructions (64 bit Store Double Word Conditional Indexed):
+ bitrot - updated to use newer CR register operators.
+
+ * ppc-instructions (64bit Floating Convert from Integer
+ Doubleword): Correct call to Round_Float().
+
+Mon Oct 16 00:31:20 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * basics.h: #include "sim_callbacks.h" earlier so that its
+ prototypes are declared in all other header files.
+
+ * bits.h, bits.c, idecode_expression.h (ROTL32, ROTL64): Update
+ 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.
+
+Sun Oct 15 22:16:11 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * devices.h, devices.c, debug.h, debug.c: add macro's for tracing
+ of each device. Make parameter names consistent so macros work.
+ Use macro's in device functions.
+
+ * device_tree.c, devices.h, devices.c: include path to device in a
+ devices node when creating it.
+
+ * device_tree.c, debug.h, debug.c: Add tracing of `device-tree'.
+
+ * core.c: add tracing of core-device, adjust parameter names in
+ core functions to be consistent with those in devices*.
+
+Sun Oct 15 20:33:20 1995 Andrew Cagney <cagney@cagney@highland.com.au>
+
+ * debug.h, debug.c (trace_option): New function. Parses the trace
+ option, updating the trace array.
+
+ * debug.h, debug.c (trace_usage): New function. Outputs the list
+ of all possible trace options.
+
+ * sim_calls.c (sim_open), main.c (main): Use new trace_option() to
+ parse trace options specified with the simpler -t flag. Adjust
+ usage.
+
+ * FIXME: basic parsing of command line options is still duplicated
+ by main.c and sim_calls.c
+
Thu Oct 26 10:42:28 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* Makefile.in (clean): Delete *.i and *.out files.
({CORE,VM,CPU,EVENTS,REGISTERS,INTERRUPTS}_INLINE): Ditto.
({SPREG,IDECODE}_INLINE): Ditto.
-Wed Oct 11 17:13:15 1995 Andrew Cagney <cagney@kremvax>
+Wed Oct 11 17:13:15 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* ppc-instructions: Initial cut of floating point suport added.
Of note include - use of host IEEE floating point instructions,
* Makefile.in et.al (sorry): tweek to use new core, core_map and
core.h.
-Wed Oct 11 12:10:26 1995 Andrew Cagney <cagney@kremvax>
+Wed Oct 11 12:10:26 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* sim_calls.c, main.c: Add -g (trace_gdb) option, add tracing to
most of the other functions in sim_calls.c.
* vm.c, vm_n.h, Makefile.in: ditto
-Tue Oct 10 15:42:59 1995 Andrew Cagney <cagney@kremvax>
+Tue Oct 10 15:42:59 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* devices.h, devices.c, memory_map.h, memory_map.c: Changed
callback interface so that there is a read/write buffer but no
eliminate transfer_mode (raw or cooked) parameter from read/write
buffer.
-Fri Oct 6 20:23:56 1995 Andrew Cagney <cagney@kremvax>
+Fri Oct 6 20:23:56 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* ppc-instructions (fmul, fmuls): correct instruction format - had
FRB instead of FRC.
-Wed Oct 4 17:31:12 1995 Andrew Cagney <cagney@kremvax>
+Wed Oct 4 17:31:12 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* psim.c, device_tree.h, device_tree.c, devices.c (printd_*,
scand_*): new functions to parse/print fields in device names
variable number of arguments. This gives greater flexability and
greater chance of bugs.
-Tue Oct 3 22:01:56 1995 Andrew Cagney - aka Noid <cagney@kremvax>
+Tue Oct 3 22:01:56 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* main.c (printf_filtered, error): Missing va_end() to close off
variable argument use.
* basics.h (sysdep.h): Don't include it.
* Makefile.in (BASICS_H): Remove sysdep.h.
-Wed Sep 6 13:25:42 1995 Andrew Cagney - aka Noid <cagney@kremvax>
+Wed Sep 6 13:25:42 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* core.c (core_add_data): First growth of bss was being put at
wrong address (0) instead of &end.
* core.c (core_add_stack, core_add_data): Was not handling case
where bss/stack is grown across the current end-of-{bss,stack}.
-Wed Sep 6 00:46:10 1995 Andrew Cagney - aka Noid <cagney@kremvax>
+Wed Sep 6 00:46:10 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* system.c (system_call): Fix SYS_break - was aligning bss to a
page boundary instead of just an 8 byte one; On first call sbrk(0)
* configure.in: Clone from other simulator targets.
* configure: Generate via autoconf from configure.in.
-Sat Aug 19 09:05:32 1995 Andrew Cagney - aka Noid <cagney@kremvax>
+Sat Aug 19 09:05:32 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* ppc-instructions: fix srawi (was geting XER[CA] real wrong).
* main.c (main): really stupid. Wasn't exiting with correct status
-Fri Aug 18 00:38:01 1995 Andrew Cagney - aka Noid <cagney@kremvax>
+Fri Aug 18 00:38:01 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* system.c (system_call): add system calls kill(2) and getpid(2).
* main.c (main): Check/return exit status when simulation
finishes.
-Thu Aug 17 14:29:18 1995 Andrew Cagney <cagney@kremvax>
+Thu Aug 17 14:29:18 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* device_tree.c (create_option_device_node): Alignment rules (at
least for the moment) now are for strict alignment only for LE OEA
* system.c (system_call) SYS_exit: Wasn't exiting with correct status.
-Thu Aug 17 01:16:38 1995 Andrew Cagney - aka Noid <cagney@kremvax>
+Thu Aug 17 01:16:38 1995 Andrew Cagney <cagney@cagney@highland.com.au>
* vm.c (DEFINE_VM_DATA_MAP_WRITE_N): For miss aligned transfer
forgot to return.
CONFIG_FILE = std-config.h
# See inline.h for appropriate flags to set
-INLINE_CFLAGS = -DDEFAULT_INLINE=2
+INLINE_CFLAGS = # -g0 -DDEFAULT_INLINE=2
+IGEN_FLAGS = -f 64 # -f 64 -e
+IGEN_OPCODE_RULES = ppc-opcode-simple # ppc-opcode-complex
+DGEN_FLAGS = # # -s
+
LIBIBERTY_LIB = ../../libiberty/libiberty.a
BFD_LIB = ../../bfd/libbfd.a
events.h \
interrupts.h \
psim.h \
- icache.h
+ icache.h \
+ itable.h \
+ mon.h
+
+EMUL_GENERIC_H = \
+ $(CPU_H) \
+ $(IDECODE_H) \
+ emul_generic.h \
+ os_emul.h
INLINE = \
icache.h \
idecode.h idecode.c \
semantics.h semantics.c \
+ itable.h itable.c \
spreg.h spreg.c \
config.h \
- ppc-config.h
+ ppc-config.h
LIB_SRC = \
psim.c \
bits.c \
- ppc-endian.c \
debug.c \
+ ppc-endian.c \
vm.c \
core.c \
events.c \
- system.c \
+ os_emul.c \
+ emul_generic.c \
+ emul_netbsd.c \
registers.c \
cpu.c \
interrupts.c \
devices.c \
- device_tree.c
+ device_tree.c \
+ mon.c
MAIN_SRC = \
main.c \
sim_calls.c
+# NOTE: semantics, idecode and psim put last so smaller files are compiled
+# first
LIB_OBJ = \
debug.o \
bits.o \
ppc-endian.o \
- system.o \
+ os_emul.o \
+ emul_generic.o \
+ emul_netbsd.o \
registers.o \
vm.o \
core.o \
events.o \
devices.o \
device_tree.o \
+ itable.o \
+ mon.o \
semantics.o \
idecode.o \
psim.o
rm -f run
ln psim run
-$(TARGETLIB): tmp-gencode $(LIB_OBJ) $(GDB_OBJ)
+$(TARGETLIB): tmp-igen tmp-dgen $(LIB_OBJ) $(GDB_OBJ)
rm -f $(TARGETLIB)
$(AR) $(AR_FLAGS) $(TARGETLIB) $(LIB_OBJ) $(GDB_OBJ)
$(RANLIB) $(TARGETLIB)
# anything changes.
psim.o: psim.c psim.h $(CPU_H) $(IDECODE_H) $(INLINE) $(LIB_SRC)
-bits.o: bits.c bits.h
+bits.o: bits.c $(BASICS_H)
debug.o: debug.c $(BASICS_H)
ppc-endian.o: ppc-endian.c ppc-endian.h \
config.h ppc-config.h words.h sim_callbacks.h
-system.o: system.c system.h $(CPU_H) $(IDECODE_H)
+os_emul.o: os_emul.c $(EMUL_GENERIC_H)
+emul_generic.o: emul_generic.c $(EMUL_GENERIC_H)
+emul_netbsd.o: emul_netbsd.c emul_netbsd.h $(EMUL_GENERIC_H)
registers.o: registers.c $(REGISTERS_H) $(BASICS_H)
cpu.o: cpu.c $(CPU_H) $(IDECODE_H)
-interrupts.o: interrupts.c $(CPU_H) $(IDECODE_H) system.h
+interrupts.o: interrupts.c $(CPU_H) $(IDECODE_H) os_emul.h
idecode.o: idecode.c $(CPU_H) $(IDECODE_H) semantics.h
# double.o: double.c dp-bit.c
vm.o: vm.c vm.h vm_n.h $(BASICS_H) $(REGISTERS_H) \
- device_tree.h core.h interrupts.h
+ device_tree.h core.h interrupts.h itable.h mon.h
core.o: core.c core.h $(BASICS_H) device_tree.h
semantics.o: semantics.c semantics.h $(CPU_H) $(IDECODE_H)
+itable.o: itable.c itable.h
+
+mon.o: $(CPU_H)
#
# Rules to create the built c source code files
cp $(srcdir)/$(CONFIG_FILE) ppc-config.h
-tmp-gencode: gen ppc-instructions ppc-spr-table $(srcdir)/../../move-if-change
- ./gen -r $(srcdir)/ppc-spr-table \
- -i $(srcdir)/ppc-instructions \
+tmp-dgen: dgen ppc-spr-table $(srcdir)/../../move-if-change
+ ./dgen $(DGEN_FLAGS) \
+ -r $(srcdir)/ppc-spr-table \
-n spreg.h -P tmp-spreg.h \
- -n spreg.c -p tmp-spreg.c \
+ -n spreg.c -p tmp-spreg.c
+ $(srcdir)/../../move-if-change tmp-spreg.h spreg.h
+ $(srcdir)/../../move-if-change tmp-spreg.c spreg.c
+ touch tmp-dgen
+
+
+tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/../../move-if-change
+ ./igen $(IGEN_FLAGS) \
+ -o $(srcdir)/$(IGEN_OPCODE_RULES) \
+ -k $(srcdir)/ppc-cache-rules \
+ -i $(srcdir)/ppc-instructions \
-n icache.h -C tmp-icache.h \
-n semantics.h -S tmp-semantics.h \
-n semantics.c -s tmp-semantics.c \
-n idecode.h -D tmp-idecode.h \
- -n idecode.c -d tmp-idecode.c
+ -n idecode.c -d tmp-idecode.c \
+ -n itable.h -T tmp-itable.h \
+ -n itable.c -t tmp-itable.c
$(srcdir)/../../move-if-change tmp-icache.h icache.h
$(srcdir)/../../move-if-change tmp-idecode.h idecode.h
$(srcdir)/../../move-if-change tmp-idecode.c idecode.c
$(srcdir)/../../move-if-change tmp-semantics.h semantics.h
$(srcdir)/../../move-if-change tmp-semantics.c semantics.c
- $(srcdir)/../../move-if-change tmp-spreg.h spreg.h
- $(srcdir)/../../move-if-change tmp-spreg.c spreg.c
- touch tmp-gencode
+ $(srcdir)/../../move-if-change tmp-itable.h itable.h
+ $(srcdir)/../../move-if-change tmp-itable.c itable.c
+ touch tmp-igen
# NOTE: Some versions of make don't handle files created as side-effects
# uncomment the below if that is the case.
#
-# $(TARGETLIB): tmp-gencode
-# icache.h idecode.h idecode.c semantics.h semantics.c spreg.h spreg.c: tmp-gencode
+# $(TARGETLIB): tmp-igen tmp-dgen
+# itable.h itable.c icache.h idecode.h idecode.c semantics.h semantics.c: tmp-igen
+# spreg.h spreg.c: tmp-dgen
-gen.o: gen.c config.h ppc-config.h
- $(CC_FOR_BUILD) -c $(CFLAGS) $(INLINE_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) $(srcdir)/gen.c
+dgen: dgen.o table.o lf.o misc.o
+ $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o dgen dgen.o table.o lf.o misc.o $(LIBIBERTY_LIB) $(LIBS)
-gen: gen.o config.h ppc-config.h $(LIBIBERTY_LIB) $(LIBS)
- $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o gen gen.o $(LIBIBERTY_LIB) $(LIBS)
+igen: igen.o table.o lf.o misc.o
+ $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o igen igen.o table.o lf.o misc.o $(LIBIBERTY_LIB) $(LIBS)
-#
+table.o: misc.h lf.h table.h
+lf.o: misc.h lf.h
+dgen.o igen.o: misc.h lf.h table.h
+misc.o: misc.h
+# With out this #, make thinks that misc.o doesn't have a rule
tags etags: TAGS
-TAGS: tmp-gencode config.h ppc-config.h
+TAGS: tmp-igen tmp-dgen config.h ppc-config.h
etags $(srcdir)/*.h $(srcdir)/*.c $(BUILT_SRC)
clean mostlyclean:
- rm -f tmp-* *.[ioas] *.out core psim run gen config.log
- rm -f icache.h idecode.h idecode.c semantics.h semantics.c spreg.h spreg.c ppc-config.h
+ rm -f tmp-* *.[oas] core psim run igen dgen config.log
distclean maintainer-clean realclean: clean
rm -f TAGS $(BUILT_SRC) Makefile config.cache config.status config.h stamp-h
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
-This directory contains the program PSIM that models the PowerPC
-architecture. It can either be run stand alone (psim or run) or used
-as part of GDB.
+This directory contains the program PSIM that models the PowerPC(tm -
+IBM) architecture. It can either be run stand alone (psim or run) or
+used as part of GDB.
-SOURCE:
+KNOWN FEATURES
- PSIM is now part of the Cygnus GDB source tree (hopefully it
- will in turn become part of the next FSF release of GDB).
- If you're looking for a more `cutting' edge version of this
- program then it can be found in:
+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.
- ftp.ci.com.au:pub/clayton/psim-sim-*.tar.gz
+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.
- This contains a replacement for the directory sim/ppc. As
- these releases prove stable they are merged back into the GDB
- source tree.
+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.
- If you find bugs or experience problems, please e-mail them to
- the alias:
+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.
- powerpc-psim@ci.com.au
+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.
- It's a majordomo mailing list.
+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.
-BUILDING:
+PERFORMANCE: In its default configuration PSIM is constructed 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.
- o At present PSIM can only be built using the compiler GCC
- (yes that is bug). This is because, among other things the
- code exploits GCC's suport of long ongs.
+FLOATING POINT: Preliminary suport for floating point is included.
+Real kernels don't need floating point.
- o I also suggest that you install: flex, bision, gnu-make and
- byacc. Doing this just makes builds easier.
- o Configure almost as per normal, specifing the special target
- eabisim vis:
+BUILDING PSIM:
- $ CC=gcc ./configure --target=powerpcle-unknown-eabisim
+To build PSIM you will need the following:
- by default (because of its dependency on GCC).
+ gdb-4.15.tar.gz From your favorite GNU ftp site
- o Build your entire gdb tree as per normal. Something along the
- lines of:
+ ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+psim-951016.diff.gz
+
+ This contains a few minor patches to
+ gdb-4.15 so that will include psim
+ when it is built.
+
+ ftp://ftp.ci.com.au/pub/clayton/gdb-4.15+psim-951016.tar.gz
+
+ This contains the psim files propper.
+
+ ftp://ftp.ci.com.au/pub/clayton/psim-test-951016.tar.gz
+
+ (Optional) A scattering of pre-compiled
+ programs that run under the simulator.
+
+ gcc Again available from your favorite
+ GNU ftp site.
+
+ patch Sun's patch behaves a little wierd
+ and doesn't appear to like creating
+ 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.
+
+
+0. A starting point
+
+ $ ls -1
+ gdb-4.15+psim-951016.diff.gz
+ gdb-4.15+psim-951016.tar.gz
+ gdb-4.15.tar.gz
+ psim-test-951016.tar.gz
- $ cd gdb-4.15
- $ make CC=gcc
- .
- .
- .
+1. Unpack gdb
+ $ gunzip < gdb-4.15.tar.gz | tar xf -
- o Install it it all as per normal. Something along the lines of:
+
+2. Change to the gdb directory, apply the psim patches and unpack
+ the psim files.
$ cd gdb-4.15
- $ make CC=gcc install
+ $ gunzip < ../gdb-4.15+psim-951016.diff.gz | more
+ $ gunzip < ../gdb-4.15+psim-951016.diff.gz | patch -p1
-RUNNING:
+ $ gunzip < ../gdb-4.15+psim-951016.tar.gz | tar tvf -
+ $ gunzip < ../gdb-4.15+psim-951016.tar.gz | tar xvf -
- PSIM can either be run as a stand alone program or as part
- of gdb. The psim-test archive (found in:
- ftp.ci.com.au:pub/clayton
+3. Configure gdb
- contains pre-compiled and linked programs that can be run on
- PSIM. The notes below assume that you have unpacked that tar
- archive.
+ $ more gdb/README
- To rebuild the archive you will need to obtain a working
- version of an ELF compiler/linker for the PowerPC.
-
- Example of running PSIM:
+ then something like (I assume SH):
- Print out the users environment:
+ $ CC=gcc ./configure --target=powerpc-unknown-eabisim
- $ sim/ppc/psim sim/ppc/test/envp
+ eabisim is needed as by default (because PSIM needs GCC) the
+ simulator is not built.
- Print out the arguments:
- $ sim/ppc/psim sim/ppc/test/argv a b c
+4. Build
- Check the OEA model:
+ $ make CC=gcc
- $ sim/ppc/psim sim/ppc/test/interrupt
+ alternativly, if you are short on disk space or just want the
+ simulator built:
- Check that sbrk works
+ $ ( cd libiberty && make CC=gcc )
+ $ ( cd bfd && make CC=gcc )
+ $ ( cd sim/ppc && make CC=gcc )
- $ sim/ppc/psim sim/ppc/test/break
- Try for speed. The program count contains a loop
- of two instructions which is looped <arg> times.
- See later for how to make PSIM run 10-100 times
- faster.
+5. Install
- $ time sim/ppc/sim sim/ppc/test/count 5000000
- $ expr 10 \* 1000 \* 1000 / <seconds>
+ $ make CC=gcc install
+ or just
+ $ cp gdb/gdb ~/bin/powerpc-unknown-eabisim-gdb
+ $ cp sim/ppc/run ~/bin/powerpc-unknown-eabisim-run
- Example of running GDB:
+USING THE SIMULATOR:
- The most important thing to be aware of is the fact
- that before the simulator is used, the user must attach
- to it (target sim) and than load the executable (load count).
+(I assume that you've unpacked the psim-test archive).
- $ cd sim/ppc/test
- $ powerpc-unknown-eabi-gdb count
- (gdb) target sim
- (gdb) load count
- (gdb) break main
- (gdb) run
- .
- .
- .
+1. As a standalone program
+ Print out the users environment:
-CONFIGURATION:
+ $ powerpc-unknown-eabisim-run envp
- Making it go faster
+ Print out the arguments:
- See the file sim/ppc/config.h (which is copied from
- sim/ppc/std-config.h) for further information.
+ $ powerpc-unknown-eabisim-run argv a b c
+ Check that sbrk works:
-KNOWN FEATURES
+ $ powerpc-unknown-eabisim-run break
- SMP: A Symetric Multi-Processor configuration is suported.
- This includes a model of the PowerPC load word and reserve
- et.al. 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).
-
- DUAL-ENDIAN: Both little and big endian modes are suported.
- Switching between the two modes at run time, however, is not.
-
- 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 of them.
- That is the User Instruction Set Architecture, the Virtual
- Environment Architecture and finally the Operating Environment
- Architecture.
-
- HARDWARE DEVICES: The OEA model includes facilities that allow
- a programmer to (I won't say easily) extend this simulator so
- that a program can interact with models of real devices.
- Illustrating this is the phony machine clayton that includes
- console, interrupt control unit and reset register devices.
-
- PEDANTIC VEA MEMORY MODEL: 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 bugs in
- peoples code so I've renamed it `a feature' :-)
-
- RUNTIME CONFIG OF HARDWARE: In addition to the three builtin
- models of hardware - VEA, OEA/Hardware and (the start of) OpenBoot,
- it is possible to load a file containing a specification of a
- custom device tree.
+2. Example of running GDB:
-KNOWN PROBLEMS:
+ The main thing to note is that before you can run the simulator
+ you must enable it. The example below illustrates this:
+
+ $ powerpc-unknown-eabisim-gdb envp
+ (gdb) target sim
+ (gdb) load
+ (gdb) break main
+ (gdb) run
+ .
+ .
+ .
+
+
+BUGS AND PROBLEMS:
- FLOATING POINT: Need to add suport for non IEEE float
- machines. Need to more fully handle exceptions (eg things
- like divide by zero).
+There is a mailing list (subscribe through majordomo@ci.com.au) (that
+is almost never used) at:
- DEVICE TREE DOC: How to create and use the device tree is not
- documented at all.
+ powerpc-psim@ci.com.au
- INITIALIZATION: When running from gdb, things are not
- re-initialzied very well e.g. registers are not rezeroed.
+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.
- 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.
+KNOWN PROBLEMS:
+
+See the ChangeLog file looking for lines taged with the word FIXME.
- Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups.
- The PowerOpen worked until I added the ELF one.
+CORE.C: The implementation of core.c (defined by core.h) isn't the
+best. It is intended to be functionaly correct rather than fast.
- 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.
+HTAB (page) code for OEA model untested. Some of the vm code
+instructions unimplemented.
- Missing VEA system calls.
+Flush instruction cache instructions do nothing. Perhaphs they should
+(if there is an instruction cache) flush it.
- Missing or commented out instructions.
+Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups. The
+PowerOpen worked until I added the ELF one.
- Only basic (hackish) floating point implemented, I would not
- trust it and it is going to change.
+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.
- 64bit target untested.
+Missing VEA system calls.
- 64bit host broken. For instance use of scanf "%x", &long long.
+Missing or commented out instructions.
- Event code for pending events from within signal handlers not
- finished/tested.
+64bit target untested.
- Better and more devices.
+64bit host broken. For instance use of scanf "%x", &long long.
- PORTABILITY (Notes taken from Michael Meissner): Heavy use of
- the ## operator - fix using the clasic X/**/Y hack; Use of the
- signed keyword. In particular, signed char has no analogue in
- classic C (though most implementations of classic C use signed
- chars); Use of long long which restricts the target compiler
- to be GCC.
+Event code for pending events from within signal handlers not
+finished/tested.
+
+Better and more devices.
+
+PORTABILITY (Notes taken from Michael Meissner): Heavy use of the ##
+operator - fix using the clasic X/**/Y hack; Use of the signed
+keyword. In particular, signed char has no analogue in classic C
+(though most implementations of classic C use signed chars); Use of
+long long which restricts the target compiler to be GCC.
- OPTIONS/FLAGS: Need a function that can parse command line
- options so that both psim and sim_{load,open,command} can all
- call it. Options should be extended to allow the setting of
- things like floating point support.
THANKS:
- Thanks go to the following who each helped in some way.
+Thanks go to the following who each helped in some way.
- Allen Briggs, Bett Koch, David Edelsohn,
- Michael Meissner, Bob Mercier, Richard Perini,
- Richard Stallman, Mitchele Walker
+ Allen Briggs, Bett Koch, David Edelsohn, Gordon Irlam,
+ Michael Meissner, Bob Mercier, Richard Perini,
+ Richard Stallman, Mitchele Walker
----------------------------------------------------------------
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
-
-----
-
-CFLAGS = -g -Wall -Wno-unused -Wmissing-prototypes -Werror
--- /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 _BITS_C_
+#define _BITS_C_
+
+#include "basics.h"
+
+#endif /* _BITS_C_ */
--- /dev/null
+#!/bin/sh
+
+case "`uname -s`-`uname -r`" in
+ NetBSD* )
+ cflags="-Wall -Wno-unused -Wmissing-prototypes -Werror"
+ ;;
+ SunOS-5* )
+ cflags="-gstabs+"
+ ;;
+ SunOS-4* )
+ cflags="-Werror"
+ ;;
+esac
+
+for target in "$@"
+do
+
+ echo ""
+ echo "$target"
+ echo ""
+
+ if [ $# -gt 1 ]
+ then
+ make clean
+ fi
+
+ case $target in
+ *unsafe* )
+ with_trace="-DWITH_TRACE=0"
+ with_assert="-DWITH_ASSERT=0"
+ unsafe_flags="-g0 -fomit-frame-pointer -fno-strength-reduce"
+ ;;
+ *safe* )
+ with_trace=
+ with_assert=
+ unsafe_flags="-g0"
+ ;;
+ * )
+ with_trace=
+ with_assert=
+ unsafe_flags=
+ ;;
+ esac
+
+ case $target in
+ *little* )
+ with_target_byte_order="-DWITH_TARGET_BYTE_ORDER=LITTLE_ENDIAN"
+ ;;
+ *big* )
+ with_target_byte_order="-DWITH_TARGET_BYTE_ORDER=BIG_ENDIAN"
+ ;;
+ * )
+ with_target_byte_order=
+ ;;
+ esac
+
+ case $target in
+ *vea* )
+ with_environment="-DWITH_ENVIRONMENT=VIRTUAL_ENVIRONMENT"
+ with_smp="-DWITH_SMP=0"
+ ;;
+ *oea* )
+ with_environment="-DWITH_ENVIRONMENT=OPERATING_ENVIRONMENT"
+ with_smp="-DWITH_SMP=2"
+ ;;
+ * )
+ with_environment=
+ with_smp=
+ ;;
+ esac
+
+ case $target in
+ *complex* )
+ igen_opcode_rules="IGEN_OPCODE_RULES=ppc-opcode-complex"
+ igen_flags="-e -r 1024"
+ opt_flags="-O2"
+ ;;
+ *simple* )
+ igen_opcode_rules="IGEN_OPCODE_RULES=ppc-opcode-simple"
+ igen_flags="-e"
+ opt_flags="-O2"
+ ;;
+ * )
+ igen_opcode_rules=
+ igen_flags=
+ opt_flags=
+ ;;
+ esac
+
+ case $target in
+ *64* )
+ with_target_word_bitsize="-DWITH_TARGET_WORD_BITSIZE=64"
+ igen_flags="$igen_flags -f 32"
+ ;;
+ *32* )
+ with_target_word_bitsize="-DWITH_TARGET_WORD_BITSIZE=32"
+ igen_flags="$igen_flags -f 64"
+ ;;
+ * )
+ with_target_word_bitsize=
+ igen_flags="$igen_flags -f 64"
+ ;;
+ esac
+
+ case $target in
+ *inline* )
+ default_inline="-DDEFAULT_INLINE=2"
+ ;;
+ * )
+ default_inline=
+ ;;
+ esac
+
+ case $target in
+ *nomon* )
+ with_mon="-DWITH_MON=0"
+ ;;
+ * )
+ with_mon=
+ ;;
+ esac
+
+ case $target in
+ *bswap* )
+ with_bswap="-DWITH_BSWAP=1"
+ ;;
+ * )
+ with_bswap=
+ ;;
+ esac
+
+ if ( set -x ; make \
+ $igen_opcode_rules \
+ IGEN_FLAGS="$igen_flags" \
+ INLINE_CFLAGS=" \
+ $cflags \
+ $unsafe_flags \
+ $opt_flags \
+ $with_bswap \
+ $with_target_byte_order \
+ $with_environment \
+ $with_smp \
+ $default_inline \
+ $with_target_word_bitsize \
+ $with_trace \
+ $with_assert \
+ $with_mon \
+ " )
+ then
+ rm -f psim-${target}-failed
+ ( set -x ; cp psim psim-$target )
+ else
+ ( set -x ; touch psim-${target}-failed )
+ fi
+done
device_io_read_buffer_callback *reader;
device_io_write_buffer_callback *writer;
/* common */
- int address_space;
+ int space;
unsigned_word base;
unsigned_word bound;
unsigned nr_bytes;
STATIC_INLINE_CORE core_mapping *
new_core_mapping(attach_type attach,
- int address_space,
- unsigned_word addr,
- unsigned nr_bytes,
- const device *device,
- void *buffer,
- int free_buffer)
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ const device *device,
+ void *buffer,
+ int free_buffer)
{
core_mapping *new_mapping = ZALLOC(core_mapping);
switch (attach) {
attach);
}
/* common */
- new_mapping->address_space = address_space;
+ new_mapping->space = space;
new_mapping->base = addr;
new_mapping->nr_bytes = nr_bytes;
new_mapping->bound = addr + (nr_bytes - 1);
STATIC_INLINE_CORE void
core_map_attach(core_map *access_map,
- attach_type attach,
- int address_space,
- unsigned_word addr,
- unsigned nr_bytes, /* host limited */
- const device *device, /*callback/default*/
- void *buffer, /*raw_memory*/
- int free_buffer) /*raw_memory*/
+ attach_type attach,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes, /* host limited */
+ const device *device, /*callback/default*/
+ void *buffer, /*raw_memory*/
+ int free_buffer) /*raw_memory*/
{
if (attach == attach_default) {
if (access_map->default_map != NULL)
error("core_map_attach() default mapping already in place\n");
ASSERT(buffer == NULL);
access_map->default_map = new_core_mapping(attach,
- address_space, addr, nr_bytes,
- device, buffer, free_buffer);
+ space, addr, nr_bytes,
+ device, buffer, free_buffer);
}
else {
/* find the insertion point for this additional mapping and insert */
/* create/insert the new mapping */
*last_mapping = new_core_mapping(attach,
- address_space, addr, nr_bytes,
- device, buffer, free_buffer);
+ space, addr, nr_bytes,
+ device, buffer, free_buffer);
(*last_mapping)->next = next_mapping;
}
}
INLINE_CORE void
core_attach(core *memory,
attach_type attach,
- int address_space,
+ int space,
access_type access,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
if (access & access_read)
core_map_attach(memory->map + access_map,
attach,
- address_space, addr, nr_bytes,
+ space, addr, nr_bytes,
device, buffer, !free_buffer);
free_buffer ++;
break;
if (access & access_write)
core_map_attach(memory->map + access_map,
attach,
- address_space, addr, nr_bytes,
+ space, addr, nr_bytes,
device, buffer, !free_buffer);
free_buffer ++;
break;
if (access & access_exec)
core_map_attach(memory->map + access_map,
attach,
- address_space, addr, nr_bytes,
+ space, addr, nr_bytes,
device, buffer, !free_buffer);
free_buffer ++;
break;
if (mapping->reader != NULL) {
if (mapping->reader(mapping->device,
&byte,
- mapping->address_space,
+ mapping->space,
raddr - mapping->base,
1, /* nr_bytes */
0, /*processor*/
if (mapping->writer != NULL) {
if (mapping->writer(mapping->device,
&byte,
- mapping->address_space,
+ mapping->space,
raddr - mapping->base,
1, /*nr_bytes*/
0, /*processor*/
psim *system)
{
core *memory = (core*)me->data;
+ DTRACE_INIT(core);
core_init(memory);
}
core_attach_address_callback(const device *me,
const char *name,
attach_type attach,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
{
core *memory = (core*)me->data;
unsigned_word device_address;
- if (address_space != 0)
+ DTRACE_ATTACH_ADDRESS(core);
+ if (space != 0)
error("core_attach_address_callback() invalid address space\n");
core_attach(memory,
attach,
- address_space,
+ space,
access,
addr,
nr_bytes,
STATIC_INLINE_CORE unsigned
core_dma_read_buffer_callback(const device *me,
- void *target,
- int address_space,
- unsigned_word offset,
+ void *dest,
+ int space,
+ unsigned_word addr,
unsigned nr_bytes)
{
core *memory = (core*)me->data;
+ DTRACE_DMA_READ_BUFFER(core);
return core_map_read_buffer(core_readable(memory),
- target,
- offset,
+ dest,
+ addr,
nr_bytes);
}
STATIC_INLINE_CORE unsigned
core_dma_write_buffer_callback(const device *me,
const void *source,
- int address_space,
- unsigned_word offset,
+ int space,
+ unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
core_map *map = (violate_read_only_section
? core_readable(memory)
: core_writeable(memory));
+ DTRACE_DMA_WRITE_BUFFER(core);
return core_map_write_buffer(map,
source,
- offset,
+ addr,
nr_bytes);
}
INLINE_CORE const device *
core_device_create(core *memory)
{
- return device_create_from("core", memory, &core_callbacks, NULL);
+ return device_create_from("core", "/", memory, &core_callbacks, NULL);
}
unsigned_N data;
if (mapping->reader(mapping->device,
&data,
- mapping->address_space,
+ mapping->space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
unsigned_N data = H2T_N(val);
if (mapping->writer(mapping->device,
&data,
- mapping->address_space,
+ mapping->space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
node_string
} node_type;
+static char *node_type_names[] = {
+ "any",
+ "device",
+ "integer",
+ "boolean",
+ "string",
+ NULL,
+};
struct _device_tree {
/* where i am */
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)
{
if (path[name_len] == '\0') {
if (action == device_tree_grow)
error("device_tree_find_node() node %s already present\n",
- path);
+ 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 does not match type %d\n",
- path, type);
+ 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);
}
switch (action) {
case device_tree_grow:
if (path[name_len] != '\0')
- error("device_tree_find_node() not a leaf %s\n", path);
+ 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;
device_tree_add_passthrough(device_tree *root,
const char *path)
{
- device_tree *new_node = device_tree_find_node(root,
- path,
- node_device,
- device_tree_grow);
+ device_tree *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_passthrough(root=0x%x, path=%s)\n", 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%x\n", new_node));
return new_node;
}
const char *path,
const device *dev)
{
- device_tree *new_node = device_tree_find_node(root,
- path,
- node_device,
- device_tree_grow);
+ device_tree *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_device(root=0x%x, path=%s, dev=0x%x)\n",
+ root, path, 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%x\n", new_node));
return new_node;
}
const char *path,
signed_word integer)
{
- device_tree *new_node = device_tree_find_node(root,
- path,
- node_integer,
- device_tree_grow);
+ device_tree *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_integer(root=0x%x, path=%s, integer=%d)\n",
+ root, path, 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%x\n", new_node));
return new_node;
}
const char *path,
const char *string)
{
- device_tree *new_node = device_tree_find_node(root,
- path,
- node_string,
- device_tree_grow);
+ device_tree *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_device(root=0x%x, path=%s, string=%s)\n",
+ root, path, string));
+ new_node = device_tree_find_node(root,
+ path,
+ path, /* full-name */
+ node_string,
+ device_tree_grow);
new_node->string = string;
+ TRACE(trace_device_tree,
+ ("device_tree_add_string() = 0x%x\n", new_node));
return new_node;
}
const char *path,
int boolean)
{
- device_tree *new_node = device_tree_find_node(root,
- path,
- node_boolean,
- device_tree_grow);
+ device_tree *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_boolean(root=0x%x, path=%s, boolean=%d)\n",
+ 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%x\n", new_node));
return new_node;
}
device_tree_add_found_device(device_tree *root,
const char *path)
{
- device_tree *new_node = device_tree_add_device(root, path, NULL);
+ device_tree *new_node;
+ TRACE(trace_device_tree,
+ ("device_tree_add_found_device(root=0x%x, path=%s)\n",
+ 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%x\n", new_node));
return new_node;
}
device_tree_find_device(device_tree *root,
const char *path)
{
- device_tree *node = device_tree_find_node(root,
- path,
- node_device,
- device_tree_abort);
+ device_tree *node;
+ TRACE(trace_device_tree,
+ ("device_tree_find_device(root=0x%x, path=%s)\n", 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%x\n", node->device));
return node->device;
}
device_tree_find_integer(device_tree *root,
const char *path)
{
- device_tree *node = device_tree_find_node(root,
- path,
- node_integer,
- device_tree_abort);
+ device_tree *node;
+ TRACE(trace_device_tree,
+ ("device_tree_find_integer(root=0x%x, path=%s)\n", 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() = %d\n", node->integer));
return node->integer;
}
device_tree_find_string(device_tree *root,
const char *path)
{
- device_tree *node = device_tree_find_node(root,
- path,
- node_string,
- device_tree_abort);
+ device_tree *node;
+ TRACE(trace_device_tree,
+ ("device_tree_find_string(root=0x%x, path=%s)\n", 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%x\n", node->string));
return node->string;
}
device_tree_find_boolean(device_tree *root,
const char *path)
{
- device_tree *node = device_tree_find_node(root,
- path,
- node_boolean,
- device_tree_abort);
+ device_tree *node;
+ TRACE(trace_device_tree,
+ ("device_tree_find_boolean(root=0x%x, path=%s)\n", 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() = %d\n", node->boolean));
return node->boolean;
}
device_tree_init_device(device_tree *root,
void *data)
{
- psim *system = (psim*)data;
- if (root->type == node_device)
+ psim *system;
+ system = (psim*)data;
+ if (root->type == node_device) {
+ TRACE(trace_device_tree,
+ ("device_tree_init() initializing device=0x%x:%s\n",
+ root->device, root->device->full_name));
root->device->callback->init(root->device, system);
+ }
}
device_tree_init(device_tree *root,
psim *system)
{
+ TRACE(trace_device_tree,
+ ("device_tree_init(root=0x%x, system=0x%x)\n", root, system));
device_tree_traverse(root, device_tree_init_device, NULL, system);
+ TRACE(trace_device_tree,
+ ("device_tree_init() = void\n"));
}
/* Parse a device name, various formats */
-#ifndef __NetBSD__
-#define strtouq strtoul
-#endif
-
#define SCAN_INIT(START, END, COUNT, NAME) \
char *START = NULL; \
char *END = strchr(NAME, '@'); \
#define SCAN_U(START, END, COUNT, U) \
do { \
- *U = strtouq(START, &END, 0); \
+ *U = strtoul(START, &END, 0); \
if (START == END) \
return COUNT; \
COUNT++; \
START = END + 1; \
} while (0)
-#define SCAN_C(START, END, COUNT, C) \
+#define SCAN_C(START, END, COUNT, C, SIZE) \
do { \
char *chp = C; \
END = START; \
*chp = *END; \
chp += 1; \
END += 1; \
+ if ((SIZE) <= ((END) - (START))) \
+ return COUNT; /* overflow */ \
} \
*chp = '\0'; \
if (START == END) \
INLINE_DEVICE_TREE int
scand_c(const char *name,
- char *c1)
+ char *c1, int c1size)
{
SCAN_INIT(start, end, count, name);
- SCAN_C(start, end, count, c1);
+ SCAN_C(start, end, count, c1, c1size);
return count;
}
INLINE_DEVICE_TREE int
scand_c_uw_u(const char *name,
- char *c1,
+ char *c1, int c1size,
unsigned_word *uw2,
unsigned *u3)
{
SCAN_INIT(start, end, count, name);
- SCAN_C(start, end, count, c1);
+ SCAN_C(start, end, count, c1, c1size);
SCAN_U(start, end, count, uw2);
SCAN_U(start, end, count, u3);
return count;
void *ignore_data_argument);
-/* Parse a device name, various formats */
+/* Parse a device name, various formats:
+
+ uw: unsigned_word
+ u: unsigned
+ c: string */
INLINE_DEVICE_TREE int scand_uw
(const char *name,
INLINE_DEVICE_TREE int scand_c
(const char *name,
- char *c1);
+ char *c1, int c1size);
INLINE_DEVICE_TREE int scand_c_uw_u
(const char *name,
- char *c1,
+ char *c1, int c1size,
unsigned_word *uw2,
unsigned *u3);
me->parent->callback->attach_address(me->parent,
me->name,
attach_callback,
- 0 /*address_space*/,
+ 0 /*space*/,
addr,
nr_bytes,
access_read_write,
unimp_device_attach_address(const device *me,
const char *name,
attach_type type,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
unimp_device_detach_address(const device *me,
const char *name,
attach_type type,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
INLINE_DEVICES unsigned
unimp_device_io_read_buffer(const device *me,
void *dest,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
INLINE_DEVICES unsigned
unimp_device_io_write_buffer(const device *me,
const void *source,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
INLINE_DEVICES unsigned
unimp_device_dma_read_buffer(const device *me,
void *target,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes)
{
INLINE_DEVICES unsigned
unimp_device_dma_write_buffer(const device *me,
const void *source,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
INLINE_DEVICES void
pass_device_attach_address(const device *me,
const char *name,
- attach_type type,
- int address_space,
+ attach_type attach,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
const device *who) /*callback/default*/
{
- me->parent->callback->attach_address(me->parent, name, type,
- address_space, addr, nr_bytes,
+ 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 type,
- int address_space,
+ attach_type attach,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
const device *who) /*callback/default*/
{
- me->parent->callback->detach_address(me->parent, name, type,
- address_space, addr, nr_bytes, access,
+ 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 *target,
- int address_space,
+ void *dest,
+ int space,
unsigned_word addr,
unsigned nr_bytes)
{
- return me->parent->callback->dma_read_buffer(me->parent, target,
- address_space, addr, 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 address_space,
+ 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,
- address_space, addr,
+ space, addr,
nr_bytes,
violate_read_only_section);
}
STATIC_INLINE_DEVICES unsigned
console_io_read_buffer_callback(const device *me,
void *dest,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
{
console_device *console = (console_device*)me->data;
unsigned_1 val;
- TRACE(trace_console_device,
- ("device=0x%x, addr=0x%x, nr_bytes=%d\n",
- me, addr, nr_bytes));
+ DTRACE_IO_READ_BUFFER(console);
/* determine what was read */
STATIC_INLINE_DEVICES unsigned
console_io_write_buffer_callback(const device *me,
const void *source,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
{
console_device *console = (console_device*)me->data;
unsigned_1 val = *(unsigned8*)source;
-
- TRACE(trace_console_device,
- ("device=0x%x, addr=0x%x, nr_bytes=%d, val=%d\n",
- me, addr, nr_bytes, val));
+ DTRACE_IO_WRITE_BUFFER(console);
switch (addr) {
case console_read_buffer:
console->input.status = val;
break;
case console_write_buffer:
- TRACE(trace_console_device,
- ("<%c:%d>", val, val));
+ DTRACE(console, ("<%c:%d>", val, val));
printf_filtered("%c",val) ;
console->output.buffer = val;
console->output.status = 1;
STATIC_INLINE_DEVICES const device *
console_create(const char *name,
+ const char *full_name,
const device *parent)
{
/* create the descriptor */
/* insert into the device tree along with its address info */
return device_create_from(name,
+ full_name,
console, /* data */
&console_callbacks,
parent);
STATIC_INLINE_DEVICES unsigned
icu_io_read_buffer_callback(const device *me,
void *dest,
- int address_space,
- unsigned_word base,
+ int space,
+ unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
unsigned_1 val;
- TRACE(trace_icu_device,
- ("device=0x%x, base=0x%x, nr_bytes=%d\n",
- me, base, nr_bytes));
+ DTRACE_IO_READ_BUFFER(icu);
val = cpu_nr(processor);
bzero(dest, nr_bytes);
*(unsigned_1*)dest = val;
STATIC_INLINE_DEVICES unsigned
icu_io_write_buffer_callback(const device *me,
const void *source,
- int address_space,
- unsigned_word base,
+ int space,
+ unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
psim *system = cpu_system(processor);
unsigned_1 val = H2T_1(*(unsigned_1*)source);
- TRACE(trace_icu_device,
- ("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
- me, base, nr_bytes, val));
+ 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 */
STATIC_INLINE_DEVICES unsigned
halt_io_read_buffer_callback(const device *me,
void *dest,
- int address_space,
- unsigned_word base,
+ 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 address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
+ DTRACE_IO_WRITE_BUFFER(halt);
cpu_halt(processor, cia, was_exited, 0);
return 0;
}
unsigned_word value;
unsigned which_cpu;
int status;
- status = scand_c_uw_u(me->name, name, &value, &which_cpu);
+ 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);
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;
STATIC_INLINE_DEVICES void
vm_attach_address(const device *me,
const char *name,
- attach_type type,
- int address_space,
+ 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;
STATIC_INLINE_DEVICES unsigned
vm_io_read_buffer_callback(const device *me,
void *dest,
- int address_space,
+ 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) {
bzero(dest, nr_bytes); /* always initialized to zero */
return nr_bytes;
STATIC_INLINE_DEVICES unsigned
vm_io_write_buffer_callback(const device *me,
const void *source,
- int address_space,
+ 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,
- address_space, addr,
+ space, addr,
nr_bytes,
0/*violate_read_only*/);
}
STATIC_INLINE_DEVICES const device *
vea_vm_create(const char *name,
- const device *parent)
+ const char *full_name,
+ const device *parent)
{
vm_device *vm = ZALLOC(vm_device);
unsigned_word addr;
/* insert in the tree including the buffer */
return device_create_from(name,
+ full_name,
vm, /* data */
&vm_callbacks,
parent);
unsigned_word addr;
unsigned nr_bytes;
unsigned access;
+ int nr_args;
+ DTRACE_INIT(memory);
- if (scand_uw_u_u(me->name, &addr, &nr_bytes, &access) != 3)
+ 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,
};
-STATIC_INLINE_DEVICES const device *
-memory_create(const char *name,
- const device *parent)
-{
- void *buffer;
- unsigned_word addr;
- unsigned nr_bytes;
- if (scand_uw_u(name, &addr, &nr_bytes) != 2)
- error("memory_create() invalid memory device %s\n");
-
- /* insert in the tree including the buffer */
- return device_create_from(name,
- buffer, /* data */
- &memory_callbacks,
- parent);
-}
-
-
\f
/* IOBUS device: iobus@<address>
iobus_attach_address_callback(const device *me,
const char *name,
attach_type type,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
if (type == attach_default)
error("iobus_attach_address_callback() no default for %s/%s\n",
me->name, name);
- if (address_space != 0)
- error("iobus_attach_address_callback() no address_space for %s/%s\n",
+ 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)
me->parent->callback->attach_address(me->parent,
me->name,
type,
- 0 /*address_space*/,
+ 0 /*space*/,
iobus_addr + addr,
nr_bytes,
access,
psim *system)
{
unsigned_word addr;
+ unsigned count;
char *file_name;
char buf;
FILE *image;
+ DTRACE_INIT(file);
if ((file_name = strchr(me->name, ',')) == NULL
|| scand_uw(me->name, &addr) != 1)
error("file_init_callback() file open failed for %s\n", me->name);
/* read it in slowly */
+ count = 0;
while (fread(&buf, 1, 1, image) > 0) {
- me->parent->callback->dma_write_buffer(me->parent,
- &buf,
- 0 /*address-space*/,
- addr,
- 1 /*nr-bytes*/,
- 1 /*violate ro*/);
- addr++;
+ if (me->parent->callback->dma_write_buffer(me->parent,
+ &buf,
+ 0 /*address-space*/,
+ addr+count,
+ 1 /*nr-bytes*/,
+ 1 /*violate ro*/) != 1)
+ error("file_init_callback() failed to write to address 0x%x, offset %d\n",
+ addr+count, count);
+ count++;
}
/* close down again */
htab_init_callback(const device *me,
psim *system)
{
+ DTRACE_INIT(htab);
/* only the pte does work */
if (strncmp(me->name, "pte@", strlen("pte@")) == 0) {
unsigned_word htab_ra;
this device loads or maps the relevant text/data segments into
memory using dma. */
-/* create a device tree from the image */
-
STATIC_INLINE_DEVICES void
-update_device_tree_for_section(bfd *abfd,
- asection *the_section,
- PTR obj)
+update_for_binary_section(bfd *abfd,
+ asection *the_section,
+ PTR obj)
{
unsigned_word section_vma;
unsigned_word section_size;
/* find where it is to go */
section_vma = bfd_get_section_vma(abfd, the_section);
- TRACE(trace_device_tree,
- ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
- bfd_get_section_name(abfd, the_section),
- section_vma, section_size,
- 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" : ""
- ));
+ DTRACE(binary,
+ ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
+ bfd_get_section_name(abfd, the_section),
+ section_vma, section_size,
+ 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 (me->parent->callback->dma_write_buffer(me->parent,
section_init,
- 0 /*address_space*/,
+ 0 /*space*/,
section_vma,
section_size,
1 /*violate_read_only*/)
{
char file_name[100];
bfd *image;
+ DTRACE_INIT(binary);
/* get a file name */
- if (scand_c(me->name, file_name) != 1)
+ if (scand_c(me->name, file_name, sizeof(file_name)) != 1)
error("load_binary_init_callback() invalid load-binary device %s\n",
me->name);
/* and the data sections */
bfd_map_over_sections(image,
- update_device_tree_for_section,
+ update_for_binary_section,
(PTR)me);
bfd_close(image);
unsigned_word start_arg,
unsigned_word end_arg)
{
- TRACE(trace_create_stack,
- ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
- "system", system, "arg", arg,
- "start_block", start_block, "start_arg", start_arg));
+ DTRACE(stack,
+ ("write_stack_arguments(system=0x%x, arg=0x%x, start_block=0x%x, end_block=0x%x, start_arg=0x%x, end_arg=0x%x)\n",
+ system, arg, start_block, end_block, start_arg, 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;
- TRACE(trace_create_stack,
- ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
+ DTRACE(stack,
+ ("write_stack_arguments() write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
"**arg", *arg, "start_block", start_block,
"len", len, "start_arg", start_arg));
if (psim_write_memory(system, 0, *arg,
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
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%x:%s, system=0x%x, processor=0x%x, cia=0x%x, argv=0x%x, envp=0x%x)\n",
+ me, me->full_name, system, processor, cia, argv, 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"));
}
typedef const device *(device_creator)
(const char *name,
+ const char *full_name,
const device *parent);
typedef struct _device_descriptor device_descriptor;
static device_descriptor devices[] = {
{ "console", console_create, NULL },
- { "memory", memory_create, NULL },
+ { "memory", NULL, &memory_callbacks },
{ "vm", vea_vm_create, NULL },
{ "halt", NULL, &halt_callbacks },
{ "icu", NULL, &icu_callbacks },
INLINE_DEVICES const device *
device_create(const char *name,
+ const char *full_name,
const device *parent)
{
device_descriptor *device;
&& (device->name[name_len] == '\0'
|| device->name[name_len] == '@'))
if (device->creator != NULL)
- return device->creator(name, parent);
+ return device->creator(name, full_name, parent);
else
return device_create_from(name,
+ full_name,
NULL /* data */,
device->callbacks,
parent);
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;
(const device *me,
psim *system);
+#define DTRACE_INIT(OBJECT) \
+ DTRACE(OBJECT, \
+ (#OBJECT "_init(me=0x%x:%s system=0x%x)\n", \
+ me, me->full_name, system))
/* Data transfers:
typedef void (device_config_address_callback)
(const device *me,
const char *name,
- attach_type type,
- int address_space,
+ 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%x:%s, name=%s, attach=%d, space=%d, addr=0x%x, nr_bytes=%d, access=%d, who=0x%x)\n", \
+ me, me->full_name, name, attach, space, addr, nr_bytes, access, who))
+#define DTRACE_DETACH_ADDRESS(OBJECT) \
+ DTRACE(OBJECT, \
+ (#OBJECT "_detach_address(me=0x%x:%s, name=%s, attach=%d, space=%d, addr=0x%x, nr_bytes=%d, access=%d, who=0x%x)\n", \
+ me, me->full_name, name, attach, space, addr, nr_bytes, access, who))
+
+
typedef unsigned (device_io_read_buffer_callback)
(const device *me,
void *dest,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
typedef unsigned (device_io_write_buffer_callback)
(const device *me,
const void *source,
- int address_space,
+ 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%x:%s dest=0x%x space=%d addr=0x%x nr_bytes=%d processor=0x%x cia=0x%x)\n", \
+ me, me->full_name, dest, space, addr, nr_bytes, processor, cia))
+#define DTRACE_IO_WRITE_BUFFER(OBJECT) \
+ DTRACE(OBJECT, \
+ (#OBJECT "_io_write_buffer(me=0x%x:%s source=0x%x space=%d addr=0x%x nr_bytes=%d processor=0x%x cia=0x%x)\n", \
+ me, me->full_name, source, space, addr, nr_bytes, processor, cia))
+
+
typedef unsigned (device_dma_read_buffer_callback)
(const device *me,
void *dest,
- int address_space,
+ int space,
unsigned_word addr,
unsigned nr_bytes);
typedef unsigned (device_dma_write_buffer_callback)
(const device *me,
const void *source,
- int address_space,
+ 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%x:%s dest=0x%x space=%d addr=0x%x nr_bytes=%d)\n", \
+ me, me->full_name, dest, space, addr, nr_bytes))
+#define DTRACE_DMA_WRITE_BUFFER(OBJECT) \
+ DTRACE(OBJECT, \
+ (#OBJECT "_dma_write_buffer(me=0x%x:%s source=0x%x space=%d addr=0x%x nr_bytes=%d)\n", \
+ me, me->full_name, source, space, addr, nr_bytes))
+
/* Interrupts:
/* A device */
struct _device {
- const char *name; /* eg rom@0x1234, 0x400 */
+ 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;
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);
--- /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_NETBSD_H_
+#define _EMUL_NETBSD_H_
+
+extern emulation emul_netbsd;
+
+#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.
-
- */
-
-
-/* BUGS:
-
- Instead of using/abusing macro's the semantic code should be parsed
- and each `cachable' expression replaced with the corresponding
- value. */
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "config.h"
-#include "ppc-config.h"
-
-#undef WITH_ASSERT
-#define WITH_ASSERT 1
-
-#include "debug.h"
-
-
-/****************************************************************/
-
-static void
-error (char *msg, ...)
-{
- va_list ap;
- va_start(ap, msg);
- vprintf(msg, ap);
- va_end(ap);
- exit (1);
-}
-
-static void *
-zmalloc(long size)
-{
- void *memory = malloc(size);
- if (memory == NULL)
- error("zmalloc failed\n");
- bzero(memory, size);
- return memory;
-}
-
-static void
-dumpf (int indent, char *msg, ...)
-{
- va_list ap;
- for (; indent > 0; indent--)
- printf(" ");
- va_start(ap, msg);
- vprintf(msg, ap);
- va_end(ap);
-}
-
-
-/****************************************************************/
-
-int idecode_expand_semantics = WITH_IDECODE_EXPAND_SEMANTICS;
-int idecode_cache = WITH_IDECODE_CACHE;
-int spreg_lookup_table = WITH_SPREG_LOOKUP_TABLE;
-
-/****************************************************************/
-
-typedef struct {
- int valid;
- char *old_name;
- char *new_name;
- char *type;
- char *expression;
-} extraction_rules;
-
-extraction_rules cachable_values[] = WITH_IDECODE_CACHE_RULES;
-
-/****************************************************************/
-
-typedef struct _opcode_rules {
- int valid;
- int first;
- int last;
- int force_first;
- int force_last;
- int force_slash;
- char *force_expansion;
- int use_switch;
- unsigned special_mask;
- unsigned special_value;
- unsigned special_rule;
-} opcode_rules;
-
-/* FIXME - this should be loaded from a file */
-opcode_rules opcode_table[] = WITH_IDECODE_OPCODE_RULES;
-
-static void
-dump_opcode_rule(opcode_rules *rule,
- int indent)
-{
- printf("(opcode_rules*)%p\n", rule);
- dumpf(indent, "(valid %d)\n", rule->valid);
- ASSERT(rule != NULL);
- if (rule->valid) {
- dumpf(indent, "(first %d)\n", rule->first);
- dumpf(indent, "(last %d)\n", rule->last);
- dumpf(indent, "(force_first %d)\n", rule->force_first);
- dumpf(indent, "(force_last %d)\n", rule->force_last);
- dumpf(indent, "(force_slash %d)\n", rule->force_slash);
- dumpf(indent, "(force_expansion %s)\n", rule->force_expansion);
- }
-}
-
-
-/****************************************************************/
-
-enum gen_constants {
- insn_size = 32,
- nr_of_sprs = 1024
-};
-
-char cache_idecode_formal[] = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia,\n idecode_cache *cache_entry";
-char cache_idecode_actual[] = "processor, instruction, cia, cache_entry";
-char cache_insn_formal[] = "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia";
-char cache_insn_actual[] = "processor, entry, cia";
-
-char insn_formal[] = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia";
-char insn_actual[] = "processor, instruction, cia";
-
-char insn_local[] = "unsigned_word nia = cia + 4;";
-
-
-/****************************************************************/
-
-static int
-bin2i(char *bin, int width)
-{
- int i = 0;
- while (*bin != '\0' && width != 0) {
- i = (i << 1) + (*bin - '0');
- width--;
- bin++;
- }
- return i;
-}
-
-
-static int
-it_is(char *flag,
- char *flags)
-{
- int flag_len = strlen(flag);
- while (*flags != '\0') {
- if (!strncmp(flags, flag, flag_len)
- && (flags[flag_len] == ',' || flags[flag_len] == '\0'))
- return 1;
- while (*flags != ',') {
- if (*flags == '\0')
- return 0;
- flags++;
- }
- flags++;
- }
- return 0;
-}
-
-
-/****************************************************************/
-
-typedef struct _lf lf;
-struct _lf {
- FILE *stream;
- int line_nr; /* nr complete lines written, curr line is line_nr+1 */
- int indent;
- int line_blank;
- char *file_name;
-};
-
-
-static lf *
-lf_open(char *name,
- char *real_name)
-{
- /* create a file object */
- lf *new_lf = zmalloc(sizeof(lf));
- ASSERT(new_lf != NULL);
- new_lf->file_name = (real_name == NULL
- ? name
- : real_name);
-
- /* attach to stdout if pipe */
- if (!strcmp(name, "-")) {
- new_lf->stream = stdout;
- }
- else {
- /* create a new file */
- new_lf->stream = fopen(name, "w");
- ASSERT(new_lf->stream != NULL);
- }
- return new_lf;
-}
-
-
-static void
-lf_close(lf *file)
-{
- if (file->stream != stdout) {
- if (fclose(file->stream)) {
- perror("lf_close.fclose");
- exit(1);
- }
- free(file);
- }
-}
-
-
-static void
-lf_putchr(lf *file,
- const char chr)
-{
- if (chr == '\n') {
- file->line_nr += 1;
- file->line_blank = 1;
- }
- else if (file->line_blank) {
- int pad;
- for (pad = file->indent; pad > 0; pad--)
- putc(' ', file->stream);
- file->line_blank = 0;
- }
- putc(chr, file->stream);
-}
-
-static void
-lf_indent_suppress(lf *file)
-{
- file->line_blank = 0;
-}
-
-
-static void
-lf_putstr(lf *file,
- const char *string)
-{
- const char *chp;
- if (string != NULL) {
- for (chp = string; *chp != '\0'; chp++) {
- lf_putchr(file, *chp);
- }
- }
-}
-
-static void
-do_lf_putunsigned(lf *file,
- unsigned u)
-{
- if (u > 0) {
- do_lf_putunsigned(file, u / 10);
- lf_putchr(file, (u % 10) + '0');
- }
-}
-
-
-static void
-lf_putint(lf *file,
- int decimal)
-{
- if (decimal == 0)
- lf_putchr(file, '0');
- else if (decimal < 0) {
- lf_putchr(file, '-');
- do_lf_putunsigned(file, -decimal);
- }
- else if (decimal > 0) {
- do_lf_putunsigned(file, decimal);
- }
- else
- ASSERT(0);
-}
-
-static void
-lf_printf(lf *file,
- const char *fmt,
- ...)
-{
- char buf[1024];
- va_list ap;
- int nr_chars;
-
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- /* FIXME - this is really stuffed but so is vsprintf() on a sun! */
- ASSERT(strlen(buf) > 0 && strlen(buf) < sizeof(buf));
- lf_putstr(file, buf);
- va_end(ap);
-}
-
-static void
-lf_print_file_line_nr(lf *file)
-{
-#if WITH_LINE_NUMBERS
- lf_indent_suppress(file);
- lf_putstr(file, "#line ");
- lf_putint(file, file->line_nr+2); /*line_nr == last_line, want next */
- lf_putstr(file, " \"");
- lf_putstr(file, file->file_name);
- lf_putstr(file, "\"\n");
-#endif
-}
-
-static void
-lf_indent(lf *file, int delta)
-{
- file->indent += delta;
-}
-
-
-/****************************************************************/
-
-/* read entries from ppc.instructions */
-
-enum {
- file_table_max_fields = 6,
-};
-
-typedef struct _file_table file_table;
-struct _file_table {
- size_t size;
- char *buffer;
- char *pos;
- int line_nr;
- char *file_name;
-};
-
-typedef struct _file_table_entry file_table_entry;
-struct _file_table_entry {
- char *fields[file_table_max_fields];
- int line_nr;
- char *file_name;
- char *annex;
-};
-
-
-static file_table *
-file_table_open(char *file_name)
-{
- int fd;
- struct stat stat_buf;
- file_table *file;
-
- /* create a file descriptor */
- file = (file_table*)zmalloc(sizeof(file_table));
- ASSERT(file != NULL);
-
- /* save the file name */
- file->file_name = (char*)zmalloc(strlen(file_name) + 1);
- ASSERT(file->file_name != NULL);
- strcpy(file->file_name, file_name);
-
- /* open the file */
- fd = open(file->file_name, O_RDONLY, 0);
- ASSERT(fd >= 0);
-
- /* determine the size */
- if (fstat(fd, &stat_buf) < 0) {
- perror("file_table_open.fstat");
- exit(1);
- }
- file->size = stat_buf.st_size;
-
- /* allocate this much memory */
- file->buffer = (char*)zmalloc(file->size+1);
- if(file->buffer == NULL) {
- perror("file_table_open.calloc.file->size+1");
- exit(1);
- }
- file->pos = file->buffer;
-
- /* read it in */
- if (read(fd, file->buffer, file->size) < file->size) {
- perror("file_table_open.read");
- exit(1);
- }
- file->buffer[file->size] = '\0';
-
- /* done */
- close(fd);
- return file;
-}
-
-
-static file_table_entry *
-file_table_read(file_table *file)
-{
- int field;
- file_table_entry *entry;
-
- /* skip comments/blanks */
- while(1) {
- /* leading white space */
- while (*file->pos != '\0'
- && *file->pos != '\n'
- && isspace(*file->pos))
- file->pos++;
- /* comment */
- if (*file->pos == '#') {
- do {
- file->pos++;
- } while (*file->pos != '\0' && *file->pos != '\n');
- }
- /* end of line? */
- if (*file->pos == '\n') {
- file->pos++;
- file->line_nr++;
- }
- else
- break;
- }
- if (*file->pos == '\0')
- return NULL;
-
- /* create this new entry */
- entry = (file_table_entry*)zmalloc(sizeof(file_table_entry));
- ASSERT(entry != NULL);
- entry->file_name = file->file_name;
-
- /* break the line into its colon delimitered fields */
- for (field = 0; field < file_table_max_fields-1; field++) {
- entry->fields[field] = file->pos;
- while(*file->pos && *file->pos != ':' && *file->pos != '\n')
- file->pos++;
- if (*file->pos == ':') {
- *file->pos = '\0';
- file->pos++;
- }
- }
-
- /* any trailing stuff not the last field */
- ASSERT(field == file_table_max_fields-1);
- entry->fields[field] = file->pos;
- while (*file->pos && *file->pos != '\n') {
- file->pos++;
- }
- if (*file->pos == '\n') {
- *file->pos = '\0';
- file->pos++;
- }
- file->line_nr++;
- entry->line_nr = file->line_nr;
-
- /* if following lines tab indented, put in the annex */
- if (*file->pos == '\t') {
- entry->annex = file->pos;
- do {
- do {
- file->pos++;
- } while (*file->pos != '\0' && *file->pos != '\n');
- if (*file->pos == '\n') {
- file->pos++;
- file->line_nr++;
- }
- } while (*file->pos != '\0' && *file->pos == '\t');
- if (file->pos[-1] == '\n')
- file->pos[-1] = '\0';
- }
- else
- entry->annex = NULL;
-
- /* return it */
- return entry;
-
-}
-
-
-static void
-dump_file_table_entry(file_table_entry *entry,
- int indent)
-{
- printf("(file_table_entry*)%p\n", entry);
-
- if (entry != NULL) {
- int field;
- char sep;
-
- sep = ' ';
- dumpf(indent, "(fields");
- for (field = 0; field < file_table_max_fields; field++) {
- printf("%c%s", sep, entry->fields[field]);
- sep = ':';
- }
- printf(")\n");
-
- dumpf(indent, "(line_nr %d)\n", entry->line_nr);
-
- dumpf(indent, "(file_name %s)\n", entry->file_name);
-
- dumpf(indent, "(annex\n%s\n", entry->annex);
- dumpf(indent, " )\n");
-
- }
-}
-
-
-/****************************************************************/
-
-typedef struct _insn_field insn_field;
-struct _insn_field {
- int first;
- int last;
- int width;
- int is_int;
- int is_slash;
- int is_string;
- int val_int;
- char *pos_string;
- char *val_string;
- insn_field *next;
- insn_field *prev;
-};
-
-typedef struct _insn_fields insn_fields;
-struct _insn_fields {
- insn_field *bits[insn_size];
- insn_field *first;
- insn_field *last;
- unsigned value;
-};
-
-static insn_field *
-insn_field_new()
-{
- insn_field *new_field = (insn_field*)zmalloc(sizeof(insn_field));
- ASSERT(new_field != NULL);
- return new_field;
-}
-
-static insn_fields *
-insn_fields_new()
-{
- insn_fields *new_fields = (insn_fields*)zmalloc(sizeof(insn_fields));
- ASSERT(new_fields != NULL);
- return new_fields;
-}
-
-
-static insn_fields *
-parse_insn_format(file_table_entry *entry,
- char *format)
-{
- char *chp;
- insn_fields *fields = insn_fields_new();
-
- /* create a leading sentinal */
- fields->first = insn_field_new();
- fields->first->first = -1;
- fields->first->last = -1;
- fields->first->width = 0;
-
- /* and a trailing sentinal */
- fields->last = insn_field_new();
- fields->last->first = insn_size;
- fields->last->last = insn_size;
- fields->last->width = 0;
-
- /* link them together */
- fields->first->next = fields->last;
- fields->last->prev = fields->first;
-
- /* now work through the formats */
- chp = format;
-
- while (*chp != '\0') {
- char *start_pos;
- char *start_val;
- int strlen_val;
- int strlen_pos;
- insn_field *new_field;
-
- /* sanity check */
- if (!isdigit(*chp)) {
- error("%s:%d: missing position field at `%s'\n",
- entry->file_name, entry->line_nr, chp);
- }
-
- /* break out the bit position */
- start_pos = chp;
- while (isdigit(*chp))
- chp++;
- strlen_pos = chp - start_pos;
- if (*chp == '.' && strlen_pos > 0)
- chp++;
- else {
- error("%s:%d: missing field value at %s\n",
- entry->file_name, entry->line_nr, chp);
- break;
- }
-
- /* break out the value */
- start_val = chp;
- while ((*start_val == '/' && *chp == '/')
- || (isdigit(*start_val) && isdigit(*chp))
- || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_')))
- chp++;
- strlen_val = chp - start_val;
- if (*chp == ',')
- chp++;
- else if (*chp != '\0' || strlen_val == 0) {
- error("%s:%d: missing field terminator at %s\n",
- entry->file_name, entry->line_nr, chp);
- break;
- }
-
- /* create a new field and insert it */
- new_field = insn_field_new();
- new_field->next = fields->last;
- new_field->prev = fields->last->prev;
- new_field->next->prev = new_field;
- new_field->prev->next = new_field;
-
- /* the value */
- new_field->val_string = (char*)zmalloc(strlen_val+1);
- strncpy(new_field->val_string, start_val, strlen_val);
- if (isdigit(*new_field->val_string)) {
- new_field->val_int = atoi(new_field->val_string);
- new_field->is_int = 1;
- }
- else if (new_field->val_string[0] == '/') {
- new_field->is_slash = 1;
- }
- else {
- new_field->is_string = 1;
- }
-
- /* the pos */
- new_field->pos_string = (char*)zmalloc(strlen_pos+1);
- strncpy(new_field->pos_string, start_pos, strlen_pos);
- new_field->first = atoi(new_field->pos_string);
- new_field->last = new_field->next->first - 1; /* guess */
- new_field->width = new_field->last - new_field->first + 1; /* guess */
- new_field->prev->last = new_field->first-1; /*fix*/
- new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/
- }
-
- /* fiddle first/last so that the sentinals `disapear' */
- ASSERT(fields->first->last < 0);
- ASSERT(fields->last->first >= insn_size);
- fields->first = fields->first->next;
- fields->last = fields->last->prev;
-
- /* now go over this again, pointing each bit position at a field
- record */
- {
- int i;
- insn_field *field;
- field = fields->first;
- for (i = 0; i < insn_size; i++) {
- while (field->last < i)
- field = field->next;
- fields->bits[i] = field;
- }
- }
-
- /* go over each of the fields, and compute a `value' for the insn */
- {
- insn_field *field;
- fields->value = 0;
- for (field = fields->first;
- field->last < insn_size;
- field = field->next) {
- fields->value <<= field->width;
- if (field->is_int)
- fields->value |= field->val_int;
- }
- }
- return fields;
-}
-
-
-typedef enum {
- field_constant_int = 1,
- field_constant_slash = 2,
- field_constant_string = 3
-} constant_field_types;
-
-
-static int
-insn_field_is_constant(insn_field *field,
- opcode_rules *rule)
-{
- /* field is an integer */
- if (field->is_int)
- return field_constant_int;
- /* field is `/' and treating that as a constant */
- if (field->is_slash && rule->force_slash)
- return field_constant_slash;
- /* field, though variable is on the list */
- if (field->is_string && rule->force_expansion != NULL) {
- char *forced_fields = rule->force_expansion;
- while (*forced_fields != '\0') {
- int field_len;
- char *end = strchr(forced_fields, ',');
- if (end == NULL)
- field_len = strlen(forced_fields);
- else
- field_len = end-forced_fields;
- if (strncmp(forced_fields, field->val_string, field_len) == 0
- && field->val_string[field_len] == '\0')
- return field_constant_string;
- forced_fields += field_len;
- if (*forced_fields == ',')
- forced_fields++;
- }
- }
- return 0;
-}
-
-
-static void
-dump_insn_field(insn_field *field,
- int indent)
-{
-
- printf("(insn_field*)0x%x\n", (unsigned)field);
-
- dumpf(indent, "(first %d)\n", field->first);
-
- dumpf(indent, "(last %d)\n", field->last);
-
- dumpf(indent, "(width %d)\n", field->width);
-
- if (field->is_int)
- dumpf(indent, "(is_int %d)\n", field->val_int);
-
- if (field->is_slash)
- dumpf(indent, "(is_slash)\n");
-
- if (field->is_string)
- dumpf(indent, "(is_string `%s')\n", field->val_string);
-
- dumpf(indent, "(next 0x%x)\n", field->next);
-
- dumpf(indent, "(prev 0x%x)\n", field->prev);
-
-
-}
-
-static void
-dump_insn_fields(insn_fields *fields,
- int indent)
-{
- insn_field *field;
- int i;
-
- printf("(insn_fields*)%p\n", fields);
-
- dumpf(indent, "(first 0x%x)\n", fields->first);
- dumpf(indent, "(last 0x%x)\n", fields->last);
-
- dumpf(indent, "(value 0x%x)\n", fields->value);
-
- for (i = 0; i < insn_size; i++) {
- dumpf(indent, "(bits[%d] ", i, fields->bits[i]);
- dump_insn_field(fields->bits[i], indent+1);
- dumpf(indent, " )\n");
- }
-
-}
-
-
-/****************************************************************/
-
-typedef struct _opcode_field opcode_field;
-struct _opcode_field {
- int first;
- int last;
- int is_boolean;
- opcode_field *parent;
-};
-
-static opcode_field *
-opcode_field_new()
-{
- opcode_field *new_field = (opcode_field*)zmalloc(sizeof(opcode_field));
- ASSERT(new_field != NULL);
- new_field->first = insn_size;
- new_field->last = -1;
- return new_field;
-}
-
-static void
-dump_opcode_field(opcode_field *field, int indent, int levels)
-{
- printf("(opcode_field*)%p\n", field);
- if (levels && field != NULL) {
- dumpf(indent, "(first %d)\n", field->first);
- dumpf(indent, "(last %d)\n", field->last);
- dumpf(indent, "(is_boolean %d)\n", field->is_boolean);
- dumpf(indent, "(parent ");
- dump_opcode_field(field->parent, indent, levels-1);
- }
-}
-
-
-/****************************************************************/
-
-typedef struct _insn_bits insn_bits;
-struct _insn_bits {
- int is_expanded;
- int value;
- insn_field *field;
- opcode_field *opcode;
- insn_bits *last;
-};
-
-static insn_bits *
-insn_bits_new()
-{
- insn_bits *new_bits = (insn_bits*)zmalloc(sizeof(insn_bits));
- ASSERT(new_bits);
- return new_bits;
-}
-
-
-static void
-dump_insn_bits(insn_bits *bits, int indent, int levels)
-{
- printf("(insn_bits*)%p\n", bits);
-
- if (levels && bits != NULL) {
- dumpf(indent, "(value %d)\n", bits->value);
- dumpf(indent, "(opcode ");
- dump_opcode_field(bits->opcode, indent+1, 0);
- dumpf(indent, " )\n");
- dumpf(indent, "(field ");
- dump_insn_field(bits->field, indent+1);
- dumpf(indent, " )\n");
- dumpf(indent, "(last ");
- dump_insn_bits(bits->last, indent+1, levels-1);
- }
-}
-
-
-/****************************************************************/
-
-
-typedef enum {
- insn_format,
- insn_form,
- insn_flags,
- insn_nmemonic,
- insn_name,
- insn_comment,
- nr_insn_table_fields = file_table_max_fields,
-} insn_table_fields;
-char *insn_field_name[] = {
- "format", "form", "flags", "nmemonic", "name", "comments"
-};
-
-typedef enum {
- function_type = insn_format,
- function_name = insn_name,
- function_param = insn_comment,
-} function_table_fields;
-
-
-typedef struct _insn insn;
-struct _insn {
- file_table_entry *file_entry;
- insn_fields *fields;
- insn *next;
-};
-
-typedef struct _insn_table insn_table;
-struct _insn_table {
- int opcode_nr;
- insn_bits *expanded_bits;
- int nr_insn;
- insn *insns;
- insn *functions;
- opcode_rules *opcode_rule;
- opcode_field *opcode;
- int nr_entries;
- insn_table *entries;
- insn_table *sibling;
- insn_table *parent;
-};
-
-
-
-static insn *
-insn_new()
-{
- insn *new_entry = ((insn*) zmalloc(sizeof(insn)));
- ASSERT(new_entry != NULL);
- return new_entry;
-}
-
-static insn_table *
-insn_table_new()
-{
- insn_table *new_table = (insn_table*)zmalloc(sizeof(insn_table));
- ASSERT(new_table != NULL);
- return new_table;
-}
-
-
-static void
-insn_table_insert_function(insn_table *table,
- file_table_entry *file_entry)
-{
- insn **ptr_to_cur_function = &table->functions;
-
- /* create a new function */
- insn *new_function = insn_new();
- new_function->file_entry = file_entry;
-
- /* append it to the end of the function list */
- while (*ptr_to_cur_function != NULL) {
- ptr_to_cur_function = &(*ptr_to_cur_function)->next;
- }
- *ptr_to_cur_function = new_function;
-}
-
-
-static void
-insn_table_insert_insn(insn_table *table,
- file_table_entry *file_entry,
- insn_fields *fields)
-{
- insn **ptr_to_cur_insn = &table->insns;
- insn *cur_insn = *ptr_to_cur_insn;
-
- /* create a new instruction */
- insn *new_insn = insn_new();
- new_insn->file_entry = file_entry;
- new_insn->fields = fields;
-
- /* insert it according to the order of the fields */
- while (cur_insn != NULL
- && new_insn->fields->value >= cur_insn->fields->value) {
- ptr_to_cur_insn = &cur_insn->next;
- cur_insn = *ptr_to_cur_insn;
- }
-
- new_insn->next = cur_insn;
- *ptr_to_cur_insn = new_insn;
-
- table->nr_insn++;
-}
-
-
-static opcode_field *
-insn_table_find_opcode_field(insn *insns,
- opcode_rules *rule,
- int string_only)
-{
- opcode_field *curr_opcode = opcode_field_new();
- insn *entry;
-
- ASSERT(rule->valid);
-
- for (entry = insns; entry != NULL; entry = entry->next) {
- insn_fields *fields = entry->fields;
- opcode_field new_opcode;
-
- /* find a start point for the opcode field */
- new_opcode.first = rule->first;
- while (new_opcode.first <= rule->last
- && (!string_only
- || insn_field_is_constant(fields->bits[new_opcode.first],
- rule) != field_constant_string)
- && (string_only
- || !insn_field_is_constant(fields->bits[new_opcode.first],
- rule)))
- new_opcode.first = fields->bits[new_opcode.first]->last + 1;
- ASSERT(new_opcode.first > rule->last
- || (string_only
- && insn_field_is_constant(fields->bits[new_opcode.first],
- rule) == field_constant_string)
- || (!string_only
- && insn_field_is_constant(fields->bits[new_opcode.first],
- rule)));
-
- /* find the end point for the opcode field */
- new_opcode.last = rule->last;
- while (new_opcode.last >= rule->first
- && (!string_only
- || insn_field_is_constant(fields->bits[new_opcode.last],
- rule) != field_constant_string)
- && (string_only
- || !insn_field_is_constant(fields->bits[new_opcode.last],
- rule)))
- new_opcode.last = fields->bits[new_opcode.last]->first - 1;
- ASSERT(new_opcode.last < rule->first
- || (string_only
- && insn_field_is_constant(fields->bits[new_opcode.last],
- rule) == field_constant_string)
- || (!string_only
- && insn_field_is_constant(fields->bits[new_opcode.last],
- rule)));
-
- /* now see if our current opcode needs expanding */
- if (new_opcode.first <= rule->last
- && curr_opcode->first > new_opcode.first)
- curr_opcode->first = new_opcode.first;
- if (new_opcode.last >= rule->first
- && curr_opcode->last < new_opcode.last)
- curr_opcode->last = new_opcode.last;
-
- }
-
- /* was any thing interesting found? */
- if (curr_opcode->first > rule->last) {
- ASSERT(curr_opcode->last < rule->first);
- free(curr_opcode);
- return NULL;
- }
- ASSERT(curr_opcode->last >= rule->first);
- ASSERT(curr_opcode->first <= rule->last);
-
- /* if something was found, check it includes the forced field range */
- if (!string_only
- && curr_opcode->first > rule->force_first) {
- curr_opcode->first = rule->force_first;
- }
- if (!string_only
- && curr_opcode->last < rule->force_last) {
- curr_opcode->last = rule->force_last;
- }
- /* handle special case elminating any need to do shift after mask */
- if (string_only
- && rule->force_last == insn_size-1) {
- curr_opcode->last = insn_size-1;
- }
-
- /* handle any special cases */
- switch (rule->special_rule) {
- case 0: /* let the above apply */
- break;
- case 1: /* expand a limited nr of bits, ignoring the rest */
- curr_opcode->first = rule->force_first;
- curr_opcode->last = rule->force_last;
- break;
- case 2: /* boolean field */
- curr_opcode->is_boolean = 1;
- break;
- }
-
- return curr_opcode;
-}
-
-
-static void
-insn_table_insert_expanded(insn_table *table,
- insn *old_insn,
- int new_opcode_nr,
- insn_bits *new_bits)
-{
- insn_table **ptr_to_cur_entry = &table->entries;
- insn_table *cur_entry = *ptr_to_cur_entry;
-
- /* find the new table for this entry */
- while (cur_entry != NULL
- && cur_entry->opcode_nr < new_opcode_nr) {
- ptr_to_cur_entry = &cur_entry->sibling;
- cur_entry = *ptr_to_cur_entry;
- }
-
- if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) {
- insn_table *new_entry = insn_table_new();
- new_entry->opcode_nr = new_opcode_nr;
- new_entry->expanded_bits = new_bits;
- new_entry->opcode_rule = table->opcode_rule+1;
- new_entry->sibling = cur_entry;
- new_entry->parent = table;
- *ptr_to_cur_entry = new_entry;
- cur_entry = new_entry;
- table->nr_entries++;
- }
- /* ASSERT new_bits == cur_entry bits */
- ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr);
- insn_table_insert_insn(cur_entry,
- old_insn->file_entry,
- old_insn->fields);
-}
-
-static void
-insn_table_expand_opcode(insn_table *table,
- insn *instruction,
- int field_nr,
- int opcode_nr,
- insn_bits *bits)
-{
-
- if (field_nr > table->opcode->last) {
- insn_table_insert_expanded(table, instruction, opcode_nr, bits);
- }
- else {
- insn_field *field = instruction->fields->bits[field_nr];
- if (field->is_int || field->is_slash) {
- ASSERT(field->first >= table->opcode->first
- && field->last <= table->opcode->last);
- insn_table_expand_opcode(table, instruction, field->last+1,
- ((opcode_nr << field->width) + field->val_int),
- bits);
- }
- else {
- int val;
- int last_pos = ((field->last < table->opcode->last)
- ? field->last : table->opcode->last);
- int first_pos = ((field->first > table->opcode->first)
- ? field->first : table->opcode->first);
- int width = last_pos - first_pos + 1;
- int last_val = (table->opcode->is_boolean
- ? 2 : (1 << width));
- for (val = 0; val < last_val; val++) {
- insn_bits *new_bits = insn_bits_new();
- new_bits->field = field;
- new_bits->value = val;
- new_bits->last = bits;
- new_bits->opcode = table->opcode;
- insn_table_expand_opcode(table, instruction, last_pos+1,
- ((opcode_nr << width) | val),
- new_bits);
- }
- }
- }
-}
-
-static void
-insn_table_insert_expanding(insn_table *table,
- insn *entry)
-{
- insn_table_expand_opcode(table,
- entry,
- table->opcode->first,
- 0,
- table->expanded_bits);
-}
-
-
-static void
-insn_table_expand_insns(insn_table *table)
-{
-
- ASSERT(table->nr_insn >= 1);
-
- /* determine a valid opcode */
- while (table->opcode_rule->valid) {
- /* specials only for single instructions */
- if ((table->nr_insn > 1
- && table->opcode_rule->special_mask == 0
- && table->opcode_rule->special_rule == 0)
- || (table->nr_insn == 1
- && table->opcode_rule->special_mask != 0
- && ((table->insns->fields->value
- & table->opcode_rule->special_mask)
- == table->opcode_rule->special_value))
- || (idecode_expand_semantics
- && table->opcode_rule->special_mask == 0
- && table->opcode_rule->special_rule == 0))
- table->opcode =
- insn_table_find_opcode_field(table->insns,
- table->opcode_rule,
- table->nr_insn == 1/*string*/
- );
- if (table->opcode != NULL)
- break;
- table->opcode_rule++;
- }
-
- /* did we find anything */
- if (table->opcode == NULL) {
- return;
- }
- ASSERT(table->opcode != NULL);
-
- /* back link what we found to its parent */
- if (table->parent != NULL) {
- ASSERT(table->parent->opcode != NULL);
- table->opcode->parent = table->parent->opcode;
- }
-
- /* expand the raw instructions according to the opcode */
- {
- insn *entry;
- for (entry = table->insns; entry != NULL; entry = entry->next) {
- insn_table_insert_expanding(table, entry);
- }
- }
-
- /* and do the same for the sub entries */
- {
- insn_table *entry;
- for (entry = table->entries; entry != NULL; entry = entry->sibling) {
- insn_table_expand_insns(entry);
- }
- }
-}
-
-
-
-static insn_table *
-insn_table_load_insns(char *file_name)
-{
- file_table *file = file_table_open(file_name);
- insn_table *table = insn_table_new();
- file_table_entry *file_entry;
- table->opcode_rule = opcode_table;
-
- while ((file_entry = file_table_read(file)) != NULL) {
- if (it_is("function", file_entry->fields[insn_flags])
- || it_is("internal", file_entry->fields[insn_flags])) {
- insn_table_insert_function(table, file_entry);
- }
- else {
- insn_fields *fields;
- /* skip instructions that aren't relevant to the mode */
- if ((it_is("64", file_entry->fields[insn_flags])
- && WITH_TARGET_WORD_BITSIZE != 64)
- || (it_is("32", file_entry->fields[insn_flags])
- && WITH_TARGET_WORD_BITSIZE != 32)
- || (it_is("f", file_entry->fields[insn_flags])
- && WITH_FLOATING_POINT == SOFT_FLOATING_POINT))
- continue;
- /* create/insert the new instruction */
- fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
- insn_table_insert_insn(table, file_entry, fields);
- }
- }
- return table;
-}
-
-
-static void
-dump_insn(insn *entry, int indent, int levels)
-{
- printf("(insn*)%p\n", entry);
-
- if (levels && entry != NULL) {
-
- dumpf(indent, "(file_entry ");
- dump_file_table_entry(entry->file_entry, indent+1);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(fields ");
- dump_insn_fields(entry->fields, indent+1);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(next ");
- dump_insn(entry->next, indent+1, levels-1);
- dumpf(indent, " )\n");
-
- }
-
-}
-
-
-static void
-dump_insn_table(insn_table *table,
- int indent, int levels)
-{
-
- printf("(insn_table*)%p\n", table);
-
- if (levels && table != NULL) {
- insn *entry;
-
- dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr);
-
- dumpf(indent, "(expanded_bits ");
- dump_insn_bits(table->expanded_bits, indent+1, -1);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(int nr_insn %d)\n", table->nr_insn);
-
- dumpf(indent, "(insns ");
- dump_insn(table->insns, indent+1, table->nr_insn);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(opcode_rule ");
- dump_opcode_rule(table->opcode_rule, indent+1);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(opcode ");
- dump_opcode_field(table->opcode, indent+1, 1);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(nr_entries %d)\n", table->entries);
- dumpf(indent, "(entries ");
- dump_insn_table(table->entries, indent+1, table->nr_entries);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(sibling ", table->sibling);
- dump_insn_table(table->sibling, indent+1, levels-1);
- dumpf(indent, " )\n");
-
- dumpf(indent, "(parent ", table->parent);
- dump_insn_table(table->parent, indent+1, 0);
- dumpf(indent, " )\n");
-
- }
-}
-
-
-/****************************************************************/
-
-
-static void
-lf_print_copyleft(lf *file)
-{
- lf_putstr(file, "\
-/* This file is part of psim (model of the PowerPC(tm) architecture)
-
- Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License
- as published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This library 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- --
-
- PowerPC is a trademark of International Business Machines Corporation.
-
- --
-
- This file was generated by the program gen */
-");
-}
-
-
-static void
-lf_print_c_line_nr(lf *file, file_table_entry *entry)
-{
-#if WITH_LINE_NUMBERS
- lf_indent_suppress(file);
- lf_putstr(file, "#line ");
- lf_putint(file, entry->line_nr);
- lf_putstr(file, " \"");
- lf_putstr(file, entry->file_name);
- lf_putstr(file, "\"\n");
-#endif
-}
-
-
-static void
-lf_print_c_code(lf *file, char *code)
-{
- char *chp = code;
- int in_bit_field = 0;
- while (*chp != '\0') {
- if (*chp == '\t')
- chp++;
- if (*chp == '#')
- lf_indent_suppress(file);
- while (*chp != '\0' && *chp != '\n') {
- if (chp[0] == '{' && !isspace(chp[1])) {
- in_bit_field = 1;
- lf_putchr(file, '_');
- }
- else if (in_bit_field && chp[0] == ':') {
- lf_putchr(file, '_');
- }
- else if (in_bit_field && *chp == '}') {
- lf_putchr(file, '_');
- in_bit_field = 0;
- }
- else {
- lf_putchr(file, *chp);
- }
- chp++;
- }
- if (in_bit_field)
- error("bit field paren miss match some where\n");
- if (*chp == '\n') {
- lf_putchr(file, '\n');
- chp++;
- }
- }
- lf_putchr(file, '\n');
-}
-
-
-static void
-lf_print_binary(lf *file, int decimal, int width)
-{
- int bit;
- ASSERT(width > 0);
-
- for (bit = 1 << (width-1); bit != 0; bit >>= 1) {
- if (decimal & bit)
- lf_putchr(file, '1');
- else
- lf_putchr(file, '0');
- }
-
-}
-
-
-static void
-lf_print_insn_bits(lf *file, insn_bits *bits)
-{
- if (bits == NULL)
- return;
- lf_print_insn_bits(file, bits->last);
- lf_putchr(file, '_');
- lf_putstr(file, bits->field->val_string);
- if (!bits->opcode->is_boolean || bits->value == 0) {
- if (bits->opcode->last < bits->field->last)
- lf_putint(file, bits->value << (bits->field->last - bits->opcode->last));
- else
- lf_putint(file, bits->value);
- }
-}
-
-static void
-lf_print_opcodes(lf *file,
- insn_table *table)
-{
- if (table != NULL) {
- while (1) {
- lf_printf(file, "_%d_%d",
- table->opcode->first,
- table->opcode->last);
- if (table->parent == NULL) break;
- lf_printf(file, "__%d", table->opcode_nr);
- table = table->parent;
- }
- }
-}
-
-static void
-lf_print_table_name(lf *file,
- insn_table *table)
-{
- lf_printf(file, "idecode_table");
- lf_print_opcodes(file, table);
-}
-
-
-
-typedef enum {
- function_name_prefix_semantics,
- function_name_prefix_idecode,
- function_name_prefix_none
-} lf_function_name_prefixes;
-
-static void
-lf_print_function_name(lf *file,
- char *basename,
- insn_bits *expanded_bits,
- lf_function_name_prefixes prefix)
-{
-
- /* the prefix */
- switch (prefix) {
- case function_name_prefix_semantics:
- lf_putstr(file, "semantic_");
- break;
- case function_name_prefix_idecode:
- lf_printf(file, "idecode_");
- break;
- default:
- break;
- }
-
- /* the function name */
- {
- char *pos;
- for (pos = basename;
- *pos != '\0';
- pos++) {
- switch (*pos) {
- case '/':
- case '-':
- break;
- case ' ':
- lf_putchr(file, '_');
- break;
- default:
- lf_putchr(file, *pos);
- break;
- }
- }
- }
-
- /* the suffix */
- if (idecode_expand_semantics)
- lf_print_insn_bits(file, expanded_bits);
-}
-
-
-static void
-lf_print_idecode_table(lf *file,
- insn_table *entry)
-{
- int can_assume_leaf;
- int rule;
-
- /* have a look at the rule table, if all table rules follow all
- switch rules, I can assume that all end points are leaves */
- rule = 0;
- while (opcode_table[rule].valid
- && opcode_table[rule].use_switch)
- rule++;
- while (opcode_table[rule].valid
- && !opcode_table[rule].use_switch
- && !opcode_table[rule].special_rule)
- rule++;
- can_assume_leaf = !opcode_table[rule].valid;
-
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- {
- lf_printf(file, "idecode_table_entry *table = ");
- lf_print_table_name(file, entry);
- lf_printf(file, ";\n");
- lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n",
- entry->opcode->first, entry->opcode->last);
- lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n");
- lf_printf(file, "while (1) {\n");
- lf_indent(file, +2);
- {
- lf_printf(file, "while (table_entry->mask != 0) {\n");
- lf_indent(file, +2);
- {
- lf_printf(file, "table = ((idecode_table_entry*)\n");
- lf_printf(file, " table_entry->function_or_table);\n");
- lf_printf(file, "opcode = ((instruction & table_entry->mask)\n");
- lf_printf(file, " >> table_entry->shift);\n");
- lf_printf(file, "table_entry = table + opcode;\n");
- }
- lf_indent(file, -2);
- lf_printf(file, "}\n");
- if (!idecode_cache && can_assume_leaf) {
- lf_printf(file, "return (((idecode_semantic*)\n");
- lf_printf(file, " table_entry->function_or_table)\n");
- lf_printf(file, " (%s));\n", insn_actual);
- }
- else if (!idecode_cache && !can_assume_leaf) {
- lf_printf(file, "if (table_entry->shift == 0)");
- lf_printf(file, " return (((idecode_semantic*)\n");
- lf_printf(file, " table_entry->function_or_table)\n");
- lf_printf(file, " (%s));\n", insn_actual);
- }
- else {
- lf_printf(file, "if (table_entry->shift == 0)\n");
- lf_printf(file, " return (((idecode_crack*)\n");
- lf_printf(file, " table_entry->function_or_table)\n");
- lf_printf(file, " (%s));\n", cache_idecode_actual);
- }
- if (!can_assume_leaf) {
- lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n");
- lf_printf(file, "table = ((idecode_table_entry*)\n");
- lf_printf(file, " table_entry->function_or_table);\n");
- lf_printf(file, "table_entry = table + opcode;\n");
- }
- }
- lf_indent(file, -2);
- lf_printf(file, "}\n");
- }
- lf_indent(file, -2);
- lf_printf(file, "}\n");
-}
-
-
-static void
-lf_print_my_prefix(lf *file,
- file_table_entry *file_entry)
-{
- lf_printf(file, "const char *const my_prefix = \n");
- lf_printf(file, " \"%s:%s:%d:cache\";\n",
- file_entry->file_name,
- file_entry->fields[insn_name],
- file_entry->line_nr);
-}
-
-
-static void
-lf_print_ptrace(lf *file)
-{
- lf_printf(file, "\n");
- lf_putstr(file, "ITRACE(trace_semantics, (\"cia=0x%x\\n\", cia));\n");
-}
-
-
-/****************************************************************/
-
-typedef void leaf_handler
-(insn_table *entry,
- void *data,
- int depth);
-typedef void padding_handler
-(insn_table *table,
- void *data,
- int depth,
- int opcode_nr);
-
-
-static void
-insn_table_traverse_tree(insn_table *table,
- void *data,
- int depth,
- leaf_handler *start,
- leaf_handler *leaf,
- leaf_handler *end,
- padding_handler *padding)
-{
- insn_table *entry;
- int entry_nr;
-
- ASSERT(table != NULL
- && table->opcode != NULL
- && table->nr_entries > 0
- && table->entries != 0);
-
- if (start != NULL && depth >= 0)
- start(table, data, depth);
-
- for (entry_nr = 0, entry = table->entries;
- entry_nr < (table->opcode->is_boolean
- ? 2
- : (1 << (table->opcode->last - table->opcode->first + 1)));
- entry_nr ++) {
- if (entry == NULL
- || (!table->opcode->is_boolean
- && entry_nr < entry->opcode_nr)) {
- if (padding != NULL && depth >= 0)
- padding(table, data, depth, entry_nr);
- }
- else {
- ASSERT(entry != NULL && (entry->opcode_nr == entry_nr
- || table->opcode->is_boolean));
- if (entry->opcode != NULL && depth != 0) {
- insn_table_traverse_tree(entry, data, depth+1,
- start, leaf, end, padding);
- }
- else if (depth >= 0) {
- if (leaf != NULL)
- leaf(entry, data, depth);
- }
- entry = entry->sibling;
- }
- }
- if (end != NULL && depth >= 0)
- end(table, data, depth);
-}
-
-
-typedef void function_handler
-(insn_table *table,
- void *data,
- file_table_entry *function);
-
-static void
-insn_table_traverse_function(insn_table *table,
- void *data,
- function_handler *leaf)
-{
- insn *function;
- for (function = table->functions;
- function != NULL;
- function = function->next) {
- leaf(table, data, function->file_entry);
- }
-}
-
-
-typedef void insn_handler
-(insn_table *table,
- void *data,
- insn *instruction);
-
-static void
-insn_table_traverse_insn(insn_table *table,
- void *data,
- insn_handler *leaf)
-{
- insn *instruction;
- for (instruction = table->insns;
- instruction != NULL;
- instruction = instruction->next) {
- leaf(table, data, instruction);
- }
-}
-
-
-static void
-update_depth(insn_table *entry,
- void *data,
- int depth)
-{
- int *max_depth = (int*)data;
- if (*max_depth < depth)
- *max_depth = depth;
-}
-
-
-static int
-insn_table_depth(insn_table *table)
-{
- int depth = 0;
- insn_table_traverse_tree(table,
- &depth,
- 1,
- NULL, /*start*/
- update_depth,
- NULL, /*end*/
- NULL); /*padding*/
- return depth;
-}
-
-
-/****************************************************************/
-
-static void
-dump_traverse_start(insn_table *table,
- void *data,
- int depth)
-{
- dumpf(depth*2, "(%d\n", table->opcode_nr);
-}
-
-static void
-dump_traverse_leaf(insn_table *entry,
- void *data,
- int depth)
-{
- ASSERT(entry->nr_entries == 0
- && entry->nr_insn == 1
- && entry->opcode == NULL);
- dumpf(depth*2, ".%d %s\n", entry->opcode_nr,
- entry->insns->file_entry->fields[insn_format]);
-}
-
-static void
-dump_traverse_end(insn_table *table,
- void *data,
- int depth)
-{
- dumpf(depth*2, ")\n");
-}
-
-static void
-dump_traverse_padding(insn_table *table,
- void *data,
- int depth,
- int opcode_nr)
-{
- dumpf(depth*2, ".<%d>\n", opcode_nr);
-}
-
-
-static void
-dump_traverse(insn_table *table)
-{
- insn_table_traverse_tree(table, NULL, 1,
- dump_traverse_start,
- dump_traverse_leaf,
- dump_traverse_end,
- dump_traverse_padding);
-}
-
-
-/****************************************************************/
-
-
-static void
-semantics_h_print_function(lf *file,
- char *basename,
- insn_bits *expanded_bits)
-{
- lf_printf(file, "\n");
- lf_printf(file, "INLINE_SEMANTICS unsigned_word ");
- lf_print_function_name(file,
- basename,
- expanded_bits,
- function_name_prefix_semantics);
- lf_printf(file, "\n(%s);\n",
- (idecode_cache ? cache_insn_formal : insn_formal));
-}
-
-
-static void
-semantics_h_leaf(insn_table *entry,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(entry->nr_insn == 1);
- semantics_h_print_function(file,
- entry->insns->file_entry->fields[insn_name],
- entry->expanded_bits);
-}
-
-static void
-semantics_h_insn(insn_table *entry,
- void *data,
- insn *instruction)
-{
- lf *file = (lf*)data;
- semantics_h_print_function(file,
- instruction->file_entry->fields[insn_name],
- NULL);
-}
-
-static void
-semantics_h_function(insn_table *entry,
- void *data,
- file_table_entry *function)
-{
- lf *file = (lf*)data;
- if (function->fields[function_type] == NULL
- || function->fields[function_type][0] == '\0') {
- semantics_h_print_function(file,
- function->fields[function_name],
- NULL);
- }
- else {
- lf_printf(file, "\n");
- lf_printf(file, "INLINE_SEMANTICS %s %s\n(%s);\n",
- function->fields[function_type],
- function->fields[function_name],
- function->fields[function_param]);
- }
-}
-
-
-static void
-gen_semantics_h(insn_table *table, lf *file)
-{
-
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _SEMANTICS_H_\n");
- lf_printf(file, "#define _SEMANTICS_H_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef INLINE_SEMANTICS\n");
- lf_printf(file, "#define INLINE_SEMANTICS\n");
- lf_printf(file, "#endif\n");
- lf_printf(file, "\n");
- lf_printf(file, "\n");
-
- /* output a declaration for all functions */
- insn_table_traverse_function(table,
- file,
- semantics_h_function);
-
- /* output a declaration for all instructions */
- if (idecode_expand_semantics)
- insn_table_traverse_tree(table,
- file,
- 1,
- NULL, /* start */
- semantics_h_leaf, /* leaf */
- NULL, /* end */
- NULL); /* padding */
- else
- insn_table_traverse_insn(table,
- file,
- semantics_h_insn);
-
- lf_printf(file, "\n");
- lf_printf(file, "#endif /* _SEMANTICS_H_ */\n");
-
-}
-
-/****************************************************************/
-
-typedef struct _icache_tree icache_tree;
-struct _icache_tree {
- char *name;
- icache_tree *next;
- icache_tree *children;
-};
-
-static icache_tree *
-icache_tree_new()
-{
- icache_tree *new_tree = (icache_tree*)zmalloc(sizeof(icache_tree));
- ASSERT(new_tree != NULL);
- return new_tree;
-}
-
-static icache_tree *
-icache_tree_insert(icache_tree *tree,
- char *name)
-{
- icache_tree *new_tree;
- /* find it */
- icache_tree **ptr_to_cur_tree = &tree->children;
- icache_tree *cur_tree = *ptr_to_cur_tree;
- while (cur_tree != NULL
- && strcmp(cur_tree->name, name) < 0) {
- ptr_to_cur_tree = &cur_tree->next;
- cur_tree = *ptr_to_cur_tree;
- }
- ASSERT(cur_tree == NULL
- || strcmp(cur_tree->name, name) >= 0);
- /* already in the tree */
- if (cur_tree != NULL
- && strcmp(cur_tree->name, name) == 0)
- return cur_tree;
- /* missing, insert it */
- ASSERT(cur_tree == NULL
- || strcmp(cur_tree->name, name) > 0);
- new_tree = icache_tree_new();
- new_tree->name = name;
- new_tree->next = cur_tree;
- *ptr_to_cur_tree = new_tree;
- return new_tree;
-}
-
-
-static icache_tree *
-insn_table_cache_fields(insn_table *table)
-{
- icache_tree *tree = icache_tree_new();
- insn *instruction;
- for (instruction = table->insns;
- instruction != NULL;
- instruction = instruction->next) {
- insn_field *field;
- icache_tree *form =
- icache_tree_insert(tree,
- instruction->file_entry->fields[insn_form]);
- for (field = instruction->fields->first;
- field != NULL;
- field = field->next) {
- if (field->is_string)
- icache_tree_insert(form, field->val_string);
- }
- }
- return tree;
-}
-
-
-
-static void
-gen_icache_h(icache_tree *tree,
- lf *file)
-{
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _ICACHE_H_\n");
- lf_printf(file, "#define _ICACHE_H_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef INLINE_ICACHE\n");
- lf_printf(file, "#define INLINE_ICACHE\n");
- lf_printf(file, "#endif\n");
- lf_printf(file, "\n");
- lf_printf(file, "\n");
-
- /* create an instruction cache if being used */
- if (idecode_cache) {
- icache_tree *form;
- lf_printf(file, "typedef struct _idecode_cache {\n");
- lf_printf(file, " unsigned_word address;\n");
- lf_printf(file, " void *semantic;\n");
- lf_printf(file, " union {\n");
- for (form = tree->children;
- form != NULL;
- form = form->next) {
- icache_tree *field;
- lf_printf(file, " struct {\n");
- for (field = form->children;
- field != NULL;
- field = field->next) {
- extraction_rules *rule;
- int found_rule = 0;
- for (rule = cachable_values;
- rule->valid;
- rule++) {
- if (strcmp(field->name, rule->old_name) == 0) {
- found_rule = 1;
- if (rule->new_name != NULL)
- lf_printf(file, " %s %s; /* %s */\n",
- rule->type == NULL ? "unsigned" : rule->type,
- rule->new_name, rule->old_name);
- }
- }
- if (!found_rule)
- lf_printf(file, " unsigned %s;\n", field->name);
- }
- lf_printf(file, " } %s;\n", form->name);
- }
- lf_printf(file, " } crack;\n");
- lf_printf(file, "} idecode_cache;\n");
- }
- else {
- /* alernativly, since no cache, #define the fields to be
- extractions from the instruction variable */
- extraction_rules *rule;
- lf_printf(file, "\n");
- for (rule = cachable_values;
- rule->valid;
- rule++) {
- if (rule->expression != NULL)
- lf_printf(file, "#define %s %s\n",
- rule->new_name, rule->expression);
- }
- }
-
- lf_printf(file, "\n");
- lf_printf(file, "#endif /* _ICACHE_H_ */\n");
-}
-
-
-
-
-/****************************************************************/
-
-
-static void
-lf_print_c_extraction(lf *file,
- insn *instruction,
- char *field_name,
- char *field_type,
- char *field_expression,
- insn_field *cur_field,
- insn_bits *bits,
- int get_value_from_cache,
- int put_value_in_cache)
-{
- ASSERT(field_name != NULL);
- if (bits != NULL
- && (!bits->opcode->is_boolean || bits->value == 0)
- && strcmp(field_name, cur_field->val_string) == 0) {
- ASSERT(bits->field == cur_field);
- ASSERT(field_type == NULL);
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_printf(file, "const unsigned %s = ",
- field_name);
- if (bits->opcode->last < bits->field->last)
- lf_printf(file, "%d;\n",
- bits->value << (bits->field->last - bits->opcode->last));
- else
- lf_printf(file, "%d;\n", bits->value);
- }
- else {
- /* put the field in the local variable */
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_printf(file, "%s const %s = ",
- field_type == NULL ? "unsigned" : field_type,
- field_name);
- /* getting it from the cache */
- if (get_value_from_cache || put_value_in_cache) {
- lf_printf(file, "cache_entry->crack.%s.%s",
- instruction->file_entry->fields[insn_form],
- field_name);
- if (put_value_in_cache) /* also put it in the cache? */
- lf_printf(file, " = ");
- }
- if (!get_value_from_cache) {
- if (strcmp(field_name, cur_field->val_string) == 0)
- lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
- cur_field->first, cur_field->last);
- else if (field_expression != NULL)
- lf_printf(file, "%s", field_expression);
- else
- lf_printf(file, "eval_%s", field_name);
- }
- lf_printf(file, ";\n");
- }
-}
-
-
-static void
-lf_print_c_extractions(lf *file,
- insn *instruction,
- insn_bits *expanded_bits,
- int get_value_from_cache,
- int put_value_in_cache)
-{
- insn_field *cur_field;
-
- /* extract instruction fields */
- lf_printf(file, "/* extraction: %s */\n",
- instruction->file_entry->fields[insn_format]);
-
- for (cur_field = instruction->fields->first;
- cur_field->first < insn_size;
- cur_field = cur_field->next) {
- if (cur_field->is_string) {
- insn_bits *bits;
- int found_rule = 0;
- /* find any corresponding value */
- for (bits = expanded_bits;
- bits != NULL;
- bits = bits->last) {
- if (bits->field == cur_field)
- break;
- }
- /* try the cache rule table for what to do */
- if (get_value_from_cache || put_value_in_cache) {
- extraction_rules *field_rule;
- for (field_rule = cachable_values;
- field_rule->valid;
- field_rule++) {
- if (strcmp(cur_field->val_string, field_rule->old_name) == 0) {
- found_rule = 1;
- if (field_rule->valid > 1 && put_value_in_cache)
- lf_print_c_extraction(file,
- instruction,
- field_rule->new_name,
- field_rule->type,
- field_rule->expression,
- cur_field,
- bits,
- 0,
- 0);
- else if (field_rule->valid == 1)
- lf_print_c_extraction(file,
- instruction,
- field_rule->new_name,
- field_rule->type,
- field_rule->expression,
- cur_field,
- bits,
- get_value_from_cache,
- put_value_in_cache);
- }
- }
- }
- if (found_rule == 0)
- lf_print_c_extraction(file,
- instruction,
- cur_field->val_string,
- 0,
- 0,
- cur_field,
- bits,
- get_value_from_cache,
- put_value_in_cache);
- /* if any (XXX == 0), output a corresponding test */
- if (instruction->file_entry->annex != NULL) {
- char *field_name = cur_field->val_string;
- char *is_0_ptr = instruction->file_entry->annex;
- int field_len = strlen(field_name);
- if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) {
- is_0_ptr += field_len;
- while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) {
- if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0
- && !isalpha(is_0_ptr[ - field_len - 1])) {
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_printf(file, "const unsigned %s_is_0 = (", field_name);
- if (bits != NULL)
- lf_printf(file, "%d", bits->value);
- else
- lf_printf(file, "%s", field_name);
- lf_printf(file, " == 0);\n");
- break;
- }
- is_0_ptr += strlen("_is_0");
- }
- }
- }
- /* any thing else ... */
- }
- }
- lf_print_file_line_nr(file);
-}
-
-
-static void
-lf_print_idecode_illegal(lf *file)
-{
- if (idecode_cache)
- lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual);
- else
- lf_printf(file, "return semantic_illegal(%s);\n", insn_actual);
-}
-
-
-static void
-lf_print_idecode_floating_point_unavailable(lf *file)
-{
- if (idecode_cache)
- lf_printf(file, "return idecode_floating_point_unavailable(%s);\n",
- cache_idecode_actual);
- else
- lf_printf(file, "return semantic_floating_point_unavailable(%s);\n",
- insn_actual);
-}
-
-
-/* Output code to do any final checks on the decoded instruction.
- This includes things like verifying any on decoded fields have the
- correct value and checking that (for floating point) floating point
- hardware isn't disabled */
-
-static void
-lf_print_c_validate(lf *file,
- insn *instruction,
- opcode_field *opcodes)
-{
- /* Validate: unchecked instruction fields
-
- If any constant fields in the instruction were not checked by the
- idecode tables, output code to check that they have the correct
- value here */
- {
- unsigned check_mask = 0;
- unsigned check_val = 0;
- insn_field *field;
- opcode_field *opcode;
-
- /* form check_mask/check_val containing what needs to be checked
- in the instruction */
- for (field = instruction->fields->first;
- field->first < insn_size;
- field = field->next) {
-
- check_mask <<= field->width;
- check_val <<= field->width;
-
- /* is it a constant that could need validating? */
- if (!field->is_int && !field->is_slash)
- continue;
-
- /* has it been checked by a table? */
- for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) {
- if (field->first >= opcode->first
- && field->last <= opcode->last)
- break;
- }
- if (opcode != NULL)
- continue;
-
- check_mask |= (1 << field->width)-1;
- check_val |= field->val_int;
- }
-
- /* if any bits not checked by opcode tables, output code to check them */
- if (check_mask) {
- lf_printf(file, "\n");
- lf_printf(file, "/* validate: %s */\n",
- instruction->file_entry->fields[insn_format]);
- lf_printf(file, "if ((instruction & 0x%x) != 0x%x)\n",
- check_mask, check_val);
- lf_indent(file, +2);
- lf_print_idecode_illegal(file);
- lf_indent(file, -2);
- }
- }
-
- /* Validate floating point hardware
-
- If the simulator is being built with out floating point hardware
- (different to it being disabled in the MSR) then floating point
- instructions are invalid */
- {
- if (it_is("f", instruction->file_entry->fields[insn_flags])) {
- lf_printf(file, "\n");
- lf_printf(file, "/* Validate: FP hardware exists */\n");
- lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n");
- lf_indent(file, +2);
- lf_print_idecode_illegal(file);
- lf_indent(file, -2);
- }
- }
-
- /* Validate: Floating Point available
-
- If floating point is not available, we enter a floating point
- unavailable interrupt into the cache instead of the instruction
- proper.
-
- The PowerPC spec requires a CSI after MSR[FP] is changed and when
- ever a CSI occures we flush the instruction cache. */
-
- {
- if (it_is("f", instruction->file_entry->fields[insn_flags])) {
- lf_printf(file, "\n");
- lf_printf(file, "/* Validate: FP available according to MSR[FP] */\n");
- lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
- lf_indent(file, +2);
- lf_print_idecode_floating_point_unavailable(file);
- lf_indent(file, -2);
- }
- }
-}
-
-
-static void
-lf_print_c_cracker(lf *file,
- insn *instruction,
- insn_bits *expanded_bits,
- opcode_field *opcodes)
-{
-
- /* function header */
- lf_printf(file, "{\n");
- lf_indent(file, +2);
-
- lf_print_my_prefix(file,
- instruction->file_entry);
-
- lf_print_ptrace(file);
-
- lf_print_c_validate(file, instruction, opcodes);
-
- lf_printf(file, "\n");
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- lf_print_c_extractions(file,
- instruction,
- expanded_bits,
- 0/*get_value_from_cache*/,
- 1/*put_value_in_cache*/);
- lf_indent(file, -2);
- lf_printf(file, "}\n");
-
- /* return the function propper (main sorts this one out) */
- lf_printf(file, "\n");
- lf_printf(file, "/* semantic routine */\n");
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_printf(file, "return ");
- lf_print_function_name(file,
- instruction->file_entry->fields[insn_name],
- expanded_bits,
- function_name_prefix_semantics);
- lf_printf(file, ";\n");
-
- lf_print_file_line_nr(file);
- lf_indent(file, -2);
- lf_printf(file, "}\n");
-}
-
-
-static void
-lf_print_c_semantic(lf *file,
- insn *instruction,
- insn_bits *expanded_bits,
- opcode_field *opcodes)
-{
-
- lf_printf(file, "{\n");
- lf_indent(file, +2);
-
- lf_print_my_prefix(file,
- instruction->file_entry);
- lf_putstr(file, insn_local);
- lf_printf(file, "\n");
-
- lf_printf(file, "\n");
- lf_print_c_extractions(file,
- instruction,
- expanded_bits,
- idecode_cache/*get_value_from_cache*/,
- 0/*put_value_in_cache*/);
-
- lf_print_ptrace(file);
-
- /* validate the instruction, if a cache this has already been done */
- if (!idecode_cache)
- lf_print_c_validate(file, instruction, opcodes);
-
- /* generate the code (or at least something */
- if (instruction->file_entry->annex != NULL) {
- /* true code */
- lf_printf(file, "\n");
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- lf_print_c_code(file, instruction->file_entry->annex);
- lf_indent(file, -2);
- lf_printf(file, "}\n");
- lf_print_file_line_nr(file);
- }
- else if (it_is("nop", instruction->file_entry->fields[insn_flags])) {
- lf_print_file_line_nr(file);
- }
- else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
- /* unimplemented floating point instruction - call for assistance */
- lf_printf(file, "\n");
- lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n");
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
- lf_print_file_line_nr(file);
- }
- else {
- /* abort so it is implemented now */
- lf_print_c_line_nr(file, instruction->file_entry);
- lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n");
- lf_print_file_line_nr(file);
- lf_printf(file, "\n");
- }
-
- /* the function footer */
- lf_printf(file, "return nia;\n");
- lf_indent(file, -2);
- lf_printf(file, "}\n");
-}
-
-static void
-lf_print_c_semantic_function_header(lf *file,
- char *basename,
- insn_bits *expanded_bits)
-{
- lf_printf(file, "\n");
- lf_printf(file, "INLINE_SEMANTICS unsigned_word\n");
- lf_print_function_name(file,
- basename,
- expanded_bits,
- function_name_prefix_semantics);
- lf_printf(file, "\n(%s)\n",
- (idecode_cache ? cache_insn_formal : insn_formal));
-}
-
-static void
-lf_print_c_semantic_function(lf *file,
- insn *instruction,
- insn_bits *expanded_bits,
- opcode_field *opcodes)
-{
-
- /* build the semantic routine to execute the instruction */
- lf_print_c_semantic_function_header(file,
- instruction->file_entry->fields[insn_name],
- expanded_bits);
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- lf_printf(file, "cpu_increment_number_of_insns (processor);\n");
-
- lf_print_c_semantic(file,
- instruction,
- expanded_bits,
- opcodes);
-
- lf_indent(file, -2);
- lf_printf(file, "}\n");
-}
-
-
-static void
-semantics_c_leaf(insn_table *entry,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(entry->nr_insn == 1
- && entry->opcode == NULL
- && entry->parent != NULL
- && entry->parent->opcode != NULL);
- lf_print_c_semantic_function(file,
- entry->insns,
- entry->expanded_bits,
- entry->parent->opcode);
-}
-
-static void
-semantics_c_insn(insn_table *table,
- void *data,
- insn *instruction)
-{
- lf *file = (lf*)data;
- lf_print_c_semantic_function(file, instruction,
- NULL, NULL);
-}
-
-static void
-semantics_c_function(insn_table *table,
- void *data,
- file_table_entry *function)
-{
- lf *file = (lf*)data;
- if (function->fields[function_type] == NULL
- || function->fields[function_type][0] == '\0') {
- lf_print_c_semantic_function_header(file,
- function->fields[function_name],
- NULL);
- }
- else {
- lf_printf(file, "\n");
- lf_printf(file, "INLINE_SEMANTICS %s\n%s(%s)\n",
- function->fields[function_type],
- function->fields[function_name],
- function->fields[function_param]);
- }
- lf_print_c_line_nr(file, function);
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- lf_print_c_code(file, function->annex);
- lf_indent(file, -2);
- lf_printf(file, "}\n");
- lf_print_file_line_nr(file);
-}
-
-
-
-static void
-gen_semantics_c(insn_table *table, lf *file)
-{
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _SEMANTICS_C_\n");
- lf_printf(file, "#define _SEMANTICS_C_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef STATIC_INLINE_SEMANTICS\n");
- lf_printf(file, "#define STATIC_INLINE_SEMANTICS STATIC_INLINE\n");
- lf_printf(file, "#endif\n");
- lf_printf(file, "\n");
- lf_printf(file, "#include \"cpu.h\"\n");
- lf_printf(file, "#include \"idecode.h\"\n");
- lf_printf(file, "#include \"semantics.h\"\n");
- lf_printf(file, "\n");
-
- /* output a definition (c-code) for all functions */
- insn_table_traverse_function(table,
- file,
- semantics_c_function);
-
- /* output a definition (c-code) for all instructions */
- if (idecode_expand_semantics)
- insn_table_traverse_tree(table,
- file,
- 1,
- NULL, /* start */
- semantics_c_leaf,
- NULL, /* end */
- NULL); /* padding */
- else
- insn_table_traverse_insn(table,
- file,
- semantics_c_insn);
-
- lf_printf(file, "\n");
- lf_printf(file, "#endif /* _SEMANTICS_C_ */\n");
-}
-
-
-/****************************************************************/
-
-static void
-gen_idecode_h(insn_table *table, lf *file)
-{
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _IDECODE_H_\n");
- lf_printf(file, "#define _IDECODE_H_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef INLINE_IDECODE\n");
- lf_printf(file, "#define INLINE_IDECODE\n");
- lf_printf(file, "#endif\n");
- lf_printf(file, "\n");
- lf_printf(file, "#include \"idecode_expression.h\"\n");
- lf_printf(file, "#include \"idecode_fields.h\"\n");
- lf_printf(file, "#include \"idecode_branch.h\"\n");
- lf_printf(file, "\n");
- lf_printf(file, "#include \"icache.h\"\n");
- lf_printf(file, "\n");
- lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n",
- (idecode_cache ? cache_insn_formal : insn_formal));
- lf_printf(file, "\n");
- if (idecode_cache)
- lf_printf(file, "INLINE_IDECODE idecode_semantic *idecode\n(%s);\n",
- cache_idecode_formal);
- else
- lf_printf(file, "INLINE_IDECODE unsigned_word idecode_issue\n(%s);\n",
- insn_formal);
- lf_printf(file, "\n");
- lf_printf(file, "#endif /* _IDECODE_H_ */\n");
-}
-
-
-/****************************************************************/
-
-
-static void
-idecode_table_start(insn_table *table,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(depth == 0);
- /* start of the table */
- if (!table->opcode_rule->use_switch) {
- lf_printf(file, "\n");
- lf_printf(file, "static idecode_table_entry ");
- lf_print_table_name(file, table);
- lf_printf(file, "[] = {\n");
- }
-}
-
-static void
-idecode_table_leaf(insn_table *entry,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(entry->parent != NULL);
- ASSERT(depth == 0);
-
- /* add an entry to the table */
- if (!entry->parent->opcode_rule->use_switch) {
- if (entry->opcode == NULL) {
- /* table leaf entry */
- lf_printf(file, " /*%d*/ { 0, 0, ", entry->opcode_nr);
- lf_print_function_name(file,
- entry->insns->file_entry->fields[insn_name],
- entry->expanded_bits,
- (idecode_cache
- ? function_name_prefix_idecode
- : function_name_prefix_semantics));
- lf_printf(file, " },\n");
- }
- else if (entry->opcode_rule->use_switch) {
- /* table calling switch statement */
- lf_printf(file, " /*%d*/ { -1, 0, ",
- entry->opcode_nr);
- lf_print_table_name(file, entry);
- lf_printf(file, " },\n");
- }
- else {
- /* table `calling' another table */
- lf_printf(file, " /*%d*/ { ", entry->opcode_nr);
- if (entry->opcode->is_boolean)
- lf_printf(file, "MASK32(%d,%d), 0, ",
- entry->opcode->first, entry->opcode->last);
- else
- lf_printf(file, "%d, MASK32(%d,%d), ",
- insn_size - entry->opcode->last - 1,
- entry->opcode->first, entry->opcode->last);
- lf_print_table_name(file, entry);
- lf_printf(file, " },\n");
- }
- }
-}
-
-static void
-idecode_table_end(insn_table *table,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(depth == 0);
-
- if (!table->opcode_rule->use_switch) {
- lf_printf(file, "};\n");
- }
-}
-
-static void
-idecode_table_padding(insn_table *table,
- void *data,
- int depth,
- int opcode_nr)
-{
- lf *file = (lf*)data;
- ASSERT(depth == 0);
-
- if (!table->opcode_rule->use_switch) {
- lf_printf(file, " /*%d*/ { 0, 0, %s_illegal },\n",
- opcode_nr, (idecode_cache ? "idecode" : "semantic"));
- }
-}
-
-
-/****************************************************************/
-
-
-void lf_print_idecode_switch
-(lf *file,
- insn_table *table);
-
-
-static void
-idecode_switch_start(insn_table *table,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(depth == 0);
- ASSERT(table->opcode_rule->use_switch);
-
- lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n",
- table->opcode->first, table->opcode->last);
-}
-
-
-static void
-idecode_switch_leaf(insn_table *entry,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(entry->parent != NULL);
- ASSERT(depth == 0);
- ASSERT(entry->parent->opcode_rule->use_switch);
-
- lf_printf(file, "case %d:\n", entry->opcode_nr);
- lf_indent(file, +2);
- {
- if (entry->opcode == NULL) {
- /* switch calling leaf */
- lf_printf(file, "return ");
- lf_print_function_name(file,
- entry->insns->file_entry->fields[insn_name],
- entry->expanded_bits,
- (idecode_cache
- ? function_name_prefix_idecode
- : function_name_prefix_semantics));
- if (idecode_cache)
- lf_printf(file, "(%s);\n", cache_idecode_actual);
- else
- lf_printf(file, "(%s);\n", insn_actual);
- }
- else if (entry->opcode_rule->use_switch) {
- /* switch calling switch */
- lf_print_idecode_switch(file, entry);
- }
- else {
- /* switch calling table */
- lf_printf(file, "return ");
- lf_print_idecode_table(file, entry);
- }
- lf_printf(file, "break;\n");
- }
- lf_indent(file, -2);
-}
-
-
-static void
-lf_print_idecode_switch_illegal(lf *file)
-{
- lf_indent(file, +2);
- lf_print_idecode_illegal(file);
- lf_printf(file, "break;\n");
- lf_indent(file, -2);
-}
-
-static void
-idecode_switch_end(insn_table *table,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(depth == 0);
- ASSERT(table->opcode_rule->use_switch);
-
- if (table->opcode_rule->use_switch == 1) {
- lf_printf(file, "default:\n");
- lf_print_idecode_switch_illegal(file);
- }
- lf_printf(file, "}\n");
-}
-
-static void
-idecode_switch_padding(insn_table *table,
- void *data,
- int depth,
- int opcode_nr)
-{
- lf *file = (lf*)data;
-
- ASSERT(depth == 0);
- ASSERT(table->opcode_rule->use_switch);
-
- if (table->opcode_rule->use_switch > 1) {
- lf_printf(file, "case %d:\n", opcode_nr);
- lf_print_idecode_switch_illegal(file);
- }
-}
-
-
-void
-lf_print_idecode_switch(lf *file,
- insn_table *table)
-{
- insn_table_traverse_tree(table,
- file,
- 0,
- idecode_switch_start,
- idecode_switch_leaf,
- idecode_switch_end,
- idecode_switch_padding);
-}
-
-
-static void
-idecode_expand_if_switch(insn_table *table,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
-
- if (table->opcode_rule->use_switch
- && table->parent != NULL /* don't expand the top one yet */
- && !table->parent->opcode_rule->use_switch) {
- lf_printf(file, "\n");
- lf_printf(file, "STATIC_INLINE_IDECODE void\n");
- lf_print_table_name(file, table);
- lf_printf(file, "\n(%s)\n",
- (idecode_cache ? cache_idecode_formal : insn_formal));
- lf_printf(file, "{\n");
- {
- lf_indent(file, +2);
- lf_print_idecode_switch(file, table);
- lf_indent(file, -2);
- }
- lf_printf(file, "}\n");
- }
-}
-
-
-static void
-lf_print_c_cracker_function(lf *file,
- insn *instruction,
- insn_bits *expanded_bits,
- opcode_field *opcodes)
-{
- /* if needed, generate code to enter this routine into a cache */
- lf_printf(file, "\n");
- lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
- lf_print_function_name(file,
- instruction->file_entry->fields[insn_name],
- expanded_bits,
- function_name_prefix_idecode);
- lf_printf(file, "\n(%s)\n", cache_idecode_formal);
-
- lf_print_c_cracker(file,
- instruction,
- expanded_bits,
- opcodes);
-}
-
-static void
-idecode_crack_leaf(insn_table *entry,
- void *data,
- int depth)
-{
- lf *file = (lf*)data;
- ASSERT(entry->nr_insn == 1
- && entry->opcode == NULL
- && entry->parent != NULL
- && entry->parent->opcode != NULL);
- lf_print_c_cracker_function(file,
- entry->insns,
- entry->expanded_bits,
- entry->opcode);
-}
-
-static void
-idecode_crack_insn(insn_table *entry,
- void *data,
- insn *instruction)
-{
- lf *file = (lf*)data;
- lf_print_c_cracker_function(file,
- instruction,
- NULL,
- NULL);
-}
-
-static void
-idecode_c_internal_function(insn_table *table,
- void *data,
- file_table_entry *function)
-{
- lf *file = (lf*)data;
- ASSERT(idecode_cache != 0);
- if (it_is("internal", function->fields[insn_flags])) {
- lf_printf(file, "\n");
- lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
- lf_print_function_name(file,
- function->fields[insn_name],
- NULL,
- function_name_prefix_idecode);
- lf_printf(file, "\n(%s)\n", cache_idecode_formal);
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- lf_printf(file, "/* semantic routine */\n");
- lf_print_c_line_nr(file, function);
- lf_printf(file, "return ");
- lf_print_function_name(file,
- function->fields[insn_name],
- NULL,
- function_name_prefix_semantics);
- lf_printf(file, ";\n");
-
- lf_print_file_line_nr(file);
- lf_indent(file, -2);
- lf_printf(file, "}\n");
- }
-}
-
-
-/****************************************************************/
-
-static void
-gen_idecode_c(insn_table *table, lf *file)
-{
- int depth;
-
- /* the intro */
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _IDECODE_C_\n");
- lf_printf(file, "#define _IDECODE_C_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef STATIC_INLINE_IDECODE\n");
- lf_printf(file, "#define STATIC_INLINE_IDECODE STATIC_INLINE\n");
- lf_printf(file, "#endif\n");
- lf_printf(file, "\n");
- lf_printf(file, "#include \"cpu.h\"\n");
- lf_printf(file, "#include \"idecode.h\"\n");
- lf_printf(file, "#include \"semantics.h\"\n");
- lf_printf(file, "\n");
- lf_printf(file, "\n");
- lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n",
- (idecode_cache ? cache_idecode_formal : insn_formal));
- lf_printf(file, "\n");
- lf_printf(file, "typedef struct _idecode_table_entry {\n");
- lf_printf(file, " unsigned shift;\n");
- lf_printf(file, " unsigned mask;\n");
- lf_printf(file, " void *function_or_table;\n");
- lf_printf(file, "} idecode_table_entry;\n");
- lf_printf(file, "\n");
- lf_printf(file, "\n");
-
- /* output `internal' invalid/floating-point unavailable functions
- where needed */
- if (idecode_cache) {
- insn_table_traverse_function(table,
- file,
- idecode_c_internal_function);
- }
-
- /* output cracking functions where needed */
- if (idecode_cache) {
- if (idecode_expand_semantics)
- insn_table_traverse_tree(table,
- file,
- 1,
- NULL,
- idecode_crack_leaf,
- NULL,
- NULL);
- else
- insn_table_traverse_insn(table,
- file,
- idecode_crack_insn);
- }
-
-
- /* output tables where needed */
- for (depth = insn_table_depth(table);
- depth > 0;
- depth--) {
- insn_table_traverse_tree(table,
- file,
- 1-depth,
- idecode_table_start,
- idecode_table_leaf,
- idecode_table_end,
- idecode_table_padding);
- }
-
- /* output switch functions where needed */
- insn_table_traverse_tree(table,
- file,
- 1,
- idecode_expand_if_switch, /* START */
- NULL, NULL, NULL);
-
- /* output the main idecode routine */
- lf_printf(file, "\n");
- if (idecode_cache)
- lf_printf(file, "INLINE_IDECODE idecode_semantic *\nidecode\n(%s)\n",
- cache_idecode_formal);
- else
- lf_printf(file, "INLINE_IDECODE unsigned_word\nidecode_issue\n(%s)\n",
- insn_formal);
- lf_printf(file, "{\n");
- lf_indent(file, +2);
- if (table->opcode_rule->use_switch)
- lf_print_idecode_switch(file, table);
- else
- lf_print_idecode_table(file, table);
- lf_indent(file, -2);
- lf_printf(file, "}\n");
- lf_printf(file, "\n");
- lf_printf(file, "#endif\n");
-}
-
-
-/****************************************************************/
-
-
-typedef enum {
- spreg_name,
- spreg_reg_nr,
- spreg_readonly,
- spreg_length,
- nr_spreg_registers = file_table_max_fields
-} spreg_fields;
-
-typedef struct _spreg_table_entry spreg_table_entry;
-struct _spreg_table_entry {
- char *name;
- int spreg_nr;
- int is_readonly;
- int length;
- file_table_entry *entry;
- spreg_table_entry *next;
-};
-
-typedef struct _spreg_table spreg_table;
-struct _spreg_table {
- spreg_table_entry *sprs;
-};
-
-static spreg_table_entry *
-spreg_table_entry_new()
-{
- spreg_table_entry *new_entry =
- (spreg_table_entry*)zmalloc(sizeof(spreg_table_entry));
- ASSERT(new_entry != NULL);
- return new_entry;
-}
-
-static spreg_table *
-spreg_table_new()
-{
- spreg_table *new_table = (spreg_table*)zmalloc(sizeof(spreg_table));
- ASSERT(new_table != NULL);
- return new_table;
-}
-
-static void
-spreg_table_insert(spreg_table *table, file_table_entry *entry)
-{
- /* create a new spr entry */
- spreg_table_entry *new_spr = spreg_table_entry_new();
- new_spr->next = NULL;
- new_spr->entry = entry;
- new_spr->spreg_nr = atoi(entry->fields[spreg_reg_nr]);
- new_spr->is_readonly = (entry->fields[spreg_readonly]
- ? atoi(entry->fields[spreg_readonly])
- : 0);
- new_spr->length = atoi(entry->fields[spreg_length]);
- new_spr->name = (char*)zmalloc(strlen(entry->fields[spreg_name]) + 1);
- ASSERT(new_spr->name != NULL);
- {
- int i;
- for (i = 0; entry->fields[spreg_name][i] != '\0'; i++) {
- if (isupper(entry->fields[spreg_name][i]))
- new_spr->name[i] = tolower(entry->fields[spreg_name][i]);
- else
- new_spr->name[i] = entry->fields[spreg_name][i];
- }
- }
-
- /* insert, by spreg_nr order */
- {
- spreg_table_entry **ptr_to_spreg_entry = &table->sprs;
- spreg_table_entry *spreg_entry = *ptr_to_spreg_entry;
- while (spreg_entry != NULL && spreg_entry->spreg_nr < new_spr->spreg_nr) {
- ptr_to_spreg_entry = &spreg_entry->next;
- spreg_entry = *ptr_to_spreg_entry;
- }
- ASSERT(spreg_entry == NULL || spreg_entry->spreg_nr != new_spr->spreg_nr);
- *ptr_to_spreg_entry = new_spr;
- new_spr->next = spreg_entry;
- }
-
-}
-
-
-static spreg_table *
-spreg_table_load(char *file_name)
-{
- file_table *file = file_table_open(file_name);
- spreg_table *table = spreg_table_new();
-
- {
- file_table_entry *entry;
- while ((entry = file_table_read(file)) != NULL) {
- spreg_table_insert(table, entry);
- }
- }
-
- return table;
-}
-
-
-/****************************************************************/
-
-char *spreg_attributes[] = {
- "is_valid",
- "is_readonly",
- "name",
- "index",
- "length",
- 0
-};
-
-static void
-gen_spreg_h(spreg_table *table, lf *file)
-{
- spreg_table_entry *entry;
- char **attribute;
-
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _SPREG_H_\n");
- lf_printf(file, "#define _SPREG_H_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef INLINE_SPREG\n");
- lf_printf(file, "#define INLINE_SPREG\n");
- lf_printf(file, "#endif\n");
- lf_printf(file, "\n");
- lf_printf(file, "typedef unsigned_word spreg;\n");
- lf_printf(file, "\n");
- lf_printf(file, "typedef enum {\n");
-
- for (entry = table->sprs;
- entry != NULL ;
- entry = entry->next) {
- lf_printf(file, " spr_%s = %d,\n", entry->name, entry->spreg_nr);
- }
-
- lf_printf(file, " nr_of_sprs = %d\n", nr_of_sprs);
- lf_printf(file, "} sprs;\n");
- lf_printf(file, "\n");
- for (attribute = spreg_attributes;
- *attribute != NULL;
- attribute++) {
- if (strcmp(*attribute, "name") == 0)
- lf_printf(file, "INLINE_SPREG char *spr_%s(sprs spr);\n",
- *attribute);
- else
- lf_printf(file, "INLINE_SPREG int spr_%s(sprs spr);\n",
- *attribute);
- }
- lf_printf(file, "\n");
- lf_printf(file, "#endif /* _SPREG_H_ */\n");
-}
-
-
-static void
-gen_spreg_c(spreg_table *table, lf *file)
-{
- spreg_table_entry *entry;
- char **attribute;
- int spreg_nr;
-
- lf_print_copyleft(file);
- lf_printf(file, "\n");
- lf_printf(file, "#ifndef _SPREG_C_\n");
- lf_printf(file, "#define _SPREG_C_\n");
- lf_printf(file, "\n");
- lf_printf(file, "#include \"words.h\"\n");
- lf_printf(file, "#include \"spreg.h\"\n");
-
- lf_printf(file, "\n");
- lf_printf(file, "typedef struct _spreg_info {\n");
- lf_printf(file, " char *name;\n");
- lf_printf(file, " int is_valid;\n");
- lf_printf(file, " int length;\n");
- lf_printf(file, " int is_readonly;\n");
- lf_printf(file, " int index;\n");
- lf_printf(file, "} spreg_info;\n");
- lf_printf(file, "\n");
- lf_printf(file, "static spreg_info spr_info[nr_of_sprs+1] = {\n");
- entry = table->sprs;
- for (spreg_nr = 0; spreg_nr < nr_of_sprs+1; spreg_nr++) {
- if (entry == NULL || spreg_nr < entry->spreg_nr)
- lf_printf(file, " { 0, 0, 0, 0, %d},\n", spreg_nr);
- else {
- lf_printf(file, " { \"%s\", %d, %d, %d, spr_%s /*%d*/ },\n",
- entry->name, 1, entry->length, entry->is_readonly,
- entry->name, entry->spreg_nr);
- entry = entry->next;
- }
- }
- lf_printf(file, "};\n");
-
- for (attribute = spreg_attributes;
- *attribute != NULL;
- attribute++) {
- lf_printf(file, "\n");
- if (strcmp(*attribute, "name") == 0)
- lf_printf(file, "INLINE_SPREG char *\n");
- else
- lf_printf(file, "INLINE_SPREG int\n");
- lf_printf(file, "spr_%s(sprs spr)\n", *attribute);
- lf_printf(file, "{\n");
- if (spreg_lookup_table
- || strcmp(*attribute, "name") == 0
- || strcmp(*attribute, "index") == 0)
- lf_printf(file, " return spr_info[spr].%s;\n",
- *attribute);
- else {
- spreg_table_entry *entry;
- lf_printf(file, " switch (spr) {\n");
- for (entry = table->sprs; entry != NULL; entry = entry->next) {
- lf_printf(file, " case %d:\n", entry->spreg_nr);
- if (strcmp(*attribute, "is_valid") == 0)
- lf_printf(file, " return 1;\n");
- else if (strcmp(*attribute, "is_readonly") == 0)
- lf_printf(file, " return %d;\n", entry->is_readonly);
- else if (strcmp(*attribute, "length") == 0)
- lf_printf(file, " return %d;\n", entry->length);
- else
- ASSERT(0);
- }
- lf_printf(file, " default:\n");
- lf_printf(file, " return 0;\n");
- lf_printf(file, " }\n");
- }
- lf_printf(file, "}\n");
- }
-
- lf_printf(file, "\n");
- lf_printf(file, "#endif /* _SPREG_C_ */\n");
-}
-
-
-
-/****************************************************************/
-
-
-int
-main(int argc,
- char **argv,
- char **envp)
-{
- insn_table *instructions = NULL;
- spreg_table *sprs = NULL;
- icache_tree *cache_fields = NULL;
- char *real_file_name = NULL;
- int ch;
-
- while ((ch = getopt(argc, argv, "n:i:I:r:S:s:D:d:P:p:C:")) != -1) {
- fprintf(stderr, "\t-%c %s\n", ch, optarg);
- switch(ch) {
- case 'I':
- case 'i':
- instructions = insn_table_load_insns(optarg);
- fprintf(stderr, "\texpanding ...\n");
- insn_table_expand_insns(instructions);
- fprintf(stderr, "\tcache fields ...\n");
- cache_fields = insn_table_cache_fields(instructions);
- if (ch == 'I') {
- dump_traverse(instructions);
- dump_insn_table(instructions, 0, 1);
- }
- break;
- case 'r':
- sprs = spreg_table_load(optarg);
- break;
- case 'n':
- real_file_name = strdup(optarg);
- break;
- default:
- {
- lf *file = lf_open(optarg, real_file_name);
- switch (ch) {
- case 'S':
- gen_semantics_h(instructions, file);
- break;
- case 's':
- gen_semantics_c(instructions, file);
- break;
- case 'P':
- gen_spreg_h(sprs, file);
- break;
- case 'p':
- gen_spreg_c(sprs, file);
- break;
- case 'D':
- gen_idecode_h(instructions, file);
- break;
- case 'd':
- gen_idecode_c(instructions, file);
- break;
- case 'C':
- gen_icache_h(cache_fields, file);
- break;
- }
- lf_close(file);
- }
- real_file_name = NULL;
- }
- }
- return 0;
-}
--- /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 _OS_EMUL_C_
+#define _OS_EMUL_C_
+
+#include "cpu.h"
+#include "idecode.h"
+#include "os_emul.h"
+
+#include "emul_generic.h"
+#include "emul_netbsd.h"
+
+#ifndef STATIC_INLINE_OS_EMUL
+#define STATIC_INLINE_OS_EMUL STATIC_INLINE
+#endif
+
+
+INLINE_OS_EMUL void
+os_emul_call(cpu *processor,
+ unsigned_word cia)
+{
+ emulation *emul = &emul_netbsd;
+ emul_do_call(emul,
+ cpu_registers(processor)->gpr[0],
+ 3, /*r3 contains arg0*/
+ processor,
+ cia);
+}
+
+#endif /* _OS_EMUL_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 _OS_EMUL_H_
+#define _OS_EMUL_H_
+
+#ifndef INLINE_OS_EMUL
+#define INLINE_OS_EMUL
+#endif
+
+typedef struct _os_emul *os_emul;
+
+INLINE_OS_EMUL os_emul *os_emul_create
+(char *emulation_name);
+
+INLINE_OS_EMUL void os_emul_init
+(os_emul *emulation);
+
+INLINE_OS_EMUL void os_emul_call
+(cpu *processor,
+ unsigned_word cia);
+
+#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.
+#
+#
+# Instruction unpacking:
+#
+# Once the instruction has been decoded, the register (and other)
+# fields within the instruction need to be extracted.
+#
+# The table that follows determines how each field should be treated.
+# Importantly it considers the case where the extracted field is to
+# be used immediatly or stored in an instruction cache.
+#
+# <valid>
+#
+# Zero marks the end of the table. More importantly 1. indicates
+# that the entry is valid and can be cached. 2. indicates that that
+# the entry is valid but can not be cached.
+#
+# <old_name>
+#
+# The field name as given in the instruction spec.
+#
+# <new_name>
+#
+# A name for <old_name> once it has been extracted from the
+# instructioin (and possibly stored in the instruction cache).
+#
+# <type>
+#
+# String specifying the storage type for <new_name> (the extracted
+# field>.
+#
+# <expression>
+#
+# Specifies how to get <new_name> from <old_name>. If null, old and
+# new name had better be the same. */
+#
+#
+1:RA:RA::
+1:RA:rA:signed_word *:(cpu_registers(processor)->gpr + RA)
+1:RT:RT::
+1:RT:rT:signed_word *:(cpu_registers(processor)->gpr + RT)
+2:RS:RS::
+1:RS:rS:signed_word *:(cpu_registers(processor)->gpr + RS)
+2:RB:RB::
+1:RB:rB:signed_word *:(cpu_registers(processor)->gpr + RB)
+2:FRA:FRA::
+1:FRA:frA:unsigned64 *:(cpu_registers(processor)->fpr + FRA)
+2:FRB:FRB::
+1:FRB:frB:unsigned64 *:(cpu_registers(processor)->fpr + FRB)
+2:FRC:FRC::
+1:FRC:frC:unsigned64 *:(cpu_registers(processor)->fpr + FRC)
+2:FRS:FRS::
+1:FRS:frS:unsigned64 *:(cpu_registers(processor)->fpr + FRS)
+2:FRT:FRT::
+1:FRT:frT:unsigned64 *:(cpu_registers(processor)->fpr + FRT)
+1:SI:EXTS_SI:unsigned_word:((signed_word)(signed16)instruction)
+2:BI:BI::
+1:BI:BIT32_BI::BIT32(BI)
+2:BA:BA::
+1:BA:BIT32_BA::BIT32(BA)
+2:BB:BB::
+1:BB:BIT32_BB::BIT32(BB)
+1:BD:EXTS_BD_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~3)
+#1:BD:CIA_plus_EXTS_BD_0b00:unsigned_word:CIA + EXTS(BD_0b00)
+1:LI:EXTS_LI_0b00:unsigned_word:((((signed_word)(signed32)(instruction << 6)) >> 6) & ~0x3)
+1:D:EXTS_D:unsigned_word:((signed_word)(signed16)(instruction))
+1:DS:EXTS_DS_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~0x3)
#include "ppc-endian.h"
#include "sim_callbacks.h"
-#if (WITH_HOST_BYTE_ORDER == LITTLE_ENDIAN) && WITH_NTOH
+#if !defined(SWAP_2) && (WITH_HOST_BYTE_ORDER == LITTLE_ENDIAN) && WITH_NTOH
#define SWAP_2(SET,RAW) SET htons (RAW)
#endif
return raw_in; \
} \
else { \
- SWAP_##BYTE_SIZE(return, raw_in); \
+ SWAP_##BYTE_SIZE(return,raw_in); \
} \
}
#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.
+#
+# 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: 0:0xfc000000:0x38000000:2
+11:15:11:15:0:RA: 0: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:: 1:0x00000000:0x00000000:0
+21:31:32:-1:0:: 1:0x00000000:0x00000000:0
--- /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 <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <string.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
of the host/target it is able to eliminate slower generic endian
handling code.
- If ENDIAN_OK is true then no byte swapping is required. If it is
- false, copy-in / copy-out functions assume that data should be byte
- reversed as part of the copy. */
+ Possible values are 0 (unknown), LITTLE_ENDIAN, BIG_ENDIAN */
+#ifndef WITH_HOST_BYTE_ORDER
#define WITH_HOST_BYTE_ORDER 0 /*unknown*/
+#endif
+
+#ifndef WITH_TARGET_BYTE_ORDER
#define WITH_TARGET_BYTE_ORDER 0 /*unknown*/
+#endif
extern int current_host_byte_order;
-extern int current_target_byte_order;
#define CURRENT_HOST_BYTE_ORDER (WITH_HOST_BYTE_ORDER \
? WITH_HOST_BYTE_ORDER \
: current_host_byte_order)
+extern int current_target_byte_order;
#define CURRENT_TARGET_BYTE_ORDER (WITH_TARGET_BYTE_ORDER \
? WITH_TARGET_BYTE_ORDER \
: current_target_byte_order)
+/* Intel host BSWAP support:
+
+ Whether to use bswap on the 486 and pentiums rather than the 386
+ sequence that uses xchgb/rorl/xchgb */
+#ifndef WITH_BSWAP
+#define WITH_BSWAP 0
+#endif
+
+
/* SMP support:
Sets a limit on the number of processors that can be simulated. If
WITH_SMP is set to zero (0), the simulator is restricted to
suporting only on processor (and as a consequence leaves the SMP
- code out of the build process). */
+ code out of the build process).
+
+ The actual number of processors is taken from the device
+ /options/smp@<nr-cpu> */
#ifndef WITH_SMP
-#define WITH_SMP 0
+#define WITH_SMP 2
+#endif
+#if WITH_SMP
+#define MAX_NR_PROCESSORS WITH_SMP
+#else
+#define MAX_NR_PROCESSORS 1
#endif
#ifndef WITH_TARGET_WORD_BITSIZE
#define WITH_TARGET_WORD_BITSIZE 32 /* compiled only */
#endif
+
#ifndef WITH_HOST_WORD_BITSIZE
#define WITH_HOST_WORD_BITSIZE 32 /* 64bit ready? */
#endif
CURRENT_ENVIRONMENT specifies which of vea or oea is required for
the current runtime. */
-#define WITH_ENVIRONMENT 0
#define VIRTUAL_ENVIRONMENT 1
#define OPERATING_ENVIRONMENT 2
+#ifndef WITH_ENVIRONMENT
+#define WITH_ENVIRONMENT 0
+#endif
+
extern int current_environment;
#define CURRENT_ENVIRONMENT (WITH_ENVIRONMENT \
? WITH_ENVIRONMENT \
#ifndef WITH_ALIGNMENT
#define WITH_ALIGNMENT 0
#endif
+
extern int current_alignment;
#define CURRENT_ALIGNMENT (WITH_ALIGNMENT \
? WITH_ALIGNMENT \
#define WITH_ASSERT 1
#endif
-/* include profiling code that doesn't yet exist */
-
-#ifndef WITH_PROFILE
-#define WITH_PROFILE 1
-#endif
-
-
-/* INSTRUCTION TABLE CODE GENERATION:
-
- The program gen takes the files ppc.instructions and spr.table and
- creates from them code that provides:
-
- o instruction decode and issue
- o spr information
-
- The program gen does this according to the configuration
- information that follows. */
-
-
-/* Line numbering of generated code:
-
- When generating the semantic and idecode files, gen can also output
- line number information (w.r.t. ppc.instructions). It may be
- useful to disable this if you suspect that gen.c is incorrectly
- generating itermediate code files. */
-
-#ifndef WITH_LINE_NUMBERS
-#define WITH_LINE_NUMBERS 1
-#endif
-
-
-/* Instruction cache:
-
- Instead of the idecode routine calling the semantic function
- directly, idecode can instead return a descriptor of the
- instruction (cache entry).
-
- With level one caching, idecode just returns the address of the
- semantic function. With level two caching, in addition to this,
- the idecode routine decodes key fields within the instruction and
- also enters them into the cache. The table IDECODE_CACHE_RULES
- controls what goes into the cache.*/
-
-#ifndef WITH_IDECODE_CACHE
-#define WITH_IDECODE_CACHE 0
-#endif
-#ifndef IDECODE_CACHE_SIZE
-#define IDECODE_CACHE_SIZE 1024
-#endif
-
-
-/* Semantic code expansion:
-
- For a given instruction there is the potential to improve
- performance bo creating copies of the instructions code for one or
- more of its possible variations. Eg branch being relative. This
- macro determines of semantic functions should be expanded. How
- well they are expanded is determined by the table
- WITH_IDECODE_OPCODE_RULES. */
-
-#ifndef WITH_IDECODE_EXPAND_SEMANTICS
-#define WITH_IDECODE_EXPAND_SEMANTICS 0
-#endif
-
-
-/* SPR database:
-
- The attributes of the SPR's are kept in a `lookup table'. This
- table can be implemented as either a true table or a switch
- statement.
+/* include monitoring code */
- A swith statement may be a performance advantage if the SPR's are
- known at compile time. The compiler is then able to eliminate the
- switch. */
-
-#ifndef WITH_SPREG_LOOKUP_TABLE
-#define WITH_SPREG_LOOKUP_TABLE 1
+#define MONITOR_INSTRUCTION_ISSUE 1
+#define MONITOR_LOAD_STORE_UNIT 2
+#ifndef WITH_MON
+#define WITH_MON (MONITOR_LOAD_STORE_UNIT \
+ | MONITOR_INSTRUCTION_ISSUE)
#endif
-/* 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
-
- Ok? */
-
-
-#define WITH_IDECODE_OPCODE_RULES { \
- { 1, 0, 5, 0, 5, 0, 0, 1, 0x00000000, 0x00000000, 0 }, \
- { 1, 21, 31, 32, -1, 0, 0, 1, 0x00000000, 0x00000000, 0 }, \
- { 0 } \
-}
-
-
-/* Instruction unpacking:
-
- Once the instruction has been decoded, the register (and other)
- fields within the instruction need to be extracted.
-
- The table that follows determines how each field should be treated.
- Importantly it considers the case where the extracted field is to
- be used immediatly or stored in an instruction cache.
-
- <valid>
-
- Zero marks the end of the table. More importantly 1. indicates
- that the entry is valid and can be cached. 2. indicates that that
- the entry is valid but can not be cached.
-
- <old_name>
-
- The field name as given in the instruction spec.
-
- <new_name>
-
- A name for <old_name> once it has been extracted from the
- instructioin (and possibly stored in the instruction cache).
-
- <type>
-
- String specifying the storage type for <new_name> (the extracted
- field>.
-
- <expression>
-
- Specifies how to get <new_name> from <old_name>. If null, old and
- new name had better be the same. */
-
-#define WITH_IDECODE_CACHE_RULES { \
- { 1, "RA", "RA", 0, 0 }, \
- { 1, "RA", "rA", "signed_word *", \
- "(cpu_registers(processor)->gpr + RA)" }, \
- { 1, "RT", "RT", 0, 0 }, \
- { 1, "RT", "rT", "signed_word *", \
- "(cpu_registers(processor)->gpr + RT)" }, \
- { 2, "RS", "RS", 0, 0 }, \
- { 1, "RS", "rS", "signed_word *", \
- "(cpu_registers(processor)->gpr + RS)" }, \
- { 2, "RB", "RB", 0, 0 }, \
- { 1, "RB", "rB", "signed_word *", \
- "(cpu_registers(processor)->gpr + RB)" }, \
- { 2, "FRA", "FRA", 0, 0 }, \
- { 1, "FRA", "frA", "unsigned64 *", \
- "(cpu_registers(processor)->fpr + FRA)" }, \
- { 2, "FRB", "FRB", 0, 0 }, \
- { 1, "FRB", "frB", "unsigned64 *", \
- "(cpu_registers(processor)->fpr + FRB)" }, \
- { 2, "FRC", "FRC", 0, 0 }, \
- { 1, "FRC", "frC", "unsigned64 *", \
- "(cpu_registers(processor)->fpr + FRC)" }, \
- { 2, "FRS", "FRS", 0, 0 }, \
- { 1, "FRS", "frS", "unsigned64 *", \
- "(cpu_registers(processor)->fpr + FRS)" }, \
- { 2, "FRT", "FRT", 0, 0 }, \
- { 1, "FRT", "frT", "unsigned64 *", \
- "(cpu_registers(processor)->fpr + FRT)" }, \
- { 1, "SI", "EXTS_SI", "unsigned_word", \
- "((signed_word)(signed16)instruction)" }, \
- { 2, "BI", "BI", 0, 0 }, \
- { 1, "BI", "BIT32_BI", 0, \
- "BIT32(BI)" }, \
- { 2, "BA", "BA", 0, 0 }, \
- { 1, "BA", "BIT32_BA", 0, \
- "BIT32(BA)" }, \
- { 2, "BB", "BB", 0, 0 }, \
- { 1, "BB", "BIT32_BB", 0, \
- "BIT32(BB)" }, \
- { 1, "BD", "EXTS_BD_0b00", "unsigned_word", \
- "(((signed_word)(signed16)instruction) & ~3)" }, \
-/*{ 1, "BD", "CIA_plus_EXTS_BD_0b00", "unsigned_word", */ \
-/* "CIA + EXTS(BD_0b00)" }, */ \
- { 1, "LI", "EXTS_LI_0b00", "unsigned_word", \
- "((((signed_word)(signed32)(instruction << 6)) >> 6) & ~0x3)" }, \
- { 1, "D", "EXTS_D", "unsigned_word", \
- "((signed_word)(signed16)(instruction))" }, \
- { 1, "DS", "EXTS_DS_0b00", "unsigned_word", \
- "(((signed_word)(signed16)instruction) & ~0x3)" }, \
- { 0 } \
-};
-
-
/* INLINE CODE SELECTION:
controled by the <module>_INLINE macro's. Where each can have a
value:
- 0 ppc.c should call external module
+ 0 Make a normal external call to functions in the module.
- 1 ppc.c should have local copy (and hence possibly facilitate
- the in lineing of that modules external calls)
+ 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.
- 2 ppc.c should inline this module
+ 2 Both include the module and inline functions contained within
+ it.
Finally, this is not for the faint harted. I've seen GCC get up to
200mb trying to compile what this can create */
#define STATIC_INLINE static INLINE
#endif
-/* Default macro to control several of the inlines */
+/* Default macro to simplify control several of key the inlines */
#ifndef DEFAULT_INLINE
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
+#define DEFAULT_INLINE 2
+#else
#define DEFAULT_INLINE 0
#endif
+#endif
-/* Code that does byte swapping used on any memory access */
+/* Code that converts between hosts and target byte order. Used on
+ every memory access (instruction and data). (See ppc-endian.h for
+ additional byte swapping configuration information) */
#ifndef ENDIAN_INLINE
#define ENDIAN_INLINE DEFAULT_INLINE
#endif
-/* Instruction cache if in use */
-
-#if 0 /*DNE*/
-#ifndef ICACHE_INLINE
-#define ICACHE_INLINE 0
-#endif
-#endif
-
-/* Given a translated address, core maps it onto either simulator data
- or a function call, this is performed once for each
- data/instruction access */
+/* Code that gives access to various CPU internals such as registers.
+ Used every time an instruction is executed */
-
-#ifndef CORE_INLINE
-#define CORE_INLINE DEFAULT_INLINE
+#ifndef CPU_INLINE
+#define CPU_INLINE DEFAULT_INLINE
#endif
-
-/* The cpu object. May things call upon this module to manipulate
- each cpu object for instance register updates (from semantics) or
- instruction execution from psim */
+/* Code that translates between an effective and real address. Used
+ by every load or store. */
#ifndef VM_INLINE
#define VM_INLINE DEFAULT_INLINE
#endif
-/* Physical memory is implemented using the memory map module */
+/* Code that loads/stores data to/from the memory data structure.
+ Used by every load or store */
-#ifndef CPU_INLINE
-#define CPU_INLINE DEFAULT_INLINE
+#ifndef CORE_INLINE
+#define CORE_INLINE DEFAULT_INLINE
#endif
-/* handle the queue of events to happen in the future */
+/* Code to check for and process any events scheduled in the future.
+ Called once per instruction cycle */
#ifndef EVENTS_INLINE
#define EVENTS_INLINE DEFAULT_INLINE
#endif
-/* not so important register manipulation code. Most important
- register operations are performed directly on the register file */
+/* Code monotoring the processors performance. It counts events on
+ every instruction cycle */
-#ifndef REGISTERS_INLINE
-#define REGISTERS_INLINE DEFAULT_INLINE
+#ifndef MON_INLINE
+#define MON_INLINE DEFAULT_INLINE
#endif
-/* interrupt handling code */
+/* Code called on the rare occasions that an interrupt occures. */
#ifndef INTERRUPTS_INLINE
-#define INTERRUPTS_INLINE DEFAULT_INLINE
+#define INTERRUPTS_INLINE 0
+#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
#endif
-/* device code. While possibly important, this isn't as critical as
- the cpu/memory path
+/* Code called on the rare occasion that a processor is manipulating
+ real hardware instead of RAM.
+
+ Also, most of the functions in devices.c are always called through
+ a jump table.
There seems to be some problem with making either device_tree or
- devices inline. It reports the message:
- device_tree_find_node() not a leaf */
+ devices inline. It reports the message: device_tree_find_node()
+ not a leaf */
#ifndef DEVICE_TREE_INLINE
-#define DEVICE_TREE_INLINE 0
+#define DEVICE_TREE_INLINE DEFAULT_INLINE
#endif
#ifndef DEVICES_INLINE
#define DEVICES_INLINE 0
#endif
-/* Special Purpose Register tables. Provide information on the
- attributes of given SPR's. */
+/* Code called whenever information on a Special Purpose Register is
+ required. Called by the mflr/mtlr pseudo instructions */
#ifndef SPREG_INLINE
#define SPREG_INLINE DEFAULT_INLINE
inline all of their called functions */
#ifndef SEMANTICS_INLINE
-#define SEMANTICS_INLINE 0
+#define SEMANTICS_INLINE (DEFAULT_INLINE ? 1 : 0)
#endif
-/* Functions that decode an instruction. Called by the cpu module.
- Part of the performance critical fetch - decode - issue sequence */
+/* Code to decode an instruction. Normally called on every instruction
+ cycle */
#ifndef IDECODE_INLINE
#define IDECODE_INLINE DEFAULT_INLINE
#endif
-
-
-/* If you're confused by the above, check out some of the generic
- configurations below. */
-
-
-#if 0
-/* Allow the expansion of the semantic functions. That is, if the
- branch instruction is called with AA=0 and AA=1, generate separate
- functions for each case */
-
-#undef WITH_IDECODE_EXPAND_SEMANTICS
-#define WITH_IDECODE_EXPAND_SEMANTICS 1
-
-#undef WITH_IDECODE_OPCODE_RULES
-#define WITH_IDECODE_OPCODE_RULES { \
- { 1, 0, 5, 0, 5, 0, 0, 0, 0x00000000, 0x00000000, 0 }, \
- { 1, 21, 31, 32, -1, 0, "OE,LR,AA,Rc,LK", 0, 0x00000000, 0x00000000, 0 }, \
- { 1, 6, 9, 6, 9, 0, "BO", 0, 0xfc000000, 0x40000000, 1 }, \
- { 1, 11, 15, 11, 15, 0, "RA", 0, 0xfc000000, 0x38000000, 2 }, \
- { 1, 11, 15, 11, 15, 0, "RA", 0, 0xfc000000, 0x3c000000, 2 }, \
- { 0 } \
-}
-#endif
-
-
-#if 0
-/* eliminate any debugging noise */
-
-#undef WITH_TRACE
-#define WITH_TRACE 0
-
-#undef WITH_ASSERT
-#define WITH_ASSERT 0
-
-#endif
-
-
-#if 0
-/* A reasonable set of inline macro's that give the compiler a
- fighting chance at eliminating much of the function call overhead.
-
- Typically, with the below the -O3 option (to get inline of all
- functioins) isn't of any greate benefit. */
-
-#undef INLINE
-#define INLINE inline
-
-#undef STATIC_INLINE
-#define STATIC_INLINE static INLINE
-
-#undef ENDIAN_INLINE
-#define ENDIAN_INLINE 2
-
-#if 0 /*DNE*/
-#undef ICACHE_INLINE
-#define ICACHE_INLINE 0
-#endif
-
-#undef CORE_INLINE
-#define CORE_INLINE 2
-
-#undef VM_INLINE
-#define VM_INLINE 2
-
-#undef CPU_INLINE
-#define CPU_INLINE 2
-
-#undef EVENTS_INLINE
-#define EVENTS_INLINE 2
-
-#undef REGISTERS_INLINE
-#define REGISTERS_INLINE 2
-
-#undef INTERRUPTS_INLINE
-#define INTERRUPTS_INLINE 2
-
-#undef DEVICE_TREE_INLINE
-#define DEVICE_TREE_INLINE 0
-
-#undef DEVICES_INLINE
-#define DEVICES_INLINE 0
-
-#undef SPREG_INLINE
-#define SPREG_INLINE 2
-
-#undef SEMANTICS_INLINE
-#define SEMANTICS_INLINE 1 /* not 2! as it blows away the compiler */
-
-#undef IDECODE_INLINE
-#define IDECODE_INLINE 2
-
-#endif
-
-
-#if 0
-/* Enable the full cracking cache. The cracked instruction cache
- appears to give best performance if most functions have been lined
- as well */
-
-#undef WITH_IDECODE_CACHE
-#define WITH_IDECODE_CACHE 2
-
-#endif
-
-
-
-#if 0
-/* With the VEA model, can eliminate some things. Not least of which
- is support for the OEA model */
-
-#undef WITH_ENVIRONMENT
-#define WITH_ENVIRONMENT VIRTUAL_ENVIRONMENT
-
-#undef WITH_EVENTS
-#define WITH_EVENTS 0
-
-#undef WITH_SMP
-#define WITH_SMP 0
-
-#undef WITH_TARGET_BYTE_ORDER
-#define WITH_TARGET_BYTE_ORDER WITH_HOST_BYTE_ORDER
-
-#endif
-
-
-
-
-#if 0
-/* Finally, the expansion rules below are extreemly agressive. Only
- consider them if your build machine is VERY VERY VERY VERY VERY
- well configured */
-
-#undef WITH_IDECODE_EXPAND_SEMANTICS
-#define WITH_IDECODE_EXPAND_SEMANTICS 1
-
-#undef WITH_IDECODE_OPCODE_RULES
-#define WITH_IDECODE_OPCODE_RULES { \
- { 1, 0, 5, 0, 5, 0, 0, 0, 0x00000000, 0x00000000, 0 }, \
- { 1, 21, 31, 32, -1, 0, "OE,LR,AA,Rc,LK", 0, 0x00000000, 0x00000000, 0 }, \
- { 1, 6, 15, 6, 15, 0, "BO,BI", 0, 0xfc000000, 0x40000000, 0 }, \
- { 1, 11, 15, 11, 15, 0, "RA", 0, 0xfc000000, 0x38000000, 0 }, \
- { 1, 11, 15, 11, 15, 0, "RA", 0, 0xfc000000, 0x3c000000, 0 }, \
- { 1, 11, 20, 11, 20, 0, "spr", 0, 0xfc000000, 0x7c000000, 0 }, \
- { 0 } \
-}
-#endif
-
-
#endif /* _CONFIG_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 _SYSTEM_C_
-#define _SYSTEM_C_
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/errno.h>
-#include <sys/param.h>
-#include <fcntl.h>
-
-#if (NetBSD >= 199306) /* here NetBSD as that is what we're emulating */
-#include <sys/syscall.h> /* FIXME - should not be including this one */
-#include <sys/sysctl.h>
-#endif
-
-#if (BSD < 199306) /* here BSD as just a bug */
-extern int errno;
-#endif
-
-#include "cpu.h"
-#include "idecode.h"
-#include "system.h"
-
-
-#ifndef STATIC_INLINE_SYSTEM
-#define STATIC_INLINE_SYSTEM STATIC_INLINE
-#endif
-
-
-#if (NetBSD >= 199306)
-#define SYS(X) ASSERT(call == (SYS_##X))
-#else
-#define SYS(X)
-#endif
-
-#if (NetBSD >= 199306 && PATH_MAX != 1024)
-#error "PATH_MAX not 1024"
-#elif !defined(PATH_MAX)
-#define PATH_MAX 1024
-#endif
-
-
-STATIC_INLINE_SYSTEM char *
-read_string(cpu *processor,
- char *dest,
- unsigned_word addr,
- unsigned nr_bytes)
-{
- unsigned nr_moved = 0;
- if (addr == 0)
- return NULL;
- while (1) {
- if (vm_data_map_read_buffer(cpu_data_map(processor),
- &dest[nr_moved],
- addr + nr_moved,
- sizeof(dest[nr_moved]))
- != sizeof(dest[nr_moved]))
- return NULL;
- if (dest[nr_moved] == '\0' || nr_moved >= nr_bytes)
- break;
- nr_moved++;
- }
- dest[nr_moved] = '\0';
- return dest;
-}
-
-
-STATIC_INLINE_SYSTEM void
-write_status(cpu *processor,
- int status)
-{
- cpu_registers(processor)->gpr[3] = status;
- if (status < 0)
- cpu_registers(processor)->gpr[0] = errno;
- else
- cpu_registers(processor)->gpr[0] = 0;
-}
-
-
-STATIC_INLINE_SYSTEM void
-write_stat(cpu *processor,
- unsigned_word addr,
- struct stat buf)
-{
- int nr_moved;
- H2T(buf.st_dev);
- H2T(buf.st_ino);
- H2T(buf.st_mode);
- H2T(buf.st_nlink);
- H2T(buf.st_uid);
- H2T(buf.st_gid);
- H2T(buf.st_rdev);
- H2T(buf.st_size);
- H2T(buf.st_atime);
- /* H2T(buf.st_spare1); */
- H2T(buf.st_mtime);
- /* H2T(buf.st_spare2); */
- H2T(buf.st_ctime);
- /* H2T(buf.st_spare3); */
- H2T(buf.st_blksize);
- H2T(buf.st_blocks);
-#if (NetBSD >= 199306)
- H2T(buf.st_flags);
- H2T(buf.st_gen);
-#endif
- nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
- &buf,
- addr,
- sizeof(buf),
- 0/*violate_ro*/);
- if (nr_moved != sizeof(buf))
- error("write_stat() write failed\n");
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_exit(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- int status = (int)cpu_registers(processor)->gpr[3];
- SYS(exit);
- cpu_halt(processor, cia, was_exited, status);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_read(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- void *scratch_buffer;
- int d = (int)cpu_registers(processor)->gpr[3];
- unsigned_word buf = cpu_registers(processor)->gpr[4];
- int nbytes = cpu_registers(processor)->gpr[5];
- int status;
- int nr_moved;
- SYS(read);
-
- /* get a tempoary bufer */
- scratch_buffer = zalloc(nbytes);
-
- /* check if buffer exists by reading it */
- nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
- scratch_buffer,
- buf,
- nbytes);
- if (nr_moved != nbytes)
- error("system_call()read - check on buffer failed\n");
-
- /* read */
-#if 0
- if (d == 0) {
- status = fread (scratch_buffer, 1, nbytes, stdin);
- if (status == 0 && ferror (stdin))
- status = -1;
- }
-#endif
- status = read (d, scratch_buffer, nbytes);
-
- if (status == -1) {
- cpu_registers(processor)->gpr[0] = errno;
- } else {
- cpu_registers(processor)->gpr[3] = status;
-
- if (status > 0) {
- nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
- scratch_buffer,
- buf,
- status,
- 0/*violate_ro*/);
- if (nr_moved != status)
- error("system_call()read - write to buffer failed\n");
- }
- }
-
- zfree(scratch_buffer);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_write(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- void *scratch_buffer = NULL;
- int nr_moved;
- int d = (int)cpu_registers(processor)->gpr[3];
- unsigned_word buf = cpu_registers(processor)->gpr[4];
- int nbytes = cpu_registers(processor)->gpr[5];
- int status;
- SYS(write);
-
- /* get a tempoary bufer */
- scratch_buffer = zalloc(nbytes); /* FIXME - nbytes == 0 */
-
- /* copy in */
- nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
- scratch_buffer,
- buf,
- nbytes);
- if (nr_moved != nbytes) {
- /* FIXME - should handle better */
- error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
- nr_moved, nbytes);
- }
-
- /* write */
- status = write(d, scratch_buffer, nbytes);
- if (status == -1) {
- cpu_registers(processor)->gpr[0] = errno;
- }
- cpu_registers(processor)->gpr[3] = status;
-
- zfree(scratch_buffer);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_open(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- unsigned_word path_addr = cpu_registers(processor)->gpr[3];
- char path_buf[PATH_MAX];
- char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
- int flags = (int)cpu_registers(processor)->gpr[4];
- int mode = (int)cpu_registers(processor)->gpr[4];
- SYS(open);
- write_status(processor, open(path, flags, mode));
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_close(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- int d = (int)cpu_registers(processor)->gpr[3];
- SYS(close);
- write_status(processor, close(d));
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_break(unsigned call,
- cpu *processor,
- unsigned_word cia)
- /* just pass this onto the `vm' device */
-{
- psim *system = cpu_system(processor);
- const device *vm = psim_device(system, "/vm");
- SYS(break);
- vm->callback->ioctl(vm,
- system,
- processor,
- cia,
- 0, /*ioctl*/
- NULL); /*ioctl-data*/
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_getpid(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- SYS(getpid);
- cpu_registers(processor)->gpr[3] = (int)getpid();
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_getuid(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- SYS(getuid);
- cpu_registers(processor)->gpr[3] = (int)getuid();
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_geteuid(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- SYS(geteuid);
- cpu_registers(processor)->gpr[3] = (int)geteuid();
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_kill(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- pid_t pid = cpu_registers(processor)->gpr[3];
- int sig = cpu_registers(processor)->gpr[4];
- SYS(kill);
- error("SYS_kill - more to this than just a kill\n");
- cpu_halt(processor, cia, was_signalled, sig);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_sigprocmask(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- natural_word how = cpu_registers(processor)->gpr[3];
- unsigned_word set = cpu_registers(processor)->gpr[4];
- unsigned_word oset = cpu_registers(processor)->gpr[5];
- SYS(sigprocmask);
- TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n",
- how, set, oset));
- cpu_registers(processor)->gpr[3] = 0;
- cpu_registers(processor)->gpr[4] = set;
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_ioctl(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- SYS(ioctl);
- TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n",
- cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5]));
- cpu_registers(processor)->gpr[3] = 0;
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_umask(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- SYS(umask);
- cpu_registers(processor)->gpr[3] = umask(cpu_registers(processor)->gpr[3]);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_stat(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- char path_buf[PATH_MAX];
- unsigned_word path_addr = cpu_registers(processor)->gpr[3];
- unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
- char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
- struct stat buf;
- SYS(stat);
- write_status(processor, stat(path, &buf));
- write_stat(processor, stat_buf_addr, buf);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_fstat(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- int fd = cpu_registers(processor)->gpr[3];
- unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
- struct stat buf;
- SYS(fstat);
- write_status(processor, fstat(fd, &buf));
- write_stat(processor, stat_buf_addr, buf);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do_lstat(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- char path_buf[PATH_MAX];
- unsigned_word path_addr = cpu_registers(processor)->gpr[3];
- char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
- unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
- struct stat buf;
- SYS(lstat);
- write_status(processor, stat(path, &buf));
- write_stat(processor, stat_buf_addr, buf);
-}
-
-
-STATIC_INLINE_SYSTEM void
-do___sysctl(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- /* call the arguments by their real name */
- unsigned_word name = cpu_registers(processor)->gpr[3];
- natural_word namelen = cpu_registers(processor)->gpr[4];
- unsigned_word oldp = cpu_registers(processor)->gpr[5];
- unsigned_word oldlenp = cpu_registers(processor)->gpr[6];
- natural_word oldlen;
- natural_word mib;
- natural_word int_val;
- SYS(__sysctl);
-
- /* pluck out the management information base id */
- if (namelen < 1)
- error("system_call()SYS___sysctl bad name[0]\n");
- mib = vm_data_map_read_word(cpu_data_map(processor),
- name,
- processor,
- cia);
- name += sizeof(mib);
-
- /* see what to do with it ... */
- switch (mib) {
- case 6/*CTL_HW*/:
-#if (NetBSD >= 199306) && (CTL_HW != 6)
-# error "CTL_HW"
-#endif
- if (namelen < 2)
- error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
- mib = vm_data_map_read_word(cpu_data_map(processor),
- name,
- processor,
- cia);
- name += sizeof(mib);
- switch (mib) {
- case 7/*HW_PAGESIZE*/:
-#if (NetBSD >= 199306) && (HW_PAGESIZE != 7)
-# error "HW_PAGESIZE"
-#endif
- oldlen = vm_data_map_read_word(cpu_data_map(processor),
- oldlenp,
- processor,
- cia);
- if (sizeof(natural_word) > oldlen)
- error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
- int_val = 8192;
- oldlen = sizeof(int_val);
- vm_data_map_write_word(cpu_data_map(processor),
- oldp,
- int_val,
- processor,
- cia);
- vm_data_map_write_word(cpu_data_map(processor),
- oldlenp,
- oldlen,
- processor,
- cia);
- break;
- default:
- error("sysctl() CTL_HW.%d unknown\n", mib);
- break;
- }
- break;
- default:
- error("sysctl() name[0]=%s unknown\n", (int)mib);
- break;
- }
- cpu_registers(processor)->gpr[3] = 0;
-}
-
-STATIC_INLINE_SYSTEM void
-unimp(unsigned call,
- cpu *processor,
- unsigned_word cia)
-{
- error("unimplemented system call %d, cia=0x%x\n", call, cia);
-}
-
-
-typedef void (sys_handler)
- (unsigned call,
- cpu *processor,
- unsigned_word cia);
-
-static sys_handler *(handlers[]) = {
- unimp, /* SYS_syscall 0 */
- do_exit, /* 1*/
- unimp, /* SYS_fork 2 */
- do_read, /* 3 */
- do_write, /* 4 */
- do_open, /* 5 */
- do_close, /* 6 */
- unimp, /* SYS_wait4 7 */
- unimp, /* 8 is old creat */
- unimp, /* SYS_link 9 */
- unimp, /* SYS_unlink 10 */
- unimp, /* 11 is obsolete execv */
- unimp, /* SYS_chdir 12 */
- unimp, /* SYS_fchdir 13 */
- unimp, /* SYS_mknod 14 */
- unimp, /* SYS_chmod 15 */
- unimp, /* SYS_chown 16 */
- do_break, /* 17 */
- unimp, /* SYS_getfsstat 18 */
- unimp, /* 19 is old lseek */
- do_getpid, /* 20 */
- unimp, /* SYS_mount 21 */
- unimp, /* SYS_unmount 22 */
- unimp, /* SYS_setuid 23 */
- do_getuid, /* 24 */
- do_geteuid, /* 25 */
- unimp, /* SYS_ptrace 26 */
- unimp, /* SYS_recvmsg 27 */
- unimp, /* SYS_sendmsg 28 */
- unimp, /* SYS_recvfrom 29 */
- unimp, /* SYS_accept 30 */
- unimp, /* SYS_getpeername 31 */
- unimp, /* SYS_getsockname 32 */
- unimp, /* SYS_access 33 */
- unimp, /* SYS_chflags 34 */
- unimp, /* SYS_fchflags 35 */
- unimp, /* SYS_sync 36 */
- do_kill, /* 37 */
- unimp, /* 38 is old stat */
- unimp, /* SYS_getppid 39 */
- unimp, /* 40 is old lstat */
- unimp, /* SYS_dup 41 */
- unimp, /* SYS_pipe 42 */
- unimp, /* SYS_getegid 43 */
- unimp, /* SYS_profil 44 */
- unimp, /* SYS_ktrace 45 */
- unimp, /* SYS_sigaction 46 */
- unimp, /* SYS_getgid 47 */
- do_sigprocmask, /* 48 */
- unimp, /* SYS_getlogin 49 */
- unimp, /* SYS_setlogin 50 */
- unimp, /* SYS_acct 51 */
- unimp, /* SYS_sigpending 52 */
- unimp, /* SYS_sigaltstack 53 */
- do_ioctl, /* 54 */
- unimp, /* SYS_reboot 55 */
- unimp, /* SYS_revoke 56 */
- unimp, /* SYS_symlink 57 */
- unimp, /* SYS_readlink 58 */
- unimp, /* SYS_execve 59 */
- do_umask, /* 60 */
- unimp, /* SYS_chroot 61 */
- unimp, /* 62 is old fstat */
- unimp, /* 63 is old getkerninfo */
- unimp, /* 64 is old getpagesize */
- unimp, /* SYS_msync 65 */
- unimp, /* SYS_vfork 66 */
- unimp, /* 67 is obsolete vread */
- unimp, /* 68 is obsolete vwrite */
- unimp, /* SYS_sbrk 69 */
- unimp, /* SYS_sstk 70 */
- unimp, /* 71 is old mmap */
- unimp, /* SYS_vadvise 72 */
- unimp, /* SYS_munmap 73 */
- unimp, /* SYS_mprotect 74 */
- unimp, /* SYS_madvise 75 */
- unimp, /* 76 is obsolete vhangup */
- unimp, /* 77 is obsolete vlimit */
- unimp, /* SYS_mincore 78 */
- unimp, /* SYS_getgroups 79 */
- unimp, /* SYS_setgroups 80 */
- unimp, /* SYS_getpgrp 81 */
- unimp, /* SYS_setpgid 82 */
- unimp, /* SYS_setitimer 83 */
- unimp, /* 84 is old wait */
- unimp, /* SYS_swapon 85 */
- unimp, /* SYS_getitimer 86 */
- unimp, /* 87 is old gethostname */
- unimp, /* 88 is old sethostname */
- unimp, /* 89 is old getdtablesize */
- unimp, /* SYS_dup2 90 */
- unimp, /* 91 */
- unimp, /* SYS_fcntl 92 */
- unimp, /* SYS_select 93 */
- unimp, /* 94 */
- unimp, /* SYS_fsync 95 */
- unimp, /* SYS_setpriority 96 */
- unimp, /* SYS_socket 97 */
- unimp, /* SYS_connect 98 */
- unimp, /* 99 is old accept */
- unimp, /* SYS_getpriority 100 */
- unimp, /* 101 is old send */
- unimp, /* 102 is old recv */
- unimp, /* SYS_sigreturn 103 */
- unimp, /* SYS_bind 104 */
- unimp, /* SYS_setsockopt 105 */
- unimp, /* SYS_listen 106 */
- unimp, /* 107 is obsolete vtimes */
- unimp, /* 108 is old sigvec */
- unimp, /* 109 is old sigblock */
- unimp, /* 110 is old sigsetmask */
- unimp, /* SYS_sigsuspend 111 */
- unimp, /* 112 is old sigstack */
- unimp, /* 113 is old recvmsg */
- unimp, /* 114 is old sendmsg */
- unimp, /* SYS_vtrace 115 - is obsolete vtrace */
- unimp, /* SYS_gettimeofday 116 */
- unimp, /* SYS_getrusage 117 */
- unimp, /* SYS_getsockopt 118 */
- unimp, /* SYS_resuba 119 */
- unimp, /* SYS_readv 120 */
- unimp, /* SYS_writev 121 */
- unimp, /* SYS_settimeofday 122 */
- unimp, /* SYS_fchown 123 */
- unimp, /* SYS_fchmod 124 */
- unimp, /* 125 is old recvfrom */
- unimp, /* 126 is old setreuid */
- unimp, /* 127 is old setregid */
- unimp, /* SYS_rename 128 */
- unimp, /* 129 is old truncate */
- unimp, /* 130 is old ftruncate */
- unimp, /* SYS_flock 131 */
- unimp, /* SYS_mkfifo 132 */
- unimp, /* SYS_sendto 133 */
- unimp, /* SYS_shutdown 134 */
- unimp, /* SYS_socketpair 135 */
- unimp, /* SYS_mkdir 136 */
- unimp, /* SYS_rmdir 137 */
- unimp, /* SYS_utimes 138 */
- unimp, /* 139 is obsolete 4.2 sigreturn */
- unimp, /* SYS_adjtime 140 */
- unimp, /* 141 is old getpeername */
- unimp, /* 142 is old gethostid */
- unimp, /* 143 is old sethostid */
- unimp, /* 144 is old getrlimit */
- unimp, /* 145 is old setrlimit */
- unimp, /* 146 is old killpg */
- unimp, /* SYS_setsid 147 */
- unimp, /* SYS_quotactl 148 */
- unimp, /* 149 is old quota */
- unimp, /* 150 is old getsockname */
- unimp, /* 151 */
- unimp, /* 152 */
- unimp, /* 153 */
- unimp, /* 154 */
- unimp, /* SYS_nfssvc 155 */
- unimp, /* 156 is old getdirentries */
- unimp, /* SYS_statfs 157 */
- unimp, /* SYS_fstatfs 158 */
- unimp, /* 159 */
- unimp, /* 160 */
- unimp, /* SYS_getfh 161 */
- unimp, /* 162 is old getdomainname */
- unimp, /* 163 is old setdomainname */
- unimp, /* 164 is old uname */
- unimp, /* SYS_sysarch 165 */
- unimp, /* 166 */
- unimp, /* 167 */
- unimp, /* 168 */
- unimp, /* SYS_semsys 169 */
- unimp, /* SYS_msgsys 170 */
- unimp, /* SYS_shmsys 171 */
- unimp, /* 172 */
- unimp, /* 173 */
- unimp, /* 174 */
- unimp, /* 175 */
- unimp, /* 176 */
- unimp, /* 177 */
- unimp, /* 178 */
- unimp, /* 179 */
- unimp, /* 180 */
- unimp, /* SYS_setgid 181 */
- unimp, /* SYS_setegid 182 */
- unimp, /* SYS_seteuid 183 */
- unimp, /* SYS_lfs_bmapv 184 */
- unimp, /* SYS_lfs_markv 185 */
- unimp, /* SYS_lfs_segclean 186 */
- unimp, /* SYS_lfs_segwait 187 */
- do_stat, /* 188 */
- do_fstat, /* 189 */
- do_lstat, /* 190 */
- unimp, /* SYS_pathconf 191 */
- unimp, /* SYS_fpathconf 192 */
- unimp, /* 193 */
- unimp, /* SYS_getrlimit 194 */
- unimp, /* SYS_setrlimit 195 */
- unimp, /* SYS_getdirentries 196 */
- unimp, /* SYS_mmap 197 */
- unimp, /* SYS___syscall 198 */
- unimp, /* SYS_lseek 199 */
- unimp, /* SYS_truncate 200 */
- unimp, /* SYS_ftruncate 201 */
- do___sysctl, /* 202 */
- unimp, /* SYS_mlock 203 */
- unimp, /* SYS_munlock 204 */
-};
-
-INLINE_SYSTEM void
-system_call(cpu *processor,
- unsigned_word cia)
-{
- unsigned call = cpu_registers(processor)->gpr[0];
- if (call >= sizeof(handlers)/sizeof(handlers[0]))
- error("system call %d out-of-range\n", call);
- cpu_registers(processor)->gpr[0] = 0; /* default success */
- handlers[call](call, processor, cia);
-}
-
-#endif /* _SYSTEM_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 _SYSTEM_H_
-#define _SYSTEM_H_
-
-#ifndef INLINE_SYSTEM
-#define INLINE_SYSTEM
-#endif
-
-INLINE_SYSTEM void system_call
-(cpu *processor,
- unsigned_word cia);
-
-#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.
+
+ */
+
+
+/* load a table into memory */
+
+typedef struct _table table;
+
+typedef struct _table_entry table_entry;
+struct _table_entry {
+ int line_nr;
+ int nr_fields;
+ char *file_name;
+ char *annex;
+ char *fields[0]; /* User defined */
+};
+
+
+extern table *table_open
+(char *file_name,
+ int max_nr_fields);
+
+extern table_entry *table_entry_read
+(table *file);
+
+extern void dump_table_entry
+(table_entry *entry,
+ int indent);
+
+extern void table_entry_lf_c_line_nr
+(lf *file,
+ table_entry *entry);