diff options
author | Michael Meissner <gnu@the-meissners.org> | 1995-10-31 18:29:37 +0000 |
---|---|---|
committer | Michael Meissner <gnu@the-meissners.org> | 1995-10-31 18:29:37 +0000 |
commit | 5b4d72dd7362598e6f9c5483b990d0dee05fce1d (patch) | |
tree | ec3cb552f7ad6b1445d1f9619492c64a0a18e457 | |
parent | 5666490bee263c9357118553e40637449d186988 (diff) | |
download | fsf-binutils-gdb-5b4d72dd7362598e6f9c5483b990d0dee05fce1d.zip fsf-binutils-gdb-5b4d72dd7362598e6f9c5483b990d0dee05fce1d.tar.gz fsf-binutils-gdb-5b4d72dd7362598e6f9c5483b990d0dee05fce1d.tar.bz2 |
New changes from Andrew
-rw-r--r-- | sim/ppc/.Sanitize | 26 | ||||
-rw-r--r-- | sim/ppc/ChangeLog | 218 | ||||
-rw-r--r-- | sim/ppc/Makefile.in | 103 | ||||
-rw-r--r-- | sim/ppc/README.psim | 329 | ||||
-rw-r--r-- | sim/ppc/bits.c | 27 | ||||
-rwxr-xr-x | sim/ppc/build-psim | 155 | ||||
-rw-r--r-- | sim/ppc/core.c | 78 | ||||
-rw-r--r-- | sim/ppc/core_n.h | 4 | ||||
-rw-r--r-- | sim/ppc/device_tree.c | 195 | ||||
-rw-r--r-- | sim/ppc/device_tree.h | 10 | ||||
-rw-r--r-- | sim/ppc/devices.c | 233 | ||||
-rw-r--r-- | sim/ppc/devices.h | 50 | ||||
-rw-r--r-- | sim/ppc/emul_netbsd.h (renamed from sim/ppc/system.h) | 12 | ||||
-rw-r--r-- | sim/ppc/gen.c | 3323 | ||||
-rw-r--r-- | sim/ppc/os_emul.c | 49 | ||||
-rw-r--r-- | sim/ppc/os_emul.h | 41 | ||||
-rw-r--r-- | sim/ppc/ppc-cache-rules | 85 | ||||
-rw-r--r-- | sim/ppc/ppc-endian.c | 4 | ||||
-rw-r--r-- | sim/ppc/ppc-opcode-complex | 95 | ||||
-rw-r--r-- | sim/ppc/ppc-opcode-simple | 92 | ||||
-rw-r--r-- | sim/ppc/spa-reporter.c | 758 | ||||
-rw-r--r-- | sim/ppc/spa-system-calls.c | 499 | ||||
-rw-r--r-- | sim/ppc/spa-system-calls.h | 119 | ||||
-rw-r--r-- | sim/ppc/std-config.h | 534 | ||||
-rw-r--r-- | sim/ppc/system.c | 720 | ||||
-rw-r--r-- | sim/ppc/table.h | 49 |
26 files changed, 2897 insertions, 4911 deletions
diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize index c25d589..efa34bd 100644 --- a/sim/ppc/.Sanitize +++ b/sim/ppc/.Sanitize @@ -31,6 +31,7 @@ README.psim basics.h bits.c bits.h +build-psim config.in configure configure.in @@ -45,22 +46,38 @@ device_tree.c 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 @@ -69,9 +86,12 @@ registers.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 diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index 538ef48..14625b1 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,3 +1,197 @@ +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. @@ -93,7 +287,7 @@ Thu Oct 12 11:35:53 1995 Michael Meissner <meissner@tiktok.cygnus.com> ({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, @@ -110,7 +304,7 @@ Wed Oct 11 17:13:15 1995 Andrew Cagney <cagney@kremvax> * 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. @@ -121,7 +315,7 @@ Wed Oct 11 12:10:26 1995 Andrew Cagney <cagney@kremvax> * 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 @@ -133,12 +327,12 @@ Tue Oct 10 15:42:59 1995 Andrew Cagney <cagney@kremvax> 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 @@ -152,7 +346,7 @@ Wed Oct 4 17:31:12 1995 Andrew Cagney <cagney@kremvax> 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. @@ -275,7 +469,7 @@ Fri Sep 8 09:51:03 1995 Michael Meissner <meissner@tiktok.cygnus.com> * 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. @@ -283,7 +477,7 @@ Wed Sep 6 13:25:42 1995 Andrew Cagney - aka Noid <cagney@kremvax> * 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) @@ -329,7 +523,7 @@ Tue Aug 22 09:31:18 1995 Michael Meissner <meissner@tiktok.cygnus.com> * 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). @@ -340,14 +534,14 @@ Sat Aug 19 09:05:32 1995 Andrew Cagney - aka Noid <cagney@kremvax> * 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 @@ -355,7 +549,7 @@ Thu Aug 17 14:29:18 1995 Andrew Cagney <cagney@kremvax> * 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. diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in index c5e9ff4..d92ca56 100644 --- a/sim/ppc/Makefile.in +++ b/sim/ppc/Makefile.in @@ -80,7 +80,11 @@ INCLUDES = -I. -I$(srcdir) $(LIB_INCLUDES) $(BFD_INCLUDES) $(GDB_INCLUDES) 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 @@ -128,7 +132,15 @@ CPU_H = \ 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 = \ @@ -139,35 +151,43 @@ BUILT_SRC = \ 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 \ @@ -177,6 +197,8 @@ LIB_OBJ = \ events.o \ devices.o \ device_tree.o \ + itable.o \ + mon.o \ semantics.o \ idecode.o \ psim.o @@ -192,7 +214,7 @@ run: psim 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) @@ -201,27 +223,29 @@ $(TARGETLIB): tmp-gencode $(LIB_OBJ) $(GDB_OBJ) # 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 @@ -240,6 +264,9 @@ device_tree.o: device_tree.c device_tree.h devices.h $(BASICS_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 @@ -249,47 +276,63 @@ ppc-config.h: $(CONFIG_FILE) 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 diff --git a/sim/ppc/README.psim b/sim/ppc/README.psim index f9a1486..89bf369 100644 --- a/sim/ppc/README.psim +++ b/sim/ppc/README.psim @@ -3,231 +3,250 @@ 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 ---------------------------------------------------------------- @@ -274,7 +293,3 @@ i486DX2/66 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 diff --git a/sim/ppc/bits.c b/sim/ppc/bits.c new file mode 100644 index 0000000..2424e85 --- /dev/null +++ b/sim/ppc/bits.c @@ -0,0 +1,27 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _BITS_C_ +#define _BITS_C_ + +#include "basics.h" + +#endif /* _BITS_C_ */ diff --git a/sim/ppc/build-psim b/sim/ppc/build-psim new file mode 100755 index 0000000..ea7318a --- /dev/null +++ b/sim/ppc/build-psim @@ -0,0 +1,155 @@ +#!/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 diff --git a/sim/ppc/core.c b/sim/ppc/core.c index a40128e..4acf0a3 100644 --- a/sim/ppc/core.c +++ b/sim/ppc/core.c @@ -42,7 +42,7 @@ struct _core_mapping { 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; @@ -130,12 +130,12 @@ core_executable(core *memory) 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) { @@ -154,7 +154,7 @@ new_core_mapping(attach_type 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); @@ -164,21 +164,21 @@ new_core_mapping(attach_type attach, 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 */ @@ -206,8 +206,8 @@ core_map_attach(core_map *access_map, /* 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; } } @@ -216,7 +216,7 @@ core_map_attach(core_map *access_map, 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 */ @@ -236,7 +236,7 @@ core_attach(core *memory, 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; @@ -244,7 +244,7 @@ core_attach(core *memory, 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; @@ -252,7 +252,7 @@ core_attach(core *memory, 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; @@ -320,7 +320,7 @@ core_map_read_buffer(core_map *map, if (mapping->reader != NULL) { if (mapping->reader(mapping->device, &byte, - mapping->address_space, + mapping->space, raddr - mapping->base, 1, /* nr_bytes */ 0, /*processor*/ @@ -357,7 +357,7 @@ core_map_write_buffer(core_map *map, if (mapping->writer != NULL) { if (mapping->writer(mapping->device, &byte, - mapping->address_space, + mapping->space, raddr - mapping->base, 1, /*nr_bytes*/ 0, /*processor*/ @@ -382,6 +382,7 @@ core_init_callback(const device *me, psim *system) { core *memory = (core*)me->data; + DTRACE_INIT(core); core_init(memory); } @@ -390,7 +391,7 @@ STATIC_INLINE_CORE void 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, @@ -398,11 +399,12 @@ core_attach_address_callback(const device *me, { 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, @@ -412,15 +414,16 @@ core_attach_address_callback(const device *me, 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); } @@ -428,8 +431,8 @@ core_dma_read_buffer_callback(const device *me, 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) { @@ -437,9 +440,10 @@ core_dma_write_buffer_callback(const device *me, 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); } @@ -463,7 +467,7 @@ static device_callbacks const core_callbacks = { 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); } diff --git a/sim/ppc/core_n.h b/sim/ppc/core_n.h index d4c54bc..8a80ac8 100644 --- a/sim/ppc/core_n.h +++ b/sim/ppc/core_n.h @@ -47,7 +47,7 @@ XCONCAT2(core_map_read_,N)(core_map *map, unsigned_N data; if (mapping->reader(mapping->device, &data, - mapping->address_space, + mapping->space, addr - mapping->base, sizeof(unsigned_N), /* nr_bytes */ processor, @@ -78,7 +78,7 @@ XCONCAT2(core_map_write_,N)(core_map *map, 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, diff --git a/sim/ppc/device_tree.c b/sim/ppc/device_tree.c index 78b6e1b..0d9f768 100644 --- a/sim/ppc/device_tree.c +++ b/sim/ppc/device_tree.c @@ -41,6 +41,14 @@ typedef enum { node_string } node_type; +static char *node_type_names[] = { + "any", + "device", + "integer", + "boolean", + "string", + NULL, +}; struct _device_tree { /* where i am */ @@ -89,6 +97,7 @@ typedef enum { 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) { @@ -139,13 +148,13 @@ device_tree_find_node(device_tree *root, 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; @@ -153,6 +162,7 @@ device_tree_find_node(device_tree *root, else return device_tree_find_node(child, path + name_len + 1, + full_path, type, action); } @@ -163,10 +173,15 @@ device_tree_find_node(device_tree *root, 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; @@ -180,14 +195,22 @@ INLINE_DEVICE_TREE device_tree * 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; } @@ -197,11 +220,18 @@ device_tree_add_device(device_tree *root, 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; } @@ -210,11 +240,18 @@ device_tree_add_integer(device_tree *root, 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; } @@ -223,11 +260,18 @@ device_tree_add_string(device_tree *root, 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; } @@ -236,11 +280,18 @@ device_tree_add_boolean(device_tree *root, 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; } @@ -248,9 +299,16 @@ INLINE_DEVICE_TREE device_tree * 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; } @@ -261,10 +319,16 @@ INLINE_DEVICE_TREE const device * 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; } @@ -272,10 +336,16 @@ INLINE_DEVICE_TREE signed_word 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; } @@ -283,10 +353,16 @@ INLINE_DEVICE_TREE const char * 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; } @@ -294,10 +370,16 @@ INLINE_DEVICE_TREE int 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; } @@ -308,9 +390,14 @@ STATIC_INLINE_DEVICE_TREE void 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); + } } @@ -318,7 +405,11 @@ INLINE_DEVICE_TREE void 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")); } @@ -363,10 +454,6 @@ device_tree_dump(device_tree *device, /* 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, '@'); \ @@ -377,7 +464,7 @@ device_tree_dump(device_tree *device, #define SCAN_U(START, END, COUNT, U) \ do { \ - *U = strtouq(START, &END, 0); \ + *U = strtoul(START, &END, 0); \ if (START == END) \ return COUNT; \ COUNT++; \ @@ -397,7 +484,7 @@ do { \ 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; \ @@ -407,6 +494,8 @@ do { \ *chp = *END; \ chp += 1; \ END += 1; \ + if ((SIZE) <= ((END) - (START))) \ + return COUNT; /* overflow */ \ } \ *chp = '\0'; \ if (START == END) \ @@ -465,21 +554,21 @@ scand_uw_uw_u(const char *name, 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; diff --git a/sim/ppc/device_tree.h b/sim/ppc/device_tree.h index d8e5481..bcd9bea 100644 --- a/sim/ppc/device_tree.h +++ b/sim/ppc/device_tree.h @@ -110,7 +110,11 @@ INLINE_DEVICE_TREE void device_tree_dump 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, @@ -135,11 +139,11 @@ INLINE_DEVICE_TREE int scand_uw_uw_u 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); diff --git a/sim/ppc/devices.c b/sim/ppc/devices.c index 6b4d940..c0813d6 100644 --- a/sim/ppc/devices.c +++ b/sim/ppc/devices.c @@ -59,7 +59,7 @@ generic_init_callback(const device *me, me->parent->callback->attach_address(me->parent, me->name, attach_callback, - 0 /*address_space*/, + 0 /*space*/, addr, nr_bytes, access_read_write, @@ -81,7 +81,7 @@ INLINE_DEVICES void 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, @@ -94,7 +94,7 @@ INLINE_DEVICES void 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, @@ -106,7 +106,7 @@ unimp_device_detach_address(const device *me, 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, @@ -119,7 +119,7 @@ unimp_device_io_read_buffer(const device *me, 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, @@ -132,7 +132,7 @@ unimp_device_io_write_buffer(const device *me, INLINE_DEVICES unsigned unimp_device_dma_read_buffer(const device *me, void *target, - int address_space, + int space, unsigned_word addr, unsigned nr_bytes) { @@ -143,7 +143,7 @@ unimp_device_dma_read_buffer(const device *me, 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) @@ -213,15 +213,16 @@ ignore_device_init(const device *me, 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); } @@ -229,39 +230,42 @@ pass_device_attach_address(const device *me, 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); } @@ -341,7 +345,7 @@ typedef enum { 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, @@ -349,9 +353,7 @@ console_io_read_buffer_callback(const device *me, { 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 */ @@ -416,7 +418,7 @@ console_io_read_buffer_callback(const device *me, 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, @@ -424,10 +426,7 @@ console_io_write_buffer_callback(const device *me, { 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: @@ -437,8 +436,7 @@ console_io_write_buffer_callback(const device *me, 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; @@ -472,6 +470,7 @@ static device_callbacks const console_callbacks = { STATIC_INLINE_DEVICES const device * console_create(const char *name, + const char *full_name, const device *parent) { /* create the descriptor */ @@ -485,6 +484,7 @@ console_create(const char *name, /* insert into the device tree along with its address info */ return device_create_from(name, + full_name, console, /* data */ &console_callbacks, parent); @@ -507,16 +507,14 @@ console_create(const char *name, 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; @@ -527,17 +525,15 @@ icu_io_read_buffer_callback(const device *me, 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 */ @@ -575,12 +571,13 @@ static device_callbacks const icu_callbacks = { 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; } @@ -589,12 +586,13 @@ halt_io_read_buffer_callback(const device *me, 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; } @@ -630,7 +628,8 @@ register_init_callback(const device *me, 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); @@ -702,6 +701,7 @@ vm_init_callback(const device *me, psim *system) { vm_device *vm = (vm_device*)me->data; + DTRACE_INIT(vm); /* revert the stack/heap variables to their defaults */ vm->stack_lower_limit = vm->stack_bound; @@ -724,14 +724,15 @@ vm_init_callback(const device *me, 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; @@ -799,12 +800,13 @@ add_vm_space(const device *me, 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; @@ -817,15 +819,16 @@ vm_io_read_buffer_callback(const device *me, 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*/); } @@ -873,7 +876,8 @@ static device_callbacks const vm_callbacks = { 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; @@ -887,6 +891,7 @@ vea_vm_create(const char *name, /* insert in the tree including the buffer */ return device_create_from(name, + full_name, vm, /* data */ &vm_callbacks, parent); @@ -905,9 +910,20 @@ memory_init_callback(const device *me, 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, @@ -936,24 +952,6 @@ static device_callbacks const memory_callbacks = { }; -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); -} - - /* IOBUS device: iobus@<address> @@ -963,7 +961,7 @@ STATIC_INLINE_DEVICES void 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, @@ -974,8 +972,8 @@ iobus_attach_address_callback(const device *me, 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) @@ -984,7 +982,7 @@ iobus_attach_address_callback(const device *me, me->parent->callback->attach_address(me->parent, me->name, type, - 0 /*address_space*/, + 0 /*space*/, iobus_addr + addr, nr_bytes, access, @@ -1052,9 +1050,11 @@ file_init_callback(const device *me, 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) @@ -1067,14 +1067,17 @@ file_init_callback(const device *me, 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 */ @@ -1115,6 +1118,7 @@ STATIC_INLINE_DEVICES void 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; @@ -1184,12 +1188,10 @@ static device_callbacks const sim_callbacks = { 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; @@ -1208,17 +1210,17 @@ update_device_tree_for_section(bfd *abfd, /* 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; @@ -1251,7 +1253,7 @@ update_device_tree_for_section(bfd *abfd, } if (me->parent->callback->dma_write_buffer(me->parent, section_init, - 0 /*address_space*/, + 0 /*space*/, section_vma, section_size, 1 /*violate_read_only*/) @@ -1268,9 +1270,10 @@ binary_init_callback(const device *me, { 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); @@ -1291,7 +1294,7 @@ binary_init_callback(const device *me, /* and the data sections */ bfd_map_over_sections(image, - update_device_tree_for_section, + update_for_binary_section, (PTR)me); bfd_close(image); @@ -1371,18 +1374,17 @@ write_stack_arguments(psim *system, 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, @@ -1402,6 +1404,8 @@ write_stack_arguments(psim *system, 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 @@ -1500,10 +1504,16 @@ stack_ioctl_callback(const device *me, 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")); } @@ -1529,6 +1539,7 @@ static device_callbacks const stack_callbacks = { typedef const device *(device_creator) (const char *name, + const char *full_name, const device *parent); typedef struct _device_descriptor device_descriptor; @@ -1540,7 +1551,7 @@ struct _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 }, @@ -1559,6 +1570,7 @@ static device_descriptor devices[] = { INLINE_DEVICES const device * device_create(const char *name, + const char *full_name, const device *parent) { device_descriptor *device; @@ -1571,9 +1583,10 @@ device_create(const char *name, && (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); @@ -1585,12 +1598,14 @@ device_create(const char *name, 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; diff --git a/sim/ppc/devices.h b/sim/ppc/devices.h index df02288..fd22a54 100644 --- a/sim/ppc/devices.h +++ b/sim/ppc/devices.h @@ -79,6 +79,10 @@ typedef void (device_init_callback) (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: @@ -160,17 +164,27 @@ typedef void (device_init_callback) 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, @@ -179,27 +193,46 @@ typedef unsigned (device_io_read_buffer_callback) 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: @@ -282,7 +315,8 @@ typedef struct _device_callbacks { /* 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; @@ -293,12 +327,14 @@ struct _device { 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); diff --git a/sim/ppc/system.h b/sim/ppc/emul_netbsd.h index 709d5c5..3bdb590 100644 --- a/sim/ppc/system.h +++ b/sim/ppc/emul_netbsd.h @@ -19,15 +19,9 @@ */ -#ifndef _SYSTEM_H_ -#define _SYSTEM_H_ +#ifndef _EMUL_NETBSD_H_ +#define _EMUL_NETBSD_H_ -#ifndef INLINE_SYSTEM -#define INLINE_SYSTEM -#endif - -INLINE_SYSTEM void system_call -(cpu *processor, - unsigned_word cia); +extern emulation emul_netbsd; #endif diff --git a/sim/ppc/gen.c b/sim/ppc/gen.c deleted file mode 100644 index 76f1bcb..0000000 --- a/sim/ppc/gen.c +++ /dev/null @@ -1,3323 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -/* 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; -} diff --git a/sim/ppc/os_emul.c b/sim/ppc/os_emul.c new file mode 100644 index 0000000..844b77f --- /dev/null +++ b/sim/ppc/os_emul.c @@ -0,0 +1,49 @@ +/* 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_ */ diff --git a/sim/ppc/os_emul.h b/sim/ppc/os_emul.h new file mode 100644 index 0000000..1febef8 --- /dev/null +++ b/sim/ppc/os_emul.h @@ -0,0 +1,41 @@ +/* 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 diff --git a/sim/ppc/ppc-cache-rules b/sim/ppc/ppc-cache-rules new file mode 100644 index 0000000..9dad017 --- /dev/null +++ b/sim/ppc/ppc-cache-rules @@ -0,0 +1,85 @@ +# +# 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) diff --git a/sim/ppc/ppc-endian.c b/sim/ppc/ppc-endian.c index 1e51bdf..ec90bb7 100644 --- a/sim/ppc/ppc-endian.c +++ b/sim/ppc/ppc-endian.c @@ -33,7 +33,7 @@ #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 @@ -67,7 +67,7 @@ endian_##NAME##_##BYTE_SIZE(unsigned_##BYTE_SIZE raw_in) \ return raw_in; \ } \ else { \ - SWAP_##BYTE_SIZE(return, raw_in); \ + SWAP_##BYTE_SIZE(return,raw_in); \ } \ } #endif diff --git a/sim/ppc/ppc-opcode-complex b/sim/ppc/ppc-opcode-complex new file mode 100644 index 0000000..0435846 --- /dev/null +++ b/sim/ppc/ppc-opcode-complex @@ -0,0 +1,95 @@ +# +# This file is part of the program psim. +# +# Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Instruction decode: +# +# The table that follows is used by gen to construct a decision tree +# that can identify each possible instruction. Gen then outputs this +# decision tree as (according to config) a table or switch statement +# as the function idecode. +# +# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS +# determines of the semantic functions themselves should be expanded +# in a similar way. +# +# The table contains the following entries: +# +# <valid> +# +# Must be 1 for the entry to be considered. The last entry must be +# zero. +# +# <first> +# <last> +# +# Range of bits (within the instruction) that should be searched for +# an instruction field. Within such ranges, gen looks for opcodes +# (constants), registers (strings) and reserved bits (slash) and +# according to the rules that follows includes or excludes them from +# a possible instruction field. +# +# <force_first> +# <force_last> +# +# If an instructioin field was found, enlarge the field size so that +# it is forced to at least include bits starting from <force_first> +# (<force_last>). To stop this occuring, use <force_first> = <last> +# + 1 and <force_last> = <first> - 1. +# +# <force_slash> +# +# Treat `/' fields as a constant instead of variable when looking for +# an instruction field. +# +# <force_expansion> +# +# Treat any contained register (string) fields as constant when +# determining the instruction field. For the instruction decode (and +# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of +# what would otherwize be non constant bits of an instruction. +# +# <use_switch> +# +# Should this table be expanded using a switch statement (val 1) and +# if so, should it be padded with entries so as to force the compiler +# to generate a jump table (val 2). +# +# <special_mask> +# <special_value> +# <special_rule> +# +# Special rule to fine tune how specific (or groups) of instructions +# are expanded. The applicability of the rule is determined by +# +# <special_mask> != 0 && (instruction> & <special_mask>) == <special_value> +# +# Where <instruction> is obtained by looking only at constant fields +# with in an instructions spec. When determining an expansion, the +# rule is only considered when a node contains a single instruction. +# <special_rule> can be any of: +# +# 0: for this instruction, expand by earlier rules +# 1: expand bits <force_low> .. <force_hi> only +# 2: boolean expansion of only zero/non-zero cases +# + 0: 5: 0: 5:0:: 0:0x00000000:0x00000000:0 +21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0 + 6: 9: 6: 9:0:BO: 0:0xfc000000:0x40000000:1 +11:15:11:15:0:RA: 0:0xfc000000:0x38000000:2 +11:15:11:15:0:RA: 0:0xfc000000:0x3c000000:2 diff --git a/sim/ppc/ppc-opcode-simple b/sim/ppc/ppc-opcode-simple new file mode 100644 index 0000000..b3a1316 --- /dev/null +++ b/sim/ppc/ppc-opcode-simple @@ -0,0 +1,92 @@ +# +# 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 diff --git a/sim/ppc/spa-reporter.c b/sim/ppc/spa-reporter.c new file mode 100644 index 0000000..9a7dd29 --- /dev/null +++ b/sim/ppc/spa-reporter.c @@ -0,0 +1,758 @@ +/* + * 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; +} diff --git a/sim/ppc/spa-system-calls.c b/sim/ppc/spa-system-calls.c new file mode 100644 index 0000000..a344595 --- /dev/null +++ b/sim/ppc/spa-system-calls.c @@ -0,0 +1,499 @@ +/* + * 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 *); + diff --git a/sim/ppc/spa-system-calls.h b/sim/ppc/spa-system-calls.h new file mode 100644 index 0000000..1ee9c1e --- /dev/null +++ b/sim/ppc/spa-system-calls.h @@ -0,0 +1,119 @@ +/* + * 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 diff --git a/sim/ppc/std-config.h b/sim/ppc/std-config.h index 07018bf..9e06267 100644 --- a/sim/ppc/std-config.h +++ b/sim/ppc/std-config.h @@ -29,32 +29,52 @@ 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 @@ -68,6 +88,7 @@ extern int current_target_byte_order; #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 @@ -85,10 +106,13 @@ extern int current_target_byte_order; 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 \ @@ -170,6 +194,7 @@ extern int current_environment; #ifndef WITH_ALIGNMENT #define WITH_ALIGNMENT 0 #endif + extern int current_alignment; #define CURRENT_ALIGNMENT (WITH_ALIGNMENT \ ? WITH_ALIGNMENT \ @@ -210,254 +235,16 @@ extern int current_floating_point; #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: @@ -486,12 +273,14 @@ extern int current_floating_point; 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 */ @@ -512,86 +301,92 @@ extern int current_floating_point; #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 @@ -610,163 +405,14 @@ extern int current_floating_point; 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 */ diff --git a/sim/ppc/system.c b/sim/ppc/system.c deleted file mode 100644 index 25ea8eb..0000000 --- a/sim/ppc/system.c +++ /dev/null @@ -1,720 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -#ifndef _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_ */ diff --git a/sim/ppc/table.h b/sim/ppc/table.h new file mode 100644 index 0000000..1fe29d2 --- /dev/null +++ b/sim/ppc/table.h @@ -0,0 +1,49 @@ +/* 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); |