New simulator changes from Andrew

This commit is contained in:
Michael Meissner
1996-07-23 15:42:42 +00:00
parent 856bcbcbbc
commit 30c87b55ec
50 changed files with 11297 additions and 6935 deletions

View File

@@ -51,6 +51,7 @@ debug.c
debug.h
device.c
device.h
device.maybe
device_table.c
device_table.h
dgen.c
@@ -68,9 +69,24 @@ emul_unix.c
emul_unix.h
events.c
events.h
filter.c
filter.h
filter_filename.c
filter_filename.h
gen-icache.c
gen-icache.h
gen-idecode.c
gen-idecode.h
gen-itable.c
gen-itable.h
gen-model.c
gen-model.h
gen-semantics.c
gen-semantics.h
gen-support.c
gen-support.h
hw_com.c
hw_core.c
hw_cpu.c
hw_cpu.h
hw_disk.c
@@ -92,10 +108,17 @@ idecode_branch.h
idecode_expression.h
idecode_fields.h
igen.c
igen.h
inline.c
inline.h
interrupts.c
interrupts.h
ld-cache.c
ld-cache.h
ld-decode.c
ld-decode.h
ld-insn.c
ld-insn.h
lf.c
lf.h
main.c
@@ -112,6 +135,7 @@ ppc-cache-rules
ppc-instructions
ppc-opcode-complex
ppc-opcode-flat
ppc-opcode-jump
ppc-opcode-simple
ppc-opcode-stupid
ppc-opcode-test-1

View File

@@ -1,3 +1,255 @@
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* gen-semantics.c: Make the my_index variable a macro MY_INDEX.
* ppc-instructions: Adjust so that references are to MY_INDEX and
not my_index.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* gen-idecode.c: Output the complete run_until_stop function
instead of just the code to handle a single instruction issue.
* : Have the generated idecode.c include inline.c (instead of psim.c).
* std-config.h: Change psim.c so that it isn't inlined (as this is
no longer needed).
* psim.c (run_until_stop): Delete the old run_until_stop function
instead calling the idecode_run and idecode_run_until_stop
functions that gen-idecode.c is now creating.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* dgen.c: Maintenance - update to use new features found in lf.c.
* filter_filename.c (filter_filename): Maintenance - make the
string constant.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* debug.c (TRACE, ITRACE, DTRACE): Have GCC instead of CPP
eliminate trace statements.
* debug.c: Change trace format so that it is consistent
(file:line-nr) with CC's error output.
* gen-itable.c (itable_c_insn): Add the source file name and
source line number to the instruction's informational entry.
* debug.c (ITRACE): Use the itable (and my_index) to get the
current instructions name and source line number.
* gen-semantics.c, gen-icache.c: Adjust generated ITRACE calls to
match new interface.
* emul_bugapi.c (emul_bugapi_instruction_call): Adjust
corresponding call to ITRACE so that it still matches.
* idecode_expression.h (ALU_END, CR0_COMPARE): Use TRACE instead
of ITRACE. The CPP line directives would have previously set the
line-nr and file name so ITRACE isn't needed.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* gen-idecode.c (print_jump_until_stop_body): New function and
idecode generation option. Instead of generating and calling
separate functions containing the semantic and icache code
generate a single monolythic function and use goto's (and GCC's
indirect jump) to move between code blocks.
* Makefile.in: Add sim_jump flag to those passed to igen.
* configure.in: New option --enable-sim-jump (default disabled)
* ppc-instructions: Eliminate any uses of labels and goto's.
These result in duplicate declarations when a single flat function
is being create.
* ppc-opcode-jump: New file. Set of opcode rules useful when
testing jumping idecodes.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* gen-idecode.c: Optionally include the semantic code for an
instruction in the function that is doing the decoding.
* igen.c: Add option (-C) to generate semantics in the instruction
decode functions.
* configure.in (--enable-sim-icache): Accept an option list such
as 1024,define. Add a new choice to the list - semantic - which
will cause igen to generate instruction decode functions that
include the corresponding semantic code.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* configure.in: New option --enable-sim-line-nr (default enabled).
Enable/disable the inclusion of CPP line directives in the
generated files. Such directives refer back to the source files
used when generating the simulator code.
* Makefile.in (sim_line_nr): Pass to igen.
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* igen.c (main): Revamp the options so that more letters are
available.
* configure.in: Adjust to match igen's revamped options
Sun Jul 21 21:18:05 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* Makefile.in (pk.h, hw.h): Rewrite depenencies for hw.h (etc) so
that they use the same technique as igen (ie a dummy targets
tmp-pk and tmp-hw are created).
Mon Jun 24 22:28:00 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* Makefile.in (BUILD_CFLAGS): Include WARNING_CFLAGS.
Wed Jun 19 21:45:28 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* ld-cache.[hc], ld-decode.[hc], ld-insn.[hc]: New files. Separate
out the loading of each of the tables from the rest of igen.
* Makefile.in: Adjust.
* igen.c: Adjust.
* gen-icache.[hc], gen-idecode.[hc], gen-itable.[hc],
gen-model.[hc], gen-semantics.[hc]: New files. Separate out the
code creating each separate set of generated files.
* Makefile.in: Adjust.
* igen.c: Adjust.
* gen-support.[ch]: New files. Output the support functions (found
in the ppc-instructions file) into a separate file.
* Makefile.in: Add.
* inline.h, inline.c: Add.
* std-config.h: Add.
* ld-cache.c: Re-design the cache table format.
* ppc-cache-rules: Update to new format.
* ld-decode.c: Re-design the decode table format.
* ppc-opcode-simple: Update to new format
* ppc-opcode-complex: Ditto
* ppc-opcode-flat: Ditto
* filter.h, filter.c: New files. Separate the opcode filter table
reading code from the rest of igen.c. Re-design the filter so that
it works inclusivly not exclusivly.
* igen.c: Remove the opcode filter table loading code.
* Makefile.in (filter.o): Adjust
* configure.in: Adjust filter flag so that default includes 32bit
and floating point.
* ppc-instructions: Clean up filter fields so that only in use
entries are specifed (ie delete `be').
* misc.c (name2i, i2name): New function. Map between a string and
an integer value.
Mon Jun 17 20:08:03 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* sim_calls.c (sim_close): If simulator not created, skip printing
of run information.
Mon Jun 17 20:08:03 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* registers.c (register_description): Typo, insns not insn.
* ppc-instructions (model_get_number_of_stalls): New model function,
returns number of stalls for the specified processor.
* psim.c (psim_read_register): Add call to new function
model_get_number_of_stalls().
* ppc-instructions (model_get_number_of_cycles): New model function,
returns number of stalls for the specified processor.
* psim.c (psim_read_register): Add call to new function
model_get_number_of_cycles().
Fri Jun 14 00:11:56 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* device_table.h: Don't pass the parent device into a devices
create function. This makes the create function consistent with
the documentation.
* device.c (device_template_create_device): Ditto
* hw_pal.c (hw_pal_create): Ditto
* hw_core.c (hw_core_create): Ditto
* hw_vm.c (hw_vm_create): Ditto
* hw_disk.c (hw_disk_create): Ditto
* hw_nvram.c (hw_nvram_create): Ditto
* hw_memory.c (hw_memory_create): Ditto
* hw_cpu.c (hw_cpu_create): Ditto.
* device.c (split_find_device): Allow a null initial parent device.
(device_template_create_device): Ditto.
* device.c (device_create_from): Make local (static) only used
within device.c.
* device_table.h: typedef device_callbacks moved here (from
device.h) where it belongs.
* hw_core.c: New file. Implements just the core device using the
core object.
* corefile.c: Moved all core device functions into the new
hw_core.c file. core_device_create() disapears.
* psim.c (psim_tree): Use device_tree_add_parsed() to create the
core device.
Thu Jun 13 00:09:29 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* hw_init.c: Correct typo in comment.
* corefile.c (core_init): Remove any remaining references to a
default map.
(core_map_find_mapping): Ditto.
Wed Jun 12 22:30:32 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* corefile.c (core_init): Make function global so that other
devices are able to use the full core object.
* corefile.c (core_create, core_from_device): Break core_create
into two functions. The first creates a core object, the second
returns the core object associated with a core device.
* corefile.c (core_device_create): Use core_create to make the
core object.
* psim.c (psim_create): Use core_from_device() instead of
core_create().
* device.c (device_template_create_device): Make static as only
needed by functions internal to device.c.
Fri Jun 7 23:47:18 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* ppc-opcode-test-2: Remove description of fields.
* ppc-opcode-complex: Ditto
* ppc-opcode-flat: Ditto
* ppc-opcode-simple: Ditto
* ppc-opcode-stupid: Ditto
* ppc-opcode-test-1: Ditto
* ppc-cache-rules: Ditto
* igen.c: Add description of files as a comment at the front.
Wed Jun 26 12:50:33 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* configure.in: Check for whether the termios and termio
structures are really defined, and whether or not, they define the
c_line field.
* configure: Regenerate.
* Makefile.in ({,TERMIO_}CFLAGS): Add TERMIO_CFLAGS options set by
configure.
* emul_unix.c: Various changes to allow for building on systems
with different termio and termios structures. If host has both
termio and termios, just use termios. No longer include
sys/ioctl.h.
Wed Jun 26 12:26:55 1996 Jason Molenda (crash@godzilla.cygnus.co.jp)
* Makefile.in (bindir, libdir, datadir, mandir, infodir, includedir,
@@ -7,6 +259,13 @@ Wed Jun 26 12:26:55 1996 Jason Molenda (crash@godzilla.cygnus.co.jp)
(AC_PROG_INSTALL): Added.
* configure: Rebuilt.
Wed Jun 5 23:53:42 1996 Andrew Cagney <cagney@kremvax.highland.com.au>
* corefile.h: Rewrite documentation so that it can be extracted and
converted into texinfo (and hence ready for translation into html,
tex or nroff).
* device.h: Ditto
Thu Jun 6 09:52:37 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* hw_disk.c (SEEK_SET): If SEEK_SET is not defined, define as 0.

View File

@@ -84,6 +84,7 @@ RESERVED_CFLAGS = @sim_reserved@
MONITOR_CFLAGS = @sim_monitor@
MODEL_CFLAGS = @sim_model@ @sim_default_model@ @sim_model_issue@
STDIO_CFLAGS = @sim_stdio@
TERMIO_CFLAGS = @sim_termio@
WARNING_CFLAGS = @sim_warnings@
CONFIG_CFLAGS = $(BSWAP_CFLAGS) \
$(ENDIAN_CFLAGS) \
@@ -101,24 +102,28 @@ CONFIG_CFLAGS = $(BSWAP_CFLAGS) \
$(RESERVED_CFLAGS) \
$(MONITOR_CFLAGS) \
$(MODEL_CFLAGS) \
$(STDIO_CFLAGS)
$(STDIO_CFLAGS) \
$(TERMIO_CFLAGS)
STD_CFLAGS = $(CFLAGS) $(INLINE_CFLAGS) $(CONFIG_CFLAGS) $(WARNING_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES)
NOWARN_CFLAGS = $(CFLAGS) $(INLINE_CFLAGS) $(CONFIG_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES)
BUILD_CFLAGS = -O $(INCLUDES)
BUILD_CFLAGS = -O $(INCLUDES) $(WARNING_CFLAGS)
BUILD_LDFLAGS =
CONFIG_FILE = @sim_config@
IGEN_OPCODE_RULES = @sim_opcode@
IGEN_DUPLICATE = @sim_dup@
IGEN_JUMP = @sim_jump@
IGEN_FILTER = @sim_filter@
IGEN_ICACHE = @sim_icache@
IGEN_SMP = @sim_igen_smp@
IGEN_LINE_NR = @sim_line_nr@
DGEN_FLAGS = @sim_switch@
HDEFINES = @HDEFINES@
TDEFINES =
IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER) $(IGEN_ICACHE)
IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_JUMP) $(IGEN_FILTER) $(IGEN_ICACHE) $(IGEN_SMP) $(IGEN_LINE_NR)
.NOEXPORT:
MAKEOVERRIDES=
@@ -170,13 +175,13 @@ CPU_H = \
cpu.h \
$(BASICS_H) \
$(REGISTERS_H) \
$(IDECODE_H) \
device.h \
corefile.h \
vm.h \
events.h \
interrupts.h \
psim.h \
icache.h \
itable.h \
mon.h \
model.h
@@ -199,12 +204,14 @@ INLINE = \
inline.c
BUILT_SRC_WO_CONFIG = \
icache.h \
icache.h icache.c \
support.h support.c \
idecode.h idecode.c \
semantics.h semantics.c \
itable.h itable.c \
spreg.h spreg.c \
model.h model.c \
support.h support.c \
pk.h \
hw.h hw.c \
filter_host.c
@@ -273,12 +280,14 @@ LIB_OBJ = \
device_table.o \
itable.o \
mon.o \
icache.o \
semantics.o \
idecode.o \
support.o \
psim.o \
options.o \
$(PACKAGES) \
$(HW)
$(PACKAGE_OBJ) \
$(HW_OBJ)
GDB_OBJ = sim_calls.o
@@ -294,9 +303,10 @@ HW_SRC = \
hw_register.c \
hw_vm.c \
hw_init.c \
hw_core.c \
hw_pal.c
HW = \
HW_OBJ = \
hw_cpu.o \
hw_memory.o \
hw_nvram.o \
@@ -307,12 +317,13 @@ HW = \
hw_register.o \
hw_vm.o \
hw_init.o \
hw_core.o \
hw_pal.o
PACKAGE_SRC = \
pk_disklabel.c
PACKAGES = \
PACKAGE_OBJ = \
pk_disklabel.o
@@ -323,7 +334,7 @@ run: psim
rm -f run
ln psim run
$(TARGETLIB): tmp-igen tmp-dgen $(HW) $(LIB_OBJ) $(GDB_OBJ)
$(TARGETLIB): tmp-igen tmp-dgen tmp-hw tmp-pk $(LIB_OBJ) $(GDB_OBJ)
rm -f $(TARGETLIB)
$(AR) $(AR_FLAGS) $(TARGETLIB) $(LIB_OBJ) $(GDB_OBJ)
$(RANLIB) $(TARGETLIB)
@@ -382,6 +393,11 @@ cap.o: cap.c cap.h $(BASICS_H)
semantics.o: semantics.c semantics.h $(CPU_H) $(IDECODE_H)
$(CC) -c $(NOWARN_CFLAGS) $<
icache.o: icache.c icache.h $(IDECODE_H) $(CPU_H)
$(CC) -c $(NOWARN_CFLAGS) $<
support.o: support.c support.h $(IDECODE_H) $(CPU_H)
itable.o: itable.c itable.h
mon.o: mon.c $(CPU_H)
@@ -401,28 +417,32 @@ ppc-config.h: $(CONFIG_FILE)
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.h -hp tmp-spreg.h \
-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
tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/../../move-if-change tmp-ld-decode tmp-ld-cache tmp-ld-insn tmp-filter
./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 itable.h -T tmp-itable.h \
-n itable.c -t tmp-itable.c \
-n model.h -M tmp-model.h \
-n model.c -m tmp-model.c
-n icache.h -hc tmp-icache.h \
-n icache.c -c tmp-icache.c \
-n semantics.h -hs tmp-semantics.h \
-n semantics.c -s tmp-semantics.c \
-n idecode.h -hd tmp-idecode.h \
-n idecode.c -d tmp-idecode.c \
-n itable.h -ht tmp-itable.h \
-n itable.c -t tmp-itable.c \
-n model.h -hm tmp-model.h \
-n model.c -m tmp-model.c \
-n support.h -hf tmp-support.h \
-n support.c -f tmp-support.c
$(srcdir)/../../move-if-change tmp-icache.h icache.h
$(srcdir)/../../move-if-change tmp-icache.c icache.c
$(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
@@ -431,20 +451,22 @@ tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/.
$(srcdir)/../../move-if-change tmp-itable.c itable.c
$(srcdir)/../../move-if-change tmp-model.h model.h
$(srcdir)/../../move-if-change tmp-model.c model.c
$(srcdir)/../../move-if-change tmp-support.h support.h
$(srcdir)/../../move-if-change tmp-support.c support.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-igen tmp-dgen
itable.h itable.c icache.h idecode.h idecode.c semantics.h semantics.c model.h model.c: tmp-igen
itable.h itable.c icache.h icache.c idecode.h idecode.c semantics.h semantics.c model.h model.c support.h support.c: tmp-igen
spreg.h spreg.c: tmp-dgen
dgen: dgen.o table.o lf.o misc.o filter_host.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -o dgen dgen.o table.o lf.o misc.o filter_host.o $(BUILD_LIBS)
igen: igen.o table.o lf.o misc.o filter_host.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o table.o lf.o misc.o filter_host.o $(BUILD_LIBS)
igen: igen.o table.o lf.o misc.o filter_host.o ld-decode.o ld-cache.o filter.o ld-insn.o gen-model.o gen-itable.o gen-icache.o gen-semantics.o gen-idecode.o gen-support.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o table.o lf.o misc.o filter_host.o ld-decode.o ld-cache.o filter.o ld-insn.o gen-model.o gen-itable.o gen-icache.o gen-semantics.o gen-idecode.o gen-support.o $(BUILD_LIBS)
filter_host.c: filter_filename.c
cat $(srcdir)/filter_filename.c > filter_host.c
@@ -458,36 +480,76 @@ table.o: table.c misc.h filter_filename.h lf.h table.h
lf.o: lf.c misc.h filter_filename.h lf.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/lf.c
filter.o: filter.c misc.h lf.h table.h filter.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/filter.c
tmp-filter: filter.c misc.h misc.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-filter -DMAIN $(srcdir)/filter.c misc.o $(BUILD_LIBS)
ld-decode.o: ld-decode.c misc.h lf.h table.h ld-decode.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/ld-decode.c
tmp-ld-decode: ld-decode.o misc.o lf.o table.o filter_host.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-decode -DMAIN $(srcdir)/ld-decode.c misc.o lf.o table.o filter_host.o $(BUILD_LIBS)
ld-cache.o: ld-cache.c misc.h lf.h table.h ld-cache.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/ld-cache.c
tmp-ld-cache: ld-cache.o misc.o lf.o table.o filter_host.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-cache -DMAIN $(srcdir)/ld-cache.c misc.o lf.o table.o filter_host.o $(BUILD_LIBS)
ld-insn.o: ld-insn.c misc.h lf.h table.h ld-insn.h ld-decode.h igen.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/ld-insn.c
tmp-ld-insn: ld-insn.o misc.o lf.o table.o ld-decode.o filter_host.o filter.o
$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-insn -DMAIN $(srcdir)/ld-insn.c misc.o lf.o table.o ld-decode.o filter_host.o filter.o $(BUILD_LIBS)
gen-model.o: gen-model.c misc.h lf.h table.h gen-model.h ld-decode.h igen.h ld-insn.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-model.c
gen-itable.o: gen-itable.c misc.h lf.h table.h gen-itable.h ld-decode.h igen.h ld-insn.h igen.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-itable.c
gen-icache.o: gen-icache.c misc.h lf.h table.h gen-icache.h ld-decode.h igen.h ld-insn.h gen-semantics.h gen-idecode.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-icache.c
gen-semantics.o: gen-semantics.c misc.h lf.h table.h gen-semantics.h ld-decode.h igen.h ld-insn.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-semantics.c
gen-idecode.o: gen-idecode.c misc.h lf.h table.h gen-idecode.h gen-icache.h gen-semantics.h ld-decode.h igen.h ld-insn.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-idecode.c
gen-support.o: gen-support.c misc.h lf.h table.h gen-support.h ld-decode.h igen.h ld-insn.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-support.c
dgen.o: dgen.c misc.h filter_filename.h lf.h table.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/dgen.c
igen.o: igen.c misc.h filter_filename.h lf.h table.h
igen.o: igen.c misc.h filter_filename.h lf.h table.h ld-decode.h ld-cache.h ld-insn.h filter.h gen-model.h gen-itable.h gen-icache.h gen-idecode.h gen-semantics.h gen-support.h igen.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/igen.c
misc.o: misc.c misc.h filter_filename.h
$(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/misc.c
# With out this #, make thinks that misc.o doesn't have a rule
# real hardware
hw.h: Makefile
tmp-hw: Makefile $(HW_SRC) $(srcdir)/../../move-if-change
(cd $(srcdir); ls $(HW_SRC)) \
| sed -e 's/^.*\(hw_.*\)\.c/\1/' \
-e 's/^/extern const device_descriptor /' \
-e 's/$$/_device_descriptor\[\];/' \
> tmp-hw.h
mv tmp-hw.h hw.h
hw.c: Makefile
(cd $(srcdir); ls $(HW_SRC)) \
| sed -e 's/^.*\(hw_.*\)\.c/\1/' \
-e 's/^/ /' \
-e 's/$$/_device_descriptor,/' \
> tmp-hw.c
mv tmp-hw.c hw.c
$(srcdir)/../../move-if-change tmp-hw.h hw.h
$(srcdir)/../../move-if-change tmp-hw.c hw.c
touch tmp-hw
hw_cpu.o: hw_cpu.c $(DEVICE_TABLE_H)
hw_memory.o: hw_memory.c $(DEVICE_TABLE_H)
hw_nvram.o: hw_nvram.c $(DEVICE_TABLE_H)
hw_iobus.o: hw_iobus.c $(DEVICE_TABLE_H)
hw_core.o: hw_core.c $(DEVICE_TABLE_H)
hw_pal.o: hw_pal.c $(DEVICE_TABLE_H)
hw_htab.o: hw_htab.c $(DEVICE_TABLE_H)
hw_disk.o: hw_disk.c $(DEVICE_TABLE_H) pk.h
@@ -498,18 +560,22 @@ hw_init.o: hw_init.c $(DEVICE_TABLE_H)
# ignore this line, it stops make from getting confused
# real packages
pk.h: Makefile
tmp-pk: Makefile $(PACKAGE_SRC) $(srcdir)/../../move-if-change
(cd $(srcdir); ls $(PACKAGE_SRC)) \
| sed -e 's/^pk_\(.*\)\.c/\1/' \
-e 's/^/extern package_create_instance_callback pk_/' \
-e 's/$$/_create_instance;/' \
> tmp-pk.h
mv tmp-pk.h pk.h
$(srcdir)/../../move-if-change tmp-pk.h pk.h
touch tmp-pk
pk_disklabel.o: pk.h $(DEVICE_TABLE_H)
# ignore this line, it stops make from getting confused
tags etags: TAGS
TAGS: $(BUILT_SRC)

View File

2129
sim/ppc/configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.3)dnl
AC_PREREQ(2.5)dnl
AC_INIT(Makefile.in)
AC_PROG_INSTALL
AC_PROG_CC
# Put a plausible default for CC_FOR_BUILD in Makefile.
@@ -34,6 +35,17 @@ if test x"$silent" != x"yes" && test x"$sim_warnings" != x""; then
echo "Setting warning flags = $sim_warnings" 6>&1
fi],[sim_warnings=""])dnl
AC_ARG_ENABLE(sim-line-nr,
[ --enable-sim-line-nr=opts Generate extra CPP code that references source rather than generated code],
[case "${enableval}" in
yes) sim_line_nr="";;
no) sim_line_nr="-L";;
*) AC_MSG_ERROR("--enable-sim-line-nr does not take a value"); sim_line_nr="";;
esac
if test x"$silent" != x"yes" && test x"$sim_line_nr" != x""; then
echo "Setting warning flags = $sim_line_nr" 6>&1
fi],[sim_line-nr=""])dnl
AC_ARG_ENABLE(sim-config,
[ --enable-sim-config=file Override default config file],
[case "${enableval}" in
@@ -91,27 +103,41 @@ fi])dnl
AC_ARG_ENABLE(sim-duplicate,
[ --enable-sim-duplicate Expand (duplicate) semantic functions.],
[case "${enableval}" in
yes) sim_dup="-e";;
yes) sim_dup="-E";;
no) sim_dup="";;
*) AC_MSG_ERROR("--enable-sim-duplicate does not take a value"); sim_dup="";;
esac
if test x"$silent" != x"yes" && test x"$sim_dup" != x""; then
echo "Setting duplicate flags = $sim_dup" 6>&1
fi],[sim_dup="-e"
fi],[sim_dup="-E"
if test x"$silent" != x"yes"; then
echo "Setting duplicate flags = $sim_dup" 6>&1
fi])dnl
AC_ARG_ENABLE(sim-jump,
[ --enable-sim-jump Jump between semantic code (instead of call/return).],
[case "${enableval}" in
yes) sim_jump="-J";;
no) sim_jump="";;
*) AC_MSG_ERROR("--enable-sim-jump does not take a value"); sim_jump="";;
esac
if test x"$silent" != x"yes" && test x"$sim_jump" != x""; then
echo "Setting jump flag = $sim_jump" 6>&1
fi],[sim_jump="-E"
if test x"$silent" != x"yes"; then
echo "Setting jump flag = $sim_jump" 6>&1
fi])dnl
AC_ARG_ENABLE(sim-filter,
[ --enable-sim-filter=rule Specify filter rules.],
[case "${enableval}" in
yes) AC_MSG_ERROR("--enable-sim-filter must be specified with a rule to filter or no"); sim_filter="";;
no) sim_filter="";;
*) sim_filter="-f $enableval";;
*) sim_filter="-F $enableval";;
esac
if test x"$silent" != x"yes" && test x"$sim_filter" != x""; then
echo "Setting filter flags = $sim_filter" 6>&1
fi],[sim_filter="-f 64"
fi],[sim_filter="-F 32,f"
if test x"$silent" != x"yes"; then
echo "Setting filter flags = $sim_filter" 6>&1
fi])dnl
@@ -120,16 +146,25 @@ AC_ARG_ENABLE(sim-icache,
[ --enable-sim-icache=size Specify instruction cache size.],
icache=""
[case "${enableval}" in
yes) sim_icache="-r 1024"; icache="1024";;
define) sim_icache="-r 1024 -R"; icache="1024";;
yes) icache="1024"; sim_icache="-I $icache";;
no) sim_icache="";;
*) sim_icache="-r ${enableval}"; icache="${enableval}";;
*) icache=1024
sim_icache="-"
for x in `echo "${enableval}" | sed -e "s/,/ /g"`; do
case "$x" in
define) sim_icache="${sim_icache}R";;
semantic) sim_icache="${sim_icache}C";;
0*|1*|2*|3*|4*|5*|6*|7*|8*|9*) icache=$x;;
*) AC_MSG_ERROR("Unknown value $x for --enable-sim-icache"); sim_icache="";;
esac
done
sim_icache="${sim_icache}I $icache";;
esac
if test x"$silent" != x"yes" && test x"$icache" != x""; then
echo "Setting instruction cache size to $icache"
fi],[sim_icache="-r 1024"
echo "Setting instruction cache size to $icache ($sim_icache)"
fi],[sim_icache="-CI 1024"
if test x"$silent" != x"yes"; then
echo "Setting instruction cache size to 1024"
echo "Setting instruction cache size to 1024 ($sim_icache)"
fi])dnl
AC_ARG_ENABLE(sim-inline,
@@ -219,13 +254,13 @@ fi])dnl
AC_ARG_ENABLE(sim-smp,
[ --enable-sim-smp=n Specify number of processors to configure for.],
[case "${enableval}" in
yes) sim_smp="-DWITH_SMP=5";;
no) sim_smp="-DWITH_SMP=0";;
*) sim_smp="-DWITH_SMP=$enableval";;
yes) sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5";;
no) sim_smp="-DWITH_SMP=0" ; sim_igen_smp="-N 0";;
*) sim_smp="-DWITH_SMP=$enableval" ; sim_igen_smp="-N $enableval";;
esac
if test x"$silent" != x"yes" && test x"$sim_smp" != x""; then
echo "Setting smp flags = $sim_smp" 6>&1
fi],[sim_smp="-DWITH_SMP=5"
fi],[sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5"
if test x"$silent" != x"yes"; then
echo "Setting smp flags = $sim_smp" 6>&1
fi])dnl
@@ -500,10 +535,12 @@ AC_SUBST(AR)
AC_PROG_RANLIB
AC_SUBST(sim_cflags)
AC_SUBST(sim_warnings)
AC_SUBST(sim_line_nr)
AC_SUBST(sim_config)
AC_SUBST(sim_opcode)
AC_SUBST(sim_switch)
AC_SUBST(sim_dup)
AC_SUBST(sim_jump)
AC_SUBST(sim_filter)
AC_SUBST(sim_icache)
AC_SUBST(sim_inline)
@@ -512,6 +549,7 @@ AC_SUBST(sim_endian)
AC_SUBST(sim_xor_endian)
AC_SUBST(sim_hostendian)
AC_SUBST(sim_smp)
AC_SUBST(sim_igen_smp)
AC_SUBST(sim_bitsize)
AC_SUBST(sim_hostbitsize)
AC_SUBST(sim_env)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

876
sim/ppc/device.maybe Normal file
View File

@@ -0,0 +1,876 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DEVICE_H_
#define _DEVICE_H_
#ifndef INLINE_DEVICE
#define INLINE_DEVICE
#endif
/* declared in basics.h, this object is used everywhere */
/* typedef struct _device device; */
/* Device templates:
*** THIS SECTION DESCRIBES HOW A DEVICE HAS A STATIC AND DYNAMIC
COMPONENT ** on the device in the tree is dynamic. *****
A device node is created from its template. The only valid
operation on a template is to create a device node from it: */
INLINE_DEVICE\
(device *) device_template_create_device
(device *parent,
const char *name,
const char *unit_address,
const char *args);
/* The create is paramaterized by both the devices unit address (a
string that is converted into numeric form by the devices parent)
and optionally extra argument information.
The actual device node is constructed by a number of pieces provided
by the template function: */
typedef struct _device_callbacks device_callbacks;
INLINE_DEVICE\
(device *) device_create_from
(const char *name,
const device_unit *unit_address,
void *data,
const device_callbacks *callbacks,
device *parent);
/* OpenBoot discusses the creation of packages (devices). */
/* Devices:
As with OpenBoot, all nodes in the device tree are considered to be
devices. Each node then has associated with it a number of methods
and properties (duscussed later).
OpenBoot documentation refers to devices, device nodes, packages,
package instances, methods, static methods and properties. This
device implementation uses its own termonology. Where ever it
exists, the notes will indicate a correspondance between PSIM terms
and those found in OpenBoot.
device:
A device is the basic building block in this model. A device can
be further categorized into one of three classes - template, node
and instance.
device-node (aka device):
The device tree is constructed from device-nodes. Each node has
both local state (data), a relationship with the device nodes
around it and an address (unit-address) on the parents bus `bus' */
INLINE_DEVICE\
(device *) device_parent
(device *me);
INLINE_DEVICE\
(device *) device_sibling
(device *me);
INLINE_DEVICE\
(device *) device_child
(device *me);
INLINE_DEVICE\
(const char *) device_name
(device *me);
INLINE_DEVICE\
(const char *) device_path
(device *me);
INLINE_DEVICE\
(void *) device_data
(device *me);
INLINE_DEVICE\
(psim *) device_system
(device *me);
typedef struct _device_unit {
int nr_cells;
unsigned32 cells[4]; /* unused cells are zero */
} device_unit;
INLINE_DEVICE\
(const device_unit *) device_unit_address
(device *me);
/* Each device-node normally corresponds to a hardware component of
the system being modeled. Leaf nodes matching external devices and
intermediate nodes matching bridges and controllers.
Device nodes also support methods that are an abstraction of the
transactions that occure in real hardware. These operations
(io/dma read/writes and interrupts) are discussed separatly.
OpenBoot refers to device nodes by many names. The most common are
device, device node and package. */
/* Properties:
In IEEE1275 many of the the characteristics of a device are stored
in the device tree as properties. Each property consists of a name
and an associated (implicitly typed) value. A device will have a
list of properties attached to it. The user is able to manipulate
the list, adding and removing properties and set/modify the value
of each property.
PSIM's device tree follows this model but with the addition of
strongly typing each property's value. The simulator will detect
at run time, the incorrect use of a property.
In addition to the standard use of properties, Both PSIM and
individual devices will use properties to record simulation
configuration information. For instance, a disk device might store
in a string property called <<file>> the name of the file that
contains the disk image to use. */
/* The following are valid property types. The property `array' is a
for generic untyped data. */
typedef enum {
array_property,
boolean_property,
ihandle_property,
integer_property,
string_property,
} device_property_type;
typedef struct _device_property device_property;
struct _device_property {
device *owner;
const char *name;
device_property_type type;
unsigned sizeof_array;
const void *array;
const device_property *original;
object_disposition disposition;
};
/* iterate through the properties attached to a device */
INLINE_DEVICE\
(const device_property *) device_next_property
(const device_property *previous);
INLINE_DEVICE\
(const device_property *) device_find_property
(device *me,
const char *property); /* NULL for first property */
/* Manipulate the properties belonging to a given device.
SET on the other hand will force the properties value. The
simulation is aborted if the property was present but of a
conflicting type.
FIND returns the specified properties value, aborting the
simulation if the property is missing. Code locating a property
should first check its type (using device_find_property above) and
then obtain its value using the below. */
INLINE_DEVICE\
(void) device_set_array_property
(device *me,
const char *property,
const void *array,
int sizeof_array);
INLINE_DEVICE\
(const device_property *) device_find_array_property
(device *me,
const char *property);
#if 0
INLINE_DEVICE\
(void) device_set_boolean_property
(device *me,
const char *property,
int bool);
#endif
INLINE_DEVICE\
(int) device_find_boolean_property
(device *me,
const char *property);
#if 0
INLINE_DEVICE\
(void) device_set_ihandle_property
(device *me,
const char *property,
device_instance *ihandle);
#endif
INLINE_DEVICE\
(device_instance *) device_find_ihandle_property
(device *me,
const char *property);
#if 0
INLINE_DEVICE\
(void) device_set_integer_property
(device *me,
const char *property,
signed_word integer);
#endif
INLINE_DEVICE\
(signed_word) device_find_integer_property
(device *me,
const char *property);
#if 0
INLINE_DEVICE\
(void) device_set_string_property
(device *me,
const char *property,
const char *string);
#endif
INLINE_DEVICE\
(const char *) device_find_string_property
(device *me,
const char *property);
/* Instances:
As with IEEE1275, a device can be opened, creating an instance.
Instances provide more abstract interfaces to the underlying
hardware. For example, the instance methods for a disk may include
code that is able to interpret file systems found on disks. Such
methods would there for allow the manipulation of files on the
disks file system. The operations would be implemented using the
basic block I/O model provided by the disk.
This model includes methods that faciliate the creation of device
instance and (should a given device support it) standard operations
on those instances. */
*** device-instance ***
Devices support an abstract I/O model. A unique I/O instance can be
created from a device node and then this instance used to perform
I/O that is independant of other instances. */
typedef struct _device_instance_callbacks device_instance_callbacks;
INLINE_DEVICE\
(device_instance *) device_create_instance_from
(device *me, /*OR*/ device_instance *parent,
void *data,
const char *path,
const char *args,
const device_instance_callbacks *callbacks);
INLINE_DEVICE\
(device_instance *) device_create_instance
(device *me,
const char *device_specifier);
INLINE_DEVICE\
(void) device_instance_delete
(device_instance *instance);
INLINE_DEVICE\
(int) device_instance_read
(device_instance *instance,
void *addr,
unsigned_word len);
INLINE_DEVICE\
(int) device_instance_write
(device_instance *instance,
const void *addr,
unsigned_word len);
INLINE_DEVICE\
(int) device_instance_seek
(device_instance *instance,
unsigned_word pos_hi,
unsigned_word pos_lo);
INLINE_DEVICE\
(unsigned_word) device_instance_claim
(device_instance *instance,
unsigned_word address,
unsigned_word length,
unsigned_word alignment);
INLINE_DEVICE\
(void) device_instance_release
(device_instance *instance,
unsigned_word address,
unsigned_word length);
INLINE_DEVICE\
(device *) device_instance_device
(device_instance *instance);
INLINE_DEVICE\
(const char *) device_instance_path
(device_instance *instance);
INLINE_DEVICE\
(void *) device_instance_data
(device_instance *instance);
/* A device instance can be marked (when created) as being permenant.
Such instances are assigned a reserved address and are *not*
deleted between simulation runs.
OpenBoot refers to a device instace as a package instance */
/* PIO:
*** DESCRIBE HERE WHAT A PIO OPERATION IS and how, broadly it is
modeled ****
During initialization, each device attaches its self to is parent
registering the address spaces that it is interested in:
a. The <<com>> device attaches its self to its parent <<phb>>
device at address <<0x3f8>> through to address <<0x3f8 + 16>>.
b. The <<phb>> has in turn attached its self to addresses
<<0xf0000000 .. 0xf0100000>>.
During the execution of the simulation propper, the following then
occure:
1. After any virtual to physical translation, the processor
passes the address to be read (or written to the core device).
(eg address 0xf00003f8).
2. The core device then looks up the specified addresses in its
address to device map, determines that in this case the address
belongs to the phb and passes it down.
3. The <<phb>> in turn determines that the address belongs to the
serial port and passes to that device the request for an access
to location <<0x3f8>>.
@figure mio
*/
/* Device Hardware
This model assumes that the data paths of the system being modeled
have a tree topology. That is, one or more processors sit at the
top of a tree. That tree containing leaf nodes (real devices) and
branch nodes (bridges).
For instance, consider the tree:
/pci # PCI-HOST bridge
/pci/pci1000,1@1 # A pci controller
/pci/isa8086 # PCI-ISA bridge
/pci/isa8086/fdc@300 # floppy disk controller on ISA bus
A processor needing to access the device fdc@300 on the ISA bus
would do so using a data path that goes through the pci-host bridge
(pci)and the isa-pci bridge (isa8086) to finally reach the device
fdc@300. As the data transfer passes through each intermediate
bridging node that bridge device is able to (just like with real
hardware) manipulate either the address or data involved in the
transfer. */
INLINE_DEVICE\
(unsigned) device_io_read_buffer
(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
INLINE_DEVICE\
(unsigned) device_io_write_buffer
(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
/* To avoid the need for an intermediate (bridging) node to ask each
of its child devices in turn if an IO access is intended for them,
parent nodes maintain a table mapping addresses directly to
specific devices. When a device is `connected' to its bus it
attaches its self to its parent. */
/* Address access attributes */
typedef enum _access_type {
access_invalid = 0,
access_read = 1,
access_write = 2,
access_read_write = 3,
access_exec = 4,
access_read_exec = 5,
access_write_exec = 6,
access_read_write_exec = 7,
} access_type;
/* Address attachement types */
typedef enum _attach_type {
attach_invalid,
attach_raw_memory,
attach_callback,
/* ... */
} attach_type;
INLINE_DEVICE\
(void) device_attach_address
(device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
device *who); /*callback/default*/
INLINE_DEVICE\
(void) device_detach_address
(device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
device *who); /*callback/default*/
/* where the attached address space can be any of
callback - all accesses to that range of addresses are past on to
the attached child device. The callback addresses are ordered
according to the callback level (attach_callback, .. + 1, .. + 2,
...). Lower levels are searched first. This facilitates the
implementation of more unusual addressing schema such as
subtractive decoding (as seen on the PCI bus). Within a given
callback level addresses must not overlap.
memory - the specified address space contains RAM, the node that is
having the ram attached is responsible for allocating space for and
maintaining that space. The device initiating the attach will not
be notified of accesses to such an attachement.
The memory attachment is very important. By giving the parent node
the responsability (and freedom) of managing the RAM, that node is
able to implement memory spaces more efficiently. For instance it
could `cache' accesses or merge adjacent memory areas.
In addition to I/O and DMA, devices interact with the rest of the
system via interrupts. Interrupts are discussed separatly. */
/* DMA:
*** DESCRIBE HERE WHAT A DMA OPERATION IS AND HOW IT IS MODELED,
include an interation of an access being reflected back down ***
*/
/* Conversly, the device pci1000,1@1 my need to perform a dma transfer
into the cpu/memory core. Just as I/O moves towards the leaves,
dma transfers move towards the core via the initiating devices
parent nodes. The root device (special) converts the DMA transfer
into reads/writes to memory */
INLINE_DEVICE\
(unsigned) device_dma_read_buffer
(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes);
INLINE_DEVICE\
(unsigned) device_dma_write_buffer
(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section);
/* Interrupts:
*** DESCRIBE HERE THE INTERRUPT NETWORK ***
PSIM models interrupts and their wiring as a directed graph of
connections between interrupt sources and destinations. The source
and destination are both a tupple consisting of a port number and
device. Both multiple destinations attached to a single source and
multiple sources attached to a single destination are allowed.
When a device drives an interrupt port with multiple destinations a
broadcast of that interrupt event (message to all destinations)
occures. Each of those destination (device/port) are able to
further propogate the interrupt until it reaches its ultimate
destination.
Normally an interrupt source would be a model of a real device
(such as a keyboard) while an interrupt destination would be an
interrupt controller. The facility that allows an interrupt to be
delivered to multiple devices and to be propogated from device to
device was designed to support the requirements specified by
OpenPIC (ISA interrupts go to both OpenPIC and 8259), CHRP (8259
connected to OpenPIC) and hardware designs such as PCI-PCI
bridges. */
/* Interrupting a processor
The cpu object provides methods for delivering external interrupts
to a given processor.
The problem of synchronizing external interrupt delivery with the
execution of the cpu is handled internally by the processor object. */
/* Interrupt Source
A device drives its interrupt line using the call: */
INLINE_DEVICE\
(void) device_interrupt_event
(device *me,
int my_port,
int value,
cpu *processor,
unsigned_word cia);
/* This interrupt event will then be propogated to any attached
interrupt destinations.
Any interpretation of PORT and VALUE is model dependant. However
as guidelines the following are recommended: PCI interrupts a-d
correspond to lines 0-3; level sensative interrupts be requested
with a value of one and withdrawn with a value of 0; edge sensative
interrupts always have a value of 1, the event its self is treated
as the interrupt.
Interrupt Destinations
Attached to each interrupt line of a device can be zero or more
desitinations. These destinations consist of a device/port pair.
A destination is attached/detached to a device line using the
attach and detach calls. */
INLINE_DEVICE\
(void) device_interrupt_attach
(device *me,
int my_port,
device *dest,
int dest_port,
object_disposition disposition);
INLINE_DEVICE\
(void) device_interrupt_detach
(device *me,
int my_port,
device *dest,
int dest_port);
/* DESTINATION is attached (detached) to LINE of the device ME
Interrupt conversion
Users refer to interrupt port numbers symbolically. For instance a
device may refer to its `INT' signal which is internally
represented by port 3.
To convert to/from the symbolic and internal representation of a
port name/number. The following functions are available. */
INLINE_DEVICE\
(int) device_interrupt_decode
(device *me,
const char *symbolic_name);
INLINE_DEVICE\
(int) device_interrupt_encode
(device *me,
int port_number,
char *buf,
int sizeof_buf);
/* Initialization:
In PSIM, the device tree is created and then initialized in stages.
When using devices it is important to be clear what initialization
the simulator assumes is being performed during each of these
stages.
Firstly, each device is created in isolation (using the create from
template method). Only after it has been created will a device be
inserted into the tree ready for initialization.
Once the tree is created, it is initialized as follows:
1. All properties (apart from those containing instances)
are (re)initialized
2. Any interrupts addeded as part of the simulation run
are removed.
4. The initialize address method of each device (in top
down order) is called. At this stage the device
is expected to:
o Clear address maps and delete allocated memory
associated with the devices children.
o (Re)attach its own addresses to its parent device.
o Ensure that it is otherwize sufficiently
initialized such that it is ready for a
device instance create call.
5. All properties containing an instance of
a device are (re)initialized
6. The initialize data method for each device is called (in
top down) order. At this stage the device is expected to:
o Perform any needed data transfers. Such
transfers would include the initialization
of memory created during the address initialization
stage using DMA.
*/
INLINE_DEVICE\
(void) device_tree_init
(device *root,
psim *system);
/* IOCTL:
Very simply, a catch all for any thing that turns up that until now
either hasn't been thought of or doesn't justify an extra function. */
EXTERN_DEVICE\
(int) device_ioctl
(device *me,
cpu *processor,
unsigned_word cia,
...);
/* External communcation:
Devices interface to the external environment */
/* device_error() reports the problem to the console and aborts the
simulation. The error message is prefixed with the name of the
reporting device. */
EXTERN_DEVICE\
(void volatile) device_error
(device *me,
const char *fmt,
...) __attribute__ ((format (printf, 2, 3)));
/* Tree utilities:
In addition to the standard method of creating a device from a
device template, the following sortcuts can be used.
Create a device or property from a textual representation */
EXTERN_DEVICE\
(device *) device_tree_add_parsed
(device *current,
const char *fmt,
...) __attribute__ ((format (printf, 2, 3)));
/* where FMT,... once formatted (using vsprintf) is used to locate and
create either a device or property. Its syntax is almost identical
to that used in OpenBoot documentation - the only extension is in
allowing properties and their values to be specified vis:
"/pci/pci1000,1@1/disk@0,0"
Path:
The path to a device or property can either be absolute (leading
`/') or relative (leading `.' or `..'). Relative paths start from
the CURRENT node. The new current node is returned as the result.
In addition, a path may start with a leading alias (resolved by
looking in /aliases).
Device name:
<name> "@" <unit> [ ":" <args> ]
Where <name> is the name of the template device, <unit> is a
textual specification of the devices unit address (that is
converted into a numeric form by the devices parent) and <args> are
optional additional information to be passed to the device-template
when it creates the device.
Properties:
Properties are specified in a similar way to devices except that
the last element on the path (which would have been the device) is
the property name. This path is then followed by the property
value. Unlike OpenBoot, the property values in the device tree are
strongly typed.
String property:
<property-name> " " <text>
<property-name> " " "\"" <text>
Boolean property:
<property-name> " " [ "true" | "false" ]
Integer property or integer array property:
<property-name> " " <number> { <number> }
Phandle property:
<property-name> " " "&" <path-to-device>
Ihandle property:
<property-name> " " "*" <path-to-device-to-open>
Duplicate existing property:
<property-name> " " "!" <path-to-original-property>
In addition to properties, the wiring of interrupts can be
specified:
Attach interrupt <line> of <device> to <controller>:
<device> " " ">" <my-port> <dest-port> <dest-device>
Once created, a device tree can be traversed in various orders: */
typedef void (device_tree_traverse_function)
(device *device,
void *data);
INLINE_DEVICE\
(void) device_tree_traverse
(device *root,
device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix,
void *data);
/* Or dumped out in a format that can be read back in using
device_add_parsed() */
INLINE_DEVICE\
(void) device_tree_print_device
(device *device,
void *ignore_data_argument);
/* Individual nodes can be located using */
INLINE_DEVICE\
(device *) device_tree_find_device
(device *root,
const char *path);
/* And the current list of devices can be listed */
INLINE_DEVICE\
(void) device_usage
(int verbose);
/* ihandles and phandles:
Both device nodes and device instances, in OpenBoot firmware have
an external representation (phandles and ihandles) and these values
are both stored in the device tree in property nodes and passed
between the client program and the simulator during emulation
calls.
To limit the potential risk associated with trusing `data' from the
client program, the following mapping operators `safely' convert
between the two representations: */
INLINE_DEVICE\
(device *) external_to_device
(device *tree_member,
unsigned32 phandle);
INLINE_DEVICE\
(unsigned32) device_to_external
(device *me);
INLINE_DEVICE\
(device_instance *) external_to_device_instance
(device *tree_member,
unsigned32 ihandle);
INLINE_DEVICE\
(unsigned32) device_instance_to_external
(device_instance *me);
#endif /* _DEVICE_H_ */

306
sim/ppc/device_table.h Normal file
View File

@@ -0,0 +1,306 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DEVICE_TABLE_H_
#define _DEVICE_TABLE_H_
#include <stdarg.h>
#include "basics.h"
#include "device.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
typedef struct _device_callbacks device_callbacks;
/* The creator, returns a pointer to any data that should be allocated
once during (multiple) simulation runs */
typedef void *(device_creator)
(const char *name,
const device_unit *unit_address,
const char *args);
/* two stages of initialization */
typedef void (device_init_callback)
(device *me);
typedef struct _device_init_callbacks {
device_init_callback *address; /* NULL - ignore */
device_init_callback *data; /* NULL - ignore */
} device_init_callbacks;
/* attaching/detaching a devices address space to its parent */
typedef void (device_address_callback)
(device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
device *who); /*callback/default*/
typedef struct _device_address_callbacks {
device_address_callback *attach;
device_address_callback *detach;
} device_address_callbacks;
/* I/O operations - from parent */
typedef unsigned (device_io_read_buffer_callback)
(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
typedef unsigned (device_io_write_buffer_callback)
(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
typedef struct _device_io_callbacks { /* NULL - error */
device_io_read_buffer_callback *read_buffer;
device_io_write_buffer_callback *write_buffer;
} device_io_callbacks;
/* DMA transfers by a device via its parent */
typedef unsigned (device_dma_read_buffer_callback)
(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes);
typedef unsigned (device_dma_write_buffer_callback)
(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section);
typedef struct _device_dma_callbacks { /* NULL - error */
device_dma_read_buffer_callback *read_buffer;
device_dma_write_buffer_callback *write_buffer;
} device_dma_callbacks;
/* Interrupts */
typedef void (device_interrupt_event_callback)
(device *me,
int my_port,
device *source,
int source_port,
int level,
cpu *processor,
unsigned_word cia);
typedef void (device_child_interrupt_event_callback)
(device *me,
device *parent,
device *source,
int source_port,
int level,
cpu *processor,
unsigned_word cia);
typedef struct _device_interrupt_port_descriptor {
const char *name;
int number;
int bound;
} device_interrupt_port_descriptor;
typedef struct _device_interrupt_callbacks {
device_interrupt_event_callback *event;
device_child_interrupt_event_callback *child_event;
const device_interrupt_port_descriptor *ports;
} device_interrupt_callbacks;
/* symbolic value decoding */
typedef int (device_unit_decode_callback)
(device *me,
const char *unit,
device_unit *address);
typedef int (device_unit_encode_callback)
(device *me,
const device_unit *unit_address,
char *buf,
int sizeof_buf);
typedef struct _device_convert_callbacks {
device_unit_decode_callback *decode_unit;
device_unit_encode_callback *encode_unit;
} device_convert_callbacks;
/* instances */
typedef void (device_instance_delete_callback)
(device_instance *instance);
typedef int (device_instance_read_callback)
(device_instance *instance,
void *buf,
unsigned_word len);
typedef int (device_instance_write_callback)
(device_instance *instance,
const void *buf,
unsigned_word len);
typedef int (device_instance_seek_callback)
(device_instance *instance,
unsigned_word pos_hi,
unsigned_word pos_lo);
typedef unsigned_word (device_instance_claim_callback)
(device_instance *instance,
unsigned_word address,
unsigned_word length,
unsigned_word alignment);
typedef void (device_instance_release_callback)
(device_instance *instance,
unsigned_word address,
unsigned_word length);
struct _device_instance_callbacks { /* NULL - error */
device_instance_delete_callback *delete;
device_instance_read_callback *read;
device_instance_write_callback *write;
device_instance_seek_callback *seek;
device_instance_claim_callback *claim;
device_instance_release_callback *release;
};
typedef device_instance *(device_create_instance_callback)
(device *me,
const char *path,
const char *args);
typedef device_instance *(package_create_instance_callback)
(device_instance *parent,
const char *args);
/* all else fails */
typedef int (device_ioctl_callback)
(device *me,
cpu *processor,
unsigned_word cia,
va_list ap);
typedef void (device_usage_callback)
(int verbose);
/* the callbacks */
struct _device_callbacks {
/* initialization */
device_init_callbacks init;
/* address/data config - from child */
device_address_callbacks address;
/* address/data transfer - from parent */
device_io_callbacks io;
/* address/data transfer - from child */
device_dma_callbacks dma;
/* interrupt signalling */
device_interrupt_callbacks interrupt;
/* bus address decoding */
device_convert_callbacks convert;
/* instances */
device_create_instance_callback *instance_create;
/* back door to anything we've forgot */
device_ioctl_callback *ioctl;
device_usage_callback *usage;
};
/* Table of all the devices and a function to lookup/create a device
from its name */
typedef struct _device_descriptor device_descriptor;
struct _device_descriptor {
const char *name;
device_creator *creator;
const device_callbacks *callbacks;
};
extern const device_descriptor *const device_table[];
#include "hw.h"
/* Pass through, ignore and generic callback functions. A call going
towards the root device are passed on up, local calls are ignored
and call downs abort */
extern device_address_callback passthrough_device_address_attach;
extern device_address_callback passthrough_device_address_detach;
extern device_dma_read_buffer_callback passthrough_device_dma_read_buffer;
extern device_dma_write_buffer_callback passthrough_device_dma_write_buffer;
extern device_unit_decode_callback ignore_device_unit_decode;
extern device_init_callback generic_device_init_address;
extern device_unit_decode_callback generic_device_unit_decode;
extern device_unit_encode_callback generic_device_unit_encode;
extern const device_callbacks passthrough_device_callbacks;
#endif /* _DEVICE_TABLE_H_ */

View File

@@ -45,7 +45,7 @@
#define _READLN 0x004 /* Input line (pointer / count format) */
#define _CHKBRK 0x005 /* Check for break */
#define _DSKRD 0x010 /* Disk read */
#define _DKSWR 0x011 /* Disk write */
#define _DSKWR 0x011 /* Disk write */
#define _DSKCFIG 0x012 /* Disk configure */
#define _DSKFMT 0x014 /* Disk format */
#define _DSKCTRL 0x015 /* Disk control */
@@ -104,7 +104,7 @@ static const struct bug_map bug_mapping[] = {
{ _READLN, ".READLN -- Input line (pointer / count format)" },
{ _CHKBRK, ".CHKBRK -- Check for break" },
{ _DSKRD, ".DSKRD -- Disk read" },
{ _DKSWR, ".DKSWR -- Disk write" },
{ _DSKWR, ".DSKWR -- Disk write" },
{ _DSKCFIG, ".DSKCFIG -- Disk configure" },
{ _DSKFMT, ".DSKFMT -- Disk format" },
{ _DSKCTRL, ".DSKCTRL -- Disk control" },
@@ -151,13 +151,14 @@ static const struct bug_map bug_mapping[] = {
{ _SYMBOLDA, ".SYMBOLDA -- Detach symbol table" },
};
#ifndef OEA_START_ADDRESS
#define OEA_START_ADDRESS 0x100000
#ifndef BUGAPI_END_ADDRESS
#define BUGAPI_END_ADDRESS 0x100000
#endif
struct _os_emul_data {
device *root;
unsigned_word memory_size;
unsigned_word top_of_stack;
int interrupt_prefix;
@@ -169,6 +170,7 @@ struct _os_emul_data {
/* I/O devices */
device_instance *output;
device_instance *input;
device_instance *disk;
};
@@ -188,7 +190,7 @@ emul_bugapi_create(device *root,
return NULL;
if (image != NULL
&& name == NULL
&& bfd_get_start_address(image) > OEA_START_ADDRESS)
&& bfd_get_start_address(image) >= BUGAPI_END_ADDRESS)
return NULL;
bugapi = ZALLOC(os_emul_data);
@@ -203,6 +205,8 @@ emul_bugapi_create(device *root,
/* add some real hardware */
emul_add_tree_hardware(root);
bugapi->root = root;
bugapi->memory_size
= device_find_integer_property(root, "/openprom/options/oea-memory-size");
bugapi->interrupt_prefix =
@@ -217,10 +221,8 @@ emul_bugapi_create(device *root,
= device_find_boolean_property(root, "/options/little-endian?");
bugapi->floating_point_available
= device_find_boolean_property(root, "/openprom/options/floating-point?");
bugapi->input
= device_find_ihandle_property(root, "/chosen/stdin");
bugapi->output
= device_find_ihandle_property(root, "/chosen/stdout");
bugapi->input = NULL;
bugapi->output = NULL;
/* initialization */
device_tree_add_parsed(root, "/openprom/init/register/0.pc 0x%lx",
@@ -268,7 +270,7 @@ emul_bugapi_create(device *root,
(unsigned long)emul_loop_instruction);
device_tree_add_parsed(root, "/openprom/init/stack/stack-type %s",
elf_binary ? "elf" : "aix");
elf_binary ? "ppc-elf" : "ppc-xcoff");
device_tree_add_parsed(root, "/openprom/init/load-binary/file-name \"%s",
bfd_get_filename(image));
@@ -277,10 +279,14 @@ emul_bugapi_create(device *root,
}
static void
emul_bugapi_init(os_emul_data *emul_data,
emul_bugapi_init(os_emul_data *bugapi,
int nr_cpus)
{
/* nothing happens here */
/* get the current input/output devices that were created during
device tree initialization */
bugapi->input = device_find_ihandle_property(bugapi->root, "/chosen/stdin");
bugapi->output = device_find_ihandle_property(bugapi->root, "/chosen/stdout");
bugapi->disk = device_find_ihandle_property(bugapi->root, "/chosen/disk");
}
static const char *
@@ -336,6 +342,61 @@ emul_bugapi_do_read(os_emul_data *bugapi,
return status;
}
static void
emul_bugapi_do_diskio(os_emul_data *bugapi,
cpu *processor,
unsigned_word cia,
unsigned_word descriptor_addr,
int call_id)
{
struct dskio_descriptor {
unsigned_1 ctrl_lun;
unsigned_1 dev_lun;
unsigned_2 status;
unsigned_word pbuffer;
unsigned_4 blk_num;
unsigned_2 blk_cnt;
unsigned_1 flag;
#define BUG_FILE_MARK 0x80
#define IGNORE_FILENUM 0x02
#define END_OF_FILE 0x01
unsigned_1 addr_mod;
} descriptor;
int block;
emul_read_buffer(&descriptor, descriptor_addr, sizeof(descriptor),
processor, cia);
T2H(descriptor.ctrl_lun);
T2H(descriptor.dev_lun);
T2H(descriptor.status);
T2H(descriptor.pbuffer);
T2H(descriptor.blk_num);
T2H(descriptor.blk_cnt);
T2H(descriptor.flag);
T2H(descriptor.addr_mod);
for (block = 0; block < descriptor.blk_cnt; block++) {
unsigned_1 buf[512]; /*????*/
unsigned_word block_nr = descriptor.blk_num + block;
unsigned_word byte_nr = block_nr * sizeof(buf);
unsigned_word block_addr = descriptor.pbuffer + block*sizeof(buf);
if (device_instance_seek(bugapi->disk, 0, byte_nr) < 0)
error("emul_bugapi_do_diskio: bad seek\n");
switch (call_id) {
case _DSKRD:
if (device_instance_read(bugapi->disk, buf, sizeof(buf)) != sizeof(buf))
error("emul_bugapi_do_diskio: bad read\n");
emul_write_buffer(buf, block_addr, sizeof(buf), processor, cia);
break;
case _DSKWR:
emul_read_buffer(buf, block_addr, sizeof(buf), processor, cia);
if (device_instance_write(bugapi->disk, buf, sizeof(buf)) != sizeof(buf))
error("emul_bugapi_do_diskio: bad write\n");
break;
default:
error("emul_bugapi_do_diskio: bad switch\n");
}
}
}
static void
emul_bugapi_do_write(os_emul_data *bugapi,
cpu *processor,
@@ -382,13 +443,14 @@ emul_bugapi_instruction_call(cpu *processor,
os_emul_data *bugapi)
{
const int call_id = cpu_registers(processor)->gpr[10];
const char *my_prefix UNUSED = "bugapi";
unsigned char uc;
ITRACE (trace_os_emul,(" 0x%x %s, r3 = 0x%lx, r4 = 0x%lx\n",
call_id, emul_bugapi_instruction_name (call_id),
(long)cpu_registers(processor)->gpr[3],
(long)cpu_registers(processor)->gpr[4]));;
#define MY_INDEX itable_instruction_call
ITRACE (trace_os_emul,
(" 0x%x %s, r3 = 0x%lx, r4 = 0x%lx\n",
call_id, emul_bugapi_instruction_name (call_id),
(long)cpu_registers(processor)->gpr[3],
(long)cpu_registers(processor)->gpr[4]));;
/* check that this isn't an invalid instruction */
if (cia != bugapi->system_call_address)
@@ -440,9 +502,17 @@ emul_bugapi_instruction_call(cpu *processor,
case _PCRLF:
device_instance_write(bugapi->output, "\n", 1);
break;
/* return to ppcbug monitor */
/* read/write blocks of data to/from the disk */
case _DSKWR:
case _DSKRD:
emul_bugapi_do_diskio(bugapi, processor, cia,
cpu_registers(processor)->gpr[3],
call_id);
break;
/* return to ppcbug monitor (exiting with gpr[3] as status is not
part of the bug monitor) */
case _RETURN:
cpu_halt(processor, cia, was_exited, 0); /* always succeeds */
cpu_halt(processor, cia, was_exited, cpu_registers(processor)->gpr[3]);
break;
}
return 1;

View File

@@ -290,6 +290,11 @@ emul_add_tree_options(device *tree,
model_name[WITH_DEFAULT_MODEL]);
device_tree_add_parsed(tree, "/openprom/options/model-issue %d",
MODEL_ISSUE_IGNORE);
/* useful options */
/* FIXME - need to check the OpenBoot powerpc bindings to see if
this is still used and if so what it should be */
device_tree_add_parsed(tree, "/options/load-base 0x80000");
}
INLINE_EMUL_GENERIC void
@@ -298,6 +303,11 @@ emul_add_tree_hardware(device *root)
int i;
int nr_cpus = device_find_integer_property(root, "/openprom/options/smp");
/* sanity check the number of processors */
if (nr_cpus > MAX_NR_PROCESSORS)
error("Specified number of processors (%d) exceeds the number configured (%d).\n",
nr_cpus, MAX_NR_PROCESSORS);
/* add some memory */
if (device_tree_find_device(root, "/memory") == NULL) {
unsigned_word memory_size =
@@ -315,21 +325,29 @@ emul_add_tree_hardware(device *root)
/* a fake eeprom - need to be able to write to it */
device_tree_add_parsed(root, "/openprom/memory@0xfff00000/reg { 0xfff00000 0x3000");
/* A local bus containing basic devices */
device_tree_add_parsed(root, "/iobus@0xf0000000/reg { 0xf0000000 0x0f000000");
/* NVRAM with clock */
device_tree_add_parsed(root, "/iobus/nvram@0x0/reg { 0 0x1000");
device_tree_add_parsed(root, "/iobus/nvram/timezone 600");
device_tree_add_parsed(root, "/iobus/nvram/timezone 0");
/* the debugging pal. Wire interrupts up directly */
device_tree_add_parsed(root, "/iobus/pal@0x0x1000/reg { 0x1000 32");
for (i = 0; i < nr_cpus; i++) {
device_tree_add_parsed(root, "/iobus/pal > %d int /cpus/cpu@%d", i, i);
device_tree_add_parsed(root, "/iobus/pal > int%d int /cpus/cpu@%d", i, i);
}
/* a disk containing zero's */
device_tree_add_parsed(root, "/iobus/disk@0x2000/reg { 0x2000 0x1000");
device_tree_add_parsed(root, "/iobus/disk/file \"/dev/zero");
/* chosen etc */
device_tree_add_parsed(root, "/chosen/stdin */iobus/pal");
device_tree_add_parsed(root, "/chosen/stdout !/chosen/stdin");
device_tree_add_parsed(root, "/chosen/memory */memory");
device_tree_add_parsed(root, "/chosen/disk */iobus/disk");
}
#endif /* _EMUL_GENERIC_C_ */

150
sim/ppc/filter.c Normal file
View File

@@ -0,0 +1,150 @@
/* 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.
*/
#include <stdio.h>
#include "config.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include "misc.h"
#include "filter.h"
struct _filter {
char *flag;
filter *next;
};
filter *
new_filter(const char *filt,
filter *filters)
{
while (strlen(filt) > 0) {
filter *new_filter;
/* break up the filt list */
char *end = strchr(filt, ',');
char *next;
int len;
if (end == NULL) {
end = strchr(filt, '\0');
next = end;
}
else {
next = end + 1;
}
len = end - filt;
/* add to filter list */
new_filter = ZALLOC(filter);
new_filter->flag = (char*)zalloc(len + 1);
strncpy(new_filter->flag, filt, len);
new_filter->next = filters;
filters = new_filter;
filt = next;
}
return filters;
}
int
is_filtered_out(const char *flags,
filter *filters)
{
while (strlen(flags) > 0) {
int present;
filter *filt = filters;
/* break the string up */
char *end = strchr(flags, ',');
char *next;
int len;
if (end == NULL) {
end = strchr(flags, '\0');
next = end;
}
else {
next = end + 1;
}
len = end - flags;
/* check that it is present */
present = 0;
filt = filters;
while (filt != NULL) {
if (strncmp(flags, filt->flag, len) == 0
&& strlen(filt->flag) == len) {
present = 1;
break;
}
filt = filt->next;
}
if (!present)
return 1;
flags = next;
}
return 0;
}
int
it_is(const char *flag,
const 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;
}
#ifdef MAIN
int
main(int argc, char **argv)
{
filter *filters = NULL;
int i;
if (argc < 2) {
printf("Usage: filter <flags> <filter> ...\n");
exit (1);
}
/* load the filter up */
for (i = 2; i < argc; i++)
filters = new_filter(argv[i], filters);
if (is_filtered_out(argv[1], filters))
printf("fail\n");
else
printf("pass\n");
return 0;
}
#endif

43
sim/ppc/filter.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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.
*/
typedef struct _filter filter;
/* append the filter onto the end of the list */
extern filter *new_filter
(const char *filt,
filter *filters);
/* returns true if the flags are non empty and some are missing from the filter list */
extern int is_filtered_out
(const char *flags,
filter *filters);
/* true if the flag is in the list */
extern int it_is
(const char *flag,
const char *flags);

595
sim/ppc/gen-icache.c Normal file
View File

@@ -0,0 +1,595 @@
/* 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.
*/
#include "misc.h"
#include "lf.h"
#include "table.h"
#include "filter.h"
#include "ld-decode.h"
#include "ld-cache.h"
#include "ld-insn.h"
#include "igen.h"
#include "gen-semantics.h"
#include "gen-idecode.h"
#include "gen-icache.h"
static void
print_icache_function_header(lf *file,
const char *basename,
insn_bits *expanded_bits,
int is_function_definition)
{
lf_printf(file, "\n");
lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", " ");
print_function_name(file,
basename,
expanded_bits,
function_name_prefix_icache);
lf_printf(file, "\n(%s)", ICACHE_FUNCTION_FORMAL);
if (!is_function_definition)
lf_printf(file, ";");
lf_printf(file, "\n");
}
void
print_icache_declaration(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
if (generate_expanded_instructions) {
ASSERT(entry->nr_insn == 1);
print_icache_function_header(file,
entry->insns->file_entry->fields[insn_name],
entry->expanded_bits,
0/* is not function definition */);
}
else {
print_icache_function_header(file,
instruction->file_entry->fields[insn_name],
NULL,
0/* is not function definition */);
}
}
static void
print_icache_extraction(lf *file,
insn *instruction,
char *field_name,
char *field_type,
char *field_expression,
const char *file_name,
int line_nr,
insn_field *cur_field,
insn_bits *bits,
int use_defines,
int get_value_from_cache,
int put_value_in_cache)
{
ASSERT(field_name != NULL);
if (use_defines && put_value_in_cache) {
/* We've finished with the value - destory it */
lf_indent_suppress(file);
lf_printf(file, "#undef %s\n", field_name);
return;
}
else if (use_defines && get_value_from_cache) {
lf_indent_suppress(file);
lf_printf(file, "#define %s ", field_name);
}
else {
lf_print__external_reference(file, line_nr, file_name);
lf_printf(file, "%s const %s __attribute__((__unused__)) = ",
field_type == NULL ? "unsigned" : field_type,
field_name);
}
if (bits != NULL
&& ((bits->opcode->is_boolean
&& bits->value == 0)
|| !bits->opcode->is_boolean)
&& strcmp(field_name, cur_field->val_string) == 0) {
/* The field has been made constant (as a result of expanding
instructions or similar) - define a constant variable with the
corresponding value. */
ASSERT(bits->field == cur_field);
ASSERT(field_type == NULL);
if (bits->opcode->is_boolean)
lf_printf(file, "%d", bits->opcode->boolean_constant);
else if (bits->opcode->last < bits->field->last)
lf_printf(file, "%d",
bits->value << (bits->field->last - bits->opcode->last));
else
lf_printf(file, "%d", bits->value);
}
else {
/* put the field in the local variable, possibly also enter it
into the cache */
/* 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)",
i2target(hi_bit_nr, cur_field->first),
i2target(hi_bit_nr, cur_field->last));
else if (field_expression != NULL)
lf_printf(file, "%s", field_expression);
else
lf_printf(file, "eval_%s", field_name);
}
}
if (use_defines && get_value_from_cache)
lf_printf(file, "\n");
else
lf_printf(file, ";\n");
}
void
print_icache_body(lf *file,
insn *instruction,
insn_bits *expanded_bits,
cache_table *cache_rules,
int use_defines,
int get_value_from_cache,
int put_value_in_cache)
{
insn_field *cur_field;
/* extract instruction fields */
lf_printf(file, "/* extraction: %s defines=%d get-value=%d put-value=%d */\n",
instruction->file_entry->fields[insn_format],
use_defines, get_value_from_cache, put_value_in_cache);
for (cur_field = instruction->fields->first;
cur_field->first < insn_bit_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) {
cache_table *cache_rule;
for (cache_rule = cache_rules;
cache_rule != NULL;
cache_rule = cache_rule->next) {
if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) {
found_rule = 1;
if (cache_rule->type == compute_value
&& put_value_in_cache
&& !use_defines)
print_icache_extraction(file,
instruction,
cache_rule->new_name,
cache_rule->type_def,
cache_rule->expression,
cache_rule->file_entry->file_name,
cache_rule->file_entry->line_nr,
cur_field,
bits,
0 /*use_defines*/,
0 /*get-value-from-cache*/,
0 /*put-value-in-cache*/);
else if (cache_rule->type == cache_value)
print_icache_extraction(file,
instruction,
cache_rule->new_name,
cache_rule->type_def,
cache_rule->expression,
cache_rule->file_entry->file_name,
cache_rule->file_entry->line_nr,
cur_field,
bits,
use_defines,
get_value_from_cache,
put_value_in_cache);
}
}
}
if (found_rule == 0)
print_icache_extraction(file,
instruction,
cur_field->val_string,
0,
0,
instruction->file_entry->file_name,
instruction->file_entry->line_nr,
cur_field,
bits,
use_defines,
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])) {
if (!use_defines || (use_defines && get_value_from_cache)) {
if (use_defines) {
lf_indent_suppress(file);
lf_printf(file, "#define %s_is_0 ", field_name);
}
else {
table_entry_print_cpp_line_nr(file, instruction->file_entry);
lf_printf(file, "const unsigned %s_is_0 __attribute__((__unused__)) = ",
field_name);
}
if (bits != NULL)
lf_printf(file, "(%d == 0)", bits->value);
else
lf_printf(file, "(%s == 0)", field_name);
if (use_defines)
lf_printf(file, "\n");
else
lf_printf(file, ";\n");
}
else if (use_defines && put_value_in_cache) {
lf_indent_suppress(file);
lf_printf(file, "#undef %s_is_0\n", field_name);
}
break;
}
is_0_ptr += strlen("_is_0");
}
}
}
/* any thing else ... */
}
}
lf_print__internal_reference(file);
}
typedef struct _icache_tree icache_tree;
struct _icache_tree {
char *name;
icache_tree *next;
icache_tree *children;
};
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 = ZALLOC(icache_tree);
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 = ZALLOC(icache_tree);
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;
}
extern void
print_icache_struct(insn_table *instructions,
cache_table *cache_rules,
lf *file)
{
icache_tree *tree = insn_table_cache_fields(instructions);
lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n",
(code & generate_with_icache) ? icache_size : 0);
lf_printf(file, "\n");
/* create an instruction cache if being used */
if ((code & generate_with_icache)) {
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) {
cache_table *cache_rule;
int found_rule = 0;
for (cache_rule = cache_rules;
cache_rule != NULL;
cache_rule = cache_rule->next) {
if (strcmp(field->name, cache_rule->old_name) == 0) {
found_rule = 1;
if (cache_rule->new_name != NULL)
lf_printf(file, " %s %s; /* %s */\n",
(cache_rule->type_def == NULL
? "unsigned"
: cache_rule->type_def),
cache_rule->new_name,
cache_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. Emit a dummy
definition for idecode_cache to allow model_issue to not
be #ifdefed at the call level */
cache_table *cache_rule;
lf_printf(file, "\n");
lf_printf(file, "typedef void idecode_cache;\n");
lf_printf(file, "\n");
for (cache_rule = cache_rules;
cache_rule != NULL;
cache_rule = cache_rule->next) {
if (cache_rule->expression != NULL
&& strlen(cache_rule->expression) > 0)
lf_printf(file, "#define %s %s\n",
cache_rule->new_name, cache_rule->expression);
}
}
}
static void
print_icache_function(lf *file,
insn *instruction,
insn_bits *expanded_bits,
opcode_field *opcodes,
cache_table *cache_rules)
{
int indent;
/* generate code to enter decoded instruction into the icache */
lf_printf(file, "\n");
lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", "\n");
indent = print_function_name(file,
instruction->file_entry->fields[insn_name],
expanded_bits,
function_name_prefix_icache);
lf_indent(file, +indent);
lf_printf(file, "(%s)\n", ICACHE_FUNCTION_FORMAL);
lf_indent(file, -indent);
/* function header */
lf_printf(file, "{\n");
lf_indent(file, +2);
print_define_my_index(file, instruction->file_entry);
print_itrace(file, instruction->file_entry, 1/*putting-value-in-cache*/);
print_idecode_validate(file, instruction, opcodes);
lf_printf(file, "\n");
lf_printf(file, "{\n");
lf_indent(file, +2);
print_icache_body(file,
instruction,
expanded_bits,
cache_rules,
0/*use_defines*/,
0/*get_value_from_cache*/,
1/*put_value_in_cache*/);
if ((code & generate_with_semantic_icache)) {
lf_printf(file, "unsigned_word nia;\n");
lf_printf(file, "cache_entry->address = cia;\n");
lf_printf(file, "cache_entry->semantic = ");
print_function_name(file,
instruction->file_entry->fields[insn_name],
expanded_bits,
function_name_prefix_semantics);
lf_printf(file, ";\n");
print_semantic_body(file,
instruction,
expanded_bits,
opcodes);
lf_printf(file, "\n");
lf_printf(file, "return nia;\n");
}
lf_indent(file, -2);
lf_printf(file, "}\n");
if (!(code & generate_with_semantic_icache)) {
/* return the function propper (main sorts this one out) */
lf_printf(file, "\n");
lf_printf(file, "/* semantic routine */\n");
table_entry_print_cpp_line_nr(file, instruction->file_entry);
lf_printf(file, "return ");
print_function_name(file,
instruction->file_entry->fields[insn_name],
expanded_bits,
function_name_prefix_semantics);
lf_printf(file, ";\n");
lf_print__internal_reference(file);
}
lf_indent(file, -2);
lf_printf(file, "}\n");
}
void
print_icache_definition(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
cache_table *cache_rules = (cache_table*)data;
if (generate_expanded_instructions) {
ASSERT(entry->nr_insn == 1
&& entry->opcode == NULL
&& entry->parent != NULL
&& entry->parent->opcode != NULL);
ASSERT(entry->nr_insn == 1
&& entry->opcode == NULL
&& entry->parent != NULL
&& entry->parent->opcode != NULL
&& entry->parent->opcode_rule != NULL);
print_icache_function(file,
entry->insns,
entry->expanded_bits,
entry->opcode,
cache_rules);
}
else {
print_icache_function(file,
instruction,
NULL,
NULL,
cache_rules);
}
}
void
print_icache_internal_function_declaration(insn_table *table,
lf *file,
void *data,
table_entry *function)
{
ASSERT((code & generate_with_icache) != 0);
if (it_is("internal", function->fields[insn_flags])) {
lf_printf(file, "\n");
lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE",
"\n");
print_function_name(file,
function->fields[insn_name],
NULL,
function_name_prefix_icache);
lf_printf(file, "\n(%s);\n", ICACHE_FUNCTION_FORMAL);
}
}
void
print_icache_internal_function_definition(insn_table *table,
lf *file,
void *data,
table_entry *function)
{
ASSERT((code & generate_with_icache) != 0);
if (it_is("internal", function->fields[insn_flags])) {
lf_printf(file, "\n");
lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE",
"\n");
print_function_name(file,
function->fields[insn_name],
NULL,
function_name_prefix_icache);
lf_printf(file, "\n(%s)\n", ICACHE_FUNCTION_FORMAL);
lf_printf(file, "{\n");
lf_indent(file, +2);
lf_printf(file, "/* semantic routine */\n");
table_entry_print_cpp_line_nr(file, function);
if ((code & generate_with_semantic_icache)) {
lf_print__c_code(file, function->annex);
lf_printf(file, "error(\"Internal function must longjump\\n\");\n");
lf_printf(file, "return 0;\n");
}
else {
lf_printf(file, "return ");
print_function_name(file,
function->fields[insn_name],
NULL,
function_name_prefix_semantics);
lf_printf(file, ";\n");
}
lf_print__internal_reference(file);
lf_indent(file, -2);
lf_printf(file, "}\n");
}
}

56
sim/ppc/gen-icache.h Normal file
View File

@@ -0,0 +1,56 @@
/* 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.
*/
/* Output code to manipulate the instruction cache: either create it
or reference it */
extern void print_icache_body
(lf *file,
insn *instruction,
insn_bits *expanded_bits,
cache_table *cache_rules,
int use_defines,
int get_value_from_cache,
int put_value_in_cache);
/* Output an instruction cache decode function */
extern insn_handler print_icache_declaration;
extern insn_handler print_icache_definition;
/* Output an instruction cache support function */
extern function_handler print_icache_internal_function_declaration;
extern function_handler print_icache_internal_function_definition;
/* Output the instruction cache table data structure */
extern void print_icache_struct
(insn_table *instructions,
cache_table *cache_rules,
lf *file);
/* Output a single instructions decoder */

1282
sim/ppc/gen-idecode.c Normal file

File diff suppressed because it is too large Load Diff

40
sim/ppc/gen-idecode.h Normal file
View File

@@ -0,0 +1,40 @@
/* 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.
*/
extern void gen_idecode_h
(lf *file,
insn_table *table,
cache_table *cache_rules);
extern void gen_idecode_c
(lf *file,
insn_table *table,
cache_table *cache_rules);
/* 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 */
extern void print_idecode_validate
(lf *file,
insn *instruction,
opcode_field *opcodes);

122
sim/ppc/gen-itable.c Normal file
View File

@@ -0,0 +1,122 @@
/* 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.
*/
#include "misc.h"
#include "lf.h"
#include "table.h"
#include "filter.h"
#include "ld-decode.h"
#include "ld-insn.h"
#include "igen.h"
#include "gen-itable.h"
#ifndef NULL
#define NULL 0
#endif
static void
itable_h_insn(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
lf_printf(file, " ");
print_function_name(file,
instruction->file_entry->fields[insn_name],
NULL,
function_name_prefix_itable);
lf_printf(file, ",\n");
}
extern void
gen_itable_h(insn_table *table, lf *file)
{
/* output an enumerated type for each instruction */
lf_printf(file, "typedef enum {\n");
insn_table_traverse_insn(table,
file, NULL,
itable_h_insn);
lf_printf(file, " nr_itable_entries,\n");
lf_printf(file, "} itable_index;\n");
lf_printf(file, "\n");
/* output the table that contains the actual instruction info */
lf_printf(file, "typedef struct _itable_instruction_info {\n");
lf_printf(file, " itable_index nr;\n");
lf_printf(file, " char *format;\n");
lf_printf(file, " char *form;\n");
lf_printf(file, " char *flags;\n");
lf_printf(file, " char *mnemonic;\n");
lf_printf(file, " char *name;\n");
lf_printf(file, " char *file;\n");
lf_printf(file, " int line_nr;\n");
lf_printf(file, "} itable_info;\n");
lf_printf(file, "\n");
lf_printf(file, "extern itable_info itable[nr_itable_entries];\n");
}
/****************************************************************/
static void
itable_c_insn(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
char **fields = instruction->file_entry->fields;
lf_printf(file, " { ");
print_function_name(file,
instruction->file_entry->fields[insn_name],
NULL,
function_name_prefix_itable);
lf_printf(file, ",\n");
lf_printf(file, " \"%s\",\n", fields[insn_format]);
lf_printf(file, " \"%s\",\n", fields[insn_form]);
lf_printf(file, " \"%s\",\n", fields[insn_flags]);
lf_printf(file, " \"%s\",\n", fields[insn_mnemonic]);
lf_printf(file, " \"%s\",\n", fields[insn_name]);
lf_printf(file, " \"%s\",\n", filter_filename (instruction->file_entry->file_name));
lf_printf(file, " %d,\n", instruction->file_entry->line_nr);
lf_printf(file, " },\n");
}
extern void
gen_itable_c(insn_table *table, lf *file)
{
/* output the table that contains the actual instruction info */
lf_printf(file, "#include \"itable.h\"\n");
lf_printf(file, "\n");
lf_printf(file, "itable_info itable[nr_itable_entries] = {\n");
insn_table_traverse_insn(table,
file, NULL,
itable_c_insn);
lf_printf(file, "};\n");
}

28
sim/ppc/gen-itable.h Normal file
View File

@@ -0,0 +1,28 @@
/* 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.
*/
extern void gen_itable_h
(insn_table *table,
lf *file);
extern void gen_itable_c
(insn_table *table,
lf *file);

30
sim/ppc/gen-model.h Normal file
View File

@@ -0,0 +1,30 @@
/* 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.
*/
extern void gen_model_h
(insn_table *table,
lf *file);
extern void gen_model_c
(insn_table *table,
lf *file);

253
sim/ppc/gen-semantics.c Normal file
View File

@@ -0,0 +1,253 @@
/* 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.
*/
#include "misc.h"
#include "lf.h"
#include "table.h"
#include "filter.h"
#include "ld-decode.h"
#include "ld-cache.h"
#include "ld-insn.h"
#include "igen.h"
#include "gen-semantics.h"
#include "gen-icache.h"
#include "gen-idecode.h"
static void
print_semantic_function_header(lf *file,
const char *basename,
insn_bits *expanded_bits,
int is_function_definition)
{
int indent;
lf_printf(file, "\n");
lf_print_function_type(file, SEMANTIC_FUNCTION_TYPE, "EXTERN_SEMANTICS",
(is_function_definition ? "\n" : " "));
indent = print_function_name(file,
basename,
expanded_bits,
function_name_prefix_semantics);
if (is_function_definition)
lf_indent(file, +indent);
else
lf_printf(file, "\n");
lf_printf(file, "(%s)", SEMANTIC_FUNCTION_FORMAL);
if (is_function_definition)
lf_indent(file, -indent);
else
lf_printf(file, ";");
lf_printf(file, "\n");
}
void
print_semantic_declaration(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
if (generate_expanded_instructions) {
ASSERT(entry->nr_insn == 1);
print_semantic_function_header(file,
instruction->file_entry->fields[insn_name],
entry->expanded_bits,
0/* is not function definition*/);
}
else {
print_semantic_function_header(file,
instruction->file_entry->fields[insn_name],
NULL,
0/* is not function definition*/);
}
}
/* generate the semantics.c file */
void
print_idecode_illegal(lf *file,
const char *result)
{
if ((code & generate_jumps))
lf_printf(file, "goto %s_illegal;\n", (code & generate_with_icache) ? "icache" : "semantic");
else if ((code & generate_with_icache))
lf_printf(file, "%s icache_illegal(%s);\n", result, ICACHE_FUNCTION_ACTUAL);
else
lf_printf(file, "%s semantic_illegal(%s);\n", result, SEMANTIC_FUNCTION_ACTUAL);
}
void
print_semantic_body(lf *file,
insn *instruction,
insn_bits *expanded_bits,
opcode_field *opcodes)
{
print_itrace(file, instruction->file_entry, 0/*put_value_in_cache*/);
/* validate the instruction, if a cache this has already been done */
if (!(code & generate_with_icache))
print_idecode_validate(file, instruction, opcodes);
/* generate the profiling call - this is delayed until after the
instruction has been verified */
lf_printf(file, "\n");
lf_printf(file, "/* monitoring: */\n");
lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE) {\n");
lf_printf(file, " mon_issue(");
print_function_name(file,
instruction->file_entry->fields[insn_name],
NULL,
function_name_prefix_itable);
lf_printf(file, ", processor, cia);\n");
lf_printf(file, "}\n");
/* generate the code (or at least something */
lf_printf(file, "\n");
lf_printf(file, "/* semantics: */\n");
lf_printf(file, "nia = cia + %d;\n", insn_bit_size / 8);
if (instruction->file_entry->annex != NULL) {
/* true code */
table_entry_print_cpp_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__internal_reference(file);
}
else if (it_is("nop", instruction->file_entry->fields[insn_flags])) {
lf_print__internal_reference(file);
}
else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
/* unimplemented floating point instruction - call for assistance */
lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n");
table_entry_print_cpp_line_nr(file, instruction->file_entry);
lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
lf_print__internal_reference(file);
}
else {
/* abort so it is implemented now */
table_entry_print_cpp_line_nr(file, instruction->file_entry);
lf_putstr(file, "error(\"%s:%d:0x%08lx:%s unimplemented\\n\",\n");
lf_printf(file, " itable[MY_INDEX].file, itable[MY_INDEX].line_nr, (long)cia, itable[MY_INDEX].name);\n");
lf_print__internal_reference(file);
}
}
static void
print_c_semantic(lf *file,
insn *instruction,
insn_bits *expanded_bits,
opcode_field *opcodes,
cache_table *cache_rules)
{
lf_printf(file, "{\n");
lf_indent(file, +2);
print_define_my_index(file, instruction->file_entry);
lf_printf(file, "\n");
print_icache_body(file,
instruction,
expanded_bits,
cache_rules,
(code & generate_with_direct_access_icache),
(code & generate_with_icache)/*get_value_from_cache*/,
0/*put_value_in_cache*/);
lf_printf(file, "unsigned_word nia;\n");
print_semantic_body(file,
instruction,
expanded_bits,
opcodes);
lf_printf(file, "return nia;\n");
/* generate something to clean up any #defines created for the cache */
if ((code & generate_with_direct_access_icache))
print_icache_body(file,
instruction,
expanded_bits,
cache_rules,
1/*use_defines*/,
0/*get_value_from_cache*/,
1/*put_value_in_cache*/);
lf_indent(file, -2);
lf_printf(file, "}\n");
}
static void
print_c_semantic_function(lf *file,
insn *instruction,
insn_bits *expanded_bits,
opcode_field *opcodes,
cache_table *cache_rules)
{
/* build the semantic routine to execute the instruction */
print_semantic_function_header(file,
instruction->file_entry->fields[insn_name],
expanded_bits,
1/*is-function-definition*/);
print_c_semantic(file,
instruction,
expanded_bits,
opcodes,
cache_rules);
}
void
print_semantic_definition(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
cache_table *cache_rules = (cache_table*)data;
if (generate_expanded_instructions) {
ASSERT(entry->nr_insn == 1
&& entry->opcode == NULL
&& entry->parent != NULL
&& entry->parent->opcode != NULL);
ASSERT(entry->nr_insn == 1
&& entry->opcode == NULL
&& entry->parent != NULL
&& entry->parent->opcode != NULL
&& entry->parent->opcode_rule != NULL);
print_c_semantic_function(file,
entry->insns,
entry->expanded_bits,
entry->parent->opcode,
cache_rules);
}
else {
print_c_semantic_function(file, instruction,
NULL, NULL,
cache_rules);
}
}

81
sim/ppc/gen-semantics.h Normal file
View File

@@ -0,0 +1,81 @@
/* 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.
*/
/* Creates the files semantics.[hc].
The generated file semantics contains functions that implement the
operations required to model a single target processor instruction.
Several different variations on the semantics file can be created:
o uncached
No instruction cache exists. The semantic function
needs to generate any required values locally.
o cached - separate cracker and semantic
Two independant functions are created. Firstly the
function that cracks an instruction entering it into a
cache and secondly the semantic function propper that
uses the cache.
o cached - semantic + cracking semantic
The function that cracks the instruction and enters
all values into the cache also contains a copy of the
semantic code (avoiding the need to call both the
cracker and the semantic function when there is a
cache miss).
For each of these general forms, several refinements can occure:
o do/don't duplicate/expand semantic functions
As a consequence of decoding an instruction, the
decoder, as part of its table may have effectivly made
certain of the variable fields in an instruction
constant. Separate functions for each of the
alternative values for what would have been treated as
a variable part can be created.
o use cache struct directly.
When a cracking cache is present, the semantic
functions can be generated to either hold intermediate
cache values in local variables or always refer to the
contents of the cache directly. */
extern insn_handler print_semantic_declaration;
extern insn_handler print_semantic_definition;
extern void print_idecode_illegal
(lf *file,
const char *result);
extern void print_semantic_body
(lf *file,
insn *instruction,
insn_bits *expanded_bits,
opcode_field *opcodes);

128
sim/ppc/gen-support.c Normal file
View File

@@ -0,0 +1,128 @@
/* 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.
*/
#include "misc.h"
#include "lf.h"
#include "table.h"
#include "filter.h"
#include "ld-decode.h"
#include "ld-cache.h"
#include "ld-insn.h"
#include "igen.h"
#include "gen-semantics.h"
#include "gen-support.h"
static void
print_support_function_name(lf *file,
table_entry *function,
int is_function_definition)
{
if (it_is("internal", function->fields[insn_flags])) {
lf_print_function_type(file, SEMANTIC_FUNCTION_TYPE, "INLINE_SUPPORT",
(is_function_definition ? "\n" : " "));
print_function_name(file,
function->fields[function_name],
NULL,
function_name_prefix_semantics);
lf_printf(file, "\n(%s)", SEMANTIC_FUNCTION_FORMAL);
if (!is_function_definition)
lf_printf(file, ";");
lf_printf(file, "\n");
}
else {
lf_print_function_type(file,
function->fields[function_type],
"INLINE_SUPPORT",
(is_function_definition ? "\n" : " "));
lf_printf(file, "%s\n(%s)%s",
function->fields[function_name],
function->fields[function_param],
(is_function_definition ? "\n" : ";\n"));
}
}
static void
support_h_function(insn_table *entry,
lf *file,
void *data,
table_entry *function)
{
ASSERT(function->fields[function_type] != NULL);
ASSERT(function->fields[function_param] != NULL);
print_support_function_name(file,
function,
0/*!is_definition*/);
lf_printf(file, "\n");
}
extern void
gen_support_h(insn_table *table,
lf *file)
{
/* output a declaration for all functions */
insn_table_traverse_function(table,
file, NULL,
support_h_function);
}
static void
support_c_function(insn_table *table,
lf *file,
void *data,
table_entry *function)
{
ASSERT(function->fields[function_type] != NULL);
print_support_function_name(file,
function,
1/*!is_definition*/);
table_entry_print_cpp_line_nr(file, function);
lf_printf(file, "{\n");
lf_indent(file, +2);
lf_print__c_code(file, function->annex);
if (it_is("internal", function->fields[insn_flags])) {
lf_printf(file, "error(\"Internal function must longjump\\n\");\n");
lf_printf(file, "return 0;\n");
}
lf_indent(file, -2);
lf_printf(file, "}\n");
lf_print__internal_reference(file);
lf_printf(file, "\n");
}
void
gen_support_c(insn_table *table,
lf *file)
{
lf_printf(file, "#include \"cpu.h\"\n");
lf_printf(file, "#include \"idecode.h\"\n");
lf_printf(file, "#include \"support.h\"\n");
lf_printf(file, "\n");
/* output a definition (c-code) for all functions */
insn_table_traverse_function(table,
file, NULL,
support_c_function);
}

29
sim/ppc/gen-support.h Normal file
View File

@@ -0,0 +1,29 @@
/* 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.
*/
extern void gen_support_h
(insn_table *table,
lf *file);
extern void gen_support_c
(insn_table *table,
lf *file);

142
sim/ppc/hw_core.c Normal file
View File

@@ -0,0 +1,142 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, 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 _HW_CORE_C_
#define _HW_CORE_C_
#include "device_table.h"
#include "corefile.h"
/* DEVICE
core - root of the device tree
DESCRIPTION
The core device positioned at the root of the device tree appears
to its child devices as a normal device just like every other
device in the tree.
Internally it is implemented using a core object. Requests to
attach (or detach) address spaces are passed to that core object.
Requests to transfer (DMA) data are reflected back down the device
tree using the core_map data transfer methods.
PROPERTIES
None.
*/
static void
hw_core_init_address_callback(device *me)
{
core *memory = (core*)device_data(me);
core_init(memory);
}
static void
hw_core_attach_address_callback(device *me,
const char *name,
attach_type attach,
int space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
device *who) /*callback/default*/
{
core *memory = (core*)device_data(me);
if (space != 0)
error("core_attach_address_callback() invalid address space\n");
core_attach(memory,
attach,
space,
access,
addr,
nr_bytes,
who);
}
static unsigned
hw_core_dma_read_buffer_callback(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
core *memory = (core*)device_data(me);
return core_map_read_buffer(core_readable(memory),
dest,
addr,
nr_bytes);
}
static unsigned
hw_core_dma_write_buffer_callback(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
core *memory = (core*)device_data(me);
core_map *map = (violate_read_only_section
? core_readable(memory)
: core_writeable(memory));
return core_map_write_buffer(map,
source,
addr,
nr_bytes);
}
static device_callbacks const hw_core_callbacks = {
{ hw_core_init_address_callback, },
{ hw_core_attach_address_callback, },
{ NULL, }, /* IO */
{ hw_core_dma_read_buffer_callback,
hw_core_dma_write_buffer_callback, },
{ NULL, }, /* interrupt */
{ generic_device_unit_decode,
generic_device_unit_encode, }
};
static void *
hw_core_create(const char *name,
const device_unit *unit_address,
const char *args)
{
core *memory = core_create();
return memory;
}
const device_descriptor hw_core_device_descriptor[] = {
{ "core", hw_core_create, &hw_core_callbacks },
{ NULL },
};
#endif /* _HW_CORE_C_ */

316
sim/ppc/hw_memory.c Normal file
View File

@@ -0,0 +1,316 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, 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 _HW_MEMORY_C_
#define _HW_MEMORY_C_
#ifndef STATIC_INLINE_HW_MEMORY
#define STATIC_INLINE_HW_MEMORY STATIC_INLINE
#endif
#include "device_table.h"
/* DEVICE
memory - description of system memory
DESCRIPTION
This device describes the size and location of the banks of
physical memory within the simulation.
In addition, this device supports the "claim" and "release" methods
that can be used by OpenBoot client programs to manage the
allocation of physical memory.
PROPERTIES
reg = { <address> <size> } (required)
Each pair specify one bank of memory.
available = { <address> <size> } (automatic)
Each pair specifies a block of memory that is currently unallocated.
*/
typedef struct _memory_reg_spec {
unsigned32 base;
unsigned32 size;
} memory_reg_spec;
typedef struct _hw_memory_chunk hw_memory_chunk;
struct _hw_memory_chunk {
unsigned_word address;
unsigned_word size;
unsigned_word alloc_address;
unsigned_word alloc_size;
int available;
hw_memory_chunk *next;
};
typedef struct _hw_memory_device {
hw_memory_chunk *heap;
} hw_memory_device;
static void *
hw_memory_create(const char *name,
const device_unit *unit_address,
const char *args)
{
hw_memory_device *hw_memory = ZALLOC(hw_memory_device);
return hw_memory;
}
static void
hw_memory_set_available(device *me,
hw_memory_device *hw_memory)
{
hw_memory_chunk *chunk = NULL;
memory_reg_spec *available = NULL;
int nr_available = 0;
int curr = 0;
int sizeof_available = 0;
/* determine the nr of available chunks */
chunk = hw_memory->heap;
nr_available = 0;
while (chunk != NULL) {
if (chunk->available)
nr_available += 1;
chunk = chunk->next;
}
/* now create the available struct */
ASSERT(nr_available > 0);
sizeof_available = sizeof(memory_reg_spec) * nr_available;
available = zalloc(sizeof_available);
chunk = hw_memory->heap;
curr = 0;
while (chunk != NULL) {
if (chunk->available) {
available[curr].base = H2BE_4(chunk->address);
available[curr].size = H2BE_4(chunk->size);
curr += 1;
}
chunk = chunk->next;
}
/* update */
device_set_array_property(me, "available", available, sizeof_available);
zfree(available);
}
static void
hw_memory_init_address(device *me)
{
hw_memory_device *hw_memory = (hw_memory_device*)device_data(me);
const device_property *reg = device_find_array_property(me, "reg");
const memory_reg_spec *spec = reg->array;
int nr_entries = reg->sizeof_array / sizeof(*spec);
/* sanity check reg property */
if ((reg->sizeof_array % sizeof(*spec)) != 0)
error("devices/%s reg property of incorrect size\n", device_name(me));
/* free up any previous structures */
{
hw_memory_chunk *curr_chunk = hw_memory->heap;
hw_memory->heap = NULL;
while (curr_chunk != NULL) {
hw_memory_chunk *dead_chunk = curr_chunk;
curr_chunk = dead_chunk->next;
dead_chunk->next = NULL;
zfree(dead_chunk);
}
}
/* count/allocate memory entries */
{
hw_memory_chunk **curr_chunk = &hw_memory->heap;
while (nr_entries > 0) {
hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk);
new_chunk->address = BE2H_4(spec->base);
new_chunk->size = BE2H_4(spec->size);
new_chunk->available = 1;
device_attach_address(device_parent(me),
device_name(me),
attach_raw_memory,
0 /*address space*/,
new_chunk->address,
new_chunk->size,
access_read_write_exec,
me);
spec++;
nr_entries--;
*curr_chunk = new_chunk;
curr_chunk = &new_chunk->next;
}
}
/* initialize the alloc property for this device */
hw_memory_set_available(me, hw_memory);
}
static void
hw_memory_instance_delete(device_instance *instance)
{
return;
}
static unsigned_word
hw_memory_instance_claim(device_instance *instance,
unsigned_word address,
unsigned_word size,
unsigned_word alignment)
{
hw_memory_device *hw_memory = device_instance_data(instance);
hw_memory_chunk *chunk = NULL;
DTRACE(memory, ("claim - address=0x%lx size=0x%lx alignment=%d\n",
(unsigned long)address,
(unsigned long)size,
(int)alignment));
/* find a chunk candidate, either according to address or alignment */
if (alignment == 0) {
chunk = hw_memory->heap;
while (chunk != NULL
&& (address+size) > (chunk->address+chunk->size))
chunk = chunk->next;
if (chunk == NULL || address < chunk->address || !chunk->available)
error("hw_memory_instance_claim: failed to allocate @0x%lx, size %ld\n",
(unsigned long)address, (unsigned long)size);
}
else {
chunk = hw_memory->heap;
while (chunk != NULL && chunk->size < size)
chunk = chunk->next;
if (chunk == NULL || FLOOR_PAGE(alignment-1) > 0)
error("hw_memory_instance_claim: failed to allocate %ld, align %ld\n",
(unsigned long)size, (unsigned long)size);
address = chunk->address;
}
/* break of a part before this memory if needed */
ASSERT(address >= chunk->address);
if (FLOOR_PAGE(address) > chunk->address) {
hw_memory_chunk *last_chunk = chunk;
/* insert a new earlier chunk */
chunk = ZALLOC(hw_memory_chunk);
chunk->next = last_chunk->next;
last_chunk->next = chunk;
/* adjust the address/size */
chunk->address = FLOOR_PAGE(address);
chunk->size = last_chunk->size - (chunk->address - last_chunk->address);
last_chunk->size = chunk->address - last_chunk->address;
}
ASSERT(FLOOR_PAGE(address) == chunk->address);
/* break of a bit after this chunk if needed */
if (ALIGN_PAGE(address+size) < chunk->address + chunk->size) {
hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
/* insert it in to the list */
next_chunk->next = chunk->next;
chunk->next = next_chunk;
next_chunk->available = 1;
/* adjust the address/size */
next_chunk->address = ALIGN_PAGE(address+size);
next_chunk->size = chunk->address + chunk->size - next_chunk->address;
chunk->size = next_chunk->address - chunk->address;
}
ASSERT(ALIGN_PAGE(address+size) == chunk->address + chunk->size);
/* now allocate it */
chunk->alloc_address = address;
chunk->alloc_size = size;
chunk->available = 0;
hw_memory_set_available(device_instance_device(instance), hw_memory);
return address;
}
static void
hw_memory_instance_release(device_instance *instance,
unsigned_word address,
unsigned_word length)
{
hw_memory_device *hw_memory = device_instance_data(instance);
hw_memory_chunk *chunk = hw_memory->heap;
while (chunk != NULL) {
if (chunk->alloc_address == address
&& chunk->alloc_size == length
&& chunk->available == 0) {
/* free this chunk */
chunk->available = 1;
/* check for merge */
chunk = hw_memory->heap;
while (chunk != NULL) {
if (chunk->available
&& chunk->next != NULL && chunk->next->available) {
/* adjacent */
hw_memory_chunk *delete = chunk->next;
ASSERT(chunk->address + chunk->size == delete->address);
chunk->size += delete->size;
chunk->next = delete->next;
zfree(delete);
}
}
/* update the corresponding property */
hw_memory_set_available(device_instance_device(instance), hw_memory);
return;
}
chunk = chunk->next;
}
error("hw_memory_instance_release: Address 0x%lx, size %ld not found\n",
(unsigned long)address, (unsigned long)length);
/* FIXME - dump allocated */
/* FIXME - dump arguments */
}
static device_instance_callbacks const hw_memory_instance_callbacks = {
hw_memory_instance_delete,
NULL /*read*/, NULL /*write*/, NULL /*seek*/,
hw_memory_instance_claim, hw_memory_instance_release
};
static device_instance *
hw_memory_create_instance(device *me,
const char *path,
const char *args)
{
return device_create_instance_from(me, NULL,
device_data(me), /* nothing better */
path, args,
&hw_memory_instance_callbacks);
}
static device_callbacks const hw_memory_callbacks = {
{ hw_memory_init_address, },
{ NULL, }, /* address */
{ NULL, }, /* IO */
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, }, /* unit */
hw_memory_create_instance,
};
const device_descriptor hw_memory_device_descriptor[] = {
{ "memory", hw_memory_create, &hw_memory_callbacks },
{ NULL },
};
#endif /* _HW_MEMORY_C_ */

View File

@@ -27,18 +27,12 @@
#endif
#include "device_table.h"
#include "cpu.h"
#include "cpu.h"
#include <stdio.h>
#include <fcntl.h>
#if 0
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
@@ -59,31 +53,65 @@
#define WITH_STDIO DO_USE_STDIO
#endif
/* Device:
/* DEVICE
pal@<address>
pal - glue logic device containing assorted junk
Description:
DESCRIPTION
Typical hardware dependant hack. This device allows the firmware
to gain access to all the things the firmware needs (but the OS
doesn't). All registers are little endian (byte 0 is the least
significant) and must be accessed correctly aligned.
doesn't).
The pal contains the following registers. Except for the interrupt
level register, each of the below is 8 bytes in size and must be
accessed using correct alignment. For 16 and 32 bit accesses the
bytes not directed to the register are ignored:
<address> + 0: write - halts simulation with exit code byte[0].
|0 reset register (write)
|4 processor id register (read)
|8 interrupt port (write)
|9 interrupt level (write)
|12 processor count register (read)
|16 tty input fifo register (read)
|20 tty input status register (read)
|24 tty output fifo register (write)
|28 tty output status register (read)
Reset register (write) halts the simulator exiting with the
value written.
<address> + 4: read - processor nr in byte[0].
Processor id register (read) returns the processor number (0
.. N-1) of the processor performing the read.
<address> + 8: write - send interrupt message to port byte[0] with
value byte[1].
The interrupt registers should be accessed as a pair (using a 16 or
32 bit store). The low byte specifies the interrupt port while the
high byte specifies the level to drive that port at. By
convention, the pal's interrupt ports (int0, int1, ...) are wired
up to the corresponding processor's level sensative external
interrupt pin. Eg: A two byte write to address 8 of 0x0102
(big-endian) will result in processor 2's external interrupt pin to
be asserted.
Processor count register (read) returns the total number of
processors active in the current simulation.
TTY input fifo register (read), if the TTY input status register
indicates a character is available by being nonzero, returns the
next available character from the pal's tty input port.
Similarly, the TTY output fifo register (write), if the TTY output
status register indicates the output fifo is not full by being
nonzero, outputs the character written to the tty's output port.
PROPERTIES
<address> + 12: read - nr processors in byte[0].
Properties:
NONE. */
reg = <address> <size> (required)
Specify the address (within the parent bus) that this device is to
live.
*/
enum {
@@ -259,13 +287,6 @@ hw_pal_io_write_buffer_callback(device *me,
/* instances of the hw_pal device */
static void *
hw_pal_instance_create_callback(device *me,
const char *args)
{
/* make life easier, attach the hw_pal data to the instance */
return device_data(me);
}
static void
hw_pal_instance_delete_callback(device_instance *instance)
@@ -306,26 +327,45 @@ hw_pal_instance_write_callback(device_instance *instance,
return i;
}
static const device_instance_callbacks hw_pal_instance_callbacks = {
hw_pal_instance_delete_callback,
hw_pal_instance_read_callback,
hw_pal_instance_write_callback,
};
static device_instance *
hw_pal_create_instance(device *me,
const char *path,
const char *args)
{
return device_create_instance_from(me, NULL,
device_data(me),
path, args,
&hw_pal_instance_callbacks);
}
static const device_interrupt_port_descriptor hw_pal_interrupt_ports[] = {
{ "int", 0, MAX_NR_PROCESSORS },
{ NULL }
};
static device_callbacks const hw_pal_callbacks = {
{ generic_device_init_address, },
{ NULL, }, /* address */
{ hw_pal_io_read_buffer_callback,
hw_pal_io_write_buffer_callback, },
{ NULL, }, /* DMA */
{ NULL, }, /* interrupt */
{ NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
{ NULL, }, /* unit */
{ hw_pal_instance_create_callback,
hw_pal_instance_delete_callback,
hw_pal_instance_read_callback,
hw_pal_instance_write_callback, },
hw_pal_create_instance,
};
static void *
hw_pal_create(const char *name,
const device_unit *unit_address,
const char *args,
device *parent)
const char *args)
{
/* create the descriptor */
hw_pal_device *hw_pal = ZALLOC(hw_pal_device);

View File

@@ -1,6 +1,6 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
Copyright (C) 1994-1996, 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
@@ -86,8 +86,8 @@
else \
XER &= (~xer_carry); */ \
} \
ITRACE(trace_alu, (" Result = %ld (0x%lx), XER = %ld\n", \
(long)alu_result, (long)alu_result, (long)XER)); \
TRACE(trace_alu, (" Result = %ld (0x%lx), XER = %ld\n", \
(long)alu_result, (long)alu_result, (long)XER)); \
/* Update the Result Conditions if needed */ \
CR0_COMPARE(alu_result, 0, Rc); \
/* assign targ same */ \
@@ -281,9 +281,9 @@ do { \
do { \
if (Rc) { \
CR_COMPARE(0, LHS, RHS); \
ITRACE(trace_alu, \
("CR=0x%08lx, LHS=%ld, RHS=%ld\n", \
(unsigned long)CR, (long)LHS, (long)RHS)); \
TRACE(trace_alu, \
("CR=0x%08lx, LHS=%ld, RHS=%ld\n", \
(unsigned long)CR, (long)LHS, (long)RHS)); \
} \
} while (0)

File diff suppressed because it is too large Load Diff

186
sim/ppc/igen.h Normal file
View File

@@ -0,0 +1,186 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, 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.
*/
/* What does the instruction look like - bit ordering and size */
extern int hi_bit_nr;
extern int insn_bit_size;
/* generation options: */
enum {
generate_with_icache = 0x1,
generate_with_semantic_icache = 0x2,
generate_with_direct_access_icache = 0x4,
};
typedef enum {
/* Transfer control to an instructions semantic code using the the
standard call/return mechanism */
generate_calls = 0x10,
/* In addition, pre-decode an instructions opcode fields (entering
them into an icache) so that semantic code can avoid the need to
re-decode fields each time it is executed */
generate_calls_with_icache
= generate_calls | generate_with_icache,
/* In addition, the instruction decode code includes a duplicated
copy of the instructions semantic code. This avoids the need to
perform two calls (one to decode an instructions opcode fields
and one to execute the instruction) when there is a miss of the
icache */
generate_calls_with_semantic_icache
= generate_calls_with_icache | generate_with_semantic_icache,
/* In addition, the semantic function refers to icache entries
directly instead of first moving them into local variables */
generate_calls_with_direct_access_icache
= generate_calls_with_icache | generate_with_direct_access_icache,
generate_calls_with_direct_access_semantic_icache
= generate_calls_with_direct_access_icache | generate_with_semantic_icache,
/* Transfer control to an instructions semantic code using
(computed) goto's instead of the more conventional call/return
mechanism */
generate_jumps = 0x20,
/* As for generate_calls_with_icache but applies to jumping code */
generate_jumps_with_icache
= generate_jumps | generate_with_icache,
/* As for generate_calls_with_semantic_icache but applies to jumping
code */
generate_jumps_with_semantic_icache
= generate_jumps_with_icache | generate_with_semantic_icache,
/* As for generate_calls_with_direct_access_icache */
generate_jumps_with_direct_access_icache
= generate_jumps_with_icache | generate_with_direct_access_icache,
generate_jumps_with_direct_access_semantic_icache
= generate_jumps_with_direct_access_icache | generate_with_semantic_icache,
} igen_code;
extern igen_code code;
extern int icache_size;
/* Instruction expansion?
Should the semantic code for each instruction, when the oportunity
arrises, be expanded according to the variable opcode files that
the instruction decode process renders constant */
extern int generate_expanded_instructions;
/* SMP?
Should the generated code include SMP support (>0) and if so, for
how many processors? */
extern int generate_smp;
/* Misc junk */
/* Function header definitions */
/* Cache functions: */
#define ICACHE_FUNCTION_FORMAL \
"cpu *processor,\n\
instruction_word instruction,\n\
unsigned_word cia,\n\
idecode_cache *cache_entry"
#define ICACHE_FUNCTION_ACTUAL "processor, instruction, cia, cache_entry"
#define ICACHE_FUNCTION_TYPE \
((code & generate_with_semantic_icache) \
? SEMANTIC_FUNCTION_TYPE \
: "idecode_semantic *")
/* Semantic functions: */
#define SEMANTIC_FUNCTION_FORMAL \
((code & generate_with_icache) \
? "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia" \
: "cpu *processor,\n instruction_word instruction,\n unsigned_word cia")
#define SEMANTIC_FUNCTION_ACTUAL \
((code & generate_with_icache) \
? "processor, instruction, cia, cache_entry" \
: "processor, instruction, cia")
#define SEMANTIC_FUNCTION_TYPE "unsigned_word"
extern void print_define_my_index
(lf *file,
table_entry *file_entry);
extern void print_itrace
(lf *file,
table_entry *file_entry,
int idecode);
typedef enum {
function_name_prefix_semantics,
function_name_prefix_idecode,
function_name_prefix_itable,
function_name_prefix_goto,
function_name_prefix_icache,
function_name_prefix_none
} lf_function_name_prefixes;
extern int print_function_name
(lf *file,
const char *basename,
insn_bits *expanded_bits,
lf_function_name_prefixes prefix);

View File

@@ -22,76 +22,77 @@
#ifndef _INLINE_C_
#define _INLINE_C_
#if BITS_INLINE
#include "config.h"
#include "ppc-config.h"
#include "inline.h"
#if (BITS_INLINE & INCLUDE_MODULE)
#include "bits.c"
#endif
#if SIM_ENDIAN_INLINE
#if (SIM_ENDIAN_INLINE & INCLUDE_MODULE)
#include "sim-endian.c"
#endif
#if ICACHE_INLINE
#if (ICACHE_INLINE & INCLUDE_MODULE)
#include "icache.c"
#endif
#if CORE_INLINE
#if (CORE_INLINE & INCLUDE_MODULE)
#include "corefile.c"
#endif
#if VM_INLINE
#if (VM_INLINE & INCLUDE_MODULE)
#include "vm.c"
#endif
#if CPU_INLINE
#include "cpu.c"
#endif
#if EVENTS_INLINE
#if (EVENTS_INLINE & INCLUDE_MODULE)
#include "events.c"
#endif
#if MODEL_INLINE
#if (MODEL_INLINE & INCLUDE_MODULE)
#include "model.c"
#endif
#if OPTIONS_INLINE
#if (OPTIONS_INLINE & INCLUDE_MODULE)
#include "options.c"
#endif
#if FUNCTION_UNIT_INLINE
#include "function_unit.c"
#endif
#if MON_INLINE
#if (MON_INLINE & INCLUDE_MODULE)
#include "mon.c"
#endif
#if REGISTERS_INLINE
#if (REGISTERS_INLINE & INCLUDE_MODULE)
#include "registers.c"
#endif
#if INTERRUPTS_INLINE
#if (INTERRUPTS_INLINE & INCLUDE_MODULE)
#include "interrupts.c"
#endif
#if DEVICE_TREE_INLINE
#include "device_tree.c"
#if (DEVICE_INLINE & INCLUDE_MODULE)
#include "device.c"
#endif
#if DEVICES_INLINE
#include "devices.c"
#endif
#if SPREG_INLINE
#if (SPREG_INLINE & INCLUDE_MODULE)
#include "spreg.c"
#endif
#if SEMANTICS_INLINE
#if (SEMANTICS_INLINE & INCLUDE_MODULE)
#include "semantics.c"
#endif
#if IDECODE_INLINE
#if (IDECODE_INLINE & INCLUDE_MODULE)
#include "idecode.c"
#endif
#if (SUPPORT_INLINE & INCLUDE_MODULE)
#include "support.c"
#endif
#if (OS_EMUL_INLINE & INCLUDE_MODULE)
#include "os_emul.c"
#endif
#endif

View File

@@ -22,154 +22,447 @@
#ifndef _INLINE_H_
#define _INLINE_H_
#if SIM_ENDIAN_INLINE
#if SIM_ENDIAN_INLINE == 2
#define INLINE_SIM_ENDIAN static INLINE
#define STATIC(TYPE) static TYPE
/* sim_endian is always inlined */
#if !defined(_SIM_ENDIAN_C_) && (SIM_ENDIAN_INLINE & INCLUDE_MODULE)
# if (SIM_ENDIAN_INLINE & INLINE_MODULE)
# define INLINE_SIM_ENDIAN(TYPE) static INLINE TYPE UNUSED
# define EXTERN_SIM_ENDIAN(TYPE) static TYPE UNUSED
# else
# define INLINE_SIM_ENDIAN(TYPE) static TYPE UNUSED
# define EXTERN_SIM_ENDIAN(TYPE) static TYPE UNUSED
# endif
#else
#define INLINE_SIM_ENDIAN static
#endif
# define INLINE_SIM_ENDIAN(TYPE) TYPE
# define EXTERN_SIM_ENDIAN(TYPE) TYPE
#endif
#if ICACHE_INLINE
#if ICACHE_INLINE == 2
#define INLINE_ICACHE static INLINE
#if (SIM_ENDIAN_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_SIM_ENDIAN(TYPE) static INLINE TYPE
#else
#define INLINE_ICACHE static
#endif
# define STATIC_INLINE_SIM_ENDIAN(TYPE) static TYPE
#endif
#if CORE_INLINE
#if CORE_INLINE == 2
#define INLINE_CORE static INLINE
/* bits is always inlined */
#if !defined(_BITS_C_) && (BITS_INLINE & INCLUDE_MODULE)
# if (BITS_INLINE & INLINE_MODULE)
# define INLINE_BITS(TYPE) static INLINE TYPE UNUSED
# define EXTERN_BITS(TYPE) static TYPE UNUSED
# else
# define INLINE_BITS(TYPE) static TYPE UNUSED
# define EXTERN_BITS(TYPE) static TYPE UNUSED
# endif
#else
#define INLINE_CORE static
#endif
# define INLINE_BITS(TYPE) TYPE
# define EXTERN_BITS(TYPE) TYPE
#endif
#if VM_INLINE
#if VM_INLINE == 2
#define INLINE_VM static INLINE
#if (BITS_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_BITS(TYPE) static INLINE TYPE
#else
#define INLINE_VM static
#endif
# define STATIC_INLINE_BITS(TYPE) static TYPE
#endif
#if CPU_INLINE
#if CPU_INLINE == 2
#define INLINE_CPU static INLINE
/* core is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_CORE_C_) && (CORE_INLINE & INCLUDE_MODULE)
# if (CORE_INLINE & INLINE_MODULE)
# define INLINE_CORE(TYPE) static INLINE TYPE UNUSED
# define EXTERN_CORE(TYPE) static TYPE UNUSED
#else
#define INLINE_CPU static
# define INLINE_CORE(TYPE) static TYPE UNUSED
# define EXTERN_CORE(TYPE) static TYPE UNUSED
#endif
#endif
#if MODEL_INLINE
#if MODEL_INLINE == 2
#define INLINE_MODEL static INLINE
#else
#define INLINE_MODEL static
#endif
#define STATIC_MODEL static
#define EXTERN_MODEL static
# define INLINE_CORE(TYPE) TYPE
# define EXTERN_CORE(TYPE) TYPE
#endif
#if BITS_INLINE
#if BITS_INLINE == 2
#define INLINE_BITS static INLINE
#if (CORE_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_CORE(TYPE) static INLINE TYPE
#else
#define INLINE_BITS static
#endif
# define STATIC_INLINE_CORE(TYPE) static TYPE
#endif
#if EVENTS_INLINE
#if EVENTS_INLINE == 2
#define INLINE_EVENTS static INLINE
/* vm is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_VM_C_) && (VM_INLINE & INCLUDE_MODULE)
# if (VM_INLINE & INLINE_MODULE)
# define INLINE_VM(TYPE) static INLINE TYPE UNUSED
# define EXTERN_VM(TYPE) static TYPE UNUSED
#else
#define INLINE_EVENTS static
# define INLINE_VM(TYPE) static TYPE UNUSED
# define EXTERN_VM(TYPE) static TYPE UNUSED
#endif
#endif
#if MON_INLINE
#if MON_INLINE == 2
#define INLINE_MON static INLINE
#else
#define INLINE_MON static
#endif
# define INLINE_VM(TYPE) TYPE
# define EXTERN_VM(TYPE) TYPE
#endif
#if REGISTERS_INLINE
#if REGISTERS_INLINE == 2
#define INLINE_REGISTERS static INLINE
#if (VM_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_VM(TYPE) static INLINE TYPE
#else
#define INLINE_REGISTERS static
#endif
# define STATIC_INLINE_VM(TYPE) static TYPE
#endif
#if INTERRUPTS_INLINE
#if INTERRUPTS_INLINE == 2
#define INLINE_INTERRUPTS static INLINE
/* cpu is always inlined */
#if !defined(_CPU_C_) && (CPU_INLINE & INCLUDE_MODULE)
# if (CPU_INLINE & INLINE_MODULE)
# define INLINE_CPU(TYPE) static INLINE TYPE UNUSED
# define EXTERN_CPU(TYPE) static TYPE UNUSED
#else
#define INLINE_INTERRUPTS static
# define INLINE_CPU(TYPE) static TYPE UNUSED
# define EXTERN_CPU(TYPE) static TYPE UNUSED
#endif
#endif
#if DEVICE_TREE_INLINE
#if DEVICE_TREE_INLINE == 2
#define INLINE_DEVICE_TREE static INLINE
#else
#define INLINE_DEVICE_TREE static
#endif
# define INLINE_CPU(TYPE) TYPE
# define EXTERN_CPU(TYPE) TYPE
#endif
#if DEVICES_INLINE
#if DEVICES_INLINE == 2
#define INLINE_DEVICES static INLINE
#if (CPU_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_CPU(TYPE) static INLINE TYPE
#else
#define INLINE_DEVICES static
#endif
#define STATIC_DEVICES static
# define STATIC_INLINE_CPU(TYPE) static TYPE
#endif
#if SPREG_INLINE
#if SPREG_INLINE == 2
#define INLINE_SPREG static INLINE
/* model is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_MODEL_C_) && (MODEL_INLINE & INCLUDE_MODULE)
# if (MODEL_INLINE & INLINE_MODULE)
# define INLINE_MODEL(TYPE) static INLINE TYPE UNUSED
# define EXTERN_MODEL(TYPE) static TYPE UNUSED
#else
#define INLINE_SPREG static
# define INLINE_MODEL(TYPE) static TYPE UNUSED
# define EXTERN_MODEL(TYPE) static TYPE UNUSED
#endif
#endif
#if SEMANTICS_INLINE && !defined(_SEMANTICS_C_)
#if SEMANTICS_INLINE == 2
#define INLINE_SEMANTICS static INLINE
#else
#define INLINE_SEMANTICS static
#endif
#define STATIC_SEMANTICS static
# define INLINE_MODEL(TYPE) TYPE
# define EXTERN_MODEL(TYPE) TYPE
#endif
#if IDECODE_INLINE
#if IDECODE_INLINE == 2
#define INLINE_IDECODE static INLINE
#if (MODEL_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_MODEL(TYPE) static INLINE TYPE
#else
#define INLINE_IDECODE static
#endif
#define STATIC_IDECODE static
# define STATIC_INLINE_MODEL(TYPE) static TYPE
#endif
#if FUNCTION_UNIT_INLINE
#if FUNCTION_UNIT_INLINE == 2
#define INLINE_FUNCTION_UNIT static INLINE
/* events is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_EVENTS_C_) && (EVENTS_INLINE & INCLUDE_MODULE)
# if (EVENTS_INLINE & INLINE_MODULE)
# define INLINE_EVENTS(TYPE) static INLINE TYPE UNUSED
# define EXTERN_EVENTS(TYPE) static TYPE UNUSED
#else
#define INLINE_FUNCTION_UNIT static
# define INLINE_EVENTS(TYPE) static TYPE UNUSED
# define EXTERN_EVENTS(TYPE) static TYPE UNUSED
#endif
#endif
#if OPTIONS_INLINE
#if OPTIONS_INLINE == 2
#define INLINE_OPTIONS static INLINE
#else
#define INLINE_OPTIONS static
# define INLINE_EVENTS(TYPE) TYPE
# define EXTERN_EVENTS(TYPE) TYPE
#endif
#if (EVENTS_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_EVENTS(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_EVENTS(TYPE) static TYPE
#endif
/* mon is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_MON_C_) && (MON_INLINE & INCLUDE_MODULE)
# if (MON_INLINE & INLINE_MODULE)
# define INLINE_MON(TYPE) static INLINE TYPE UNUSED
# define EXTERN_MON(TYPE) static TYPE UNUSED
#else
# define INLINE_MON(TYPE) static TYPE UNUSED
# define EXTERN_MON(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_MON(TYPE) TYPE
# define EXTERN_MON(TYPE) TYPE
#endif
#if (MON_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_MON(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_MON(TYPE) static TYPE
#endif
/* registers is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_REGISTERS_C_) && (REGISTERS_INLINE & INCLUDE_MODULE)
# if (REGISTERS_INLINE & INLINE_MODULE)
# define INLINE_REGISTERS(TYPE) static INLINE TYPE UNUSED
# define EXTERN_REGISTERS(TYPE) static TYPE UNUSED
#else
# define INLINE_REGISTERS(TYPE) static TYPE UNUSED
# define EXTERN_REGISTERS(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_REGISTERS(TYPE) TYPE
# define EXTERN_REGISTERS(TYPE) TYPE
#endif
#if (REGISTERS_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_REGISTERS(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_REGISTERS(TYPE) static TYPE
#endif
/* interrupts is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_INTERRUPTS_C_) && (INTERRUPTS_INLINE & INCLUDE_MODULE)
# if (INTERRUPTS_INLINE & INLINE_MODULE)
# define INLINE_INTERRUPTS(TYPE) static INLINE TYPE UNUSED
# define EXTERN_INTERRUPTS(TYPE) static TYPE UNUSED
#else
# define INLINE_INTERRUPTS(TYPE) static TYPE UNUSED
# define EXTERN_INTERRUPTS(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_INTERRUPTS(TYPE) TYPE
# define EXTERN_INTERRUPTS(TYPE) TYPE
#endif
#if (INTERRUPTS_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_INTERRUPTS(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_INTERRUPTS(TYPE) static TYPE
#endif
/* device is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_DEVICE_C_) && (DEVICE_INLINE & INCLUDE_MODULE)
# if (DEVICE_INLINE & INLINE_MODULE)
# define INLINE_DEVICE(TYPE) static INLINE TYPE UNUSED
# define EXTERN_DEVICE(TYPE) static TYPE UNUSED
#else
# define INLINE_DEVICE(TYPE) static TYPE UNUSED
# define EXTERN_DEVICE(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_DEVICE(TYPE) TYPE
# define EXTERN_DEVICE(TYPE) TYPE
#endif
#if (DEVICE_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_DEVICE(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_DEVICE(TYPE) static TYPE
#endif
/* spreg is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_SPREG_C_) && (SPREG_INLINE & INCLUDE_MODULE)
# if (SPREG_INLINE & INLINE_MODULE)
# define INLINE_SPREG(TYPE) static INLINE TYPE UNUSED
# define EXTERN_SPREG(TYPE) static TYPE UNUSED
#else
# define INLINE_SPREG(TYPE) static TYPE UNUSED
# define EXTERN_SPREG(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_SPREG(TYPE) TYPE
# define EXTERN_SPREG(TYPE) TYPE
#endif
#if (SPREG_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_SPREG(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_SPREG(TYPE) static TYPE
#endif
/* semantics is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_SEMANTICS_C_) && (SEMANTICS_INLINE & INCLUDE_MODULE)
# if (SEMANTICS_INLINE & INLINE_MODULE)
# define INLINE_SEMANTICS(TYPE) static INLINE TYPE UNUSED
# define EXTERN_SEMANTICS(TYPE) static TYPE UNUSED REGPARM
#else
# define INLINE_SEMANTICS(TYPE) static TYPE UNUSED REGPARM
# define EXTERN_SEMANTICS(TYPE) static TYPE UNUSED REGPARM
#endif
#else
# define INLINE_SEMANTICS(TYPE) TYPE REGPARM
# define EXTERN_SEMANTICS(TYPE) TYPE REGPARM
#endif
#if (SEMANTICS_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_SEMANTICS(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_SEMANTICS(TYPE) static TYPE REGPARM
#endif
/* idecode is actually not inlined */
#if defined(_INLINE_C_) && !defined(_IDECODE_C_) && (IDECODE_INLINE & INCLUDE_MODULE)
# if (IDECODE_INLINE & INLINE_MODULE)
# define INLINE_IDECODE(TYPE) static INLINE TYPE UNUSED
# define EXTERN_IDECODE(TYPE) static TYPE UNUSED REGPARM
#else
# define INLINE_IDECODE(TYPE) static TYPE UNUSED REGPARM
# define EXTERN_IDECODE(TYPE) static TYPE UNUSED REGPARM
#endif
#else
# define INLINE_IDECODE(TYPE) TYPE REGPARM
# define EXTERN_IDECODE(TYPE) TYPE REGPARM
#endif
#if (IDECODE_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_IDECODE(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_IDECODE(TYPE) static TYPE REGPARM
#endif
/* icache is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_ICACHE_C_) && (ICACHE_INLINE & INCLUDE_MODULE)
# if (ICACHE_INLINE & INLINE_MODULE)
# define INLINE_ICACHE(TYPE) static INLINE TYPE UNUSED
# define EXTERN_ICACHE(TYPE) static TYPE UNUSED REGPARM
#else
# define INLINE_ICACHE(TYPE) static TYPE UNUSED REGPARM
# define EXTERN_ICACHE(TYPE) static TYPE UNUSED REGPARM
#endif
#else
# define INLINE_ICACHE(TYPE) TYPE REGPARM
# define EXTERN_ICACHE(TYPE) TYPE REGPARM
#endif
#if (ICACHE_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_ICACHE(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_ICACHE(TYPE) static TYPE REGPARM
#endif
/* support is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_SUPPORT_C_) && (SUPPORT_INLINE & INCLUDE_MODULE)
# if (SUPPORT_INLINE & INLINE_MODULE)
# define INLINE_SUPPORT(TYPE) static INLINE TYPE UNUSED
# define EXTERN_SUPPORT(TYPE) static TYPE UNUSED REGPARM
#else
# define INLINE_SUPPORT(TYPE) static TYPE UNUSED REGPARM
# define EXTERN_SUPPORT(TYPE) static TYPE UNUSED REGPARM
#endif
#else
# define INLINE_SUPPORT(TYPE) TYPE REGPARM
# define EXTERN_SUPPORT(TYPE) TYPE REGPARM
#endif
#if (SUPPORT_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_SUPPORT(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_SUPPORT(TYPE) static TYPE REGPARM
#endif
/* options is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_OPTIONS_C_) && (OPTIONS_INLINE & INCLUDE_MODULE)
# if (OPTIONS_INLINE & INLINE_MODULE)
# define INLINE_OPTIONS(TYPE) static INLINE TYPE UNUSED
# define EXTERN_OPTIONS(TYPE) static TYPE UNUSED
#else
# define INLINE_OPTIONS(TYPE) static TYPE UNUSED
# define EXTERN_OPTIONS(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_OPTIONS(TYPE) TYPE
# define EXTERN_OPTIONS(TYPE) TYPE
#endif
#if (OPTIONS_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_OPTIONS(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_OPTIONS(TYPE) static TYPE
#endif
/* os_emul is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_OS_EMUL_C_) && (OS_EMUL_INLINE & INCLUDE_MODULE)
# if (OS_EMUL_INLINE & INLINE_MODULE)
# define INLINE_OS_EMUL(TYPE) static INLINE TYPE UNUSED
# define EXTERN_OS_EMUL(TYPE) static TYPE UNUSED
#else
# define INLINE_OS_EMUL(TYPE) static TYPE UNUSED
# define EXTERN_OS_EMUL(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_OS_EMUL(TYPE) TYPE
# define EXTERN_OS_EMUL(TYPE) TYPE
#endif
#if (OS_EMUL_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_OS_EMUL(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_OS_EMUL(TYPE) static TYPE
#endif
/* psim is actually not inlined */
#if defined(_INLINE_C_) && !defined(_PSIM_C_) && (PSIM_INLINE & INCLUDE_MODULE)
# if (PSIM_INLINE & INLINE_MODULE)
# define INLINE_PSIM(TYPE) static INLINE TYPE UNUSED
# define EXTERN_PSIM(TYPE) static TYPE UNUSED
#else
# define INLINE_PSIM(TYPE) static TYPE UNUSED
# define EXTERN_PSIM(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_PSIM(TYPE) TYPE
# define EXTERN_PSIM(TYPE) TYPE
#endif
#if (PSIM_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_PSIM(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_PSIM(TYPE) static TYPE
#endif
/* cap is inlined with inline.c */
#if defined(_INLINE_C_) && !defined(_CAP_C_) && (CAP_INLINE & INCLUDE_MODULE)
# if (CAP_INLINE & INLINE_MODULE)
# define INLINE_CAP(TYPE) static INLINE TYPE UNUSED
# define EXTERN_CAP(TYPE) static TYPE UNUSED
#else
# define INLINE_CAP(TYPE) static TYPE UNUSED
# define EXTERN_CAP(TYPE) static TYPE UNUSED
#endif
#else
# define INLINE_CAP(TYPE) TYPE
# define EXTERN_CAP(TYPE) TYPE
#endif
#if (CAP_INLINE & INLINE_LOCALS)
# define STATIC_INLINE_CAP(TYPE) static INLINE TYPE
#else
# define STATIC_INLINE_CAP(TYPE) static TYPE
#endif
#endif

114
sim/ppc/ld-cache.c Normal file
View File

@@ -0,0 +1,114 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, 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.
*/
#include "misc.h"
#include "lf.h"
#include "table.h"
#include "ld-cache.h"
#ifndef NULL
#define NULL 0
#endif
enum {
ca_type,
ca_old_name,
ca_new_name,
ca_type_def,
ca_expression,
nr_cache_rule_fields,
};
static const name_map cache_type_map[] = {
{ "cache", cache_value },
{ "compute", compute_value },
{ NULL, 0 },
};
cache_table *
load_cache_table(char *file_name,
int hi_bit_nr)
{
table *file = table_open(file_name, nr_cache_rule_fields, 0);
table_entry *entry;
cache_table *table = NULL;
cache_table **curr_rule = &table;
while ((entry = table_entry_read(file)) != NULL) {
cache_table *new_rule = ZALLOC(cache_table);
new_rule->type = name2i(entry->fields[ca_type], cache_type_map);
new_rule->old_name = entry->fields[ca_old_name];
new_rule->new_name = entry->fields[ca_new_name];
new_rule->type_def = (strlen(entry->fields[ca_type_def])
? entry->fields[ca_type_def]
: NULL);
new_rule->expression = (strlen(entry->fields[ca_expression]) > 0
? entry->fields[ca_expression]
: NULL);
new_rule->file_entry = entry;
*curr_rule = new_rule;
curr_rule = &new_rule->next;
}
return table;
}
#ifdef MAIN
static void
dump_cache_rule(cache_table* rule,
int indent)
{
dumpf(indent, "((cache_table*)0x%x\n", rule);
dumpf(indent, " (type %s)\n", i2name(rule->type, cache_type_map));
dumpf(indent, " (old_name \"%s\")\n", rule->old_name);
dumpf(indent, " (new_name \"%s\")\n", rule->new_name);
dumpf(indent, " (type-def \"%s\")\n", rule->type_def);
dumpf(indent, " (expression \"%s\")\n", rule->expression);
dumpf(indent, " (next 0x%x)\n", rule->next);
dumpf(indent, " )\n");
}
static void
dump_cache_rules(cache_table* rule,
int indent)
{
while (rule) {
dump_cache_rule(rule, indent);
rule = rule->next;
}
}
int
main(int argc, char **argv)
{
cache_table *rules;
if (argc != 3)
error("Usage: cache <cache-file> <hi-bit-nr>\n");
rules = load_cache_table(argv[1], a2i(argv[2]));
dump_cache_rules(rules, 0);
return 0;
}
#endif

75
sim/ppc/ld-cache.h Normal file
View File

@@ -0,0 +1,75 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, 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. */
typedef enum {
cache_value,
compute_value,
} cache_rule_type;
typedef struct _cache_table cache_table;
struct _cache_table {
cache_rule_type type;
char *old_name;
char *new_name;
char *type_def;
char *expression;
table_entry *file_entry;
cache_table *next;
};
extern cache_table *load_cache_table
(char *file_name,
int hi_bit_nr);

139
sim/ppc/ld-decode.h Normal file
View File

@@ -0,0 +1,139 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, 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 table:
<options>:<first>:<last>:<force-first>:<force-last>:<force-expand>:<special>...
Ignore the below:
The instruction decode table contains rules that dictate how igen
is going to firstly break down the opcode table and secondly
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.
<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 instruction 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). Or a branch table (val 3).
<special_mask>
<special_value>
<special_rule>
<special_constant>
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
3: boolean expansion of equality of special constant
*/
typedef enum {
normal_decode_rule,
expand_forced_rule,
boolean_rule,
nr_decode_rules
} decode_special_type;
typedef enum {
array_gen,
switch_gen,
padded_switch_gen,
goto_gen,
nr_decode_gen_types,
} decode_gen_type;
typedef struct _decode_table decode_table;
struct _decode_table {
decode_special_type type;
decode_gen_type gen;
int first;
int last;
int force_first;
int force_last;
int force_slash;
char *force_expansion;
unsigned special_mask;
unsigned special_value;
unsigned special_constant;
decode_table *next;
};
extern decode_table *load_decode_table
(char *file_name,
int hi_bit_nr);
extern void dump_decode_rule
(decode_table *rule,
int indent);

925
sim/ppc/ld-insn.c Normal file
View File

@@ -0,0 +1,925 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, 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.
*/
#include "misc.h"
#include "lf.h"
#include "table.h"
#include "filter.h"
#include "ld-decode.h"
#include "ld-cache.h"
#include "ld-insn.h"
#include "igen.h"
static void
update_depth(insn_table *entry,
lf *file,
void *data,
insn *instruction,
int depth)
{
int *max_depth = (int*)data;
if (*max_depth < depth)
*max_depth = depth;
}
int
insn_table_depth(insn_table *table)
{
int depth = 0;
insn_table_traverse_tree(table,
NULL,
&depth,
1,
NULL, /*start*/
update_depth,
NULL, /*end*/
NULL); /*padding*/
return depth;
}
static insn_fields *
parse_insn_format(table_entry *entry,
char *format)
{
char *chp;
insn_fields *fields = ZALLOC(insn_fields);
/* create a leading sentinal */
fields->first = ZALLOC(insn_field);
fields->first->first = -1;
fields->first->last = -1;
fields->first->width = 0;
/* and a trailing sentinal */
fields->last = ZALLOC(insn_field);
fields->last->first = insn_bit_size;
fields->last->last = insn_bit_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 = ZALLOC(insn_field);
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*)zalloc(strlen_val+1);
strncpy(new_field->val_string, start_val, strlen_val);
if (isdigit(*new_field->val_string)) {
new_field->val_int = a2i(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*)zalloc(strlen_pos+1);
strncpy(new_field->pos_string, start_pos, strlen_pos);
new_field->first = target_a2i(hi_bit_nr, 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_bit_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_bit_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_bit_size;
field = field->next) {
fields->value <<= field->width;
if (field->is_int)
fields->value |= field->val_int;
}
}
return fields;
}
static void
model_table_insert(insn_table *table,
table_entry *file_entry)
{
int len;
/* create a new model */
model *new_model = ZALLOC(model);
new_model->name = file_entry->fields[model_identifer];
new_model->printable_name = file_entry->fields[model_name];
new_model->insn_default = file_entry->fields[model_default];
while (*new_model->insn_default && isspace(*new_model->insn_default))
new_model->insn_default++;
len = strlen(new_model->insn_default);
if (max_model_fields_len < len)
max_model_fields_len = len;
/* append it to the end of the model list */
if (last_model)
last_model->next = new_model;
else
models = new_model;
last_model = new_model;
}
static void
model_table_insert_specific(insn_table *table,
table_entry *file_entry,
insn **start_ptr,
insn **end_ptr)
{
insn *ptr = ZALLOC(insn);
ptr->file_entry = file_entry;
if (*end_ptr)
(*end_ptr)->next = ptr;
else
(*start_ptr) = ptr;
(*end_ptr) = ptr;
}
static void
insn_table_insert_function(insn_table *table,
table_entry *file_entry)
{
/* create a new function */
insn *new_function = ZALLOC(insn);
new_function->file_entry = file_entry;
/* append it to the end of the function list */
if (table->last_function)
table->last_function->next = new_function;
else
table->functions = new_function;
table->last_function = new_function;
}
extern void
insn_table_insert_insn(insn_table *table,
table_entry *file_entry,
insn_fields *fields)
{
insn **ptr_to_cur_insn = &table->insns;
insn *cur_insn = *ptr_to_cur_insn;
table_model_entry *insn_model_ptr;
model *model_ptr;
/* create a new instruction */
insn *new_insn = ZALLOC(insn);
new_insn->file_entry = file_entry;
new_insn->fields = fields;
/* Check out any model information returned to make sure the model
is correct. */
for(insn_model_ptr = file_entry->model_first; insn_model_ptr; insn_model_ptr = insn_model_ptr->next) {
char *name = insn_model_ptr->fields[insn_model_name];
int len = strlen (insn_model_ptr->fields[insn_model_fields]);
while (len > 0 && isspace(*insn_model_ptr->fields[insn_model_fields])) {
len--;
insn_model_ptr->fields[insn_model_fields]++;
}
if (max_model_fields_len < len)
max_model_fields_len = len;
for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
if (strcmp(name, model_ptr->printable_name) == 0) {
/* Replace the name field with that of the global model, so that when we
want to print it out, we can just compare pointers. */
insn_model_ptr->fields[insn_model_name] = model_ptr->printable_name;
break;
}
}
if (!model_ptr)
error("%s:%d: machine model `%s' was not known about\n",
file_entry->file_name, file_entry->line_nr, name);
}
/* 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++;
}
insn_table *
load_insn_table(const char *file_name,
decode_table *decode_rules,
filter *filters)
{
table *file = table_open(file_name, nr_insn_table_fields, nr_insn_model_table_fields);
insn_table *table = ZALLOC(insn_table);
table_entry *file_entry;
table->opcode_rule = decode_rules;
while ((file_entry = table_entry_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 if (it_is("model", file_entry->fields[insn_flags])) {
model_table_insert(table, file_entry);
}
else if (it_is("model-macro", file_entry->fields[insn_flags])) {
model_table_insert_specific(table, file_entry, &model_macros, &last_model_macro);
}
else if (it_is("model-function", file_entry->fields[insn_flags])) {
model_table_insert_specific(table, file_entry, &model_functions, &last_model_function);
}
else if (it_is("model-internal", file_entry->fields[insn_flags])) {
model_table_insert_specific(table, file_entry, &model_internal, &last_model_internal);
}
else if (it_is("model-static", file_entry->fields[insn_flags])) {
model_table_insert_specific(table, file_entry, &model_static, &last_model_static);
}
else if (it_is("model-data", file_entry->fields[insn_flags])) {
model_table_insert_specific(table, file_entry, &model_data, &last_model_data);
}
else {
insn_fields *fields;
/* skip instructions that aren't relevant to the mode */
if (is_filtered_out(file_entry->fields[insn_flags], filters)) {
fprintf(stderr, "Dropping %s - %s\n",
file_entry->fields[insn_name],
file_entry->fields[insn_flags]);
}
else {
/* 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;
}
extern void
insn_table_traverse_tree(insn_table *table,
lf *file,
void *data,
int depth,
leaf_handler *start,
insn_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, file, 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, file, 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, file, data, depth+1,
start, leaf, end, padding);
}
else if (depth >= 0) {
if (leaf != NULL)
leaf(entry, file, data, entry->insns, depth);
}
entry = entry->sibling;
}
}
if (end != NULL && depth >= 0)
end(table, file, data, depth);
}
extern void
insn_table_traverse_function(insn_table *table,
lf *file,
void *data,
function_handler *leaf)
{
insn *function;
for (function = table->functions;
function != NULL;
function = function->next) {
leaf(table, file, data, function->file_entry);
}
}
extern void
insn_table_traverse_insn(insn_table *table,
lf *file,
void *data,
insn_handler *handler)
{
insn *instruction;
for (instruction = table->insns;
instruction != NULL;
instruction = instruction->next) {
handler(table, file, data, instruction, 0);
}
}
/****************************************************************/
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,
decode_table *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 opcode_field *
insn_table_find_opcode_field(insn *insns,
decode_table *rule,
int string_only)
{
opcode_field *curr_opcode = ZALLOC(opcode_field);
insn *entry;
ASSERT(rule);
curr_opcode->first = insn_bit_size;
curr_opcode->last = -1;
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);
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_bit_size-1) {
curr_opcode->last = insn_bit_size-1;
}
/* handle any special cases */
switch (rule->type) {
case normal_decode_rule:
/* let the above apply */
break;
case expand_forced_rule:
/* expand a limited nr of bits, ignoring the rest */
curr_opcode->first = rule->force_first;
curr_opcode->last = rule->force_last;
break;
case boolean_rule:
curr_opcode->is_boolean = 1;
curr_opcode->boolean_constant = rule->special_constant;
break;
default:
error("Something is going wrong\n");
}
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 = ZALLOC(insn_table);
new_entry->opcode_nr = new_opcode_nr;
new_entry->expanded_bits = new_bits;
new_entry->opcode_rule = table->opcode_rule->next;
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 = ZALLOC(insn_bits);
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);
}
extern void
insn_table_expand_insns(insn_table *table)
{
ASSERT(table->nr_insn >= 1);
/* determine a valid opcode */
while (table->opcode_rule) {
/* specials only for single instructions */
if ((table->nr_insn > 1
&& table->opcode_rule->special_mask == 0
&& table->opcode_rule->type == normal_decode_rule)
|| (table->nr_insn == 1
&& table->opcode_rule->special_mask != 0
&& ((table->insns->fields->value
& table->opcode_rule->special_mask)
== table->opcode_rule->special_value))
|| (generate_expanded_instructions
&& table->opcode_rule->special_mask == 0
&& table->opcode_rule->type == normal_decode_rule))
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 = table->opcode_rule->next;
}
/* 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);
}
}
}
#ifdef MAIN
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)
{
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_bit_size; i++) {
dumpf(indent, "(bits[%d] ", i, fields->bits[i]);
dump_insn_field(fields->bits[i], indent+1);
dumpf(indent, " )\n");
}
}
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);
}
}
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);
}
}
static void
dump_insn(insn *entry, int indent, int levels)
{
printf("(insn*)%p\n", entry);
if (levels && entry != NULL) {
dumpf(indent, "(file_entry ");
dump_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) {
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_decode_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");
}
}
int insn_bit_size = max_insn_bit_size;
int hi_bit_nr;
int generate_expanded_instructions;
int
main(int argc, char **argv)
{
filter *filters = NULL;
decode_table *decode_rules = NULL;
insn_table *instructions = NULL;
if (argc != 5)
error("Usage: insn <filter> <hi-bit-nr> <decode-table> <insn-table>\n");
filters = new_filter(argv[1], filters);
hi_bit_nr = a2i(argv[2]);
ASSERT(hi_bit_nr < insn_bit_size);
decode_rules = load_decode_table(argv[3], hi_bit_nr);
instructions = load_insn_table(argv[4], decode_rules, filters);
insn_table_expand_insns(instructions);
dump_insn_table(instructions, 0, -1);
return 0;
}
#endif

281
sim/ppc/ld-insn.h Normal file
View File

@@ -0,0 +1,281 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, 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.
*/
/*
# --
#
#
# Fields:
#
# 1 Instruction format as a `start-bit,content' pairs.
# the content is one of a digit, field name or `/' (aka.0)
#
# 2 Format specifier
#
# 3 Flags: 64 - 64bit only
# f - floating point enabled required
#
# 4 short name
#
# 5 Description
#
#
# For flags marked 'model', the fields are interpreted as follows:
#
# 1 Not used
#
# 2 Not used
#
# 3 "macro"
#
# 4 String name for model
#
# 5 Specific CPU model, must be an identifier
#
# 6 Comma separated list of functional units
*/
/* Global constants */
enum {
max_insn_bit_size = 32,
};
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[max_insn_bit_size];
insn_field *first;
insn_field *last;
unsigned value;
};
/****************************************************************/
typedef struct _opcode_field opcode_field;
struct _opcode_field {
int first;
int last;
int is_boolean;
unsigned boolean_constant;
opcode_field *parent;
};
/****************************************************************/
typedef struct _insn_bits insn_bits;
struct _insn_bits {
int is_expanded;
int value;
insn_field *field;
opcode_field *opcode;
insn_bits *last;
};
/****************************************************************/
typedef enum {
insn_format,
insn_form,
insn_flags,
insn_mnemonic,
insn_name,
insn_comment,
nr_insn_table_fields
} insn_table_fields;
typedef enum {
function_type = insn_format,
function_name = insn_name,
function_param = insn_comment
} function_table_fields;
typedef enum {
model_name = insn_mnemonic,
model_identifer = insn_name,
model_default = insn_comment,
} model_table_fields;
typedef struct _insn insn;
struct _insn {
table_entry *file_entry;
insn_fields *fields;
insn *next;
};
typedef struct _insn_undef insn_undef;
struct _insn_undef {
insn_undef *next;
char *name;
};
typedef struct _model model;
struct _model {
model *next;
char *name;
char *printable_name;
char *insn_default;
table_model_entry *func_unit_start;
table_model_entry *func_unit_end;
};
typedef struct _insn_table insn_table;
struct _insn_table {
int opcode_nr;
insn_bits *expanded_bits;
int nr_insn;
insn *insns;
insn *functions;
insn *last_function;
decode_table *opcode_rule;
opcode_field *opcode;
int nr_entries;
insn_table *entries;
insn_table *sibling;
insn_table *parent;
};
typedef enum {
insn_model_name,
insn_model_fields,
nr_insn_model_table_fields
} insn_model_table_fields;
extern insn_table *load_insn_table
(const char *file_name,
decode_table *decode_rules,
filter *filters);
model *models;
model *last_model;
insn *model_macros;
insn *last_model_macro;
insn *model_functions;
insn *last_model_function;
insn *model_internal;
insn *last_model_internal;
insn *model_static;
insn *last_model_static;
insn *model_data;
insn *last_model_data;
int max_model_fields_len;
extern void insn_table_insert_insn
(insn_table *table,
table_entry *file_entry,
insn_fields *fields);
/****************************************************************/
/****************************************************************/
typedef void leaf_handler
(insn_table *entry,
lf *file,
void *data,
int depth);
typedef void insn_handler
(insn_table *table,
lf *file,
void *data,
insn *instruction,
int depth);
typedef void padding_handler
(insn_table *table,
lf *file,
void *data,
int depth,
int opcode_nr);
extern void insn_table_traverse_tree
(insn_table *table,
lf *file,
void *data,
int depth,
leaf_handler *start,
insn_handler *handler,
leaf_handler *end,
padding_handler *padding);
extern void insn_table_traverse_insn
(insn_table *table,
lf *file,
void *data,
insn_handler *handler);
/****************************************************************/
typedef void function_handler
(insn_table *table,
lf *file,
void *data,
table_entry *function);
extern void
insn_table_traverse_function
(insn_table *table,
lf *file,
void *data,
function_handler *leaf);
/****************************************************************/
extern void insn_table_expand_insns
(insn_table *table);
extern int insn_table_depth
(insn_table *table);

View File

@@ -17,84 +17,47 @@
# 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:RA:RA_BITMASK:unsigned32:(1 << RA)
1:RT:RT::
1:RT:rT:signed_word *:(cpu_registers(processor)->gpr + RT)
1:RT:RT_BITMASK:unsigned32:(1 << RT)
2:RS:RS::
1:RS:rS:signed_word *:(cpu_registers(processor)->gpr + RS)
1:RS:RS_BITMASK:unsigned32:(1 << RS)
2:RB:RB::
1:RB:rB:signed_word *:(cpu_registers(processor)->gpr + RB)
1:RB:RB_BITMASK:unsigned32:(1 << RB)
2:FRA:FRA::
1:FRA:frA:unsigned64 *:(cpu_registers(processor)->fpr + FRA)
1:FRA:FRA_BITMASK:unsigned32:(1 << FRA)
2:FRB:FRB::
1:FRB:frB:unsigned64 *:(cpu_registers(processor)->fpr + FRB)
1:FRB:FRB_BITMASK:unsigned32:(1 << FRB)
2:FRC:FRC::
1:FRC:frC:unsigned64 *:(cpu_registers(processor)->fpr + FRC)
1:FRC:FRC_BITMASK:unsigned32:(1 << FRC)
2:FRS:FRS::
1:FRS:frS:unsigned64 *:(cpu_registers(processor)->fpr + FRS)
1:FRS:FRS_BITMASK:unsigned32:(1 << FRS)
2:FRT:FRT::
1:FRT:frT:unsigned64 *:(cpu_registers(processor)->fpr + FRT)
1:FRT:FRT_BITMASK:unsigned32:(1 << FRT)
1:SI:EXTS_SI:unsigned_word:((signed_word)(signed16)instruction)
2:BI:BI::
1:BI:BIT32_BI::BIT32(BI)
1:BF:BF::
1:BF:BF_BITMASK:unsigned32:(1 << BF)
2:BA:BA::
1:BA:BIT32_BA::BIT32(BA)
1:BA:BA_BITMASK:unsigned32:(1 << BA)
2:BB:BB::
1:BB:BIT32_BB::BIT32(BB)
1:BB:BB_BITMASK:unsigned32:(1 << BB)
1:BT:BT::
1:BT:BT_BITMASK:unsigned32:(1 << BT)
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)
cache:RA:RA::
cache:RA:rA:signed_word *:(cpu_registers(processor)->gpr + RA)
cache:RA:RA_BITMASK:unsigned32:(1 << RA)
cache:RT:RT::
cache:RT:rT:signed_word *:(cpu_registers(processor)->gpr + RT)
cache:RT:RT_BITMASK:unsigned32:(1 << RT)
compute:RS:RS::
cache:RS:rS:signed_word *:(cpu_registers(processor)->gpr + RS)
cache:RS:RS_BITMASK:unsigned32:(1 << RS)
compute:RB:RB::
cache:RB:rB:signed_word *:(cpu_registers(processor)->gpr + RB)
cache:RB:RB_BITMASK:unsigned32:(1 << RB)
compute:FRA:FRA::
cache:FRA:frA:unsigned64 *:(cpu_registers(processor)->fpr + FRA)
cache:FRA:FRA_BITMASK:unsigned32:(1 << FRA)
compute:FRB:FRB::
cache:FRB:frB:unsigned64 *:(cpu_registers(processor)->fpr + FRB)
cache:FRB:FRB_BITMASK:unsigned32:(1 << FRB)
compute:FRC:FRC::
cache:FRC:frC:unsigned64 *:(cpu_registers(processor)->fpr + FRC)
cache:FRC:FRC_BITMASK:unsigned32:(1 << FRC)
compute:FRS:FRS::
cache:FRS:frS:unsigned64 *:(cpu_registers(processor)->fpr + FRS)
cache:FRS:FRS_BITMASK:unsigned32:(1 << FRS)
compute:FRT:FRT::
cache:FRT:frT:unsigned64 *:(cpu_registers(processor)->fpr + FRT)
cache:FRT:FRT_BITMASK:unsigned32:(1 << FRT)
cache:SI:EXTS_SI:unsigned_word:((signed_word)(signed16)instruction)
compute:BI:BI::
cache:BI:BIT32_BI::BIT32(BI)
cache:BF:BF::
cache:BF:BF_BITMASK:unsigned32:(1 << BF)
compute:BA:BA::
cache:BA:BIT32_BA::BIT32(BA)
cache:BA:BA_BITMASK:unsigned32:(1 << BA)
compute:BB:BB::
cache:BB:BIT32_BB::BIT32(BB)
cache:BB:BB_BITMASK:unsigned32:(1 << BB)
cache:BT:BT::
cache:BT:BT_BITMASK:unsigned32:(1 << BT)
cache:BD:EXTS_BD_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~3)
cache:LI:EXTS_LI_0b00:unsigned_word:((((signed_word)(signed32)(instruction << 6)) >> 6) & ~0x3)
cache:D:EXTS_D:unsigned_word:((signed_word)(signed16)(instruction))
cache:DS:EXTS_DS_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~0x3)

View File

@@ -1,7 +1,7 @@
#
# This file is part of the program psim.
#
# Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
# Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
#
# --
#
@@ -33,38 +33,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# --
#
#
# Fields:
#
# 1 Instruction format as a `start-bit,content' pairs.
# the content is one of a digit, field name or `/' (aka.0)
#
# 2 Format specifier
#
# 3 Flags: 64 - 64bit only
# f - floating point enabled required
#
# 4 short name
#
# 5 Description
#
#
# For flags marked 'model', the fields are interpreted as follows:
#
# 1 Not used
#
# 2 Not used
#
# 3 "macro"
#
# 4 String name for model
#
# 5 Specific CPU model, must be an identifier
#
# 6 Comma separated list of functional units
# PowerPC models
::model:604:ppc604: PPC_UNIT_BAD, PPC_UNIT_BAD, 1, 1, 0
@@ -78,68 +46,68 @@
do { \
if (CURRENT_MODEL_ISSUE > 0) { \
if (RC) \
ppc_insn_int(my_index, cpu_model(processor), OUT_MASK, IN_MASK); \
ppc_insn_int(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK); \
else \
ppc_insn_int_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \
ppc_insn_int_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \
} \
} while (0)
#define PPC_INSN_INT_CR(OUT_MASK, IN_MASK, CR_MASK) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_int_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \
ppc_insn_int_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \
} while (0)
#define PPC_INSN_CR(OUT_MASK, IN_MASK) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK); \
ppc_insn_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK); \
} while (0)
#define PPC_INSN_FLOAT(OUT_MASK, IN_MASK, RC) \
do { \
if (CURRENT_MODEL_ISSUE > 0) { \
if (RC) \
ppc_insn_float(my_index, cpu_model(processor), OUT_MASK, IN_MASK); \
ppc_insn_float(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK); \
else \
ppc_insn_float_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \
ppc_insn_float_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \
} \
} while (0)
#define PPC_INSN_FLOAT_CR(OUT_MASK, IN_MASK, CR_MASK) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_float_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \
ppc_insn_float_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \
} while (0)
#define PPC_INSN_INT_FLOAT(OUT_INT_MASK, OUT_FP_MASK, IN_INT_MASK, IN_FP_MASK) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_int_float(my_index, cpu_model(processor), OUT_INT_MASK, OUT_FP_MASK, IN_INT_MASK, IN_FP_MASK); \
ppc_insn_int_float(MY_INDEX, cpu_model(processor), OUT_INT_MASK, OUT_FP_MASK, IN_INT_MASK, IN_FP_MASK); \
} while (0)
#define PPC_INSN_FROM_SPR(INT_MASK, SPR) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_from_spr(my_index, cpu_model(processor), INT_MASK, SPR); \
ppc_insn_from_spr(MY_INDEX, cpu_model(processor), INT_MASK, SPR); \
} while (0)
#define PPC_INSN_TO_SPR(INT_MASK, SPR) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_to_spr(my_index, cpu_model(processor), INT_MASK, SPR); \
ppc_insn_to_spr(MY_INDEX, cpu_model(processor), INT_MASK, SPR); \
} while (0)
#define PPC_INSN_MFCR(INT_MASK) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_mfcr(my_index, cpu_model(processor), INT_MASK); \
ppc_insn_mfcr(MY_INDEX, cpu_model(processor), INT_MASK); \
} while (0)
#define PPC_INSN_MTCR(INT_MASK, FXM) \
do { \
if (CURRENT_MODEL_ISSUE > 0) \
ppc_insn_mtcr(my_index, cpu_model(processor), INT_MASK, FXM); \
ppc_insn_mtcr(MY_INDEX, cpu_model(processor), INT_MASK, FXM); \
} while (0)
::model-data:::
@@ -187,7 +155,7 @@
signed16 done; /* # of cycles until insn is done */
signed16 nr_writebacks; /* # of registers this unit writes back */
};
/* Structure to hold the current state information for the simulated CPU model */
struct _model_data {
cpu *processor; /* point back to processor */
@@ -783,6 +751,15 @@ void::model-function::model_halt:model_data *model_ptr
while (model_ptr->busy_head.next)
model_new_cycle(model_ptr);
unsigned_word::model-function::model_get_number_of_stalls:model_data *model_ptr
return (model_ptr->nr_stalls_data
+ model_ptr->nr_stalls_unit
+ model_ptr->nr_stalls_serialize
+ model_ptr->nr_stalls_writeback);
unsigned_word::model-function::model_get_number_of_cycles:model_data *model_ptr
return (model_ptr->nr_cycles);
model_print *::model-function::model_mon_info:model_data *model_ptr
model_print *head;
model_print *tail;
@@ -828,7 +805,7 @@ model_print *::model-function::model_mon_info:model_data *model_ptr
tail = tail->next;
tail->count = model_ptr->nr_stalls_writeback;
tail->name = "";
tail->suffix_plural = "times a writeback slot was unavilable";
tail->suffix_plural = "times a write-back slot was unavailable";
tail->suffix_singular = "time a writeback was unavilable";
}
@@ -942,7 +919,6 @@ void::model-function::model_branch_predict:model_data *model_ptr, int success
::internal::illegal
program_interrupt(processor, cia,
illegal_instruction_program_interrupt);
return 0;
# The following (floating point unavailable) instruction is `known' by gen
@@ -950,7 +926,6 @@ void::model-function::model_branch_predict:model_data *model_ptr, int success
# executed but floating point is make unavailable by the MSR
::internal::floating_point_unavailable
floating_point_unavailable_interrupt(processor, cia);
return 0;
#
@@ -1134,59 +1109,64 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64
int rbit = 0;
int xbit = 0;
int sign = EXTRACTED64(frb, 0, 0);
if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 63) == 0)
goto Infinity_Operand;
if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 0)
goto SNaN_Operand;
if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 1)
goto QNaN_Operand;
if (EXTRACTED64(frb, 1, 11) > 1086) goto Large_Operand;
if (EXTRACTED64(frb, 1, 11) > 0) exp = EXTRACTED64(frb, 1, 11) - 1023;
if (EXTRACTED64(frb, 1, 11) == 0) exp = -1022;
if (EXTRACTED64(frb, 1, 11) > 0) { /* normal */
frac = BIT64(1) | INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53);
frac64 = 0;
}
if (EXTRACTED64(frb, 1, 11) == 0) { /* denorm */
frac = INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53);
frac64 = 0;
}
gbit = 0, rbit = 0, xbit = 0;
for (i = 1; i <= 63 - exp; i++) {
xbit = rbit | xbit;
rbit = gbit;
gbit = frac64;
frac64 = EXTRACTED64(frac, 63, 63);
frac = INSERTED64(EXTRACTED64(frac, 0, 62), 1, 63);
}
Round_Integer(processor, sign, &frac, &frac64, gbit, rbit, xbit, round_mode);
if (sign == 1) { /* frac[0:64] = ~frac[0:64] + 1 */
frac = ~frac;
frac64 ^= 1;
frac += (frac64 ? 1 : 0);
frac64 = (frac64 + 1) & 0x1;
}
if (tgt_precision == 32 /* can ignore frac64 in compare */
&& (signed64)frac > (signed64)MASK64(33+1, 63)/*2^31-1 >>1*/)
goto Large_Operand;
if (tgt_precision == 64 /* can ignore frac64 in compare */
&& (signed64)frac > (signed64)MASK64(1+1, 63)/*2^63-1 >>1*/)
goto Large_Operand;
if (tgt_precision == 32 /* can ignore frac64 in compare */
&& (signed64)frac < (signed64)MASK64(0, 32+1)/*-2^31 >>1*/)
goto Large_Operand;
if (tgt_precision == 64 /* can ignore frac64 in compare */
&& (signed64)frac < (signed64)MASK64(0, 0+1)/*-2^63 >>1*/)
goto Large_Operand;
FPSCR_SET_XX(FPSCR & fpscr_fi);
if (tgt_precision == 32)
*frt = MASKED64(*frt, 0, 31) | (EXTRACTED64(frac, 33, 63) << 1) | frac64;
if (tgt_precision == 64)
*frt = (EXTRACTED64(frac, 1, 63) << 1) | frac64;
/*FPSCR[fprf] = undefined */
goto Done;
/**/
Infinity_Operand:
enum { start, finish, Infinity_Operand, SNaN_Operand, QNaN_Operand, Large_Operand, Done } label = start;
while (label != finish) switch (label) {
case finish:
error("Unhandled switch\n");
case start:
if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 63) == 0)
{ label = Infinity_Operand; break; }
if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 0)
{ label = SNaN_Operand; break; }
if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 1)
{ label = QNaN_Operand; break; }
if (EXTRACTED64(frb, 1, 11) > 1086) { label = Large_Operand; break; }
if (EXTRACTED64(frb, 1, 11) > 0) exp = EXTRACTED64(frb, 1, 11) - 1023;
if (EXTRACTED64(frb, 1, 11) == 0) exp = -1022;
if (EXTRACTED64(frb, 1, 11) > 0) { /* normal */
frac = BIT64(1) | INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53);
frac64 = 0;
}
if (EXTRACTED64(frb, 1, 11) == 0) { /* denorm */
frac = INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53);
frac64 = 0;
}
gbit = 0, rbit = 0, xbit = 0;
for (i = 1; i <= 63 - exp; i++) {
xbit = rbit | xbit;
rbit = gbit;
gbit = frac64;
frac64 = EXTRACTED64(frac, 63, 63);
frac = INSERTED64(EXTRACTED64(frac, 0, 62), 1, 63);
}
Round_Integer(processor, sign, &frac, &frac64, gbit, rbit, xbit, round_mode);
if (sign == 1) { /* frac[0:64] = ~frac[0:64] + 1 */
frac = ~frac;
frac64 ^= 1;
frac += (frac64 ? 1 : 0);
frac64 = (frac64 + 1) & 0x1;
}
if (tgt_precision == 32 /* can ignore frac64 in compare */
&& (signed64)frac > (signed64)MASK64(33+1, 63)/*2^31-1 >>1*/)
{ label = Large_Operand; break; }
if (tgt_precision == 64 /* can ignore frac64 in compare */
&& (signed64)frac > (signed64)MASK64(1+1, 63)/*2^63-1 >>1*/)
{ label = Large_Operand; break; }
if (tgt_precision == 32 /* can ignore frac64 in compare */
&& (signed64)frac < (signed64)MASK64(0, 32+1)/*-2^31 >>1*/)
{ label = Large_Operand; break; }
if (tgt_precision == 64 /* can ignore frac64 in compare */
&& (signed64)frac < (signed64)MASK64(0, 0+1)/*-2^63 >>1*/)
{ label = Large_Operand; break; }
FPSCR_SET_XX(FPSCR & fpscr_fi);
if (tgt_precision == 32)
*frt = MASKED64(*frt, 0, 31) | (EXTRACTED64(frac, 33, 63) << 1) | frac64;
if (tgt_precision == 64)
*frt = (EXTRACTED64(frac, 1, 63) << 1) | frac64;
/*FPSCR[fprf] = undefined */
{ label = Done; break; }
/**/
case Infinity_Operand:
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
FPSCR_OR_VX(fpscr_vxcvi);
@@ -1201,9 +1181,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64
}
/* FPSCR[FPRF] = undefined */
}
goto Done;
{ label = Done; break; }
/**/
SNaN_Operand:
case SNaN_Operand:
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
FPSCR_OR_VX(fpscr_vxsnan | fpscr_vxcvi);
@@ -1212,9 +1192,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64
if (tgt_precision == 64) *frt = BIT64(0); /*0x8000_0000_0000_0000*/
/* FPSCR[fprf] = undefined */
}
goto Done;
{ label = Done; break; }
/**/
QNaN_Operand:
case QNaN_Operand:
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
FPSCR_OR_VX(fpscr_vxcvi);
@@ -1223,9 +1203,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64
if (tgt_precision == 64) *frt = BIT64(0);/*0x8000_0000_0000_0000*/
/* FPSCR[fprf] = undefined */
}
goto Done;
{ label = Done; break; }
/**/
Large_Operand:
case Large_Operand:
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
FPSCR_OR_VX(fpscr_vxcvi);
@@ -1241,7 +1221,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64
/* FPSCR[fprf] = undefined */
}
/**/
Done:
case Done:
{ label = finish; break; }
}
# extract out raw fields of a FP number
@@ -1419,7 +1401,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
#
# I.2.4.1 Branch Instructions
#
0.18,6.LI,30.AA,31.LK:I:t::Branch
0.18,6.LI,30.AA,31.LK:I:::Branch
*601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
@@ -1430,7 +1412,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
if (CURRENT_MODEL_ISSUE > 0)
model_branches(cpu_model(processor), 1, -1);
0.16,6.BO,11.BI,16.BD,30.AA,31.LK:B:t::Branch Conditional
0.16,6.BO,11.BI,16.BD,30.AA,31.LK:B:::Branch Conditional
*601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
@@ -1464,7 +1446,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
model_branch_predict(cpu_model(processor), reverse ? !succeed : succeed);
}
0.19,6.BO,11.BI,16./,21.16,31.LK:XL:t::Branch Conditional to Link Register
0.19,6.BO,11.BI,16./,21.16,31.LK:XL:::Branch Conditional to Link Register
*601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
@@ -1490,7 +1472,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
model_branch_predict(cpu_model(processor), BO{4} ? !succeed : succeed);
}
0.19,6.BO,11.BI,16./,21.528,31.LK:XL:t::Branch Conditional to Count Register
0.19,6.BO,11.BI,16./,21.528,31.LK:XL:::Branch Conditional to Count Register
*601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
*603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0
@@ -1515,13 +1497,13 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
#
# I.2.4.2 System Call Instruction
#
0.17,6./,11./,16./,30.1,31./:SC:t::System Call
0.17,6./,11./,16./,30.1,31./:SC:::System Call
*601: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0
*603: PPC_UNIT_SRU, PPC_UNIT_SRU, 3, 3, 0
*603e:PPC_UNIT_SRU, PPC_UNIT_SRU, 3, 3, 0
*604: PPC_UNIT_SCIU1, PPC_UNIT_SCIU2, 1, 1, 0
if (CURRENT_MODEL_ISSUE > 0)
model_serialize(my_index, cpu_model(processor));
model_serialize(MY_INDEX, cpu_model(processor));
system_call_interrupt(processor, cia);
#
@@ -2143,22 +2125,22 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
# I.3.3.5 Fixed-Point Load and Store Multiple Instrctions
#
0.46,6.RT,11.RA,16.D:D:be::Load Multiple Word
0.46,6.RT,11.RA,16.D:D:::Load Multiple Word
0.47,6.RS,11.RA,16.D:D:be::Store Multiple Word
0.47,6.RS,11.RA,16.D:D:::Store Multiple Word
#
# I.3.3.6 Fixed-Point Move Assist Instructions
#
0.31,6.RT,11.RA,16.NB,21.597,31./:X:be::Load String Word Immediate
0.31,6.RT,11.RA,16.NB,21.597,31./:X:::Load String Word Immediate
0.31,6.RT,11.RA,16.RB,21.533,31./:X:be::Load String Word Indexed
0.31,6.RT,11.RA,16.RB,21.533,31./:X:::Load String Word Indexed
0.31,6.RS,11.RA,16.NB,21.725,31./:X:be::Store String Word Immedate
0.31,6.RS,11.RA,16.NB,21.725,31./:X:::Store String Word Immedate
0.31,6.RS,11.RA,16.RB,21.661,31./:X:be::Store String Word Indexed
0.31,6.RS,11.RA,16.RB,21.661,31./:X:::Store String Word Indexed
#
@@ -2259,7 +2241,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
# I.3.3.9 Fixed-Point Arithmetic Instructions
#
0.14,6.RT,11.RA,16.SI:D:T::Add Immediate
0.14,6.RT,11.RA,16.SI:D:::Add Immediate
*601: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0
*603: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0
*603e:PPC_UNIT_IU, PPC_UNIT_SRU, 1, 1, 0
@@ -4028,28 +4010,32 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
int sign;
int exp;
unsigned64 frac_grx;
/* split off cases for what to do */
if (EXTRACTED64(*frB, 1, 11) < 897
&& EXTRACTED64(*frB, 1, 63) > 0) {
if ((FPSCR & fpscr_ue) == 0) goto Disabled_Exponent_Underflow;
if ((FPSCR & fpscr_ue) != 0) goto Enabled_Exponent_Underflow;
}
if (EXTRACTED64(*frB, 1, 11) > 1150
&& EXTRACTED64(*frB, 1, 11) < 2047) {
if ((FPSCR & fpscr_oe) == 0) goto Disabled_Exponent_Overflow;
if ((FPSCR & fpscr_oe) != 0) goto Enabled_Exponent_Overflow;
}
if (EXTRACTED64(*frB, 1, 11) > 896
&& EXTRACTED64(*frB, 1, 11) < 1151) goto Normal_Operand;
if (EXTRACTED64(*frB, 1, 63) == 0) goto Zero_Operand;
if (EXTRACTED64(*frB, 1, 11) == 2047) {
if (EXTRACTED64(*frB, 12, 63) == 0) goto Infinity_Operand;
if (EXTRACTED64(*frB, 12, 12) == 1) goto QNaN_Operand;
if (EXTRACTED64(*frB, 12, 12) == 0
&& EXTRACTED64(*frB, 13, 63) > 0) goto SNaN_Operand;
}
/* handle them */
Disabled_Exponent_Underflow:
enum { start, finish, Disabled_Exponent_Underflow, Enabled_Exponent_Underflow, Disabled_Exponent_Overflow, Enabled_Exponent_Overflow, Normal_Operand, Zero_Operand, Infinity_Operand, QNaN_Operand, SNaN_Operand, Enabled_Overflow, Done } label = start;
while (label != finish) switch (label) {
case finish:
error("Unhandled switch\n");
case start:
/* split off cases for what to do */
if (EXTRACTED64(*frB, 1, 11) < 897
&& EXTRACTED64(*frB, 1, 63) > 0) {
if ((FPSCR & fpscr_ue) == 0) { label = Disabled_Exponent_Underflow; break; }
if ((FPSCR & fpscr_ue) != 0) { label = Enabled_Exponent_Underflow; break; }
}
if (EXTRACTED64(*frB, 1, 11) > 1150
&& EXTRACTED64(*frB, 1, 11) < 2047) {
if ((FPSCR & fpscr_oe) == 0) { label = Disabled_Exponent_Overflow; break; }
if ((FPSCR & fpscr_oe) != 0) { label = Enabled_Exponent_Overflow; break; }
}
if (EXTRACTED64(*frB, 1, 11) > 896
&& EXTRACTED64(*frB, 1, 11) < 1151) { label = Normal_Operand; break; }
if (EXTRACTED64(*frB, 1, 63) == 0) { label = Zero_Operand; break; }
if (EXTRACTED64(*frB, 1, 11) == 2047) {
if (EXTRACTED64(*frB, 12, 63) == 0) { label = Infinity_Operand; break; }
if (EXTRACTED64(*frB, 12, 12) == 1) { label = QNaN_Operand; break; }
if (EXTRACTED64(*frB, 12, 12) == 0
&& EXTRACTED64(*frB, 13, 63) > 0) { label = SNaN_Operand; break; }
}
case Disabled_Exponent_Underflow:
sign = EXTRACTED64(*frB, 0, 0);
if (EXTRACTED64(*frB, 1, 11) == 0) {
exp = -1022;
@@ -4091,8 +4077,8 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
| INSERTED64(exp + 1023, 1, 11)
| INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
}
goto Done;
Enabled_Exponent_Underflow:
{ label = Done; break; }
case Enabled_Exponent_Underflow:
FPSCR_SET_UX(1);
sign = EXTRACTED64(*frB, 0, 0);
if (EXTRACTED64(*frB, 1, 11) == 0) {
@@ -4117,8 +4103,8 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
| INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
goto Done;
Disabled_Exponent_Overflow:
{ label = Done; break; }
case Disabled_Exponent_Overflow:
FPSCR_SET_OX(1);
if ((FPSCR & fpscr_rn) == fpscr_rn_round_to_nearest) {
if (EXTRACTED64(*frB, 0, 0) == 0) {
@@ -4163,43 +4149,43 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
/* FPSCR[FR] <- undefined */
FPSCR_SET_FI(1);
FPSCR_SET_XX(1);
goto Done;
Enabled_Exponent_Overflow:
{ label = Done; break; }
case Enabled_Exponent_Overflow:
sign = EXTRACTED64(*frB, 0, 0);
exp = EXTRACTED64(*frB, 1, 11) - 1023;
frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
Round_Single(processor, sign, &exp, &frac_grx);
FPSCR_SET_XX(FPSCR & fpscr_fi);
Enabled_Overflow:
FPSCR_SET_OX(1);
exp = exp - 192;
*frT = (INSERTED64(sign, 0, 0)
| INSERTED64(exp + 1023, 1, 11)
| INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
goto Done;
Zero_Operand:
case Enabled_Overflow:
FPSCR_SET_OX(1);
exp = exp - 192;
*frT = (INSERTED64(sign, 0, 0)
| INSERTED64(exp + 1023, 1, 11)
| INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
{ label = Done; break; }
case Zero_Operand:
*frT = *frB;
if (EXTRACTED64(*frB, 0, 0) == 0) FPSCR_SET_FPRF(fpscr_rf_pos_zero);
if (EXTRACTED64(*frB, 0, 0) == 1) FPSCR_SET_FPRF(fpscr_rf_neg_zero);
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
goto Done;
Infinity_Operand:
{ label = Done; break; }
case Infinity_Operand:
*frT = *frB;
if (EXTRACTED64(*frB, 0, 0) == 0) FPSCR_SET_FPRF(fpscr_rf_pos_infinity);
if (EXTRACTED64(*frB, 0, 0) == 1) FPSCR_SET_FPRF(fpscr_rf_neg_infinity);
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
goto Done;
QNaN_Operand:
{ label = Done; break; }
case QNaN_Operand:
*frT = INSERTED64(EXTRACTED64(*frB, 0, 34), 0, 34);
FPSCR_SET_FPRF(fpscr_rf_quiet_nan);
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
goto Done;
SNaN_Operand:
{ label = Done; break; }
case SNaN_Operand:
FPSCR_OR_VX(fpscr_vxsnan);
if ((FPSCR & fpscr_ve) == 0) {
*frT = (MASKED64(*frB, 0, 11)
@@ -4209,23 +4195,25 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
}
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
goto Done;
Normal_Operand:
{ label = Done; break; }
case Normal_Operand:
sign = EXTRACTED64(*frB, 0, 0);
exp = EXTRACTED64(*frB, 1, 11) - 1023;
frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
Round_Single(processor, sign, &exp, &frac_grx);
FPSCR_SET_XX(FPSCR & fpscr_fi);
if (exp > 127 && (FPSCR & fpscr_oe) == 0) goto Disabled_Exponent_Overflow;
if (exp > 127 && (FPSCR & fpscr_oe) != 0) goto Enabled_Overflow;
if (exp > 127 && (FPSCR & fpscr_oe) == 0) { label = Disabled_Exponent_Overflow; break; }
if (exp > 127 && (FPSCR & fpscr_oe) != 0) { label = Enabled_Overflow; break; }
*frT = (INSERTED64(sign, 0, 0)
| INSERTED64(exp + 1023, 1, 11)
| INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
goto Done;
Done:
PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc);
{ label = Done; break; }
case Done:
PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc);
{ label = finish; break; }
}
0.63,6.FRT,11./,16.FRB,21.814,31.Rc:X:64,f::Floating Convert To Integer Doubleword
@@ -4249,30 +4237,37 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
int sign = EXTRACTED64(*frB, 0, 0);
int exp = 63;
unsigned64 frac = *frB;
if (frac == 0) goto Zero_Operand;
if (sign == 1) frac = ~frac + 1;
while (EXTRACTED64(frac, 0, 0) == 0) {
/*??? do the loop 0 times if (FRB) = max negative integer */
frac = INSERTED64(EXTRACTED64(frac, 1, 63), 0, 62);
exp = exp - 1;
}
Round_Float(processor, sign, &exp, &frac, FPSCR & fpscr_rn);
if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
*frT = (INSERTED64(sign, 0, 0)
| INSERTED64(exp + 1023, 1, 11)
| INSERTED64(EXTRACTED64(frac, 1, 52), 12, 63));
goto Done;
enum { start, finish, Zero_Operand, Done } label = start;
while (label != finish) switch (label) {
case finish:
error("Unhandled switch\n");
case start:
if (frac == 0) { label = Zero_Operand; break; }
if (sign == 1) frac = ~frac + 1;
while (EXTRACTED64(frac, 0, 0) == 0) {
/*??? do the loop 0 times if (FRB) = max negative integer */
frac = INSERTED64(EXTRACTED64(frac, 1, 63), 0, 62);
exp = exp - 1;
}
Round_Float(processor, sign, &exp, &frac, FPSCR & fpscr_rn);
if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
*frT = (INSERTED64(sign, 0, 0)
| INSERTED64(exp + 1023, 1, 11)
| INSERTED64(EXTRACTED64(frac, 1, 52), 12, 63));
{ label = Done; break; }
/**/
Zero_Operand:
case Zero_Operand:
FPSCR_SET_FR(0);
FPSCR_SET_FI(0);
FPSCR_SET_FPRF(fpscr_rf_pos_zero);
*frT = 0;
goto Done;
{ label = Done; break; }
/**/
Done:
PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc);
case Done:
PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc);
{ label = finish; break; }
}
#
# I.4.6.7 Floating-Point Compare Instructions
@@ -4487,6 +4482,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
| MASKED(SRR1, 48, 63));
NIA = MASKED(SRR0, 0, 61);
cpu_synchronize_context(processor);
check_masked_interrupts(processor);
}
#
@@ -4503,8 +4499,10 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
if (IS_PROBLEM_STATE(processor))
program_interrupt(processor, cia,
privileged_instruction_program_interrupt);
else
else {
MSR = *rS;
check_masked_interrupts(processor);
}
0.31,6.RT,11./,16./,21.83,31./:X:::Move From Machine State Register
*601: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0
@@ -4514,8 +4512,10 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
if (IS_PROBLEM_STATE(processor))
program_interrupt(processor, cia,
privileged_instruction_program_interrupt);
else
else {
*rT = MSR;
check_masked_interrupts(processor);
}
#
@@ -4591,11 +4591,37 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia,
0.31,6./,11./,16./,21.498,31./:X:64::SLB Invalidate All
0.31,6./,11./,16.RB,21.306,31./:X:::TLB Invalidate Entry
if (IS_PROBLEM_STATE(processor))
program_interrupt(processor, cia,
privileged_instruction_program_interrupt);
else {
int nr = 0;
cpu *proc;
while (1) {
proc = psim_cpu(cpu_system(processor), nr);
if (proc == NULL) break;
cpu_page_tlb_invalidate_entry(proc, *rB);
nr++;
}
}
0.31,6./,11./,16./,21.370,31./:X:::TLB Invalidate All
if (IS_PROBLEM_STATE(processor))
program_interrupt(processor, cia,
privileged_instruction_program_interrupt);
else {
int nr = 0;
cpu *proc;
while (1) {
proc = psim_cpu(cpu_system(processor), nr);
if (proc == NULL) break;
cpu_page_tlb_invalidate_all(proc);
nr++;
}
}
0.31,6./,11./,16./,21.566,31./:X:::TLB Sychronize
0.31,6./,11./,16./,21.566,31./:X:::TLB Synchronize
/* nothing happens here - always in sync */
#
# III.A.1.2 External Access Instructions

View File

@@ -17,79 +17,11 @@
# 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
array,normal: 0: 5: 0: 5:
array,normal: 21:31:32:-1:OE,LR,AA,Rc,LK:
array,expand-forced: 6: 9: 6: 9:BO: 0xfc000000:0x40000000
array,boolean: 11:15:11:15:0RA: 0xfc000000:0x38000000:0
array,boolean: 11:15:11:15:RA: 0xfc000000:0x3c000000:0
# BLR instruction - LR=8 is munged into 0x100
array,boolean: 11:20:11:20:SPR: 0xfc0007ff:0x7c0003a6:0x100
array,boolean: 11:20:11:20:SPR: 0xfc0007ff:0x7c0002a6:0x100

View File

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

21
sim/ppc/ppc-opcode-jump Normal file
View File

@@ -0,0 +1,21 @@
#
# 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.
#
array: 0: 5: 0: 5
array:21:31

View File

@@ -17,76 +17,9 @@
# 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.
# Create a two level switch statement. The first level branches on bits
# 0..5 while the second level branches on bits 21..31
#
# 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
switch: 0: 5: 0: 5
switch:21:31

View File

@@ -16,77 +16,6 @@
# 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: 0:0x00000000:0x00000000:0
21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0

View File

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

View File

@@ -16,77 +16,6 @@
# 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

View File

@@ -22,7 +22,10 @@
#ifndef _PSIM_C_
#define _PSIM_C_
#include "inline.c"
#include "cpu.h" /* includes psim.h */
#include "idecode.h"
#include "options.h"
#include <stdio.h>
#include <ctype.h>
@@ -33,10 +36,6 @@
#include <setjmp.h>
#include "cpu.h" /* includes psim.h */
#include "idecode.h"
#include "options.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
@@ -45,6 +44,7 @@
#endif
#endif
#include "bfd.h"
@@ -87,7 +87,7 @@ INLINE_PSIM\
(device *)
psim_tree(void)
{
device *root = core_device_create();
device *root = device_tree_add_parsed(NULL, "core");
device_tree_add_parsed(root, "/aliases");
device_tree_add_parsed(root, "/options");
device_tree_add_parsed(root, "/chosen");
@@ -245,7 +245,8 @@ psim_options(device *root,
argp += 1;
}
/* force the trace node to (re)process its options */
device_init_data(device_tree_find_device(root, "/openprom/trace"), NULL);
device_ioctl(device_tree_find_device(root, "/openprom/trace"), NULL, 0);
/* return where the options end */
return argv + argp;
}
@@ -345,7 +346,7 @@ psim_create(const char *file_name,
/* create things */
system = ZALLOC(psim);
system->events = event_queue_create();
system->memory = core_create(root);
system->memory = core_from_device(root);
system->monitor = mon_create();
system->nr_cpus = nr_cpus;
system->os_emulation = os_emulation;
@@ -373,7 +374,7 @@ psim_create(const char *file_name,
/* allow the simulation to stop/restart abnormaly */
STATIC_INLINE_PSIM\
INLINE_PSIM\
(void)
psim_set_halt_and_restart(psim *system,
void *halt_jmp_buf,
@@ -383,7 +384,7 @@ psim_set_halt_and_restart(psim *system,
system->path_to_restart = restart_jmp_buf;
}
STATIC_INLINE_PSIM\
INLINE_PSIM\
(void)
psim_clear_halt_and_restart(psim *system)
{
@@ -418,6 +419,20 @@ psim_halt(psim *system,
longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
}
INLINE_PSIM\
(int)
psim_last_cpu(psim *system)
{
return system->last_cpu;
}
INLINE_PSIM\
(int)
psim_nr_cpus(psim *system)
{
return system->nr_cpus;
}
INLINE_PSIM\
(psim_status)
psim_get_status(psim *system)
@@ -463,7 +478,8 @@ psim_init(psim *system)
/* scrub the monitor */
mon_init(system->monitor, system->nr_cpus);
os_emul_init(system->os_emulation, system->nr_cpus);
/* trash any pending events */
event_queue_init(system->events);
/* scrub all the cpus */
@@ -473,6 +489,9 @@ psim_init(psim *system)
/* init all the devices (which updates the cpus) */
device_tree_init(system->devices, system);
/* and the emulation (which needs an initialized device tree) */
os_emul_init(system->os_emulation, system->nr_cpus);
/* now sync each cpu against the initialized state of its registers */
for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
cpu_synchronize_context(system->processors[cpu_nr]);
@@ -480,7 +499,7 @@ psim_init(psim *system)
}
/* force loop to restart */
system->last_cpu = system->nr_cpus - 1;
system->last_cpu = -1; /* when incremented will become 0 - first CPU */
}
INLINE_PSIM\
@@ -497,7 +516,6 @@ psim_stack(psim *system,
unsigned_word stack_pointer;
psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
device_ioctl(stack_device,
system,
NULL, /*cpu*/
0, /*cia*/
stack_pointer,
@@ -508,219 +526,6 @@ psim_stack(psim *system,
/* EXECUTE REAL CODE:
Unfortunatly, there are multiple cases to consider vis:
<icache> X <smp> X <events> X <keep-running-flag> X ...
Consequently this function is written in multiple different ways */
STATIC_INLINE_PSIM\
(void)
run_until_stop(psim *system,
volatile int *keep_running)
{
jmp_buf halt;
jmp_buf restart;
#if WITH_IDECODE_CACHE_SIZE
int cpu_nr;
for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
cpu_flush_icache(system->processors[cpu_nr]);
#endif
psim_set_halt_and_restart(system, &halt, &restart);
#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
/* CASE 1: No instruction cache and no SMP.
In this case, we can take advantage of the fact that the current
instruction address does not need to be returned to the cpu
object after every execution of an instruction. Instead it only
needs to be saved when either A. the main loop exits or B. a
cpu-{halt,restart} call forces the loop to be re-entered. The
later functions always save the current cpu instruction
address. */
if (!setjmp(halt)) {
do {
if (!setjmp(restart)) {
cpu *const processor = system->processors[0];
unsigned_word cia = cpu_get_program_counter(processor);
do {
if (WITH_EVENTS) {
if (event_queue_tick(system->events)) {
cpu_set_program_counter(processor, cia);
event_queue_process(system->events);
cia = cpu_get_program_counter(processor);
}
}
{
instruction_word const instruction
= vm_instruction_map_read(cpu_instruction_map(processor),
processor, cia);
cia = idecode_issue(processor, instruction, cia);
}
} while (keep_running == NULL || *keep_running);
cpu_set_program_counter(processor, cia);
}
} while(keep_running == NULL || *keep_running);
}
#endif
#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
/* CASE 2: Instruction case but no SMP
Here, the additional complexity comes from there being two
different cache implementations. A simple function address cache
or a full cracked instruction cache */
if (!setjmp(halt)) {
do {
if (!setjmp(restart)) {
cpu *const processor = system->processors[0];
unsigned_word cia = cpu_get_program_counter(processor);
do {
if (WITH_EVENTS)
if (event_queue_tick(system->events)) {
cpu_set_program_counter(processor, cia);
event_queue_process(system->events);
cia = cpu_get_program_counter(processor);
}
{
idecode_cache *const cache_entry = cpu_icache_entry(processor,
cia);
if (cache_entry->address == cia) {
idecode_semantic *const semantic = cache_entry->semantic;
cia = semantic(processor, cache_entry, cia);
}
else {
instruction_word const instruction
= vm_instruction_map_read(cpu_instruction_map(processor),
processor,
cia);
idecode_semantic *const semantic = idecode(processor,
instruction,
cia,
cache_entry);
if (WITH_MON != 0)
mon_event(mon_event_icache_miss, processor, cia);
cache_entry->address = cia;
cache_entry->semantic = semantic;
cia = semantic(processor, cache_entry, cia);
}
}
} while (keep_running == NULL || *keep_running);
cpu_set_program_counter(processor, cia);
}
} while(keep_running == NULL || *keep_running);
}
#endif
#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
/* CASE 3: No ICACHE but SMP
The complexity here comes from needing to correctly restart the
system when it is aborted. In particular if cpu0 requests a
restart, the next cpu is still cpu1. Cpu0 being restarted after
all the other CPU's and the event queue have been processed */
if (!setjmp(halt)) {
int first_cpu = setjmp(restart);
if (first_cpu == 0)
first_cpu = system->last_cpu + 1;
do {
int current_cpu;
for (current_cpu = first_cpu, first_cpu = 0;
current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
current_cpu++) {
if (WITH_EVENTS && current_cpu == system->nr_cpus) {
if (event_queue_tick(system->events))
event_queue_process(system->events);
}
else {
cpu *const processor = system->processors[current_cpu];
unsigned_word const cia = cpu_get_program_counter(processor);
instruction_word instruction =
vm_instruction_map_read(cpu_instruction_map(processor),
processor,
cia);
cpu_set_program_counter(processor,
idecode_issue(processor, instruction, cia));
}
if (!(keep_running == NULL || *keep_running)) {
system->last_cpu = current_cpu;
break;
}
}
} while (keep_running == NULL || *keep_running);
}
#endif
#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
/* CASE 4: ICACHE and SMP ...
This time, everything goes wrong. Need to restart loops
correctly, need to save the program counter and finally need to
keep track of each processors current address! */
if (!setjmp(halt)) {
int first_cpu = setjmp(restart);
if (!first_cpu)
first_cpu = system->last_cpu + 1;
do {
int current_cpu;
for (current_cpu = first_cpu, first_cpu = 0;
current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
current_cpu++) {
if (WITH_EVENTS && current_cpu == system->nr_cpus) {
if (event_queue_tick(system->events))
event_queue_process(system->events);
}
else {
cpu *processor = system->processors[current_cpu];
unsigned_word const cia = cpu_get_program_counter(processor);
idecode_cache *cache_entry = cpu_icache_entry(processor, cia);
if (cache_entry->address == cia) {
idecode_semantic *semantic = cache_entry->semantic;
cpu_set_program_counter(processor,
semantic(processor, cache_entry, cia));
}
else {
instruction_word instruction =
vm_instruction_map_read(cpu_instruction_map(processor),
processor,
cia);
idecode_semantic *semantic = idecode(processor,
instruction,
cia,
cache_entry);
if (WITH_MON != 0)
mon_event(mon_event_icache_miss, system->processors[current_cpu], cia);
cache_entry->address = cia;
cache_entry->semantic = semantic;
cpu_set_program_counter(processor,
semantic(processor, cache_entry, cia));
}
}
if (!(keep_running == NULL || *keep_running))
break;
}
} while (keep_running == NULL || *keep_running);
}
#endif
psim_clear_halt_and_restart(system);
}
/* SIMULATE INSTRUCTIONS, various different ways of achieving the same
thing */
@@ -729,14 +534,16 @@ INLINE_PSIM\
psim_step(psim *system)
{
volatile int keep_running = 0;
run_until_stop(system, &keep_running);
idecode_run_until_stop(system, &keep_running,
system->events, system->processors, system->nr_cpus);
}
INLINE_PSIM\
(void)
psim_run(psim *system)
{
run_until_stop(system, NULL);
idecode_run(system,
system->events, system->processors, system->nr_cpus);
}
INLINE_PSIM\
@@ -744,7 +551,8 @@ INLINE_PSIM\
psim_run_until_stop(psim *system,
volatile int *keep_running)
{
run_until_stop(system, keep_running);
idecode_run_until_stop(system, keep_running,
system->events, system->processors, system->nr_cpus);
}
@@ -806,6 +614,23 @@ psim_read_register(psim *system,
*(msreg*)cooked_buf = cpu_registers(processor)->msr;
break;
case reg_insns:
*(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
which_cpu);
break;
case reg_stalls:
if (cpu_model(processor) == NULL)
error("$stalls only valid if processor unit model enabled (-I)\n");
*(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
break;
case reg_cycles:
if (cpu_model(processor) == NULL)
error("$cycles only valid if processor unit model enabled (-I)\n");
*(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
break;
default:
printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
(unsigned long)processor, (unsigned long)buf, reg,

View File

@@ -1,6 +1,6 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
Copyright (C) 1994-1996, 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
@@ -23,7 +23,6 @@
#include <stdarg.h>
#include <ctype.h>
#include "cpu.h"
#include "psim.h"
#include "options.h"
@@ -41,8 +40,6 @@
#include "../../gdb/defs.h"
#include "devices.h"
#include "../../gdb/remote-sim.h"
#include "../../gdb/callback.h"
@@ -50,79 +47,30 @@
/* Structures used by the simulator, for gdb just have static structures */
static psim *simulator;
static char *register_names[] = REGISTER_NAMES;
static int print_info = 0;
static device *root_device;
static const char *register_names[] = REGISTER_NAMES;
void
sim_open (char *args)
{
/* Note: The simulation is not created by sim_open() because
complete information is not yet available */
/* trace the call */
TRACE(trace_gdb, ("sim_open(args=%s) called\n", args ? args : "(null)"));
if (root_device != NULL)
printf_filtered("Warning - re-open of simulator leaks memory\n");
root_device = psim_tree();
simulator = NULL;
if (args) {
char **argv = buildargv(args);
int argp = 0;
int argc;
for (argc = 0; argv[argc]; argc++);
while (argp < argc) {
if (*argv[argp] != '-')
error ("Argument is not an option '%s'", argv[argp]);
else {
/* check arguments -- note, main.c also contains argument processing
code for the standalone emulator. */
char *p = argv[argp] + 1;
while (*p != '\0') {
switch (*p) {
default:
printf_filtered("Usage:\n\ttarget sim [ -t <trace-option> ] [-m model] [-i] [-I]\n");
trace_usage();
error ("");
break;
case 't':
if (p[1])
trace_option(p+1);
else {
argp += 1;
if (argv[argp] == NULL)
error("Missing <trace> option for -t\n");
else
trace_option(argv[argp]);
}
break;
case 'm':
if (p[1])
model_set(p+1);
else {
argp += 1;
if (argv[argp] == NULL)
error("Missing <trace> option for -t\n");
else
model_set(argv[argp]);
}
break;
case 'i':
print_info = 1;
break;
case 'I':
current_model_issue = MODEL_ISSUE_PROCESS;
print_info = 2;
break;
}
p += 1;
}
}
argp += 1;
}
psim_options(root_device, argv);
freeargv(argv);
}
if (ppc_trace[trace_opts])
print_options ();
/* do something */
TRACE(trace_tbd, ("sim_open() - TBD - should parse the arguments\n"));
TRACE(trace_tbd, ("sim_open() - TBD - can not create simulator here as do not have description of it\n"));
}
@@ -130,10 +78,8 @@ void
sim_close (int quitting)
{
TRACE(trace_gdb, ("sim_close(quitting=%d) called\n", quitting));
if (print_info)
psim_print_info (simulator, print_info);
/* nothing to do */
if (ppc_trace[trace_print_info] && simulator != NULL)
psim_print_info (simulator, ppc_trace[trace_print_info]);
}
@@ -151,7 +97,7 @@ sim_load (char *prog, int from_tty)
/* create the simulator */
TRACE(trace_gdb, ("sim_load() - first time, create the simulator\n"));
simulator = psim_create(argv[0]);
simulator = psim_create(argv[0], root_device);
/* bring in all the data section */
psim_init(simulator);
@@ -323,9 +269,15 @@ sim_resume (int step, int siggnal)
}
void
sim_do_command(char *cmd)
sim_do_command (char *cmd)
{
TRACE(trace_gdb, ("sim_do_commands(cmd=%s) called\n", cmd));
TRACE(trace_gdb, ("sim_do_commands(cmd=%s) called\n",
cmd ? cmd : "(null)"));
if (cmd) {
char **argv = buildargv(cmd);
psim_options(root_device, argv);
freeargv(argv);
}
}
void
@@ -350,3 +302,8 @@ void zfree(void *data)
{
mfree(NULL, data);
}
void flush_stdoutput(void)
{
gdb_flush (gdb_stdout);
}

View File

@@ -287,6 +287,15 @@ extern int current_model_issue;
? WITH_MODEL_ISSUE \
: current_model_issue)
/* Whether or not input/output just uses stdio, or uses printf_filtered for
output, and polling input for input. */
#define DONT_USE_STDIO 0
#define DO_USE_STDIO 1
#ifndef WITH_STDIO
#define WITH_STDIO DONT_USE_STDIO
#endif
/* INLINE CODE SELECTION:
GCC -O3 attempts to inline any function or procedure in scope. The
@@ -308,18 +317,30 @@ extern int current_model_issue;
The following additional values are `bit fields' and can be
combined.
1 Include the C file for the module into the file being compiled
REVEAL_MODULE:
Include the C file for the module into the file being compiled
but do not make the functions within the module inline.
While of no apparent benefit, this makes it possible for the
included module, when compiled to inline its calls to what
would otherwize be external functions.
2 Make external functions within the module `inline'. Thus if
INLINE_MODULE:
Make external functions within the module `inline'. Thus if
the module is included into a file being compiled, calls to
its funtions can be eliminated. 2 implies 1.
4 Make internal (static) functions within the module `inline'.
INLINE_LOCALS:
Make internal (static) functions within the module `inline'.
The following abreviations are available:
INCLUDE_MODULE == (REVEAL_MODULE | INLINE_MODULE)
ALL_INLINE == (REVEAL_MODULE | INLINE_MODULE | INLINE_LOCALS)
In addition to this, modules have been put into two categories.
@@ -401,7 +422,7 @@ extern int current_model_issue;
REALITY CHECK:
This is not for the faint hearted. I've seen GCC get up to 200mb
This is not for the faint hearted. I've seen GCC get up to 500mb
trying to compile what this can create.
Some of the modules do not yet implement the WITH_INLINE_STATIC
@@ -433,6 +454,18 @@ extern int current_model_issue;
#endif
#endif
/* Your compilers pass parameters in registers reserved word */
#if !defined REGPARM
#if (defined(i386) || defined(i486) || defined(i586) || defined(__i386__) || defined(__i486__) || defined(__i586__)) && WITH_REGPARM
#define REGPARM __attribute__((__regparm__(WITH_REGPARM)))
#else
#define REGPARM
#endif
#endif
/* Default prefix for static functions */
#ifndef STATIC_INLINE
@@ -513,14 +546,10 @@ extern int current_model_issue;
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 */
a jump table. */
#ifndef DEVICE_INLINE
#define DEVICE_INLINE DEFAULT_INLINE
#define DEVICE_INLINE INLINE_LOCALS
#endif
/* Code called whenever information on a Special Purpose Register is
@@ -546,11 +575,21 @@ extern int current_model_issue;
#define SEMANTICS_INLINE DEFAULT_INLINE
#endif
/* Code to decode an instruction. Normally called on every instruction
cycle */
/* When using the instruction cache, code to decode an instruction and
install it into the cache. Normally called when ever there is a
miss in the instruction cache. */
#ifndef IDECODE_INLINE
#define IDECODE_INLINE DEFAULT_INLINE
#ifndef ICACHE_INLINE
#define ICACHE_INLINE DEFAULT_INLINE
#endif
/* General functions called by semantics functions but part of the
instruction table. Although called by the semantic functions the
frequency of calls is low. Consequently the need to inline this
code is reduced. */
#ifndef SUPPORT_INLINE
#define SUPPORT_INLINE INLINE_LOCALS
#endif
/* Model specific code used in simulating functional units. Note, it actaully
@@ -559,7 +598,7 @@ extern int current_model_issue;
of the code, which is not friendly to the cache. */
#ifndef MODEL_INLINE
#define MODEL_INLINE DEFAULT_INLINE
#define MODEL_INLINE (DEFAULT_INLINE & ~INLINE_MODULE)
#endif
/* Code to print out what options we were compiled with. Because this
@@ -568,11 +607,24 @@ extern int current_model_issue;
routines will be pulled in twice. */
#ifndef OPTIONS_INLINE
#define OPTIONS_INLINE DEFAULT_INLINE
#define OPTIONS_INLINE MODEL_INLINE
#endif
/* Code to emulate os or rom compatibility. Called on the rare
occasion that the OS or ROM code is being emulated. */
/* idecode acts as the hub of the system, everything else is imported
into this file */
#ifndef IDECOCE_INLINE
#define IDECODE_INLINE INLINE_LOCALS
#endif
/* psim, isn't actually inlined */
#ifndef PSIM_INLINE
#define PSIM_INLINE INLINE_LOCALS
#endif
/* Code to emulate os or rom compatibility. This code is called via a
table and hence there is little benefit in making it inline */
#ifndef OS_EMUL_INLINE
#define OS_EMUL_INLINE 0