forked from Imagelibrary/binutils-gdb
New simulator changes from Andrew
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
2129
sim/ppc/configure
vendored
2129
sim/ppc/configure
vendored
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
2611
sim/ppc/device.c
2611
sim/ppc/device.c
File diff suppressed because it is too large
Load Diff
943
sim/ppc/device.h
943
sim/ppc/device.h
File diff suppressed because it is too large
Load Diff
876
sim/ppc/device.maybe
Normal file
876
sim/ppc/device.maybe
Normal 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
306
sim/ppc/device_table.h
Normal 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_ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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
150
sim/ppc/filter.c
Normal 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
43
sim/ppc/filter.h
Normal 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
595
sim/ppc/gen-icache.c
Normal 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
56
sim/ppc/gen-icache.h
Normal 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
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
40
sim/ppc/gen-idecode.h
Normal 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
122
sim/ppc/gen-itable.c
Normal 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
28
sim/ppc/gen-itable.h
Normal 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
30
sim/ppc/gen-model.h
Normal 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
253
sim/ppc/gen-semantics.c
Normal 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
81
sim/ppc/gen-semantics.h
Normal 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
128
sim/ppc/gen-support.c
Normal 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
29
sim/ppc/gen-support.h
Normal 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
142
sim/ppc/hw_core.c
Normal 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
316
sim/ppc/hw_memory.c
Normal 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_ */
|
||||
114
sim/ppc/hw_pal.c
114
sim/ppc/hw_pal.c
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
3577
sim/ppc/igen.c
3577
sim/ppc/igen.c
File diff suppressed because it is too large
Load Diff
186
sim/ppc/igen.h
Normal file
186
sim/ppc/igen.h
Normal 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);
|
||||
@@ -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
|
||||
|
||||
491
sim/ppc/inline.h
491
sim/ppc/inline.h
@@ -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
114
sim/ppc/ld-cache.c
Normal 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
75
sim/ppc/ld-cache.h
Normal 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
139
sim/ppc/ld-decode.h
Normal 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
925
sim/ppc/ld-insn.c
Normal 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
281
sim/ppc/ld-insn.h
Normal 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);
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
21
sim/ppc/ppc-opcode-jump
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
283
sim/ppc/psim.c
283
sim/ppc/psim.c
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user