summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Elliston <bje@redhat.com>2000-07-28 04:11:52 +0000
committerBen Elliston <bje@redhat.com>2000-07-28 04:11:52 +0000
commit824bbc4849b364faa16054cecc940ab214b42379 (patch)
tree0eed8e22c55cbee8df3bad491c15b10f52652213
parent418d8e2e61a27d428f363b110a52dd88361ff6d7 (diff)
downloadgdb-cgen-1-0.tar.gz
CGEN 1.0 importcgen-1-0
-rw-r--r--cgen/AUTHORS1
-rw-r--r--cgen/COPYING.CGEN44
-rw-r--r--cgen/ChangeLog4263
-rw-r--r--cgen/INSTALL182
-rw-r--r--cgen/Makefile.am124
-rw-r--r--cgen/Makefile.in449
-rw-r--r--cgen/NEWS3
-rw-r--r--cgen/README191
-rw-r--r--cgen/aclocal.m4137
-rw-r--r--cgen/arm.cpu404
-rw-r--r--cgen/arm.sim39
-rw-r--r--cgen/arm7.cpu1995
-rw-r--r--cgen/attr.scm910
-rw-r--r--cgen/cgen-gas.scm80
-rw-r--r--cgen/cgen-opc.scm99
-rw-r--r--cgen/cgen-sim.scm112
-rw-r--r--cgen/cgen-stest.scm79
-rwxr-xr-xcgen/configure1374
-rw-r--r--cgen/configure.in18
-rw-r--r--cgen/cos.scm1336
-rw-r--r--cgen/decode.scm640
-rw-r--r--cgen/desc-cpu.scm954
-rw-r--r--cgen/desc.scm238
-rw-r--r--cgen/dev.scm179
-rw-r--r--cgen/doc/Makefile.am17
-rw-r--r--cgen/doc/Makefile.in335
-rw-r--r--cgen/doc/app.texi430
-rw-r--r--cgen/doc/cgen.texi118
-rw-r--r--cgen/doc/credits.texi27
-rw-r--r--cgen/doc/glossary.texi29
-rw-r--r--cgen/doc/internals.texi377
-rw-r--r--cgen/doc/intro.texi759
-rw-r--r--cgen/doc/notes.texi237
-rw-r--r--cgen/doc/opcodes.texi186
-rw-r--r--cgen/doc/pmacros.texi457
-rw-r--r--cgen/doc/porting.texi863
-rw-r--r--cgen/doc/rtl.texi2276
-rw-r--r--cgen/doc/running.texi9
-rw-r--r--cgen/doc/sim.texi45
-rw-r--r--cgen/doc/stamp-vti3
-rw-r--r--cgen/doc/version.texi3
-rw-r--r--cgen/enum.scm391
-rw-r--r--cgen/fixup.scm38
-rw-r--r--cgen/fr30.cpu1845
-rw-r--r--cgen/fr30.opc242
-rw-r--r--cgen/gas-test.scm227
-rw-r--r--cgen/hardware.scm1172
-rw-r--r--cgen/i960.cpu1320
-rw-r--r--cgen/i960.opc32
-rw-r--r--cgen/ia32.cpu917
-rw-r--r--cgen/ia64.cpu2355
-rw-r--r--cgen/ifield.scm1164
-rw-r--r--cgen/iformat.scm614
-rw-r--r--cgen/insn.scm958
-rw-r--r--cgen/m32r.cpu2088
-rw-r--r--cgen/m32r.opc264
-rw-r--r--cgen/m68k.cpu253
-rw-r--r--cgen/mach.scm1473
-rw-r--r--cgen/minsn.scm259
-rw-r--r--cgen/mode.scm471
-rw-r--r--cgen/model.scm304
-rw-r--r--cgen/opc-asmdis.scm182
-rw-r--r--cgen/opc-ibld.scm319
-rw-r--r--cgen/opc-itab.scm724
-rw-r--r--cgen/opc-opinst.scm168
-rw-r--r--cgen/opcodes.scm804
-rw-r--r--cgen/operand.scm1559
-rw-r--r--cgen/pgmr-tools.scm183
-rw-r--r--cgen/play.cpu265
-rw-r--r--cgen/pmacros.scm562
-rw-r--r--cgen/profile.scm180
-rw-r--r--cgen/read.scm1198
-rw-r--r--cgen/rtl-c.scm1662
-rw-r--r--cgen/rtl.scm2205
-rw-r--r--cgen/rtx-funcs.scm1002
-rw-r--r--cgen/sem-frags.scm1236
-rw-r--r--cgen/semantics.scm879
-rw-r--r--cgen/sim-arch.scm181
-rw-r--r--cgen/sim-cpu.scm1231
-rw-r--r--cgen/sim-decode.scm592
-rw-r--r--cgen/sim-model.scm394
-rw-r--r--cgen/sim-test.scm244
-rw-r--r--cgen/sim.scm2019
-rw-r--r--cgen/simplify.inc198
-rw-r--r--cgen/slib/genwrite.scm270
-rw-r--r--cgen/slib/pp.scm10
-rw-r--r--cgen/slib/sort.scm151
-rw-r--r--cgen/sparc.cpu612
-rw-r--r--cgen/sparc.opc180
-rw-r--r--cgen/sparc32.cpu170
-rw-r--r--cgen/sparc64.cpu422
-rw-r--r--cgen/sparccom.cpu766
-rw-r--r--cgen/sparcfpu.cpu527
-rw-r--r--cgen/stamp-h.in1
-rw-r--r--cgen/thumb.cpu842
-rw-r--r--cgen/types.scm278
-rw-r--r--cgen/utils-cgen.scm654
-rw-r--r--cgen/utils-gen.scm506
-rw-r--r--cgen/utils-sim.scm955
-rw-r--r--cgen/utils.scm1268
100 files changed, 62008 insertions, 0 deletions
diff --git a/cgen/AUTHORS b/cgen/AUTHORS
new file mode 100644
index 00000000000..c0b497b4543
--- /dev/null
+++ b/cgen/AUTHORS
@@ -0,0 +1 @@
+CGEN was originally written by Doug Evans <devans@cygnus.com>.
diff --git a/cgen/COPYING.CGEN b/cgen/COPYING.CGEN
new file mode 100644
index 00000000000..b64876fa992
--- /dev/null
+++ b/cgen/COPYING.CGEN
@@ -0,0 +1,44 @@
+CGEN - a Cpu tools GENerator
+Copyright 2000 Red Hat, Inc.
+
+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, 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 software; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA
+
+As a special exception, Red Hat gives unlimited permission to copy,
+distribute and modify the code that is the output of CGEN. You need
+not follow the terms of the GNU General Public License when using or
+distributing such code, even though portions of the text of CGEN
+appear in them. The GNU General Public License (GPL) does govern all
+other use of the material that constitutes the CGEN program.
+
+Certain portions of the CGEN source text are designed to be copied (in
+certain cases, depending on the input) into the output of CGEN. We
+call these the "data" portions. CPU description files are, for the
+purposes of this copyright, deemed "data". The rest of the CGEN
+source text consists of comments plus executable code that decides
+which of the data portions to output in any given case. We call these
+comments and executable code the "non-data" portions. CGEN never
+copies any of the non-data portions into its output.
+
+This special exception to the GPL applies to versions of CGEN released
+by Red Hat. When you make and distribute a modified version of CGEN,
+you may extend this special exception to the GPL to apply to your
+modified version as well, *unless* your modified version has the
+potential to copy into its output some of the text that was the
+non-data portion of the version that you started with. (In other
+words, unless your change moves or copies text from the non-data
+portions to the data portions.) If your modification has such
+potential, you must delete any notice of this special exception to the
+GPL from your modified version.
diff --git a/cgen/ChangeLog b/cgen/ChangeLog
new file mode 100644
index 00000000000..8f7c9449f0d
--- /dev/null
+++ b/cgen/ChangeLog
@@ -0,0 +1,4263 @@
+2000-07-25 Ben Elliston <bje@redhat.com>
+
+ * doc/credits.texi (Credits): Add Frank Eigler.
+
+2000-07-24 Dave Brolley <brolley@redhat.com>
+
+ * opc-itab.scm (gen-insn-opcode-table): Initialize the first element
+ fully.
+ * desc.scm (gen-attr-table-defn): Initialize all elements fully.
+ (<keyword>): Initialize all elements fully.
+ * desc-cpu.scm (-gen-isa-table-defns): Initialize the last element
+ fully.
+ (-gen-mach-table-defns): Ditto.
+ (-gen-ifld-defns): Ditto.
+ (-gen-operand-table): Ditto.
+ (-gen-insn-table): Ditto.
+ (-gen-cpu-open): Nothing to do for the mach table.
+
+2000-07-13 Ben Elliston <bje@redhat.com>
+
+ * doc/version.texi (UPDATED): Update.
+
+2000-07-05 Ben Elliston <bje@redhat.com>
+
+ * configure.in (AC_PATH_PROG): Remove.
+ * configure: Regenerate.
+ * Makefile.am (GUILE): Locate guile dynamically.
+ * Makefile.in: Regenerate.
+ * doc/Makefile.in: Likewise.
+
+2000-07-03 Ben Elliston <bje@redhat.com>
+
+ * desc-cpu.scm (cgen-desc.c): Include "libiberty.h".
+ * opc-itab.scm (cgen-opc.c): Likewise.
+
+2000-06-28 Frank Ch. Eigler <fche@redhat.com>
+
+ * rtl.scm (-rtx-traverse-locals): Correct call to `symbol?' for
+ guile 1.4 compatibility.
+ (rtx-env-dump): Comment out buggy display calls.
+
+2000-06-15 matthew green <mrg@redhat.com>
+
+ * opc-itab.scm (-gen-ifmt-table-1): Add extra braces to pacify GCC.
+
+2000-06-14 Frank Ch. Eigler <fche@redhat.com>
+
+ * Makefile.in: Regenerated.
+
+ * desc-cpu.scm (gen-ifld-decls): Exclude derived ifields.
+ (gen-ifld-defns): Ditto.
+ * pgmr-tools.scm (pgmr-pretty-print-insn-format): Ditto.
+ * rtl.c (rtl-finish!): Ditto.
+ * opc-itab.scm (-gen-ifield-decls): Ditto.
+ * opcodes.scm (gen-switch): Exclude derived operands.
+ * operand.scm (op-iflds-used): Expand derived operands.
+ (hw-index-derived): New dummy function to create dummy object.
+ (-derived-operand-parse): Fix mode arg passed to <derived-operand>
+ constructor. Set object's hw-name and index fields.
+ (-anyof-merge-subchoices): Set instance object's index also.
+ (-anyof-name): New helper function.
+ (anyof-merge-semantics): Correct replacement of operand names in
+ anyof instance.
+ (op-ifield): Tolerate derived-operands and their funny indices better.
+ * ifield.scm (ifld-known-values): Expand derived ifields.
+ (non-multi-ifields, non-derived-ifields): New utility functions.
+ (ifld-decode-mode): Tolerate objects with unbound decode field.
+ * iformat.scm (compute-insn-length): Expand derived ifields.
+ (compute-insn-base-mask): Ditto.
+ * insn.scm (insn-base-ifields): Remove.
+ (<insn>): Add iflds-values entry to cache ifld-base-ifields values.
+ (insn-value): Call ifld-base-ifields and ifld-constant? instead.
+ * mach.scm (arch-analyze-insns!): Exclude multi-insns.
+ * sem-frags.scm (sim-sfrag-analyze-insns!): Ditto.
+ (-frag-test-data): Ditto.
+ * sim-decode.scm (cgen-decode.h, cgen-decode.cxx): Ditto.
+ * utils-sim.scm (op-extract?): Handle derived operands.
+
+ * gas-test.scm (cgen-build.sh): Quote '*' chars printed by objdump.
+ * semantics.scm (-build-operand!): Handle 'DFLT case during parsing.
+ * hardware.scm (hardware-for-mode): New function.
+
+ * insn.scm (filter-harmlessly-ambiguous-insns): New function for
+ cleaning up decode tables.
+ (mask-superset?): Little helper function for above.
+ * decode.scm (-build-decode-table-entry): Call it.
+ (-opcode-slots): Add some more tracing.
+ * arm.cpu: Disable decode-splits construct due to implementation
+ conflict with `filter-harmlessly-ambiguous-insns'
+
+ * decode.scm (-population-top-few): New function for better decode
+ bit generation. Includes minor helper functions.
+ (decode-get-best-bits): Call it instead.
+ (OLDdecode-get-best-bits): Renamed previous version of above.
+
+
+2000-06-13 Ben Elliston <bje@redhat.com>
+
+ * configure.in: Use AC_EXEEXT with Cygnus mode. Remove AC_ARG_WITH
+ for the Guile library directory.
+ * configure: Regenerate.
+ * Makefile.in, doc/Makefile.in: Regenerate.
+
+ * Makefile.in, doc/Makefile.in: Regenerate.
+ * configure.in: Remove unnecessary tests. Move to version 1.0.
+ * acconfig.h, config.in: Remove.
+ * configure, aclocal.m4: Regenerate.
+ * doc/stamp-vti, doc/version.texi: Likewise.
+ * AUTHORS: New file.
+
+2000-06-07 Ben Elliston <bje@redhat.com>
+
+ * fixup.scm (symbol-bound?): Reduce debugging output.
+
+2000-06-02 matthew green <mrg@redhat.com>
+
+ * insn.scm (insn-base-ifields): Returns all the instruction fields for
+ a given instruction, replacing derived fields with their subfields.
+ (insn-value): Use `insn-base-ifields' to find all constant values.
+ (multi-insn-instantiate!): Comment some debug messages.
+
+2000-06-01 Ben Elliston <bje@redhat.com>
+
+ * doc/rtl.texi (Expressions): Document a hazard with the choice of
+ symbol names used in a (c-call ..) rtx.
+
+ * sim-test.scm (build-test-set): Return (()) for an instruction
+ with no operands, so it too is included in the generated test set.
+
+2000-05-31 Ben Elliston <bje@redhat.com>
+
+ * Makefile.am (gas-test): Ensure $(ISA) is not empty.
+ (sim-test): Likewise.
+ * Makefile.in: Regenerate.
+
+2000-05-30 Frank Ch. Eigler <fche@redhat.com>
+
+ * read.scm (-cgen): In debugging mode (-b), ask guile for untruncated
+ stack traceback, in an order that resembles gdb's `bt'.
+
+2000-05-24 Frank Ch. Eigler <fche@redhat.com>
+
+ * desc-cpu.scm (-gen-hash-defines): Use ifmt-ifields again.
+ * opc-itab.scm (-gen-ifmt-table-1): Ditto.
+ * gas-test.scm (gas-test-analyze!, cgen-build.sh): Filter out
+ multi insns.
+ * ifield.scm (multi-ifield): Define workable field-mask and field-value
+ virtual functions.
+ (ifld-base-ifields): New routine to replace ifmt-expanded-ifields.
+ * iformat.scm (ifmt-expanded-ifields): Gone.
+ (ifields-base-ifields): New function. Call ifld-base-ifields for real
+ work.
+ (-ifmt-lookup-ifmt!): Use it to expand derived/multi combos in new
+ ifmt entries.
+
+ * opcodes.scm (multi-ifield gen-extract): Correct spacing in generated
+ code.
+
+2000-05-19 Frank Ch. Eigler <fche@redhat.com>
+
+ * utils-gen.scm (gen-multi-ifld-extract): Fix decode hook for sim.
+
+2000-05-18 Frank Ch. Eigler <fche@redhat.com>
+
+ * ifield.scm (-multi-ifield-parse): Add encode/decode args.
+ (-multi-ifield-read): Parse them.
+ (define-full-multi-ifield): Pass #f/#f as defaults for them.
+ * opcodes.scm (multi-ifield gen-insert): Add encode hook.
+ (multi-ifield gen-extract): Add decode hook.
+ * utils-gen.scm (gen-multi-ifld-extract): Add decode hook for sim.
+
+ * insn.scm (syntax-break-out): More correctly handle \-escaped
+ syntax characters.
+ (syntax-make-elements): Ditto.
+ * opc-itab.scm (compute-syntax): Ditto.
+
+
+2000-05-17 Ben Elliston <bje@redhat.com>
+
+ * gas-test.scm (cgen-build.sh): Log the correct script filename.
+
+2000-05-15 Frank Ch. Eigler <fche@redhat.com>
+
+ * gas-test.scm (build-test-set): Return (()) for an instruction
+ with no operands, so it too is included in the generated test set.
+
+2000-05-15 Frank Ch. Eigler <fche@redhat.com>
+
+ * desc-cpu.scm (-gen-hash-defines): Define CGEN_ACTUAL_MAX values for
+ IFMT_OPERANDS and SYNTAX_BYTES.
+
+
+2000-05-15 Frank Ch. Eigler <fche@redhat.com>
+
+ * sim.scm (with-any-profile?): New function.
+ * utils-sim.scm (-sfmt-contents): Use above instead of `with-profile?'
+ to decide whether or not to include profiling counters.
+
+2000-05-10 Frank Ch. Eigler <fche@redhat.com>
+
+ Fuller derived-operand support for opcodes.
+ * insn.scm (non-multi-insns): New filter to oppose `multi-insns'.
+ * desc-cpu.scm (-define-hash-defines): Compute CGEN_MAX_SYNTAX_BYTES.
+ Correctly compute ..._IFMT_OPERANDS. Omit useless ..._INSN_OPERANDS.
+ (gen-operand-table): Omit derived- and anyof- operands from table.
+ (gen-insn-table): Omit multi-insns from table.
+ * iformat.scm (ifmt-expanded-fields): New function to expand
+ subfields of derived-ifields.
+ (ifmt-compute!): Ignore remaining multi-insns.
+ * mach.scm (isa-min-insn-bitsize, isa-max-insn-bitsize): Ignore
+ multi-insns.
+ * opc-itab.scm (-gen-ifmt-table-1): Use ifmt-expanded-ifields.
+ (-gen-insn-enum, -gen-insn-opcode-table): Ignore multi-insns.
+ * opcodes.scm (derived-operand): Define abort()ing gen-insert,
+ gen-extract, gen-fget, gen-fset, gen-parse, gen-print functions.
+ (gen-switch): Omit anyof-operands.
+ * operand.scm (-anyof-syntax): New function.
+ (-anyof-merge-syntax): Call it.
+ * utils.scm (collect): New idiomatic function.
+
+2000-05-10 Ben Elliston <bje@redhat.com>
+
+ * m68k.cpu: New file (work in progress).
+
+2000-05-05 Frank Ch. Eigler <fche@redhat.com>
+
+ * Makefile.am (all-local): New target. Create stamp-cgen.
+ * Makefile.in: Regenerated.
+ * doc/Makefile.in: Regenerated.
+
+2000-04-26 Frank Ch. Eigler <fche@redhat.com>
+
+ * operand.scm (-operand-g/setter-syntax): Correct off-by-one error.
+ (-operand-parse-setter): Ditto.
+ * utils-sim.scm (needed-iflds): Store ifield (index) in argbuf, even
+ for CACHE-ADDR operands.
+
+
+2000-04-23 matthew green <mrg@redhat.com>
+
+ * m32r.cpu: Fix a typo.
+
+Fri Apr 21 22:18:48 2000 Jim Wilson <wilson@cygnus.com>
+
+ * ia64.cpu (define-model): Change merced to Itanium.
+ (f-qp): Change quilifying to qualifying.
+ (movbr_ph, movbr_pvec): Delete.
+ (I-I21): Delete uses of movbr_ph and movbr_pvec.
+
+2000-04-07 Ben Elliston <bje@redhat.com>
+
+ * doc/porting.texi (Building a simulator test suite): Clarify
+ where generated test cases are placed.
+
+2000-04-07 Ben Elliston <bje@redhat.com>
+
+ * Makefile.am (gas-test): Remove dependency on `cgen'.
+ (sim-test): Ditto.
+ * Makefile.in: Regenerate.
+
+2000-04-04 Frank Ch. Eigler <fche@redhat.com>
+
+ * hardware.scm (<hw-pc> parse): Allow user to set type for pc register.
+ * mode.scm (mode-finish!): Add placeholder code for mach-dependent
+ type reconfiguration.
+ * utils-sim.scm (-sfmt-contents): Add profile-counters only if
+ with-profile?.
+
+2000-03-30 Ben Elliston <bje@redhat.com>
+
+ * doc/rtl.texi (Enumerated constants): Add concept index entries.
+
+2000-03-24 Ben Elliston <bje@redhat.com>
+
+ * Makefile.am (stamp-cgen): Reinstate target.
+ * Makefile.in: Regenerate.
+
+2000-03-22 Ben Elliston <bje@redhat.com>
+
+ * slib/ppfile.scm: Remove; unused.
+ * slib/defmacex.scm: Likewise.
+
+2000-03-21 Ben Elliston <bje@redhat.com>
+
+ * doc/internals.texi (Source file overview): Document.
+
+ * Makefile.am (GUILEDIR): Remove.
+ (CGEN): Ditto. Callers use $(GUILE) instead.
+ (GUILEFLAGS): Ditto.
+ (CGENFILES): Ditto.
+ (APPDESCFILES): Ditto.
+ (OPCODESFILES): Ditto.
+ (SIMFILES): Ditto.
+ (pkgdata_SCRIPTS): Ditto.
+ (stamp-cgen): Remove target.
+ * Makefile.in: Regenerate.
+
+ * configure.in: Remove header and library tests.
+ * configure: Regenerate.
+ * config.in: Likewise.
+
+2000-03-20 Ben Elliston <bje@redhat.com>
+
+ * read.scm: Cease loading "hob-sup.scm".
+ * utils.scm: Inherit the fastcall family of procedures (for now).
+ * hob-sup.scm: Remove.
+
+2000-03-20 Ben Elliston <bje@redhat.com>
+
+ * configure.in (AC_OUTPUT): Do not emit .gdbinit.
+ * configure: Regenerate.
+ * gdbinit.in: Remove.
+
+2000-03-17 Ben Elliston <bje@redhat.com>
+
+ * Makefile.am (CGEN): Use guile, not cgen.
+ (CGENCFLAGS, LIBIBERTY, INCLUDES): Remove.
+ (bin_PROGRAMS, cgen_SOURCES): Likewise.
+ (CGENFILES): Fold CGEN_HOB_INPUT_FILES and CGEN_NOHOB_FILES.
+ (HOBBIT_INPUT_FILES, HOBBIT_OUTPUT_FILE): Remove.
+ (HOB_OBJS): Likewise.
+ (CGEN_HOB_SRC, CGEN_HOB_OBJ): Likewise.
+ (CGENOBJS): Likewise.
+ (cgen_DEPENDENCIES, cgen_LDFLAGS, cgen_LDADD): Likewise.
+ (hobbit, hobbit.o, hobbit.c): Remove targets.
+ (cos.o, cgen.o, cgen-gh.o, hob-sup.o): Likewise.
+ (CLEANFILES): Update.
+ * acconfig.h (WITH_HOBBIT): Remove.
+ * configure.in: Do not test for 3 arg scm_make_vector. Remove
+ option --with-cgen-hobbit.
+ * cos.h, cos.c, hob-main.c, hob-sup.c, hob-sup.h, hob.sh: Remove.
+ * cgen-gh.h, cgen-gh.c, cgen-hob.scm, cgen.c: Likewise.
+ * hobbit.c, hobbit.h, hobbit.scm: Likewise.
+ * hobscmif.h, hobslib.scm, scmhob.h: Likewise.
+ * Makefile.in: Regenerate.
+ * config.in: Likewise.
+ * aclocal.m4: Likewise.
+ * configure: Likewise.
+ * README (Hobbit support): Remove.
+ * doc/internals.texi (Conventions): Do not mention Hobbit.
+ * doc/porting.texi (Supported Guile versions): Likewise.
+
+2000-03-16 Frank Ch. Eigler <fche@redhat.com>
+
+ * mipscom.cpu (break, syscall, define-trap): Make these non-cti
+ insns.
+ * sid-cpu.scm (-gen-sem-switch-engine): Adjust calling &
+ callback convention to new sid sidutil::basic_cpu code.
+ (-gen-sfrag-engine-fn): Ditto.
+ * sid.scm (-create-virtual-insns!): Ditto.
+ (-hw-gen-set-quiet-pc): Mark delay slot execution specially in pbb
+ mode.
+ (cxmake-skip): Implement properly for pbb mode.
+
+2000-03-03 Ben Elliston <bje@redhat.com>
+
+ * doc/internals.texi: New file.
+
+2000-02-29 Ben Elliston <bje@redhat.com>
+
+ * doc/rtl.texi (Derived operands): Remove unnecessary footnote.
+ * doc/porting.texi: Formatting tweaks.
+
+2000-02-25 Nick Clifton <nickc@cygnus.com>
+
+ * desc-cpu.scm (*_cgen_cpu_open): Initialise signed_overflow_ok_p
+ field.
+
+Thu Feb 24 14:09:01 2000 Doug Evans <devans@seba.cygnus.com>
+
+ * operand.scm (<anyof-operand>,make!): Initialize mode-name, not
+ mode.
+
+2000-02-23 Andrew Haley <aph@cygnus.com>
+
+ * m32r.cpu (pcmpbz): Make pcmpbz a special (i.e. hidden)
+ instruction.
+
+2000-02-24 Ben Elliston <bje@redhat.com>
+
+ * doc/rtl.texi (Derived operands): Add some cindex entries.
+
+2000-02-23 Ben Elliston <bje@redhat.com>
+
+ * ia32.cpu (dndo): Move general purpose macro from here ..
+ * simplify.inc (dndo): .. to here.
+
+2000-02-18 Frank Ch. Eigler <fche@redhat.com>
+
+ * arm.cpu (h-tbit): Add c-call setter function.
+ (h-mbits): Ditto.
+
+2000-02-17 Frank Ch. Eigler <fche@redhat.com>
+
+ * sem-frags.scm (-frag-hash-compute!): Add appstuff arg for traversal.
+ (-frag-cost-compute!): Ditto.
+ * utils.scm (copyright-cygnus): Add Y2K.
+ * sid-cpu.scm (@prefix@_pbb_run): Add unsigned& argument.
+
+2000-01-25 Nick Clifton <nickc@cygnus.com>
+
+ * desc-cpu.scm (@arch@_cgen_cpu_open): Add code to initialise
+ flags field of the CGEN_CPU_TABLE structure.
+
+Sun Dec 12 14:20:36 1999 Doug Evans <devans@seba.cygnus.com>
+
+ * operand.scm (<anyof-instance>): Renamed from <anyof-value>.
+ All references updated.
+
+Tue Nov 30 11:06:22 1999 Doug Evans <devans@seba.cygnus.com>
+
+ * ia32.cpu: Rewrite addressing mode support.
+
+ * ifield.scm (<ifield>): New member `follows'.
+ (ifld-known-values): New proc.
+ (<ifield>): New method set-word-offset!.
+ (ifld-set-word-offset!): New proc.
+ (ifld-new-word-offset): New proc.
+ (<ifield>): New method next-word.
+ (<multi-ifield>): New method next-word.
+ (ifld-next-word): New proc.
+ (ifld-precedes?): New proc.
+ (-ifield-parse): New args word-offset,word-length,follows.
+ All callers updated. Handle CISC-style vs RISC-style ifields.
+ (-ifield-read): Recognize word-offset,word-length,follows specs.
+ (-ifld-parse-follows): New proc.
+ (-multi-ifield-make-default-insert): New proc.
+ (-multi-ifield-make-default-extract): New proc.
+ (-multi-ifield-parse): Provide default values for insert,extract
+ handlers if not specified.
+ (<derived-ifield>): New class.
+ (derived-ifield?): New predicate.
+ (ifld-derived-operand?): New predicate.
+ (f-anyof): New global.
+ (ifld-anyof?,ifld-anyof-operand?): New predicates.
+ (f-derived,ifld-derived?): Delete.
+ (ifield-builtin!): Delete init of f-derived. Init f-anyof.
+ * insn.scm (-sub-insn-ifields): New proc.
+ (-sub-insn-make!): New proc.
+ (multi-insn-instantiate!): Provide initial implementation.
+ (-insn-parse): If insn contains "anyof" operands, create a
+ <multi-insn> object instead of a plain <insn>.
+ (-parse-insn-format-symbol): Rewrite derived operand handling.
+ Add anyof operand handling.
+ (-parse-insn-format-ifield-spec): Rewrite.
+ (-parse-insn-format-operand-spec): Delete.
+ (-parse-insn-format-list): Delete support for `(operand value)'.
+ (anyof-operand-format?): Replaces derived-operand-format?.
+ * operand.scm (-operand-parse-getter): Improve error messages.
+ (-operand-parse-setter): Ditto.
+ (<derived-operand>): New members args,syntax,base-ifield,encoding,
+ ifield-assertion.
+ (<anyof-operand>): Change baseclass from <derived-operand> to
+ <operand>. Delete member values. New members base-ifield,choices.
+ (anyof-operand?): New predicate.
+ (-derived-parse-encoding,-derived-parse-ifield-assertion): New procs.
+ (-derived-operand-parse): Rewrite.
+ (-derived-operand-read): Rewrite.
+ (-anyof-parse-choice): New proc.
+ (-anyof-operand-parse): Rewrite.
+ (-anyof-operand-read,define-anyof-operand): New procs.
+ (<anyof-value>): Rewrite.
+ (-anyof-initial-known): New proc.
+ (anyof-satisfies-assertions?): New proc.
+ (-anyof-merge-syntax,-anyof-merge-encoding): New procs.
+ (-anyof-merge-getter,-anyof-merge-setter): New procs.
+ (-anyof-merge-semantics,-anyof-merge-ifield-assertion): New procs.
+ (-anyof-merge-subchoices,-anyof-all-subchoices): New procs.
+ (-anyof-value-from-derived): New proc.
+ (-anyof-all-choices-1,anyof-all-choices): New procs.
+ (operand-init!): Create define-anyof-operand reader command.
+
+ * insn (syntax-break-out): Take syntax as argument instead of insn.
+ All callers updated.
+ (syntax-make): Move here, from ???.
+
+ * types.scm (<bitrange>): Rename accessors from bitrange:foo to
+ bitrange-foo. All uses updated.
+ (bitrange-next-word): New proc.
+
+ * semantics.scm (-solve-expr-fn,rtx-solve): New procs.
+
+ * rtl.scm (rtx-canonicalize): Provide initial implementation.
+ (rtx-make-const,rtx-make-enum): New procs.
+ (rtx-arg1,rtx-arg2): Renamed from -rtx-arg[12]. All callers updated.
+ (rtx-mem-addr,rtx-mem-sel): New procs.
+ (rtx-change-address): New proc.
+ (rtx-make-ifield,rtx-make-operand,rtx-make-local): New proc.
+ (rtx-make-set,rtx-single-set?): New procs.
+ (rtx-combine): New proc.
+
+ * rtl.scm (rtx-traverse): New arg `appstuff'. All callers updated.
+ (rtx-traverse-with-locals): Ditto.
+ (-rtx-traverse,-rtx-traverse-*): Ditto.
+
+ * rtl.scm (define-subr): New proc.
+ (rtl-init!): Create reader command `define-subr'.
+
+ * cos.c (_object_mi_p): Ensure argument is an object.
+ (indent): New function.
+ (_object_print_elms): Add pretty-printing support.
+ (_object_print): Ditto.
+
+ * hobbit.scm (*reckless-s->c-fun-table*): Add fastcall7.
+ (*floats-s->c-fun-table*): Ditto.
+ * hobbit.c,hobbit.h: Rebuild.
+ * hob-sup.c (fastcall7): New proc.
+ * hob-sup.h (fastcall7): Declare.
+ * hob-sup.scm (fastcall7): New macro.
+
+ * mach.scm (<arch>): New member subr-list.
+ (current-subr-list,current-subr-add!,current-subr-lookup): New procs.
+ (arch-finish!): Reverse recorded subr list.
+
+ * read.scm (debug-env): New global.
+ (debug-var-names,debug-var,debug-repl-env): New procs.
+ (debug-repl): Rewrite. New arg `env-list'. All callers updated.
+ (debug-quit): Renamed from `continue'.
+
+ * simplify.inc (dsmf): New pmacro.
+
+ * utils.scm (plus-scan): New proc.
+ (split-bits): Rewrite.
+ (split-value): New proc.
+
+1999-10-13 Doug Evans <devans@casey.cygnus.com>
+
+ * doc/Makefile.am (DOCFILES): Add notes.texi.
+ * doc/Makefile.in: Rebuild.
+
+1999-10-11 Doug Evans <devans@casey.cygnus.com>
+
+ * ifield.scm (ifld-derived?): New proc.
+ (f-derived): New global.
+ (ifield-builtin!): Create ifield f-derived.
+ (<multi-insn>): New class.
+ (multi-insn?): New predicate.
+ (multi-insn-instantiate!): New proc.
+ (-insn-parse): Create <multi-insn> objects for insns with derived
+ ifields.
+ (-parse-insn-format-symbol): Handle derived ifields.
+ (-parse-insn-format-ifield-spec): New proc.
+ (-parse-insn-format-operand-spec): New proc.
+ (-parse-insn-format-list): Simplify.
+ (-parse-insn-format): No longer allow (ifield-object value) spec.
+ (derived-operand-format?): New proc.
+ (insn-alias?): New proc.
+ (non-alias-insns): Rewrite.
+ (insn-real?): Renamed from real-insn?, all callers updated.
+ (virutal-insns): Rewrite.
+ (multi-insns): New proc.
+ * mach.scm (arch-analyze-insns!): Instantiate multi-insns if present.
+ * operand.scm (op-ifield): Renamed from op:ifield, all callers updated.
+ Return #f if operand doesn't have an index or if index is not an
+ ifield.
+ (hw-index-anyof): New proc.
+ (-operand-parse): Allow integer indices.
+ (<derived-operand>): New class.
+ (derived-operand?): New predicate.
+ (<anyof-operand>): New class.
+ (<anyof-value>): New class.
+ (-anyof-parse-value,-anyof-operand-parse): New procs.
+ (-derived-operand-parse,-derived-operand-read): New procs.
+ (define-derived-operand,define-full-derived-operand): New procs.
+ (operand-init!): New reader command define-derived-operand.
+
+ * utils.scm (list-take): Handle negative amount.
+ (element?): Rewrite.
+
+1999-10-10 Doug Evans <devans@casey.cygnus.com>
+
+ * dev.scm: quick-utils.scm renamed to ~/.cgenrc.
+
+1999-10-04 Richard Henderson <rth@cygnus.com>
+
+ * ia64.cpu: Checkpoint.
+
+1999-09-29 Doug Evans <devans@casey.cygnus.com>
+
+ * sim-cpu.scm (-gen-semantic-fn-table): Virtual insns are always valid.
+
+ * sim.scm (sim-finish!,x-invalid): Always set pc. Set vpc based on
+ default-insn-bitsize. Pass vpc to sim_engine_invalid_insn.
+
+Wed Sep 29 14:39:39 1999 Dave Brolley <brolley@cygnus.com>
+
+ * sim.scm (sim-finish!): Don't call sim_io_error for invalid insn. Use
+ PC returned by sim_engine_invalid_insn.
+
+1999-09-28 Doug Evans <devans@casey.cygnus.com>
+
+ * ia32.cpu: New file.
+
+1999-09-25 Doug Evans <devans@casey.cygnus.com>
+
+ * utils.scm (bit-set?): Fix off by one error.
+
+ * rtl-c.scm (s-sequence): Fix non-void-mode result output.
+
+ * rtl.scm (hw): Check for valid hardware element before trying to
+ get its mode.
+
+ * arm.cpu (arm7f cpu): Renamed from arm. All users updated.
+ * arm7.cpu (bx): Fix name of target address operand in assembler spec.
+ (*): arm_compute_operand2_foo renamed to compute_operand2_foo.
+ * thumb.cpu (*): arm_compute_operand2_foo renamed to
+ compute_operand2_foo.
+
+
+ * rtl-c.scm (<rtl-c-eval-state>): New member output-language.
+ (estate-output-language-c?,estate-output-language-c++?): New procs.
+ (<rtl-c-eval-state>,vmake!): Handle #:output-language.
+ (estate-make-for-normal-rtl-c++): New proc.
+ (rtl-c++-parsed,rtl-c++): New proc.
+ (s-c-call): Invoke cpu class method if c++.
+ (join): Use s-c-raw-call.
+
+ * rtl-c.scm (subword): Don't pass current_cpu to SUBWORD.
+ (nop): Rewrite.
+
+ * rtl-c.scm (delay): Mark the sequence as #:delay'd.
+ * rtl.scm (<eval-state>): New member `modifiers'.
+ (<eval-state>,vmake!): Handle #:modifiers.
+ (estate-with-modifiers): New proc.
+
+ * rtl.scm (rtx-side-effects?): New proc.
+ (rtx-canonical-bool): Don't change expr if it has side effects.
+ * semantics.scm (-simplify-expr-fn): Handle exprs with side-effects
+ better.
+
+1999-09-23 Doug Evans <devans@casey.cygnus.com>
+
+ * sim.scm (gen-scache-type): Fix typo in last patch.
+
+Tue Sep 21 17:12:55 1999 Dave Brolley <brolley@cygnus.com>
+
+ * sim.scm (gen-scache-type): Add last_insn_p flag for parallel support.
+
+1999-09-05 Doug Evans <devans@casey.cygnus.com>
+
+
+ * decode.scm (decode-build-table): Delete args startbit,index-list.
+ All callers updated.
+ * utils-sim.scm (gen-decoder): Delete args startbit,index-list.
+ All callers updated.
+ * sim-decode.scm (-gen-decode-fn): Always pass 0 for startbit
+ to decode-get-best-bits.
+
+ * hardware.scm (hw-bits): New proc.
+ (-hw-parse): New arg layout. All callers updated.
+ (define-full-hardware): New arg layout. All callers updated.
+ (-hw-validate-layout): New proc.
+ (-hw-create-[gs]etter-from-layout): New procs.
+ (<hw-register>,parse!): Handle layout spec.
+ * types.scm (type-bits): New proc.
+
+ * sem-frags.scm (-frag-cost-compute!): Fix calculation of
+ UNARY, BINARY, TRINARY rtxs.
+
+ * attr.scm (<enum-attribute>,parse-value): Allow strings.
+ * enum.scm (parse-enum-vals): Use reverse! instead of reverse.
+ Support '- as "unused spot" indicator.
+
+1999-09-03 Doug Evans <devans@casey.cygnus.com>
+
+ * pgmr-tools.scm (pgmr-pretty-print-insn-format): Fix typo.
+
+1999-09-02 Doug Evans <devans@casey.cygnus.com>
+
+ * rtx-funcs.scm (subword): Fix mode spec of `value'.
+
+ * rtl.scm (-rtx-traverse-operands): Fix debugging message
+ construction.
+ (tstate-make): New arg `depth'. All callers updated.
+ (tstate-depth,tstate-set-depth!): New procs.
+ (tstate-incr-depth!,tstate-decr-depth!): New procs.
+ (-rtx-traverse-operands): Indent debugging output by traversal depth.
+ (-rtx-traverse): Ditto. Keep track of traversal depth.
+
+1999-09-01 Doug Evans <devans@casey.cygnus.com>
+
+ * sim-decode.scm (-gen-decoder+supporting cast): Move to utils-sim.scm.
+ * utils-sim.scm: Decoder generator support moved here.
+ (-decode-equiv-entries?,-decode-sort-entries): New procs.
+ (-gen-decoder-switch): Sort entries for more fall-throughs.
+
+ * Makefile.am (gas-test,sim-test): Specify ISA when invoking cgen.
+ * Makefile.in: Rebuild.
+ * sim-test.scm (build-sim-testcase): Add logging message.
+ * dev.scm (cload): Recognize SIM-TEST application.
+ (load-stest): Set APPLICATION to SIM-TEST.
+
+ * desc-cpu.scm (-gen-hash-defines): Add \n to output.
+
+ * ifield.scm (-ifield-parse): Allow bit numbers up to 127.
+ * mach.scm (-isa-parse): Allow insn bitsizes from 8 to 128.
+ * mode.scm (mode-make-int,mode-make-uint): Allow values up to 64 bits.
+
+ * insn.scm (syntax-break-out): Handle ${foo}.
+
+Sun Aug 29 11:11:15 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * Makefile.am (noinst_PROGRAMS,noinst_LIBRARIES): Delete.
+ (bin_PROGRAMS): Define.
+ (CGEN_HOB_INPUT_FILES): Remove $(srcdir)/.
+ (cgen-hob.c): Prepend $(srcdir)/ here.
+ (APPDESCFILES,OPCODESFILES,SIMFILES,pkgdata_SCRIPTS): Define.
+ (libcpu_a_SOURCES): Delete.
+ (cgen_DEPENDENCIES,cgen_LDADD): Rewrite.
+ (CGEN_HOB_OBJ,CGENOBJS): New variables.
+ * configure.in (LIBS): Replace -Wl,-rpath with -R.
+ Add AC_CHECK_LIB(guile,main).
+ * Makefile.in: Rebuild.
+ * doc/Makefile.in: Rebuild.
+ * aclocal.m4: Rebuild.
+ * config.in: Rebuild.
+ * configure: Rebuild.
+
+1999-08-28 Doug Evans <devans@casey.cygnus.com>
+
+ Rename rtx functions from name: to name, accept optional leading
+ modifier and mode.
+ VM -> VOID, DM -> DFLT, use DFLT instead of VM for default mode.
+ * attr.scm (-attr-eval): Update.
+ * hardware.scm (hw-mode-ok?): Rename arg mode to new-mode-name.
+ (<hw-register>,mode-ok?): Disallow VOID.
+ (<hw-immediate>,mode-ok?): Disallow VOID.
+ (<hw-address>,mode-ok?): Disallow VOID.
+ * mode.scm (mode-name?): New proc.
+ (VOID): Renamed from VM.
+ (DFLT): Renamed from DM.
+ (mode-builtin!): Update.
+ * opcodes.scm (<ifield>,gen-insert): Update.
+ (<ifield>,gen-extract): Update.
+ (<multi-ifield>,gen-insert,gen-extract): Update.
+ * operand.scm (op:mode): Update.
+ (<pc>,make!): Update.
+ (op:new-mode): Update.
+ (-operand-read): Update.
+ * rtl.scm (-rtx-valid-types): Add OPTIONS, EXPLNUMMODE,
+ NONVOIDMODE, DFLTMODE. Rename VMMODE to VOIDMODE.
+ (def-rtx-dual-mode,define-rtx-dual-mode): Delete.
+ (-rtx-lazy-sem-mode): Renamed from -rtx-mode. All callers updated.
+ (rtx-make): Call -rtx-munge-mode&options.
+ (rtx accessors): Rewrite.
+ (rtx-pretty-name): Update.
+ (-rtx-traverse-*): Update.
+ (-rtx-traverse-explnummode,-rtx-traverse-nonvoidmode): New procs.
+ (-rtx-traverse-voidmode,-rtx-traverse-dfltmode): New procs.
+ (-rtx-make-traverse-table): Update.
+ (-rtx-traverse-operands): Update.
+ (-rtx-option?,-rtx-option-list?): New procs.
+ (-rtx-munge-mode&options): New proc.
+ (-rtx-traverse-expr): Call -rtx-munge-mode&options.
+ (-rtx-traverse): Update.
+ (rtx-traverse,rtx-traverse-with-locals,rtx-compile): Update.
+ (rtx-compile-time-constant?): Update.
+ (rtx-true?,rtx-false?,rtx-true,rtx-false): Update.
+ (rtx-value): Update.
+ (hw,reg,mem): Renamed from foo:. Update. All callers updated.
+ * rtx-funcs.scm (*): Update.
+ * rtl-c.scm (rtl-c-get): Update.
+ (rtl-c-set-quiet,rtl-c-set-trace): Update.
+ (s-c-call,s-c-raw-call): Update.
+ (s-boolifop,s-convop,s-if,s-cond): Update.
+ (s-case-vm,-gen-non-vm-case-test,s-case): Update.
+ (-par-replace-set-dests,-par-replace-set-srcs): Update.
+ (s-parallel,s-sequence): Update.
+ (rtl-c-build-table): Update.
+ * sem-frags.scm (-frag-hash-compute!): Update.
+ (-frag-cost-compute!): Improperly handle unary,binary,trinary ops
+ for temporary bug compatibility with previous version.
+ (-frag-expr-locals,-frag-expr-stmts): Update.
+ (-frag-compute-desired-frags,-frag-pick-best): Update.
+ * semantics.scm (-simplify-expr-fn): Update.
+ (rtx-simplify): Update.
+ (-rtx-ref-type): Update. Account for modifiers.
+ (-build-operand!,-build-reg-operand!,-build-mem-operand!): Update.
+ (-build-ifield-operand!): Update.
+ (-build-known-values): Update.
+ (semantic-compile): Update.
+ (-gen-reg-access-defns): Update.
+ (gen-semantic-code,-gen-sem-case): Update.
+ (-gen-sfrag-code,-gen-sfrag-case): Update.
+ * sim-cpu (gen-semantic-code): Update.
+ * sim.scm (<hw-pc>,gen-write,cxmake-skip): Update.
+ (<hw-register>,gen-write,gen-set-macro,cxmake-get-raw): Update.
+ (-hw-cxmake-get): Update.
+ (<hw-memory>,cxmake-get,gen-set-quiet,gen-write): Update.
+ (<hw-index>,cxmake-get): Update.
+ (<operand>,gen-type,gen-read,cxmake-get): Update.
+ (<operand>,gen-set-quiet,gen-set-trace): Update.
+ (<pc>,cxmake-get): Update.
+ (sim-finish!): Update.
+ * utils-gen.scm (-gen-ifld-extract-base): Update.
+ (-gen-ifld-extract-beyond): Update.
+ (gen-multi-ifld-extract): Update.
+ * *.cpu: Update.
+ * simplify.inc: Update.
+
+1999-08-20 Doug Evans <devans@casey.cygnus.com>
+
+ * sim.scm (-op-gen-queued-write): Fix memory address calculation.
+ Prefix queue function name with sim_ instead of @cpu@_.
+
+ * sim.scm (-with-parallel-only?): New global.
+ (option-init!): Initialize it.
+ (option-set!): Set it.
+ (with-parallel-only?): New proc.
+ * sim-decode.scm (-gen-decode-insn-globals): Don't include parallel
+ and writeback markers if with-parallel-only.
+ (-gen-idesc-init-fn): Update.
+ * sim-cpu.scm (cgen-cpu.h): Don't generate struct parexec if
+ with-generic-write.
+
+Wed Aug 18 15:04:30 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * sim-cpu.scm (-gen-semantic-fn-table): Handle unsupported insns
+ with the invalid insn handler.
+
+ * utils.scm (list-maybe-ref): New proc.
+
+ * mach.scm (-isa-parse): Signal error if isa wasn't specified in
+ define-arch.
+ (-mach-parse): Signal error if mach wasn't specified in define-arch.
+
+ * i960.cpu (test*-*): Delete `expr' arg.
+ (test-op,branch-op): Update.
+
+1999-08-09 Doug Evans <devans@casey.cygnus.com>
+
+ * sim.scm (gen-reg-getter-fn,gen-reg-setter-fn): New procs.
+ (gen-reg-access-decl): Replace `name' arg with `hw'. All callers
+ updated.
+ (gen-reg-access-defn): Ditto.
+ (-gen-hw-addr): Rewrite.
+ (-op-gen-queued-write): Rewrite.
+ * sim-cpu.scm (-gen-cpu-reg-access-decls):
+ (-gen-scache-semantic-fn): Handle with-generic-write.
+ (-gen-no-scache-semantic-fn): Ditto.
+
+1999-08-08 Doug Evans <devans@casey.cygnus.com>
+
+ * utils-gen.scm (gen-define-ifmt-ifields): Tweak output.
+
+ * sim.scm (-with-generic-write?): New global.
+ (option-init!): Initialize it.
+ (option-set!): Set it.
+ (with-generic-write?): New proc.
+ (-gen-hw-addr): New proc.
+ (-op-gen-queued-write): New proc.
+ (-op-gen-set-{quiet,trace}-parallel): Use it if with-generic-write?.
+
+ * sim-cpu.scm (-gen-hardware-types): Output code with parallel support
+ turned off.
+ (-gen-sem-switch): Preserve existing with-parallel? value.
+ (-gen-sem-parallel-switch): Ditto.
+ (-gen-write-case): Add /indent support.
+ (cgen-write.c): Rewrite.
+
+ * utils.scm (-current-print-state): New global.
+ (make-print-state): New proc.
+ (pstate-indent,pstate-set-indent!): New procs.
+ (pstate-cmd?,pstate-cmd-do): New procs.
+ (/indent): New global.
+ (/indent-set,/indent-add): New procs.
+ (string-write): Set -current-print-state.
+ (-string-write): New arg pstate, all callers updated.
+ Handle print-state commands.
+ (-string-list-flatten): New proc.
+ (string-list->string): Use it.
+
+ * sim-cpu.scm (-gen-sem-fn-name): Move here from sim-decode.scm.
+ (-gen-sem-fn-table-entry): New proc.
+ (-gen-semantic-fn-table): New proc.
+ (-gen-scache-semantic-fn): Make fn static.
+ (-gen-no-scache-semantic-fn): Ditto.
+ (cgen-semantics.c): Define macro SEM_FN_NAME.
+ * sim-decode.scm (-gen-decode-insn-globals): Delete FMT,TYPE,IDX,
+ FAST,FULL. Update @cpu@_insn_sem contents.
+ (-gen-semf-fn-name): Delete.
+ (-gen-sem-fn-decls): Delete.
+ (-gen-idesc-decls): Output prototypes of @cpu@_sem_init_idesc_table,
+ @cpu@_semf_init_idesc_table.
+ (-gen-idesc-init-fn): Update. Don't initialize pointers to semantic
+ handlers here.
+ (cgen-decode.h): Print sfmt enum.
+ * utils-gen.scm (gen-sfmt-enum-decl): New proc.
+
+ * iformat.scm (sfmt-build): Rename sformats from fmt-foo to sfmt-foo.
+ (ifmt-compute!): Ditto.
+ * sim-decode.scm (-gen-decoder-switch): Ditto.
+
+ * insn.scm (insn-virtual?): New proc.
+
+ * enum.scm (gen-enum-decl): Speed up, build string as list and then
+ convert to string.
+ * mach.scm (<arch>): attr-list is now a pair of lists.
+ (current-attr-list): Rewrite.
+ (current-attr-add!,current-attr-lookup): Rewrite.
+ * sim.scm (gen-cpu-insn-enum-decl): Replace append with append!.
+
+1999-08-06 Richard Henderson <rth@cygnus.com>
+
+ * ia64.cpu: Initial checkpoint.
+
+1999-08-06 Doug Evans <devans@casey.cygnus.com>
+
+ * pmacros.scm (-pmacro-apply): Fix definition, takes only 1 arg.
+ (pmacros-init!): Update .apply help string.
+
+1999-08-03 Doug Evans <devans@casey.cygnus.com>
+
+ * sim.scm (-hw-gen-set-quiet-pc): Update call to SEM_BRANCH_VIA_CACHE.
+ (<hw-pc>,cxmake-skip): New method.
+ (<pc>,cxmake-skip): New method.
+ (-gen-argbuf-fields-union): Add branch_target to `chain' member.
+ (gen-argbuf-type): New member `skip_count'.
+ (sim-finish!): Update calls to @cpu@_pbb_cti_chain.
+ * utils-cgen.scm (atlist-cti?): Don't include SKIP-CTI insns.
+
+ * utils-sim.scm: New file.
+ * dev.scm (load-sim): Load it.
+ (load-sid): Load it.
+ * cgen-sid.scm: Load it.
+ * cgen-sim.scm: Load it.
+ * iformat.scm (<sformat>): New member sbuf, not initialized by
+ default make.
+ * rtx-funcs.scm (skip): Rewrite.
+ * rtl-c.scm (skip): Rewrite.
+ * m32r.cpu (sc,snc): Update `skip' usage.
+ * mode.scm (mode-real-mode): New proc.
+ * sem-frags.scm (-frag-split-by-sbuf): Rename from -frag-split-by-sfmt.
+ Distinguish fragments by the <sformat-abuf> they use.
+ * sim.scm (gen-profile-index-type): Delete.
+ (ifield argbuf support): Move to utils-sim.scm and sim-decode.scm.
+ (-gen-ifld-decoded-val): Delete, use gen-extracted-ifld-value instead.
+ (hardware argbuf support): Move to utils-sim.scm and sim-decode.scm.
+ (operand argbuf support): Move to utils-sim.scm and sim-decode.scm.
+ (-gen-argbuf-elm): Rewrite.
+ (-gen-argbuf-hw-elm): Delete.
+ (-gen-argbuf-fields-union): Generate structs for each sbuf instead
+ of each sfmt.
+ (-sim-sformat-argbuf-list,-sim-insns-analyzed?): New globals.
+ (sim-init!): Initialize them.
+ (sim-analyze-insns!): Set them.
+ (current-sbuf-list): New proc.
+ * sim-cpu.scm (-gen-no-scache-semantic-fn): Update calls to
+ gen-sfmt-op-argbuf-defns,gen-sfmt-op-argbuf-assigns.
+ * sim-model.scm (-gen-model-insn-fn): Ditto.
+ * sim-decode.scm (-gen-extract-decls): Delete.
+ (-gen-record-argbuf-ifld,-gen-trace-argbuf-ifld): New procs.
+ (<hardware-base>,gen-extract,gen-trace-extract): Move here from
+ sim.scm.
+ (<hw-register,gen-extract,gen-trace-extract): Ditto.
+ (<hw-address,gen-extract,gen-trace-extract): Ditto.
+ (-gen-op-extract,-gen-op-trace-extract): New procs.
+ (gen-sfmt-op-argbuf-defns,gen-sfmt-op-argbuf-assigns): Rename from
+ gen-sfmt-argvars-foo and rewrite.
+ (-gen-record-args): Rewrite.
+ (-gen-extract-case): Tweak.
+
+ * cgen-gh.c (gh_putc,gh_puts): New functions.
+ * cgen-gh.h (gh_putc,gh_puts): Declare them.
+ * cos.c (_object_print_elms,_object_print): Use them.
+ * hob-sup.c (fastcall_print): Use them.
+ * configure.in: Check for scm_gen_puts, scm_puts.
+ * config.in: Rebuild.
+ * configure: Rebuild.
+ * aclocal.m4: Rebuild.
+ * Makefile.in: Rebuild.
+
+ * dev.scm (load-opc): Use load instead of maybe-load.
+ (load-gtest,load-sim,load-stest): Ditto.
+ (load-sid): Ditto.
+
+1999-07-23 Doug Evans <devans@casey.cygnus.com>
+
+
+1999-07-22 Doug Evans <devans@casey.cygnus.com>
+
+ * cos.c (cos_init): Protect _make_x_symbol from garbage collection.
+
+ * read.scm: Load sem-frags.scm.
+ * sem-frags.scm (*): Lots rewritten.
+ * arm.cpu (arm isa): Enable decode-splits.
+ * arm7.cpu (multiply insns): Rename result to mul-result.
+
+ Rename decode-specialize to decode-split.
+ * decode.scm (*): Update.
+ * insn.scm (*): Update.
+ * mach.scm (*): Update.
+
+1999-07-19 Doug Evans <devans@casey.cygnus.com>
+
+ Record objects as a smob.
+ * cos.c (scm_tc16_object): New static global.
+ (cos_init): Initialize it.
+ (OBJECT_P,OBJECT_ELEMENTS,OBJECT_CLASS_DESC): Update macros.
+ (OBJECT_CLASS,OBJECT_ELEMENT_OFFSET): Update.
+ (_object_tag): Delete.
+ (_object_make_smob): New function.
+ (_object_make_x,_object_make_with_values_x): Rewrite.
+ (_object_elements,_object_class_desc): Rewrite.
+ (_object_copy,object_p): Rewrite.
+ (_object_specialize): Rewrite.
+ (_object_print_elms,_object_print): New functions.
+ (object_smob): New static global.
+ (default_make_x): Use OBJECT_ELEMENT_OFFSET instead of magic number.
+
+ * cos.c (_make_x_symbol): New static global.
+ (object_make): Use it.
+ (cos_init): Initialize it.
+
+1999-07-16 Doug Evans <devans@casey.cygnus.com>
+
+ * frv.opc (CGEN_DIS_HASH_SIZE): Change to 128.
+ (CGEN_DIS_HASH): Hash on f-op ifield value.
+
+1999-07-15 Doug Evans <devans@casey.cygnus.com>
+
+ * rtl-c.scm (ifield): Back out last patch, use estate-ifield-var?
+ instead to determine whether to use FLD macro.
+ (<rtl-c-eval-state>): New member ifield-var?.
+ (<rtl-c-eval-state>,vmake!): Recognize #:ifield-var?.
+ * utils-gen.scm (-gen-ifld-extract-base): Specify #:ifield-var? #f.
+ (-gen-ifld-extract-beyond,gen-multi-ifld-extract): Ditto.
+
+ * rtl.scm (rtx-sequence-assq-locals): New proc.
+
+ * cos.scm (-object-error): Don't crash on non-objects.
+
+ * Makefile.am (CLEANFILES): Add hobbit.
+ * Makefile.in: Rebuild.
+
+ * rtl-c.scm (s-c-call): Delete unnecessary code.
+
+1999-07-14 Doug Evans <devans@casey.cygnus.com>
+
+ * rtl-c.scm (ifield): Always reference value via `FLD'.
+
+ * cos.c (elm_bound_p): Return problem SCM boolean values.
+
+ * utils-cgen.scm (display-argv): New proc.
+ * cgen-opc.scm (cgen): Call it.
+ * cgen-sim.scm (cgen): Ditto.
+ * cgen-gas.scm (cgen): Ditto.
+ * cgen-stest.scm (cgen): Ditto.
+
+1999-07-05 Doug Evans <devans@casey.cygnus.com>
+
+ * opc-asmdis.scm (-gen-parse-switch): New local var `junk'.
+ * opc-ibld.scm (-gen-insert-switch): Initialize result to NULL.
+ (-gen-extract-switch): Initialize result to 1.
+ * opcodes.scm (gen-ifield-default-type): New proc.
+ (gen-ifield-value-decl): Renamed from gen-ifield-type. All callers
+ updated.
+ (<hw-index>,gen-insert): Handle non-ifield indices.
+ (<hw-index>,gen-extract): Ditto.
+ (<hw-asm>,gen-parse): Ditto.
+ (<hw-asm>,gen-print): Ditto.
+ (<keyword>,gen-parse): Ditto.
+ (<keyword>,gen-print): Ditto.
+ (<operand>,gen-fget): Ditto.
+ (<operand>,gen-fset): Ditto.
+
+ * sim.scm (-gen-hw-index-raw): Handle scalar indices.
+ (-gen-hw-index): Ditto.
+
+ * sem-frags.scm: New file.
+
+ * attr.scm (attr-parse): Add better checking of input.
+
+ * hardware.scm (-hw-parse-getter): Renamed from -hw-parse-get.
+ All uses updated.
+ (-hw-parse-setter): Renamed from -hw-parse-set. All uses updated.
+
+ * ifield.scm (ifld-nil?): New proc.
+
+ * operand.scm (<operand>): New members getter,setter.
+ (<operand>,make!): New args getter,setter. All uses updated.
+ (op:getter,op:setter): New procs.
+ (<hw-index>,field-start): Return 0 for non-ifield indices.
+ (<hw-index>,field-length): Return 0 for non-ifield indices.
+ (-operand-parse-getter,-operand-parse-setter): New procs.
+ (-operand-parse): New args getter,setter. All callers updated.
+ Always use hw-index-scalar for scalar operands.
+ (-operand-read): Handle getter,setter.
+ (define-full-operand): New args getter,setter. All uses updated.
+ * semantics.scm (-build-ifield-operand!): Update.
+ (-build-index-of-operand!): Update.
+ * sim.scm (<operand>,cxmake-get): If operand has getter, use it.
+ * simplify.inc (define-normal-operand): Update.
+
+ * rtl.scm (abs,sqrt,cos,sin,min,max,umin,umax): New rtx fns.
+ * rtl-c.scm (s-unop): Indirect fp ops through fpu op vector.
+ (s-binop,s-cmpop,s-convop): Ditto.
+ (abs,sqrt,cos,sin,min,max,umin,umax): New rtx fns.
+ * sparc.cpu (insn-fmt2): Add FPOPS1,FPOPS2.
+ (fcc-tests): New insn-enum.
+ (fcc-value): Rename from fcc-type.
+ * sparcfpu.cpu: New file. All fp support moved here.
+
+ * rtl.scm (<rtx-func>): New member class.
+ (rtx-class-*?): New procs.
+ (def-rtx-node): New arg class. All callers updated.
+ (def-rtx-syntax-node,def-rtx-operand-node,def-rtx-dual-node): Ditto.
+ * rtx-funcs.scm (*): Specify class.
+
+ * utils-cgen.scm (context-make-reader): New proc.
+
+ * utils.scm (assert-fail-msg): New variable.
+ (assert): Use it.
+ (list-drop,list-tail-drop): New procs.
+
+1999-06-22 Doug Evans <devans@casey.cygnus.com>
+
+ * desc-cpu.scm (-gen-hash-defines): Restore generation of
+ CGEN_MIN_INSN_SIZE deleted on March 22.
+
+ * ifield.scm (<ifield>,needed-iflds): New method.
+ (<multi-ifield>,needed-iflds): New method.
+ (ifld-needed-iflds): New proc.
+ (multi-ifield?): New proc.
+ * iformat.scm (<sfmt>): Delete member ifmt. New members length,iflds.
+ (-sfmt-search-key): Include insn length in key.
+ (-sfmt-order-iflds,-sfmt-used-iflds): New procs.
+ (<fmt-desc>): Delete members ifmt-key,sfmt-key. New member used-iflds.
+ (-ifmt-lookup-ifmt!): Compute key here.
+ (-ifmt-lookup-sfmt!): Compute key here. Delete arg ifmt.
+ All callers updated.
+ (ifmt-build): Delete arg desc. New args search-key,iflds.
+ All callers updated.
+ (sfmt-build): Delete args desc,ifmt. New args search-key,cti?,
+ in-ops,out-ops,sorted-used-iflds. All callers updated.
+ * minsn.scm (minsn-make-alias): Use insn-set-ifmt!. Update call
+ to ifmt-build.
+ * operand.scm (op-iflds-used): New proc.
+ * utils-gen.scm (gen-ifld-type): Move here from sim.scm
+ and sim-cpu.scm.
+ (gen-ifld-extract-decl,-gen-ifld-extract-base): Ditto.
+ (-gen-extract-word,-gen-ifld-extract-beyond): Ditto.
+ (gen-ifld-extract,gen-multi-ifld-extract): Ditto.
+ (gen-extracted-ifld-value): Ditto.
+ (-extract-chunk-specs): Ditto.
+ (gen-define-ifields,gen-define-ifmt-ifields): Ditto.
+ (-extract-chunk,-gen-extract-beyond-var-list): Ditto.
+ (gen-extract-ifields,gen-extract-ifmt-ifields): Ditto.
+ (-extract-insert-subfields): New function.
+ * sim.scm (gen-record-argbuf-ifld): Renamed from gen-ifld-extract.
+ (gen-record-argvar-ifld): Renamed from gen-ifld-extract-argvar.
+ * sim-cpu.scm (-gen-extract-ifmt-macro): Replace calls to
+ gen-define-ifields with gen-define-ifmt-ifields. Ditto for
+ gen-extract-foo.
+ (-gen-no-scache-semantic-fn): Ditto.
+ (-gen-sem-case): Ditto.
+ (-gen-read-case): Update calls to gen-define-ifields,
+ gen-extract-ifields.
+ * sim-decode.scm (-gen-record-args): Update.
+ (-gen-sfmt-argvars-assigns): Update.
+ (-gen-extract-case): Update.
+ * sim-model.scm (-gen-model-insn-fn): Replace calls to
+ gen-define-ifields with gen-define-ifmt-ifields. Ditto for
+ gen-extract-foo.
+
+1999-06-18 Doug Evans <devans@casey.cygnus.com>
+
+
+ * rtl.scm (-rtx-traverse): Output symbol shortcuts in source form,
+ (operand name) not (operand object), (local name) not (local object).
+ (rtx-traverse-with-locals): New proc.
+ (-compile-expr-fn): New proc.
+ (rtx-compile): Rewrite.
+ * rtl-c.scm (rtl-c-get): Handle operand/local names for src arg.
+ (rtl-c-set-quiet): Don't accept operand/local names for dest arg.
+ (rtl-c-set-trace): Ditto.
+ (operand define-fn): Recognize operand name argument.
+ (local define-fn): Recognize sequence temp name argument.
+ * rtx-funcs.scm (operand): Argument is operand name, not object,
+ so call current-op-lookup.
+ (local): Similarily, so call rtx-temp-lookup.
+
+ * rtl.scm (rtx-field?): Use rtx-name instead of car.
+ (rtx-operand?): Ditto.
+ (rtx-pretty-name): Ditto.
+ (rtx-local-obj): Flag symbol argument as an error.
+ (rtx-local-name): New proc.
+ (rtx-sequence-locals,rtx-sequence-exprs): New procs.
+
+ * rtl.scm (-rtx-traverse-operands): Fix debugging output of arg-types.
+
+ * read.scm (debug-repl): Renamed from -debug-repl. All callers
+ updated.
+
+ * arm7.cpu (do-word/byte-store): Use (trunc: QI rd) rather than
+ (and: QI rd #xff).
+
+ * hobbit.scm (*reckless-s->c-fun-table*): Add fastcall4, fastcall6.
+ (*floats-s->c-fun-table*): Ditto.
+ * hobbit.c,hobbit.h: Rebuild.
+ * rtl.scm (-rtx-traverse-expr): Use fastcall6.
+ * semantics.scm (rtx-simplify): Use /fastcall-make.
+
+ * iformat.scm (-sfmt-search-key): Don't include memory modes.
+
+ * insn.scm (<insn>): Delete members condition, compiled-condition.
+ (<insn>,make!): Update
+ (<insn> getters,setters): Update.
+ (-insn-parse,insn-read,define-full-insn): Update.
+ * minsn.scm (minsn-make-alias): Update.
+ * iformat.scm (ifmt-analyze): Delete insn-condition reference.
+ (ifmt-compute!): Ditto.
+ * sim.scm (sim-finish!): Update.
+ * simplify.inc: (define-normal-insn): Update.
+
+ * iformat.scm (-ifmt-lookup-ifmt!): Use insn-set-ifmt!.
+ (-ifmt-lookup-sfmt!): Use insn-set-sfmt!.
+ (ifmt-compute!): Ditto.
+
+1999-06-16 Doug Evans <devans@casey.cygnus.com>
+
+ * minsn.scm (minsn-compute-iflds): Print better error message for
+ missing ifields.
+
+1999-06-12 Doug Evans <devans@casey.cygnus.com>
+
+ * rtl.scm (tstate->estate): Don't copy over expr-fn.
+
+ * Makefile.am (HOBFLAGS): New variable.
+ (cgen-hob.c): Use it.
+ (hobbit.c): Use it.
+ (libcpu_a_SOURCES): Add hob-sup.c.
+ (hob-sup.o): New rule.
+ * Makefile.in: Rebuild.
+ * cgen.c: #include hob-sup.h.
+ (cgen_init_c): Call hobbit_init_support.
+ * hobbit.scm (*fastcall-make*,*c-symbol*): New variables.
+ (*special-scm->c-functions*): Add them.
+ (display-c-expression): Handle *c-symbol*.
+ (*reckless-s->c-fun-table*): Add *fastcall-make*, fastcall5.
+ (*floats-s->c-fun-table*): Ditto.
+ (normalize): Recognize /fastcall-make.
+ (normalize-fastcall-make): New proc.
+ * hobbit.c,hobbit.h: Rebuild.
+ * hob-sup.scm: New file.
+ * hob-sup.c: New file.
+ * hob-sup.h: New file.
+ * read.scm: Load hob-sup.scm.
+ * rtl.scm (-rtx-name-list): New variable.
+ (rtx-name-list): New proc.
+ (rtx-lookup): Try symbol first.
+ (def-rtx-node): Add name to -rtx-name-list.
+ (def-rtx-syntax-node,def-rtx-operand-node,def-rtx-macro-node): Ditto.
+ (-rtx-traverse-anymode): New proc.
+ (-rtx-traverse-{emode,intmode,floatmode,nummode,vmmode}): New procs.
+ (-rtx-traverse-{rtx,setrtx,testrtx,condrtx,casertx}): New procs.
+ (-rtx-traverse-{locals,env,attrs,symbol,string,number}): New procs.
+ (-rtx-traverse-{symornum,object}): New procs.
+ (-rtx-make-traverse-table): Rewrite.
+ (-rtx-traverse-operands): Rewrite arg-types handling.
+ Handle #f result of traverser.
+ (-rtx-traverse): Renamed from -rtx-traverse-normal.
+ Move debug handling here.
+ (-rtx-traverse-debug): Delete.
+ (rtl-finish!): Change -rtx-traverse-table into list of handlers
+ for each rtx.
+ * semantics.scm (semantic-compile:process-expr!): Fix call to
+ -rtx-traverse.
+ * utils.scm (map1-improper): New proc.
+
+1999-06-08 Doug Evans <devans@casey.cygnus.com>
+
+ * arm.sim (h-tbit): Replace FUN-ACCESS with FUN-SET.
+ (h-mbits): Ditto.
+
+1999-06-07 Doug Evans <devans@casey.cygnus.com>
+
+ * thumb.cpu (dnti): Delete timing spec.
+ (all insn): Update.
+
+ * arm.cpu (arm isa): New fields condition, setup-semantics.
+ (thumb isa): New field setup-semantics.
+ (h-gr): Add attribute CACHE-ADDR.
+ * arm7.cpu (dnai): Delete condition.
+ (eval-cond): Delete.
+
+ * mach.scm (<isa>): New member setup-semantics.
+ (-isa-parse-setup-semantics): New proc.
+ (-isa-parse): New arg setup-semantics.
+ (-isa-read): Recognize setup-semantics.
+
+ * utils-cgen.scm (obj-set-name!): New proc.
+
+ * attr.scm (-attr-eval): Rewrite calls to rtx-simplify/rtx-compile.
+ * iformat.scm (ifmt-analyze): Pass `insn' to semantic-compile,
+ semantic-attrs.
+ (ifmt-compute!): Delete arg `arch'. Result is list of iformats,
+ sformats.
+ * mach.scm (arch-analyze-insns!): Update call to ifmt-compute!.
+ * rtl-c.scm (rtl-c-get): Use DM for default mode instead of VM.
+ Avoid infinite loop when rtx-eval-with-estate leaves expr alone.
+ (attr): Rewrite test for insn owner.
+ (member): New rtx function.
+ * rtl.scm (rtx-* accessors): Define as cxr directly rather than
+ as separate function.
+ (rtx-ifield?,rtx-ifield-name): New procs.
+ (rtx-operand-obj): Rewrite.
+ (rtx-operand-name): New proc.
+ (rtx-cmp-op-mode,rtx-cmp-op-arg): New procs.
+ (rtx-number-list-values,rtx-member-value,rtx-member-set): New procs.
+ (tstate-make): New args owner, known. All callers updated.
+ (tstate-known-lookup): New proc.
+ (rtx-traverse): New arg owner. All callers updated.
+ (rtx-make-bool): New proc.
+ (rtl-find-ifields): Rewrite.
+ (rtx-simplify,rtx-simplify-eq-attr-{insn,mach}): Moved to ...
+ * semantics.scm: ... here.
+ (rtx-const-equal,rtx-const-list-equal): New procs.
+ (-build-known-values): New proc.
+ (semantic-compile): New arg `insn'. Call rtx-simplify.
+ (semantic-attrs): Ditto.
+ * rtx-funcs.scm (member,number-list): New rtx functions.
+
+ * attr.scm (attr-remove-meta-attrs-alist): Delete leading '-' in name.
+ Rewrite. Delete arg `all-attrs'. All callers updated.
+ (attr-remove-meta-attrs): Delete leading '-' in name. All callers
+ updated.
+ * utils-cgen.scm (gen-bool-attrs): Remove meta attrs.
+
+ * decode.scm (subdtable-add): Handle `expr' entries.
+ (exprtable-entry-make): Use vector. Record ifields refered to by expr.
+ (exprtable-entry-*): Update.
+ (exprtable-entry-iflds): New proc.
+ (exprentry-cost): New proc.
+ (exprtable-sort,-gen-exprtable-name): New procs.
+ (exprtable-make): New arg `name'. All callers updated. use vector.
+ (exprtable-*): Update.
+ (-build-decode-table-entry): Don't issue collision warning if all are
+ specialized insns. Sort exprtable entries before building table.
+
+ * read.scm (-reader-process-expanded-1): Move pretty printing of
+ input to logging level 4.
+
+ * utils.scm (string-list->string): New proc.
+
+ * insn.scm (<insn>): Define setters for ifield-assertion, condition,
+ semantics.
+ (insn-read): Delete leading '-' in name. All callers updated.
+ (real-insn?): New proc.
+ (real-insns): Rewrite.
+ (insn-has-ifield?): New proc.
+ (insn-builtin!): Create insn attribute SPECIALIZED.
+
+ * mach.scm (<arch>): Delete member app-data.
+ (current-raw-insn-list): New proc.
+ (insn-list-car,insn-list-splice!): New procs.
+ (<decode-specialize>): New class.
+ (-isa-parse-decode-specialize): New proc.
+ (-isa-parse-decode-specializes): New proc.
+ (<isa>): New members `condition', `decode-specializes'.
+ (-isa-parse-condition): New proc.
+ (-isa-parse): New args condition, decode-specializes.
+ (-isa-read): Recognize condition, decode-specializes.
+ (-isa-add-decode-specialize!): New proc.
+ (modify-isa): New proc.
+ (isa-conditional-exec?,state-conditional-exec?): New procs.
+ (arch-init!): New reader command `modify-isa'.
+
+ * mode.scm (mode-class-signed?,mode-class-unsigned?): New procs.
+ (mode-signed,mode-unsigned?): New procs.
+
+Thu Jun 3 16:00:40 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * types.scm (<array>): New method get-shape.
+ * hardware.scm (<hardware-base>): Forward get-shape,get-num-elms
+ onto type.
+ (hw-shape,hw-num-elms): New procs.
+ * sim.scm (<hw-register>,gen-profile-index-type): Use "unsigned short"
+ if there's more than 255 registers.
+
+ * hardware.scm (-hw-parse): Flag as error CACHE-ADDR specified
+ with get/set specs.
+
+1999-05-10 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu: Remove coprocessor related fields, operands and insn
+ definitions for now. Take the undefined instruction trap instead.
+ (ldmda-wb): New instruction.
+ (ldmib-wb): Likewise.
+ (ldmdb-wb): Likewise.
+ (stmdb-wb): Likewise.
+ (stmib-wb): Likewise.
+ (stmda-wb): Likewise.
+
+1999-05-08 Doug Evans <devans@casey.cygnus.com>
+
+
+ * utils-cgen.scm (keyword-list->arg-list): Fix call to substring,
+ hobbit can't handle optional third arg.
+
+1999-05-07 Doug Evans <devans@casey.cygnus.com>
+
+ * arm.cpu (h-tbit): Delete set spec.
+ (h-mbits): Don't call arm_mbits_set in set spec.
+ * arm.sim: New file.
+ * hardware.scm (modify-hardware): New proc.
+ (hardware-init!): Add modify-hardware command.
+ * utils-cgen.scm (keyword-list?): New proc.
+ (keyword-list->arg-list,arg-list-validate-name): New procs.
+ (arg-list-check-no-args,arg-list-symbol-arg): New procs.
+
+ * arm7.cpu (eval-cond): Pass pc to @cpu@_eval_cond handler.
+
+
+ * attr.scm (obj-prepend-atlist!): New proc.
+
+ * opc-opinst.scm (cgen-opinst.c): Analyze instructions if necessary.
+
+ * sim.scm (<operand>,profilable?): Use op:type.
+
+1999-05-04 Doug Evans <devans@casey.cygnus.com>
+
+ * utils.scm (find-index,find): Be more stack friendly.
+
+ * arm7.cpu (arith-imm-op): Compute pc before setting cpsr.
+ (bic-imm): Ditto.
+
+1999-05-01 Doug Evans <devans@casey.cygnus.com>
+
+ * arm.cpu (h-gr-usr): New hardware element.
+ (h-gr-fiq,h-gr-svc,h-gr-abt,h-gr-irq,h-gr-und): New hardware elements.
+ (arm-mode): New keyword.
+ (h-mbits): Add set spec.
+ (h-spsr): Implement get/set specs.
+
+ * read.scm: Load slib/pp.scm, slib/genwrite.scm.
+ (-reader-process-expanded-1): Pretty print logging output.
+
+
+ * utils-cgen.scm (context-error): Accept variable number of
+ trailing args.
+
+ * rtx-funcs.scm (error:): New rtx function.
+ * rtl-c.scm (s-case-vm): New proc.
+ (-gen-non-vm-case-get,s-case-non-vm): New procs.
+ (s-case): Simplify, handle non-VM result.
+ (error:): New rtx function.
+
+1999-04-30 Doug Evans <devans@casey.cygnus.com>
+
+ * arm.cpu (h-pc): Add set spec to zero bottom bits.
+ (test-hi,test-ls): Fix cbit handling.
+ (shift-type,h-operand2-shifttype): Move here ...
+ * arm7.cpu: ... from here.
+ (set-cond,set-cond-maybe,dnix): Delete, unused.
+ (set-zn-flags,set-logical-cc,set-add-flags,set-sub-flags): Move ...
+ * arm.cpu: ... to here.
+ * thumb.cpu (cmp,alu-cmp): Use set-sub-flags.
+ (alu-cmn): Use set-add-flags.
+ (alu-tst): Use set-zn-flags.
+ (alu-cmp): Use set-sub-flags.
+ (lsl,lsr,asr): Set condition codes.
+ (add,addi,sub,subi,mov,addi8,subi8): Ditto.
+ (alu-op): Split into three: alu-logical-op,alu-arith-op,
+ alu-shift-op.
+ (hireg-op): Split sem-fn into lo-dest-sem-fn,hi-dest-sem-fn.
+ All callers updated.
+ (sub-sp): Rename from add-sp-neg.
+ (f-lbwl-offset): Delete.
+ (f-lbwl-hi,f-lbwl-lo): New ifields.
+ (lbwl-hi,lbwl-lo): Update.
+ (bl-hi): Add 4 to pc.
+ (push-reg,pop-reg): Simplify.
+ (push,push-lr): Push registers in correct order.
+ (pop,pop-pc): Pop registers in correct order.
+ (save-reg-inc,load-reg-inc): Simplify.
+ (ldmia): Save registers in correct order.
+
+1999-04-30 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu (f-op-hdt): Remove; unused.
+ (f-ror-imm8-value,f-ror-imm-rotate): New fields.
+ (f-ror-imm8): New multi-ifield.
+ (f-operand2-bit7): Remove; use the generic `f-bit7' instead. All
+ callers updated.
+ (f-uimm12): New field.
+ (ror-imm8): New operand.
+ (uimm12): Likewise.
+ (hdt-offset8): Reinstate operand.
+ (offset4-hi,offset4-lo): Remove.
+ (set-cond): Remove macro; unused.
+ (set-cond-maybe): Likewise.
+ (load-word/byte): Use uimm12 operand for a true 12-bit immediate.
+ (store-word/byte): Likewise.
+ (load-halfword): Use hdt-offset8 multifield operand instead of two
+ 4-bit operands that are explicitly combined by semantic code.
+ (do-halfword-store): Bug fix. Set address when not preindexing.
+ (store-halfword): Also use hdt-offset8 operand.
+ (arith-op): Avoid clobbering source registers when one of them is
+ the destination register.
+ (arith-imm-op): Likewise.
+ (tst-imm): Use ror-imm8 operand. Handle special case of rot 0.
+ (teq-imm): Likewise.
+ (ldm-p): Rename to ldmdb.
+ (stm-pw): Rename to stmdb-wb.
+ (multi-action): New macro; test reg-list bits and execute a
+ semantic fn if the bit is set.
+ (ldmda,ldmib,ldmia,ldmia-wb,ldmdb): New multiple load insns.
+ (stmdb,stmib,stmia,stmia-wb,stmda,stmdb-wb): Store insns.
+ (all insns): Use dnai entries for simplicity rather than dni.
+ (*): Use short-form of (const ..).
+
+1999-04-29 Doug Evans <devans@casey.cygnus.com>
+
+ * rtl.scm (<rtx-func>): Rename member type to style. Rename
+ member eval to evaluator.
+ (rtx-foo accessors): Rename from rtx:foo. All callers updated.
+ (tstate-make): Delete arg op-fn. All callers updated.
+ (tstate-op-fn,tstate-set-op-fn!): Delete.
+ (rtx-traverse): Delete op-fn arg. All callers updated.
+ * semantics.scm (-simplify-for-compilation-process-expr): New proc,
+ split out of -simplify-for-compilation.
+
+ * Makefile.am (CGEN_NONHOB_FILES,CGENFILES): New variables.
+ (cgen_DEPENDENCIES): Add stamp-cgen.
+ (stamp-cgen): New rule.
+ * Makefile.in: Rebuild.
+
+ * rtl-c.scm (enum:): Define emitter for.
+ * rtl.scm (rtx-constant?): Rename from rtx-const? and check for
+ enums as well.
+ (rtx-constant-value,rtx-enum-value): New procs.
+ (-rtx-traverse-normal): Expand enum-value to (enum enum-value).
+ (rtx-compile-time-constant?): Return #t for enums.
+ (rtx-true?,rtx-false?): Handle enums.
+ (rtx-simplify-eq-attr-mach): Use rtx-true,rtx-false instead of
+ building result by hand.
+ (rtx-simplify-eq-attr-insn): Ditto.
+ * rtx-funcs.scm (enum:,enum): New rtx functions.
+
+ * mach.scm (<arch>): New members insns-analyzed?, semantics-analyzed?,
+ aliases-analyzed?.
+ (arch-analyze-insns!): New proc.
+ * opcodes.scm (opcodes-analyze!): Call arch-analyze-insns! instead
+ of calling ifmt-compute! directly.
+ * sim.scm (-sim-insns-analyzed?): Delete.
+ (sim-analyze!): Call arch-analyze-insns! instead of calling
+ ifmt-compute! directly.
+
+ * utils.scm (string-take-with-filler): New proc.
+ (string-take): Use it.
+
+ * pgmr-tools.scm: New file.
+ * read.scm: Load it.
+ * insn.scm (pretty-print-insn-format): Move to pgmr.scm.
+
+ * insn.scm (insn-base-mask): Renamed from insn:mask.
+ All callers updated.
+ (insn-base-mask-length): Renamed from insn:mask-length.
+ All callers updated.
+ (insn-foo): Renamed from insn:foo. All callers updated.
+ * minsn.scm (minsn-foo): Renamed from minsn:foo. All callers updated.
+ * iformat.scm (compute-insn-base-mask-length): Renamed from
+ compute-insn-mask-length. All callers updated.
+ (compute-insn-base-mask): Renamed from compute-insn-mask.
+ All callers updated.
+
+ * enum.scm (-enum-parse-prefix): New proc.
+ (<enum>,make!): Don't parse enum values here.
+ (-enum-parse): Do it here. Call -enum-parse-prefix.
+ (define-full-insn-enum): Ditto.
+ (enum-vals-upcase): New proc.
+ * hardware.scm (define-keyword): Make enum prefix uppercase.
+ * hobscmif.h (CHAR_LOWERP,CHAR_UPPERP,CHAR_WHITEP): New macros.
+
+ * ifield.scm (<ifield>,field-mask): Allow container to be #f.
+ (<ifield>,field-extract): New method.
+ (<multi-ifield>,field-extract): New method.
+ (ifld-extract): New proc.
+ * opcodes.scm (ifld-insert-fn-name): Renamed from ifld-insert.
+ (ifld-extract-fn-name): Renamed from ifld-extract.
+
+ * ifield.scm (ifld-new-value): Renamed from ifield-make.
+ All callers updated.
+
+ * ifield.scm (ifld-lsb0?): New proc.
+ (sort-ifield-list): New arg up?. All callers updated.
+ * iformat.scm (compute-insn-mask): Get lsb0? flag from argument,
+ rather than global state.
+
+1999-04-27 Doug Evans <devans@casey.cygnus.com>
+
+ * insn.scm (pretty-print-insn-format): New proc.
+
+ * Makefile.in: Rebuild.
+ * aclocal.m4: Rebuild
+ * configure: Rebuild.
+
+Mon Apr 26 10:30:18 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * configure.in (AM_INIT_AUTOMAKE): Update version to 0.7.2.
+ * configure: Rebuild.
+ * aclocal.m4: Rebuild.
+ * Makefile.in: Rebuild.
+ * doc/Makefile.in: Rebuild.
+ * doc/version.texi: Rebuild.
+
+1999-04-25 Doug Evans <devans@casey.cygnus.com>
+
+ * utils.scm (bits->bools): New proc.
+
+1999-04-23 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu (ldrsh-pu): Remove.
+ (do-halfword-load): New pmacro.
+ (load-halfword): Likewise.
+ (do-halfword-store): Likewise.
+ (store-halfword): Likewise.
+ (strh-*): New instructions.
+ (ldrsb-*): Likewise.
+ (ldrh-*): Likewise.
+ (ldrsh-*): Likewise.
+
+1999-04-22 Doug Evans <devans@casey.cygnus.com>
+
+ * ifield.scm (ifld-constant?): Delete special handling of RESERVED
+ fields.
+
+ * arm7.cpu (do-word/byte-store): Fix typo.
+
+1999-04-22 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu (do-word/byte-load): Handle cases where the destination
+ register is the program counter (R15).
+
+ * arm7.cpu (do-word/byte-store,store-word/byte): New pmacros.
+ (str-*): Implement using store-word-byte. Remove older versions.
+ (bic): Use the `inv' rtx for obtaining bitwise complements.
+ (bic-imm): Likewise.
+ (mvn): Likewise.
+ (mvn-imm): Likewise.
+ (store-indev-reg): Remove crufty pmacro.
+ (load-indiv-reg): Likewise.
+ (ldm-p): Reverse the order of register processing for decrement.
+ (stm-p): Likewise.
+ (stbi): Remove; handled by the str-* insns.
+
+1999-04-21 Doug Evans <devans@casey.cygnus.com>
+
+ * thumb.cpu (cmp): Fix carry bit computation.
+ (alu-cmp): Ditto.
+
+1999-04-20 Doug Evans <devans@casey.cygnus.com>
+
+ * arm.cpu (h-tbit): Specify set spec.
+ (h-cpsr): Ditto.
+ * arm7.cpu (bx): Don't call C routine, just set h-tbit.
+ (set-sub-flags): Interpret "carry bit" as a borrow.
+ (all sub/cmp insns): Carry bit is actually a borrow bit.
+ * thumb.cpu (bx-rs,bx-hs): Don't call C routine, just set h-tbit.
+ (add-carry,sub-carry,thumb-neg,thumb-bic,thumb-inv): Delete. Use
+ .pmacro instead.
+ (hireg-add,hireg-cmp,hireg-move): Ditto.
+
+ * read.scm (-CGEN-VERSION): Change version to 0.7.2.
+ (-CGEN-LANG-VERSION): Ditto.
+
+1999-04-18 Doug Evans <devans@casey.cygnus.com>
+
+ * pmacros.scm (-pmacro-make): New arg `default-values',
+ all callers updated.
+ (-pmacro-default-values): New proc.
+ (-pmacro-process-keyworded-args): New proc.
+ (-pmacro-process-args): New proc.
+ (-pmacro-invoke): Process arguments before expanding macro.
+ (-pmacro-get-arg-spec,-pmacro-get-default-values): New procs.
+ (define-pmacro): Handle default values specified in arg list.
+ * rtl.scm (rtx-alu-op-mode,rtx-alu-op-arg): New procs.
+ (rtx-boolif-op-arg[01]): New procs.
+ (rtx-true,rtx-false,rtx-canonical-bool): New procs.
+ (rtx-simplify): Handle not,orif,andif.
+ * semantics.scm (-simplify-for-compilation): Simplify not,orif,andif.
+ * utils.scm (alist-copy): New proc.
+ * arm7.cpu (do-word/byte-load,load-word/byte): New pmacros.
+ (ldr*): Rewrite.
+ (swi): Explicitly set pc.
+
+ * thumb.cpu (bx-rs,bx-hs): Reverse test for switch to arm mode.
+
+1999-04-17 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu (ldr-pu): Do not add 8 to R15; the step() method
+ correctly adjusts the program counter now.
+
+ * arm7.cpu (f-halfword?): Rename from `f-hdt-halfword?'.
+ (f-signed?): Rename from `f-hdt-signed?'.
+ (f-offset4-hi): Rename from `h-hdt-off4-ms'.
+ (f-offset4-lo): Rename from `h-hdt-off4-ls'.
+ (f-hdt-offset8): Use new field names.
+ (ldr): Use `imm12' field, not `offset12', since we do our own
+ address arithmetic.
+ (str, str-*): Likewise.
+ (ldu-*): Remove most; better not implemented than broken.
+ (ldrh*): Likewise.
+ (ldrsh-pu): New insn.
+ (stri): Likewise.
+ (stri-p): Likewise.
+ (stbi): Likewise.
+ (ldm-p): Likewise; replace (load-indiv-reg) version.
+
+1999-04-15 Doug Evans <devans@casey.cygnus.com>
+
+ * arm.cpu (h-pc): Delete VIRTUAL attribute, get/set specs.
+ * arm7.cpu (*): Fix mode of result of arm_compute_carry_out_*.
+ (*): Explicitly specify mode in c-call.
+ (logical-op): Recognize sets of h-gr[15] as sets of pc.
+ (arith-op): Ditto.
+ (and-imm,orr-imm,xor-imm,mov-imm,bic-imm,mvn-imm): Ditto.
+ (arith-imm-op): New pmacro.
+ (add-imm,adc-imm,sub-imm,sbc-imm,rsb-imm,rsc-imm): Use it.
+ * thumb.cpu (bx-rs,bx-hs): Rewrite.
+
+1999-04-14 Doug Evans <devans@casey.cygnus.com>
+
+ * rtl.scm (rtx-simplify-eq-attr-insn): Fix call to context-error.
+
+ * rtl.scm (rtl-find-ifields): Implement.
+
+ * utils-gen.scm: New file.
+ * read.scm: Load it.
+ * desc.scm: Move generic attribute code to utils-gen.scm.
+ * Makefile.am (CGEN_HOB_INPUT_FILES): Add it.
+ * Makefile.in: Rebuild.
+
+ * arm7.cpu (R15-OFFSET): New attribute.
+ (dnai): New pmacro.
+ (logical-op): Delete arg `result?'. All callers updated. Use dnai.
+ Delete use of eval-cond (dnai specifies it). Specify R15-OFFSET of 12
+ for reg-shift version.
+ (arith-op): Ditto.
+ (data processing insns): Reorganize. Use dnai.
+
+ * attr.scm (attr-kind): New proc.
+ (attr-list-enum-list): Rewrite.
+ (-attr-sort): Split result into two lists, bools and non-bools.
+ (current-attr-list-for): Update.
+
+ * thumb.cpu (bx-rs): Rename @cpu@_do_bx to @prefix@_do_bx.
+ (bx-hs): Ditto.
+ (swi): Rename @cpu@_swi to @prefix@_swi.
+
+ * decode.scm (-build-decode-table-entry): Remove heuristic for
+ distinguishing insns, and use insn ifield-assertion specs.
+
+ * desc-cpu.scm (gen-A-attr-mask): Simplify.
+ (gen-ifld-defns): Boolean attributes begin at number 0 now.
+ (gen-hw-table-defns,gen-operand-table,gen-insn-table): Ditto.
+ * opc-itab.scm (-gen-macro-insn-table): Ditto.
+ * utils-cgen.scm (gen-attr-enum-decl): Change type arg to prefix,
+ all callers updated.
+ (gen-attr-name): New proc
+ (gen-attr-mask): Use it. Boolean attributes start at 0 now.
+ (gen-obj-attr-defn): Delete num_nonbools count.
+
+ * iformat.scm (ifmt-analyze): Handle insn-condition.
+ (ifmt-compute!): Ditto.
+ * insn.scm (<insn>): Specify default value for condition,
+ post-cond-trap,compiled-condition,compiled-semantics.
+ (<insn>,make!): New arg condition.
+ (<insn>): Add getters for condition,compiled-condition.
+ (-insn-parse): New arg condition, all callers updated.
+ (-insn-read): Recognize condition spec.
+ (define-full-insn): New arg condition.
+ * minsn.scm (minsn-make-alias): Update call to (make <insn> ...).
+ * semantics.scm (semantic-compile): Change arg sem-code to
+ sem-code-list.
+ (semantic-attrs): Ditto.
+ * sim.scm (sim-finish!): Update calls to define-full-insn.
+ * simplify.inc (define-normal-insn): Update call to define-full-insn.
+
+Tue Apr 13 17:04:34 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * Makefile.am (sim-cpu): Allow specification of ISA.
+ * Makefile.in: Rebuild.
+
+Sun Apr 11 00:37:56 1999 Jim Wilson <wilson@cygnus.com>
+
+ * i960.cpu (sll-expr, srl-expr, sra-expr): Handle large shift counts.
+
+1999-04-10 Doug Evans <devans@casey.cygnus.com>
+
+ * sparccom.cpu (check-fp-enable): Wrap TRAP32_FP_DIS in c-code.
+
+ * arm.cpu (gr-names): Put pc first so it gets prefered in disassembly.
+
+ * attr.scm (atlist?): New proc.
+ (-attr-eval): Rewrite.
+ (attr-parse): New proc.
+ (atlist-parse): Use it.
+
+ * decode.scm (exprtable-entry-make): New proc.
+ (exprtable-entry-insn,exprtable-entry-expr): New procs.
+ (exprtable-make,exprtable-insns): New procs.
+
+ * hardware.scm (hw-mode-ok?): Delete argument `set?'.
+ All uses updated.
+ (hardware-builtin!): Make h-memory a vector.
+
+ * iformat.scm (ifmt-ifields): Renamed from ifmt-fields.
+ All callers updated.
+ (ifmt-analyze): Use csem-* accessors on result of semantic-compile.
+
+ * insn.scm (<insn>). Rename ifld-assertions to ifield-assertion.
+ All uses updated.
+ (-insn-parse): Set semantics to #f if not specified.
+ (define-insn,define-full-insn): Take out code that ignores ALIAS's
+ if simulator.
+ (-parse-insn-format): Recognize `=' iformat spec.
+
+ * mach.scm (isa-min-insn-bitsize): Ignore ALIAS's.
+ (isa-max-insn-bitsize): Ditto.
+
+ * opcodes.scm (<ifield>,gen-insert): Call rtl-c instead of
+ rtl-c-with-alist.
+ (<ifield>,gen-extract): Ditto.
+ (<multi-ifield>,gen-insert,gen-extract): Ditto.
+ * sim-cpu.scm (gen-semantic-code): Rewrite.
+ * sim.scm (-gen-ifld-extract-base): Call rtl-c instead of
+ rtl-c-with-alist.
+ (-gen-ifld-extract-beyond): Ditto.
+ (<multi-ifield>,gen-ifld-extract): Ditto.
+ (<hw-register>,gen-get-macro,gen-set-macro): Ditto.
+ (<*>,cxmake-get,gen-set-quiet,gen-set-trace,gen-write): Update to new
+ rtl evaluation code.
+ (op:read): Build an <eval-state> to pass to gen-read.
+ (op:write): Build an <eval-state> to pass to gen-write.
+ (op:record-profile): Build an <eval-state> to pass to
+ gen-record-profile.
+
+ * operand.scm (<operand>): Give `selector' default value of #f.
+ Give `num' default value of -1. Give `cond?' default value of #f.
+ (op:new-mode): Delete arg `set?', all uses updated.
+
+ * read.scm (reader-error): Handle #f return from port-filename.
+ (-init-parse-cpu!): Call rtl-c-init!.
+ (reader-install-builtin!): Call rtl-builtin!.
+
+ * rtl-c.scm: New file.
+ * semantics.scm: New file.
+ * read.scm: Load them.
+ * rtl.scm: C generation moved to rtl-c.scm. Semantic analysis moved
+ to semantics.scm.
+ (<rtx-func>): Delete members syntax?,macro,c,expr. New members
+ type,eval,num.
+ (rtx-lookup): Renamed from -rtx-func-lookup. All callers updated.
+ (-rtx-num-text,-rtx-max-num): New globals.
+ (def-rtx-operand-node,define-rtx-operand-node): New procs.
+ (-rtx-macro-lookup): New proc.
+ (rtx-lvalue-mode-name): Renamed from rtx-expr-mode-name.
+ (rtx-env-stack-empty?,rtx-env-stack-head): New procs.
+ (rtx-env-var-list,rtx-env-empty-stack,rtx-env-init-stack1): New procs.
+ (rtx-env-make,rtx-env-empty?,rtx-env-make-locals): New procs.
+ (rtx-env-push,rtx-temp-lookup,-rtx-closure-make): New procs.
+ (rtx-make,rtx-kind?,rtx-const?,rtx-const-value,rtx-symbol-name,
+ rtx-operand?,rtx-operand-obj,rtx-local?,rtx-local-obj, rtx-xop-obj,
+ rtx-index-of-value,rtx-if-mode,rtx-if-test,rtx-if-then,rtx-if-else,
+ rtx-eq-attr-owner,rtx-eq-attr-attr,rtx-eq-attr-value): New procs.
+ (rtx-pretty-name): New proc.
+ (-rtx-traverser-table,-rtx-make-traverse-table): New procs.
+ (rtx-traverse-*): Rewrite rtx traversing.
+ (rtx-eval-*): Rewrite rtx evaluation.
+ (rtx-compile): New proc.
+ (rtx-simplify): New proc.
+ (rtx-simply-eq-attr-mach,rtx-simplify-eq-attr-insn): New procs.
+ * rtx-funcs.scm: C generation moved to rtl-c.scm.
+ (ifield,index-of): Rewrite.
+ (name): Renamed from `operand:'.
+ (operand,xop,local): New rtx's.
+ (current-insn): Rewrite.
+ * Makefile.am (CGEN_HOB_INPUT_FILES): Add rtl-c.scm, semantics.scm.
+ (cgen-hob.h): Remove rule for.
+ (cgen-hob.o): Depend on cgen-hob.c only.
+ * Makefile.in: Rebuild.
+
+ * utils-cgen.scm (vmake): New proc.
+ (<context>): New class.
+ (context-make-prefix,context-error): New procs.
+
+Fri Apr 9 19:26:28 1999 Jim Wilson <wilson@cygnus.com>
+
+ * i960.cpu: Add some ??? comments.
+ (xnor, ornot): New instructions.
+ (*): Delete obsolete COND-CTI and UNCOND-CTI attributes.
+
+1999-04-08 Doug Evans <devans@casey.cygnus.com>
+
+ * cos.scm (-object-error): Print better error message.
+
+ * pmacros.scm (-pmacro-env-make): Renamed from -env-make.
+ (-pmacro-env-ref): Renamed from -env-ref.
+
+1999-03-31 Doug Evans <devans@casey.cygnus.com>
+
+ * hardware.scm (<hw-pc>,parse!): Allow get/set specs.
+ (h-pc): Delete.
+ (hardware-builtin!): Delete h-pc builtin.
+ * arm.cpu (h-pc): Define.
+ (h-gr): Delete get,set specs. Make array of 16 regs again.
+ * arm7.cpu (set-logical-cc-maybe): Delete.
+ (set-zn-flags,set-add-flags,set-sub-flags): New macros.
+ (data processing insns): Rewrite.
+ * m32r.cpu (h-pc): Define.
+ * fr30.cpu (h-pc): Define.
+ * i960.cpu (h-pc): Define.
+ * sparc.cpu (h-pc): Define.
+
+ * rtl.scm (-rtx-traverse-operands): Add some error checking to LOCALS.
+ (s-parallel): Replace do {...} while (0) with {...}.
+ (s-sequence): Ditto.
+
+
+1999-03-30 Doug Evans <devans@casey.cygnus.com>
+
+ * sparccom.cpu (arith-cc-binop): New args s32-set-flags,s64-set-flags.
+ All callers updated.
+ (arith-carry-cc-binop): New arg set-flags. All callers updated.
+
+
+ * read.scm (-reader-process-expanded-1): New proc.
+ (-reader-process-expanded): Call it to catch nested begin's.
+ (reader-process): Move `begin' handling to -reader-process-expanded.
+
+ * insn.scm (-insn-read): Fix name of `format' spec.
+
+ * pmacros.scm (.pmacro): New builtin.
+ (scan-symbol): If procedure macro, return macro rather than its symbol.
+ (check-macro): Don't do lookup, instead check if (car expr) is
+ macro object.
+ (scan-list): Handle .pmacro.
+ (scan): No longer re-examine text for another macro invocation.
+ (-pmacro-build-lambda): New proc.
+ (define-pmacro): Rewrite. If defining one pmacro to be an alias of
+ another, fetch the other's value (rather than doing it during
+ expansion).
+
+1999-03-27 Doug Evans <devans@casey.cygnus.com>
+
+ * Makefile.am (CGEN_HOB_INPUT_FILES): Add decode.scm.
+ * Makefile.in: Rebuild.
+
+ * decode.scm (decode-get-best-bits): Use memq instead of element?.
+ (-fill-slot!): Simplify.
+ (-build-slots): Simplify.
+
+ * sim-decode.scm: Replace computed goto decoder/extractor with plain
+ switch's.
+
+1999-03-26 Doug Evans <devans@casey.cygnus.com>
+
+ * sim-decode.scm: Clean up pass. Move decoder computation into ...
+ * decode.scm: ... here. New file.
+ * read.scm: Load decode.scm.
+
+ * arm.cpu (arm710 model): Add u-exec function unit.
+ (h-gr): Delete CACHE-ADDR for now. Make array of 15, not 16 regs.
+ Add get/set specs to redirect reg 15 to h-pc.
+ (h-*): Indicate for both ARM and THUMB isas.
+ (cbit,nbit,vbit,zbit): Ditto.
+ (h-ibit,h-fbit,h-tbit,h-mbits): New hardware elements.
+ (h-cpsr): Make virtual. Add get/set specs.
+ (h-spsr-fiq,h-spsr-svc,h-spsr-abt,h-spsr-irq,h-spsr-und): New hw.
+ (h-spsr): New virtual reg.
+ * arm7.cpu (shift-type): New explicitly defined keyword.
+ (h-operand2-shifttype): Use it.
+ (set-logical-cc-maybe): Delete carry-out arg. New args arg1,arg2.
+ All callers updated. Don't set cbit.
+ (logical-op): Add rm to ifield list. Change case to case:. Use
+ shift-type enum as case choices. Set cbit.
+ (and,orr,eor,add-imm): Uncomment out.
+ (undefined): Temporarily comment out.
+ * thumb.scm (mov,cmp,addi8,subi8,str-sprel,ldr-sprel): s/rd/bit10-rd/.
+ (lda-pc,lda-sp): Ditto.
+ (ldr-pc): Rename from ldr.
+ (cbranch): Mark insns as being thumb insns.
+
+ * attr.scm (<bitset-attribute>,parse-value): Recognize strings.
+
+
+ * insn.scm (<insn>,iflds): Renamed from flds. All uses updated.
+ (<insn>,ifld-assertions): New member.
+ (<insn>,make!): New arg ifld-assertions, all callers updated.
+ (<insn> accessors): Change insn:foo to insn-foo. All callers updated.
+ (insn:fields): Delete.
+ (-insn-parse): New arg ifld-assertions. All callers updated.
+ (-insn-read,define-insn): New procs.
+ (define-full-insn): New arg ifld-assertions. All callers updated.
+ (insn-init!): New comment define-insn.
+
+ * model.scm (-model-parse): Ensure at least one unit specified.
+
+ * rtl.scm (-rtx-traverse-operands): Recognize environments.
+ (<c-expr-temp>,get-name): New method.
+ (-rtx-make-current-closure,s-closure): New proc.
+ (hw:): Wrap rtx indices in a closure.
+ (-gen-case-prefix): New proc.
+ (s-case): Simplify.
+ * rtx-funcs.scm (case:): Fix call to s-case.
+ (closure): New rtx func.
+
+ * hardware.scm (<hardware-base>): New member isas-cache.
+ (<hardware-base>,get-isas): New method.
+ (hardware-builtin): Indicate for all isas.
+ * ifield.scm (-ifield-parse): Only keep if isa+mach are kept.
+ * mach.scm (current-arch-mach-name-list): Return list of names.
+ (current-isa-mach-name-list): Ditto.
+ (define-arch): Install builtin objects here.
+ * read.scm (keep-atlist?): Only keep if both mach and isa are
+ being kept.
+ (keep-mach-atlist?): New proc.
+ (keep-isa-multiple?,current-keep-isa-name-list): New proc.
+ (reader-install-builtin!): Renamed from -install-builtin!.
+ * sim.scm (sim-finish!): Specify isa of added x-* virtual insns.
+
+1999-03-22 Doug Evans <devans@casey.cygnus.com>
+
+ * thumb.cpu (cpu,mach,model): Delete.
+ (dntf): New pmacro. Use it for all field definitions.
+ (dntop): New pmacro. Use it for all operand definitions.
+ (asr): Correct field list.
+ (add,addi,sub,subi,add-sp,add-sp-neg): Ditto.
+
+ * utils-cgen.scm (define-getters): New macro to simplify
+ writing class accessors.
+ (define-setters): Ditto.
+ (sanitize): Recognize isa elements.
+
+ * sim-decode.scm (-gen-decode-switch): Ditto.
+
+ * sim-arch.scm (-regs-for-access-fns): Delete.
+ (-biggest-reg-mode,-gen-arch-reg-access-decls): Delete.
+ (-gen-arch-reg-access-defns): Delete.
+
+ * sim-cpu.scm (*): Replace cpu:liw-insns with state-liw-insns,
+ cpu:parallel-insns with state-parallel-insns, cpu:parallel-exec?
+ with state-parallel=exec?.
+ (cgen-*): Call sim-analyze-insns! here.
+ * sim-decode.scm (cgen-*): Ditto.
+ * sim-model.scm (cgen-*): Ditto.
+ * sim.scm (-sim-insns-analyzed): New global variable.
+ (sim-init!): Reset it.
+ (sim-analyze-insns!): Renamed from sim-analyze!. Keep track if we've
+ already done the analysis.
+
+ * sim-model.scm (-gen-mach-defns): Add mach attribute number to
+ MACH struct.
+
+ * arm.cpu: Only include arm7.cpu,thumb.cpu if necessary.
+ (arm arch): Update isa spec.
+ (arm,thumb isas): Define.
+ (arm7 cpu): default-insn-bitsize,base-insn-bitsize moved to isas.
+ (arm7tdmi mach): Add isa spec.
+ * arm7.cpu (*): Replace subreg: with subword:. Remove unnecessary
+ `const' on word number.
+ * fr30.cpu (fr30 arch): Update isa spec.
+ (fr30 isa): Define.
+ (fr30bf cpu): default-insn-bitsize,base-insn-bitsize,decode-assist,
+ moved to isa spec.
+ * i960.cpu (i960 arch): Update isa spec.
+ (i960 isa): Define.
+ (i960base cpu): default-insn-bitsize,base-insn-bitsize,decode-assist,
+ liw-insns,parallel-insns moved to isas spec.
+ * m32r.cpu (m32r arch): Update isas spec.
+ (m32r isa): Define.
+ (m32rbf cpu): default-insn-bitsize,base-insn-bitsize,decode-assist,
+ liw-insns,parallel-insns moved to isa spec.
+ * sparc.cpu (sparc arch): Update isas spec.
+ (sparc isa): Define.
+ * sparc32.cpu (sparc32 cpu): default-insn-bitsize,base-insn-bitsize,
+ decode-assist moved to isa spec.
+ * sparc64.cpu (sparc64 cpu): Ditto.
+ * sparccom.cpu (trap insns): Correct mode of result of c-call:.
+ * desc-cpu.scm (-gen-isa-table-defns): New proc.
+ (-gen-mach-table-defns): Output mach table.
+ (-gen-hash-defines): Delete insn size macros, except for
+ CGEN_MAX_INSN_SIZE.
+ (-cgen-cpu-open): Rewrite cpu_open handling. Take stdarg list of args.
+ (cgen-desc.h): Define MAX_ISAS.
+ (cgen-desc.c): Include stdarg.h. Call -gen-isa-table-defns.
+ * mach.scm (<arch>): Rename arch-data to data. New member isa-list.
+ (arch-* accessors): Renamed from arch:*. All callers updated.
+ (current-arch-isa-name-list): New proc.
+ (-arch-parse-isas): Renamed from -arch-parse-isa.
+ (def-isa-attr!): Rewrite.
+ (<iframe>): New class.
+ (<itype>): New class.
+ (<isa>): Rewrite.
+ (isa-min-insn-bitsize,isa-max-insn-bitsize): New procs.
+ (isa-integral-insn?,isa-parallel-exec?): New procs.
+ (-isa-parse,-isa-read,define-isa): New proc.
+ (<cpu>): Members default-insn-bitsize,base-insn-bitsize,decode-assist,
+ liw-insns moved to <isa>.
+ (cpu-* accessors): Renamed from cpu:*. All callers updated.
+ (-cpu-parse,-cpu-read): Update.
+ (state-*): Renamed from state:*. All callers updated.
+ (state-default-insn-bitsize,state-base-insn-bitsize): Use isa spec,
+ not cpu.
+ (state-parallel-insns,state-parallel-exec?,state-liw-insns): New procs.
+ (state-decode-assist): New proc.
+ (<derived-arch-data>): Delete min-insn-bitsize,max-insn-bitsize.
+ (-adata-set-derived!): Rewrite.
+ (adata-integral-insn?): Renamed from adata:integral-insn?. All
+ callers updated.
+ (arch-init!): Add define-isa command.
+ * read.scm (<reader>): Default keep-isa member to (all).
+ (reader-* accessors): Renamed from reader:*. All callers updated.
+ (-keep-isa-set!): Call string->symbol on isa name list.
+ (keep-isa-validate!): Rewrite.
+ (current-isa): New proc.
+ (keep-isa?): Recognize "all".
+ (-init-parse-cpu!): New arg keep-isa. All callers updated.
+ Call -keep-isa-set!.
+ (cmd-if): Recognize keep-isa?.
+ (cpu-load): New arg keep-isa. All callers updated.
+ (-opt-spec-update): New proc.
+ (common-arguments): First arg is string, not symbol.
+ (-cgen): Call -opt-spec-update. Rewrite argument parsing.
+
+ * rtl.scm (rtx-get): Default mode of string arg is INT.
+
+ * rtl.scm (s-subword): Renamed from s-subreg. All uses updated.
+
+ * rtx-funcs.scm (join:): Pass cpu to handler.
+
+ * configure.in (guile_include_dir): Delete.
+ * configure: Rebuild.
+ * Makefile.in: Rebuild.
+ * doc/Makefile.in: Rebuild.
+
+
+1999-03-22 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu (ldri-p): New instruction.
+ (swi): Do not vector through 0x8 yet--there is nothing there.
+ (addi): Reinstate.
+ (movi): Likewise.
+ (all): Use (const x) in subreg expressions.
+
+1999-03-19 Ben Elliston <bje@cygnus.com>
+
+ * arm7.cpu (smull): Use operand field `rs', not `mul-rn'. Thinko.
+ (smlal): Likewise.
+
+1999-03-17 Doug Evans <devans@casey.cygnus.com>
+
+ * fr30.cpu (define-arch): Specify "forced" default-alignment.
+ * mach.scm (-parse-alignment): Recognize "forced" alignment.
+ * sim-cpu.scm (-extract-chunk-specs): New proc.
+ (gen-define-fields): Use it.
+ (-extract-chunk): New proc.
+ (-gen-extract-beyond-var-list): Use it.
+ (gen-extract-fields): Simplify.
+
+ Port to guile 1.3.1.
+ * Makefile.am (GUILEINCDIR,GUILELDFLAGS,GUILELDADD): Delete.
+ (LIBIBERTY): New var.
+ (HOB_OBJS): Add cgen-gh.o.
+ (hobbit): Delete $(CFLAGS) from link, add $(LIBS) $(LIBIBERTY).
+ * Makefile.in: Rebuild.
+ * acconfig.h: Add HAVE_3_ARG_SCM_MAKE_VECTOR.
+ * config.in: Rebuild.
+ * configure.in: Add checks for libdl, libreadline, libnsl, libsocket,
+ libncurses, libtermcap.
+ Add checks for needed functions in guile 1.2 not in guile 1.3,
+ and vice versa. Add test for 3 argument scm_make_vector.
+ * configure: Rebuild.
+ * cgen-gh.c (scm_list_length,scm_list_append,scm_list_reverse): Provide
+ definitions if guile doesn't have them.
+ (gh_make_vector,gh_length,gh_vector_set_x,gh_vector_ref):
+ (cgh_vector): Replace gh_vector with gh_make_vector. Replace gh_vset
+ with gh_vector_set_x.
+ (cgh_qsort): Replace gh_list_length with gh_length.
+ * cgen-gh.h: Add decls for added functions.
+ (cgh_qsort): Don't declare if IN_HOBBIT.
+ * cos.c: Include config.h. Replace gh_vref with gh_vector_ref,
+ gh_vset with gh_vector_set_x, gh_list_length with gh_length,
+ scm_make_vector with gh_make_vector.
+ * cos.scm: Use vector-length instead of length on vectors.
+ * dev.scm (cload): Make varargs proc with keyword/value args.
+ * hobscmif.h: Include config.h, cgen-gh.h. Undef make_vector and
+ provide version that works with guile 1.2 or 1.3.
+ Include private copy of scmhob.h.
+ * scmhob.h: New file. Keep our own copy for now.
+
+Tue Mar 16 13:22:01 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * rtl.scm (-rtx-traverse-error): Ensure expression is output in
+ plain text.
+ (-rtx-traverse-operands): Dump cx temp stack if debugging.
+ (-cx-temp-dump-stack): Pretty up output.
+
+ * arm.cpu: comment out thumb.cpu until isa support ready.
+ * arm7.cpu (bl): Replace lr with (reg h-gr 14).
+ (f-imm12,f-offset24,swi,undef): Fix thinko, add `const'.
+ * thumb.cpu (h-gr-t,h-lr-t,h-sp-t,dnti,h-hiregs): s/MACH/ISA/.
+
+
+1999-03-11 Doug Evans <devans@casey.cygnus.com>
+
+ * hardware.scm (<hw-immediate>,mode-ok?): Ensure result is boolean.
+ (<hw-address>,mode-ok?): unsigned/signed are compatible.
+
+ * operand (op:new-mode): Improve error message.
+
+ * arm.cpu: Move arm isa into arm7.cpu. Include arm7.cpu, thumb.cpu.
+ * arm7.cpu: New file.
+
+1999-03-12 Ben Elliston <bje@cygnus.com>
+
+ * arm.cpu: Lots of minor fixes after desk checking.
+
+1999-03-11 Doug Evans <devans@casey.cygnus.com>
+
+ * thumb.cpu: snapshot of current work
+
+ * rtl.scm (rtx-get): Tweak error message.
+
+1999-03-10 Doug Evans <devans@casey.cygnus.com>
+
+ * Makefile.am (cos.o,cgen.o,cgen-gh.o): Fix dependencies.
+ * Makefile.in: Rebuild.
+
+ * cos.c (cos_vector_copy): New function.
+ (_object_copy): Use it.
+
+ * mode.scm (mode:eq?): Clean up.
+ * rtl.scm (cx-new-mode): Copy attributes.
+ (rtx-get): Don't make copy if <c-expr> with identical mode.
+
+ * fr30.cpu (define-arch): Delete default-insn-word-bitsize,
+ add new isas spec.
+ (gr-names): h-gr register names moved here.
+ (h-gr): Update.
+ (cr-names): h-cr register names moved here.
+ (h-cr): update.
+ (dr-names): h-dr register names moved here.
+ (h-dr): update.
+ (h-ps): Replace FUN-ACCESS attribute with get/set specs.
+ (h-sbit,h-ccr,h-scr,h-ilm): Ditto.
+ * i960.cpu (define-arch): Delete default-insn-word-bitsize,
+ add new isas spec.
+ * m32r.cpu (define-arch): Delete default-insn-word-bitsize,
+ add new isas spec.
+ (gr-names): h-gr register names moved here.
+ (h-gr): Update.
+ (cr-names): h-cr register names moved here.
+ (h-cr): update.
+ (h-accum): Replace FUN-ACCESS attribute with get/set specs.
+ (h-accums,h-psw): Ditto.
+ * sparc.cpu (define-arch): Delete default-insn-word-bitsize,
+ add new isas spec.
+ (gr-names): h-gr register names moved here.
+ (h-gr-indices): Delete.
+ (sparc32 h-gr): Update. Replace FUN-ACCESS with get/set specs.
+ (sparc64 h-gr): Ditto.
+ (h-y): Add get/set specs.
+ (fp regs): Rewrite.
+ (fp operands): Rewrite.
+ * sparc32.cpu (h-psr): Replace FUN-ACCESS with get/set specs.
+ (h-tbr,h-cwp,h-wim): Ditto.
+ * sparc64.cpu (h-fpsr): Add get/set specs.
+ * sparccom.cpu (ldd-reg+reg): Load value all at once.
+ (fp-ld-op): New arg `dest', all callers updated.
+ (*): Replace `make-di' with `join'.
+
+
+ * sim-arch.scm (-regs-for-access-fns): New proc.
+ (-biggest-reg-mode): New proc.
+ (-gen-arch-reg-access-decls,-gen-arch-reg-access-defns): Rewrite.
+ * sim-cpu.scm (-gen-hardware-types): Output get/set handlers for
+ virtual regs separately.
+ (-gen-cpu-reg-access-defns): Replace fun-access? with new
+ get/set specs.
+ (gen-semantic-code): Save/restore rtl generator state.
+ (cgen-cpu.h): Call rtl-gen-init!.
+ (cgen-cpu.c): Ditto. #include cgen-ops.h.
+ * sim-model.scm: mach:cpu renamed to mach-cpu. mach:bfd-name
+ renamed to mach-bfd-name.
+ * sim.scm (-gen-ifld-extract-base): Update call to rtx-c-with-alist.
+ (-gen-ifld-extract-beyond): Ditto.
+ (<multi-ifield>,gen-ifld-extract): Ditto.
+ (<scalar>,gen-sym-get-macro): Update call to gen-get-macro.
+ (<scalar>,gen-sym-set-macro): Update call to gen-set-macro.
+ (all gen-read,gen-write,cxmake-get,gen-set-* methods): New arg
+ `gstate'.
+ (hw-fun-access?): Delete.
+ (-hw-gen-set-quiet-pc): New arg `gstate'.
+ (<hw-register>,gen-get-macro): Rewrite.
+ (<hw-register>,gen-set-macro): Rewrite.
+ (-hw-gen-fun-get,-hw-gen-fun-set): Delete.
+ (-hw-cxmake-get): New arg `gstate'. Rewrite.
+ (<hw-register>,cxmake-get-raw): New method.
+ (-hw-gen-set-quiet): New arg `gstate'. Rewrite.
+ (<hw-register>,gen-set-quiet-raw): New method.
+ (-gen-hw-index-raw): Update call to rtx-c. Update cxmake-get
+ invocation.
+ (-gen-hw-index): Ditto.
+ (<hw-index>): New arg `gstate'.
+ (-gen-hw-selector): Update call to rtx-c.
+ (<pc>): New arg `gstate'.
+ (op:read): Update gen-read invocation.
+ (op:write): Update gen-write invocation.
+ (<operand>,cxmake-get): Handle raw-reg.
+ (-op-gen-set-quiet,-op-gen-set-quiet-parallel): New arg `gstate'.
+ (-op-gen-set-trace,-op-gen-set-trace-parallel): Ditto.
+ (<operand>,gen-set-quiet): Handle raw-reg.
+ (<operand>,gen-set-trace): Handle raw-reg.
+ (-gen-mach-data): mach:cpu renamed to mach-cpu.
+
+ * desc-cpu.scm (gen-operand-decls): Take nub of operands for
+ cgen_operand_type enum.
+ (gen-operand-table): Add operand type enum. Replace pointer to
+ hardware element with its enum. Null terminate table.
+ (-gen-cpu-open): Add new `isa' argument to @arch@_cgen_cpu_open.
+ Build operand table.
+ * ifield.scm (-ifield-parse): Recognize ISA attribute.
+ * mach.scm (<arch-data>): New member `isas'.
+ (adata-isas): New accessor.
+ (<isa>): New class.
+ (isa-default-insn-word-bitsize): New accessor.
+ (isa-enum): New proc.
+ (current-arch-default-insn-word-bitsize): Delete.
+ (current-isa-list,current-isa-lookup): New procs.
+ (-arch-parse-isa): New proc.
+ (-arch-parse): Rewrite.
+ (-arch-read): Recognize `isas'. Delete `default-insn-word-bitsize'.
+ (define-arch): Define ISA attribute.
+ (def-isa-attr!,isa-supports?): New procs.
+ (<mach>): New member `isas'.
+ (mach-isas): New accessor.
+ (-mach-parse): New arg `isas', all callers updated.
+ (-mach-read): Recognize `isas'.
+ (arch-finish!): Rewrite.
+ * opc-ibld.scm (-gen-fget-switch): Add `cd' arg to
+ @arch@_cgen_get_{int,vma}_operand.
+ (-gen-fset-switch): Add `cd' arg to @arch@_cgen_set_{int,vma}_operand.
+ * opc-opinst.scm (-gen-operand-instance): Output operand enum instead
+ of pointer to table entry.
+ * opcodes.scm (gen-switch): Handle multiply defined operands.
+ * operand.scm (op-sort): New proc.
+
+ * hardware.scm (<hardware-base>): Rename getters/setters to get/set.
+ (hw-getter,hw-setter): Renamed from hw-getters,hw-setter.
+ (hw-enum): Accept symbol argument.
+ (hardware-builtin!): Delete attribute FUN-ACCESS.
+ * ifield.scm (ifld-encode-mode,ifld-decode-mode): New procs.
+
+ * attr.scm (atlist-source-form): New proc.
+ (attr-builtin!): New attr `PRIVATE'.
+ * desc.scm (<keyword>,gen-defn): Make keyword entry table static.
+ * desc-cpu.scm (-gen-hw-defn): Only output index and value tables
+ if they have `PRIVATE' attribute.
+ (gen-hw-table-defns): Output definitions of explicitly defined
+ keyword tables.
+ * hardware.scm (<keyword>): New member print-name. Rename member
+ `value' to `values', all uses updated.
+ (kw-mode,kw-print-name,kw-prefix,kw-values): New procs.
+ (keyword-parse): Rewrite.
+ (-keyword-read): New proc.
+ (define-keyword): New proc.
+ (-hw-parse-keyword): New proc.
+ (-hw-parse-indices): Rewrite keyword handling, support new index spec
+ `extern-keyword'.
+ (-hw-parse-values): Ditto.
+ (-hw-parse-get,-hw-parse-set): Rewrite.
+ (hardware-init!): Add new comment define-keyword.
+ * mach.scm (<arch>): New member `kw-list'.
+ (arch:kw-list,arch_set-kw-list!): New accessors.
+ (current-kw-list,current-kw-add!,current-kw-lookup): New procs.
+
+ * hardware.scm (<hw-register>,mode-ok?): Rewrite.
+ * mode.scm (mode-class-integral?): New proc.
+ (mode-class-float?,mode-class-numeric?): New procs.
+ (mode-integral?,mode-float?,mode-numeric?): New procs.
+ (mode-compatible?): New proc.
+ * opcodes.scm (<ifield>,gen-insert): Update alist arg to
+ rtx-c-with-alist.
+ (<ifield>,gen-extract): Ditto.
+ * rtl.scm (-rtl-simulator?,-rtx-current-obj): Delete.
+ (<gstate>): New class.
+ (gstate-simulator?,gstate-set-simulator?!): New accessors.
+ (gstate-context,gstate-set-context!): New accessors.
+ (gstate-macro?,gstate-set-macro?!): New accessors.
+ (gstate-make,gstate-copy): New procs.
+ (-rtl-current-gstate): New global.
+ (current-gstate-simulator?): New proc.
+ (current-gstate-context,current-gstate-macro?): New procs.
+ (current-gstate,current-gstate-set!): New procs.
+ (rtl-gen-init!): Rewrite.
+ (-rtx-valid-types): Add INTMODE, FLOATMODE, NUMMODE.
+ (tstate-make): New arg `gstate', all callers updated.
+ (tstate-set-expr-fn!,tstate-set-op-fn!): New accessors.
+ (tstate-set-cond?!,tstate-set?,tstate-set-set?!): New accessors.
+ (tstate-gstate,tstate-set-gstate!): New accessors.
+ (tstate-copy): New proc.
+ (tstate-new-cond?,tstate-new-set?): Rewrite.
+ (-rtx-traverse-operands): Handle INTMODE, FLOATMODE, NUMMODE.
+ (rtx-traverse): New arg `gstate', all callers updated.
+ (rtx-strdump): New proc.
+ (-simplify-for-compilation): New arg `gstate', all callers updated.
+ (semantic-in-out-operands): Ditto.
+ (semantic-attrs): Ditto.
+ (rtx-eval): Rewrite. New arg `gstate', all callers updated.
+ (rtx-eval-with-temps,rtx-eval-with-alist): Ditto.
+ (rtx-value): Rewrite.
+ (<c-expr>,gen-name): New method.
+ (<c-expr>,gen-set-quiet): New arg `gstate', all callers updated.
+ (<c-expr>,gen-set-trace): New arg `gstate', all callers updated.
+ (cx-new-mode): New proc.
+ (-rtx-c-with-tstate): New proc.
+ (rtx-c,rtx-c-with-temps,rtx-c-with-alist): New arg `gstate', all
+ callers updated.
+ (-rtx-mode): Rewrite.
+ (-rtx-mode-compatible?): New proc.
+ (<c-expr-temp>): New member `value'.
+ (cx-temp:value): New accessor.
+ (<c-expr-temp>,make!): Override default method.
+ (<c-expr-temp>,cxmake-get): Rewrite.
+ (<c-expr-temp>,gen-set-quiet): Rewrite.
+ (<c-expr-temp>,gen-set-trace): Rewrite.
+ (gen-temp-defs): Use cx-temp:value.
+ (record-temp!): New arg value, all callers updated.
+ (cx-temp:cx:make): Delete.
+ (-cx-temp-dump-stack): New proc.
+ (rtx-get): New arg `gstate', all callers updated. Do mode
+ compatibility checks. Ensure result has specified mode.
+ (rtx-set-quiet): New arg `gstate', all callers updated.
+ (rtx-set-trace): Ditto.
+ (s-c-call): New arg `tstate', all callers updated.
+ (s-c-raw-call): Ditto.
+ (s-unop,s-binop,s-binop-with-with,s-shop,s-boolifop,s-convop): Ditto.
+ (s-cmpop,s-if,e-if): Ditto.
+ (s-subreg): New proc.
+ (-par-new-temp!): New proc.
+ (-par-next-temp!): Rewrite.
+ (-par-replace-set-dests): Use -par-new-temp!.
+ (s-parallel): Rewrite temp handling. Use -rtx-c-with-state.
+ (s-sequence): Use -rtx-c-with-state.
+ * rtx-funcs.scm (*): Update.
+ (raw-reg:): New rtx function.
+ (make-di): Delete.
+ (join:,subreg:): New rtx functions.
+
+ * insn.scm (<insn>): New members pre-cond-trap, condition,
+ post-cond-trap, compiled-condition.
+
+ * insn.scm (syntax-break-out): Replace eval with current-op-lookup.
+
+ * opcodes.scm (<pc>,cxmake-get): New arg `selector'.
+
+ * utils-cgen.scm (parse-symbol): New proc.
+ (parse-string): New proc.
+ (gen-get-macro,gen-set-macro): New arg `index-args'.
+ (gen-set-macro2): Ditto. Enclose code in do { } while (0).
+ Prepend \ to newlines.
+
+ * utils.scm (alist-remove-duplicates): Delete.
+
+
+1999-03-05 Ben Elliston <bje@cygnus.com>
+
+ * arm.cpu: New file.
+
+1999-03-03 Doug Evans <devans@casey.cygnus.com>
+
+ * Makefile.am (CGEN_HOB_INPUT_FILES): Add hardware.scm.
+ * Makefile.in: Rebuild.
+
+ * attr.scm (<integer-attribute>,parse-value-def): Tweak.
+ (-attr-parse): Validate default value.
+
+ * read.scm (-CGEN-VERSION): Change to 0.7.1.
+ (-CGEN-LANG-VERSION): Ditto.
+ (-keep-all-machs): Renamed from -keep-all, all uses updated.
+ (<reader>): New member keep-isa plus accessors.
+ (-keep-isa-set!,keep-isa-validate!): New procs.
+ (keep-isa?,keep-isa-atlist?,keep-isa-obj?): New procs.
+ (common-arguments): New variable.
+ (cgen-usage,getarg,catch-with-backtrace,option-arg): New procs.
+ (-debug-repl,continue): New procs.
+ (-cgen,cgen): New procs.
+ * cgen-gas.scm: Rewrite.
+ * cgen-opc.scm: Rewrite.
+ * cgen-sim.scm: Rewrite.
+ * cgen-stest.scm: Rewrite.
+
+ * gas-test.scm (gas-test-init!): Call opcodes-init!.
+ (gas-test-finish!): Call opcodes-finish!.
+ (gas-test-analyze!): Call opcodes-analyze!.
+ (<hw-asm>): New method test-data.
+ (<operand>,testdata): Rewrite.
+ * sim-test.scm (sim-test-init!): Call opcodes-init!.
+ (sim-test-finish!): Call opcodes-finish!.
+ (sim-test-analyze!): Call opcodes-analyze!.
+ (<hw-asm>): New method test-data.
+ (<operand>,testdata): Rewrite.
+
+1999-03-01 Doug Evans <devans@casey.cygnus.com>
+
+ * fixup.scm (reverse!): Define if missing.
+ * *.scm: Use reverse! instead of list-reverse!.
+
+ * utils.scm (leading-id-char?): New proc.
+ (id-char?): Rewrite.
+ (chars-until-delimiter): New proc.
+ * opc-itab.scm (extract-syntax-operands): Rewrite.
+ (strip-mnemonic): Rewrite.
+ (compute-syntax): Rewrite.
+
+ * pmacros.scm (-pmacro-substr): New proc.
+ (pmacros-init!): Add builtin .substr.
+
+1999-02-26 Doug Evans <devans@casey.cygnus.com>
+
+ * thumb.cpu: New file.
+
+1999-02-24 Doug Evans <devans@casey.cygnus.com>
+
+ * Makefile.am (CGENCFLAGS): New variable.
+ (WITH_HOBBIT): Use automake conditional.
+ (CGEN_HOB_SRC): New variable.
+ (libcpu_a_SOURCES): Use $(CGEN_HOB_SRC).
+ (*.o): Compile with CGENCFLAGS.
+ (cgen-hob.c): Simplify.
+ (cgen-nohob.c): New rule.
+ (hobbit): Renamed from hob.x.
+ (CLEANFILES): Add cgen-nohob.c.
+ * Makefile.in: Rebuild.
+ * doc/Makefile.in: Rebuild.
+ * configure.in (AM_INIT_AUTOMAKE): Update CGEN version to 0.7.1.
+ (WITH_HOBBIT): Use AM_CONDITIONAL.
+ * configure: Rebuild.
+ * aclocal.m4: Rebuild.
+
+ * sim-arch.scm (-gen-arch-reg-access-defns): Replace string-map
+ with string-write-map.
+
+ * sim-cpu.scm (hw-need-storage?): New proc.
+ (-gen-hardware-types): Use it.
+ (gen-parallel-exec-elm): Call op-save-index?.
+
+ * sim-decode.scm (cgen-decode.c): Call rtl-gen-init!.
+
+ * sim.scm (-gen-ifld-extract-base): Use mode:class instead of
+ UNSIGNED attribute.
+ (-gen-ifld-extract-beyond): Ditto.
+ (<integer>): Delete all references.
+ (<sim-hardware>): Delete.
+ (hw-profilable?): New proc.
+ (<hardware-base>): New methods gen-get-macro,gen-set-macro.
+ (<hw-register>): Rename method get-index-mode to save-index?.
+ (<hw-register>): New methods gen-get-macro,gen-set-macro.
+ (<hw-register>,gen-sym-decl): Make virtual.
+ (<hw-memory>,gen-sym-decl): Make virtual.
+ (<hw-memory>): Rename method get-index-mode to save-index?.
+ (<hw-address>,gen-sym-decl): Make virtual.
+ (<operand>): New method save-index?.
+ (sim-init!): Delete calls to sim-hw-init!,sim-hw-init-parsers!.
+
+ * opc-itab.scm (opc-{parse,insert,extract,print}-handlers): opc-
+ prefix added. All uses updated.
+
+ * opc-opinst.scm (-gen-operand-instance): Output hw enum value
+ rather than pointer to table entry.
+
+ * opcodes.scm: Remove all attribute support, lives in desc.scm.
+ Remove all hw-asm,op-asm support.
+ (-gen-parse-number,-gen-parse-address): New procs.
+ (<keyword>,gen-parse): Redo function name computation.
+ (<keyword>,gen-print): Ditto.
+ (<operand>,gen-function-name): Rewrite.
+ (<operand>,gen-fget,gen-fset,gen-parse,gen-print): Ditto.
+ (opcodes-init!): Delete call to add-parser!.
+
+ * desc-cpu.scm (gen-hw-decls): Rename enum hw_type to cgen_hw_type.
+ Define enum using hardware semantic name.
+ (-gen-hw-decl,-gen-hw-defn): New procs.
+ (gen-hw-table-decls): Use -gen-hw-decl.
+ (gen-hw-table-defns): Use -gen-hw-defn. Rewrite generation of
+ CGEN_HW_ENTRY structs.
+ (gen-operand-table): Output hw's enum, not pointer to table entry.
+ (-gen-cpu-open): Build table of selected hardware elements.
+
+ * desc.scm (-hw-asm-specs,-parse-hw-asm): Delete.
+ (<hardware> support): Delete.
+ (<hw-asm>): Delete, moved to hardware.scm.
+ (normal-hw-asm,hw-asm:parse,hw-asm:print): Delete.
+ (<hw-asm>,gen-table-entry): New method.
+ (<hw-asm>,parse!): Delete.
+ (<keyword>,gen-table-entry): New method.
+ (<keyword>,parse!): Delete.
+ (<hw-{register,memory,immediate,address}>): Delete forwarding methods
+ for gen-decl,gen-defn,gen-ref,gen-init.
+ (desc-init!): Don't create parser for operand asm specs.
+
+ * attr.scm (attr-builtin!): Delete UNSIGNED attribute.
+ * ifield.scm (<ifield>): New member `mode'.
+ (<ifield>,make!): New arg `mode'.
+ (ifld-mode): Rewrite.
+ (ifld-hw-type): Rewrite.
+ (<ifield>,min-value): Rewrite.
+ (<ifield>,max-value): Rewrite.
+ (-ifield-parse): New arg `mode'.
+ (-ifield-read): Update.
+ (define-full-ifield): New arg `mode'.
+ (define-full-multi-ifield): Ditto.
+ (-multi-ifield-parse): Ditto.
+ (-multi-ifield-read): Update.
+ (define-full-multi-ifield): New arg `mode'.
+ (ifield-builtin!): Update definition of f-nil.
+ * simplify.inc (define-normal-ifield): Update call to
+ define-full-ifield.
+ (define-normal-multi-ifield): Update call to define-full-multi-ifield.
+ (define-normal-hardware): Delete arg asm. New args indices, values,
+ handlers. Update call to define-full-hardware.
+ (define-simple-hardware,dsh): New pmacros.
+ (define-normal-operand): Update call to define-full-operand.
+ * fr30.cpu (f-*): Delete UNSIGNED attribute. Default is now UNSIGNED.
+ Specify INT/UINT mode instead.
+ (h-gr,h-cr): Use "indices" instead of "asm".
+ (h-dr,h-ps): Update keyword syntax.
+ (h-r13,h-r14,h-r15): Ditto.
+ (h-nbit,h-zbit,h-vbit,h-cbit): Use dsh instead of dnh.
+ (h-d0bit,h-d1bit,h-ibit,h-sbit,h-tbit,h-ccr,h-scr,h-ilm): Ditto.
+ (m4): Fix typo on HASH-PREFIX. Use "handlers" instead of "asm".
+ (reglist_low_ld,reglist_hi_ld,reglist_low_st,reglist_hi_st): Ditto.
+ * i960.cpu (f-*): Delete UNSIGNED attribute. Default is now UNSIGNED.
+ Specify INT/UINT mode instead.
+ (h-gr): Use "indices" instead of "asm".
+ (h-cc): Update keyword syntax.
+ * m32r.cpu (f-*): Delete UNSIGNED attribute. Default is now UNSIGNED.
+ Specify INT/UINT mode instead.
+ (h-hi16,h-slo16,h-ulo16): Update.
+ (h-gr,h-cr): Use "indices" instead of "asm".
+ (h-accum,h-cond,h-psw,h-bpsw,h-bbpsw,h-lock): Use dsh instead of dnh.
+ (h-accums): Update keyword syntax.
+ (hash,hi16,slo16,ulo16): Use "indices" instead of "asm".
+ * sparc.cpu (f-*): Delete UNSIGNED attribute. Default is now UNSIGNED.
+ Specify INT/UINT mode instead.
+ (h-gr-indices): New pmacro.
+ (h-gr32,h-gr64): Split up from h-gr.
+ (h-a): Update type spec. Use values instead of asm spec.
+ (h-icc-[cnvz],h-xcc-[cnvz]): Use dsh instead of dnh.
+ (h-y,h-annul-p): Ditto.
+ (h-asr): Update keyword spec.
+ (h-lo10,h-lo13,h-hi22): Update.
+ (get-freg-spec,set-freg-spec): New pmacros.
+ (h-fr32,h-fr64): Split up from h-fr.
+ (rdd): Comment out get/set specs.
+ (lo10,lo13,hi22): Use "handlers" instead of "asm".
+ * sparc32.cpu (h-psr): Use dsh instead of dnh.
+ (h-s,h-ps,h-pil,h-et,h-tbr,h-cwp,h-ag,h-ec,h-ef,h-fsr): Ditto.
+ * sparc64.cpu (f-*): Delete UNSIGNED attribute. Default is now
+ UNSIGNED. Specify INT/UINT mode instead.
+ (h-*): Use dsh instead of dnh where appropriate.
+ (h-ixcc): Update type spec. Use "values" instead of "asm".
+ (h-p,h-membarmask): Ditto.
+ (membarmask): Use "handlers" instead of "asm".
+
+ * hardware.scm (<hardware-base>): New member sem-name,type,indices,
+ values,handlers,getters,setters plus accessors.
+ (hw-mode-ok?,hw-default-mode): New procs.
+ (<hardware-base>): Rename method new-mode to mode-ok?
+ (<hardware-base>): New method get-index-mode.
+ (hw-index-mode): New proc.
+ (pc?): Delete, moved to operand.scm.
+ (address?): New proc.
+ (<hardware>): Delete.
+ (<hw-asm>): Definition moved here from desc.scm.
+ (keyword-parse): New proc.
+ (hardware-parsers): Delete.
+ (-parse-hw-type,-parse-hw-asm,-parse-hw-profile): Delete.
+ (-hw-parse-indices,-hw-parse-values,-hw-parse-handlers): New procs.
+ (-hw-parse-get,-hw-parse-set): New procs.
+ (-hw-parse): Delete args aasm,profile,extra. New args semantic-name,
+ indices,values,handlers,get,set. Rewrite.
+ (-hw-read-extra): Delete.
+ (-hw-read): Update.
+ (define-hardware): Don't add object if not selected.
+ (define-full-hardware): Ditto.
+ (current-hw-sem-lookup,current-hw-sem-lookup-1): New procs.
+ (<hw-register>): Member `type' moved to baseclass. Delete member
+ hw-asm.
+ (<hw-register>,parse!): Rewrite.
+ (<hw-register>): Delete methods get-rank,get-mode.
+ (<hw-register>): Method new-mode renamed to mode-ok?
+ (<hw-register>): New method get-index-mode.
+ (<hw-pc>,parse!): Rewrite.
+ (<hw-memory>): Member `type' moved to baseclass. Delete member hw-asm.
+ (<hw-memory>,parse!): Rewrite.
+ (<hw-memory>): Delete methods get-rank,get-mode.
+ (<hw-memory>): Method new-mode renamed to mode-ok?
+ (<hw-memory>): New method get-index-mode.
+ (<hw-immediate>): Member `type' moved to baseclass. Delete member
+ hw-asm.
+ (<hw-immediate>,parse!): Rewrite.
+ (<hw-immediate>): Delete methods get-rank,get-mode.
+ (<hw-immediate>): Method new-mode renamed to mode-ok?
+ (<hw-address>): Delete member hw-asm.
+ (<hw-address>,parse!): Rewrite.
+ (<hw-address>): Delete methods get-rank,get-mode.
+ (<hw-address>): Method new-mode renamed to mode-ok?
+ (hw-profilable?): Delete.
+ (hardware-init!): Delete hardware-parsers reference.
+ Update argument specs of command define-full-hardware.
+ (hardware-builtin!): Update definitions of hardware builtins.
+ * operand.scm (<operand>): New members hw-name,mode-name.
+ Delete member op-asm. New member handlers.
+ (<operand>,make!): Update.
+ (op:hw-name,op:mode-name,op:handlers): New procs.
+ (op:type): Rewrite.
+ (op:mode): Rewrite.
+ (<operand>): New method get-index-mode.
+ (<pc>,make!): Update.
+ (op:new-mode): Rewrite.
+ (operand-parsers): Delete.
+ (-operand-parse): Rewrite. Return #f if insn not selected.
+ (-op-read-extra): Delete.
+ (-operand-read): Update.
+ (define-operand,define-full-operand): Update.
+ (operand-init!): Delete operand-parsers reference.
+ Update syntax of define-full-operand command.
+
+ * insn.scm (-insn-parse): Rewrite. Return #f if insn not selected.
+ (define-full-insn): Update.
+ * minsn.scm (-minsn-parse): Rewrite. Return #f if insn not selected.
+ (define-full-minsn): Update.
+
+ * mode.scm (<mode>): New member class.
+ (mode:class): New proc.
+ (mode?): Rewrite.
+ (-mode-parse): New arg class.
+ (define-full-mode): Update.
+ (mode-find): Rewrite.
+ (mode-make-int,mode-make-uint): New procs.
+ (mode-init!): Update syntax of define-full-mode command.
+ (mode-builtin!): Update definitions of builtin modes.
+
+ * model.scm (<profile>): Delete.
+
+ * read.scm (keep-atlist?): New proc.
+ (keep-multiple?): New proc.
+ (<parser-list>): Delete.
+ (add-parser!,parse-spec!): Delete.
+
+ * rtl.scm (def-rtx-node): Prepend arg *tstate* to all handlers.
+ (def-rtx-syntax-node): Ditto.
+ (-rtx-traverse-debug?): New variable.
+ (tstate-make): New proc.
+ (tstate-expr-fn,tstate-op-fn,tstate-cond?,tstate-set?): New procs.
+ (tstate-new-cond?,tstate-new-set?): New procs.
+ (-rtx-traverse-normal): Delete args cond?,expr-fn,op-fn. New arg
+ tstate. All callers updated.
+ (-rtx-traverse-expr,-rtx-traverse-debug): Ditto.
+ (-rtx-traverse-list,-rtx-traverse-operands): Ditto.
+ (-build-operand!): Replace arg cond? with tstate.
+ (-build-reg-operand!,-build-mem-operand!): Ditto.
+ (-build-index-of-operand!): Update making of <operand> object.
+ (s-ifield): New arg tstate. All callers updated.
+ (hw:): New arg tstate. All callers updated. Replace call to
+ current-hw-lookup with current-hw-sem-lookup-1.
+ (s-index-of): New arg tstate. All callers updated.
+ (reg:,mem:): Ditto.
+ (-rtx-use-sem-fn?): New proc.
+ (s-unop,s-binop,s-shop): Use it. Only use semantic mode when using
+ semantic cover fns.
+ (s-convop): Only use semantic mode when using semantic cover fns.
+ (s-cmpop): Call -rtx-use-sem-fn?.
+ (s-cond,s-case): New arg tstate. All callers updated.
+ (s-parallel,s-sequence): Ditto.
+
+ * rtx-funcs.scm (set,set-quiet:): Use SETRTX to mark the set dest.
+
+ * types.scm (<scalar>): Rewrite implementation.
+ (<integer>): Delete.
+ (parse-type): Rewrite.
+
+ * utils-cgen.scm (parse-handlers): New proc.
+
+ * utils.scm (!=): New proc.
+
+Tue Feb 23 12:10:29 1999 Doug Evans <devans@canuck.cygnus.com>
+
+ * pmacros.scm (-pmacro-expand): Fix typo.
+
+1999-02-12 Doug Evans <devans@casey.cygnus.com>
+
+ * pmacros.scm (-pmacro-hex,-pmacro-upcase,-pmacro-downcase): New procs.
+ (pmacros-init!): Install builtins .hex, .upcase, .downcase.
+ * i960.cpu (build-hex2): New pmacro.
+ (insn-opcode): Simplify.
+ (insn-opcode2): Ditto.
+
+ * cgen-sim.scm (catch-with-backtrace): Comment out debugging printf.
+ * cgen-stest.scm (catch-with-backtrace): Ditto.
+
+1999-02-11 Doug Evans <devans@casey.cygnus.com>
+
+ * pmacros.scm (-pmacro-lookup): Renamed from -pmacro-ref.
+ All callers updated.
+ (-pmacro-invoke): New proc.
+ (-pmacro-sym,-pmacro-str): New procs.
+ (-pmacro-iota,-pmacro-map,-pmacro-apply): New procs.
+ (pmacros-init!): Install builtins .iota, .map, .apply.
+ * sparc.cpu (cc-tests): Add CC_NZ,CC_Z,CC_GEU,CC_LU aliases.
+ (h-fr): Simplify register name spec.
+ * sparc64.cpu (cond-move-1): New arg mnemonic. All callers updated.
+ * utils.scm (num-args-ok?): New proc.
+
+1999-02-10 Doug Evans <devans@casey.cygnus.com>
+
+ * pmacros.scm (-pmacro-error): New proc.
+ (-pmacro-expand): Use it.
+ (-pmacro-splice): New proc.
+ (pmacros-init!): Install new builtin .splice.
+
+ * sparc.cpu: Include sparc64.cpu when appropriate.
+ (f-mmask,f-simm11): Moved to sparc64.cpu.
+ (insn-fmt2): Add FLUSH,FLUSHW,IMPDEP1,IMPDEP2,MEMBAR,MOVCC.
+ (ANNUL attribute): Delete.
+ (test-* pmacros): New arg cc, all callers updated.
+ (uncond-br-sem,cond-br-sem): New arg cc, all callers updated.
+ * sparc32.cpu (atom-op): Moved to sparccom.cpu and renamed to
+ atomic-opc.
+ (ldstub,swap): Moved to sparccom.cpu.
+ * sparc64.cpu: Add more insns.
+
+1999-02-09 Doug Evans <devans@casey.cygnus.com>
+
+ * sim-cpu.scm (cgen-semantics.c): Replace CGEN_INSN_ATTR with
+ CGEN_ATTR_VALUE.
+ (cgen-sem-switch.c): Ditto.
+ * sim-decode.scm (-gen-idesc-decls): struct idesc definition
+ moved to cgen-engine.h.
+ (-gen-insn-sem-type): Delete, struct insn_sem mvoed to cgen-engine.h.
+ (-gen-idesc-init-fn,init_idesc): Lookup insn table via descriptor, not
+ global. Cache attributes and insn length in IDESC.
+ * sim-model.scm (-gen-cpu-defns): Generate new func @cpu@_prepare_run.
+ @cpu@_opcode renamed to @cpu@_get_idata.
+ (-gen-mach-defns,@mach@_init_cpu): Don't initialize IDESC table here,
+ done later underneath sim_resume.
+ (@mach@_mach): Record @cpu@_prepare_run.
+ * sim.scm (<hardware-base>,cxmake-get): New arg selector, all callers
+ updated.
+ (-hw-gen-set-quiet-pc): Ditto.
+ (-hw-cxmake-get,-hw-gen-set-quiet): Ditto.
+ (<hw-memory>,cxmake-get,gen-set-quiet): Ditto.
+ (<hw-addr>,cxmake-get): Ditto.
+ (<hw-iaddr>,cxmake-get): Ditto.
+ (<pc>,cxmake-get): Ditto.
+ (<operand>,cxmake-get,gen-set-quiet,gen-set-trace): Ditto.
+ (-op-gen-set-quiet,-op-gen-set-quiet-parallel): Ditto.
+ (-op-gen-set-trace,-op-gen-set-trace-parallel): Ditto.
+ (<hw-pc>,gen-write): Use hw-selector-default.
+ (<hw-register>,gen-write): Ditto.
+ (<hw-memory>,gen-write): Ditto.
+ (-gen-hw-index-raw,-gen-hw-index): Handle selector.
+ (-gen-hw-selector): New proc.
+
+ * desc.scm: New file.
+ * desc-cpu.scm: New file.
+ * opcodes.scm: Split up into several smaller files.
+ * opc-asmdis.scm: New file.
+ * opc-ibld.scm: New file.
+ * opc-itab.scm: New file.
+ * opc-opinst.scm: New file.
+ * Makefile.am (desc): New target.
+ (opcodes): Update args to cgen-opc.scm.
+ * Makefile.in: Rebuild.
+ * aclocal.m4: Rebuild.
+ * config.in: Rebuild.
+ * configure.in: Update arg to AC_INIT.
+ Update version number to 0.7.0. Change AM_EXEEXT to AC_EXEEXT.
+ Update AC_PREREG arg to 2.13. Change AM_PROG_INSTALL to
+ AC_PROG_INSTALL.
+ * configure: Rebuild.
+ * cgen-gas.scm: Update files to load.
+ * cgen-opc.scm: Ditto. Reorganize option letters.
+ * cgen-sim.scm: Update files to load.
+ * cgen-stest.scm: Ditto.
+ * dev.scm (cload): New app "DESC".
+ (load-opc): Update files to load.
+ (load-gtest,load-sim,load-stest): Ditto.
+
+ * attr.scm (bool-attr?): New proc.
+ (attr-list-enum-list): New proc.
+ (-attr-sort): Rewrite.
+ (attr-builtin!): Give ALIAS attribute a fixed index.
+ * utils-cgen.scm (gen-attr-enum-decl): Call attr-list-enum-list to
+ calculate attribute enum list.
+ (gen-attr-mask): Subtract CGEN_ATTR_BOOL_OFFSET from attribute's enum.
+
+ * insn.scm (-insn-parse): Renamed from parse-insn.
+
+ * hardware.scm (-hw-parse): New arg errtxt, all callers updated.
+ (-hw-read): Ditto.
+
+ * mode.scm (-mode-parse): Renamed from parse-mode.
+
+ * operand.scm (<operand>): New member `selector'.
+ (<operand>,make!): Use default selector.
+ (hw-selector-default): New variable.
+ (hw-selector-default?): New proc.
+
+ * pmacros.scm (pmacros-init!): New proc.
+ (-pmacro-{make,name,arg-spec,transformer,comment}): New procs.
+ (-env-set!): Delete.
+ (-pmacro-expand): New proc apply-macro.
+ Use it in scan-list,scan. Scan list first, then see if macro
+ invocation.
+ (define-pmacro): Rewrite.
+ * read.scm (-init-parse-cpu!): Call utils-init!,parse-init!.
+
+ * rtl.scm (-simplify-for-compilation): Ensure at least one mach
+ selected if (current-mach) seen.
+ (rtx?): Renamed from rtx-uneval?, all callers updated.
+ (<c-expr>,gen-set-quiet,gen-set-trace): New arg selector, all callers
+ updated.
+ (<c-expr-temp>,cxmake-get,gen-set-quiet,gen-set-trace): New arg
+ selector, all callers updated.
+ (hw:): New arg selector, all callers updated. Delete old comments
+ and code.
+ (reg:,mem:): Handle selectors
+ * rtx-funcs.scm (reg:): Handle selectors.
+
+ * read.scm: Renamed from cpu.scm.
+ (<command>): New class.
+ (<reader>): New member commands.
+ (reader-add-command!): New proc.
+ (reader-lookup-command): New proc.
+ (reader-error,-reader-process-expanded,reader-process): New procs.
+ (reader-read-file!): New proc.
+ (include): Call reader-read-file!.
+ (cmd-if): New proc.
+ (cpu-load): Call reader-read-file!.
+ * utils.scm (num-args): New proc.
+ * simplify.inc: New file.
+ * *.scm: Delete def-foo procs. Rewrite define-foo/define-full-foo
+ procs. Move define-normal-foo procs (and abbreviated forms) to
+ simplify.inc. Install define-foo/define-full-foo commands in foo-init!
+ routines.
+ * fr30.cpu: Include simplify.inc.
+ * fr30.opc: CGEN_OPCODE_DESC renamed to CGEN_CPU_DESC.
+ * i960.cpu: Include simplify.inc.
+ * m32r.cpu: Include simplify.inc.
+ * m32r.opc: CGEN_OPCODE_DESC renamed to CGEN_CPU_DESC.
+ (CGEN_PRINT_NORMAL): Use CGEN_BOOL_ATTR.
+ * sparc.cpu: Include simplify.inc.
+ * sparc.opc: CGEN_OPCODE_DESC renamed to CGEN_CPU_DESC.
+ * utils-cgen.scm (parse-error): Moved to read.scm.
+ (sanitize): Rewrite.
+ (utils-init!): New proc.
+
+1999-02-02 Doug Evans <devans@casey.cygnus.com>
+
+ * sparc.cpu: New file.
+ * sparc32.cpu: New file.
+ * sparc64.cpu: New file.
+ * sparccom.cpu: New file.
+ * sparc.opc: New file.
+
+1999-01-27 Frank Eigler <fche@cygnus.com>
+
+ * utils.scm (gen-copyright): New proc.
+
+1999-01-27 Doug Evans <devans@casey.cygnus.com>
+
+ Parameterize rtl parsing, rather than having lots of little handlers.
+ * rtl.scm (<rtx-func>): New members arg-types,arg-modes.
+ Delete member traverse.
+ (rtx:set-traverse!): Delete.
+ (-rtx-valid-types,-rtx-valid-matches): New variables.
+ (-rtx-func-lookup): Take symbol or <rtx-func> object as argument
+ instead of expression. All callers updated.
+ (def-rtx-node): New args arg-types,arg-modes.
+ (def-rtx-syntax-node): Ditto.
+ (def-rtx-dual-mode): Ditto.
+ (-rtx-macro-expand-list): Renamed from -rtx-macro-maybe-expand-list.
+ All callers updated.
+ (-rtx-macro-expand): Renamed from -rtx-macro-maybe-expand.
+ All callers updated.
+ (rtx-macro-expand): New proc.
+ (-rtx-traverse-check-args): Delete.
+ (-rtx-traverse-normal): Call -rtx-traverse-expr rather than calling
+ an rtx specific traverser.
+ (-rtx-any-mode?,-rtx-symornum?): New procs.
+ (-rtx-traverse-rtx-list,-rtx-traverse-error): New proc.
+ (-rtx-traverse-no-mode): Delete.
+ (-rtx-traverse-syntax-expr,-rtx-traverse-syntax-no-mode): Delete.
+ (-rtx-traverse-operands): Rewrite.
+ (-rtx-traverse-expr): Rewrite.
+ (rtx-traverse): Don't expand macros here, leave for caller to do.
+ (rtx-simplify): Delete.
+ (rtx-compile-time-constant?): Rewrite. Handle FALSE/TRUE for boolean
+ attributes.
+ (rtx-true?,rtx-false?): Ditto.
+ (-rtx-ref-type): Set dest is operand 1 now.
+ (-simplify-for-compilation): New proc.
+ (semantic-in-out-operands): Recognize regno as an alias for index-of.
+ Expand macros before calling rtx-traverse. Sort operands by name
+ to avoid unnecessary semantic formats.
+ (semantic-attrs): New proc.
+ (rtx-uneval?): Handle (<rtx-func> ...).
+ (s-boolifop): Delete arg mode. All callers updated.
+ * rtx-funcs.scm (all non-macros): Add arg-type and arg-mode specs.
+ (eq-attr): New arg obj.
+ (eq-attr:): Delete.
+ * m32r.cpu (rach): Update calls to andif.
+
+ * minsn.scm (-minsn-parse-expansion): Renamed from
+ parse-minsn-expansion.
+ (-minsn-parse): Renamed from parse-minsn.
+ (-minsn-read): Renamed from read-minsn.
+ (def-minsn): Don't check APPLICATION here.
+ (def-full-minsn): New proc.
+ (define-macro-insn): Check APPLICATION here. Expand macros.
+ (define-normal-macro-insn): Ditto.
+
+ * utils.scm (word-value): New arg start-lsb?.
+ (word-mask,word-extract): Ditto.
+ (split-bits,powers-of-2): Use integer-expt instead of expt.
+ (bit-set?): Handle 32 bit values (which are bignums).
+ (cg-logand,cg-logxor): New functions.
+ * ifield.scm (<ifield>,field-mask): Update call to word-mask.
+ (<ifield>,field-value): Update call to word-value.
+ (<ifield>,min-value): Use integer-expt instead of expt.
+ (<ifield>,max-value): Ditto.
+
+ * hardware.scm (<hw-register>,new-mode): Rename local mode to cur-mode.
+
+ * insn.scm (def-full-insn): Discard ALIAS insns if simulator.
+
+ Compute raw instruction format in addition to semantic based format.
+ * iformat.scm: Delete members cti?,sem-in-ops,sem-out-ops.
+ (<iformat> accessors): Rename accessors to ifmt-*.
+ (<sformat>): New class.
+ (fmt-enum): Renamed from fmt:enum.
+ (-ifmt-search-key): Rewrite.
+ (-sfmt-search-key): New proc.
+ (ifmt-analyze): Rename arg include-sem-operands? to compute-sformat?
+ Compute iformat and sformat search keys.
+ (ifmt-build): Update.
+ (sfmt-build): New proc.
+ (-ifmt-lookup-ifmt!,-ifmt-lookup-sfmt!): New procs.
+ (ifmt-compute!): Compute instruction format <iformat> based on
+ instruction fields alone. Compute new semantic format <sformat>
+ based on instruction fields and semantic information.
+ (ifmt:lookup): Delete.
+ * mach.scm (<arch>): New member sfmt-list, plus accessors.
+ (current-sfmt-list): New proc.
+ * insn.scm (<insn>): Rename member fmt-tmp to tmp.
+ Rename member fmt to ifmt. New members fmt-desc, sfmt.
+ (insn-length,insn-length-bytes): Update.
+ (insn:mask-length,insn:mask): Update.
+ (insn-lookup-op): Update.
+ * gas-test.scm (gas-test-analyze!): Update.
+ (gen-gas-test): Ditto.
+ * sim-test.scm (sim-test-analyze!): Update.
+ (gen-sim-test): Ditto.
+ * opcodes.scm (gen-operand-instance-table): Update.
+ (gen-operand-instance-ref): Ditto.
+ (max-operand-instances): Use heuristic if semantics not parsed.
+ (ifmt-opcode-operands): Renamed from fmt-opcode-operands.
+ (opcodes-analyze!): Only scan semantics of building operand instance
+ tables.
+ * sim-cpu.scm (*) Update calls to <iformat>/<sformat> accessors.
+ (-gen-extract-ifmt-macro): Renamed from -gen-extract-fmt-macro.
+ * sim-decode.scm (*) Update calls to <iformat>/<sformat> accessors.
+ (gen-sfmt-argvars-defns): Renamed from gen-ifmt-argvars-defns.
+ (gen-sfmt-argvars-assigns): Renamed from gen-ifmt-argvars-assigns.
+ * sim-model.scm (*) Update calls to <iformat>/<sformat> accessors.
+ * sim.scm (*) Update calls to <iformat>/<sformat> accessors.
+
+ * sim-decode.scm (usable-decode-bit?): Rename from decode-bit?
+ New arg lsb0? All callers updated.
+ (decode-bits): New arg lsb0?. All callers updated.
+ (opcode-slots): Update call to bit-set?. Call integer-expt instead
+ of expt.
+ (-gen-decode-bits): New arg lsb0?. All callers updated.
+ (build-slots): Call integer-expt instead of expt.
+ (build-decode-table-entry): Handle crossing word boundaries better.
+ (-gen-decode-switch): New arg lsb0?. All callers updated.
+ (-gen-extract-decls): Rename decode format entry from ifmt to sfmt.
+
+ * enum.scm (define-enum): Rewrite.
+ (define-normal-enum): Ditto.
+ (def-full-insn-enum): New proc.
+ (define-normal-insn-enum): Rewrite.
+
+ * attr.scm (<bitset-attribute>,gen-value-for-defn): Ensure result is
+ valid C.
+ (<{integer,enum}-attribute>,gen-value-for-defn): Ditto.
+
+
+ * Makefile.am (opcodes,sim-arch,sim-cpu): New targets.
+ (CLEANFILES): Add tmp-*.
+ * Makefile.in: Rebuild.
+
+ * doc/Makefile.am: New file.
+ * doc/Makefile.in: New file.
+ * doc/cgen.texi: New file.
+ * Makefile.am (SUBDIRS): Define.
+ * Makefile.in: Rebuild.
+ * configure.in: Create doc/Makefile.
+ * configure: Rebuild.
+
+1999-01-18 Doug Evans <devans@casey.cygnus.com>
+
+ * insn.scm (insn:syn): Delete.
+
+1999-01-15 Doug Evans <devans@casey.cygnus.com>
+
+ * fr30.cpu (model fr30-1): Add state variables load-regs,
+ load-regs-pending. Delete h-gr. Clean up operand names of all units.
+ * m32r.cpu (model m32r/d): Clean up operand names of u-exec.
+ (model m32rx): Ditto.
+ (addi): Simplify function unit usage spec.
+ (ld-plus): Rewrite operand names in function unit usage spec.
+ (mvtachi,mvtachi-a,mvtaclo,mvtaclo-a,st-plus,st-minus): Ditto.
+ * sim.scm (<unit>,gen-profile-code): Redo how operand names are
+ overridden. Allow operand to appear in input and output spec.
+ (<insn>,gen-profile-code): string-append -> string-list.
+
+ * ifield.scm (define-ifield): Call pmacro-expand.
+ (define-full-ifield,define-normal-ifield): Ditto.
+ (define-multi-ifield,define-normal-multi-ifield): Ditto.
+
+ * sim.scm (gen-argbuf-type): Keep leading part of ARGBUF same for
+ with-scache and without-scache cases.
+
+1999-01-14 Doug Evans <devans@casey.cygnus.com>
+
+ * fr30.cpu (fr30-1): Add state variable h-gr.
+ Add units u-cti, u-load, u-store, u-ldm, u-stm.
+ (all insns): First pass at providing cycle counts.
+ * sim.scm (<unit>,gen-profile-code): Only check for output operands
+ when initializing unit output operands, ditto for input operands.
+
+ * insn.scm (insn-length,insn-length-bytes): New procs.
+ * mach.scm (-adata-set-derived!): Use them.
+ * sim-cpu.scm (-gen-sem-case): Ditto.
+
+ * sim-cpu.scm (-gen-trace-record-type): PCADDR->IADDR.
+ (-gen-write-case): Ditto.
+ (gen-semantic-fn): Ditto. Split into two:
+ -gen-scache-semantic-fn and -gen-no-scache-semantic-fn. Fix bitrot
+ in non-scache case.
+ (-gen-all-semantic-fns): Renamed from -gen-all-semantics. Handle
+ scache/no-scache appropriately. All callers updated.
+ (-gen-sem-case): PCADDR->IADDR.
+ * sim.scm (gen-argbuf-type): PCADDR->IADDR.
+
+ * sim-decode.scm (*): Replace string-append,string-map with
+ string-list,string-list-map where the result is sufficiently large.
+ (-gen-decode-insn-table): Go back to simple version for non-scache
+ case: just record IDESC in decoder tables and leave field extraction
+ to the caller.
+ (-gen-decode-switch): Ditto.
+ (-gen-decode-fn): Ditto.
+ (-gen-extract-decls): Only emit format enum if with-scache?.
+ * sim-model.scm (-gen-model-insn-fn): Extract ifields here in
+ non-scache case.
+ (-gen-model-insn-fns): Don't emit model fns for virtual insns.
+ (-gen-insn-timing): Ditto.
+ * sim.scm (gen-argbuf-type): Only output sem_fields union in
+ with-scache case.
+
+ * sim.scm (-hw-gen-fun-get): Use GET_<H-NAME> macro.
+ (-hw-gen-fun-set): Use SET_<H-NAME> macro.
+
+1999-01-12 Doug Evans <devans@casey.cygnus.com>
+
+ * cpu.scm (keep-mach-validate!): New proc.
+ (include): New proc.
+
+ * mach.scm (current-arch-mach-name-list): New proc.
+ (-parse-arch-machs): Always return canonical form.
+ (def-arch): Validate user specified machs to be kept.
+ (def-mach-attr!): Simplify.
+
+ * opcodes.scm (-opcodes-build-operand-instance-table?): New global.
+ (option-init!): Initialize it.
+ (option-set!): Set it.
+ (gen-insn-table-entry): Emit 0 for operand instance ref if not
+ output operand instance tables.
+ (cgen-opc.in): Only output operand instance tables if asked to.
+
+ * sim.scm (option-init!,option-set!): Clarify returned value.
+
+ * sim.scm (gen-mach-bfd-name): Move from here.
+ * utils-cgen.scm: To here.
+
+1999-01-11 Doug Evans <devans@casey.cygnus.com>
+
+ * fr30.cpu (ilm): Fix comment field.
+ (cond-branch): Remove explicit setting of COND-CTI, let cgen
+ compute it.
+
+ * rtl.scm (rtx-simplify,rtx-compile-time-constant?): New procs.
+ (rtx-true?, rtx-false?): New procs.
+ * rtx-funcs.scm (annul): Rename vpc to pc.
+ (-rtx-traverse-if): Improve determination of whether then/else parts
+ are conditionally executed.
+
+ * sim.scm (-gen-argbuf-fields-union): Move definition of union to
+ outer level.
+ (gen-argbuf-type): Simplify generated definition (big sem_fields
+ union moved outside).
+
+1999-01-11 Ben Elliston <bje@cygnus.com>
+
+ * doc/porting.texi: New file.
+
+ * doc/intro.texi: New file.
+ (Layout): Use @example to insert preformatted ASCII text (such as
+ diagrams). @code is inappropriate here.
+
+1999-01-06 Doug Evans <devans@casey.cygnus.com>
+
+ * ifield.scm (-multi-ifield-read): Fix handling of insert/extract.
+
+ * m32r.opc (print_hash): Cast dis_info.
+
+ * sim-cpu.scm (-gen-hardware-types): Sanitize get/set macros.
+ * sim.scm (<sim-hardware>,make!): Emit a comment for user-written
+ get/set macros.
+
+1999-01-05 Doug Evans <devans@casey.cygnus.com>
+
+ * i960.cpu (f-br-disp): Remove RELOC attribute.
+ (f-ctrl-disp): Ditto.
+ (callx-disp): set-quiet -> set for (reg h-gr 2).
+ (callx-indirect,callx-indirect-offset): Ditto.
+
+ * Makefile.am (gas-test): Fix dependencies.
+ * Makefile.in: Rebuild.
+ * cgen-gas.asm: File creation args are -<uppercase-letter>.
+ * gas-test.scm (break-out-syntax,make-file-name): Delete.
+ (gas-test-analyze!): Use syntax-break-out.
+ * sim-test.scm (break-out-syntax,make-file-name): Delete.
+ (sim-test-analyze!): Use syntax-break-out.
+ (cgen-build.sh): Use gen-file-name.
+ (cgen-allinsn.exp): Compute and pass all machs to run_sim_test.
+ * insn.scm (syntax-break-out): New proc.
+ * utils.scm (gen-file-name): New proc.
+
+ * fixup.scm (nil,<?,<=?,>?): Delete.
+
+ * utils.scm (count-true): Rewrite.
+
+ * slib/sort.scm: Move sort.scm to slib directory.
+ * cpu.scm: Update.
+
+ * iformat.scm (ifmt-compute!): Record empty format.
+
+ * rtl.scm (semantic-in-out-operands): Simplify by moving several
+ internal procs outside. Handle expression register numbers.
+ Handle index-of.
+
+ * rtx-funcs.scm (annul): Rename new_pc to vpc.
+
+ * sim-cpu.scm (-gen-cpu-reg-access-defns): Define access fns for
+ every register.
+ (-gen-write-case): Pass vpc to SEM_BRANCH_FINI.
+ (gen-semantic-fn,-gen-sem-case): Ditto.
+ (cgen-cpu.c): Define WANT_CPU to @cpu@.
+ (cgen-semantics.c): Ditto.
+ * sim-decode.scm (-gen-extract-decls): Handle non-with-scache case.
+ (gen-ifmt-argvars-defns): New proc.
+ (gen-ifmt-argvars-assigns): New proc.
+ (-gen-all-extractors): Delete FMT_EMPTY case, now handled like others.
+ (-gen-decode-fn): Handle non-with-scache case.
+ (cgen-decode.c): Define WANT_CPU to @cpu@.
+ * sim-models.scm (-gen-mach-defns): Emit bfd name.
+ (cgen-model.c): Define WANT_CPU to @cpu@.
+ * sim.scm (gen-ifld-extract-argvar): New proc.
+ (<sim-hardware>,make!): Don't emit [GS]ET_H_FOO macros for elements
+ with FUN-ACCESS specified.
+ (hw-fun-access?): New proc, as <hardware-base>:fun-access? method.
+ (<hw-register>,gen-extract): New arg local?.
+ (<hw-address>,gen-extract): Ditto.
+ (-hw-cxmake-get): Handle non-with-scache case.
+ (-hw-gen-set-quiet): Ditto.
+ (<hw-address>,cxmake-get): Handle non-with-scache case.
+ (gen-op-extract-argvar): New proc.
+ (<operand>,gen-record-profile): Rewrite.
+ (<operand>,gen-profile-code): Rewrite.
+ (<unit>,gen-profile-code): Use -gen-argfld-ref.
+ (gen-argbuf-fields-union): New proc.
+ (gen-argbuf-type): Use it. Handle non-scache case.
+
+ * *.scm: class:foo procs renamed to class-foo.
+ * attr.scm (<attribute>): New member `for'.
+ (-attr-parse): New first value in list for default if
+ none specified.
+ (non-bool-attr-list,attr:add!): Delete.
+ (def-attr): Use current-attr-add!.
+ (atlist-attr-value-no-default): New proc.
+ (attr-lookup-default): Handle boolean attributes.
+ (gen-attr-enum): New proc.
+ (-attr-remove-meta-attrs-alist): New proc.
+ (attr-nub): New proc.
+ (current-attr-list-for): New proc.
+ (current-{ifld,hw,op,insn}-attr-list): New procs.
+ (attr-builtin!): New proc.
+ * cpu.scm (keep-obj?): Rewrite.
+ (-init-parse-cpu!): Call arch-init!.
+ (-install-builtin!): Call {attr,mode,ifield,insn}-builtin!.
+ (-finish-parse-cpu!): Call arch-finish!.
+ * enum.scm (enum-list,enum:add,enum:lookup): Delete.
+ (def-enum,def-full-enum): Use current-enum-add!.
+ (gen-obj-list-enums): New proc.
+ * hardware.scm (hw:add!,hw:lookup): Delete.
+ (def-hardware,def-hardware-ext): Use current-hw-add!.
+ (hw:std-attrs,hw:attr-list): Delete.
+ (hardware-builtin!): Define builtin hardware attributes.
+ * ifield.scm (ifld:add!,ifld:lookup): Delete.
+ (def-ifield,def-full-ifield): Use current-ifld-add!.
+ (ifld:std-attrs,ifld:attr-list): Delete.
+ (ifield-builtin!): New proc.
+ * insn.scm (insn:add!,insn:lookup): Delete.
+ (def-full-insn): Use current-insn-add!.
+ (insn:std-attrs): Delete.
+ (insn-builtin!): New proc.
+ * mach.scm (<arch>): New members attr-list,enum-list,op-list,
+ minsn-list.
+ (<arch-data>): New member machs.
+ (current-attr-list,current-enum-list): New procs.
+ (current-op-list,current-minsn-list): New procs.
+ (current-{attr,enum,ifld,op,hw,insn,minsn,cpu,mach,model}-add!): Ditto.
+ (current-{attr,enum,ifld,op,hw,insn,minsn,cpu,mach,model}-lookup):
+ Ditto.
+ (-parse-arch-machs): New proc.
+ (-arch-parse): New arg machs, all callers updated.
+ (-arch-read): Handle machs spec.
+ (def-arch): Define MACH attribute here.
+ (mach-init!,mach-finish!): Not here.
+ (cpu:add!,cpu:lookup): Delete.
+ (def-cpu): Use current-cpu-add!.
+ (<mach>): New member bfd-name.
+ (-mach-parse): New arg bfd-name, all callers updated.
+ (-mach-read): Handle bfd-name spec.
+ (mach:add!,mach:lookup): Delete.
+ (def-mach): Use current-mach-add!.
+ (def-mach-attr!): New proc.
+ (arch-init!): New proc.
+ (arch-finish!): New proc. Reverse all object lists here.
+ * minsn.scm (minsn-list,minsn-add!,minsn:lookup): Delete.
+ (def-minsn): Use current-minsn-add!. Ignore minsn if mach not kept.
+ (define-normal-macro-insn): Ignore minsn if mach not kept.
+ * mode.scm (mode-builtin!): New proc.
+ * model.scm (model:add!,model:lookup): Delete.
+ (def-model): Use current-model-add!.
+ * opcodes.scm (insn:attr-list): Delete.
+ (attr-bool-gen-decl,attr-bool-gen-defn): New procs.
+ (gen-attr-table-defn): Emit value for default.
+ (gen-attr-table-defns): Emit bool_attr. Emit ifield attr table.
+ (op:attr-list): Delete.
+ (gen-operand-decls,gen-insn-decls): New proc.
+ (compute-insn-attr-list): Delete.
+ (cgen-opc.h): Reorganize and simplify.
+ * operand.scm (-operand-list,operand-list,op:add,op:lookup): Delete.
+ (def-operand,def-full-operand): Use current-op-add!.
+ (op:std-attrs): Delete.
+ (operand-enum): Delete.
+ (operand-builtin!): Define builtin operand attrs.
+ * utils-cgen.scm (sanitize): Update calls to lookup procs.
+ (gen-attr-enum-decl): Use gen-obj-list-enums.
+ (gen-obj-attr-defn): Renamed from gen-attr-defn, all callers updated.
+ Rewrite.
+ * fr30.cpu (define-arch): Add machs spec.
+ (f-i4): SIGNED attribute -> !UNSIGNED.
+ (f-disp8,f-disp9,f-disp10,f-s10,f-rel9,f-rel12): Ditto.
+ (HASH-PREFIX): Define operand attribute.
+ (NOT-IN-DELAY-SLOT): Define insn attribute.
+ * i960.cpu (define-arch): Add machs spec.
+ * m32r.cpu (define-arch): Add machs spec.
+ (h-hi16): Remove UNSIGNED,SIGN-OPT attributes.
+ (HASH-PREFIX): Define operand attribute.
+ (FILL-SLOT): Define insn attribute.
+
+Thu Dec 17 17:15:06 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (stilm): Correct mask for and operation.
+
+1998-12-17 Doug Evans <devans@casey.cygnus.com>
+
+ * sim-test.scm (cgen-build.sh): Use `mach' to specify machs, not `cpu'.
+ Replace START/EXIT with start/pass.
+ (gen-sim-test): Delete ".text".
+
+Wed Dec 16 16:16:39 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (cond-branch): Conditional branches not allowed in delay slots.
+
+Tue Dec 15 17:30:01 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu: Add NOT-IN-DELAY-SLOT as appropriate.
+ (h-sbit): Make it FUN-ACCESS.
+ (h-gr): Reorder so that general regs are always printed by number.
+
+1998-12-14 James E Wilson <wilson@wilson-pc.cygnus.com>
+
+ * i960.cpu (flushreg): Use nop.
+
+1998-12-14 Doug Evans <devans@casey.cygnus.com>
+
+ * m32r.cpu (default-alignment): Specify.
+ * mach.scm (<arch-data>): New member default-alignment.
+ (adata:default-alignment): New proc.
+ (current-arch-default-alignment): New proc.
+ (-arch-parse): New arg default-alignment.
+ (parse-alignment): New proc.
+ (-arch-read): Handle default-alignment spec.
+
+ * rtx-funcs.scm (attr:): Pass attr-name through gen-c-symbol.
+
+ * insn.scm (f-%): Delete.
+ * sim-cpu.scm (gen-define-fields): Delete support for f-%. Can
+ be readded if proved useful.
+ (gen-extract-fields): Ditto. Use gen-ifetch.
+ * sim.scm (<hw-memory>,cxmake-get): Pass pc to GETMEM*.
+ (<hw-memory>,gen-set-quiet): Pass pc to SETMEM*.
+
+Mon Dec 14 16:20:59 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (div2): Set zbit properly when remainder not zero.
+
+1998-12-14 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu: Remove stub macros.
+ (div1): Shift bits from mdl into mdh. Don't use addc/subc.
+ (div2): Don't use addc/subc.
+
+1998-12-11 Doug Evans <devans@casey.cygnus.com>
+
+ * utils-cgen.scm (gen-obj-sanitize): Only catch spelling errors
+ if opcodes.
+
+Thu Dec 10 18:37:34 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (div0s,div0u,div1,div2,div3,div4s): Implemented.
+
+Thu Dec 10 12:28:53 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * cpu.scm (keep-all?): New proc.
+ (assert-keep-all): Use it.
+ * opcodes.scm (gen-ifmt-table-1): Use gen-obj-sanitize.
+ * utils-cgen.scm (gen-obj-sanitize): Handle macro-insns.
+ Check for spelling errors.
+
+1998-12-09 Doug Evans <devans@casey.cygnus.com>
+
+ * rtl.scm (s-convop): Call -rtx-sem-mode.
+
+Tue Dec 8 10:58:38 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * hardware.scm (-parse-hw-type): parse! no longer returns a result.
+ (-parse-hw-profile): Ditto.
+ (<hw-register>, parse!): Return `void' result.
+ (<hw-pc>, parse!): Ditto.
+ (<hw-memory>, parse!): Ditto.
+ (<hw-immediate>, parse!): Ditto.
+ (<hw-address>, parse!): Ditto.
+
+ * ifield.scm (-ifield-parse): Validate encode/decode fields.
+ (-ifld-parse-encode-decode): New proc.
+ (-ifld-parse-encode,-ifld-parse-decode): New proc.
+ (-multi-ifield-parse): Set encode/decode to #f.
+ (ifld:decode-mode): New proc.
+ * utils.scm (nub): Rewrite.
+ * operand.scm (op-nub): Rewrite.
+ * sim.scm (<ifield>, gen-type): Rewrite.
+ (-gen-ifld-argbuf-defn): New proc.
+ (gen-ifld-extract,gen-ifld-trace-extract): New procs.
+ (<sim-hardware>): Forward gen-trace-extract onto `type'.
+ Ditto for needed-iflds. gen-argbuf-defn renamed from gen-argbuf-elm.
+ (<hardware-base>): New method needed-iflds. gen-argbuf-defn
+ renamed from gen-argbuf-elm, return "". Rewrite gen-extract.
+ New method gen-trace-extract.
+ (<hw-register>): New method needed-iflds. gen-argbuf-defn renamed
+ from gen-argbuf-elm, return "" if not caching register address.
+ Rewrite gen-extract. New method gen-trace-extract.
+ (<hw-address>): New methods needed-iflds, gen-argbuf-defn,
+ gen-extract, gen-trace-extract, cxmake-get.
+ (<hw-iaddress>): New method cxmake-get.
+ (op-needed-iflds): New proc.
+ (<operand>): Delete methods gen-argbuf-elm, gen-extract.
+ (-gen-op-argbuf-defn): New proc.
+ (gen-op-extract): Renamed from op:extract.
+ (gen-op-trace-extract): Renamed from op:trace-extract.
+ (fmt-extractable-operands): Renamed from fmt-semantic-operands
+ and rewritten.
+ (gen-argbuf-elm): Rewrite.
+ * sim-decode.scm (-gen-record-args): Update.
+
+ * sim.scm (c-cpu-macro): Renamed from cpu-deref. All uses changed.
+
+ * pmacros.scm (-pmacro-expand): Handle procedural macros in
+ argument position. Flag symbolic macros in function position as
+ an error.
+ (define-pmacro): Handle quoting in definition of symbolic macros.
+ (pmacro-trace): Call -pmacro-expand, not -pmacro-ref.
+
+Tue Dec 8 13:06:44 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.opc (parse_register_list): Account for reverse masks
+ for load and store.
+ (print_register_list): Ditto.
+ (parse_low_register_list_ld): New function.
+ (parse_hi_register_list_ld): New function.
+ (parse_low_register_list_st): New function.
+ (parse_hi_register_list_st): New function.
+ (print_hi_register_list_ld): New function.
+ (print_hi_register_list_st): New function.
+ (print_low_register_list_ld): New function.
+ (print_low_register_list_st): New function.
+ * fr30.cpu (ldr15dr): Implement workaround.
+ (ldm0,ldm1,stm0,stm1): Implemented.
+
+1998-12-08 Doug Evans <devans@casey.cygnus.com>
+
+ * configure.in: Rename --with-hobbit to --with-cgen-hobbit.
+ * configure: Regenerate.
+ * Makefile.am (WITH_HOBBIT): Update.
+ (cgen-hob.c): Remove Makefile dependency.
+ (cgen.o): Depend on cgen-gh.h, config.h.
+ * Makefile.in: Regenerate.
+ * aclocal.m4: Regenerate.
+
+1998-12-07 James E Wilson <wilson@wilson-pc.cygnus.com>
+
+ * i960.cpu, i960.opc: New files.
+
+Mon Dec 7 14:30:24 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.opc (parse_register_number): New function.
+ (parse_register_list): New function.
+ (parse_low_register_list): Use parse_register_list.
+ (parse_hi_register_list): Use parse_register_list.
+ * fr30.cpu (sth): Fix assembler syntax. Implement more
+ insns.
+
+Fri Dec 4 16:07:13 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * sim-cpu.scm (cgen-sem-switch.c): Update definition of TRACE_RESULT.
+ * sim-decode.scm (-gen-record-args): Update call to TRACE_EXTRACT.
+ * sim.scm (-op-gen-set-trace): Update call to TRACE_RESULT.
+ (-op-gen-set-trace-parallel): Ditto.
+ (gen-argbuf-type): New ARGBUF members trace_p,profile_p;
+
+ * fr30.cpu (call,calld): Fix setting of pc.
+ (f-op5): Fix start bit number.
+
+Fri Dec 4 17:06:28 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (st): Fix operand ordering. Implement more
+ insns.
+
+Thu Dec 3 23:59:40 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * ifield.scm (ifld:mode,ifld:hw-type): New procs.
+ * iformat.scm (fmt-opcode-operands): Move to opcodes.scm.
+ (fmt-semantic-operands): Move to sim.scm.
+ * opcodes.scm (fmt-opcode-operands): Moved here from iformat.scm.
+ * operand.scm (<hw-index>): New member `name'. All builders updated.
+ (<hw-index>): New method get-name.
+ (op-profilable?): Moved to sim.scm.
+ (op-nub): New proc.
+ * sim.scm (fmt-semantic-operands): Moved here from iformat.scm.
+ (op-profilable?): Moved here from operand.scm.
+ (gen-extract-type): Delete.
+ (c-argfld-macro): Renamed from c-ifield-macro. All uses updated.
+ (-gen-argfld-ref): New proc.
+ (-gen-ifld-argfld-name): New proc.
+ (gen-ifld-argfld-ref): Renamed from -gen-ifld-ref. All uses updated.
+ (-gen-ifld-decoded-val): Renamed from -gen-ifld-raw-val.
+ (-gen-hw-index-argfld-name,-gen-hw-index-argfld-ref): New procs.
+ (<hardware-base>): Delete method gen-extract-type. New method
+ gen-argbuf-elm.
+ (<hw-register): Ditto. Update method gen-extract.
+ (<operand>, method gen-argbuf-elm): Rewrite.
+ * rtl.scm (semantic-in-out-operands): Handle (ifield f-name).
+ (s-cmpop): Fix handling of eq,ne for unsigned modes.
+ * rtx-funcs.scm (eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu): Update.
+
+ * sim-decode.scm (-gen-record-args): Tweak.
+
+ * sim.scm (gen-argbuf-elm): Handle case of all constant opcode fields.
+
+Thu Dec 3 14:23:27 1998 Dave Brolley <brolley@cygnus.com>
+
+ * doc/porting: Fix typo: gas->sim.
+ * fr30.opc (print_m4): New function.
+ * fr30.cpu: Implemented many insns.
+
+Thu Dec 3 00:03:16 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * rtl.scm (build-reg-operand!): Remove redundant setting of hw-name.
+
+ * fr30.cpu (f-rel9): Delete RELOC attribute.
+ (f-rel12): Add PCREL-ADDR attribute.
+ (label9): Make an h-iaddr, not h-uint. Delete asm print spec.
+ (label12): Delete PCREL-ADDR attribute. Make an h-iaddr, not h-sint.
+ * fr30.opc (print_label9): Delete.
+
+ * iformat.scm (ifmt-analyze): Check attributes derived from semantic
+ code for CTI indicators.
+ * insn.scm (insn-cti?): Simplify.
+ * utils-cgen.scm (atlist:cti?): New proc.
+
+1998-11-30 Doug Evans <devans@casey.cygnus.com>
+
+ * fr30.cpu (arch): default-insn-bitsize -> default-insn-word-bitsize.
+ (f-i20-4,f-i20-16,f-i20): New fields.
+ (i20): New operand.
+ (ldi8): Implement.
+ (ldi20): New insn.
+ (ldi32m): Delete.
+ (jmpd): Implement.
+ * fr30.opc (CGEN_DIS_HASH_SIZE,CGEN_DIS_HASH): Define in opc.h.
+ * m32r.cpu (arch): default-insn-bitsize -> default-insn-word-bitsize.
+ * mach.scm (arch-data): Ditto.
+ (current-arch-default-insn-word-bitsize): Renamed from
+ current-arch-default-insn-bitsize [ya, that's a pretty long name].
+ (-arch-read): Update.
+
+ * hardware.scm (hw:attr-list): Move here ...
+ * opcodes.scm: ... from here.
+
+ * ifield.scm (fld:bitrange): Delete.
+ (fld:word-offset,fld:word-length): New procs.
+ (ifield?): Use class-instance.
+ (<ifield>, method field-start): Rewrite.
+ (ifld:enum): New proc.
+ (<ifield>, methods field-mask,field-value): Rewrite.
+ (-ifield-parse): Rewrite.
+ (<multi-ifield> support): Rewrite.
+ (ifld-beyond-base?): Rewrite.
+ (ifld:std-attrs): New variable.
+ (ifld:attr-list): New proc.
+ * iformat.scm (-compute-insn-mask): Rewrite.
+ * insn.scm (-parse-insn-format): New arg errtxt, all callers updated.
+ Simplify.
+ (-parse-insn-format-symbol,-parse-insn-format-list): New procs.
+ * opcodes.scm (<hardware>): No longer forward gen-insert,gen-extract
+ onto type.
+ (<operand>): Ditto. Forward onto index instead.
+ (gen-ifld-decls,gen-ifld-defns): New procs.
+ (ifld:insert,ifld:extract): New procs.
+ (<ifield>): New methods gen-insert, gen-extract.
+ (<multi-ifield>): Ditto.
+ (<hw-index>): Forward gen-insert,gen-extract onto value.
+ (<hw-asm>): Delete insert/extract support.
+ (<hw-register,hw-memory,hw-immediate>): Ditto.
+ (gen-hash-defines): Use string-list.
+ Define CGEN_MAX_IFMT_OPERANDS.
+ (gen-switch): Use string-list,string-list-map.
+ (gen-fget-switch,gen-fset-switch): Use string-list.
+ (gen-parse-switch,gen-insert-switch): Ditto.
+ (gen-extract-switch,gen-print-switch): Ditto.
+ (gen-insert-switch,gen-extract-switch): New local `total_length'.
+ (gen-ifmt-table-1,gen-ifmt-table): New procs.
+ (gen-ifmt-entry): Renamed from gen-iformat-entry, rewrite.
+ (gen-ivalue-entry): New proc.
+ (gen-insn-table-entry): Use string-list. Update iformat,ivalue
+ computation. Use 0 for operand ref table if ALIAS insn.
+ (gen-minsn-table-entry): Use string-list.
+ (gen-macro-insn-table): Temporarily emit format tables for ALIAS insns.
+ (gen-opcode-open): Record address of ifield table.
+ (cgen-opc.h): Call gen-ifld-decls.
+ (cgen-opc.in): Call gen-ifld-defns, gen-ifmt-table.
+ * types.scm (<bitrange>): New members word-offset,word-length.
+ Delete member total-length. Delete methods start,mask,value.
+ (bitrange:word-offset,bitrange:word-length): New procs.
+ * sim-cpu.scm (gen-define-fields): Simplify.
+ (gen-extract-fields): Simplify.
+ * sim.scm (<ifield>, gen-ifld-extract): Rewrite.
+ (<ifield>): New methods gen-ifld-extract-decl.
+ Delete method gen-ifld-extract-beyond.
+ (<multi-ifield>): New methods gen-ifld-extract-decl.
+ (<multi-ifield>, method gen-ifld-extract): Implement.
+ (-gen-ifld-extract-base,-gen-ifld-extract-beyond): New procs.
+ (gen-ifld-exttact,gen-ifld-extract-beyond): Delete.
+
+ * rtl.scm (-rtx-traverse-no-mode): Process operands.
+ (-rtx-traverse-syntax-no-mode): New proc.
+ (semantic-in-out-operands): Watch for `delay' and add DELAY-SLOT attr.
+ (s-ifield): New proc.
+ (s-shop): Don't prepend `unsigned' for unsigned modes.
+ * rtx-funcs.scm (ifield): New rtx function.
+ (ref,symbol): Use standard -rtx-traverse-syntax-no-mode.
+ (delay): New rtx function.
+ * insn.scm (insn:std-attrs): Add DELAY-SLOT.
+
+ * cos.scm (-elm-make-method-getter): Fix typo.
+
+ * utils.scm (backslash): Handle lists of strings.
+
+Thu Nov 26 11:47:29 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (f-rel9): Correct for pc+2.
+ (label9): Use print_label9.
+ * fr30.opc (print_label9): New function.
+
+Tue Nov 24 11:19:35 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu: Change $r13,$r14,$r15 to uppercase.
+ * fr30.opc (parse_low_register_list): Renamed.
+ (parse_hi_register_list): Renamed.
+ (print_hi_register_list): Renamed.
+ (print_low_register_list): Renamed.
+
+Mon Nov 23 18:26:36 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (f-rel9): Now a pc relative offset.
+
+1998-11-23 Doug Evans <devans@casey.cygnus.com>
+
+ * opcodes.scm (op-asm): Move to here, from operands.scm.
+ (<op-asm>, method parse!): Validate arguments.
+ (<operand>, method gen-function-name): Fix thinko.
+ * operand.scm (<operand>, method make!): Don't set op-asm here.
+ * utils.scm (list-elements-ok?): New proc.
+
+ * opcodes.scm: Clean up pass.
+
+1998-11-20 Doug Evans <devans@tobor.to.cygnus.com>
+
+ * fr30.cpu (int): Defer saving of ps,pc and setting ibit,sbit to
+ the fr30_int function.
+ (h-cr): Remove PROFILE,CACHE-ADDR attributes.
+ (h-dr): Add FUN-ACCESS attribute.
+
+1998-11-20 James E Wilson <wilson@wilson-pc.cygnus.com>
+
+ * sim-model.scm (-gen-mach-defns): Use gen-sym instead of obj:name
+ for C symbol for models array.
+
+Thu Nov 19 15:57:45 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.opc (parse_reglist_low): New function.
+ (parse_reglist_hi): New function.
+ (print_reglist_low): New function.
+ (print_reglist_hi): New function.
+ * fr30.cpu: Finish remaining insn stubs.
+
+1998-11-19 Doug Evans <devans@tobor.to.cygnus.com>
+
+ * sim.scm (-gen-extract-word): Handle fields shorter than entire word.
+
+ * fr30.cpu (ldi32m): Don't use for disassembly.
+
+Wed Nov 18 21:34:41 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (int): Implement it.
+
+1998-11-18 Doug Evans <devans@casey.cygnus.com>
+
+ * rtx-funcs.scm (nop): Fix C code.
+
+ * rtl.scm (semantic-in-out-operands): Fix setting of sem-attrs.
+
+ * fr30.cpu (f-i32): New ifield.
+ (i32): New operand.
+ (ldi32): New insn.
+ (ldi32m): New macro insn.
+ (inte): Provide simple version for now.
+
+ * sim-arch.scm: New file.
+ * sim.scm: Move architecture support generation to sim-arch.scm.
+ * cgen-sim.scm: Load sim-arch.scm.
+ * dev.scm: Ditto.
+
+ * hardware.scm (pc?) New proc.
+ (class <hardware-base>): Rewrite method 'pc?.
+ (class <hardware>): Forward 'pc? to the hardware type.
+ (class <hw-pc>): New method 'pc?.
+
+ Add support for variable length ISAs.
+ * ifield.scm (ifld-beyond-base?): New proc.
+ * m32r.cpu: Remove integral-insn? spec.
+ * mach.scm (arch:derived,arch:set-derived!): New procs.
+ (arch:app-data,arch:set-app-data!): New procs.
+ (class <arch>): New members derived, app-data.
+ (class <cpu>): Delete member integral-insn?.
+ (cpu:integral-insn?): Delete.
+ (-cpu-parse): Delete arg integral-insn?. All callers updated.
+ (-cpu-read): Delete integral-insn? support.
+ (state:decode-assist): Delete.
+ (state:int-insn?): Delete.
+ (<derived-arch-data>): New class.
+ (-adata-set-derived!): New proc.
+ (mach-finish!): Call it.
+ * opcodes.scm (<hw-asm>, method gen-extract): Pass pc to C handler.
+ (gen-operand-instance): Add COND_REF support.
+ (gen-operand-instance-table): Ditto.
+ (gen-hash-defines): Update.
+ (gen-extract-switch): Update type of `insn_value' arg.
+ (gen-opcode-open): Update type of `value' arg of dis_hash_insn.
+ * rtl.scm (-rtx-ref-type): Renamed from -rtx-set?. All callers
+ updated.
+ (semantic-in-out-operands): Compute UNCOND-CTI,COND-CTI from rtl.
+ * sim-cpu.scm (gen-define-fields): Create vars to hold insn value
+ beyond the base insn (for large insns).
+ (-gen-extract-beyond-var-list): New proc.
+ (gen-extract-fields): Handle large insns.
+ (-gen-write-case): Update sem_arg computation.
+ Update initial vpc computation.
+ (gen-semantic-fn): Ditto. Update type of `insn'.
+ (-gen-sem-case): Update sem_arg computation.
+ Update initial vpc computation.
+ * sim.scm (<ifield>, gen-ifld-extract): Renamed from `extract'.
+ (-gen-extract-word): New proc.
+ (<ifield>): New method gen-ifld-extract-beyond.
+ (gen-ifld-extract-beyond): New proc.
+ * types.scm (bitrange-overlap?): New proc.
+
+ * utils.scm (bits->bytes): New proc.
+ (bytes->bits): New proc.
+
+ Move extraction support into decoder.
+ * sim-cpu.scm (-gen-record-args,-gen-record-profile-args,
+ -gen-extractor,-gen-all-extractors,cgen-extract.c): Move extraction
+ support to sim-decode.scm.
+ * sim-decode.scm (-gen-decode-insn-table): Change decoder data to
+ be array of IDESC,FMT entries. Make the array const.
+ (-gen-gcc-label-table): Make array const.
+ (-gen-decode-switch): Branch to extraction code after insn has been
+ identified.
+ (-gen-decode-insn-globals): Delete extract handler from
+ @cpu@_insn_sem.
+ (gen-decode-fn): Add extraction support.
+ (-gen-sem-fn-decls): Delete extraction fn decls.
+ (-gen-idesc-decls): Update @cpu@_decode decl.
+ (-gen-idesc-init-fn): Delete extraction support.
+ (-gen-extract-decls): New proc.
+
+ * sim-cpu.scm (cgen-sem-switch.c): Update switch test.
+ (sim-finish!): Surround pbb only code with #if WITH_SCACHE_PBB.
+
+ * sim-decode.scm (build-decode-table-entry): New arg invalid insn.
+ All callers updated.
+ (table-entry:make): Record insn value as insn object, not name.
+ All uses updated.
+
+ * hobbit.scm (path_basename): Renamed from `basename' to avoid
+ collision with C function.
+ (path_dirname): Similarily.
+ * hobbit.c,hobbit.h: Rebuild.
+
+Wed Nov 18 11:26:17 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu (dir2r15-predec-stub): Reference to R15 must be indirect.
+
+Mon Nov 16 19:19:50 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu: Implement more instruction stubs.
+
+Thu Nov 12 19:20:28 1998 Dave Brolley <brolley@cygnus.com>
+
+ * fr30.cpu: Implement more instruction stubs.
+
+Tue Nov 10 10:53:55 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * rtl.scm (-rtx-expr-mode-name): Handle sequence locals.
+
+ * rtx-funcs.scm (zflag:,zflag,nflag:,nflag): New rtx fns.
+
+ * operand.scm (<pc>, method make!): FAKE renamed to SEM-ONLY.
+ (op:std-attrs): Ditto.
+ * opcodes.scm (gen-operand-instance): Ditto.
+ (gen-switch): Ditto.
+ * m32r.cpu (condbit,accum): Update.
+ * fr30.cpu (nbit,vbit,zbit,cbit): Update.
+
+Mon Nov 9 14:30:51 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * enum.scm (-enum-read): Fix typo.
+
+ * iformat.scm (-ifmt-search-key): Simplify a little.
+
+Mon Nov 9 12:07:56 1998 Dave Brolley <brolley@cygnus.com>
+
+ * doc/porting: semantics.c -> sem.c.
+ * Makefile.in: Regenerate.
+ * fr30.cpu (add): Change ADD to add. Add more registers and set
+ status bits on 'add' instruction.
+
+Fri Nov 6 18:15:05 1998 James E Wilson <wilson@wilson-pc.cygnus.com>
+
+ * sim.scm (-gen-arch-model-decls): Default MAX_UNITS to 1 instead
+ of 0.
+
+Fri Nov 6 17:43:16 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * minsn.scm (minsn:enum): Update, call current-arch-name.
+
+ * pmacros.scm (-pmacro-expand): Make `cep' a variable.
+
+ * Makefile.am (CGEN_HOB_INPUT_FILES): Add pmacros.scm,enum.scm,
+ mach.scm,model.scm,types.scm,ifield.scm,minsn.scm.
+ (ARCH,CGEN,CGENFLAGS): New variables.
+ (gas-test,sim-test): New rules.
+ * Makefile.in: Rebuild.
+ * configure.in (arch): Define.
+ * configure: Rebuild.
+
+ * cgen-hob.scm (*UNSPECIFIED*): Renamed from UNSPECIFIED.
+ * All .scm files: Ditto.
+
+ * dev.scm: Fix gas-test call to cpu-load.
+ * gas-test.scm: Clean up pass to remove bit-rot.
+ * sim-test.scm: Ditto.
+
+ * enum.scm (read-enum): Fix typo in `vals' handling.
+
+ * hardware.scm (-parse-hw-type): Fix typo.
+ (parse-hardware): Rename `asm' to `aasm' to avoid GCC reserved word.
+ (def-hardware,define-normal-hardware): Ditto.
+
+ * hobbit.scm (*case-sensitive-flag*): New configuration variable.
+ (display-var): Use it.
+ * hobbit.c: Rebuild.
+ * hobbit.h: Rebuild.
+
+ * ifield.scm (-ifield-read): Rename local `length' to `length-' to
+ avoid hobbit problem.
+ * mach.scm (-cpu-read): Rename local `parallel-insns' to
+ `parallel-insns-' to avoid hobbit problem.
+
+Fri Nov 6 17:19:12 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * m32r.opc (parse_hi16): Fix call to cgen_parse_address.
+ (parse_slo16,parse_ulo16): Ditto.
+ * opcodes.scm (<hw-address>, method gen-parse): Ditto.
+
+Thu Nov 5 13:04:53 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * Makefile.am (GUILELDFLAGS,GUILELDADD): New variables.
+ (cgen_LDFLAGS,cgen_LDADD,hob.x): Use them.
+ * Makefile.in: Rebuild.
+ * insn.scm (define-normal-insn): Expand pmacros.
+ * mode.scm (<mode>): New member `host?'. All uses updated.
+ (mode:host?): New proc.
+ * rtl.scm (define-rtx-node): Make a syntax proc, not a macro.
+ (define-rtx-syntax-node,define-rtx-macro-node): Ditto.
+ (define-rtx-dual-mode): Ditto.
+ (s-index-of): New proc.
+ (s-unop): Use plain C for host mode operations.
+ (s-binop,s-shop,s-boolifop,s-cmpop): Ditto.
+ * rtx-funcs.scm (index-of): New rtx function.
+ * sim.scm (<hw-index>): New method cxmake-get.
+
+Wed Nov 4 23:58:08 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * sim-cpu.scm (-gen-engine-decls): Delete.
+
+Wed Nov 4 18:40:47 1998 Dave Brolley <brolley@cygnus.com>
+
+ * doc/rtl (Example): Correct Typo.
+ * doc/porting: Add 'make dep' step to opcodes port instructions.
+ * fr30.opc: New file.
+ * fr30.cpu: New file.
+
+Wed Oct 28 13:36:15 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * configure.in: Handle guile $exec_prefix = $prefix/foo.
+ * Makefile.am (GUILEINCDIR): New variable.
+ (INCLUDES): Use it.
+ * configure: Regenerate.
+ * Makefile.in: Ditto.
+ * aclocal.m4: Ditto.
+
+Mon Oct 19 13:19:34 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * sim-cpu.scm (cgen-extract.c): Delete #include cpu-sim.h
+ (cgen-semantics.c): Ditto.
+ * sim-decode.scm (cgen-decode.c): Delete #include cpu-sim.h,cpu-opc.h.
+ * sim-model.scm (cgen-model.c): Ditto.
+ * sim.scm (cgen-arch.h): Delete #include @arch@-opc.h.
+ (cgen-arch.c): Delete #include cpu-sim.h,cpu-opc.h.
+
+ * opcodes.scm (read-cpu.opc): Handle empty file.
+
+ * cos.scm (-elm-make-method-setter): Fix typo.
+
+ * cpu.scm (-init-parse-cpu!): Call types-init!.
+ (-finish-parse-cpu!): Call types-finish!.
+ * ifield.scm (<ifield>): Delete members start,length.
+ New member bitrange.
+ (<ifield>, methods field-start,field-length): Update.
+ (fld:start): New arg insn-len. All callers updated.
+ (<ifield>, methods field-mask,field-value): Update.
+ (-ifield-parse): Update.
+ (ifield-init!): Update.
+ * iformat.scm (compute-insn-length): Simplify.
+ (compute-insn-mask): Update.
+ * insn.scm (insn:value): Update.
+ * mach.scm (<arch-data>): New members default-insn-bitsize,insn-lsb0?.
+ (current-arch-default-insn-bitsize): New proc.
+ (current-arch-insn-lsb0?): New proc.
+ (-arch-parse,-arch-read): Update.
+ (<cpu>): New member file-transform.
+ (-cpu-parse,-cpu-read): Update.
+ * opcodes.scm (<hw-asm>, method gen-extract): Pass ex_info to handler.
+ (gen-hash-defines): Define CGEN_INSN_LSB0_P.
+ (CGEN_INT_INSN_P): Renamed from CGEN_INT_INSN.
+ (gen-insert-switch): Update args of @arch@_cgen_insert_operand.
+ (gen-extract-switch): Update args of @arch@_cgen_extract_operand.
+ (gen-opcode-open): Set CGEN_OPCODE_INSN_ENDIAN.
+ * operand.scm (op:start): Update call to field-start method.
+ * sim-decode.scm (opcode-slots): New arg lsb0?.
+ (fill-slot!,build-slots): Ditto.
+ (build-decode-table-entry,build-decode-table-guts): Ditto.
+ (gen-decoder-table,gen-decoder-switch,gen-decoder): Ditto.
+ (gen-decode-fn): Ditto.
+ (cgen-decode.c): Update call to gen-decode-fn.
+ * sim.scm (gen-argbuf-type): Move `semantic' to cpu specific part.
+ (-gen-cpu-header,-gen-cpuall-includes): New procs.
+ (cgen-cpuall.h): Call -gen-cpuall-includes.
+ * types.scm (<bitrange>): New class.
+ (types-init!,types-finish!): New procs.
+ * utils-cgen.scm (parse-number): New proc.
+ (parse-boolean): New proc.
+ * utils.scm (word-value): Renamed from shift-bits, rewrite.
+ (word-mask): Rewrite.
+ * m32r.cpu (define-arch): New fields default-insn-bitsize,insn-lsb0?.
+ (m32rxf): New field `file-transform'.
+ * m32r.opc (my_print_insn): print_int_insn -> print_insn.
+
+ * hobbit.h: Fix include file name.
+
+Fri Oct 9 16:58:10 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * slib: New directory of slib files used by cgen/hobbit.
+ * hobbit.scm: New file.
+ * hobbit.c: New file.
+ * hobbit.h: New file.
+ * hobscmif.h: New file.
+ * hob-main.c: New file.
+ * hobslib.scm: New file.
+ * hob.sh: New file.
+ * Makefile.am: Add support for compiling hobbit, and using compiled
+ version of hobbit to compile cgen.
+ * Makefile.in: Regenerate.
+ * configure.in: Support --with-hobbit.
+ * configure: Regenerate.
+ * acconfig.h (WITH_HOBBIT): Add.
+ * config.in: Regenerate.
+
+ * rtl.scm: New file, was cdl-c.scm.
+ Definition of rtx funcs moved to rtx-funcs.scm.
+ (semantic-in-out-operands): Rewrite to compute object form of
+ semantic code.
+ * rtx-funcs.scm: New file.
+
+ * cgen-gh.c: #include "config.h".
+ (gh_cadddr,gh_cddddr): New fns.
+ (cgh_vector_to_list): New fn.
+ (cgh_map1,cgh_map2,cgh_map1_fn2): Rewrite.
+ (cgh_init): Prefix qsort procs with "cgh-".
+ * cgen-gh.h (gh_cadddr,gh_cddddr,cgh_vector_to_list): Declare.
+ * cgen.c: #include "config.h".
+
+ * attr.scm (bitset-attr?): New proc.
+ (<bitset-attribute>, method parse-value): Value syntax changed from
+ (val1 val2 ...) to val1,val2,....
+ (<bitset-attribute>): New method gen-value.
+ (<integer-attribute>): New method gen-value.
+ (<enum-attribute>): New method gen-value.
+ * cpu.scm: Disable debugging evaluator if (not (defined? 'DEBUG-EVAL)).
+ (<reader>): New class.
+ (CURRENT-ARCH,CURRENT-READER): New globals.
+ (keep-mach?): Move here from mach.scm.
+ * mach.scm (arch,arch-comment,arch-default-mach): Delete.
+ (<arch>): New class.
+ (<arch-data>): New class.
+ (<cpu>): Make subclass of <ident>.
+ (*ENDIAN* variables): Delete.
+ (process-state-vars): Delete.
+ (mach-finish!): Add `base' value to MACH attribute.
+ * hardware.scm (<hardware>): Make subclass of <ident>.
+ (hw:std-attrs): New global.
+ (hw-profilable?): New proc.
+ * ifield.scm (<ifield>): Make subclass of <ident>.
+ (sort-ifield-list): Move here from iformat.scm.
+ * iformat.scm (<iformat>): Renamed from <insn-format>.
+ Make subclass of <ident>.
+ (-ifmt-search-key): Include cti? in categorization of formats.
+ (ifmt-analyze): Compile semantics (turn to object form).
+ * insn.scm (<insn>): Make subclass of <ident>.
+ New member compiled-semantics.
+ (insn:std-attrs): Add SKIP-CTI, VIRTUAL.
+ * mode.scm (<mode>): Make subclass of <ident>.
+ (UBI): Delete.
+ * model.scm (<unit>): Make subclass of <ident>.
+ New members inputs,outputs.
+ (<model>): Make subclass of <ident>. New member state.
+ (-unit-parse): Parse inputs,outputs.
+ (<iunit>): New class.
+ (-insn-timing-parse-model): New proc.
+ (parse-insn-timing): Function unit spec rewritten.
+ * operand.scm (<operand>): Make subclass of <ident>.
+ New members sem-name,num,cond? New method gen-pretty-name.
+ (hw-index-scalar): New global.
+ (op-nub-hw): Move here from rtl.scm.
+ (op:lookup-sem-name,op-profilable?): New procs.
+ * pmacros.scm: Rewrite to pass through hobbit.
+ * utils-cgen.scm (gen-attr-defn): Simplify using new gen-value method.
+ * utils.scm (logit): Make a macro.
+ (bit-set?): Rewrite.
+ (high-part): Rewrite.
+
+ * m32r.cpu (define-arch): Move to top of file.
+ (cpu family m32rbf): Renamed from m32rb.
+ (model m32r/d): Function unit spec rewritten.
+ (all insns): Ditto. Replace UBI with BI.
+
+ * opcodes.scm (gen-attr-table-decls): Declare
+ @arch@_cgen_hw_attr_table.
+ (gen-attr-table-defns): Generate hw attribute table.
+
+ * sim-cpu.scm (-gen-engine-decls): New proc.
+ (-gen-model-decls): New proc.
+ (gen-parallel-exec-type): Add new member `written' to struct parexec.
+ (-gen-record-args): Add SEM_BRANCH_INIT_EXTRACT if cti insn.
+ (-gen-record-profile-args): Simplify.
+ (-gen-parallel-sem-case): Delete.
+ (gen-semantic-fn): Emit SEM_BRANCH_{INIT,FINI} if cti insn.
+ New local `written'. Delete profiling code.
+ (-gen-sem-case): Ditto.
+ (-uncond-written-mask,-any-cond-written?): New procs.
+ (cgen-sem-switch.c): Include duplicates of insns that can be executed
+ parallelly or serially, and write-back handlers for all parallel insns.
+ * sim-decode.scm (-gen-decode-insn-globals): Add parallel write-back
+ support to initialization of struct insn_sem.
+ (-gen-idesc-decls): Add parallel write-back support to struct idesc.
+ (-gen-insn-sem-type): Add parallel write-back support to struct
+ insn_sem.
+ (-gen-idesc-init-fn): Add support for virtual insns.
+ Add parallel write-back support.
+ * sim-model.scm (gen-model-profile-fn): Delete
+ (-gen-model-fn-decls): New proc.
+ (-gen-model-insn-fn,-gen-model-insn-fns): New procs.
+ (-gen-model-init-fn): New proc.
+ (-gen-mach-defns): Initialize insn-name lookup and fast/full engine_fn
+ members in @mach@_init_cpu.
+ (cgen-model.c): Generate model handlers for each insn.
+ * sim.scm (gen-define-field-macro): Cti insns handled differently.
+ (<hw-pc>): New method gen-write.
+ (<hw-register>, method gen-write): New arg `mode'.
+ (<hw-register>): Delete method gen-record-profile!.
+ New method gen-profile-index-type.
+ (<hw-memory>, method gen-write): New arg `mode'.
+ (<hw-address>, method gen-extract): Delete.
+ (<hw-address>, method gen-write): New arg `mode'.
+ (<hw-index>, method get-write-index): Rewrite.
+ (<pc>, method cxmake-get-direct): Delete.
+ (<pc>): New method cxmake-get. Comment out methods
+ gen-set-quiet,gen-set-trace.
+ (<operand>): New methods gen-argbuf-elm,gen-profile-argbuf-elm,
+ gen-profile-index-type,gen-profile-code.
+ Delete method gen-pretty-name. Rewrite method gen-write.
+ Delete method cxmake-get-direct.
+ (-op-gen-set-trace): Update `written'.
+ (-op-gen-set-trace-parallel): Ditto.
+ (-gen-hw-index-raw,-gen-hw-index): Handle strings.
+ (gen-cpu-insn-enum-decl): Add extra entries for parallel
+ insns and their write-back handlers.
+ (insn-op-lookup): New proc.
+ (<unit>): New method gen-profile-code.
+ (<iunit>): New method gen-profile-code.
+ (gen-argbuf-elm): Add profiling elements.
+ (gen-argbuf-type): Define cti insns separately in their own struct.
+ Add member `addr_cache' to this struct. Add entries for pbb virtual
+ insns. Move semantic entries here from struct scache.
+ Delete everything from struct scache except argbuf.
+ (<insn>, method gen-profile-locals): Rewrite.
+ (<insn>, method gen-profile-code): Rewrite.
+ (sim-finish!): Create virtual pbb insns.
+
+Tue Sep 15 15:22:02 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * m32r.cpu (h-cr): Add bbpc,bbpsw.
+ (h-sm,h-bsm,h-ie,h-bie,h-bcond,h-bpc): Delete.
+ (h-psw,h-bpsw,h-bbpsw): Define.
+ (rte,trap): Handle bbpc,bbpsw.
+ * opcodes.scm (max-operand-instances): Fix typo.
+ * sim.scm (<hardware-base>, method 'fun-access?): Don't force virtual
+ hardware elements to be fun-access.
+ (-hw-gen-fun-get,-hw-gen-fun-set): Fix handling of scalars.
+
+Wed Sep 9 15:28:55 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * m32r.cpu (trap): Pass `pc' to m32r_trap.
+
+Mon Aug 10 14:29:33 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * opcodes.scm (gen-insn-table-entry): Comment out generation of cdx.
+
+Mon Aug 3 11:51:04 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * m32r.cpu (cpu m32rb): Renamed from m32r to distinguish from
+ architecture name.
+ (mach m32r): Update.
+
+ * mach.scm (mach:supports?): New proc.
+ * sim-cpu.scm (gen-cpu-reg-access-{decls,defns}): Renamed from
+ gen-reg-access-{decls,defns}.
+ * sim.scm (gen-reg-access-{decl,defn}): New procs.
+ (gen-mach-bfd-name): New proc.
+ (gen-arch-reg-access-{decls,defns}): New procs.
+ (cgen-arch.[ch]): Output register access cover fns.
+
+ * hardware.scm (hardware-builtin!): Set print handlers for
+ h-addr,h-iaddr.
+ * m32r.opc (parse_hash,parse_hi16,parse_slo16,parse_ulo16): New arg
+ `od'.
+ (CGEN_PRINT_NORMAL,print_hash): Ditto.
+ (my_print_insn): Ditto. Delete args buf, buflen.
+ * opcodes.scm: Pass `od' (opcode-descriptor) to all C handlers.
+ (-hw-asm-specs): Add `handlers' spec.
+ (-parse-hw-asm): Lookup class at runtime. If no asm-spec, use
+ `normal-hw-asm'.
+ (<hw-asm>): Renamed from <opval>. New elements parse,insert,extract,
+ print.
+ (<hw-asm>, gen-insert,gen-extract,gen-print): Use them.
+ (<hw-asm>, parse!): New method.
+ (gen-insn-table-entry): Print semantics.
+ (gen-opcode-open): Renamed from gen-opcode-table.
+
+ * utils.scm (string-write): No longer a macro.
+ (-string-write): Handle procedure args.
+ * opcodes.scm: Update all calls to string-write.
+ * sim-cpu.scm: Ditto.
+ * sim-decode.scm: Ditto.
+ * sim-model.scm: Ditto.
+ * sim.scm: Ditto.
+
+Fri Jul 31 14:40:38 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * opcodes.scm (cgen-ibd.h,gen-extra-ibd.h): New procs.
+ (-gen-insn-builders,-gen-insn-builder): New procs.
+
+Fri Jul 24 11:38:59 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * opcodes.scm (gen-syntax-entry): Fix bracketing for -Wall.
+ (gen-opcode-table): Properly terminate comment.
+
+Tue Jul 21 10:51:42 1998 Doug Evans <devans@seba.cygnus.com>
+
+ * Version 0.6.0.
+ Clean up pass over everything, so starting fresh.
diff --git a/cgen/INSTALL b/cgen/INSTALL
new file mode 100644
index 00000000000..b42a17ac464
--- /dev/null
+++ b/cgen/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/cgen/Makefile.am b/cgen/Makefile.am
new file mode 100644
index 00000000000..53f3fea0bba
--- /dev/null
+++ b/cgen/Makefile.am
@@ -0,0 +1,124 @@
+# Process this file with "automake --cygnus Makefile" to generate Makefile.in
+
+AUTOMAKE_OPTIONS = cygnus
+
+SUBDIRS = doc
+
+GUILE = `if test -f ../guile/libguile/guile ; then echo ../guile/libguile/guile; else echo guile ; fi`
+CGENFLAGS = -v
+ARCH = @arch@
+
+# Applications depend on stamp-cgen to tell them when .scm files have
+# been changed (so files need to be regenerated).
+# ??? Application specific files are kept with cgen for now, but may
+# eventually go with the app. stamp-cgen might still be useful to track
+# app-independent files.
+
+all-local: stamp-cgen
+
+stamp-cgen: $(CGENFILES)
+ rm -f stamp-cgen
+ echo timestamp > stamp-cgen
+
+# Phony targets to run each of the applications,
+# though most of these are for development purposes only.
+# When actually building the toolchain, the Makefile in the appropriate
+# directory will run cgen.
+
+# Build the basic description support.
+# We just stuff them in tmp-* files.
+# Usage: make desc ARCH=<arch> OPTIONS="<option list>"
+
+.PHONY: desc
+# FIXME: needs more dependencies
+desc: desc.scm
+ rm -f tmp-desc.h tmp-desc.c tmp-opinst.c
+ $(GUILE) -s $(srcdir)/cgen-opc.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS)" \
+ -m all -a $(ARCH) \
+ -H tmp-desc.h -C tmp-desc.c
+
+# Build the opcodes files.
+# We just stuff them in tmp-* files.
+# Usage: make opcodes ARCH=<arch> OPTIONS="<option list>"
+
+.PHONY: opcodes
+# FIXME: needs more dependencies
+opcodes: opcodes.scm
+ rm -f tmp-opc.h tmp-itab.c
+ rm -f tmp-asm.in tmp-dis.in tmp-ibld.h tmp-ibld.in
+ $(GUILE) -s $(srcdir)/cgen-opc.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS) opinst" \
+ -m all -a $(ARCH) \
+ -O tmp-opc.h -P tmp-opc.c -Q tmp-opinst.c \
+ -B tmp-ibld.h -L tmp-ibld.in \
+ -A tmp-asm.in -D tmp-dis.in
+
+# Build the simulator files.
+# We just stuff them in tmp-* files.
+# Usage: make sim-arch ARCH=<arch> OPTIONS="<option list>"
+# make sim-cpu ARCH=<arch> ISA="<isa>" MACHS="<mach list>" \
+# OPTIONS="<option list>"
+
+.PHONY: sim-arch sim-cpu
+# FIXME: needs more dependencies
+sim-arch: sim.scm
+ rm -f tmp-arch.h tmp-arch.c tmp-cpuall.h
+ $(GUILE) -s $(srcdir)/cgen-sim.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS)" \
+ -m all -a $(ARCH) \
+ -A tmp-arch.h -B tmp-arch.c -N tmp-cpuall.h
+sim-cpu: sim.scm
+ rm -f tmp-cpu.h tmp-cpu.c tmp-decode.h tmp-decode.c
+ rm -f tmp-model.c tmp-sem.c tmp-sem-switch.c
+ $(GUILE) -s $(srcdir)/cgen-sim.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS)" \
+ -i "$(ISA)" -m "$(MACHS)" -a $(ARCH) \
+ -C tmp-cpu.h -U tmp-cpu.c \
+ -T tmp-decode.h -D tmp-decode.c \
+ -M tmp-model.c \
+ -S tmp-semantics.c -X tmp-sem-switch.c
+
+# Build GAS testcase generator.
+
+.PHONY: gas-test
+gas-test: gas-test.scm cgen-gas.scm
+ @if test -z "$(ISA)" ; then \
+ echo "ISA not specified!" ;\
+ exit 1 ;\
+ fi
+ $(GUILE) -s $(srcdir)/cgen-gas.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -m all \
+ -i $(ISA) \
+ -a $(ARCH) \
+ -B gas-build.sh \
+ -E gas-allinsn.exp
+
+# Build simulator testcase generator.
+
+.PHONY: sim-test
+sim-test: sim-test.scm cgen-stest.scm
+ @if test -z "$(ISA)" ; then \
+ echo "ISA not specified!" ;\
+ exit 1 ;\
+ fi
+ $(GUILE) -s $(srcdir)/cgen-stest.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -m all \
+ -i $(ISA) \
+ -a $(ARCH) \
+ -B sim-build.sh \
+ -E sim-allinsn.exp
+
+CLEANFILES = tmp-*
diff --git a/cgen/Makefile.in b/cgen/Makefile.in
new file mode 100644
index 00000000000..e42cf2e6517
--- /dev/null
+++ b/cgen/Makefile.in
@@ -0,0 +1,449 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Process this file with "automake --cygnus Makefile" to generate Makefile.in
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+EXEEXT = @EXEEXT@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+arch = @arch@
+
+AUTOMAKE_OPTIONS = cygnus
+
+SUBDIRS = doc
+
+GUILE = `if test -f ../guile/libguile/guile ; then echo ../guile/libguile/guile; else echo guile ; fi`
+CGENFLAGS = -v
+ARCH = @arch@
+
+CLEANFILES = tmp-*
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_CLEAN_FILES =
+DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS aclocal.m4 configure configure.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --cygnus Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive install-info-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ test "$$subdir" = "." && dot_seen=yes; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am:
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-info-am:
+install-info: install-info-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile all-local
+all-redirect: all-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am: clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am: distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+ -rm -f config.status
+
+maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f config.status
+
+.PHONY: install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-info-am \
+install-info install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-local all-redirect all-am \
+all installdirs-am installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Applications depend on stamp-cgen to tell them when .scm files have
+# been changed (so files need to be regenerated).
+# ??? Application specific files are kept with cgen for now, but may
+# eventually go with the app. stamp-cgen might still be useful to track
+# app-independent files.
+
+all-local: stamp-cgen
+
+stamp-cgen: $(CGENFILES)
+ rm -f stamp-cgen
+ echo timestamp > stamp-cgen
+
+# Phony targets to run each of the applications,
+# though most of these are for development purposes only.
+# When actually building the toolchain, the Makefile in the appropriate
+# directory will run cgen.
+
+# Build the basic description support.
+# We just stuff them in tmp-* files.
+# Usage: make desc ARCH=<arch> OPTIONS="<option list>"
+
+.PHONY: desc
+# FIXME: needs more dependencies
+desc: desc.scm
+ rm -f tmp-desc.h tmp-desc.c tmp-opinst.c
+ $(GUILE) -s $(srcdir)/cgen-opc.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS)" \
+ -m all -a $(ARCH) \
+ -H tmp-desc.h -C tmp-desc.c
+
+# Build the opcodes files.
+# We just stuff them in tmp-* files.
+# Usage: make opcodes ARCH=<arch> OPTIONS="<option list>"
+
+.PHONY: opcodes
+# FIXME: needs more dependencies
+opcodes: opcodes.scm
+ rm -f tmp-opc.h tmp-itab.c
+ rm -f tmp-asm.in tmp-dis.in tmp-ibld.h tmp-ibld.in
+ $(GUILE) -s $(srcdir)/cgen-opc.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS) opinst" \
+ -m all -a $(ARCH) \
+ -O tmp-opc.h -P tmp-opc.c -Q tmp-opinst.c \
+ -B tmp-ibld.h -L tmp-ibld.in \
+ -A tmp-asm.in -D tmp-dis.in
+
+# Build the simulator files.
+# We just stuff them in tmp-* files.
+# Usage: make sim-arch ARCH=<arch> OPTIONS="<option list>"
+# make sim-cpu ARCH=<arch> ISA="<isa>" MACHS="<mach list>" \
+# OPTIONS="<option list>"
+
+.PHONY: sim-arch sim-cpu
+# FIXME: needs more dependencies
+sim-arch: sim.scm
+ rm -f tmp-arch.h tmp-arch.c tmp-cpuall.h
+ $(GUILE) -s $(srcdir)/cgen-sim.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS)" \
+ -m all -a $(ARCH) \
+ -A tmp-arch.h -B tmp-arch.c -N tmp-cpuall.h
+sim-cpu: sim.scm
+ rm -f tmp-cpu.h tmp-cpu.c tmp-decode.h tmp-decode.c
+ rm -f tmp-model.c tmp-sem.c tmp-sem-switch.c
+ $(GUILE) -s $(srcdir)/cgen-sim.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -f "$(OPTIONS)" \
+ -i "$(ISA)" -m "$(MACHS)" -a $(ARCH) \
+ -C tmp-cpu.h -U tmp-cpu.c \
+ -T tmp-decode.h -D tmp-decode.c \
+ -M tmp-model.c \
+ -S tmp-semantics.c -X tmp-sem-switch.c
+
+# Build GAS testcase generator.
+
+.PHONY: gas-test
+gas-test: gas-test.scm cgen-gas.scm
+ @if test -z "$(ISA)" ; then \
+ echo "ISA not specified!" ;\
+ exit 1 ;\
+ fi
+ $(GUILE) -s $(srcdir)/cgen-gas.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -m all \
+ -i $(ISA) \
+ -a $(ARCH) \
+ -B gas-build.sh \
+ -E gas-allinsn.exp
+
+# Build simulator testcase generator.
+
+.PHONY: sim-test
+sim-test: sim-test.scm cgen-stest.scm
+ @if test -z "$(ISA)" ; then \
+ echo "ISA not specified!" ;\
+ exit 1 ;\
+ fi
+ $(GUILE) -s $(srcdir)/cgen-stest.scm \
+ -s $(srcdir) \
+ $(CGENFLAGS) \
+ -m all \
+ -i $(ISA) \
+ -a $(ARCH) \
+ -B sim-build.sh \
+ -E sim-allinsn.exp
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/cgen/NEWS b/cgen/NEWS
new file mode 100644
index 00000000000..f9c9060ac00
--- /dev/null
+++ b/cgen/NEWS
@@ -0,0 +1,3 @@
+News for CGEN Version 0.7.3
+
+Prepping for public release.
diff --git a/cgen/README b/cgen/README
new file mode 100644
index 00000000000..d826225b522
--- /dev/null
+++ b/cgen/README
@@ -0,0 +1,191 @@
+This is the README for CGEN 0.7.1
+
+If you just want to read up on cgen, I suggest going directly to the
+doc directory, and in particular doc/intro.texi.
+
+What is it?
+===========
+
+In a nutshell, CGEN is a project to provide a uniform framework for doing
+binutils and simulator ports without explicitly closing any doors on anything
+else one might want to do with the cpu description (i.e. application
+independence). The "cpu description" as defined here includes anything useful.
+To this end CGEN is a very open-ended and ambitious project.
+
+The core of CGEN is a cpu description file and code to slurp it in and
+build a database describing the cpu. From this the Binutils opcodes table
+can be generated for example, as well as an ISA simulator decoder/executor.
+
+CGEN is not a new idea. Other GNU ports have done this (e.g. `sh' in its
+early days). However, the idea never really "caught on". CGEN was started
+because I think it should be.
+
+CGEN is short for "Cpu tools GENerator". It's not a very good name.
+I'm not very good at picking names. An early version of the name was
+"GENCPU"! So give me a better one.
+
+Copyright
+=========
+
+CGEN is Copyright 2000 Red Hat, Inc.
+
+The full text of the copyright for CGEN is contained in the file
+COPYING.CGEN. The copyright of CGEN uses the Autoconf copyright
+as a guide. The intent is to have CGEN under a GNU-style copyright but
+place no restrictions on the output of CGEN.
+
+Installation
+============
+
+CGEN 0.7.1 can be used with GNU Binutils snapshots as of ??????
+and GNU GDB snapshots as of ??????.
+GNU Binutils/GDB users will never "use" CGEN. The generated sources
+are shipped with GNU Binutils/GDB releases.
+Binutils/GDB developers wishing to use CGEN must configure Binutils/GDB with
+--enable-cgen-maint. This will add the necessary dependencies to
+opcodes/Makefile and sim/<arch>/Makefile for the supported processors, which
+at this point is M32R and FR30.
+
+CGEN uses Guile so Guile must be installed.
+Guile 1.2 and 1.3 are supported.
+2)
+
+Source Layout
+=============
+
+CGEN sources are divided into several categories:
+
+- documentation
+- code to read .cpu files
+- opcode table generator
+- gas testsuite generator
+- simulator generator
+- misc support scripts
+- cpu specific files
+- C support code
+
+File naming rules:
+
+1) The top level script for each application shall be named cgen-<appl>.scm.
+ No other files shall be named cgen-*.scm.
+2) Files implementing a particular class (or related collection of classes)
+ shall be named <class-name>.scm, or a reasonable abbreviation thereof.
+3) CPU description files shall be named <arch>.cpu.
+ [it should go without saying that no other files shall be named <arch>.cpu]
+4) CPU opcode support files shall be named <arch>.opc.
+ [it should go without saying that no other files shall be named <arch>.opc]
+
+??? May wish to change (1) to <appl>-cgen.scm so that each application's
+files will be collected together in `ls' output by the <appl>- prefix.
+
+documentation
+-------------
+
+doc/cgen.texi - top level .texi file, includes the others
+doc/rtl.texi - cpu description language (based on GCC's RTL)
+doc/intro.texi - global overview of cgen
+doc/opcodes.texi - opcode table usage of cgen
+doc/porting.texi - porting guide for new ports
+doc/sim.texi - simulator usage of cgen
+doc/credits.texi - inspiration and contributors
+
+code to read .cpu files
+-----------------------
+
+These files provide the basic support for reading in .cpu files. They contain
+no application specific code (and ideally as little C generating code as
+possible too), they are intended to be application independent. Applications
+(e.g. the opcode table generator and the simulator support generator) are
+built on top of these files.
+
+attr.scm - attribute support
+read.scm - top level script for .cpu file reading
+enum.scm - enum support
+hardware.scm - hardware description reader
+ifield.scm - instruction field reader
+iformat.scm - computes instruction formats
+insn.scm - instruction description reader
+mach.scm - architecture/cpu/machine reader
+minsn.scm - macro-instruction description reader
+mode.scm - mode support
+model.scm - model reader
+operand.scm - instruction operand reader
+rtl.scm - basic rtl support
+rtx-funcs.scm - defines all standard rtx functions
+types.scm - type system
+
+opcode table generator
+---------------------
+
+cgen-opc.scm - top level script to generate the opcode table + support
+opcodes.scm - opcode table generator
+opc-asmdis.scm
+opc-ibld.scm
+opc-itab.scm
+opc-opinst.scm
+
+Additional support lives in the opcodes directory.
+
+opcodes/cgen-ibld.in - input file for <arch>-ibld.c
+opcodes/cgen-asm.in - input file for <arch>-asm.c
+opcodes/cgen-dis.in - input file for <arch>-dis.c
+opcodes/cgen-opc.c - architecture independent opcode table support
+opcodes/cgen-asm.c - architecture independent assembler support
+opcodes/cgen-dis.c - architecture independent disassembler support
+opcodes/cgen.sh - shell script invoked by opcodes/Makefile to build
+ <arch>-opc.h, <arch>-opc.c, <arch>-asm.c, <arch>-dis.c.
+
+The header file that defines the interface to the opcodes table is
+include/opcode/cgen.h.
+
+gas testsuite generator
+-----------------------
+
+cgen-gas.scm - top level script to generate gas testcases
+gas-test.scm - generate gas testcases
+
+simulator generator
+-------------------
+
+cgen-sim.scm - top level script to generate simulator files
+sim-arch.scm - generator for architecture-wide support files
+sim-cpu.scm - generator for cpu specific simulator files
+sim-decode.scm - decoder generator
+sim-model.scm - generates model support
+sim.scm - interface between simulator generator and cpu database
+
+Additional support lives in sim/common/cgen-*.[ch].
+Architectures specific files live in sim/<arch>.
+
+misc. support scripts
+---------------------
+
+dev.scm - top level script for doing interactive development
+fixup.scm - munges the Scheme environment to make it suit us
+ [Guile is/was still in flux]
+cos.scm - OOP implementation
+pmacros.scm - preprocessor-style macro package
+profile.scm - Guile profiling tool [eventually wish to move this to
+ Guile distribution when finished]
+sort.scm - sort routine, from slib
+utils-cgen.scm - various utilities specific to cgen
+utils.scm - generic Scheme utilities [non cgen specific]
+
+cpu specific files
+------------------
+
+<arch>.cpu - <arch> description file
+<arch>.opc - <arch> opcode support
+
+null.cpu - minimal .cpu file for debugging purposes
+
+C version of cgen
+-----------------
+
+Makefile.am, Makefile.in - automake stuff
+acconfig.h,aclocal.m4,config.in,stamp-h.in - autoconf stuff
+configure.in,configure - autoconf stuff
+gdbinit.in - source for .gdbinit file
+cgen.c - main()
+cgen-gh.[ch] - additional functionality to Guile's gh interface
+cos.[ch] - C implementation of cgen object system
diff --git a/cgen/aclocal.m4 b/cgen/aclocal.m4
new file mode 100644
index 00000000000..f5379a5be03
--- /dev/null
+++ b/cgen/aclocal.m4
@@ -0,0 +1,137 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake. This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "[$]*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "[$]*" != "X $srcdir/configure conftestfile" \
+ && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "[$]2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+ $1=$2
+ AC_MSG_RESULT(found)
+else
+ $1="$3/missing $2"
+ AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# serial 1
+
+AC_DEFUN(AM_MAINTAINER_MODE,
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT($USE_MAINTAINER_MODE)
+ AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes)
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+# Define a conditional.
+
+AC_DEFUN(AM_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi])
+
diff --git a/cgen/arm.cpu b/cgen/arm.cpu
new file mode 100644
index 00000000000..9d1344a0ad8
--- /dev/null
+++ b/cgen/arm.cpu
@@ -0,0 +1,404 @@
+; ARM CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+(include "simplify.inc")
+
+(define-arch
+ (name arm)
+ (comment "Advanced RISC Machines (ARM)")
+ (insn-lsb0? #t)
+ (machs arm7tdmi)
+ (isas arm thumb)
+)
+
+; ??? There should be an official rtx to do this. Until then.
+(define-pmacro (invalid-insn)
+ (c-call BI "invalid_insn" pc) ; FIXME: Not VOID to workaround codegen bug.
+)
+
+(define-isa
+ (name arm)
+ (comment "ARM instruction set (32 bit insns)")
+ (base-insn-bitsize 32)
+ ; FIXME: wip. `f-cond' is currently defined in arm7.cpu.
+ (condition f-cond
+ ; `cond-code' is the extracted value of `f-cond'
+ ; FIXME: wip
+; (case BI cond-code
+; ((COND_EQ) (reg h-zbit))
+; ((COND_NE) (not (reg h-zbit)))
+; ((COND_CS) (reg h-cbit))
+; ((COND_CC) (not (reg h-cbit)))
+; ((COND_MI) (reg h-nbit))
+; ((COND_PL) (not (reg h-zbit)))
+; ((COND_VS) (reg h-vbit))
+; ((COND_VC) (not (reg h-vbit)))
+; ((COND_HI) (and (reg h-cbit) (not (reg h-zbit))))
+; ((COND_LS) (not (or (reg h-cbit) (reg h-zbit))))
+; ((COND_GE) (eq (reg h-zbit) (reg h-vbit)))
+; ((COND_LT) (ne (reg h-nbit) (reg h-vbit)))
+; ((COND_GT) (and (not (reg h-zbit))
+; (eq (reg h-nbit) (reg h-vbit))))
+; ((COND_LE) (or (reg h-zbit)
+; (ne (reg h-nbit) (reg h-vbit))))
+; ((COND_AL) 1)
+; (else (sequence BI () (invalid-insn) 1))))
+ (c-call BI "eval_cond" cond-code pc))
+ (decode-assist (27 26 25 24 23 22 21))
+ ; We can lengthen pbb's by breaking insns that set h-gr into those that set
+ ; h-gr[15] (the pc), and those that don't.
+ ; Other analysis of the isa will benefit from this, so this is recorded here
+ ; rather than in a simulator specific file.
+;; (decode-splits
+;; ; split insns with field f-rd into f-rd == 15, f-rd != 15
+;; ; ??? To be made more general in time.
+;; (f-rd ; split on values of this field
+;; () ; no extra constraints
+;; ((no-pc-dest (.iota 15)) (pc-dest 15)) ; list of splits
+;; )
+;; )
+ (setup-semantics (set-quiet (reg h-gr 15) (add pc (attr (current-insn) R15-OFFSET))))
+)
+
+(define-isa
+ (name thumb)
+ (comment "ARM Thumb instruction set (16 bit insns)")
+ (base-insn-bitsize 16)
+ (decode-assist (15 14 13 12 11 10 9 8))
+ (setup-semantics (set-quiet (reg h-gr 15) (add pc 4)))
+)
+
+(define-cpu
+ (name arm7f)
+ (comment "ARM7")
+ (endian either)
+ (word-bitsize 32)
+)
+
+(define-mach
+ (name arm7tdmi)
+ (comment "ARM 7TDMI core")
+ (cpu arm7f)
+ (isas arm thumb)
+)
+
+(define-model
+ (name arm710)
+ (comment "ARM 710 microprocessor")
+ (mach arm7tdmi)
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () () () ())
+)
+
+; Hardware.
+
+; The program counter is actually reg 15.
+; But ... [there's always a "But ..." :-(] when referenced in instructions
+; the value is either 8 or 12 beyond the address of the instruction in
+; ARM mode and 4 beyond in Thumb mode.
+; To handle this the program counter is treated as a separate register
+; and r15 is set to the appropriate offset before executing each instruction.
+; This seems like the simplest and most efficient way to handle this.
+
+(define-hardware
+ (name h-pc)
+ (comment "ARM program counter (h-gr reg 15)")
+ (attrs PC (ISA arm,thumb))
+ (type pc)
+ ; In ARM mode the bottom two bits read as zero.
+ ; In Thumb mode the bottom bit reads as zero.
+ ; This can be handled during gets, sets, or both.
+ ; Handling this in sets seems best ('tis handled in only one place and the
+ ; stored value is always correct - assuming all out-of-band sets are ok).
+ ; ??? Might be possible to optimize out the test of tbit. Later.
+ (set (newval)
+ (if (reg h-tbit)
+ (set (raw-reg SI h-pc) (and newval -2))
+ (set (raw-reg SI h-pc) (and newval -4))))
+)
+
+(define-keyword
+ (name gr-names)
+ (print-name h-gr)
+ (values (pc 15) ; put this first so it is prefered over r15
+ (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15)
+ (sp 13) (lr 14))
+)
+
+(define-hardware
+ (name h-gr)
+ (comment "General purpose registers")
+ (attrs (ISA arm,thumb) CACHE-ADDR)
+ (type register SI (16))
+ (indices extern-keyword gr-names)
+)
+
+; Banked versions of h-gr.
+; h-gr is always "active". When a mode switch happens, the copies in h-gr
+; are copied to their holding buffers, and new values are switched in.
+; ??? The non-user-mode versions of these registers have special names which
+; are just(?) aliases for the normal names.
+
+(define-hardware
+ (name h-gr-usr)
+ (comment "user/system mode r8-r14 holding buffer")
+ (attrs (ISA arm,thumb))
+ (type register SI (7))
+)
+(define-hardware
+ (name h-gr-fiq)
+ (comment "fiq mode r8-r14 regs")
+ (attrs (ISA arm,thumb))
+ (type register SI (7))
+)
+(define-hardware
+ (name h-gr-svc)
+ (comment "supervisor mode r13-r14 regs")
+ (attrs (ISA arm,thumb))
+ (type register SI (2))
+)
+(define-hardware
+ (name h-gr-abt)
+ (comment "abort mode r13-r14 regs")
+ (attrs (ISA arm,thumb))
+ (type register SI (2))
+)
+(define-hardware
+ (name h-gr-irq)
+ (comment "irq mode r13-r14 regs")
+ (attrs (ISA arm,thumb))
+ (type register SI (2))
+)
+(define-hardware
+ (name h-gr-und)
+ (comment "undefined mode r13-r14 regs")
+ (attrs (ISA arm,thumb))
+ (type register SI (2))
+)
+
+; The condition code bits.
+
+(dsh h-cbit "carry bit" ((ISA arm,thumb)) (register BI))
+(dsh h-nbit "negative bit" ((ISA arm,thumb)) (register BI))
+(dsh h-vbit "overflow bit" ((ISA arm,thumb)) (register BI))
+(dsh h-zbit "zerobit" ((ISA arm,thumb)) (register BI))
+
+(dnop cbit "carry bit" ((ISA arm,thumb)) h-cbit f-nil)
+(dnop nbit "negative bit" ((ISA arm,thumb)) h-nbit f-nil)
+(dnop vbit "overflow bit" ((ISA arm,thumb)) h-vbit f-nil)
+(dnop zbit "zero bit" ((ISA arm,thumb)) h-zbit f-nil)
+
+; The CPSR (current program status register).
+
+(dsh h-ibit "irq disable bit" ((ISA arm,thumb)) (register BI))
+(dsh h-fbit "fiq disable bit" ((ISA arm,thumb)) (register BI))
+
+(define-hardware
+ (name h-tbit)
+ (comment "thumb bit")
+ (attrs (ISA arm,thumb))
+ (type register BI)
+ (set (newval)
+ (sequence ()
+ (c-call VOID "arm_tbit_set" newval)))
+)
+
+(define-keyword
+ (name arm-mode)
+ (comment "arm cpu states")
+ (values (User #x10)
+ (FIQ #x11)
+ (IRQ #x12)
+ (Supervisor #x13)
+ (Abort #x17)
+ (Undefined #x1b)
+ (System #x1f)
+ )
+)
+
+(define-hardware
+ (name h-mbits)
+ (comment "m4,m3,m2,m1,m0")
+ (attrs (ISA arm,thumb))
+ (type register (UINT 5))
+ (set (newval)
+ (sequence ()
+ ; processor goes into an undefined state if bad value,
+ ; so do something similar
+ (case VOID newval
+ ((ARM-MODE-User ARM-MODE-FIQ ARM-MODE-IRQ
+ ARM-MODE-Supervisor ARM-MODE-Abort
+ ARM-MODE-Undefined ARM-MODE-System)
+ (nop))
+ (else (error VOID "bad value for M4-M0")))
+ (c-call VOID "arm_mbits_set" newval)))
+)
+
+(define-hardware
+ (name h-cpsr)
+ (comment "Current Program Status Register")
+ (attrs VIRTUAL (ISA arm,thumb))
+ (type register SI) ; One CPSR register.
+ (get ()
+ ; ??? 'twould be nice if one `or' would do
+ (or SI (sll (zext SI (reg BI h-nbit)) (const 31))
+ (or SI (sll (zext SI (reg BI h-zbit)) (const 30))
+ (or SI (sll (zext SI (reg BI h-cbit)) (const 29))
+ (or SI (sll (zext SI (reg BI h-vbit)) (const 28))
+ (or SI (sll (zext SI (reg BI h-ibit)) (const 7))
+ (or SI (sll (zext SI (reg BI h-fbit)) (const 6))
+ (or SI (sll (zext SI (reg BI h-tbit)) (const 5))
+ (reg UINT h-mbits)))))))))
+ (set (newval)
+ (sequence ()
+ ; FIXME: Processor enters undefined state if software changes
+ ; tbit, so we should do something similar.
+ (set (reg h-nbit) (ne (and newval #x80000000) 0))
+ (set (reg h-zbit) (ne (and newval #x40000000) 0))
+ (set (reg h-cbit) (ne (and newval #x20000000) 0))
+ (set (reg h-vbit) (ne (and newval #x10000000) 0))
+ ; FIXME: user mode is not permitted to change ibit/fbit!
+ (set (reg h-ibit) (ne (and newval #x00000080) 0))
+ (set (reg h-fbit) (ne (and newval #x00000040) 0))
+ (set (reg h-tbit) (ne (and newval #x00000020) 0))
+ (set (reg h-mbits) (and newval #x1f))))
+)
+
+(define-hardware
+ (name h-spsr-fiq)
+ (comment "Saved Process Status Register during FIQ")
+ (attrs (ISA arm,thumb))
+ (type register SI)
+)
+(define-hardware
+ (name h-spsr-svc)
+ (comment "Saved Process Status Register during SVC")
+ (attrs (ISA arm,thumb))
+ (type register SI)
+)
+(define-hardware
+ (name h-spsr-abt)
+ (comment "Saved Process Status Register during Abort")
+ (attrs (ISA arm,thumb))
+ (type register SI)
+)
+(define-hardware
+ (name h-spsr-irq)
+ (comment "Saved Process Status Register during IRQ")
+ (attrs (ISA arm,thumb))
+ (type register SI)
+)
+(define-hardware
+ (name h-spsr-und)
+ (comment "Saved Process Status Register during Undefined")
+ (attrs (ISA arm,thumb))
+ (type register SI)
+)
+
+; Virtual version of spsr to access real one based on current mode.
+
+(define-hardware
+ (name h-spsr)
+ (comment "virtual spsr")
+ (attrs VIRTUAL (ISA arm,thumb))
+ (type register SI)
+ (get ()
+ (case SI (reg h-mbits)
+ ((ARM-MODE-User) (error SI "can't read spsr in user mode"))
+ ((ARM-MODE-FIQ) (reg h-spsr-fiq))
+ ((ARM-MODE-IRQ) (reg h-spsr-irq))
+ ((ARM-MODE-Supervisor) (reg h-spsr-svc))
+ ((ARM-MODE-Abort) (reg h-spsr-abt))
+ ((ARM-MODE-Undefined) (reg h-spsr-und))
+ ((ARM-MODE-System) (error SI "can't read spsr in system mode"))
+ (else (error SI "can't read spsr, invalid mode"))))
+ (set (newval)
+ (case VOID (reg h-mbits)
+ ((ARM-MODE-User) (error VOID "can't set spsr in user mode"))
+ ((ARM-MODE-FIQ) (set (reg h-spsr-fiq) newval))
+ ((ARM-MODE-IRQ) (set (reg h-spsr-irq) newval))
+ ((ARM-MODE-Supervisor) (set (reg h-spsr-svc) newval))
+ ((ARM-MODE-Abort) (set (reg h-spsr-abt) newval))
+ ((ARM-MODE-Undefined) (set (reg h-spsr-und) newval))
+ ((ARM-MODE-System) (error VOID "can't set spsr in system mode"))
+ (else (error VOID "can't set spsr, invalid mode"))))
+)
+
+; Explicitly define the shift types so they can be used in semantics
+; (enums are created for them).
+
+(define-keyword
+ (name shift-type)
+ (comment "operand 2 shift type")
+ (prefix "")
+ (values (lsl 0) (asl 0) (lsr 1) (asr 2) (ror 3))
+)
+
+(define-hardware
+ (name h-operand2-shifttype)
+ (comment "operand2 shift type")
+ (type immediate (UINT 2))
+ (values extern-keyword shift-type)
+)
+
+; Utility macros for setting the condition codes.
+
+(define-pmacro (set-zn-flags result)
+ (sequence ()
+ (set zbit (zflag WI result))
+ (set nbit (nflag WI result)))
+)
+
+; Logical operation flag handling:
+; cbit is set to the carry out of a shift operation if present
+; nbit is set to the sign bit
+; vbit is not affected
+; zflag is set to indicate whether the result was zero or not
+
+(define-pmacro (set-logical-cc result carry-out)
+ (sequence ()
+ (set-zn-flags result)
+ (set cbit carry-out))
+)
+
+(define-pmacro (set-add-flags arg1 arg2 carry)
+ (sequence ((SI result))
+ (set result (addc arg1 arg2 carry))
+ (set-zn-flags result)
+ (set cbit (add-cflag arg1 arg2 carry))
+ (set vbit (add-oflag arg1 arg2 carry)))
+)
+
+(define-pmacro (set-sub-flags arg1 arg2 borrow)
+ (sequence ((SI result))
+ (set result (subc arg1 arg2 (not borrow)))
+ (set-zn-flags result)
+ (set cbit (not (sub-cflag arg1 arg2 (not borrow))))
+ (set vbit (sub-oflag arg1 arg2 (not borrow))))
+)
+
+; Utility macros for testing the condition codes.
+
+(define-pmacro (test-ne) (not zbit))
+(define-pmacro (test-eq) zbit)
+(define-pmacro (test-gt) (not (or zbit (xor nbit vbit))))
+(define-pmacro (test-le) (or zbit (xor nbit vbit)))
+(define-pmacro (test-ge) (not (xor nbit vbit)))
+(define-pmacro (test-lt) (xor nbit vbit))
+(define-pmacro (test-hi) (and cbit (not zbit)))
+(define-pmacro (test-ls) (or (not cbit) zbit))
+(define-pmacro (test-cc) (not cbit))
+(define-pmacro (test-cs) cbit)
+(define-pmacro (test-pl) (not nbit))
+(define-pmacro (test-mi) nbit)
+(define-pmacro (test-vc) (not vbit))
+(define-pmacro (test-vs) vbit)
+
+(if (keep-isa? (arm))
+ (include "arm7.cpu"))
+(if (keep-isa? (thumb))
+ (include "thumb.cpu"))
diff --git a/cgen/arm.sim b/cgen/arm.sim
new file mode 100644
index 00000000000..673e8e1a3ea
--- /dev/null
+++ b/cgen/arm.sim
@@ -0,0 +1,39 @@
+; ARM CPU simulator support. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; N.B.
+; - The format of this file is *extremely* wip!
+; - This isn't intended to be simulator independent, it is an application
+; specific file and not all simulator apps are equivalent.
+; - This file is loaded after all the .cpu files are loaded.
+
+; ??? The application (e.g. simulator) may wish to do further processing when
+; the tbit is set. For a C++ simulator what one would want to do is override
+; the "set" method. That presumes there's a "set" method to override and
+; that all affected code uses it. There are several to accomplish this.
+; The first way to accomplish this is to have all code always
+; access hardware elements through their get/set methods. Perhaps ok,
+; but also maybe overkill. The second is to specify those that use get/set
+; methods. One could do this for elements that have get/set specs, but this
+; requires the .cpu file to get it right (and to change when it isn't).
+; A variant of the second is to move this info to an application specific
+; file (much like what .opc files are although even they have the problem of
+; requiring collaboration with the .cpu file. -- to be fixed!).
+; The solution taken here is the latter.
+
+; The h-tbit and h-mbits registers need extra processing when they are set.
+; This is done by specifying the FUN-SET attribute, which causes all machine
+; generated references to go through the `set' access method.
+; Oh no, not FUN-ACCESS again! :-)
+
+(modify-hardware
+ (name h-tbit)
+ (add-attrs FUN-SET)
+)
+
+(modify-hardware
+ (name h-mbits)
+ (add-attrs FUN-SET)
+)
diff --git a/cgen/arm7.cpu b/cgen/arm7.cpu
new file mode 100644
index 00000000000..19b8d5fdc51
--- /dev/null
+++ b/cgen/arm7.cpu
@@ -0,0 +1,1995 @@
+; ARM7 CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+;
+; This file is included by arm.cpu.
+;
+; ??? The name of this file may be confusing.
+;
+; Every entry in this file belongs to the "arm" isa.
+; Things are simple since that is the default, but it is something to
+; keep in mind.
+
+(define-attr
+ (type integer)
+ (name R15-OFFSET)
+ (comment "offset in pc value at time of use")
+ (default 8)
+)
+
+(dnf f-cond "Condition code" () 31 4)
+
+(dnf f-op2 "Opcode (2 bits)" () 27 2)
+(dnf f-op3 "Opcode (3 bits)" () 27 3)
+(dnf f-op4 "Opcode (4 bits)" () 27 4)
+(dnf f-op5 "Opcode (5 bits)" () 27 5)
+(dnf f-op6 "Opcode (6 bits)" () 27 6)
+(dnf f-op24 "Opcode (24 bits)" () 27 24)
+
+(dnf f-op-alu "Arith/logic opcode" () 24 4)
+(dnf f-op-mul "Sub-opcode for MUL" () 7 4)
+(dnf f-op-swap1 "Sub-opcode for SWP" () 21 2)
+(dnf f-op-swap2 "Sub-opcode for SWP" () 11 8)
+(dnf f-op-mrs1 "Sub-opcode for MRS" () 21 6)
+(dnf f-op-mrs2 "Sub-opcode for MRS" () 11 12)
+(dnf f-op-msr1 "Sub-opcode for MSR" () 21 10)
+(dnf f-op-msr2 "Sub-opcode for MSR" () 11 8)
+
+(dnf f-rn "Rn" () 19 4)
+(dnf f-rd "Rd" () 15 4)
+(dnf f-rm "Rm" () 3 4)
+(dnf f-preindex? "Pre/post indexing" () 24 1)
+(dnf f-set-cc? "Set condition codes?" () 20 1)
+(dnf f-imm? "Immediate?" () 25 1)
+(dnf f-byte-qty? "Byte sized transfer?" () 22 1)
+
+; Extra fields needed for the Data Processing/PSR Transfer class.
+
+(dnf f-ror-imm8-value "8 bit value to be rotated" () 7 8)
+(dnf f-ror-imm8-rotate "Rotate amount" () 11 4)
+
+(dnmf f-ror-imm8 "8 bit rotated immediate" () UINT
+ (f-ror-imm8-value f-ror-imm8-rotate)
+ ; insert
+ (c-call SI "arm_encode_imm12" (ifield f-ror-imm8))
+ ; extract
+ (sequence ()
+ (set (ifield f-ror-imm8)
+ (ror WI (ifield f-ror-imm8-value)
+ (mul 2 (ifield f-ror-imm8-rotate))))
+ )
+)
+
+(df f-imm12 "Immediate (12 bit)" () 11 12 UINT
+ ((value pc) (c-call SI "arm_encode_imm12" value))
+ ((value pc)
+ (ror WI (and WI value #xFF)
+ (mul 2 (srl WI (and WI value #xF00) 8))))
+)
+
+; These two are for a register operand2 (i=0).
+(dnf f-operand2-reg? "Operand2 reg indicator" () 4 1)
+(dnf f-operand2-shifttype "Operand2 shift type" () 6 2)
+
+(dnf f-operand2-shiftimm "Operand2 shift amount (imm)" () 11 5)
+(dnf f-operand2-shiftreg "Operand2 shift amount (reg)" () 11 4)
+
+; Extra fields needed for the Transfer instruction classes.
+
+(dnf f-up-down "Base register direction" () 23 1)
+(dnf f-write-back? "Write back?" () 21 1)
+(dnf f-load? "Load or store?" () 20 1)
+
+; Extra fields needed for the Single Data Transfer instruction class.
+
+(df f-offset12 "Offset" (PCREL-ADDR) 11 12 INT
+ ((value pc) (sra WI (sub WI value 2)))
+ ((value pc) (add WI (sll WI value 2) pc)))
+
+(dnf f-uimm12 "Unsigned immediate (12 bit)" () 11 12)
+
+; Extra fields needed for the Branch and Exchange instruction class.
+
+(dnf f-bx-rn "Rn for branch/exchg" () 3 4)
+
+; Extra fields needed for the Halfword Data Transfer instruction class.
+
+(dnf f-halfword? "Halfword transfer?" () 5 1)
+(dnf f-signed? "Signed transfer?" () 6 1)
+(dnf f-offset4-hi "High nybble" () 11 4)
+(dnf f-offset4-lo "Low nybble" () 3 4)
+
+; Extra fields needed for the PSR Transfer instructions.
+
+(dnf f-psr "PSR selector" () 22 1)
+
+; Miscellaneous single bit fields.
+
+(dnf f-bit4 "Bit 4" () 4 1)
+(dnf f-bit7 "Bit 7" () 7 1)
+(dnf f-bit22 "Bit 22" () 22 1)
+
+(define-multi-ifield
+ (name f-hdt-offset8)
+ (comment "Immediate offset for halfword and signed data transfers")
+ (attrs)
+ (mode UINT)
+ (subfields f-offset4-hi f-offset4-lo)
+ (insert (sequence ()
+ (set (ifield f-offset4-hi)
+ (and (srl (ifield f-hdt-offset8) 4) #xF))
+ (set (ifield f-offset4-lo)
+ (and (ifield f-hdt-offset8) #xF))))
+ (extract (set (ifield f-hdt-offset8)
+ (or (sll (ifield f-offset4-hi) 4)
+ (ifield f-offset4-lo))))
+)
+
+; Extra fields needed for the Multiply instruction class.
+
+(dnf f-acc? "Accumulate?" () 21 1)
+(dnf f-mul-rd "Rd for multiply" () 19 4)
+(dnf f-mul-rn "Rn for multiply" () 15 4)
+(dnf f-rs "Rs" () 11 4)
+(dnf f-unsigned? "Unsigned multiply?" () 22 1)
+
+; Extra fields needed for the Multiply Long instruction class.
+
+(dnf f-rdhi "Rd (high)" () 19 4)
+(dnf f-rdlo "Rd (low)" () 15 4)
+(dnf f-mull-rn "Rn for long multiply" () 11 4)
+
+; Extra fields needed for the Branch instruction class.
+
+(dnf f-branch-link? "Branch and link?" () 24 1)
+(df f-offset24 "Branch offset" (PCREL-ADDR) 23 24 INT
+ ((value pc) (sra WI (sub WI value (add pc 8)) 2))
+ ((value pc) (add WI (sll WI value 2) (add pc 8)))
+)
+
+; Extra fields needed for the Block Data Transfer instruction class.
+
+(dnf f-reg-list "Register list" () 15 16)
+(dnf f-load-psr? "Load PSR?" () 22 1)
+
+; Extra fields needed for the SWI instruction.
+
+(dnf f-swi-comment "User-defined operand" () 23 24)
+
+; Extra fields needed for the undefined instruction.
+
+(dnf f-undef-dont1 "Don't care" (RESERVED) 24 20)
+(dnf f-undef-dont2 "Don't care" (RESERVED) 3 4)
+
+; Enumerated constants.
+
+(define-normal-insn-enum cond-codes "condition codes" () COND_ f-cond
+ ("EQ" "NE" "CS" "CC" "MI" "PL" "VS" "VC" "HI" "LS" "GE" "LT" "GT" "LE" "AL")
+)
+
+(define-normal-insn-enum al-opcode "Arith/logic opcode enums" () OP_ f-op-alu
+ ("AND" "EOR" "SUB" "RSB" "ADD" "ADC" "SBC" "RSC" "TST" "TEQ" "CMP" "CMN"
+ "ORR" "MOV" "BIC" "MVN")
+)
+
+(define-normal-insn-enum psr-dests "PSR transfer destinations" () PSR_
+ f-psr ("CURRENT" "SAVED")
+)
+
+; Instruction operands.
+
+(dnop cond "Condition code" () h-uint f-cond)
+(dnop rn "Rn" () h-gr f-rn)
+(dnop rd "Rd" () h-gr f-rd)
+(dnop rm "Rm" () h-gr f-rm)
+(dnop rs "Rs" () h-gr f-rs)
+(dnop imm? "Immediate constant?" () h-uint f-imm?)
+(dnop set-cc? "Set condition codes" () h-uint f-set-cc?)
+
+(dnop ror-imm8 "Rotated immediate (8 bits)" () h-uint f-ror-imm8)
+(dnop imm12 "Immediate" () h-uint f-imm12)
+(dnop uimm12 "Unsigned immediate (12 bits)" () h-uint f-uimm12)
+
+(dnop operand2-shifttype "Operand 2 shift type" ()
+ h-operand2-shifttype f-operand2-shifttype)
+(dnop operand2-shiftimm "Operand 2 shift immediate" ()
+ h-uint f-operand2-shiftimm)
+(dnop operand2-shiftreg "Operand 2 shift reg" ()
+ h-gr f-operand2-shiftreg)
+
+(dnop reglist "Register list" () h-uint f-reg-list)
+(dnop bx-rn "Source register (BX insn)" () h-gr f-bx-rn)
+(dnop mul-rd "Destination register (MUL insns)" () h-gr f-mul-rd)
+(dnop mul-rn "Source register (MUL insns)" () h-gr f-mul-rn)
+(dnop rdhi "Rd (high) for long multiply" () h-gr f-rdhi)
+(dnop rdlo "Rd (low) for long multiply" () h-gr f-rdlo)
+
+(dnop offset12 "Offset (12 bits)" () h-addr f-offset12)
+(dnop offset24 "Branch offset (24 bits)" () h-iaddr f-offset24)
+(dnop hdt-offset8 "Split offset (8 bits)" () h-addr f-hdt-offset8)
+
+(dnop swi-comment "Argument to swi" () h-uint f-swi-comment)
+
+(dnop undef-dont1 "Don't care" () h-uint f-undef-dont1)
+(dnop undef-dont2 "Don't care" () h-uint f-undef-dont2)
+
+; Useful macros.
+
+; Same as dni but leave out timing.
+; dnai - define-normal-arm-insn
+
+(define-pmacro (dnai xname xcomment xattrs xsyntax xformat xsemantics)
+ (define-insn
+ (name xname)
+ (comment xcomment)
+ (.splice attrs (.unsplice xattrs))
+ (syntax xsyntax)
+ (format xformat)
+ (semantics xsemantics)
+ )
+)
+
+; Branch insns.
+
+(dnai b "Branch"
+ ()
+ "b$cond $offset24"
+ (+ cond (f-op3 5) (f-branch-link? 0) offset24)
+ (set pc offset24)
+)
+
+(dnai bl "Branch and link"
+ ()
+ "bl$cond $offset24"
+ (+ cond (f-op3 5) (f-branch-link? 1) offset24)
+ (sequence ()
+ (set (reg h-gr 14) (and (add pc 4) -4))
+ (set pc offset24))
+)
+
+(dnai bx "Branch and exchange"
+ ()
+ "bx$cond ${bx-rn}"
+ (+ cond (f-op24 #x12FFF1) bx-rn)
+ (sequence ()
+ (set pc (and bx-rn #xfffffffe))
+ (if (and bx-rn 1)
+ (set (reg h-tbit) 1)))
+)
+
+; Load word/byte insns.
+
+(define-pmacro (do-word/byte-load byte? preindex? writeback? up? offset-expr)
+ (sequence ((SI addr) (SI offset))
+ (set offset offset-expr)
+ (if preindex?
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset)))
+ (set addr rn))
+ ; If writeback in postindexing case -> do transfer
+ ; in non-priviledged mode.
+ ; FIXME: still need to handle non-word-aligned addresses
+ (if (andif (not preindex?) writeback?)
+ (if byte?
+ ; FIXME: specify "non-priviledged mode" `selector'
+ (if (eq f-rd 15)
+ (set pc (zext SI (mem QI addr)))
+ (set rd (zext SI (mem QI addr))))
+ ; !byte
+ (if (eq f-rd 15)
+ (set pc (mem SI addr))
+ (set rd (mem SI addr))))
+ ; else
+ (if byte?
+ (if (eq f-rd 15)
+ (set pc (zext SI (mem QI addr)))
+ (set rd (zext SI (mem QI addr))))
+ ; !byte
+ (if (eq f-rd 15)
+ (set pc (mem SI addr))
+ (set rd (mem SI addr)))))
+ (if (not preindex?)
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset))))
+ (if (orif (not preindex?)
+ (andif preindex? writeback?))
+ (set rn addr))
+ )
+)
+
+(define-pmacro (load-word/byte name comment size-char t-char
+ byte? preindex? writeback? up?)
+ (begin
+ (dnai (.sym name -imm-offset)
+ (.str comment ", immediate offset")
+ ()
+ ; ??? Enhancement to compute offset syntax based on args?
+ (.str "ldr${cond}" size-char t-char " $rd,???")
+ (+ cond (f-op2 1)
+ (f-imm? 0) (f-preindex? preindex?) (f-up-down up?)
+ (f-byte-qty? byte?) (f-write-back? writeback?)
+ (f-load? 1) rn rd uimm12)
+ (do-word/byte-load byte? preindex? writeback? up? uimm12)
+ )
+ (dnai (.sym name -reg-offset)
+ (.str comment ", register offset")
+ ()
+ (.str "ldr${cond}" size-char t-char " $rd,???")
+ (+ cond (f-op2 1)
+ (f-imm? 1) (f-preindex? preindex?) (f-up-down up?)
+ (f-byte-qty? byte?) (f-write-back? writeback?)
+ (f-load? 1) rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (do-word/byte-load byte? preindex? writeback? up?
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ )
+ )
+)
+
+(load-word/byte #:name ldr-post-dec
+ #:comment "Load word (postindex, decrement)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 0 #:writeback? 0 #:up? 0)
+
+(load-word/byte #:name ldr-post-inc
+ #:comment "Load word (postindex, increment)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 0 #:writeback? 0 #:up? 1)
+
+(load-word/byte #:name ldr-post-dec-nonpriv
+ #:comment "Load word (postindex, decrement, nonpriv)"
+ #:size-char "" #:t-char "t"
+ #:byte? 0 #:preindex? 0 #:writeback? 1 #:up? 0)
+
+(load-word/byte #:name ldr-post-inc-nonpriv
+ #:comment "Load word (postindex, increment, nonpriv)"
+ #:size-char "" #:t-char "t"
+ #:byte? 0 #:preindex? 0 #:writeback? 1 #:up? 1)
+
+(load-word/byte #:name ldr-pre-dec
+ #:comment "Load word (preindex, decrement)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 0 #:up? 0)
+
+(load-word/byte #:name ldr-pre-inc
+ #:comment "Load word (preindex, increment)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 0 #:up? 1)
+
+(load-word/byte #:name ldr-pre-dec-wb
+ #:comment "Load word (preindex, decrement, writeback)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 1 #:up? 0)
+
+(load-word/byte #:name ldr-pre-inc-wb
+ #:comment "Load word (preindex, increment, writeback)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 1 #:up? 1)
+
+(load-word/byte #:name ldrb-post-dec
+ #:comment "Load byte (postindex, decrement)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 0 #:writeback? 0 #:up? 0)
+
+(load-word/byte #:name ldrb-post-inc
+ #:comment "Load byte (postindex, increment)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 0 #:writeback? 0 #:up? 1)
+
+(load-word/byte #:name ldrb-post-dec-nonpriv
+ #:comment "Load byte (postindex, decrement, nonpriv)"
+ #:size-char "b" #:t-char "t"
+ #:byte? 1 #:preindex? 0 #:writeback? 1 #:up? 0)
+
+(load-word/byte #:name ldrb-post-inc-nonpriv
+ #:comment "Load byte (postindex, increment, nonpriv)"
+ #:size-char "b" #:t-char "t"
+ #:byte? 1 #:preindex? 0 #:writeback? 1 #:up? 1)
+
+(load-word/byte #:name ldrb-pre-dec
+ #:comment "Load byte (preindex, decrement)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 0 #:up? 0)
+
+(load-word/byte #:name ldrb-pre-inc
+ #:comment "Load byte (preindex, increment)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 0 #:up? 1)
+
+(load-word/byte #:name ldrb-pre-dec-wb
+ #:comment "Load byte (preindex, decrement, writeback)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 1 #:up? 0)
+
+(load-word/byte #:name ldrb-pre-inc-wb
+ #:comment "Load byte (preindex, increment, writeback)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 1 #:up? 1)
+
+; Store word/byte insns.
+
+(define-pmacro (do-word/byte-store byte? preindex? writeback? up? offset-expr)
+ (sequence ((SI addr) (SI offset))
+ (set offset offset-expr)
+ (if preindex?
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset)))
+ (set addr rn))
+ ; If writeback in postindexing case -> do transfer
+ ; in non-priviledged mode.
+ ; FIXME: still need to handle non-word-aligned addresses
+ (if (andif (not preindex?) writeback?)
+ (if byte?
+ ; FIXME: specify "non-priviliged mode" `selector'
+ (set (mem QI addr) (trunc QI rd))
+ (set (mem SI addr) rd))
+ (if byte?
+ (set (mem QI addr) (trunc QI rd))
+ (set (mem SI addr) rd)))
+ (if (not preindex?)
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset))))
+ (if (orif (not preindex?)
+ (andif preindex? writeback?))
+ (set rn addr))
+ )
+)
+
+(define-pmacro (store-word/byte name comment size-char t-char
+ byte? preindex? writeback? up?)
+ (begin
+ (dnai (.sym name -imm-offset)
+ (.str comment ", immediate offset")
+ ()
+ (.str "ldr${cond}" size-char t-char " $rd,???")
+ (+ cond (f-op2 1)
+ (f-imm? 0) (f-preindex? preindex?) (f-up-down up?)
+ (f-byte-qty? byte?) (f-write-back? writeback?)
+ (f-load? 0) rn rd uimm12)
+ (do-word/byte-store byte? preindex? writeback? up? uimm12)
+ )
+
+ (dnai (.sym name -reg-offset)
+ (.str comment ", register offset")
+ ()
+ (.str "str${cond}" size-char t-char " $rd,???")
+ (+ cond (f-op2 1)
+ (f-imm? 1) (f-preindex? preindex?) (f-up-down up?)
+ (f-byte-qty? byte?) (f-write-back? writeback?)
+ (f-load? 0) rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (do-word/byte-store byte? preindex? writeback? up?
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ )
+ )
+)
+
+(store-word/byte #:name str-post-dec
+ #:comment "Store word (postindex, decrement)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 0 #:writeback? 0 #:up? 0)
+
+(store-word/byte #:name str-post-inc
+ #:comment "Store word (postindex, increment)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 0 #:writeback? 0 #:up? 1)
+
+(store-word/byte #:name str-post-dec-nonpriv
+ #:comment "Store word (postindex, decrement, nonpriv)"
+ #:size-char "" #:t-char "t"
+ #:byte? 0 #:preindex? 0 #:writeback? 1 #:up? 0)
+
+(store-word/byte #:name str-post-inc-nonpriv
+ #:comment "Store word (postindex, increment, nonpriv)"
+ #:size-char "" #:t-char "t"
+ #:byte? 0 #:preindex? 0 #:writeback? 1 #:up? 1)
+
+(store-word/byte #:name str-pre-dec
+ #:comment "Store word (preindex, decrement)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 0 #:up? 0)
+
+(store-word/byte #:name str-pre-inc
+ #:comment "Store word (preindex, increment)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 0 #:up? 1)
+
+(store-word/byte #:name str-pre-dec-wb
+ #:comment "Store word (preindex, decrement, writeback)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 1 #:up? 0)
+
+(store-word/byte #:name str-pre-inc-wb
+ #:comment "Store word (preindex, increment, writeback)"
+ #:size-char "" #:t-char ""
+ #:byte? 0 #:preindex? 1 #:writeback? 1 #:up? 1)
+
+(store-word/byte #:name strb-post-dec
+ #:comment "Store byte (postindex, decrement)"
+ #:size-char "b" #:t-char ""
+ #:byte? 1 #:preindex? 0 #:writeback? 0 #:up? 0)
+
+(store-word/byte #:name strb-post-inc
+ #:comment "Store byte (postindex, increment)"
+ #:size-char "" #:t-char ""
+ #:byte? 1 #:preindex? 0 #:writeback? 0 #:up? 1)
+
+(store-word/byte #:name strb-post-dec-nonpriv
+ #:comment "Store byte (postindex, decrement, nonpriv)"
+ #:size-char "" #:t-char "t"
+ #:byte? 1 #:preindex? 0 #:writeback? 1 #:up? 0)
+
+(store-word/byte #:name strb-post-inc-nonpriv
+ #:comment "Store byte (postindex, increment, nonpriv)"
+ #:size-char "" #:t-char "t"
+ #:byte? 1 #:preindex? 0 #:writeback? 1 #:up? 1)
+
+(store-word/byte #:name strb-pre-dec
+ #:comment "Store byte (preindex, decrement)"
+ #:size-char "" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 0 #:up? 0)
+
+(store-word/byte #:name strb-pre-inc
+ #:comment "Store byte (preindex, increment)"
+ #:size-char "" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 0 #:up? 1)
+
+(store-word/byte #:name strb-pre-dec-wb
+ #:comment "Store byte (preindex, decrement, writeback)"
+ #:size-char "" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 1 #:up? 0)
+
+(store-word/byte #:name strb-pre-inc-wb
+ #:comment "Store byte (preindex, increment, writeback)"
+ #:size-char "" #:t-char ""
+ #:byte? 1 #:preindex? 1 #:writeback? 1 #:up? 1)
+
+; Halfword and signed load insns.
+
+(define-pmacro (do-halfword-load preindex? up? writeback? signed?
+ halfword? offset-expr)
+ (sequence ((SI addr) (SI offset))
+ (set offset offset-expr)
+
+ ; Handle pre-increment.
+ (if preindex?
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset)))
+ (set addr rn))
+
+ ; Do the transfer; sign extend the result.
+ (if halfword?
+ (if signed?
+ (if (eq f-rd 15)
+ (set pc (ext SI (mem HI addr)))
+ (set rd (ext SI (mem HI addr))))
+ (if (eq f-rd 15)
+ (set pc (zext SI (mem HI addr)))
+ (set rd (zext SI (mem HI addr)))))
+ (if (eq f-rd 15)
+ (set pc (ext SI (mem QI addr)))
+ (set rd (ext SI (mem QI addr)))))
+
+ (if (not preindex?)
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset))))
+
+ ; Write back the modified base register.
+ (if (orif (not preindex?)
+ (andif preindex? writeback?))
+ (set rn addr))
+ )
+)
+
+(define-pmacro (load-halfword name comment preindex? up? writeback?
+ signed? halfword?)
+ (begin
+ (dnai (.sym name -imm-offset)
+ (.str comment ", immediate offset")
+ ()
+ (.str "FIXME")
+ (+ cond (f-op3 0) (f-preindex? preindex?) (f-up-down up?)
+ (f-bit22 1) (f-write-back? writeback?) (f-load? 1)
+ rn rd (f-bit7 1) (f-signed? signed?) (f-halfword? halfword?)
+ (f-bit4 1) hdt-offset8)
+ (do-halfword-load preindex? up? writeback? signed? halfword? hdt-offset8)
+ )
+ (dnai (.sym name -reg-offset)
+ (.str comment ", register offset")
+ ()
+ (.str "FIXME")
+ (+ cond (f-op3 0) (f-preindex? preindex?) (f-up-down up?)
+ (f-bit22 0) (f-write-back? writeback?) (f-load? 1)
+ rn rd (f-offset4-hi 0) (f-bit7 1) (f-signed? signed?)
+ (f-halfword? halfword?) (f-bit4 1) rm)
+ (do-halfword-load preindex? up? writeback? signed? halfword? rm)
+ )
+ )
+)
+
+(define-pmacro (do-halfword-store preindex? up? writeback? offset-expr)
+ (sequence ((SI addr) (SI offset))
+ (set offset offset-expr)
+
+ ; Handle pre-increment.
+ (if preindex?
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset)))
+ (set addr rn))
+
+ ; Do the transfer; unsigned halfwords only.
+ (set (mem HI addr) (trunc HI rd))
+
+ (if (not preindex?)
+ (if up?
+ (set addr (add rn offset))
+ (set addr (sub rn offset))))
+
+ (if (orif (not preindex?)
+ (andif preindex? writeback?))
+ (set rn addr))
+ )
+)
+
+(define-pmacro (store-halfword name comment preindex? up? writeback?)
+ (begin
+ (dnai (.sym name -imm-offset)
+ (.str comment ", immediate offset")
+ ()
+ (.str "FIXME")
+ (+ cond (f-op3 0) (f-preindex? preindex?) (f-up-down up?)
+ (f-bit22 1) (f-write-back? writeback?) (f-load? 0)
+ rn rd (f-bit7 1) (f-signed? 0) (f-halfword? 1)
+ (f-bit4 1) hdt-offset8)
+ (do-halfword-store preindex? up? writeback? hdt-offset8)
+ )
+ (dnai (.sym name -reg-offset)
+ (.str comment ", register offset")
+ ()
+ (.str "FIXME")
+ (+ cond (f-op3 0) (f-preindex? preindex?) (f-up-down up?)
+ (f-bit22 0) (f-write-back? writeback?) (f-load? 0)
+ rn rd (f-offset4-hi 0) (f-bit7 1) (f-signed? 0)
+ (f-halfword? 1) (f-bit4 1) rm)
+ (do-halfword-store preindex? up? writeback? rm)
+ )
+ )
+)
+
+(store-halfword #:name strh-pre-dec
+ #:comment "Store halfword (predecrement)"
+ #:preindex? 1 #:up? 0 #:writeback? 0)
+
+(store-halfword #:name strh-pre-inc
+ #:comment "Store halfword (preincrement)"
+ #:preindex? 1 #:up? 1 #:writeback? 0)
+
+(store-halfword #:name strh-pre-dec-wb
+ #:comment "Store halfword (predec, writeback)"
+ #:preindex? 1 #:up? 0 #:writeback? 1)
+
+(store-halfword #:name strh-pre-inc-wb
+ #:comment "Store halfword (preinc, writeback)"
+ #:preindex? 1 #:up? 1 #:writeback? 1)
+
+(store-halfword #:name strh-post-dec
+ #:comment "Store halfword (postdecrement)"
+ #:preindex? 0 #:up? 0 #:writeback? 0)
+
+(store-halfword #:name strh-post-inc
+ #:comment "Store halfword (postindex, increment)"
+ #:preindex? 0 #:up? 1 #:writeback? 0)
+
+
+(load-halfword #:name ldrsb-pre-dec
+ #:comment "Load signed byte (predecrement)"
+ #:preindex? 1 #:up? 0 #:writeback? 0
+ #:signed? 1 #:halfword? 0)
+
+(load-halfword #:name ldrsb-pre-inc
+ #:comment "Load signed byte (preincrement)"
+ #:preindex? 1 #:up? 1 #:writeback? 0
+ #:signed? 1 #:halfword? 0)
+
+(load-halfword #:name ldrsb-pre-dec-wb
+ #:comment "Load signed byte (predec, writeback)"
+ #:preindex? 1 #:up? 0 #:writeback? 1
+ #:signed? 1 #:halfword? 0)
+
+(load-halfword #:name ldrsb-pre-inc-wb
+ #:comment "Load signed byte (preinc, writeback)"
+ #:preindex? 1 #:up? 1 #:writeback? 1
+ #:signed? 1 #:halfword? 0)
+
+(load-halfword #:name ldrsb-post-dec
+ #:comment "Load signed byte (postdecrement)"
+ #:preindex? 0 #:up? 0 #:writeback? 0
+ #:signed? 1 #:halfword? 0)
+
+(load-halfword #:name ldrsb-post-inc
+ #:comment "Load signed byte (postindex, increment)"
+ #:preindex? 0 #:up? 1 #:writeback? 0
+ #:signed? 1 #:halfword? 0)
+
+(load-halfword #:name ldrh-pre-dec
+ #:comment "Load halfword (predecrement)"
+ #:preindex? 1 #:up? 0 #:writeback? 0
+ #:signed? 0 #:halfword? 1)
+
+(load-halfword #:name ldrh-pre-inc
+ #:comment "Load halfword (preincrement)"
+ #:preindex? 1 #:up? 1 #:writeback? 0
+ #:signed? 0 #:halfword? 1)
+
+(load-halfword #:name ldrh-pre-dec-wb
+ #:comment "Load halfword (predec, writeback)"
+ #:preindex? 1 #:up? 0 #:writeback? 1
+ #:signed? 0 #:halfword? 1)
+
+(load-halfword #:name ldrh-pre-inc-wb
+ #:comment "Load halfword (preinc, writeback)"
+ #:preindex? 1 #:up? 1 #:writeback? 1
+ #:signed? 0 #:halfword? 1)
+
+(load-halfword #:name ldrh-post-dec
+ #:comment "Load halfword (postdecrement)"
+ #:preindex? 0 #:up? 0 #:writeback? 0
+ #:signed? 0 #:halfword? 1)
+
+(load-halfword #:name ldrh-post-inc
+ #:comment "Load halfword (postincrement)"
+ #:preindex? 0 #:up? 1 #:writeback? 0
+ #:signed? 0 #:halfword? 1)
+
+(load-halfword #:name ldrsh-pre-dec
+ #:comment "Load signed halfword (predecrement)"
+ #:preindex? 1 #:up? 0 #:writeback? 0
+ #:signed? 1 #:halfword? 1)
+
+(load-halfword #:name ldrsh-pre-inc
+ #:comment "Load signed halfword (preincrement)"
+ #:preindex? 1 #:up? 1 #:writeback? 0
+ #:signed? 1 #:halfword? 1)
+
+(load-halfword #:name ldrsh-pre-dec-wb
+ #:comment "Load signed halfword (predec, writeback)"
+ #:preindex? 1 #:up? 0 #:writeback? 1
+ #:signed? 1 #:halfword? 1)
+
+(load-halfword #:name ldrsh-pre-inc-wb
+ #:comment "Load signed halfword (preinc, writeback)"
+ #:preindex? 1 #:up? 1 #:writeback? 1
+ #:signed? 1 #:halfword? 1)
+
+(load-halfword #:name ldrsh-post-dec
+ #:comment "Load signed halfword (postdecrement)"
+ #:preindex? 0 #:up? 0 #:writeback? 0
+ #:signed? 1 #:halfword? 1)
+
+(load-halfword #:name ldrsh-post-inc
+ #:comment "Load signed halfword (postincrement)"
+ #:preindex? 0 #:up? 1 #:writeback? 0
+ #:signed? 1 #:halfword? 1)
+
+; Multiply instructions.
+
+(define-pmacro (set-mul-cond-maybe result)
+ (if set-cc?
+ (sequence ()
+ ; vbit is not affected
+ ; cbit is set to a meaningless value, we just ignore it
+ (set zbit (zflag WI result))
+ (set nbit (nflag WI result))))
+)
+
+(define-pmacro (set-muldi-cond-maybe result)
+ (if set-cc?
+ (sequence ()
+ ; vbit,cbit are set to meaningless values, we just ignore them
+ (set zbit (zflag DI result))
+ (set nbit (nflag DI result))))
+)
+
+(dnai mul "Multiply"
+ ()
+ "mul$cond${set-cc?} ${mul-rd},$rm,$rs"
+ (+ cond (f-op6 0) (f-acc? 0) set-cc? mul-rd mul-rn rs (f-op-mul 9) rm)
+ (sequence ((WI result))
+ (set result (mul rm rs))
+ (set mul-rd result)
+ (set-mul-cond-maybe result))
+)
+
+(dnai mla "Multiply and accumulate"
+ ()
+ "mla$cond${set-cc?} ${mul-rd},$rm,$rs,${mul-rn}"
+ (+ cond (f-op6 0) (f-acc? 1) set-cc? mul-rd mul-rn rs (f-op-mul 9) rm)
+ (sequence ((WI result))
+ (set mul-rd (add (mul rm rs) mul-rn))
+ (set-mul-cond-maybe result))
+)
+
+(dnai umull "Multiply long (unsigned)"
+ ()
+ "umull$cond${set-cc?} $rdlo,$rdhi,$rm,$rs"
+ (+ cond (f-op5 1) (f-unsigned? 0) (f-acc? 0) set-cc? rdhi rdlo rs (f-op-mul 9) rm)
+ (sequence ((DI mul-result) (SI hi) (SI lo))
+ (set mul-result (mul (zext DI rs) (zext DI rm)))
+ (set rdhi (subword SI mul-result 0))
+ (set rdlo (subword SI mul-result 1))
+ (set-muldi-cond-maybe mul-result))
+)
+
+(dnai umlal "Multiply long and accumulate (unsigned)"
+ ()
+ "umlal$cond${set-cc?} $rdlo,$rdhi,$rm,$rs"
+ (+ cond (f-op5 1) (f-unsigned? 0) (f-acc? 1) set-cc? rdhi rdlo rs (f-op-mul 9) rm)
+ (sequence ((DI mul-result) (SI hi) (SI lo))
+ (set mul-result (join DI SI rdhi rdlo))
+ (set mul-result
+ (add (mul (zext DI rs) (zext DI rm)) mul-result))
+ (set rdhi (subword SI mul-result 0))
+ (set rdlo (subword SI mul-result 1))
+ (set-muldi-cond-maybe mul-result))
+)
+
+(dnai smull "Multiply long (signed)"
+ ()
+ "smull$cond${set-cc?} $rdlo,$rdhi,$rm,$rs"
+ (+ cond (f-op5 1) (f-unsigned? 1) (f-acc? 0) set-cc? rdhi rdlo rs
+ (f-op-mul 9) rm)
+ (sequence ((DI mul-result) (SI hi) (SI lo))
+ (set mul-result (mul (ext DI rs) (ext DI rm)))
+ (set rdhi (subword SI mul-result 0))
+ (set rdlo (subword SI mul-result 1))
+ (set-muldi-cond-maybe mul-result))
+)
+
+(dnai smlal "Multiply long and accumulate (signed)"
+ ()
+ "smlal$cond${set-cc?} $rdlo,$rdhi,$rm,$rs"
+ (+ cond (f-op5 1) (f-unsigned? 1) (f-acc? 1) set-cc? rdhi rdlo rs
+ (f-op-mul 9) rm)
+ (sequence ((DI mul-result) (SI hi) (SI lo))
+ (set mul-result (join DI SI rdhi rdlo))
+ (set mul-result
+ (add (mul (ext DI rs) (ext DI rm)) mul-result))
+ (set rdhi (subword SI mul-result 0))
+ (set rdlo (subword SI mul-result 1))
+ (set-muldi-cond-maybe mul-result))
+)
+
+(dnai swp "Swap word"
+ ()
+ "swp$cond $rd,$rm,[$rn]"
+ (+ cond (f-op5 2) (f-byte-qty? 0) (f-op-swap1 #b00) rn rd
+ (f-op-swap2 9) rm)
+ (sequence ((WI temp))
+ (set temp (mem WI rn)) ; read contents of swap address
+ (set (mem WI rn) rm) ; write rm to the swap address
+ (set rd temp)) ; store old swap contents in rd
+)
+
+(dnai swpb "Swap byte"
+ ()
+ "swpb${cond}b $rd,$rm,[$rn]"
+ (+ cond (f-op5 2) (f-byte-qty? 1) (f-op-swap1 #b00) rn rd
+ (f-op-swap2 #b00001001) rm)
+ (sequence ((WI temp))
+ (set temp (mem QI rn)) ; read contents of swap address
+ (set (mem QI rn) rm) ; write rm to the swap address
+ (set rd temp)) ; store old swap contents in rd
+)
+
+(dnai swi "Software interrupt"
+ ()
+ "swi$cond ${swi-comment}"
+ (+ cond (f-op4 #xF) swi-comment)
+ ; Take the software trap. Jump to the vector held in
+ ; 0x8. User code retrieves the comment field itself (see the
+ ; SWI instruction description in the ARM 7TDMI data sheet).
+ ; FIXME: more state change than this occurs
+ ;(set pc (mem WI 8)))
+ (set pc (c-call SI "arm_swi" pc swi-comment))
+)
+
+; Data processing [sic] instructions with a register for operand2.
+; The immediate operand2 case is handled separately.
+;
+; FIXME: 'twould be nice to split up each semantic element into
+; shifttype, set-cc/no-set-cc, set-pc,no-set-pc cases.
+; This is something that could be done as an optimization or extension,
+; without having to change this code [which would have general utility].
+;
+; FIXME: assembler syntaxes don't take into account unary vs binary vs
+; no-result. Later.
+
+; Logical operation semantic code.
+;
+; Flag handling if rd != pc:
+; cbit is set to the carry out of a shift operation if present
+; nbit is set to the sign bit
+; vbit is not affected
+; zflag is set to indicate whether the result was zero or not
+;
+; Flag handling if rd = pc:
+; cpsr is set from spsr
+; N.B. The pc must be set before setting cpsr as the registers that go into
+; computing the new value of pc may change when cpsr is set (new register
+; bank may get installed).
+
+; Logical operation, with a result.
+
+(define-pmacro (logical-op mnemonic comment-text opcode semantic-fn)
+ (begin
+ (dnai
+ (.sym mnemonic -reg/imm-shift)
+ (.str comment-text " immediate shift")
+ ()
+ (.str mnemonic "$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftimm}")
+ (+ cond (f-op2 0) (f-imm? 0) opcode set-cc? rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (sequence ((SI operand2) (BI carry-out) (SI result))
+ (set operand2
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ (set carry-out
+ (c-call BI "compute_carry_out_immshift" rm
+ operand2-shifttype operand2-shiftimm cbit))
+ (set result (semantic-fn rn operand2))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-logical-cc result carry-out)))))
+ )
+ (dnai
+ (.sym mnemonic -reg/reg-shift)
+ (.str comment-text " register shift")
+ ((R15-OFFSET 12))
+ (.str mnemonic "$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftreg}")
+ (+ cond (f-op2 0) (f-imm? 0) opcode set-cc? rn rd rm
+ (f-operand2-reg? 1) (f-bit7 0)
+ operand2-shifttype operand2-shiftreg)
+ (sequence ((SI operand2) (BI carry-out) (SI result))
+ (set operand2
+ (c-call SI "compute_operand2_regshift" rm
+ operand2-shifttype operand2-shiftreg))
+ (set carry-out
+ (c-call BI "compute_carry_out_regshift" rm
+ operand2-shifttype operand2-shiftreg cbit))
+ (set result (semantic-fn rn operand2))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-logical-cc result carry-out)))))
+ )
+ )
+)
+
+; Arithmetic operation semantic code.
+;
+; Flag handling if rd != pc:
+; cbit is set to the carry out of the ALU
+; N.B. For subtraction, the "carry" bit is actually a "borrow" bit.
+; nbit is set to the sign bit
+; vbit is set to indicate if an overflow occured
+; zbit is set to indicate whether the result was zero or not
+;
+; Flag handling if rd = pc:
+; cpsr is set from spsr
+
+; Arithmetic operation, with a result.
+
+(define-pmacro (arith-op mnemonic comment-text opcode semantic-fn set-flags)
+ (begin
+ (dnai
+ (.sym mnemonic -reg/imm-shift)
+ (.str comment-text " immediate shift")
+ ()
+ (.str mnemonic "$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftimm}")
+ (+ cond (f-op2 0) (f-imm? 0) opcode set-cc? rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (sequence ((SI operand2) (SI result) (SI temp-op1) (SI temp-op2))
+ (set operand2
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ (set temp-op1 rn)
+ (set temp-op2 operand2)
+ (set result (semantic-fn rn operand2 cbit))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-flags temp-op1 temp-op2 cbit)))))
+ )
+ (dnai
+ (.sym mnemonic -reg/reg-shift)
+ (.str comment-text " register shift")
+ ((R15-OFFSET 12))
+ (.str mnemonic "$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftreg}")
+ (+ cond (f-op2 0) (f-imm? 0) opcode set-cc? rn rd rm
+ (f-operand2-reg? 1) (f-bit7 0)
+ operand2-shifttype operand2-shiftreg)
+ (sequence ((SI operand2) (SI result) (SI temp-op1) (SI temp-op2))
+ (set operand2
+ (c-call SI "compute_operand2_regshift" rm
+ operand2-shifttype operand2-shiftreg))
+ (set temp-op1 rn)
+ (set temp-op2 operand2)
+ (set result (semantic-fn rn operand2 cbit))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-flags temp-op1 temp-op2 cbit)))))
+ )
+ )
+)
+
+; Arithmetic operation, with a result and immediate operand.
+
+(define-pmacro (arith-imm-op mnemonic comment-text opcode semantic-fn set-flags)
+ (dnai (.sym mnemonic -imm)
+ (.str comment-text " immediate")
+ ()
+ (.str mnemonic "$cond${set-cc?} $rd,$rn,$imm12")
+ (+ cond (f-op2 0) (f-imm? 1) opcode set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result (semantic-fn rn imm12 cbit))
+ (if (eq f-rd 15)
+ (sequence ()
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr)))
+ (set pc result))
+ (sequence ()
+ (if set-cc?
+ (set-flags rn imm12 cbit))
+ (set rd result))))
+ )
+)
+
+; Logical data processing insns.
+
+(logical-op and "Bitwise AND" OP_AND and)
+
+(dnai and-imm "Bitwise AND immediate" ()
+ "and$cond${set-cc?} $rd,$rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_AND set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result (and rn imm12))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-zn-flags result)))))
+)
+
+(logical-op orr "Bitwise OR" OP_ORR or)
+
+(dnai orr-imm "Bitwise OR immediate" ()
+ "orr$cond${set-cc?} $rd,$rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_ORR set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result (or rn imm12))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-zn-flags result)))))
+)
+
+(logical-op eor "Exclusive OR" OP_EOR xor)
+
+(dnai eor-imm "Exclusive OR immediate" ()
+ "eor$cond${set-cc?} $rd,$rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_EOR set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result (xor rn imm12))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-zn-flags result)))))
+)
+
+(logical-op mov "Move" OP_MOV (.pmacro (arg1 arg2) arg2))
+
+(dnai mov-imm "Move immediate" ()
+ "mov$cond${set-cc?} $rd,$imm12"
+ ; rn is ignored
+ (+ cond (f-op2 0) (f-imm? 1) OP_MOV set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result imm12)
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-zn-flags result)))))
+)
+
+(logical-op bic "Bit clear" OP_BIC (.pmacro (arg1 arg2) (and arg1 (inv arg2))))
+
+(dnai bic-imm "Bit clear immediate" ()
+ "bic$cond${set-cc?} $rd,$rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_BIC set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result (and rn (inv imm12)))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-zn-flags result)))))
+)
+
+(logical-op mvn "Move negate" OP_MVN (.pmacro (arg1 arg2) (inv arg2)))
+
+(dnai mvn-imm "Move (logical) negate immediate" ()
+ "mvn$cond${set-cc?} $rd,$imm12"
+ ; rn is ignored
+ (+ cond (f-op2 0) (f-imm? 1) OP_MVN set-cc? rn rd imm12)
+ (sequence ((SI result))
+ (set result (inv imm12))
+ (if (eq f-rd 15)
+ (sequence ()
+ (set pc result)
+ (if set-cc?
+ (set (reg h-cpsr) (reg h-spsr))))
+ (sequence ()
+ (set rd result)
+ (if set-cc?
+ (set-zn-flags result)))))
+)
+
+; Arithmetic data processing insns.
+
+(arith-op add "Add" OP_ADD
+ (.pmacro (arg1 arg2 carry) (add arg1 arg2))
+ (.pmacro (arg1 arg2 carry) (set-add-flags arg1 arg2 0))
+)
+
+(arith-imm-op add "Add" OP_ADD
+ (.pmacro (arg1 arg2 carry) (add arg1 arg2))
+ (.pmacro (arg1 arg2 carry) (set-add-flags arg1 arg2 0))
+)
+
+(arith-op adc "Add with carry" OP_ADC
+ (.pmacro (arg1 arg2 carry) (addc arg1 arg2 carry))
+ (.pmacro (arg1 arg2 carry) (set-add-flags arg1 arg2 carry))
+)
+
+(arith-imm-op adc "Add with carry" OP_ADC
+ (.pmacro (arg1 arg2 carry) (addc arg1 arg2 carry))
+ (.pmacro (arg1 arg2 carry) (set-add-flags arg1 arg2 carry))
+)
+
+(arith-op sub "Subtract" OP_SUB
+ (.pmacro (arg1 arg2 borrow) (sub arg1 arg2))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg1 arg2 1))
+)
+
+(arith-imm-op sub "Subtract" OP_SUB
+ (.pmacro (arg1 arg2 borrow) (sub arg1 arg2))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg1 arg2 1))
+)
+
+(arith-op sbc "Subtract with carry" OP_SBC
+ (.pmacro (arg1 arg2 borrow) (subc arg1 arg2 (not borrow)))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg1 arg2 borrow))
+)
+
+(arith-imm-op sbc "Subtract with carry" OP_SBC
+ (.pmacro (arg1 arg2 borrow) (subc arg1 arg2 (not borrow)))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg1 arg2 borrow))
+)
+
+(arith-op rsb "Reverse subtract" OP_RSB
+ (.pmacro (arg1 arg2 borrow) (sub arg2 arg1))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg2 arg1 1))
+)
+
+(arith-imm-op rsb "Reverse subtract" OP_RSB
+ (.pmacro (arg1 arg2 borrow) (sub arg2 arg1))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg2 arg1 1))
+)
+
+(arith-op rsc "Reverse subtract with carry" OP_RSC
+ (.pmacro (arg1 arg2 borrow) (subc arg2 arg1 (not borrow)))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg2 arg1 borrow))
+)
+
+(arith-imm-op rsc "Reverse subtract with carry" OP_RSC
+ (.pmacro (arg1 arg2 borrow) (subc arg2 arg1 (not borrow)))
+ (.pmacro (arg1 arg2 borrow) (set-sub-flags arg2 arg1 borrow))
+)
+
+; Comparison instructions.
+;
+; For the following data processing insns, the `S' mnemonic suffix is
+; redundant, but can be specified. The `S' bit is forced to 1 by the
+; assembler. rd is not used. rn is tested only.
+; `S' bit = 0 -> mrs,msr insns.
+
+(dnai tst-reg/imm-shift
+ "Test immediate shift"
+ ()
+ "tst$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftimm}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_TST (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (sequence ((SI operand2) (BI carry-out) (SI result))
+ (set operand2
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ (set carry-out
+ (c-call BI "compute_carry_out_immshift" rm
+ operand2-shifttype operand2-shiftimm cbit))
+ (set result (and rn operand2))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-logical-cc result carry-out)))
+)
+
+(dnai tst-reg/reg-shift
+ "Test register shift"
+ ((R15-OFFSET 12))
+ "tst$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftreg}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_TST (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 1) (f-bit7 0)
+ operand2-shifttype operand2-shiftreg)
+ (sequence ((SI operand2) (BI carry-out) (SI result))
+ (set operand2
+ (c-call SI "compute_operand2_regshift" rm
+ operand2-shifttype operand2-shiftreg))
+ (set carry-out
+ (c-call BI "compute_carry_out_regshift" rm
+ operand2-shifttype operand2-shiftreg cbit))
+ (set result (and rn operand2))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-logical-cc result carry-out)))
+)
+
+(dnai tst-imm "Test immediate" ()
+ "tst${cond}${set-cc?} $rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_TST (f-set-cc? 1) rn rd ror-imm8)
+ (sequence ((BI carry-out))
+ (if (eq f-ror-imm8-rotate 0)
+ (set carry-out cbit)
+ ; FIXME: nflag BI?
+ (set carry-out (nflag BI ror-imm8)))
+ (set-logical-cc (and rn ror-imm8) carry-out))
+)
+
+(dnai teq-reg/imm-shift
+ "Test equal immediate shift"
+ ()
+ "teq$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftimm}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_TEQ (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (sequence ((SI operand2) (BI carry-out) (SI result))
+ (set operand2
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ (set carry-out
+ (c-call BI "compute_carry_out_immshift" rm
+ operand2-shifttype operand2-shiftimm cbit))
+ (set result (xor rn operand2))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-logical-cc result carry-out)))
+)
+
+(dnai teq-reg/reg-shift
+ "Test equal register shift"
+ ((R15-OFFSET 12))
+ "teq$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftreg}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_TEQ (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 1) (f-bit7 0)
+ operand2-shifttype operand2-shiftreg)
+ (sequence ((SI operand2) (BI carry-out) (SI result))
+ (set operand2
+ (c-call SI "compute_operand2_regshift" rm
+ operand2-shifttype operand2-shiftreg))
+ (set carry-out
+ (c-call BI "compute_carry_out_regshift" rm
+ operand2-shifttype operand2-shiftreg cbit))
+ (set result (xor rn operand2))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-logical-cc result carry-out)))
+)
+
+(dnai teq-imm "Test equal immediate" ()
+ "teq${cond}${set-cc?} $rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_TEQ (f-set-cc? 1) rn rd ror-imm8)
+ ; The carry bit is preserved for the immediate form of this
+ ; insn. ??? Though semantic analysis will believe it's read/written.
+ (sequence ((BI carry-out))
+ (if (eq f-ror-imm8-rotate 0)
+ (set carry-out cbit)
+ ; FIXME: nflag BI?
+ (set carry-out (nflag BI ror-imm8)))
+ (set-logical-cc (xor rn ror-imm8) carry-out))
+)
+
+(dnai cmp-reg/imm-shift
+ "Compare immediate shift "
+ ()
+ "cmp$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftimm}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_CMP (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (sequence ((SI operand2))
+ (set operand2
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-sub-flags rn operand2 1)))
+)
+
+(dnai cmp-reg/reg-shift
+ "Compare register shift"
+ ((R15-OFFSET 12))
+ "cmp$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftreg}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_CMP (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 1) (f-bit7 0)
+ operand2-shifttype operand2-shiftreg)
+ (sequence ((SI operand2))
+ (set operand2
+ (c-call SI "compute_operand2_regshift" rm
+ operand2-shifttype operand2-shiftreg))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-sub-flags rn operand2 1)))
+)
+
+(dnai cmp-imm "Compare immediate" ()
+ "cmp${cond}${set-cc?} $rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_CMP (f-set-cc? 1) rn rd imm12)
+ (set-sub-flags rn imm12 1)
+)
+
+(dnai cmn-reg/imm-shift
+ "Compare negative immediate shift "
+ ()
+ "cmn$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftimm}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_CMN (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 0) operand2-shifttype operand2-shiftimm)
+ (sequence ((SI operand2))
+ (set operand2
+ (c-call SI "compute_operand2_immshift" rm
+ operand2-shifttype operand2-shiftimm))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-add-flags rn operand2 0)))
+)
+
+(dnai cmn-reg/reg-shift
+ "Compare negative register shift"
+ ((R15-OFFSET 12))
+ "cmn$cond${set-cc?} $rd,$rn,$rm,${operand2-shifttype} ${operand2-shiftreg}"
+ (+ cond (f-op2 0) (f-imm? 0) OP_CMN (f-set-cc? 1) rn rd rm
+ (f-operand2-reg? 1) (f-bit7 0)
+ operand2-shifttype operand2-shiftreg)
+ (sequence ((SI operand2))
+ (set operand2
+ (c-call SI "compute_operand2_regshift" rm
+ operand2-shifttype operand2-shiftreg))
+ (if (eq f-rd 15)
+ (set (reg h-cpsr) (reg h-spsr))
+ (set-add-flags rn operand2 0)))
+)
+
+(dnai cmn-imm "Compare negative immediate" ()
+ "cmn${cond}${set-cc?} $rn,$imm12"
+ (+ cond (f-op2 0) (f-imm? 1) OP_CMN (f-set-cc? 1) rn rd imm12)
+ ; ??? Is this right?
+ (set-add-flags rn imm12 0)
+)
+
+; Multiple load and store insns.
+
+(define-pmacro (multi-action bit-num semantic-fn)
+ (if (and reglist (sll 1 bit-num))
+ (semantic-fn bit-num))
+)
+
+(define-pmacro (ldmda-action bit-num)
+ (sequence ()
+ (set (reg WI h-gr bit-num) (mem WI addr))
+ (set addr (sub addr 4)))
+)
+
+(define-pmacro (ldmda-action-r15 ignored)
+ (sequence ()
+ (set pc (mem WI addr))
+ (set addr (sub addr 4)))
+)
+
+(dnai ldmda "Load multiple registers (postindex, decrement)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 ldmda-action-r15)
+ (multi-action 14 ldmda-action)
+ (multi-action 13 ldmda-action)
+ (multi-action 12 ldmda-action)
+ (multi-action 11 ldmda-action)
+ (multi-action 10 ldmda-action)
+ (multi-action 9 ldmda-action)
+ (multi-action 8 ldmda-action)
+ (multi-action 7 ldmda-action)
+ (multi-action 6 ldmda-action)
+ (multi-action 5 ldmda-action)
+ (multi-action 4 ldmda-action)
+ (multi-action 3 ldmda-action)
+ (multi-action 2 ldmda-action)
+ (multi-action 1 ldmda-action)
+ (multi-action 0 ldmda-action)
+ )
+)
+
+(dnai ldmda-wb "Load multiple registers (postindex, decrement, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 ldmda-action-r15)
+ (multi-action 14 ldmda-action)
+ (multi-action 13 ldmda-action)
+ (multi-action 12 ldmda-action)
+ (multi-action 11 ldmda-action)
+ (multi-action 10 ldmda-action)
+ (multi-action 9 ldmda-action)
+ (multi-action 8 ldmda-action)
+ (multi-action 7 ldmda-action)
+ (multi-action 6 ldmda-action)
+ (multi-action 5 ldmda-action)
+ (multi-action 4 ldmda-action)
+ (multi-action 3 ldmda-action)
+ (multi-action 2 ldmda-action)
+ (multi-action 1 ldmda-action)
+ (multi-action 0 ldmda-action)
+ (set rn addr))
+)
+
+(define-pmacro (ldmib-action bit-num)
+ (sequence ()
+ (set addr (add addr 4))
+ (set (reg WI h-gr bit-num) (mem WI addr)))
+)
+
+(define-pmacro (ldmib-action-r15 ignored)
+ (sequence ()
+ (set addr (add addr 4))
+ (set pc (mem WI addr)))
+)
+
+(dnai ldmib "Load multiple register (preindex, increment)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 ldmib-action)
+ (multi-action 1 ldmib-action)
+ (multi-action 2 ldmib-action)
+ (multi-action 3 ldmib-action)
+ (multi-action 4 ldmib-action)
+ (multi-action 5 ldmib-action)
+ (multi-action 6 ldmib-action)
+ (multi-action 7 ldmib-action)
+ (multi-action 8 ldmib-action)
+ (multi-action 9 ldmib-action)
+ (multi-action 10 ldmib-action)
+ (multi-action 11 ldmib-action)
+ (multi-action 12 ldmib-action)
+ (multi-action 13 ldmib-action)
+ (multi-action 14 ldmib-action)
+ (multi-action 15 ldmib-action-r15))
+)
+
+(dnai ldmib-wb "Load multiple registers (preindex, increment, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 ldmib-action)
+ (multi-action 1 ldmib-action)
+ (multi-action 2 ldmib-action)
+ (multi-action 3 ldmib-action)
+ (multi-action 4 ldmib-action)
+ (multi-action 5 ldmib-action)
+ (multi-action 6 ldmib-action)
+ (multi-action 7 ldmib-action)
+ (multi-action 8 ldmib-action)
+ (multi-action 9 ldmib-action)
+ (multi-action 10 ldmib-action)
+ (multi-action 11 ldmib-action)
+ (multi-action 12 ldmib-action)
+ (multi-action 13 ldmib-action)
+ (multi-action 14 ldmib-action)
+ (multi-action 15 ldmib-action-r15)
+ (set rn addr))
+)
+
+(define-pmacro (ldmia-action bit-num)
+ (sequence ()
+ (set (reg WI h-gr bit-num) (mem WI addr))
+ (set addr (add addr 4)))
+)
+
+(define-pmacro (ldmia-action-r15 ignored)
+ (sequence ()
+ (set pc (mem WI addr))
+ (set addr (add addr 4)))
+)
+
+(dnai ldmia "Load multiple registers (postindex, increment)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 ldmia-action)
+ (multi-action 1 ldmia-action)
+ (multi-action 2 ldmia-action)
+ (multi-action 3 ldmia-action)
+ (multi-action 4 ldmia-action)
+ (multi-action 5 ldmia-action)
+ (multi-action 6 ldmia-action)
+ (multi-action 7 ldmia-action)
+ (multi-action 8 ldmia-action)
+ (multi-action 9 ldmia-action)
+ (multi-action 10 ldmia-action)
+ (multi-action 11 ldmia-action)
+ (multi-action 12 ldmia-action)
+ (multi-action 13 ldmia-action)
+ (multi-action 14 ldmia-action)
+ (multi-action 15 ldmia-action-r15))
+)
+
+(dnai ldmia-wb "Load multiple registers (postindex, increment, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 ldmia-action)
+ (multi-action 1 ldmia-action)
+ (multi-action 2 ldmia-action)
+ (multi-action 3 ldmia-action)
+ (multi-action 4 ldmia-action)
+ (multi-action 5 ldmia-action)
+ (multi-action 6 ldmia-action)
+ (multi-action 7 ldmia-action)
+ (multi-action 8 ldmia-action)
+ (multi-action 9 ldmia-action)
+ (multi-action 10 ldmia-action)
+ (multi-action 11 ldmia-action)
+ (multi-action 12 ldmia-action)
+ (multi-action 13 ldmia-action)
+ (multi-action 14 ldmia-action)
+ (multi-action 15 ldmia-action-r15)
+ (set rn addr))
+)
+
+(define-pmacro (ldmdb-action bit-num)
+ (sequence ()
+ (set addr (sub addr 4))
+ (set (reg WI h-gr bit-num) (mem WI addr)))
+)
+
+(define-pmacro (ldmdb-action-r15 bit-num)
+ (sequence ()
+ (set addr (sub addr 4))
+ (set pc (mem WI addr)))
+)
+
+(dnai ldmdb "Load multiple registers (preindex, decrement)"
+ ()
+ "ldm$cond .."
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 ldmdb-action-r15)
+ (multi-action 14 ldmdb-action)
+ (multi-action 13 ldmdb-action)
+ (multi-action 12 ldmdb-action)
+ (multi-action 11 ldmdb-action)
+ (multi-action 10 ldmdb-action)
+ (multi-action 9 ldmdb-action)
+ (multi-action 8 ldmdb-action)
+ (multi-action 7 ldmdb-action)
+ (multi-action 6 ldmdb-action)
+ (multi-action 5 ldmdb-action)
+ (multi-action 4 ldmdb-action)
+ (multi-action 3 ldmdb-action)
+ (multi-action 2 ldmdb-action)
+ (multi-action 1 ldmdb-action)
+ (multi-action 0 ldmdb-action))
+)
+
+(dnai ldmdb-wb "Load multiple registers (preindex, decrement, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 1) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 ldmdb-action-r15)
+ (multi-action 14 ldmdb-action)
+ (multi-action 13 ldmdb-action)
+ (multi-action 12 ldmdb-action)
+ (multi-action 11 ldmdb-action)
+ (multi-action 10 ldmdb-action)
+ (multi-action 9 ldmdb-action)
+ (multi-action 8 ldmdb-action)
+ (multi-action 7 ldmdb-action)
+ (multi-action 6 ldmdb-action)
+ (multi-action 5 ldmdb-action)
+ (multi-action 4 ldmdb-action)
+ (multi-action 3 ldmdb-action)
+ (multi-action 2 ldmdb-action)
+ (multi-action 1 ldmdb-action)
+ (multi-action 0 ldmdb-action)
+ (set rn addr))
+)
+
+(define-pmacro (stmdb-action bit-num)
+ (sequence ()
+ (set addr (sub addr 4))
+ (set (mem WI addr) (reg WI h-gr bit-num)))
+)
+
+(define-pmacro (stmdb-action-r15 ignore)
+ (sequence ()
+ (set addr (sub addr 4))
+ (set (mem WI addr) (add (reg WI h-gr 15) 4)))
+)
+
+(dnai stmdb "Store multiple registers (preindex, decrement)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 stmdb-action-r15)
+ (multi-action 14 stmdb-action)
+ (multi-action 13 stmdb-action)
+ (multi-action 12 stmdb-action)
+ (multi-action 11 stmdb-action)
+ (multi-action 10 stmdb-action)
+ (multi-action 9 stmdb-action)
+ (multi-action 8 stmdb-action)
+ (multi-action 7 stmdb-action)
+ (multi-action 6 stmdb-action)
+ (multi-action 5 stmdb-action)
+ (multi-action 4 stmdb-action)
+ (multi-action 3 stmdb-action)
+ (multi-action 2 stmdb-action)
+ (multi-action 1 stmdb-action)
+ (multi-action 0 stmdb-action))
+)
+
+(dnai stmdb-wb "Store multiple registers (preindex, decrement, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 stmdb-action-r15)
+ (multi-action 14 stmdb-action)
+ (multi-action 13 stmdb-action)
+ (multi-action 12 stmdb-action)
+ (multi-action 11 stmdb-action)
+ (multi-action 10 stmdb-action)
+ (multi-action 9 stmdb-action)
+ (multi-action 8 stmdb-action)
+ (multi-action 7 stmdb-action)
+ (multi-action 6 stmdb-action)
+ (multi-action 5 stmdb-action)
+ (multi-action 4 stmdb-action)
+ (multi-action 3 stmdb-action)
+ (multi-action 2 stmdb-action)
+ (multi-action 1 stmdb-action)
+ (multi-action 0 stmdb-action)
+ (set rn addr))
+)
+
+(define-pmacro (stmib-action bit-num)
+ (sequence ()
+ (set addr (add addr 4))
+ (set (mem WI addr) (reg WI h-gr bit-num)))
+)
+
+(define-pmacro (stmib-action-r15 ignore)
+ (sequence ()
+ (set addr (add addr 4))
+ (set (mem WI addr) (add (reg WI h-gr 15) 4)))
+)
+
+(dnai stmib "Store multiple registers (preindex, increment)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 stmib-action)
+ (multi-action 1 stmib-action)
+ (multi-action 2 stmib-action)
+ (multi-action 3 stmib-action)
+ (multi-action 4 stmib-action)
+ (multi-action 5 stmib-action)
+ (multi-action 6 stmib-action)
+ (multi-action 7 stmib-action)
+ (multi-action 8 stmib-action)
+ (multi-action 9 stmib-action)
+ (multi-action 10 stmib-action)
+ (multi-action 11 stmib-action)
+ (multi-action 12 stmib-action)
+ (multi-action 13 stmib-action)
+ (multi-action 14 stmib-action)
+ (multi-action 15 stmib-action-r15))
+)
+
+(dnai stmib-wb "Store multiple registers (preindex, increment, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 1) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 stmib-action)
+ (multi-action 1 stmib-action)
+ (multi-action 2 stmib-action)
+ (multi-action 3 stmib-action)
+ (multi-action 4 stmib-action)
+ (multi-action 5 stmib-action)
+ (multi-action 6 stmib-action)
+ (multi-action 7 stmib-action)
+ (multi-action 8 stmib-action)
+ (multi-action 9 stmib-action)
+ (multi-action 10 stmib-action)
+ (multi-action 11 stmib-action)
+ (multi-action 12 stmib-action)
+ (multi-action 13 stmib-action)
+ (multi-action 14 stmib-action)
+ (multi-action 15 stmib-action-r15)
+ (set rn addr))
+)
+
+(define-pmacro (stmia-action bit-num)
+ (sequence ()
+ (set (mem WI addr) (reg WI h-gr bit-num))
+ (set addr (add addr 4)))
+)
+
+(define-pmacro (stmia-action-r15 ignore)
+ (sequence ()
+ (set (mem WI addr) (add (reg WI h-gr 15) 4))
+ (set addr (add addr 4)))
+)
+
+(dnai stmia "Store multiple registers (postindex, increment)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 stmia-action)
+ (multi-action 1 stmia-action)
+ (multi-action 2 stmia-action)
+ (multi-action 3 stmia-action)
+ (multi-action 4 stmia-action)
+ (multi-action 5 stmia-action)
+ (multi-action 6 stmia-action)
+ (multi-action 7 stmia-action)
+ (multi-action 8 stmia-action)
+ (multi-action 9 stmia-action)
+ (multi-action 10 stmia-action)
+ (multi-action 11 stmia-action)
+ (multi-action 12 stmia-action)
+ (multi-action 13 stmia-action)
+ (multi-action 14 stmia-action)
+ (multi-action 15 stmia-action-r15))
+)
+
+(dnai stmia-wb "Store multiple registers (postindex, increment, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 1) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 0 stmia-action)
+ (multi-action 1 stmia-action)
+ (multi-action 2 stmia-action)
+ (multi-action 3 stmia-action)
+ (multi-action 4 stmia-action)
+ (multi-action 5 stmia-action)
+ (multi-action 6 stmia-action)
+ (multi-action 7 stmia-action)
+ (multi-action 8 stmia-action)
+ (multi-action 9 stmia-action)
+ (multi-action 10 stmia-action)
+ (multi-action 11 stmia-action)
+ (multi-action 12 stmia-action)
+ (multi-action 13 stmia-action)
+ (multi-action 14 stmia-action)
+ (multi-action 15 stmia-action-r15)
+ (set rn addr))
+)
+
+(define-pmacro (stmda-action-r15 ignore)
+ (sequence ()
+ (set (mem WI addr) (add (reg WI h-gr 15) 4))
+ (set addr (sub addr 4)))
+)
+
+(define-pmacro (stmda-action bit-num)
+ (sequence ()
+ (set (mem WI addr) (reg WI h-gr bit-num))
+ (set addr (sub addr 4)))
+)
+
+(dnai stmda "Store multiple registers (postindex, decrement)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 0) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 stmda-action-r15)
+ (multi-action 14 stmda-action)
+ (multi-action 13 stmda-action)
+ (multi-action 12 stmda-action)
+ (multi-action 11 stmda-action)
+ (multi-action 10 stmda-action)
+ (multi-action 9 stmda-action)
+ (multi-action 8 stmda-action)
+ (multi-action 7 stmda-action)
+ (multi-action 6 stmda-action)
+ (multi-action 5 stmda-action)
+ (multi-action 4 stmda-action)
+ (multi-action 3 stmda-action)
+ (multi-action 2 stmda-action)
+ (multi-action 1 stmda-action)
+ (multi-action 0 stmda-action))
+)
+
+(dnai stmda-wb "Store multiple registers (postindex, decrement, writeback)"
+ ()
+ "FIXME"
+ (+ cond (f-op3 4) (f-preindex? 0) (f-up-down 0) (f-load-psr? 0)
+ (f-write-back? 1) (f-load? 0) rn reglist)
+ (sequence ((WI addr))
+ (set addr rn)
+ (multi-action 15 stmda-action-r15)
+ (multi-action 14 stmda-action)
+ (multi-action 13 stmda-action)
+ (multi-action 12 stmda-action)
+ (multi-action 11 stmda-action)
+ (multi-action 10 stmda-action)
+ (multi-action 9 stmda-action)
+ (multi-action 8 stmda-action)
+ (multi-action 7 stmda-action)
+ (multi-action 6 stmda-action)
+ (multi-action 5 stmda-action)
+ (multi-action 4 stmda-action)
+ (multi-action 3 stmda-action)
+ (multi-action 2 stmda-action)
+ (multi-action 1 stmda-action)
+ (multi-action 0 stmda-action)
+ (set rn addr))
+)
+
+
+; Coprocessor instructions.
+; Currently not implemented, so omit these, such that we take the
+; undefined instruction trap as specified by the ARM documentation.
+
+(dnai mrs-c "Transfer CPSR contents to a register"
+ ()
+ "mrs$cond $rd,cpsr"
+ (+ cond (f-op5 2) PSR_CURRENT (f-op-mrs1 #xF) rd (f-op-mrs2 0))
+ (set rd (reg h-cpsr))
+)
+
+(dnai mrs-s "Transfer SPSR contents to a register"
+ ()
+ "mrs$cond $rd,spsr"
+ (+ cond (f-op5 2) PSR_SAVED (f-op-mrs1 #xF) rd (f-op-mrs2 0))
+ (set rd (reg h-spsr))
+)
+
+(dnai msr-c "Transfer register contents to CPSR"
+ ()
+ "msr$cond cpsr,$rm"
+ (+ cond (f-op5 2) PSR_CURRENT (f-op-msr1 #x29F) (f-op-msr2 0) rm)
+ (set (reg h-cpsr) rm)
+)
+
+(dnai msr-s "Transfer register contents to SPSR"
+ ()
+ "msr$cond spsr,$rm"
+ (+ cond (f-op5 2) PSR_SAVED (f-op-msr1 #x29F) (f-op-msr2 0) rm)
+ (set (reg h-spsr) rm)
+)
+
+; TODO: msr to flag bits only
+
+; Commented out until ifield assertions added, collides with str/ldr.
+; ??? It's possible to rewrite str,ldr, but assertions are wanted anyway.
+
+;(dnai undefined "Undefined instruction"
+; ()
+; "undef"
+; (+ cond (f-op3 3) undef-dont1 (f-bit4 1) undef-dont2)
+; ; Generate an undefined exception.
+; ; Jump to the vector held in 0x4.
+; ; FIXME: More state change than this occurs.
+; (set pc (mem WI #x4))
+;)
diff --git a/cgen/attr.scm b/cgen/attr.scm
new file mode 100644
index 00000000000..1d8cd7cbbc1
--- /dev/null
+++ b/cgen/attr.scm
@@ -0,0 +1,910 @@
+; Attributes.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; There are 4 kinds of attributes: boolean, integer, enum, and bitset. Boolean
+; attributes are really enum attributes with two possible values, but they
+; occur frequently enough that they are special cased.
+;
+; All objects that use attributes must have two methods:
+; - 'get-atlist - returns the object's attr-list
+; - 'set-atlist! - set the object's attr-list
+;
+; In .cpu files, attribute lists are associative lists of (NAME VALUE).
+; Boolean attributes are specified as (NAME #t) or (NAME #f),
+; but for convenience ATTR and !ATTR are also supported.
+; integer/enum attrs are specified as (ATTR value).
+; Bitset attrs are specified as (ATTR val1,val2,val3).
+; In all cases the value needn't be constant, and can be an expression,
+; though expressions are currently only supported for META-attributes
+; (attributes that don't appear in any generated code).
+;
+; Example:
+; (FOO1 !FOO2 (BAR 3) (FOO3 X) (MACH sparc,sparclite))
+;
+; ??? Implementation of expressions is being postponed as long
+; as possible, avoiding adding complications for complication's sake, and
+; because I'm not completely sure how I want to do them.
+; The syntax for an expression value is (ATTR (rtx-func ...)).
+;
+; ??? May wish to allow a bitset attribute like (ATTR val1,!val2), where `!'
+; means to turn off that particular bit (or bits if val2 refers to several).
+;
+; ??? May wish to allow specifying enum attributes by only having to
+; specify the value (move names into "enum space" or some such).
+
+; An attr-list (or "atlist") is a collection of attributes.
+; Attributes are stored as an associative list.
+; There is possible confusion between "alist" (associative-list) and
+; "atlist" (attribute-list) but in practice I haven't had a problem.
+; ??? May wish to change this to a list of objects, as the alist doesn't carry
+; enough info. However the alist is simple and fast.
+
+(define <attr-list> (class-make '<attr-list> nil '(prefix attrs) nil))
+
+(define atlist-prefix (elm-make-getter <attr-list> 'prefix))
+(define atlist-attrs (elm-make-getter <attr-list> 'attrs))
+
+(define (atlist? x) (class-instance? <attr-list> x))
+
+; An empty attribute-list.
+
+(define atlist-empty (make <attr-list> "" nil))
+
+; The attribute baseclass.
+; The attributes of <ident> are the set of attributes for this attribute
+; [meaning attributes themselves can have attributes].
+; [Ya, that's clumsily written. I left it that way for fun.]
+; An odd notion that is of some use. It's current raison d'etre is to
+; support sanitization of attributes [which is implemented with the
+; `sanitize' attribute].
+
+(define <attribute>
+ (class-make '<attribute>
+ '(<ident>)
+ '(
+ ; List of object types this attribute is for.
+ ; Possible element values are:
+ ; attr, enum, cpu, mach, model, ifield, hardware, operand,
+ ; insn
+ ; A value of #f means the attribute is for everything.
+ for
+ )
+ nil)
+)
+
+; Accessors.
+
+(define atlist-for (elm-make-getter <attribute> 'for))
+
+; A class for each type of attribute.
+
+; `values' exists for boolean-attribute to simplify the code, it's ignored.
+; Ditto for `default'. The default for boolean-attribute is always #f.
+
+(define <boolean-attribute>
+ (class-make '<boolean-attribute>
+ '(<attribute>)
+ '(default values)
+ nil)
+)
+
+; For bitset attributes, VALUES is a list of symbols, one for each bit.
+; Int's are used to record the bitset in the generated code so there's a limit
+; of 32 elements, though there's nothing inherent in the description language
+; that precludes removing the limit.
+
+(define <bitset-attribute>
+ (class-make '<bitset-attribute>
+ '(<attribute>)
+ '(default values)
+ nil)
+)
+
+; For integer attributes, VALUES is a list of ints, one for each possible
+; value, or the empty list of all values are permissible.
+
+(define <integer-attribute>
+ (class-make '<integer-attribute>
+ '(<attribute>)
+ '(default values)
+ nil)
+)
+
+; For enum attributes, VALUES is a list of symbols, one for each possible
+; value.
+
+(define <enum-attribute>
+ (class-make '<enum-attribute>
+ '(<attribute>)
+ '(default values)
+ nil)
+)
+
+; Return a boolean indicating if X is a <boolean-attribute> object.
+
+(define (bool-attr? x) (class-instance? <boolean-attribute> x))
+
+; Return a boolean indicating if X is a <bitset-attribute> object.
+
+(define (bitset-attr? x) (class-instance? <bitset-attribute> x))
+
+; Return a symbol indicating the kind of attribute ATTR is.
+; The result is one of boolean,integer,enum,bitset.
+
+(define (attr-kind attr)
+ (case (object-class-name attr)
+ ((<boolean-attribute>) 'boolean)
+ ((<integer-attribute>) 'integer)
+ ((<enum-attribute>) 'enum)
+ ((<bitset-attribute>) 'bitset)
+ (else (error "attr-kind: internal error, not an attribute class"
+ (object-class-name attr))))
+)
+
+; Accessors.
+
+(define (attr-default attr) (elm-xget attr 'default))
+(define (attr-values attr) (elm-xget attr 'values))
+
+; Create an attribute.
+; Attributes are stored in attribute lists using the actual value
+; rather than an object containing the value, so we only have to cons
+; NAME and VALUE rather than building some object. This is for simplicity
+; and speed. We try to incrementally complicate things, only as necessary.
+
+; VALUE must be #f or #t.
+
+(define (bool-attr-make name value) (cons name value))
+
+; VALUES must be a comma separated list of symbols
+; (e.g. val1,val2 not (val1 val2)).
+
+(define (bitset-attr-make name values) (cons name values))
+
+; VALUE must be a number (or maybe a symbol).
+
+(define (int-attr-make name value) (cons name value))
+
+; VALUE must be a symbol.
+
+(define (enum-attr-make name value) (cons name value))
+
+; A boolean attribute's value is either #t or #f.
+
+(method-make!
+ <boolean-attribute> 'parse-value
+ (lambda (self errtxt val)
+ (if (and (not (null? val))
+ (boolean? (car val)))
+ (cons (obj:name self) (car val))
+ (parse-error errtxt "boolean attribute not one of #f/#t"
+ (cons (obj:name self) val))))
+)
+
+; A bitset attribute's value is a comma separated list of elements.
+; We don't validate the values. In the case of the MACH attribute,
+; there's no current mechanism to create it after all define-mach's have
+; been read in.
+; ??? Need to decide whether all define-mach's must appear before any
+; define-insn's. It would be nice to be able to spread an architecture's
+; description over several .cpu files.
+; ??? On the other hand, all machs are specified in define-arch.
+; Perhaps creation of builtins could be defered until then.
+
+(method-make!
+ <bitset-attribute> 'parse-value
+ (lambda (self errtxt val)
+ (if (and (not (null? val))
+ (or (symbol? (car val))
+ (string? (car val)))
+ (null? (cdr val)))
+ (cons (obj:name self) (car val))
+ (parse-error errtxt "improper bitset attribute"
+ (cons (obj:name self) val))))
+)
+
+; An integer attribute's value is a number
+; (or maybe a symbol representing that value).
+
+(method-make!
+ <integer-attribute> 'parse-value
+ (lambda (self errtxt val)
+ (if (and (not (null? val))
+ (or (number? (car val)) (symbol? (car val)))
+ (null? (cdr val)))
+ (cons (obj:name self) (car val))
+ (parse-error errtxt "improper integer attribute"
+ (cons (obj:name self) val))))
+)
+
+; An enum attribute's value is a symbol representing that value.
+
+(method-make!
+ <enum-attribute> 'parse-value
+ (lambda (self errtxt val)
+ (if (and (not (null? val))
+ (or (symbol? (car val)) (string? (car val)))
+ (null? (cdr val)))
+ (cons (obj:name self) (car val))
+ (parse-error errtxt "improper enum attribute"
+ (cons (obj:name self) val))))
+)
+
+; Parse a boolean attribute's value definition.
+
+(method-make!
+ <boolean-attribute> 'parse-value-def
+ (lambda (self errtxt values)
+ (if (equal? values '(#f #t))
+ values
+ (parse-error errtxt "boolean value list must be (#f #t)" values)))
+)
+
+; Parse a bitset attribute's value definition.
+; FIXME: treated as enum?
+
+(method-make!
+ <bitset-attribute> 'parse-value-def
+ (lambda (self errtxt values)
+ (parse-enum-vals "" values))
+)
+
+; Parse an integer attribute's value definition.
+; FIXME: Unfinished.
+
+(method-make!
+ <integer-attribute> 'parse-value-def
+ (lambda (self errtxt values) values)
+)
+
+; Parse an enum attribute's value definition.
+; See parse-enum-vals for more info.
+
+(method-make!
+ <enum-attribute> 'parse-value-def
+ (lambda (self errtxt values)
+ (parse-enum-vals "" values))
+)
+
+; Make an attribute list object from a list of name/value pairs.
+
+(define (atlist-make prefix . attrs) (make <attr-list> prefix attrs))
+
+; Parse an attribute definition.
+; This is the main routine for building an attribute object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; TYPE-CLASS is the class of the object to create.
+; i.e. one of <{boolean,bitset,integer,enum}-attribute>.
+; If DEFAULT is #f, use the first value.
+; ??? Allowable values for integer attributes is wip.
+
+(define (-attr-parse errtxt type-class name comment attrs for default values)
+ (logit 2 "Processing attribute " name " ...\n")
+ (let* ((name (parse-name name errtxt))
+ (errtxt (string-append errtxt ":" name))
+ (result (new type-class))
+ (parsed-values (send result 'parse-value-def errtxt values)))
+ (elm-xset! result 'name name)
+ (elm-xset! result 'comment (parse-comment comment errtxt))
+ (elm-xset! result 'attrs (atlist-parse attrs "" errtxt))
+ (elm-xset! result 'for for)
+ ; Set the default.
+ (case (class-name type-class)
+ ((<boolean-attribute>)
+ (if (and (not (memq default '(#f #t)))
+ (not (rtx? default)))
+ (parse-error errtxt "invalid default" default))
+ (elm-xset! result 'default default))
+ ((<integer-attribute>)
+ (let ((default (if default default (if (null? values) 0 (car values)))))
+ (if (and (not (integer? default))
+ (not (rtx? default)))
+ (parse-error errtxt "invalid default" default))
+ (elm-xset! result 'default default)))
+ ((<bitset-attribute> <enum-attribute>)
+ (let ((default (if default default (caar parsed-values))))
+ (if (and (not (assq default parsed-values))
+ (not (rtx? default)))
+ (parse-error errtxt "invalid default" default))
+ (elm-xset! result 'default default))))
+ (elm-xset! result 'values parsed-values)
+ result)
+)
+
+; Read an attribute description
+; This is the main routine for analyzing attributes in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -attr-parse is invoked to create the attribute object.
+
+(define (-attr-read errtxt . arg-list)
+ (let (; Current attribute elements:
+ (type-class 'not-set) ; attribute type
+ (name nil)
+ (comment "")
+ (attrs nil)
+ (for #f) ; assume for everything
+ (default #f) ; assume boolean
+ (values '(#f #t)) ; assume boolean
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((type) (set! type-class (case (cadr arg)
+ ((boolean) <boolean-attribute>)
+ ((bitset) <bitset-attribute>)
+ ((integer) <integer-attribute>)
+ ((enum) <enum-attribute>)
+ (else (parse-error
+ errtxt
+ "invalid attribute type"
+ (cadr arg))))))
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((for) (set! for (cdr arg)))
+ ((default) (set! default (cadr arg)))
+ ((values) (set! values (cdr arg)))
+ (else (parse-error errtxt "invalid attribute arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-attr-parse errtxt type-class name comment attrs for default values)
+ )
+)
+
+; Main routine for defining attributes in .cpu files.
+
+(define define-attr
+ (lambda arg-list
+ (let ((a (apply -attr-read (cons "define-attr" arg-list))))
+ (current-attr-add! a)
+ a))
+)
+
+; Query routines.
+
+; Lookup ATTR-NAME in ATTR-LIST.
+; The result is the object or #f if not found.
+
+(define (attr-lookup attr-name attr-list)
+ (object-assq attr-name attr-list)
+)
+
+; Return a boolean indicating if boolean attribute ATTR is "true" in
+; attribute alist ALIST.
+; Note that if the attribute isn't present, it is defined to be #f.
+
+(define (attr-has-attr? alist attr)
+ (let ((a (assq attr alist)))
+ (cond ((not a) a)
+ ((boolean? (cdr a)) (cdr a))
+ (else (error "Not a boolean attribute:" attr))))
+)
+
+(method-make! <attr-list> 'has-attr?
+ (lambda (self attr) (attr-has-attr? (elm-get self 'attrs) attr))
+)
+
+(define (atlist-has-attr? atlist attr)
+ (send atlist 'has-attr? attr)
+)
+
+; Expand attribute value ATVAL, which is an rtx expression.
+; OWNER is the containing object or #f if there is none.
+; OWNER is needed if an attribute is defined in terms of other attributes.
+; If it's #f obviously ATVAL can't be defined in terms of others.
+
+(define (-attr-eval atval owner)
+ (let* ((estate (estate-make-for-eval #f owner))
+ (expr (rtx-compile #f (rtx-simplify #f owner atval nil) nil))
+ (value (rtx-eval-with-estate expr 'DFLT estate)))
+ (cond ((symbol? value) value)
+ ((number? value) value)
+ (error "-attr-eval: internal error, unsupported result:" value)))
+)
+
+; Return value of ATTR in attribute alist ALIST.
+; If not present, return the default value.
+; OWNER is the containing object or #f if there is none.
+
+(define (attr-value alist attr owner)
+ (let ((a (assq-ref alist attr)))
+ (if a
+ (if (pair? a) ; pair? -> cheap non-null-list?
+ (-attr-eval a owner)
+ a)
+ (attr-lookup-default attr owner)))
+)
+
+; Return the value of ATTR in ATLIST.
+; OWNER is the containing object or #f if there is none.
+
+(define (atlist-attr-value atlist attr owner)
+ (attr-value (atlist-attrs atlist) attr owner)
+)
+
+; Same as atlist-attr-value but return nil if attribute not present.
+
+(define (atlist-attr-value-no-default atlist attr owner)
+ (let ((a (assq-ref (atlist-attrs atlist) attr)))
+ (if a
+ (if (pair? a) ; pair? -> cheap non-null-list?
+ (-attr-eval a owner)
+ a)
+ nil))
+)
+
+; Return the default for attribute A.
+; If A isn't a non-boolean attribute, we assume it's a boolean one, and
+; return #f (??? for backward's compatibility, to be removed in time).
+; OWNER is the containing object or #f if there is none.
+
+(define (attr-lookup-default a owner)
+ (let ((at (current-attr-lookup a)))
+ (if at
+ (if (bool-attr? at)
+ #f
+ (let ((deflt (attr-default at)))
+ (if deflt
+ (if (pair? deflt) ; pair? -> cheap non-null-list?
+ (-attr-eval deflt owner)
+ deflt)
+ ; If no default was provided, use the first value.
+ (caar (attr-values at)))))
+ #f))
+)
+
+; Return a boolean indicating if X is present in BITSET.
+; Bitset values are recorded as val1,val2,....
+
+(define (bitset-attr-member? x bitset)
+ (->bool (memq x (bitset-attr->list bitset)))
+)
+
+; Routines for accessing attributes in objects.
+
+; Get/set attributes of OBJ.
+; OBJ is any object which supports the get-atlist message.
+
+(define (obj-atlist obj)
+ (let ((result (send obj 'get-atlist)))
+ ; As a speed up, we allow objects to specify an empty attribute list
+ ; with #f or (), rather than creating an attr-list object.
+ ; ??? There is atlist-empty now which should be used directly.
+ (if (or (null? result) (not result))
+ atlist-empty
+ result))
+)
+(define (obj-set-atlist! obj attrs) (send obj 'set-atlist! attrs))
+
+; Add attribute ATTR to OBJ.
+; The attribute is prepended to the front so it overrides any existing
+; definition.
+
+(define (obj-cons-attr! obj attr)
+ (obj-set-atlist! obj (atlist-cons attr (obj-atlist obj)))
+)
+
+; Add attribute list ATLIST to OBJ.
+; Attributes in ATLIST override existing values, so ATLIST is "prepended".
+
+(define (obj-prepend-atlist! obj atlist)
+ ; Must have same prefix.
+ (assert (equal? (atlist-prefix (obj-atlist obj))
+ (atlist-prefix atlist)))
+ (obj-set-atlist! obj (atlist-append atlist (obj-atlist obj)))
+)
+
+; Return boolean of whether OBJ has boolean attribute ATTR or not.
+; OBJ is any object.
+
+(define (obj-has-attr? obj attr)
+ (atlist-has-attr? (obj-atlist obj) attr)
+)
+
+; FIXME: for backward compatibility. Delete in time.
+(define has-attr? obj-has-attr?)
+
+; Return value of attribute ATTR in OBJ.
+; If the attribute isn't present, the default is returned.
+; OBJ is any object that supports the get-atlist method.
+
+(define (obj-attr-value obj attr)
+ (let ((atlist (obj-atlist obj)))
+ (atlist-attr-value atlist attr obj))
+)
+
+; Utilities.
+
+; Convert a bitset value "a,b,c" into a list (a b c).
+
+(define (bitset-attr->list x)
+ (map string->symbol (string-cut x #\,))
+)
+
+; Return the enum of ATTR-NAME for type TYPE.
+; TYPE is one of 'ifld, 'hw, 'operand, 'insn.
+
+(define (gen-attr-enum type attr-name)
+ (string-upcase (string-append "CGEN_" type "_" (gen-sym attr-name)))
+)
+
+; Return a list of enum value definitions for gen-enum-decl.
+; Attributes numbers are organized as follows: booleans are numbered 0-31.
+; The range is because that's what fits in a portable int. Unused numbers
+; are left unused. Non-booleans are numbered starting at 32.
+; An alternative is start numbering the booleans at 32. The generated code
+; is simpler with the current way (the "- 32" to get back the bit number or
+; array index number occurs less often).
+;
+; Three special values are created:
+; END-BOOLS - mark end of boolean attributes
+; END-NBOOLS - mark end of non-boolean attributes
+; START-NBOOLS - marks the start of the non-boolean attributes
+; (needed in case first non-bool is sanytized out).
+;
+; ATTR-OBJ-LIST is a list of <attribute> objects (always subclassed of course).
+
+(define (attr-list-enum-list attr-obj-list)
+ (let ((sorted-attrs (-attr-sort (attr-remove-meta-attrs attr-obj-list))))
+ (assert (<= (length (car sorted-attrs)) 32))
+ (append!
+ (map (lambda (bool-attr)
+ (list (obj:name bool-attr) '-
+ (atlist-attrs (obj-atlist bool-attr))))
+ (car sorted-attrs))
+ (list '(END-BOOLS))
+ (list '(START-NBOOLS 31))
+ (map (lambda (nbool-attr)
+ (list (obj:name nbool-attr) '-
+ (atlist-attrs (obj-atlist nbool-attr))))
+ (cdr sorted-attrs))
+ (list '(END-NBOOLS))
+ ))
+)
+
+; Sort an alist of attributes so non-boolean attributes are at the front.
+; This is used to sort a particular object's attributes.
+; This is required by the C support code (cgen.h:CGEN_ATTR_VALUE).
+; Boolean attributes appear as (NAME . #t/#f), non-boolean ones appear as
+; (NAME . VALUE). Attributes of the same type are sorted by name.
+
+(define (-attr-sort-alist alist)
+ (sort alist
+ (lambda (a b)
+ ;(display (list a b "\n"))
+ (cond ((and (boolean? (cdr a)) (boolean? (cdr b)))
+ (string<? (symbol->string (car a)) (symbol->string (car b))))
+ ((boolean? (cdr a)) #f) ; we know b is non-bool here
+ ((boolean? (cdr b)) #t) ; we know a is non-bool here
+ (else (string<? (symbol->string (car a))
+ (symbol->string (car b)))))))
+)
+
+; Sort ATTR-LIST into two lists: bools and non-bools.
+; The car of the result is the bools, the cdr is the non-bools.
+; Attributes requiring a fixed index have the INDEX attribute,
+; and used for the few special attributes that are refered to by
+; architecture independent code.
+; For each of non-bools and bools, put attributes with the INDEX attribute
+; first. This is used to sort a list of attributes for output (e.g. define
+; the attr enum).
+;
+; ??? Record index number with the INDEX attribute?
+; At present it's just a boolean.
+
+(define (-attr-sort attr-list)
+ (let loop ((fixed-non-bools nil)
+ (non-fixed-non-bools nil)
+ (fixed-bools nil)
+ (non-fixed-bools nil)
+ (attr-list attr-list))
+ (cond ((null? attr-list)
+ (cons (append! (reverse! fixed-bools)
+ (reverse! non-fixed-bools))
+ (append! (reverse! fixed-non-bools)
+ (reverse! non-fixed-non-bools))))
+ ((bool-attr? (car attr-list))
+ (if (obj-has-attr? (car attr-list) 'INDEX)
+ (loop fixed-non-bools non-fixed-non-bools
+ (cons (car attr-list) fixed-bools) non-fixed-bools
+ (cdr attr-list))
+ (loop fixed-non-bools non-fixed-non-bools
+ fixed-bools (cons (car attr-list) non-fixed-bools)
+ (cdr attr-list))))
+ (else
+ (if (obj-has-attr? (car attr-list) 'INDEX)
+ (loop (cons (car attr-list) fixed-non-bools) non-fixed-non-bools
+ fixed-bools non-fixed-bools
+ (cdr attr-list))
+ (loop fixed-non-bools (cons (car attr-list) non-fixed-non-bools)
+ fixed-bools non-fixed-bools
+ (cdr attr-list))))))
+)
+
+; Return number of non-bools in attributes ATLIST.
+
+(define (attr-count-non-bools atlist)
+ (count-true (map (lambda (a) (not (bool-attr? a)))
+ atlist))
+)
+
+; Given an alist of attributes, return the non-bools.
+
+(define (attr-non-bool-attrs alist)
+ (let loop ((result nil) (alist alist))
+ (cond ((null? alist) (reverse! result))
+ ((boolean? (cdar alist)) (loop result (cdr alist)))
+ (else (loop (cons (car alist) result) (cdr alist)))))
+)
+
+; Given an alist of attributes, return the bools.
+
+(define (attr-bool-attrs alist)
+ (let loop ((result nil) (alist alist))
+ (cond ((null? alist) (reverse! result))
+ ((boolean? (cdar alist))
+ (loop (cons (car alist) result) (cdr alist)))
+ (else (loop result (cdr alist)))))
+)
+
+; Parse an attribute spec.
+; CONTEXT is a <context> object or #f if there is none.
+; ATTRS is a list of attribute specs (e.g. (FOO !BAR (BAZ 3))).
+; The result is the attribute alist.
+
+(define (attr-parse context attrs)
+ (if (not (list? attrs))
+ (context-error context "improper attribute list" attrs))
+ (let ((alist nil))
+ (for-each (lambda (elm)
+ (cond ((symbol? elm)
+ ; boolean attribute
+ (if (char=? (string-ref elm 0) #\!)
+ (set! alist (acons (string->symbol (string-drop1 elm)) #f alist))
+ (set! alist (acons elm #t alist)))
+ (if (not (current-attr-lookup (caar alist)))
+ (context-error context "unknown attribute" (caar alist))))
+ ((and (list? elm) (pair? elm) (symbol? (car elm)))
+ (let ((a (current-attr-lookup (car elm))))
+ (if (not a)
+ (context-error context "unknown attribute" elm))
+ (set! alist (cons (send a 'parse-value
+ (context-prefix context);FIXME
+ (cdr elm)) alist))))
+ (else (context-error context "improper attribute" elm))))
+ attrs)
+ alist)
+)
+
+; Parse an object attribute spec.
+; ATTRS is a list of attribute specs (e.g. (FOO !BAR (BAZ 3))).
+; The result is an <attr-list> object.
+
+(define (atlist-parse attrs prefix errtxt)
+ (make <attr-list> prefix (attr-parse (context-make-prefix errtxt) attrs))
+)
+
+; Return the source form of an atlist's values.
+; Externally attributes are ((name1 value1) (name2 value2) ...).
+; Internally they are ((name1 . value1) (name2 . value2) ...).
+
+(define (atlist-source-form atlist)
+ (map (lambda (attr)
+ (list (car attr) (cdr attr)))
+ (atlist-attrs atlist))
+)
+
+; cons an attribute to an attribute list to create a new attribute list
+; ATLIST is either an attr-list object or #f or () (both of the latter two
+; signify an empty attribute list, in which case we make the prefix of the
+; result "").
+
+(define (atlist-cons attr atlist)
+ (if (or (not atlist) (null? atlist))
+ (make <attr-list> "" (cons attr nil))
+ (make <attr-list> (atlist-prefix atlist) (cons attr (atlist-attrs atlist))))
+)
+
+; Append one attribute list to another.
+; The prefix for the new atlist is taken from the first one.
+
+(define (atlist-append attr-list1 attr-list2)
+ (make <attr-list>
+ (atlist-prefix attr-list1)
+ (append (atlist-attrs attr-list1) (atlist-attrs attr-list2)))
+)
+
+; Remove meta-attributes from ALIST.
+; "meta" may be the wrong adjective to use here.
+; The attributes in question are not intended to appear in generated files.
+; They started out being attributes of attributes, hence the name "meta".
+
+(define (attr-remove-meta-attrs-alist alist)
+ (let ((all-attrs (current-attr-list)))
+ ; FIXME: Why not use find?
+ (let loop ((result nil) (alist alist))
+ (if (null? alist)
+ (reverse! result)
+ (let ((attr (attr-lookup (caar alist) all-attrs)))
+ (if (and attr (has-attr? attr 'META))
+ (loop result (cdr alist))
+ (loop (cons (car alist) result) (cdr alist)))))))
+)
+
+; Remove meta-attributes from ATTR-LIST.
+; "meta" may be the wrong adjective to use here.
+; The attributes in question are not intended to appear in generated files.
+; They started out being attributes of attributes, hence the name "meta".
+
+(define (attr-remove-meta-attrs attr-list)
+ ; FIXME: Why not use find?
+ (let loop ((result nil) (attr-list attr-list))
+ (cond ((null? attr-list)
+ (reverse! result))
+ ((has-attr? (car attr-list) 'META)
+ (loop result (cdr attr-list)))
+ (else
+ (loop (cons (car attr-list) result) (cdr attr-list)))))
+)
+
+; Remove duplicates from ATTRS, a list of attributes.
+; Attribute lists are typically small so we use a simple O^2 algorithm.
+; The leading entry of an attribute overrides subsequent ones so this is
+; defined to pick the first entry of each attribute.
+
+(define (attr-nub attrs)
+ (let loop ((result nil) (attrs attrs))
+ (cond ((null? attrs) (reverse! result))
+ ((assq (caar attrs) result) (loop result (cdr attrs)))
+ (else (loop (cons (car attrs) result) (cdr attrs)))))
+)
+
+; Return a list of all attrs in TABLE-LIST, a list of lists of arbitrary
+; elements. A list of lists is passed to simplify computation of insn
+; attributes where the insns and macro-insns are on separate lists and
+; appending them into one list would be unnecessarily expensive.
+; ACCESSOR is a function to access the attrs field from TABLE-LIST.
+; Duplicates are eliminated and the list is sorted so non-boolean attributes
+; are at the front (required by the C code that fetches attribute values).
+; STD-ATTRS is an `attr-list' object of attrs that are always available.
+; The actual values returned are random (e.g. #t vs #f). We could
+; canonicalize them.
+; The result is an alist of all the attributes that are used in TABLE-LIST.
+; ??? The cdr of each element is some random value. Perhaps it should be
+; the default value or perhaps we should just return a list of names.
+; ??? No longer used.
+
+(define (attr-compute-all table-list accessor std-attrs)
+ (let ((accessor (lambda (elm) (atlist-attrs (accessor elm)))))
+ (attr-remove-meta-attrs-alist
+ (attr-nub
+ (-attr-sort-alist
+ (append
+ (apply append
+ (map (lambda (table-elm)
+ (apply append
+ (find-apply accessor
+ (lambda (e)
+ (let ((attrs (accessor e)))
+ (not (null? attrs))))
+ table-elm)))
+ table-list))
+ (atlist-attrs std-attrs))))))
+)
+
+; Return lists of attributes for particular object types.
+; FIXME: The output shouldn't be required to be sorted.
+
+(define (current-attr-list-for type)
+ (let ((sorted (-attr-sort (find (lambda (a)
+ (if (atlist-for a)
+ (memq type (atlist-for a))
+ #t))
+ (attr-remove-meta-attrs
+ (current-attr-list))))))
+ ; Current behaviour puts the non-bools at the front.
+ (append! (cdr sorted) (car sorted)))
+)
+(define (current-ifld-attr-list)
+ (current-attr-list-for 'ifield)
+)
+(define (current-hw-attr-list)
+ (current-attr-list-for 'hardware)
+)
+(define (current-op-attr-list)
+ (current-attr-list-for 'operand)
+)
+(define (current-insn-attr-list)
+ (current-attr-list-for 'insn)
+)
+
+; Methods to emit the C value of an attribute.
+; These don't _really_ belong here (C code doesn't belong in the appl'n
+; independent part of CGEN), but there isn't a better place for them
+; (maybe utils-cgen.scm?) and there's only a few of them.
+
+(method-make!
+ <boolean-attribute> 'gen-value-for-defn
+ (lambda (self value)
+ (if (not value)
+ "0"
+ "1"))
+ ;(string-upcase (string-append (obj:name self) "_" value)))
+)
+
+(method-make!
+ <bitset-attribute> 'gen-value-for-defn
+ (lambda (self value)
+ (string-drop1
+ (string-upcase
+ (string-map (lambda (x)
+ (string-append "|(1<<"
+ (gen-sym self)
+ "_" (gen-c-symbol x) ")"))
+ (bitset-attr->list value)))))
+)
+
+(method-make!
+ <integer-attribute> 'gen-value-for-defn
+ (lambda (self value)
+ (number->string value))
+)
+
+(method-make!
+ <enum-attribute> 'gen-value-for-defn
+ (lambda (self value)
+ (string-upcase (gen-c-symbol (string-append (obj:name self) "_" value))))
+)
+
+; Called before loading a .cpu file to initialize.
+
+(define (attr-init!)
+
+ (reader-add-command! 'define-attr
+ "\
+Define an attribute, name/value pair list version.
+"
+ nil 'arg-list define-attr)
+
+ *UNSPECIFIED*
+)
+
+; Called before a . cpu file is read in to install any builtins.
+; One thing this does is define all attributes requiring a fixed index,
+; keeping them all in one place.
+; ??? Perhaps it would make sense to define all predefined attributes here.
+
+(define (attr-builtin!)
+ (define-attr '(type boolean) '(name VIRTUAL) '(comment "virtual object"))
+
+ ; The meta attribute is used for attributes that aren't to appear in
+ ; generated output (need a better name).
+ (define-attr '(for attr) '(type boolean) '(name META))
+
+ ; Objects to keep local to a generated file.
+ (define-attr '(for keyword) '(type boolean) '(name PRIVATE))
+
+ ; Attributes requiring fixed indices.
+ ; ALIAS is used for instructions that are aliases of more general insns.
+ ; ALIAS insns are ignored by the simulator.
+ (define-attr '(for attr) '(type boolean) '(name INDEX) '(attrs META))
+ (define-attr '(for insn) '(type boolean) '(name ALIAS)
+ '(comment "insn is an alias of another")
+ '(attrs INDEX))
+
+ *UNSPECIFIED*
+)
+
+; Called after loading a .cpu file to perform any post-processing required.
+
+(define (attr-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/cgen-gas.scm b/cgen/cgen-gas.scm
new file mode 100644
index 00000000000..c6d3b945466
--- /dev/null
+++ b/cgen/cgen-gas.scm
@@ -0,0 +1,80 @@
+; CPU description file generator for the GAS testsuite.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; This is invoked to build several .s files and a script to run to
+; generate the .d files and .exp file.
+; This is invoked to build: tmp-build.sh cpu-cpu.exp
+
+; Load the various support routines.
+
+(define (load-files srcdir)
+ ; Fix up Scheme to be what we use (guile is always in flux).
+ (primitive-load-path (string-append srcdir "/fixup.scm"))
+
+ (load (string-append srcdir "/read.scm"))
+ (load (string-append srcdir "/desc.scm"))
+ (load (string-append srcdir "/desc-cpu.scm"))
+ (load (string-append srcdir "/opcodes.scm"))
+ (load (string-append srcdir "/opc-asmdis.scm"))
+ (load (string-append srcdir "/opc-ibld.scm"))
+ (load (string-append srcdir "/opc-itab.scm"))
+ (load (string-append srcdir "/opc-opinst.scm"))
+ (load (string-append srcdir "/gas-test.scm"))
+)
+
+(define gas-arguments
+ (list
+ (list '-B "file" "generate build.sh in <file>"
+ (lambda (arg) (file-write arg cgen-build.sh)))
+ (list '-E "file" "generate allinsn.exp in <file>"
+ (lambda (arg) (file-write arg cgen-allinsn.exp)))
+ )
+)
+
+; Kept global so it's available to the other .scm files.
+(define srcdir ".")
+
+; Scan argv for -s srcdir.
+; We can't process any other args until we find the cgen source dir.
+; The result is srcdir.
+; We assume "-s" isn't the argument to another option. Unwise, yes.
+; Alternatives are to require it to be the first argument or at least preceed
+; any option with a "-s" argument, or to put knowledge of the common argument
+; set and common argument parsing code in every top level file.
+
+(define (find-srcdir argv)
+ (let loop ((argv argv))
+ (if (null? argv)
+ (error "`-s srcdir' not present, can't load cgen"))
+ (if (string=? "-s" (car argv))
+ (begin
+ (if (null? (cdr argv))
+ (error "missing srcdir arg to `-s'"))
+ (cadr argv))
+ (loop (cdr argv))))
+)
+
+; Main routine, parses options and calls generators.
+
+(define (cgen-gas argv)
+ (let ()
+
+ ; Find and set srcdir, then load all Scheme code.
+ ; Drop the first argument, it is the script name (i.e. argv[0]).
+ (set! srcdir (find-srcdir (cdr argv)))
+ (set! %load-path (cons srcdir %load-path))
+ (load-files srcdir)
+
+ (display-argv argv)
+
+ (cgen #:argv argv
+ #:app-name "gas-test"
+ #:arg-spec gas-arguments
+ #:init gas-test-init!
+ #:finish gas-test-finish!
+ #:analyze gas-test-analyze!)
+ )
+)
+
+(cgen-gas (program-arguments))
diff --git a/cgen/cgen-opc.scm b/cgen/cgen-opc.scm
new file mode 100644
index 00000000000..cd98fe0598d
--- /dev/null
+++ b/cgen/cgen-opc.scm
@@ -0,0 +1,99 @@
+; CPU description file generator for the GNU Binutils.
+; This is invoked to build: $arch-desc.[ch], $arch-opinst.c,
+; $arch-opc.h, $arch-opc.c, $arch-asm.in, $arch-dis.in, and $arch-ibld.[ch].
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+;
+; This is a standalone script, we don't load anything until we parse the
+; -s argument (keeps reliance off of environment variables, etc.).
+
+; Load the various support routines.
+
+(define (load-files srcdir)
+ ; Fix up Scheme to be what we use (guile is always in flux).
+ (primitive-load-path (string-append srcdir "/fixup.scm"))
+
+ (load (string-append srcdir "/read.scm"))
+ (load (string-append srcdir "/desc.scm"))
+ (load (string-append srcdir "/desc-cpu.scm"))
+ (load (string-append srcdir "/opcodes.scm"))
+ (load (string-append srcdir "/opc-asmdis.scm"))
+ (load (string-append srcdir "/opc-ibld.scm"))
+ (load (string-append srcdir "/opc-itab.scm"))
+ (load (string-append srcdir "/opc-opinst.scm"))
+)
+
+(define opc-arguments
+ (list
+ (list '-H "file" "generate $arch-desc.h in <file>"
+ (lambda (arg) (file-write arg cgen-desc.h)))
+ (list '-C "file" "generate $arch-desc.c in <file>"
+ (lambda (arg) (file-write arg cgen-desc.c)))
+ (list '-O "file" "generate $arch-opc.h in <file>"
+ (lambda (arg) (file-write arg cgen-opc.h)))
+ (list '-P "file" "generate $arch-opc.c in <file>"
+ (lambda (arg) (file-write arg cgen-opc.c)))
+ (list '-Q "file" "generate $arch-opinst.c in <file>"
+ (lambda (arg) (file-write arg cgen-opinst.c)))
+ (list '-B "file" "generate $arch-ibld.h in <file>"
+ (lambda (arg) (file-write arg cgen-ibld.h)))
+ (list '-L "file" "generate $arch-ibld.in in <file>"
+ (lambda (arg) (file-write arg cgen-ibld.in)))
+ (list '-A "file" "generate $arch-asm.in in <file>"
+ (lambda (arg) (file-write arg cgen-asm.in)))
+ (list '-D "file" "generate $arch-dis.in in <file>"
+ (lambda (arg) (file-write arg cgen-dis.in)))
+ )
+)
+
+; (-R "file" "generate $cpu-reloc.h") ; FIXME: wip (rename to -abi.h?)
+; (-S "file" "generate cpu-$cpu.c") ; FIXME: wip (bfd's cpu-$cpu.c)
+; ((-R) (file-write *arg* cgen-reloc.c))
+; ((-S) (file-write *arg* cgen-bfdcpu.c))
+
+; Kept global so it's available to the other .scm files.
+(define srcdir ".")
+
+; Scan argv for -s srcdir.
+; We can't process any other args until we find the cgen source dir.
+; The result is srcdir.
+; We assume "-s" isn't the argument to another option. Unwise, yes.
+; Alternatives are to require it to be the first argument or at least preceed
+; any option with a "-s" argument, or to put knowledge of the common argument
+; set and common argument parsing code in every top level file.
+
+(define (find-srcdir argv)
+ (let loop ((argv argv))
+ (if (null? argv)
+ (error "`-s srcdir' not present, can't load cgen"))
+ (if (string=? "-s" (car argv))
+ (begin
+ (if (null? (cdr argv))
+ (error "missing srcdir arg to `-s'"))
+ (cadr argv))
+ (loop (cdr argv))))
+)
+
+; Main routine, parses options and calls generators.
+
+(define (cgen-opc argv)
+ (let ()
+
+ ; Find and set srcdir, then load all Scheme code.
+ ; Drop the first argument, it is the script name (i.e. argv[0]).
+ (set! srcdir (find-srcdir (cdr argv)))
+ (set! %load-path (cons srcdir %load-path))
+ (load-files srcdir)
+
+ (display-argv argv)
+
+ (cgen #:argv argv
+ #:app-name "opcodes"
+ #:arg-spec opc-arguments
+ #:init opcodes-init!
+ #:finish opcodes-finish!
+ #:analyze opcodes-analyze!)
+ )
+)
+
+(cgen-opc (program-arguments))
diff --git a/cgen/cgen-sim.scm b/cgen/cgen-sim.scm
new file mode 100644
index 00000000000..766153ae1be
--- /dev/null
+++ b/cgen/cgen-sim.scm
@@ -0,0 +1,112 @@
+; Simulator generator entry point.
+; This is invoked to build: arch.h, cpu-<cpu>.h, memops.h, semops.h, decode.h,
+; decode.c, extract.c, semantics.c, ops.c, model.c, mainloop.in.
+;
+; memops.h, semops.h, ops.c, mainloop.in are either deprecated or wip.
+;
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+;
+; This is a standalone script, we don't load anything until we parse the
+; -s argument (keeps reliance off of environment variables, etc.).
+
+; Load the various support routines.
+
+(define (load-files srcdir)
+ ; Fix up Scheme to be what we use (guile is always in flux).
+ (primitive-load-path (string-append srcdir "/fixup.scm"))
+
+ (load (string-append srcdir "/read.scm"))
+ (load (string-append srcdir "/utils-sim.scm"))
+ (load (string-append srcdir "/sim.scm"))
+ (load (string-append srcdir "/sim-arch.scm"))
+ (load (string-append srcdir "/sim-cpu.scm"))
+ (load (string-append srcdir "/sim-model.scm"))
+ (load (string-append srcdir "/sim-decode.scm"))
+)
+
+(define sim-arguments
+ (list
+ (list '-A "file" "generate arch.h in <file>"
+ (lambda (arg) (file-write arg cgen-arch.h)))
+ (list '-B "file" "generate arch.c in <file>"
+ (lambda (arg) (file-write arg cgen-arch.c)))
+ (list '-C "file" "generate cpu-<cpu>.h in <file>"
+ (lambda (arg) (file-write arg cgen-cpu.h)))
+ (list '-U "file" "generate cpu-<cpu>.c in <file>"
+ (lambda (arg) (file-write arg cgen-cpu.c)))
+ (list '-N "file" "generate cpu-all.h in <file>"
+ (lambda (arg) (file-write arg cgen-cpuall.h)))
+ (list '-F "file" "generate memops.h in <file>"
+ (lambda (arg) (file-write arg cgen-mem-ops.h)))
+ (list '-P "file" "generate semops.h in <file>"
+ (lambda (arg) (file-write arg cgen-sem-ops.h)))
+ (list '-T "file" "generate decode.h in <file>"
+ (lambda (arg) (file-write arg cgen-decode.h)))
+ (list '-D "file" "generate decode.c in <file>"
+ (lambda (arg) (file-write arg cgen-decode.c)))
+ (list '-E "file" "generate extract.c in <file>"
+ (lambda (arg) (file-write arg cgen-extract.c)))
+ (list '-R "file" "generate read.c in <file>"
+ (lambda (arg) (file-write arg cgen-read.c)))
+ (list '-W "file" "generate write.c in <file>"
+ (lambda (arg) (file-write arg cgen-write.c)))
+ (list '-S "file" "generate semantics.c in <file>"
+ (lambda (arg) (file-write arg cgen-semantics.c)))
+ (list '-X "file" "generate sem-switch.c in <file>"
+ (lambda (arg) (file-write arg cgen-sem-switch.c)))
+ (list '-O "file" "generate ops.c in <file>"
+ (lambda (arg) (file-write arg cgen-ops.c)))
+ (list '-M "file" "generate model.c in <file>"
+ (lambda (arg) (file-write arg cgen-model.c)))
+ (list '-L "file" "generate mainloop.in in <file>"
+ (lambda (arg) (file-write arg cgen-mainloop.in)))
+ )
+)
+
+; Kept global so it's available to the other .scm files.
+(define srcdir ".")
+
+; Scan argv for -s srcdir.
+; We can't process any other args until we find the cgen source dir.
+; The result is srcdir.
+; We assume "-s" isn't the argument to another option. Unwise, yes.
+; Alternatives are to require it to be the first argument or at least preceed
+; any option with a "-s" argument, or to put knowledge of the common argument
+; set and common argument parsing code in every top level file.
+
+(define (find-srcdir argv)
+ (let loop ((argv argv))
+ (if (null? argv)
+ (error "`-s srcdir' not present, can't load cgen"))
+ (if (string=? "-s" (car argv))
+ (begin
+ (if (null? (cdr argv))
+ (error "missing srcdir arg to `-s'"))
+ (cadr argv))
+ (loop (cdr argv))))
+)
+
+; Main routine, parses options and calls generators.
+
+(define (cgen-sim argv)
+ (let ()
+
+ ; Find and set srcdir, then load all Scheme code.
+ ; Drop the first argument, it is the script name (i.e. argv[0]).
+ (set! srcdir (find-srcdir (cdr argv)))
+ (set! %load-path (cons srcdir %load-path))
+ (load-files srcdir)
+
+ (display-argv argv)
+
+ (cgen #:argv argv
+ #:app-name "sim"
+ #:arg-spec sim-arguments
+ #:init sim-init!
+ #:finish sim-finish!
+ #:analyze sim-analyze!)
+ )
+)
+
+(cgen-sim (program-arguments))
diff --git a/cgen/cgen-stest.scm b/cgen/cgen-stest.scm
new file mode 100644
index 00000000000..ed1edec72fd
--- /dev/null
+++ b/cgen/cgen-stest.scm
@@ -0,0 +1,79 @@
+; CPU description file generator for the simulator testsuite.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; This is invoked to build several .s files and a script to run to
+; generate the .d files and .exp file.
+; This is invoked to build: tmp-build.sh cpu-cpu.exp
+
+; Load the various support routines
+(define (load-files srcdir)
+ ; Fix up Scheme to be what we use (guile is always in flux).
+ (primitive-load-path (string-append srcdir "/fixup.scm"))
+
+ (load (string-append srcdir "/read.scm"))
+ (load (string-append srcdir "/desc.scm"))
+ (load (string-append srcdir "/desc-cpu.scm"))
+ (load (string-append srcdir "/opcodes.scm"))
+ (load (string-append srcdir "/opc-asmdis.scm"))
+ (load (string-append srcdir "/opc-ibld.scm"))
+ (load (string-append srcdir "/opc-itab.scm"))
+ (load (string-append srcdir "/opc-opinst.scm"))
+ (load (string-append srcdir "/sim-test.scm"))
+)
+
+(define stest-arguments
+ (list
+ (list '-B "file" "generate build.sh"
+ (lambda (arg) (file-write arg cgen-build.sh)))
+ (list '-E "file" "generate the testsuite .exp"
+ (lambda (arg) (file-write arg cgen-allinsn.exp)))
+ )
+)
+
+; Kept global so it's available to the other .scm files.
+(define srcdir ".")
+
+; Scan argv for -s srcdir.
+; We can't process any other args until we find the cgen source dir.
+; The result is srcdir.
+; We assume "-s" isn't the argument to another option. Unwise, yes.
+; Alternatives are to require it to be the first argument or at least preceed
+; any option with a "-s" argument, or to put knowledge of the common argument
+; set and common argument parsing code in every top level file.
+
+(define (find-srcdir argv)
+ (let loop ((argv argv))
+ (if (null? argv)
+ (error "`-s srcdir' not present, can't load cgen"))
+ (if (string=? "-s" (car argv))
+ (begin
+ (if (null? (cdr argv))
+ (error "missing srcdir arg to `-s'"))
+ (cadr argv))
+ (loop (cdr argv))))
+)
+
+; Main routine, parses options and calls generators.
+
+(define (cgen-stest argv)
+ (let ()
+
+ ; Find and set srcdir, then load all Scheme code.
+ ; Drop the first argument, it is the script name (i.e. argv[0]).
+ (set! srcdir (find-srcdir (cdr argv)))
+ (set! %load-path (cons srcdir %load-path))
+ (load-files srcdir)
+
+ (display-argv argv)
+
+ (cgen #:argv argv
+ #:app-name "sim-test"
+ #:arg-spec stest-arguments
+ #:init sim-test-init!
+ #:finish sim-test-finish!
+ #:analyze sim-test-analyze!)
+ )
+)
+
+(cgen-stest (program-arguments))
diff --git a/cgen/configure b/cgen/configure
new file mode 100755
index 00000000000..0e48be6b04b
--- /dev/null
+++ b/cgen/configure
@@ -0,0 +1,1374 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+sitefile=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --site-file=FILE use FILE as the site file
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -site-file | --site-file | --site-fil | --site-fi | --site-f)
+ ac_prev=sitefile ;;
+ -site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*)
+ sitefile="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=read.scm
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$sitefile"; then
+ if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+ fi
+else
+ CONFIG_SITE="$sitefile"
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:586: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:607: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:625: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:659: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:712: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "$*" != "X $srcdir/configure conftestfile" \
+ && test "$*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { echo "configure: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+ fi
+
+ test "$2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:769: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=cgen
+
+VERSION=1.0
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:815: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+ ACLOCAL=aclocal
+ echo "$ac_t""found" 1>&6
+else
+ ACLOCAL="$missing_dir/missing aclocal"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:828: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+ AUTOCONF=autoconf
+ echo "$ac_t""found" 1>&6
+else
+ AUTOCONF="$missing_dir/missing autoconf"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:841: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+ AUTOMAKE=automake
+ echo "$ac_t""found" 1>&6
+else
+ AUTOMAKE="$missing_dir/missing automake"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:854: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+ AUTOHEADER=autoheader
+ echo "$ac_t""found" 1>&6
+else
+ AUTOHEADER="$missing_dir/missing autoheader"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:867: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+ MAKEINFO=makeinfo
+ echo "$ac_t""found" 1>&6
+else
+ MAKEINFO="$missing_dir/missing makeinfo"
+ echo "$ac_t""missing" 1>&6
+fi
+
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:893: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
+echo "configure:946: checking for Cygwin environment" >&5
+if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 951 "configure"
+#include "confdefs.h"
+
+int main() {
+
+#ifndef __CYGWIN__
+#define __CYGWIN__ __CYGWIN32__
+#endif
+return __CYGWIN__;
+; return 0; }
+EOF
+if { (eval echo configure:962: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_cygwin=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_cygwin=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_cygwin" 1>&6
+CYGWIN=
+test "$ac_cv_cygwin" = yes && CYGWIN=yes
+echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6
+echo "configure:979: checking for mingw32 environment" >&5
+if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 984 "configure"
+#include "confdefs.h"
+
+int main() {
+return __MINGW32__;
+; return 0; }
+EOF
+if { (eval echo configure:991: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_mingw32=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_mingw32=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_mingw32" 1>&6
+MINGW32=
+test "$ac_cv_mingw32" = yes && MINGW32=yes
+
+
+echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
+echo "configure:1010: checking for executable suffix" >&5
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$CYGWIN" = yes || test "$MINGW32" = yes; then
+ ac_cv_exeext=.exe
+else
+ rm -f conftest*
+ echo 'int main () { return 0; }' > conftest.$ac_ext
+ ac_cv_exeext=
+ if { (eval echo configure:1020: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ for file in conftest.*; do
+ case $file in
+ *.c | *.o | *.obj | *.ilk | *.pdb) ;;
+ *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
+ esac
+ done
+ else
+ { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; }
+ fi
+ rm -f conftest*
+ test x"${ac_cv_exeext}" = x && ac_cv_exeext=no
+fi
+fi
+
+EXEEXT=""
+test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext}
+echo "$ac_t""${ac_cv_exeext}" 1>&6
+ac_exeext=$EXEEXT
+
+
+# Set target cpu.
+arch=${target_cpu}
+
+
+echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
+echo "configure:1046: checking whether to enable maintainer-specific portions of Makefiles" >&5
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile doc/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@EXEEXT@%$EXEEXT%g
+s%@arch@%$arch%g
+s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g
+s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g
+s%@MAINT@%$MAINT%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile doc/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/cgen/configure.in b/cgen/configure.in
new file mode 100644
index 00000000000..c229bd80d19
--- /dev/null
+++ b/cgen/configure.in
@@ -0,0 +1,18 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.13)
+AC_INIT(read.scm)
+AC_CANONICAL_SYSTEM
+AM_INIT_AUTOMAKE(cgen, 1.0)
+
+AC_PROG_INSTALL
+AC_EXEEXT
+
+# Set target cpu.
+arch=${target_cpu}
+AC_SUBST(arch)
+
+AM_MAINTAINER_MODE
+AC_ARG_PROGRAM
+
+AC_OUTPUT([Makefile doc/Makefile])
diff --git a/cgen/cos.scm b/cgen/cos.scm
new file mode 100644
index 00000000000..7bb2a6e8630
--- /dev/null
+++ b/cgen/cos.scm
@@ -0,0 +1,1336 @@
+; Cgen's Object System.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+;
+; When Guile has an official object implementation that is stable, things will
+; be switched over then. Until such time, there's no point in getting hyper
+; (although doing so is certainly fun, but only to a point).
+; If the Guile team decides there won't be any official object system
+; (which isn't unreasonable) then we'll pick the final object system then.
+; Until such time, there are better things to do than trying to build a
+; better object system. If this is important enough to you, help the Guile
+; team finish the module(/object?) system.
+;
+; Classes look like:
+;
+; #(class-tag
+; class-name
+; parent-name-list
+; elm-alist
+; method-alist
+; full-elm-initial-list
+; full-method-alist ; ??? not currently used
+; class-descriptor)
+;
+; PARENT-NAME-LIST is a list of the names of parent classes (the inheritance
+; tree).
+;
+; ELM-ALIST is an alist of (symbol private? vector-index . initial-value)
+; for this class only.
+; Values can be looked up by name, via elm-make-[gs]etter routines, or
+; methods can use elm-get/set! for speed.
+; Various Lisp (or Lisp-like) OOP systems (e.g. CLOS, Dylan) call these
+; "slots". Maybe for consistency "slot" would be a better name. Some might
+; confuse that with intentions at directions. Given that something better
+; will eventually happen, being deliberately different is useful.
+;
+; METHOD-ALIST is an alist of (symbol . (virtual? . procedure)) for this
+; class only.
+;
+; FULL-ELM-INITIAL-LIST is the elements of the flattened inheritance tree.
+; Initially it is #f meaning it hasn't been computed yet.
+; It is computed when the class is first instantiated. During development,
+; it can be reset to #f after some module has been reloaded (requires all
+; object instantiation happens later of course).
+;
+; FULL-METHOD-ALIST is an alist of the methods of the flattened inheritance
+; tree. Each element is (symbol . (parent-list-entry . method)).
+; Initially it is #f meaning it hasn't been computed yet.
+; It is computed when the class is first instantiated. During development,
+; it can be reset to #f after some module has been reloaded (requires all
+; object instantiation happens later of course).
+;
+; CLASS-DESCRIPTOR is the processed form of parent-name-list.
+; There is an entry for the class and one for each parent (recursively):
+; (class mi? (base-offset . delta) child-backpointer (parent1-entry) ...).
+; mi? is #t if the class or any parent class has multiple inheritance.
+; This is used by the element access routines.
+; base-offset is the offset in the element vector of the baseclass (or first
+; baseclass in the mi case).
+; delta is the offset from base-offset of the class's own elements
+; (as opposed to elements in any parent class).
+; child-backpointer is #f in the top level object.
+; ??? child->subclass, parent->superclass?
+; Initially the class-descriptor is #f meaning it hasn't been computed yet.
+; It is computed when the class is first instantiated. During development,
+; it can be reset to #f after some module has been reloaded (requires all
+; object instantiation to happen later of course).
+;
+; An object is a vector of 2 elements: #(object-elements class-descriptor).
+; ??? Things would be simpler if objects were a pair but that makes eval'ing
+; them trickier. Vectors are nice in that they're self-evaluating, though
+; due to the self-referencing, which Guile 1.2 can't handle, apps have to
+; be careful.
+; ??? We could use smobs/records/whatever but the difference isn't big enough
+; for me to care at this point in time.
+;
+; `object-elements' looks like:
+;
+; #(object-tag
+; class
+; element1
+; element2
+; ...)
+;
+; CLASS is the class the object is an instance of.
+;
+; User visible procs:
+;
+; (class-make name parents elements methods) -> class
+;
+; Create a class. The result is then passed back by procedures requiring
+; a class argument. Note however that PARENTS is a list of class names,
+; not the class data type. This allows reloading the definition of a
+; parent class without having to reload any subclasses. To implement this
+; classes are recorded internally, and `object-init!' must be called if any
+; class has been redefined.
+;
+; (class-list) -> list of all defined classes
+;
+; (class-name class) -> name of CLASS
+;
+; (class-lookup class-name) -> class
+;
+; (class-instance? class object) -> #t if OBJECT is an instance of CLASS
+;
+; (object-class object) -> class of OBJECT
+;
+; (object-class-name object) -> class name of OBJECT
+;
+; (send object method-name . args) -> result of invoking METHOD-NAME
+;
+; (send-next object method-name . args) -> result of invoking next METHOD-NAME
+;
+; (new class) -> instantiate CLASS
+;
+; The object is initialized with values specified when CLASS
+; (and its parent classes) was defined.
+;
+; (vmake class . args) -> instantiate class and initialize it with 'vmake!
+;
+; This is shorthand for (send (new class) 'vmake! args).
+; ARGS is a list of option names and arguments (a la CLOS).
+; ??? Not implemented yet.
+;
+; (method-vmake! object . args) -> modify OBJECT from ARGS
+;
+; This is the standard 'vmake! method, available for use by user-written
+; 'vmake! methods.
+; ??? Not implemented yet.
+;
+; (make class . args) -> instantiate CLASS and initialize it with 'make!
+;
+; This is shorthand for (send (new class) 'make! arg1 ...).
+; This is a positional form of `new'.
+;
+; (method-make-make! class elm1-name elm2-name ...) -> unspecified
+;
+; Create a 'make! method that sets the specified elements.
+;
+; (object-copy object) -> copy of OBJ
+;
+; ??? Whether to discard the parent or keep it and retain specialization
+; is undecided.
+;
+; (object-copy-top object) -> copy of OBJECT with spec'n discarded
+;
+; (object-parent object parent-path) -> parent object in OBJECT via PARENT-PATH
+;
+; (class? foo) -> return #t if FOO is a class
+;
+; (object? foo) -> return #t if FOO is an object
+;
+; (method-make! class name lambda) -> unspecified
+;
+; Add method NAME to CLASS.
+;
+; (method-make-virtual! class name lambda) -> unspecified
+;
+; Add virtual method NAME to CLASS.
+;
+; (method-make-forward! class elm-name methods) -> unspecified
+;
+; Add METHODS to CLASS that pass the "message" onto the object in element
+; ELM-NAME.
+;
+; (method-make-virtual-forward! class elm-name methods) -> unspecified
+;
+; Add virtual METHODS to CLASS that pass the "message" onto the object in
+; element ELM-NAME.
+;
+; (elm-get object elm-name) -> value of element ELM-NAME in OBJ
+;
+; Can only be used in methods.
+;
+; (elm-set! object elm-name new-value) -> unspecified
+;
+; Set element ELM-NAME in OBJECT to NEW-VALUE.
+; Can only be used in methods.
+;
+; (elm-make-getter class elm-name) -> lambda
+;
+; Return lambda to get the value of ELM-NAME in CLASS.
+;
+; (elm-make-setter class elm-name) -> lambda
+;
+; Return lambda to set the value of ELM-NAME in CLASS.
+;
+; Conventions used in this file:
+; - procs/vars internal to this file are prefixed with "-"
+; [Of course this could all be put in a module; later if ever since
+; once Guile has its own official object system we'll convert. Note that
+; it currently does not.]
+; - except for a few exceptions, public procs begin with one of
+; class-, object-, elm-, method-.
+; The exceptions are make, new, parent, send.
+
+(define -class-tag "class")
+(define -object-tag "object")
+
+; List of all classes.
+
+(define -class-list ())
+
+; ??? Were written as a procedures for Hobbit's sake (I think).
+(define -object-unspecified #:unspecified)
+(define -object-unbound #:unbound)
+
+; Associative list of classes to be traced.
+
+(define -object-debug-classes #f)
+
+; Associative list of elements to be traced.
+
+(define -object-debug-elements #f)
+
+; Associative list of messages to be traced.
+
+(define -object-debug-methods #f)
+
+; True if error messages are verbose and debugging messages are printed.
+
+(define -object-verbose? #f)
+
+; Cover fn to set verbosity.
+
+(define (object-set-verbose! verbose?)
+ (set! -object-verbose? verbose?)
+)
+
+; Signal error if not class/object.
+
+(define (-class-check maybe-class proc-name . extra-text)
+ (if (not (class? maybe-class))
+ (apply -object-error
+ (append! (list proc-name maybe-class "not a class")
+ extra-text)))
+ -object-unspecified
+)
+(define (-object-check-name maybe-name proc-name . extra-text)
+ (if (not (symbol? maybe-name))
+ (apply -object-error
+ (append! (list proc-name maybe-name) extra-text)))
+ -object-unspecified
+)
+(define (-object-check maybe-object proc-name . extra-text)
+ (if (not (object? maybe-object))
+ (apply -object-error
+ (append! (list proc-name maybe-object "not an object")
+ extra-text)))
+ -object-unspecified
+)
+
+; X is any arbitrary Scheme data.
+(define (-object-error proc-name x . text)
+ (error (string-append proc-name ": " (apply string-append text)
+ (if (object? x)
+ (string-append
+ " (class: " (-object-class-name x)
+ (if (method-present? x 'get-name)
+ (string-append ", name: "
+ (send x 'get-name))
+ "")
+ ")")
+ "")
+ "")
+ x)
+)
+
+; Low level class operations.
+
+; Return boolean indicating if X is a class.
+
+(define (class? class)
+ (and (vector? class) (eq? -class-tag (vector-ref class 0)))
+)
+
+; Accessors.
+
+(define (-class-name class) (vector-ref class 1))
+(define (-class-parents class) (vector-ref class 2))
+(define (-class-elements class) (vector-ref class 3))
+(define (-class-methods class) (vector-ref class 4))
+(define (-class-all-initial-values class) (vector-ref class 5))
+(define (-class-all-methods class) (vector-ref class 6))
+(define (-class-class-desc class) (vector-ref class 7))
+
+(define (-class-set-parents! class parents)
+ (vector-set! class 2 parents)
+)
+
+(define (-class-set-elements! class elm-alist)
+ (vector-set! class 3 elm-alist)
+)
+
+(define (-class-set-methods! class method-alist)
+ (vector-set! class 4 method-alist)
+)
+
+(define (-class-set-all-initial-values! class init-list)
+ (vector-set! class 5 init-list)
+)
+
+(define (-class-set-all-methods! class all-meth-list)
+ (vector-set! class 6 all-meth-list)
+)
+
+(define (-class-set-class-desc! class parent-list)
+ (vector-set! class 7 parent-list)
+)
+
+; Make a class.
+; The new definition overrides any existing definition.
+
+(define (-class-make! name parents elements methods)
+ (let ((class (vector -class-tag name parents elements methods #f #f #f))
+ (list-entry (assq name -class-list)))
+ (if list-entry
+ (set-cdr! list-entry class)
+ (set! -class-list (acons name class -class-list)))
+ class)
+)
+
+; Lookup a class given its name.
+; The result is the class or #f if not found.
+
+(define (class-lookup name) (assq-ref -class-list name))
+
+; Return a list of all direct parent classes of CLASS.
+
+(define (-class-parent-classes class)
+ ; -class-parents returns the names, we want the actual classes.
+ (let loop ((parents (-class-parents class))
+ (result ()))
+ (if (null? parents)
+ (reverse! result)
+ (let ((parent (class-lookup (car parents))))
+ (if (not parent)
+ ; The proc name we pass here is made up as we don't
+ ; want it to be the name of an internal proc.
+ (-object-error "class" (car parents) "not a class"))
+ (loop (cdr parents) (cons parent result)))))
+)
+
+; Cover proc of -class-name for the outside world to use.
+; The result is the name of the class or #f if CLASS is not a class.
+; We could issue an error here, but to be consistent with object-class-name
+; we don't.
+
+(define (class-name class)
+ (if (class? class)
+ (-class-name class)
+ #f)
+)
+
+; Return a boolean indicating if CLASS or any parent class has
+; multiple inheritance.
+
+(define (-class-mi? class)
+ (-class-desc-mi? (-class-class-desc class))
+)
+
+; Class descriptor utilities.
+; A class-descriptor is:
+; (class mi? (base-offset . delta) child-backpointer (parent1-entry) ...)
+
+;(define (-class-desc-make class offset bkptr parents)
+; (append (list class offset bkptr) parents)
+;)
+(define (-class-desc? maybe-class-desc)
+ (and (pair? maybe-class-desc)
+ (class? (car maybe-class-desc)))
+)
+(define -class-desc-class car)
+(define -class-desc-mi? cadr)
+(define -class-desc-offset caddr)
+(define -class-desc-offset-base caaddr)
+(define -class-desc-offset-delta cdaddr)
+(define -class-desc-child cadddr)
+(define -class-desc-parents cddddr)
+; Note that this is an assq on the classes themselves, not their names.
+; The result is the parent's class-descriptor.
+(define -class-desc-lookup-parent assq)
+
+; Compute the class descriptor of CLASS.
+; OFFSET is the beginning offset in the element vector.
+; We can assume the parents of CLASS have already been initialized.
+;
+; A class-descriptor is:
+; (class mi? (base-offset . delta) child-backpointer (parent1-entry) ...)
+; MI? is a boolean indicating if multiple inheritance is present.
+; BASE-OFFSET is the offset into the object vector of the baseclass's elements
+; (or first baseclass in the mi case).
+; DELTA is the offset from BASE-OFFSET of the class's own elements.
+; CHILD is the backlink to the direct child class or #f for the top class.
+; ??? Is the use of `top' backwards from traditional usage?
+
+(define (-class-compute-class-desc class offset child)
+
+ ; OFFSET must be global to the calculation because it is continually
+ ; incremented as we recurse down through the hierarchy (actually, as we
+ ; traverse back up). At any point in time it is the offset from the start
+ ; of the element vector of the next class's elements.
+ ; Object elements are laid out using a depth first traversal of the
+ ; inheritance tree.
+
+ (define (compute1 class child base-offset)
+
+ ; Build the result first, then build our parents so that our parents have
+ ; the right value for the CHILD-BACKPOINTER field.
+ ; Use a bogus value for mi? and offset for the moment.
+ ; The correct values are set later.
+
+ (let ((result (list class #f (cons 999 999) child))
+ (mi? (> (length (-class-parents class)) 1)))
+
+ ; Recurse on the parents.
+ ; We use `append!' here as the location of `result' is now fixed so
+ ; that our parent's child-backpointer remains stable.
+
+ (append! result
+ (let loop ((parents (-class-parents class))
+ (parent-descs ())
+ (base-offset base-offset))
+ (if (null? parents)
+ (reverse! parent-descs)
+ (let ((parent (class-lookup (car parents))))
+ (if (not parent)
+ ; The proc name we pass here is made up as we don't
+ ; want it to be the name of an internal proc.
+ (-object-error "class" (car parents) "not a class"))
+ (if (and (not mi?)
+ (-class-mi? parent))
+ (set! mi? #t))
+ (let ((parent-desc (compute1 parent result base-offset)))
+ (loop (cdr parents)
+ (cons parent-desc parent-descs)
+ offset))))))
+
+ (list-set! result 1 mi?)
+ (list-set! result 2 (cons base-offset (- offset base-offset)))
+ (set! offset (+ offset (length (-class-elements class))))
+ result))
+
+ (compute1 class child offset)
+)
+
+; Return the top level class-descriptor of CLASS-DESC.
+
+(define (-class-desc-top class-desc)
+ (if (-class-desc-child class-desc)
+ (-class-desc-top (-class-desc-child class-desc))
+ class-desc)
+)
+
+; Pretty print a class descriptor.
+
+(define (class-desc-dump class-desc)
+ (let* ((cep (current-error-port))
+ (top-desc (-class-desc-top class-desc))
+ (spaces (lambda (n port)
+ (display (make-string n #\space) port)))
+ (writeln (lambda (indent port . args)
+ (spaces indent port)
+ (for-each (lambda (arg) (display arg port))
+ args)
+ (newline port)))
+ )
+ (letrec ((dump (lambda (cd indent)
+ (writeln indent cep "Class: "
+ (-class-name (-class-desc-class cd)))
+ (writeln indent cep " mi?: "
+ (-class-desc-mi? cd))
+ (writeln indent cep " base offset: "
+ (-class-desc-offset-base cd))
+ (writeln indent cep " delta: "
+ (-class-desc-offset-delta cd))
+ (writeln indent cep " child: "
+ (if (-class-desc-child cd)
+ (-class-name (-class-desc-class
+ (-class-desc-child cd)))
+ "-top-"))
+ (for-each (lambda (parent-cd) (dump parent-cd (+ indent 4)))
+ (-class-desc-parents cd))
+ )))
+ (display "Top level class: " cep)
+ (display (-class-name (-class-desc-class top-desc)) cep)
+ (newline cep)
+ (dump class-desc 0)
+ ))
+)
+
+; Low level object utilities.
+
+; Make an object.
+; All elements get initial (or unbound) values.
+
+(define (-object-make! class)
+ (-class-check-init! class)
+ (vector (apply vector (append! (list -object-tag class)
+ (-class-all-initial-values class)))
+ (-class-class-desc class))
+)
+
+; Make an object using VALUES.
+; VALUES must specify all elements in the class (and parent classes).
+
+(define (-object-make-with-values! class class-desc values)
+ (-class-check-init! class)
+ (vector (apply vector (append! (list -object-tag class) values))
+ class-desc)
+)
+
+; Copy an object.
+; If TOP?, the copy is of the top level object with any specialization
+; discarded.
+; WARNING: A shallow copy is currently done on the elements!
+
+(define (-object-copy obj top?)
+ (if top?
+ (vector (-object-vector-copy (-object-elements obj))
+ (-class-class-desc (-object-top-class obj)))
+ (vector (-object-vector-copy (-object-elements obj))
+ (-object-class-desc obj)))
+)
+
+; Specialize an object to be one from a parent class.
+; The result is the same object, but with a different view (confined to
+; a particular parent class).
+
+(define (-object-specialize obj class-desc)
+ (vector (-object-elements obj) class-desc)
+)
+
+; Accessors.
+
+(define (-object-elements obj) (vector-ref obj 0))
+(define (-object-class-desc obj) (vector-ref obj 1))
+(define (-object-class obj) (-class-desc-class (-object-class-desc obj)))
+(define (-object-class-name obj) (-class-name (-object-class obj)))
+(define (-object-top-class obj) (vector-ref (-object-elements obj) 1))
+
+(define (-object-elm-get obj class-desc elm-base-offset)
+ (vector-ref (-object-elements obj)
+ (+ (-class-desc-offset-base class-desc) elm-base-offset))
+)
+
+(define (-object-elm-set! obj class-desc elm-base-offset new-val)
+ (vector-set! (-object-elements obj)
+ (+ (-class-desc-offset-base class-desc) elm-base-offset)
+ new-val)
+ -object-unspecified
+)
+
+; Return a boolean indicating of OBJ has multiple-inheritance.
+
+(define (-object-mi? obj)
+ (-class-mi? (-object-top-class obj))
+)
+
+; Return boolean indicating if X is an object.
+
+(define (object? obj)
+ (and (vector? obj)
+ (= (vector-length obj) 2)
+ (vector? (vector-ref obj 0))
+ (eq? -object-tag (vector-ref (vector-ref obj 0) 0))
+ (-class-desc? (vector-ref obj 1)))
+)
+
+; Return the class of an object.
+
+(define (object-class obj)
+ (-object-check obj "object-class")
+ (-object-class obj)
+)
+
+; Cover proc of -object-class-name for the outside world to use.
+; The result is the name of the class or #f if OBJ is not an object.
+
+(define (object-class-name obj)
+ (if (object? obj)
+ (-object-class-name obj)
+ #f)
+)
+
+; Class operations.
+
+; Return the list of initial values for CLASS.
+; The result does not include parent classes.
+
+(define (-class-my-initial-values class)
+ (map cadr (-class-elements class))
+)
+
+; Initialize class if not already done.
+; FIXME: Need circularity check. Later.
+
+(define (-class-check-init! class)
+ ; This should be fast the second time through, so don't do any
+ ; computation until we know it's necessary.
+
+ (if (not (-class-all-initial-values class))
+
+ (begin
+
+ ; First pass ensures all parents are initialized.
+ (for-each -class-check-init!
+ (-class-parent-classes class))
+
+ ; Next pass initializes the initial value list.
+ (letrec ((get-inits
+ (lambda (class)
+ (let ((parents (-class-parent-classes class)))
+ (append (apply append (map get-inits parents))
+ (-class-my-initial-values class))))))
+
+ (let* ((parents (-class-parent-classes class))
+ (inits (append (apply append (map get-inits parents))
+ (-class-my-initial-values class))))
+ (-class-set-all-initial-values! class inits)))
+
+ ; Next pass initializes the class's class-descriptor.
+ ; Object elements begin at offset 2 in the element vector.
+ (-class-set-class-desc! class
+ (-class-compute-class-desc class 2 #f))
+ ))
+
+ -object-unspecified
+)
+
+; Make a class.
+;
+; PARENTS is a list of names of parent classes. The parents need not
+; exist yet, though they must exist when the class is first instantiated.
+; ELMS is a either a list of either element names or name/value pairs.
+; Elements without initial values are marked as "unbound".
+; METHODS is an initial alist of methods. More methods can be added with
+; method-make!.
+
+(define (class-make name parents elms methods)
+ (let ((elm-list #f))
+
+ ; Mark elements without initial values as unbound, and
+ ; compute indices into the element vector (relative to the class's
+ ; offset).
+ ; Elements are recorded as (symbol initial-value private? . vector-index)
+ ; FIXME: For now all elements are marked as "public".
+ (let loop ((elm-list-tmp ()) (index 0) (elms elms))
+ (if (null? elms)
+ (set! elm-list (reverse! elm-list-tmp)) ; done
+ (if (pair? (car elms))
+ (loop (acons (caar elms)
+ (cons (cdar elms) (cons #f index))
+ elm-list-tmp)
+ (+ index 1)
+ (cdr elms))
+ (loop (acons (car elms)
+ (cons -object-unbound (cons #f index))
+ elm-list-tmp)
+ (+ index 1)
+ (cdr elms)))))
+
+ (let ((result (-class-make! name parents elm-list methods)))
+
+ ; Create the standard `make!' method.
+ ; The caller can override afterwards if desired.
+ ; Note that if there are any parent classes then we don't know the names
+ ; of all of the elements yet, that is only known after the class has been
+ ; initialized which only happens when the class is first instantiated.
+ ; This method won't be called until that happens though so we're safe.
+ ; This is written without knowledge of the names, it just initializes
+ ; all elements.
+ (method-make! result 'make!
+ (lambda args
+ (let ((self (car args)))
+ ; Ensure exactly all of the elements are provided.
+ (if (not (= (length args)
+ (- (vector-length (-object-elements self)) 1)))
+ (-object-error "make!" "" "wrong number of arguments to method `make!'"))
+ (-object-make-with-values! (-object-top-class self)
+ (-object-class-desc self)
+ (cdr args)))))
+
+ result))
+)
+
+; Create an object of a class CLASS.
+
+(define (new class)
+ (-class-check class "new")
+
+ (if -object-verbose?
+ (display (string-append "Instantiating class " (-class-name class) ".\n")
+ (current-error-port)))
+
+ (-object-make! class)
+)
+
+; Make a copy of OBJ.
+; WARNING: A shallow copy is done on the elements!
+
+(define (object-copy obj)
+ (-object-check obj "object-copy")
+ (-object-copy obj #f)
+)
+
+; Make a copy of OBJ.
+; This makes a copy of top level object, with any specialization discarded.
+; WARNING: A shallow copy is done on the elements!
+
+(define (object-copy-top obj)
+ (-object-check obj "object-copy-top")
+ (-object-copy obj #t)
+)
+
+; Utility to define a standard `make!' method.
+; A standard make! method is one in which all it does is initialize
+; fields from args.
+
+(define (method-make-make! class args)
+ (let ((lambda-expr
+ (append (list 'lambda (cons 'self args))
+ (map (lambda (elm) (list 'elm-set! 'self
+ (list 'quote elm) elm))
+ args)
+ '(self))))
+ (method-make! class 'make! (eval lambda-expr))
+ )
+)
+
+; The "standard" way to invoke `make!' is (send (new class) 'make! ...).
+; This puts all that in a cover function.
+
+(define (make class . operands)
+ (apply send (append (cons (new class) ()) '(make!) operands))
+)
+
+; Return #t if class X is a subclass of BASE-NAME.
+
+(define (-class-subclass? base-name x)
+ (if (eq? base-name (-class-name x))
+ #t
+ (let loop ((parents (-class-parents x)))
+ (if (null? parents)
+ #f
+ (if (-class-subclass? base-name (class-lookup (car parents)))
+ #t
+ (loop (cdr parents))))))
+)
+
+; Return #t if OBJECT is an instance of CLASS.
+; This does not signal an error if OBJECT is not an object as this is
+; intended to be used in class predicates.
+
+(define (class-instance? class object)
+ (-class-check class "class-instance?")
+ (if (object? object)
+ (-class-subclass? (-class-name class) (-object-class object))
+ #f)
+)
+
+; Element operations.
+
+; Lookup an element in a class-desc.
+; The result is (class-desc . (private? . elm-offset)) or #f if not found.
+; ??? We could define accessors of the result but knowledge of its format
+; is restricted to this section of the source.
+
+(define (-class-lookup-element class-desc elm-name)
+ (let* ((class (-class-desc-class class-desc))
+ (elm (assq elm-name (-class-elements class))))
+ (if elm
+ (cons class-desc (cddr elm))
+ (let loop ((parents (-class-desc-parents class-desc)))
+ (if (null? parents)
+ #f
+ (let ((elm (-class-lookup-element (car parents) elm-name)))
+ (if elm
+ elm
+ (loop (cdr parents)))))
+ ))
+ )
+)
+
+; Given the result of -class-lookup-element, return the element's delta
+; from base-offset.
+
+(define (-elm-delta index)
+ (+ (-class-desc-offset-delta (car index))
+ (cddr index))
+)
+
+; Return a boolean indicating if ELM is bound in OBJ.
+
+(define (elm-bound? obj elm)
+ (-object-check obj "elm-bound?")
+ (let* ((index (-class-lookup-element (-object-class-desc obj) elm))
+ (val (-object-elm-get obj (car index) (-elm-delta index))))
+ (not (eq? val -object-unbound)))
+)
+
+; Subroutine of elm-get.
+
+(define (-elm-make-method-getter self name)
+ (-object-check self "elm-get")
+ (let ((index (-class-lookup-element (-object-class-desc self) name)))
+ (if index
+ (procedure->memoizing-macro
+ (lambda (exp env)
+ `(lambda (obj)
+ (-object-elm-get obj (-object-class-desc obj)
+ ,(-elm-delta index)))))
+ (-object-error "elm-get" self "element not present: " name)))
+)
+
+; Get an element from an object.
+; If OBJ is `self' then the caller is required to be a method and we emit
+; memoized code. Otherwise we do things the slow way.
+; ??? There must be a better way.
+; What this does is turn
+; (elm-get self 'foo)
+; into
+; ((-elm-make-method-get self 'foo) self)
+; Note the extra set of parens. -elm-make-method-get then does the lookup of
+; foo and returns a memoizing macro that returns the code to perform the
+; operation with O(1). Cute, but I'm hoping there's an easier/better way.
+
+(defmacro elm-get (self name)
+ (if (eq? self 'self)
+ `(((-elm-make-method-getter ,self ,name)) ,self)
+ `(elm-xget ,self ,name))
+)
+
+; Subroutine of elm-set!.
+
+(define (-elm-make-method-setter self name)
+ (-object-check self "elm-set!")
+ (let ((index (-class-lookup-element (-object-class-desc self) name)))
+ (if index
+ (procedure->memoizing-macro
+ (lambda (exp env)
+ `(lambda (obj new-val)
+ (-object-elm-set! obj (-object-class-desc obj)
+ ,(-elm-delta index) new-val))))
+ (-object-error "elm-set!" self "element not present: " name)))
+)
+
+; Set an element in an object.
+; This can only be used by methods.
+; See the comments for `elm-get'!
+
+(defmacro elm-set! (self name new-val)
+ (if (eq? self 'self)
+ `(((-elm-make-method-setter ,self ,name)) ,self ,new-val)
+ `(elm-xset! ,self ,name ,new-val))
+)
+
+; Get an element from an object.
+; This is for invoking from outside a method, and without having to
+; use elm-make-getter. It should be used sparingly.
+
+(define (elm-xget obj name)
+ (-object-check obj "elm-xget")
+ (let ((index (-class-lookup-element (-object-class-desc obj) name)))
+ ; FIXME: check private?
+ (if index
+ (-object-elm-get obj (car index) (-elm-delta index))
+ (-object-error "elm-xget" obj "element not present: " name)))
+)
+
+; Set an element in an object.
+; This is for invoking from outside a method, and without having to
+; use elm-make-setter. It should be used sparingly.
+
+(define (elm-xset! obj name new-val)
+ (-object-check obj "elm-xset!")
+ (let ((index (-class-lookup-element (-object-class-desc obj) name)))
+ ; FIXME: check private?
+ (if index
+ (-object-elm-set! obj (car index) (-elm-delta index) new-val)
+ (-object-error "elm-xset!" obj "element not present: " name)))
+)
+
+; Return a boolean indicating if object OBJ has element NAME.
+
+(define (elm-present? obj name)
+ (-object-check obj "elm-present?")
+ (->bool (-class-lookup-element (-object-class-desc obj) name))
+)
+
+; Return lambda to get element NAME in CLASS.
+; FIXME: validate name.
+
+(define (elm-make-getter class name)
+ (-class-check class "elm-make-getter")
+ ; We use delay here as we can't assume parent classes have been
+ ; initialized yet.
+ (let ((fast-index (delay (-class-lookup-element
+ (-class-class-desc class) name))))
+ (lambda (obj)
+ ; ??? Should be able to use fast-index in mi case.
+ ; ??? Need to involve CLASS in lookup.
+ (let ((index (if (-object-mi? obj)
+ (-class-lookup-element (-object-class-desc obj) name)
+ (force fast-index))))
+ (-object-elm-get obj (car index) (-elm-delta index)))))
+)
+
+; Return lambda to set element NAME in CLASS.
+; FIXME: validate name.
+
+(define (elm-make-setter class name)
+ (-class-check class "elm-make-setter")
+ ; We use delay here as we can't assume parent classes have been
+ ; initialized yet.
+ (let ((fast-index (delay (-class-lookup-element
+ (-class-class-desc class) name))))
+ (lambda (obj newval)
+ ; ??? Should be able to use fast-index in mi case.
+ ; ??? Need to involve CLASS in lookup.
+ (let ((index (if (-object-mi? obj)
+ (-class-lookup-element (-object-class-desc obj) name)
+ (force fast-index))))
+ (-object-elm-set! obj (car index) (-elm-delta index) newval))))
+)
+
+; Return a list of all elements in OBJ.
+
+(define (elm-list obj)
+ (cddr (vector->list (-object-elements obj)))
+)
+
+; Method operations.
+
+; Lookup the next method in a class.
+; This means begin the search in the parents.
+; ??? What should this do for virtual methods. At present we treat them as
+; non-virtual.
+
+(define (-method-lookup-next class-desc method-name)
+ (let loop ((parents (-class-desc-parents class-desc)))
+ (if (null? parents)
+ #f
+ (let ((meth (-method-lookup (car parents) method-name #f)))
+ (if meth
+ meth
+ (loop (cdr parents))))))
+)
+
+; Lookup a method in a class.
+; The result is (class-desc . method). If the method is found in a parent
+; class, the associated parent class descriptor is returned. If the method is
+; a virtual method, the appropriate subclass's class descriptor is returned.
+; VIRTUAL? is #t if virtual methods are to be treated as such.
+; Otherwise they're treated as normal methods.
+;
+; FIXME: We don't yet implement the method cache.
+
+(define (-method-lookup class-desc method-name virtual?)
+ (if -object-verbose?
+ (display (string-append "Looking up method " method-name " in "
+ (-class-name (-class-desc-class class-desc)) ".\n")
+ (current-error-port)))
+
+ (let ((meth (assq method-name (-class-methods (-class-desc-class class-desc)))))
+ (if meth
+ (if (and virtual? (cadr meth)) ; virtual?
+ ; Traverse back up the inheritance chain looking for overriding
+ ; methods. The closest one to the top is the one to use.
+ (let loop ((child (-class-desc-child class-desc))
+ (goal-class-desc class-desc)
+ (goal-meth meth))
+ (if child
+ (begin
+ (if -object-verbose?
+ (display (string-append "Looking up virtual method "
+ method-name " in "
+ (-class-name (-class-desc-class child))
+ ".\n")
+ (current-error-port)))
+ (let ((meth (assq method-name (-class-methods (-class-desc-class child)))))
+ (if meth
+ ; Method found, update goal object and method.
+ (loop (-class-desc-child child) child meth)
+ ; Method not found at this level.
+ (loop (-class-desc-child child) goal-class-desc goal-meth))))
+ ; Went all the way up to the top.
+ (cons goal-class-desc (cddr goal-meth))))
+ ; Non-virtual, done.
+ (cons class-desc (cddr meth)))
+ ; Method not found, search parents.
+ (-method-lookup-next class-desc method-name)))
+)
+
+; Return a boolean indicating if object OBJ has method NAME.
+
+(define (method-present? obj name)
+ (-object-check obj "method-present?")
+ (->bool (-method-lookup (-object-class-desc obj) name #f))
+)
+
+; Return method NAME of CLASS or #f if not present.
+; ??? Assumes CLASS has been initialized.
+
+(define (method-proc class name)
+ (-class-check class "method-proc")
+ (let ((meth (-method-lookup (-class-class-desc class) name #t)))
+ (if meth
+ (cdr meth)
+ #f))
+)
+
+; Add a method to a class.
+; FIXME: ensure method-name is a symbol
+
+(define (method-make! class method-name method)
+ (-class-check class "method-make!")
+ (if (not (procedure? method))
+ (-object-error "method-make!" method "method must be a procedure"))
+ (-class-set-methods! class (acons method-name
+ (cons #f method)
+ (-class-methods class)))
+ -object-unspecified
+)
+
+; Add a virtual method to a class.
+; FIXME: ensure method-name is a symbol
+
+(define (method-make-virtual! class method-name method)
+ (-class-check class "method-make-virtual!")
+ (if (not (procedure? method))
+ (-object-error "method-make-virtual!" method "method must be a procedure"))
+ (-class-set-methods! class (acons method-name
+ (cons #t method)
+ (-class-methods class)))
+ -object-unspecified
+)
+
+; Utility to create "forwarding" methods.
+; METHODS are forwarded to class member ELM-NAME, assumed to be an object.
+; The created methods take a variable number of arguments.
+; Argument length checking will be done by the receiving method.
+; FIXME: ensure elm-name is a symbol
+
+(define (method-make-forward! class elm-name methods)
+ (for-each (lambda (method-name)
+ (method-make!
+ class method-name
+ (eval `(lambda args
+ (apply send
+ (cons (elm-get (car args)
+ (quote ,elm-name))
+ (cons (quote ,method-name)
+ (cdr args))))))))
+ methods)
+ -object-unspecified
+)
+
+; Same as method-make-forward! but creates virtual methods.
+; FIXME: ensure elm-name is a symbol
+
+(define (method-make-virtual-forward! class elm-name methods)
+ (for-each (lambda (method-name)
+ (method-make-virtual!
+ class method-name
+ (eval `(lambda args
+ (apply send
+ (cons (elm-get (car args)
+ (quote ,elm-name))
+ (cons (quote ,method-name)
+ (cdr args))))))))
+ methods)
+ -object-unspecified
+)
+
+; Utility of send, send-next.
+
+(define (-object-method-notify obj method-name maybe-next)
+ (set! -object-verbose? #f)
+ (display (string-append "Sending " maybe-next method-name " to"
+ (if (method-present? obj 'get-name)
+ (let ((name (send obj 'get-name)))
+ (if (or (symbol? name) (string? name))
+ (string-append " object " name)
+ ""))
+ "")
+ " class " (object-class-name obj) ".\n")
+ (current-error-port))
+ (set! -object-verbose? #t)
+)
+
+; Invoke a method in an object.
+; When the method is invoked, the (possible parent class) object in which the
+; method is found is passed to the method.
+; ??? The word `send' comes from "sending messages". Perhaps should pick
+; a better name for this operation.
+
+(define (send obj method-name . args)
+ (-object-check obj "send")
+ (-object-check-name method-name "send" "not a method name")
+ (if -object-verbose? (-object-method-notify obj method-name ""))
+
+ (let ((class-desc.meth (-method-lookup (-object-class-desc obj)
+ method-name #t)))
+ (if class-desc.meth
+ (apply (cdr class-desc.meth)
+ (cons (-object-specialize obj (car class-desc.meth))
+ args))
+ (-object-error "send" obj "method not supported: " method-name)))
+)
+
+; Invoke the next method named METHOD-NAME in the heirarchy of OBJ.
+; i.e. the method that would have been invoked if the calling method
+; didn't exist.
+; This may only be called by a method.
+; ??? Ideally we shouldn't need the METHOD-NAME argument. It could be
+; removed with a bit of effort, but is it worth it?
+
+(define (send-next obj method-name . args)
+ (-object-check obj "send-next")
+ (-object-check-name method-name "send-next" "not a method name")
+ (if -object-verbose? (-object-method-notify obj method-name "next "))
+
+ (let ((class-desc.meth (-method-lookup-next (-object-class-desc obj)
+ method-name)))
+ (if class-desc.meth
+ (apply (cdr class-desc.meth)
+ (cons (-object-specialize obj (car class-desc.meth))
+ args))
+ (-object-error "send-next" obj "method not supported: " method-name)))
+)
+
+; Parent operations.
+
+; Subroutine of `parent' to lookup a (potentially nested) parent class.
+; The result is the parent's class-descriptor or #f if not found.
+
+(define (-class-parent class-desc parent)
+ (let* ((parent-descs (-class-desc-parents class-desc))
+ (desc (-class-desc-lookup-parent parent parent-descs)))
+ (if desc
+ desc
+ (let loop ((parents parent-descs))
+ (if (null? parents)
+ #f
+ (let ((desc (-class-parent (car parents) parent)))
+ (if desc
+ desc
+ (loop (cdr parents))))))))
+)
+
+; Subroutine of `parent' to lookup a parent via a path.
+; PARENT-PATH, a list, is the exact path to the parent class.
+; The result is the parent's class-descriptor or #f if not found.
+; For completeness' sake, if PARENT-PATH is empty, CLASS-DESC is returned.
+
+(define (-class-parent-via-path class-desc parent-path)
+ (if (null? parent-path)
+ class-desc
+ (let ((desc (-class-desc-lookup-parent (car parent-path)
+ (-class-desc-parents class-desc))))
+ (if desc
+ (if (null? (cdr parent-path))
+ desc
+ (-class-parent-via-path (car desc) (cdr parent-path)))
+ #f)))
+)
+
+; Lookup a parent class of object OBJ.
+; CLASS is either a class or a list of classes.
+; If CLASS is a list, it is a (possibly empty) "path" to the parent.
+; Otherwise it is any parent and is searched for breadth-first.
+; ??? Methinks this should be depth-first.
+; The result is OBJ, specialized to the found parent.
+
+(define (object-parent obj class)
+ (-object-check obj "object-parent")
+ (cond ((class? class) #t)
+ ((list? class) (for-each (lambda (class) (-class-check class
+ "object-parent"))
+ class))
+ (else (-object-error "object-parent" class "invalid parent path")))
+
+ ; Hobbit generates C code that passes the function
+ ; -class-parent-via-path or -class-parent, not the appropriate
+ ; SCM object.
+; (let ((result ((if (or (null? class) (pair? class))
+; -class-parent-via-path
+; -class-parent)
+; obj class)))
+ ; So it's rewritten like this.
+ (let ((result (if (class? class)
+ (-class-parent (-object-class-desc obj) class)
+ (-class-parent-via-path (-object-class-desc obj) class))))
+ (if result
+ (-object-specialize obj result)
+ (-object-error "object-parent" obj "parent not present")))
+ ; FIXME: should print path in error message.
+)
+
+; Make PARENT-NAME a parent of CLASS, cons'd unto the front of the search
+; order. This is used to add a parent class to a class after it has already
+; been created. Obviously this isn't something one does willy-nilly.
+; The parent is added to the front of the current parent list (affects
+; method lookup).
+
+(define (class-cons-parent! class parent-name)
+ (-class-check class "class-cons-parent!")
+ (-object-check-name parent-name "class-cons-parent!" "not a class name")
+ (-class-set-parents! class (cons parent-name (-class-parents class)))
+ -object-unspecified
+)
+
+; Make PARENT-NAME a parent of CLASS, cons'd unto the end of the search order.
+; This is used to add a parent class to a class after it has already been
+; created. Obviously this isn't something one does willy-nilly.
+; The parent is added to the end of the current parent list (affects
+; method lookup).
+
+(define (class-append-parent! class parent-name)
+ (-class-check class "class-append-parent!")
+ (-object-check-name parent-name "class-append-parent!" "not a class name")
+ (-class-set-parents! obj (append (-class-parents obj) (list parent-name)))
+ -object-unspecified
+)
+
+; Miscellaneous publically accessible utilities.
+
+; Reset the object system (delete all classes).
+
+(define (object-reset!)
+ (set! -class-list ())
+ -object-unspecified
+)
+
+; Call once to initialize the object system.
+; Only necessary if classes have been modified after objects have been
+; instantiated. This usually happens during development only.
+
+(define (object-init!)
+ (for-each (lambda (class)
+ (-class-set-all-initial-values! class #f)
+ (-class-set-all-methods! class #f)
+ (-class-set-class-desc! class #f))
+ (class-list))
+ (for-each (lambda (class)
+ (-class-check-init! class))
+ (class-list))
+ -object-unspecified
+)
+
+; Return list of all classes.
+
+(define (class-list) (map cdr -class-list))
+
+; Utility to map over a class and all its parent classes, recursively.
+
+(define (class-map-over-class proc class)
+ (cons (proc class)
+ (map (lambda (class) (class-map-over-class proc class))
+ (-class-parent-classes class)))
+)
+
+; Return class tree of a class or object.
+
+(define (class-tree class-or-object)
+ (cond ((class? class-or-object)
+ (class-map-over-class class-name class-or-object))
+ ((object? class-or-object)
+ (class-map-over-class class-name (-object-class class-or-object)))
+ (else (-object-error "class-tree" class-or-object
+ "not a class or object")))
+)
+
+; Return names of each alist.
+
+(define (-class-alist-names class)
+ (list (-class-name class)
+ (map car (-class-elements class))
+ (map car (-class-methods class)))
+)
+
+; Return complete layout of class-or-object.
+
+(define (class-layout class-or-object)
+ (cond ((class? class-or-object)
+ (class-map-over-class -class-alist-names class-or-object))
+ ((object? class-or-object)
+ (class-map-over-class -class-alist-names (-object-class class-or-object)))
+ (else (-object-error "class-layout" class-or-object
+ "not a class or object")))
+)
+
+; Like assq but based on the `name' element.
+; WARNING: Slow.
+
+(define (object-assq name obj-list)
+ (find-first (lambda (o) (eq? (elm-xget o 'name) name))
+ obj-list)
+)
+
+; Like memq but based on the `name' element.
+; WARNING: Slow.
+
+(define (object-memq name obj-list)
+ (let loop ((r obj-list))
+ (cond ((null? r) #f)
+ ((eq? name (elm-xget (car r) 'name)) r)
+ (else (loop (cdr r)))))
+)
+
+; Misc. internal utilities.
+
+; We need a fast vector copy operation.
+; If `vector-copy' doesn't exist (which is assumed to be the fast one),
+; provide a simple version.
+; FIXME: Need deep copier instead.
+
+(if (defined? 'vector-copy)
+ (define -object-vector-copy vector-copy)
+ (define (-object-vector-copy v) (list->vector (vector->list v)))
+)
+
+; Profiling support
+
+(if (and #f (defined? 'proc-profile))
+ (begin
+ (proc-profile elm-get)
+ (proc-profile elm-set!)
+ (proc-profile elm-present?)
+ (proc-profile -method-lookup)
+ (proc-profile send)
+ (proc-profile new)
+ (proc-profile make)
+ ))
diff --git a/cgen/decode.scm b/cgen/decode.scm
new file mode 100644
index 00000000000..3fbda2174df
--- /dev/null
+++ b/cgen/decode.scm
@@ -0,0 +1,640 @@
+; Application independent decoder support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+;
+; This file provides utilities for building instruction set decoders.
+; At present its rather limited, and is geared towards the simulator
+; where the goal is hyper-efficiency [not that there isn't room for much
+; improvement, but rather that that's what the current focus is].
+;
+; The CPU description file provides the first pass's bit mask with the
+; `decode-assist' spec. This gives the decoder a head start on how to
+; efficiently decode the instruction set. The rest of the decoder is
+; determined algorithmically.
+; ??? Need to say more here.
+;
+; The main entry point is decode-build-table.
+;
+; Main procedure call tree:
+; decode-build-table
+; -build-slots
+; -build-decode-table-guts
+; -build-decode-table-entry
+; -build-slots
+; -build-decode-table-guts
+;
+; -build-slots/-build-decode-table-guts are recursively called to construct a
+; tree of "table-guts" elements, and then the application recurses on the
+; result. For example see sim-decode.scm.
+;
+; FIXME: Don't create more than 3 shifts (i.e. no more than 3 groups).
+; FIXME: Exits when insns are unambiguously determined, even if there are more
+; opcode bits to examine.
+
+; Decoder data structures and accessors.
+; The set of instruction is internally recorded as a tree of two data
+; structures: "table-guts" and "table-entry".
+; [The choice of "table-guts" is historical, a better name will come to mind
+; eventually.]
+
+; Decoded tables data structure, termed "table guts".
+; A simple data structure of 4 elements:
+; bitnums: list of bits that have been used thus far to decode the insn
+; startbit: bit offset in instruction of value in C local variable `insn'
+; bitsize: size of value in C local variable `insn', the number
+; of bits of the instruction read thus far
+; entries: list of insns that match the decoding thus far,
+; each entry in the list is a `dtable-entry' record
+
+(define (dtable-guts-make bitnums startbit bitsize entries)
+ (vector bitnums startbit bitsize entries)
+)
+
+; Accessors.
+(define (dtable-guts-bitnums tg) (vector-ref tg 0))
+(define (dtable-guts-startbit tg) (vector-ref tg 1))
+(define (dtable-guts-bitsize tg) (vector-ref tg 2))
+(define (dtable-guts-entries tg) (vector-ref tg 3))
+
+; A decoded subtable.
+; A simple data structure of 3 elements:
+; key: name to distinguish this subtable from others, used for lookup
+; table: a table-guts element
+; name: name of C variable containing the table
+;
+; The implementation uses a list so the lookup can use assv.
+
+(define (subdtable-make key table name)
+ (list key table name)
+)
+
+; Accessors.
+(define (subdtable-key st) (car st))
+(define (subdtable-table st) (cadr st))
+(define (subdtable-name st) (caddr st))
+
+; List of decode subtables.
+(define -decode-subtables nil)
+
+(define (subdtable-lookup key) (assv key -decode-subtables))
+
+; Add SUBTABLE-GUTS to the subtables list if not already present.
+; Result is the subtable entry already present, or new entry.
+; The key is computed so as to make comparisons possible with assv.
+
+(define (subdtable-add subtable-guts name)
+ (let* ((key (string->symbol
+ (string-append
+ (numbers->string (dtable-guts-bitnums subtable-guts) " ")
+ " " (number->string (dtable-guts-bitsize subtable-guts))
+ (string-map
+ (lambda (elm)
+ (case (dtable-entry-type elm)
+ ((insn)
+ (string-append " " (obj:name (dtable-entry-value elm))))
+ ((table)
+ (string-append " " (subdtable-name (dtable-entry-value elm))))
+ ((expr)
+ (string-append " " (exprtable-name (dtable-entry-value elm))))
+ (else (error "bad dtable entry type:"
+ (dtable-entry-type elm)))))
+ (dtable-guts-entries subtable-guts)))))
+ (entry (subdtable-lookup key)))
+ (if (not entry)
+ (begin
+ (set! -decode-subtables (cons (subdtable-make key subtable-guts name)
+ -decode-subtables))
+ (car -decode-subtables))
+ entry))
+)
+
+; An instruction and predicate for final matching.
+
+(define (exprtable-entry-make insn expr)
+ (vector insn expr (rtl-find-ifields expr))
+)
+
+; Accessors.
+
+(define (exprtable-entry-insn entry) (vector-ref entry 0))
+(define (exprtable-entry-expr entry) (vector-ref entry 1))
+(define (exprtable-entry-iflds entry) (vector-ref entry 2))
+
+; Return a pseudo-cost of processing exprentry X.
+
+(define (exprentry-cost x)
+ (let ((expr (exprtable-entry-expr x)))
+ (case (rtx-name expr)
+ ((member) (length (rtx-member-set expr)))
+ (else 4)))
+)
+
+; Sort an exprtable, optimum choices first.
+; Basically an optimum choice is a cheaper choice.
+
+(define (exprtable-sort expr-list)
+ (sort expr-list
+ (lambda (a b)
+ (let ((costa (exprentry-cost a))
+ (costb (exprentry-cost b)))
+ (< costa costb))))
+)
+
+; Return the name of the expr table for INSN-EXPRS,
+; which is a list of exprtable-entry elements.
+
+(define (-gen-exprtable-name insn-exprs)
+ (string-map (lambda (x)
+ (string-append (obj:name (exprtable-entry-insn x))
+ "-"
+ (rtx-strdump (exprtable-entry-expr x))))
+ insn-exprs)
+)
+
+; A set of instructions that need expressions to distinguish.
+; Typically the expressions are ifield-assertion specs.
+; INSN-EXPRS is a sorted list of exprtable-entry elements.
+; The list is considered sorted in the sense that the first insn to satisfy
+; its predicate is chosen.
+
+(define (exprtable-make name insn-exprs)
+ (vector name insn-exprs)
+)
+
+; Accessors.
+
+(define (exprtable-name etable) (vector-ref etable 0))
+(define (exprtable-insns etable) (vector-ref etable 1))
+
+; Decoded table entry data structure.
+; A simple data structure of 3 elements:
+; index: index in the parent table
+; entry type indicator: 'insn or 'table or 'expr
+; value: the insn or subtable or exprtable
+
+(define (dtable-entry-make index type value)
+ (assert value)
+ (vector index type value)
+)
+
+; Accessors.
+(define (dtable-entry-index te) (vector-ref te 0))
+(define (dtable-entry-type te) (vector-ref te 1))
+(define (dtable-entry-value te) (vector-ref te 2))
+
+; Return #t if BITNUM is a good bit to use for decoding.
+; MASKS is a list of opcode masks.
+; MASK-LENS is a list of lengths of each value in MASKS.
+; BITNUM is the number of the bit to test. It's value depends on LSB0?.
+; It can be no larger than the smallest element in MASKS.
+; E.g. If MASK-LENS consists of 16 and 32 and LSB0? is #f, BITNUM must
+; be from 0 to 15.
+; FIXME: This isn't quite right. What if LSB0? = #t? Need decode-bitsize.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+;
+; FIXME: This is just a first cut, but the governing intent is to not require
+; targets to specify decode tables, hints, or algorithms.
+; Certainly as it becomes useful they can supply such information.
+; The point is to avoid having to as much as possible.
+;
+; FIXME: Bit numbers shouldn't be considered in isolation.
+; It would be better to compute use counts of all of them and then see
+; if there's a cluster of high use counts.
+
+(define (-usable-decode-bit? masks mask-lens bitnum lsb0?)
+ (let* ((has-bit (map (lambda (msk len)
+ (bit-set? msk (if lsb0? bitnum (- len bitnum 1))))
+ masks mask-lens)))
+ (or (all-true? has-bit)
+ ; If half or more insns use the bit, it's a good one.
+ ; FIXME: An empirical guess at best.
+ (>= (count-true has-bit) (quotient (length has-bit) 2))
+ ))
+)
+
+
+; Compute population counts for each bit. Return it as a vector indexed by bit number.
+(define (-mask-bit-population masks mask-lens lsb0?)
+ (let* ((max-length (apply max mask-lens))
+ (population (make-vector max-length 0)))
+ (for-each (lambda (mask len)
+ (logit 5 " population count mask=" (number->hex mask) " len=" len "\n")
+ (for-each (lambda (bitno)
+ (if (bit-set? mask (if lsb0? bitno (- len bitno 1)))
+ (vector-set! population bitno
+ (+ 1 (vector-ref population bitno)))))
+ (-range len)))
+ masks mask-lens)
+ population)
+)
+
+
+; Return a list (0 ... limit-1)
+(define (-range limit)
+ (let loop ((i 0)
+ (indices (list)))
+ (if (= i limit) (reverse indices) (loop (+ i 1) (cons i indices))))
+)
+
+; Return a list (base ... base+size-1)
+(define (-range2 base size)
+ (let loop ((i base)
+ (indices (list)))
+ (if (= i (+ base size)) (reverse indices) (loop (+ i 1) (cons i indices))))
+)
+
+
+; Return a copy of given vector, with all entries with given indices set to `value'
+(define (-vector-copy-set-all vector indices value)
+ (let ((new-vector (make-vector (vector-length vector))))
+ (for-each (lambda (index)
+ (vector-set! new-vector index (if (memq index indices)
+ value
+ (vector-ref vector index))))
+ (-range (vector-length vector)))
+ new-vector)
+)
+
+
+; Return a list of indices whose counts in the given vector exceed the given threshold.
+(define (-population-above-threshold population threshold)
+ (find (lambda (index) (if (vector-ref population index)
+ (>= (vector-ref population index) threshold)
+ #f))
+ (-range (vector-length population)))
+)
+
+
+; Return the top few most popular indices in the population vector, ignoring any
+; that are already used (marked by negative count). Don't exceed `size' unless
+; the clustering is just too good to pass up.
+(define (-population-top-few population size)
+ (let loop ((old-picks (list))
+ (remaining-population population)
+ (count-threshold (apply max (map (lambda (value) (if value value 0))
+ (vector->list population)))))
+ (let* ((new-picks (-population-above-threshold remaining-population count-threshold)))
+ (logit 4 "-population-top-few"
+ " picks=(" old-picks ") pop=(" remaining-population ")"
+ " threshold=" count-threshold " new-picks=(" new-picks ")\n")
+ (cond
+ ; No new matches?
+ ((null? new-picks)
+ (begin (assert (not (null? old-picks)))
+ old-picks))
+ ; Way too many matches?
+ ((> (+ (length new-picks) (length old-picks)) (+ 2 size))
+ (list-take (+ 2 size) (append new-picks old-picks)))
+ ; About right number of matches?
+ ((> (+ (length new-picks) (length old-picks)) (- 1 size))
+ (append old-picks new-picks))
+ ; Not enough? Lower the threshold a bit and try to add some more.
+ (else
+ (loop (append old-picks new-picks)
+ (-vector-copy-set-all remaining-population new-picks #f)
+ (truncate (* 0.8 count-threshold)))))))
+)
+
+
+
+; Given list of insns, return list of bit numbers of constant bits in opcode
+; that they all share (or mostly share), up to MAX elements.
+; ALREADY-USED is a list of bitnums we can't use.
+; STARTBIT is the bit offset of the instruction value that C variable `insn'
+; holds (note that this is independent of LSB0?).
+; DECODE-BITSIZE is the number of bits of the insn that `insn' holds.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+;
+; Nil is returned if there are none, meaning that there is an ambiguity in
+; the specification up to the current word.
+;
+; We assume INSN-LIST matches all opcode bits before STARTBIT.
+; FIXME: Revisit, as a more optimal decoder is sometimes achieved by doing
+; a cluster of opcode bits that appear later in the insn, and then coming
+; back to earlier ones.
+;
+; All insns are assumed to start at the same address so we handle insns of
+; varying lengths - we only analyze the common bits in all of them.
+;
+; Note that if we get called again to compute further opcode bits, we
+; start looking at STARTBIT again (rather than keeping track of how far in
+; the insn word we've progressed). We could do this as an optimization, but
+; we also have to handle the case where the initial set of decode bits misses
+; some and thus we have to go back and look at them. It may also turn out
+; that an opcode bit is skipped over because it doesn't contribute much
+; information to the decoding process (see -usable-decode-bit?). As the
+; possible insn list gets wittled down, the bit will become significant. Thus
+; the optimization is left for later. Also, see preceding FIXME.
+
+(define (decode-get-best-bits insn-list already-used startbit max decode-bitsize lsb0?)
+ (let* ((raw-population (-mask-bit-population (map insn-base-mask insn-list)
+ (map insn-base-mask-length insn-list)
+ lsb0?))
+ ; (undecoded (if lsb0?
+ ; (-range2 startbit (+ startbit decode-bitsize))
+ ; (-range2 (- startbit decode-bitsize) startbit)))
+ (used+undecoded already-used) ; (append already-used undecoded))
+ (filtered-population (-vector-copy-set-all raw-population used+undecoded #f))
+ (favorite-indices (-population-top-few filtered-population max))
+ (sorted-indices (sort favorite-indices (lambda (a b)
+ (if lsb0? (> a b) (< a b))))))
+ (logit 3
+ "Best decode bits (prev=" already-used " start=" startbit " decode=" decode-bitsize ")"
+ "=>"
+ "(" sorted-indices ")\n")
+ sorted-indices)
+)
+
+
+(define (OLDdecode-get-best-bits insn-list already-used startbit max decode-bitsize lsb0?)
+ (let ((masks (map insn-base-mask insn-list))
+ ; ??? We assume mask lengths are repeatedly used for insns longer
+ ; than the base insn size.
+ (mask-lens (map insn-base-mask-length insn-list))
+ (endbit (if lsb0?
+ -1 ; FIXME: for now (gets sparc port going)
+ (+ startbit decode-bitsize)))
+ (incr (if lsb0? -1 1)))
+ (let loop ((result nil)
+ (bitnum (if lsb0?
+ (+ startbit (- decode-bitsize 1))
+ startbit)))
+ (if (or (= (length result) max) (= bitnum endbit))
+ (reverse! result)
+ (if (and (not (memq bitnum already-used))
+ (-usable-decode-bit? masks mask-lens bitnum lsb0?))
+ (loop (cons bitnum result) (+ bitnum incr))
+ (loop result (+ bitnum incr))))
+ ))
+)
+
+; Return list of decode table entry numbers for INSN's opcode bits BITNUMS.
+; This is the indices into the decode table that match the instruction.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+;
+; Example: If BITNUMS is (0 1 2 3 4 5), and the constant (i.e. opcode) part of
+; the those bits of INSN is #b1100xx (where 'x' indicates a non-constant
+; part), then the result is (#b110000 #b110001 #b110010 #b110011).
+
+(define (-opcode-slots insn bitnums lsb0?)
+ (letrec ((opcode (insn-value insn))
+ (insn-len (insn-base-mask-length insn))
+ (decode-len (length bitnums))
+ (compute (lambda (val insn-len decode-len bl)
+ ;(display (list val insn-len decode-len bl)) (newline)
+ ; Oh My God. This isn't tail recursive.
+ (if (null? bl)
+ 0
+ (+ (if (bit-set? val
+ (if lsb0?
+ (car bl)
+ (- insn-len (car bl) 1)))
+ (integer-expt 2 (- (length bl) 1))
+ 0)
+ (compute val insn-len decode-len (cdr bl)))))))
+ (let* ((opcode (compute (insn-value insn) insn-len decode-len bitnums))
+ (opcode-mask (compute (insn-base-mask insn) insn-len decode-len bitnums))
+ (indices (missing-bit-indices opcode-mask (- (integer-expt 2 decode-len) 1))))
+ (logit 3 "insn =" (obj:name insn) " opcode=" opcode " indices=" indices "\n")
+ (map (lambda (index) (+ opcode index)) indices)))
+)
+
+; Subroutine of -build-slots.
+; Fill slot in INSN-VEC that INSN goes into.
+; BITNUMS is the list of opcode bits.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+;
+; Example: If BITNUMS is (0 1 2 3 4 5) and the constant (i.e. opcode) part of
+; the first six bits of INSN is #b1100xx (where 'x' indicates a non-constant
+; part), then elements 48 49 50 51 of INSN-VEC are cons'd with INSN.
+; Each "slot" is a list of matching instructions.
+
+(define (-fill-slot! insn-vec insn bitnums lsb0?)
+ ;(display (string-append "fill-slot!: " (obj:name insn) " ")) (display bitnums) (newline)
+ (let ((slot-nums (-opcode-slots insn bitnums lsb0?)))
+ ;(display (list "Filling slot(s)" slot-nums "...")) (newline)
+ (for-each (lambda (slot-num)
+ (vector-set! insn-vec slot-num
+ (cons insn (vector-ref insn-vec slot-num))))
+ slot-nums)
+ *UNSPECIFIED*
+ )
+)
+
+; Given a list of constant bitnums (ones that are predominantly, though perhaps
+; not always, in the opcode), record each insn in INSN-LIST in the proper slot.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; The result is a vector of insn lists. Each slot is a list of insns
+; that go in that slot.
+
+(define (-build-slots insn-list bitnums lsb0?)
+ (let ((result (make-vector (integer-expt 2 (length bitnums)) nil)))
+ ; Loop over each element, filling RESULT.
+ (for-each (lambda (insn)
+ (-fill-slot! result insn bitnums lsb0?))
+ insn-list)
+ result)
+)
+
+; Compute the name of a decode table, prefixed with PREFIX.
+; INDEX-LIST is a list of pairs: list of bitnums, table entry number,
+; in reverse order of traversal (since they're built with cons).
+; INDEX-LIST may be empty.
+
+(define (-gen-decode-table-name prefix index-list)
+ (set! index-list (reverse index-list))
+ (string-append
+ prefix
+ "table"
+ (string-map (lambda (elm) (string-append "_" (number->string elm)))
+ ; CDR of each element is the table index.
+ (map cdr index-list)))
+)
+
+; Generate one decode table entry for INSN-VEC at INDEX.
+; INSN-VEC is a vector of slots where each slot is a list of instructions that
+; map to that slot (opcode value). If a slot is nil, no insn has that opcode
+; value so the decoder marks it as being invalid.
+; STARTBIT is the bit offset of the instruction value that C variable `insn'
+; holds (note that this is independent of LSB0?).
+; DECODE-BITSIZE is the number of bits of the insn that `insn' holds.
+; INDEX-LIST is a list of pairs: list of bitnums, table entry number.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; INVALID-INSN is an <insn> object to use for invalid insns.
+; The result is a dtable-entry element (or "slot").
+
+; ??? For debugging.
+(define -build-decode-table-entry-args #f)
+
+(define (-build-decode-table-entry insn-vec startbit decode-bitsize index index-list lsb0? invalid-insn)
+ (let ((slot (filter-harmlessly-ambiguous-insns (vector-ref insn-vec index))))
+ (logit 2 "Processing decode entry "
+ (number->string index)
+ " in "
+ (-gen-decode-table-name "decode_" index-list)
+ ", "
+ (cond ((null? slot) "invalid")
+ ((= 1 (length slot)) (insn-syntax (car slot)))
+ (else "subtable"))
+ " ...\n")
+
+ (cond
+ ; If no insns map to this value, mark it as invalid.
+ ((null? slot) (dtable-entry-make index 'insn invalid-insn))
+
+ ; If only one insn maps to this value, that's it for this insn.
+ ((= 1 (length slot))
+ ; FIXME: Incomplete: need to check further opcode bits.
+ (dtable-entry-make index 'insn (car slot)))
+
+ ; Otherwise more than one insn maps to this value and we need to look at
+ ; further opcode bits.
+ (else
+ (logit 3 "Building subtable at index " (number->string index)
+ ", decode-bitsize = " (number->string decode-bitsize)
+ ", indices used thus far:"
+ (string-map (lambda (i) (string-append " " (number->string i)))
+ (apply append (map car index-list)))
+ "\n")
+
+ (let ((bitnums (decode-get-best-bits slot
+ (apply append (map car index-list))
+ startbit 4
+ decode-bitsize lsb0?)))
+
+ ; If bitnums is nil, either there is an ambiguity or we need to read
+ ; more of the instruction in order to distinguish insns in SLOT.
+ (if (and (null? bitnums)
+ (< startbit (apply min (map insn-length slot))))
+ (begin
+ ; We might be able to resolve the ambiguity by reading more bits.
+ ; We know from the < test that there are, indeed, more bits to
+ ; be read.
+ (set! startbit (+ startbit decode-bitsize))
+ ; FIXME: The calculation of the new decode-bitsize will
+ ; undoubtedly need refinement.
+ (set! decode-bitsize
+ (min decode-bitsize
+ (- (apply min (map insn-length slot))
+ startbit)))
+ (set! bitnums (decode-get-best-bits slot
+ ;nil ; FIXME: what to put here?
+ (apply append (map car index-list))
+ startbit 4
+ decode-bitsize lsb0?))))
+
+ ; If bitnums is still nil there is an ambiguity.
+ (if (null? bitnums)
+
+ (begin
+ ; If all insns are marked as DECODE-SPLIT, don't warn.
+ (if (not (all-true? (map (lambda (insn)
+ (obj-has-attr? insn 'DECODE-SPLIT))
+ slot)))
+ (message "WARNING: Decoder ambiguity detected: "
+ (string-drop1 ; drop leading comma
+ (string-map (lambda (insn)
+ (string-append ", " (obj:name insn)))
+ slot))
+ "\n"))
+ ; Things aren't entirely hopeless. See if any ifield-assertion
+ ; specs are present.
+ ; FIXME: For now we assume that if they all have an
+ ; ifield-assertion spec, then there is no ambiguity (it's left
+ ; to the programmer to get it right). This can be made more
+ ; clever later.
+ ; FIXME: May need to back up startbit if we've tried to read
+ ; more of the instruction.
+ (let ((assertions (map insn-ifield-assertion slot)))
+ (if (not (all-true? assertions))
+ (begin
+ ; Save arguments for debugging purposes.
+ (set! -build-decode-table-entry-args
+ (list insn-vec startbit decode-bitsize index index-list lsb0? invalid-insn))
+ (error "Unable to resolve ambiguity (maybe need some ifield-assertion specs?)")))
+ ; FIXME: Punt on even simple cleverness for now.
+ (let ((exprtable-entries
+ (exprtable-sort (map exprtable-entry-make
+ slot
+ assertions))))
+ (dtable-entry-make index 'expr
+ (exprtable-make
+ (-gen-exprtable-name exprtable-entries)
+ exprtable-entries)))))
+
+ ; There is no ambiguity so generate the subtable.
+ ; Need to build `subtable' separately because we
+ ; may be appending to -decode-subtables recursively.
+ (let* ((insn-vec (-build-slots slot bitnums lsb0?))
+ (subtable
+ (-build-decode-table-guts insn-vec bitnums startbit
+ decode-bitsize index-list lsb0?
+ invalid-insn)))
+ (dtable-entry-make index 'table
+ (subdtable-add subtable
+ (-gen-decode-table-name "" index-list)))))))
+ )
+ )
+)
+
+; Given vector of insn slots, generate the guts of the decode table, recorded
+; as a list of 3 elements: bitnums, decode-bitsize, and list of entries.
+; Bitnums is recorded with the guts so that tables whose contents are
+; identical but are accessed by different bitnums are treated as separate in
+; -decode-subtables. Not sure this will ever happen, but play it safe.
+;
+; BITNUMS is the list of bit numbers used to build the slot table.
+; STARTBIT is the bit offset of the instruction value that C variable `insn'
+; holds (note that this is independent of LSB0?).
+; For example, it is initially zero. If DECODE-BITSIZE is 16 and after
+; scanning the first fetched piece of the instruction, more decoding is
+; needed, another piece will be fetched and STARTBIT will then be 16.
+; DECODE-BITSIZE is the number of bits of the insn that `insn' holds.
+; INDEX-LIST is a list of pairs: list of bitnums, table entry number.
+; Decode tables consist of entries of two types: actual insns and
+; pointers to other tables.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; INVALID-INSN is an <insn> object representing invalid insns.
+
+(define (-build-decode-table-guts insn-vec bitnums startbit decode-bitsize index-list lsb0? invalid-insn)
+ (logit 2 "Processing decoder for bits"
+ (numbers->string bitnums " ")
+ " ...\n")
+
+ (dtable-guts-make
+ bitnums startbit decode-bitsize
+ (map (lambda (index)
+ (-build-decode-table-entry insn-vec startbit decode-bitsize index
+ (cons (cons bitnums index)
+ index-list)
+ lsb0? invalid-insn))
+ (iota (vector-length insn-vec))))
+)
+
+; Entry point.
+; Return a table that efficiently decodes INSN-LIST.
+; BITNUMS is the set of bits to initially key off of.
+; DECODE-BITSIZE is the number of bits of the instruction that `insn' holds.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; INVALID-INSN is an <insn> object representing the `invalid' insn (for
+; instructions values that don't decode to any entry in INSN-LIST).
+
+(define (decode-build-table insn-list bitnums decode-bitsize lsb0? invalid-insn)
+ ; Initialize the list of subtables computed.
+ (set! -decode-subtables nil)
+
+ ; ??? Another way to handle simple forms of ifield-assertions (like those
+ ; created by insn specialization) is to record a copy of the insn for each
+ ; possible value of the ifield and modify its ifield list with the ifield's
+ ; value. This would then let the decoder table builder handle it normally.
+ ; I wouldn't create N insns, but would rather create an intermediary record
+ ; that recorded the necessary bits (insn, ifield-list, remaining
+ ; ifield-assertions).
+
+ (let ((insn-vec (-build-slots insn-list bitnums lsb0?)))
+ (let ((table-guts (-build-decode-table-guts insn-vec bitnums
+ 0 decode-bitsize
+ nil lsb0?
+ invalid-insn)))
+ table-guts))
+)
diff --git a/cgen/desc-cpu.scm b/cgen/desc-cpu.scm
new file mode 100644
index 00000000000..1e3799c94df
--- /dev/null
+++ b/cgen/desc-cpu.scm
@@ -0,0 +1,954 @@
+; Generate .c/.h versions of main elements of cpu description file.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; ISA support code.
+
+(define (-gen-isa-table-defns)
+ (logit 2 "Generating isa table defns ...\n")
+
+ (string-list
+ "\
+/* Instruction set variants. */
+
+static const CGEN_ISA @arch@_cgen_isa_table[] = {
+"
+ (string-list-map (lambda (isa)
+ (gen-obj-sanitize
+ isa
+ (string-append " { "
+ "\"" (obj:name isa) "\", "
+ (number->string
+ (isa-default-insn-bitsize isa))
+ ", "
+ (number->string
+ (isa-base-insn-bitsize isa))
+ ", "
+ (number->string
+ (isa-min-insn-bitsize isa))
+ ", "
+ (number->string
+ (isa-max-insn-bitsize isa))
+ " },\n")))
+ (current-isa-list))
+ "\
+ { 0, 0, 0, 0, 0 }
+};
+\n"
+ )
+)
+
+; Mach support code.
+
+; Return C code to describe the various cpu variants.
+; Currently this is quite simple, the various cpu names and their mach numbers
+; are recorded in a "keyword" table.
+; ??? No longer used as there is the mach attribute.
+;
+;(set! mach-table (make <keyword> 'mach "machine list"
+; (make <attr-list> "" nil) ; FIXME: sanitization?
+; (map (lambda (elm) (list (obj:name elm) (mach-number elm)))
+; (current-mach-list))))
+
+(define (-gen-mach-table-decls)
+ (logit 2 "Generating machine table decls ...\n")
+ "" ; (gen-decl mach-table)
+)
+
+(define (-gen-mach-table-defns)
+ (logit 2 "Generating machine table defns ...\n")
+
+ (string-list
+ "\
+/* Machine variants. */
+
+static const CGEN_MACH @arch@_cgen_mach_table[] = {
+"
+ (string-list-map (lambda (mach)
+ (gen-obj-sanitize
+ mach
+ (string-append " { "
+ "\"" (obj:name mach) "\", "
+ "\"" (mach-bfd-name mach) "\", "
+ (mach-enum mach)
+ " },\n")))
+ (current-mach-list))
+ "\
+ { 0, 0, 0 }
+};
+\n"
+ )
+)
+
+; Attribute support code.
+
+; Return C code to describe the various attributes.
+
+(define (-gen-attr-table-decls)
+ (logit 2 "Generating attribute table decls ...\n")
+ (string-append
+ "/* Attributes. */\n"
+ "extern const CGEN_ATTR_TABLE @arch@_cgen_hardware_attr_table[];\n"
+ "extern const CGEN_ATTR_TABLE @arch@_cgen_ifield_attr_table[];\n"
+ "extern const CGEN_ATTR_TABLE @arch@_cgen_operand_attr_table[];\n"
+ "extern const CGEN_ATTR_TABLE @arch@_cgen_insn_attr_table[];\n"
+ "\n"
+ )
+)
+
+; Alternative GEN-MASK argument to gen-bool-attrs.
+; This uses the `A' macro to abbreviate the attribute definition.
+
+(define (gen-A-attr-mask prefix name)
+ (string-append "A(" (string-upcase (gen-c-symbol name)) ")")
+)
+
+; Instruction fields support code.
+
+; Return C code to declare various ifield bits.
+
+(define (gen-ifld-decls)
+ (logit 2 "Generating instruction field decls ...\n")
+ (string-list
+ "/* Ifield support. */\n\n"
+ "extern const struct cgen_ifld @arch@_cgen_ifld_table[];\n\n"
+ "/* Ifield attribute indices. */\n\n"
+ (gen-attr-enum-decl "cgen_ifld" (current-ifld-attr-list))
+ (gen-enum-decl 'ifield_type "@arch@ ifield types"
+ "@ARCH@_"
+ (append (gen-obj-list-enums (non-derived-ifields (current-ifld-list)))
+ '((f-max))))
+ "#define MAX_IFLD ((int) @ARCH@_F_MAX)\n\n"
+ )
+)
+
+; Return C code to define the instruction field table,
+; and any other ifield related definitions.
+
+(define (gen-ifld-defns)
+ (logit 2 "Generating ifield table ...\n")
+ (let* ((ifld-list (find (lambda (f) (not (has-attr? f 'VIRTUAL)))
+ (non-derived-ifields (current-ifld-list))))
+ (all-attrs (current-ifld-attr-list))
+ (num-non-bools (attr-count-non-bools all-attrs)))
+ (string-list
+ "\
+/* The instruction field table. */
+
+#define A(a) (1 << CONCAT2 (CGEN_IFLD_,a))
+
+const CGEN_IFLD @arch@_cgen_ifld_table[] =
+{
+"
+ (string-list-map
+ (lambda (ifld)
+ (gen-obj-sanitize ifld
+ (string-append
+ " { "
+ (ifld-enum ifld) ", "
+ "\"" (obj:name ifld) "\", "
+ (number->string (ifld-word-offset ifld)) ", "
+ (number->string (ifld-word-length ifld)) ", "
+ (number->string (ifld-start ifld #f)) ", "
+ (number->string (ifld-length ifld)) ", "
+ (gen-obj-attr-defn 'ifld ifld all-attrs
+ num-non-bools gen-A-attr-mask)
+ " },\n")))
+ ifld-list)
+ "\
+ { 0, 0, 0, 0, 0, 0, {0, {0}} }
+};
+
+#undef A
+
+"
+ ))
+)
+
+; Hardware support.
+
+; Return C code to declare the various hardware bits
+; that can be (or must be) defined before including opcode/cgen.h.
+
+(define (gen-hw-decls)
+ (logit 2 "Generating hardware decls ...\n")
+ (string-list
+ "/* Hardware attribute indices. */\n\n"
+ (gen-attr-enum-decl "cgen_hw" (current-hw-attr-list))
+ (gen-enum-decl 'cgen_hw_type "@arch@ hardware types"
+ "HW_" ; FIXME: @ARCH@_
+ (append (nub (map (lambda (hw)
+ (cons (hw-sem-name hw)
+ (cons '-
+ (atlist-attrs
+ (obj-atlist hw)))))
+ (current-hw-list))
+ (lambda (elm) (car elm)))
+ '((max))))
+ "#define MAX_HW ((int) HW_MAX)\n\n"
+ )
+)
+
+; Return declarations of variables tables used by HW.
+
+(define (-gen-hw-decl hw)
+ (string-append
+ (if (and (hw-indices hw)
+ ; ??? Commented out as opcode changes are needed
+ ) ; (not (obj-has-attr? (hw-indices hw) 'PRIVATE)))
+ (gen-decl (hw-indices hw))
+ "")
+ (if (and (hw-values hw)
+ ; ??? Commented out as opcode changes are needed
+ ) ; (not (obj-has-attr? (hw-values hw) 'PRIVATE)))
+ (gen-decl (hw-values hw))
+ "")
+ )
+)
+
+; Return C code to declare the various hardware bits
+; that must be defined after including opcode/cgen.h.
+
+(define (gen-hw-table-decls)
+ (logit 2 "Generating hardware table decls ...\n")
+ (string-list
+ "/* Hardware decls. */\n\n"
+ (string-map -gen-hw-decl (current-hw-list))
+ "\n"
+ )
+)
+
+; Return definitions of variables tables used by HW.
+; Only do this for `PRIVATE' elements. Public ones are emitted elsewhere.
+
+(define (-gen-hw-defn hw)
+ (string-append
+ (if (and (hw-indices hw)
+ (obj-has-attr? (hw-indices hw) 'PRIVATE))
+ (gen-defn (hw-indices hw))
+ "")
+ (if (and (hw-values hw)
+ (obj-has-attr? (hw-values hw) 'PRIVATE))
+ (gen-defn (hw-values hw))
+ "")
+ )
+)
+
+; Generate the tables for the various hardware bits (register names, etc.).
+; A table is generated for each element, and then another table is generated
+; which collects them all together.
+; Uses include looking up a particular register set so that a new reg
+; can be added to it [at runtime].
+
+(define (gen-hw-table-defns)
+ (logit 2 "Generating hardware table ...\n")
+ (let* ((all-attrs (current-hw-attr-list))
+ (num-non-bools (attr-count-non-bools all-attrs)))
+ (string-list
+ (string-list-map gen-defn (current-kw-list))
+ (string-list-map -gen-hw-defn (current-hw-list))
+ "
+
+/* The hardware table. */
+
+#define A(a) (1 << CONCAT2 (CGEN_HW_,a))
+
+const CGEN_HW_ENTRY @arch@_cgen_hw_table[] =
+{
+"
+ (string-list-map
+ (lambda (hw)
+ (gen-obj-sanitize hw
+ (string-list
+ " { "
+ "\"" (obj:name hw) "\", "
+ (hw-enum hw) ", "
+ ; ??? No element currently requires both indices and
+ ; values specs so we only output the needed one.
+ (or (and (hw-indices hw)
+ (send (hw-indices hw) 'gen-table-entry))
+ (and (hw-values hw)
+ (send (hw-values hw) 'gen-table-entry))
+ "CGEN_ASM_NONE, 0, ")
+ (gen-obj-attr-defn 'hw hw all-attrs
+ num-non-bools gen-A-attr-mask)
+ " },\n")))
+ (current-hw-list))
+ "\
+ { 0, 0, CGEN_ASM_NONE, 0, {0, {0}} }
+};
+
+#undef A
+
+"
+ ))
+)
+
+; Utilities of cgen-opc.h.
+
+; Return #define's of several constants.
+; FIXME: Some of these to be moved into table of structs, one per cpu family.
+
+(define (-gen-hash-defines)
+ (logit 2 "Generating #define's ...\n")
+ (string-list
+ "#define CGEN_ARCH @arch@\n\n"
+ "/* Given symbol S, return @arch@_cgen_<S>. */\n"
+ "#define CGEN_SYM(s) CONCAT3 (@arch@,_cgen_,s)\n\n"
+ "/* Selected cpu families. */\n"
+ ; FIXME: Move to sim's arch.h.
+ (string-map (lambda (cpu)
+ (gen-obj-sanitize cpu
+ (string-append "#define HAVE_CPU_"
+ (string-upcase (gen-sym cpu))
+ "\n")))
+ (current-cpu-list))
+ "\n"
+ "#define CGEN_INSN_LSB0_P " (if (current-arch-insn-lsb0?) "1" "0")
+ "\n\n"
+ "/* Minimum size of any insn (in bytes). */\n"
+ "#define CGEN_MIN_INSN_SIZE "
+ (number->string (bits->bytes
+ (apply min (map isa-min-insn-bitsize (current-isa-list)))))
+ "\n\n"
+ "/* Maximum size of any insn (in bytes). */\n"
+ "#define CGEN_MAX_INSN_SIZE "
+ (number->string (bits->bytes
+ (apply max (map isa-max-insn-bitsize (current-isa-list)))))
+ "\n\n"
+ ; This tells the assembler/disassembler whether or not it can use an int to
+ ; record insns, which is faster. Since this controls the typedef of the
+ ; insn buffer, only enable this if all isas support it.
+ "#define CGEN_INT_INSN_P "
+ (if (all-true? (map isa-integral-insn? (current-isa-list))) "1" "0")
+ "\n"
+ "\n"
+ "/* Maximum nymber of syntax bytes in an instruction. */\n"
+ "#define CGEN_ACTUAL_MAX_SYNTAX_BYTES "
+ ; The +2 account for the leading "MNEM" and trailing 0.
+ (number->string (+ 2 (apply max (map (lambda (insn)
+ (length (syntax-break-out (insn-syntax insn))))
+ (current-insn-list)))))
+ "\n"
+ "\n"
+ "/* CGEN_MNEMONIC_OPERANDS is defined if mnemonics have operands.\n"
+ " e.g. In \"b,a foo\" the \",a\" is an operand. If mnemonics have operands\n"
+ " we can't hash on everything up to the space. */\n"
+ (if strip-mnemonic?
+ "/*#define CGEN_MNEMONIC_OPERANDS*/\n"
+ "#define CGEN_MNEMONIC_OPERANDS\n")
+ "\n"
+ ; "/* Maximum number of operands any insn or macro-insn has. */\n"
+ ; FIXME: Should compute.
+ ; "#define CGEN_MAX_INSN_OPERANDS 16\n"
+ ; "\n"
+ "/* Maximum number of fields in an instruction. */\n"
+ "#define CGEN_ACTUAL_MAX_IFMT_OPERANDS "
+ (number->string (apply max (map (lambda (f) (length (ifmt-ifields f)))
+ (current-ifmt-list))))
+ "\n\n"
+ )
+)
+
+; Operand support.
+
+; Return C code to declare various operand bits.
+
+(define (gen-operand-decls)
+ (logit 2 "Generating operand decls ...\n")
+ (string-list
+ "/* Operand attribute indices. */\n\n"
+ (gen-attr-enum-decl "cgen_operand" (current-op-attr-list))
+ (gen-enum-decl 'cgen_operand_type "@arch@ operand types"
+ "@ARCH@_OPERAND_"
+ (nub (append (gen-obj-list-enums (current-op-list))
+ '((max)))
+ car))
+ "/* Number of operands types. */\n"
+ "#define MAX_OPERANDS ((int) @ARCH@_OPERAND_MAX)\n\n"
+ "/* Maximum number of operands referenced by any insn. */\n"
+ "#define MAX_OPERAND_INSTANCES "
+ (number->string (max-operand-instances))
+ "\n\n"
+ )
+)
+
+; Generate C code to define the operand table.
+
+(define (gen-operand-table)
+ (logit 2 "Generating operand table ...\n")
+ (let* ((all-attrs (current-op-attr-list))
+ (num-non-bools (attr-count-non-bools all-attrs)))
+ (string-list
+ "\
+/* The operand table. */
+
+#define A(a) (1 << CONCAT2 (CGEN_OPERAND_,a))
+#define OPERAND(op) CONCAT2 (@ARCH@_OPERAND_,op)
+
+const CGEN_OPERAND @arch@_cgen_operand_table[] =
+{
+"
+ (string-list-map
+ (lambda (op)
+ (gen-obj-sanitize op
+ (string-append
+ "/* " (obj:name op) ": " (obj:comment op) " */\n"
+ (if (or (derived-operand? op)
+ (anyof-operand? op))
+ ""
+ (string-append
+ " { "
+ "\"" (obj:name op) "\", "
+ (op-enum op) ", "
+ (hw-enum (op:hw-name op)) ", "
+ (number->string (op:start op)) ", "
+ (number->string (op:length op)) ",\n"
+ " "
+ (gen-obj-attr-defn 'operand op all-attrs
+ num-non-bools gen-A-attr-mask)
+ " },\n"
+ )))))
+ (current-op-list))
+ "\
+ { 0, 0, 0, 0, 0, {0, {0}} }
+};
+
+#undef A
+
+"
+ )
+ )
+)
+
+; Instruction table support.
+
+; Return C code to declare various insn bits.
+
+(define (gen-insn-decls)
+ (logit 2 "Generating instruction decls ...\n")
+ (string-list
+ "/* Insn attribute indices. */\n\n"
+ (gen-attr-enum-decl "cgen_insn" (current-insn-attr-list))
+ )
+)
+
+; Generate an insn table entry for INSN.
+; ALL-ATTRS is a list of all instruction attributes.
+; NUM-NON-BOOLS is the number of non-boolean insn attributes.
+
+(define (gen-insn-table-entry insn all-attrs num-non-bools)
+ (gen-obj-sanitize
+ insn
+ (string-list
+ "/* " (insn-syntax insn) " */\n"
+ " {\n"
+ " "
+ (if (has-attr? insn 'ALIAS) "-1" (insn-enum insn)) ", "
+ "\"" (obj:name insn) "\", "
+ "\"" (insn-mnemonic insn) "\", "
+ ;(if (has-attr? insn 'ALIAS) "0" (number->string (insn-length insn))) ",\n"
+ (number->string (insn-length insn)) ",\n"
+; ??? There is currently a problem with embedded newlines, and this might
+; best be put in another file [the table is already pretty big].
+; Might also wish to output bytecodes instead.
+; " "
+; (if (insn-semantics insn)
+; (string-append "\""
+; (with-output-to-string
+; ; ??? Should we do macro expansion here?
+; (lambda () (display (insn-semantics insn))))
+; "\"")
+; "0")
+; ",\n"
+ ; ??? Might wish to output the raw format spec here instead
+ ; (either as plain text or bytecodes).
+ ; Values could be lazily computed and cached.
+ " "
+ (gen-obj-attr-defn 'insn insn all-attrs num-non-bools gen-A-attr-mask)
+ "\n },\n"))
+)
+
+; Generate insn table.
+
+(define (gen-insn-table)
+ (logit 2 "Generating instruction table ...\n")
+ (let* ((all-attrs (current-insn-attr-list))
+ (num-non-bools (attr-count-non-bools all-attrs)))
+ (string-write
+ "\
+#define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
+#define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
+
+/* The instruction table. */
+
+static const CGEN_IBASE @arch@_cgen_insn_table[MAX_INSNS] =
+{
+ /* Special null first entry.
+ A `num' value of zero is thus invalid.
+ Also, the special `invalid' insn resides here. */
+ { 0, 0, 0, 0, {0, {0}} },\n"
+
+ (lambda ()
+ (string-write-map (lambda (insn)
+ (logit 3 "Generating insn table entry for " (obj:name insn) " ...\n")
+ (gen-insn-table-entry insn all-attrs num-non-bools))
+ (non-multi-insns (current-insn-list))))
+
+ "\
+};
+
+#undef A
+#undef MNEM
+#undef OP
+
+"
+ )
+ )
+)
+
+; Cpu table handling support.
+;
+; ??? A lot of this can live in a machine independent file, but there's
+; currently no place to put this file (there's no libcgen). libopcodes is the
+; wrong place as some simulator ports use this but they don't use libopcodes.
+
+; Return C routines to open/close a cpu description table.
+; This is defined here and not in cgen-opc.in because it refers to
+; CGEN_{ASM,DIS}_HASH and insn_table/macro_insn_table which is defined
+; earlier in the file. ??? Things can certainly be rearranged though
+; and opcodes/cgen.sh modified to insert the generated part into the middle
+; of the file like is done for assembler/disassembler support.
+
+(define (-gen-cpu-open)
+ (string-append
+ "\
+/* Subroutine of @arch@_cgen_cpu_open to look up a mach via its bfd name. */
+
+static const CGEN_MACH *
+lookup_mach_via_bfd_name (table, name)
+ const CGEN_MACH *table;
+ const char *name;
+{
+ while (table->name)
+ {
+ if (strcmp (name, table->bfd_name) == 0)
+ return table;
+ ++table;
+ }
+ abort ();
+}
+
+/* Subroutine of @arch@_cgen_cpu_open to build the hardware table. */
+
+static void
+build_hw_table (cd)
+ CGEN_CPU_TABLE *cd;
+{
+ int i;
+ int machs = cd->machs;
+ const CGEN_HW_ENTRY *init = & @arch@_cgen_hw_table[0];
+ /* MAX_HW is only an upper bound on the number of selected entries.
+ However each entry is indexed by it's enum so there can be holes in
+ the table. */
+ const CGEN_HW_ENTRY **selected =
+ (const CGEN_HW_ENTRY **) xmalloc (MAX_HW * sizeof (CGEN_HW_ENTRY *));
+
+ cd->hw_table.init_entries = init;
+ cd->hw_table.entry_size = sizeof (CGEN_HW_ENTRY);
+ memset (selected, 0, MAX_HW * sizeof (CGEN_HW_ENTRY *));
+ /* ??? For now we just use machs to determine which ones we want. */
+ for (i = 0; init[i].name != NULL; ++i)
+ if (CGEN_HW_ATTR_VALUE (&init[i], CGEN_HW_MACH)
+ & machs)
+ selected[init[i].type] = &init[i];
+ cd->hw_table.entries = selected;
+ cd->hw_table.num_entries = MAX_HW;
+}
+
+/* Subroutine of @arch@_cgen_cpu_open to build the hardware table. */
+
+static void
+build_ifield_table (cd)
+ CGEN_CPU_TABLE *cd;
+{
+ cd->ifld_table = & @arch@_cgen_ifld_table[0];
+}
+
+/* Subroutine of @arch@_cgen_cpu_open to build the hardware table. */
+
+static void
+build_operand_table (cd)
+ CGEN_CPU_TABLE *cd;
+{
+ int i;
+ int machs = cd->machs;
+ const CGEN_OPERAND *init = & @arch@_cgen_operand_table[0];
+ /* MAX_OPERANDS is only an upper bound on the number of selected entries.
+ However each entry is indexed by it's enum so there can be holes in
+ the table. */
+ const CGEN_OPERAND **selected =
+ (const CGEN_OPERAND **) xmalloc (MAX_OPERANDS * sizeof (CGEN_OPERAND *));
+
+ cd->operand_table.init_entries = init;
+ cd->operand_table.entry_size = sizeof (CGEN_OPERAND);
+ memset (selected, 0, MAX_OPERANDS * sizeof (CGEN_OPERAND *));
+ /* ??? For now we just use mach to determine which ones we want. */
+ for (i = 0; init[i].name != NULL; ++i)
+ if (CGEN_OPERAND_ATTR_VALUE (&init[i], CGEN_OPERAND_MACH)
+ & machs)
+ selected[init[i].type] = &init[i];
+ cd->operand_table.entries = selected;
+ cd->operand_table.num_entries = MAX_OPERANDS;
+}
+
+/* Subroutine of @arch@_cgen_cpu_open to build the hardware table.
+ ??? This could leave out insns not supported by the specified mach/isa,
+ but that would cause errors like \"foo only supported by bar\" to become
+ \"unknown insn\", so for now we include all insns and require the app to
+ do the checking later.
+ ??? On the other hand, parsing of such insns may require their hardware or
+ operand elements to be in the table [which they mightn't be]. */
+
+static void
+build_insn_table (cd)
+ CGEN_CPU_TABLE *cd;
+{
+ int i;
+ const CGEN_IBASE *ib = & @arch@_cgen_insn_table[0];
+ CGEN_INSN *insns = (CGEN_INSN *) xmalloc (MAX_INSNS * sizeof (CGEN_INSN));
+
+ memset (insns, 0, MAX_INSNS * sizeof (CGEN_INSN));
+ for (i = 0; i < MAX_INSNS; ++i)
+ insns[i].base = &ib[i];
+ cd->insn_table.init_entries = insns;
+ cd->insn_table.entry_size = sizeof (CGEN_IBASE);
+ cd->insn_table.num_init_entries = MAX_INSNS;
+}
+
+/* Subroutine of @arch@_cgen_cpu_open to rebuild the tables. */
+
+static void
+@arch@_cgen_rebuild_tables (cd)
+ CGEN_CPU_TABLE *cd;
+{
+ int i,n_isas;
+ unsigned int isas = cd->isas;
+#if 0
+ unsigned int machs = cd->machs;
+#endif
+
+ cd->int_insn_p = CGEN_INT_INSN_P;
+
+ /* Data derived from the isa spec. */
+#define UNSET (CGEN_SIZE_UNKNOWN + 1)
+ cd->default_insn_bitsize = UNSET;
+ cd->base_insn_bitsize = UNSET;
+ cd->min_insn_bitsize = 65535; /* some ridiculously big number */
+ cd->max_insn_bitsize = 0;
+ for (i = 0; i < MAX_ISAS; ++i)
+ if (((1 << i) & isas) != 0)
+ {
+ const CGEN_ISA *isa = & @arch@_cgen_isa_table[i];
+
+ /* Default insn sizes of all selected isas must be equal or we set
+ the result to 0, meaning \"unknown\". */
+ if (cd->default_insn_bitsize == UNSET)
+ cd->default_insn_bitsize = isa->default_insn_bitsize;
+ else if (isa->default_insn_bitsize == cd->default_insn_bitsize)
+ ; /* this is ok */
+ else
+ cd->default_insn_bitsize = CGEN_SIZE_UNKNOWN;
+
+ /* Base insn sizes of all selected isas must be equal or we set
+ the result to 0, meaning \"unknown\". */
+ if (cd->base_insn_bitsize == UNSET)
+ cd->base_insn_bitsize = isa->base_insn_bitsize;
+ else if (isa->base_insn_bitsize == cd->base_insn_bitsize)
+ ; /* this is ok */
+ else
+ cd->base_insn_bitsize = CGEN_SIZE_UNKNOWN;
+
+ /* Set min,max insn sizes. */
+ if (isa->min_insn_bitsize < cd->min_insn_bitsize)
+ cd->min_insn_bitsize = isa->min_insn_bitsize;
+ if (isa->max_insn_bitsize > cd->max_insn_bitsize)
+ cd->max_insn_bitsize = isa->max_insn_bitsize;
+
+ ++n_isas;
+ }
+
+#if 0 /* Does nothing?? */
+ /* Data derived from the mach spec. */
+ for (i = 0; i < MAX_MACHS; ++i)
+ if (((1 << i) & machs) != 0)
+ {
+ const CGEN_MACH *mach = & @arch@_cgen_mach_table[i];
+
+ ++n_machs;
+ }
+#endif
+
+ /* Determine which hw elements are used by MACH. */
+ build_hw_table (cd);
+
+ /* Build the ifield table. */
+ build_ifield_table (cd);
+
+ /* Determine which operands are used by MACH/ISA. */
+ build_operand_table (cd);
+
+ /* Build the instruction table. */
+ build_insn_table (cd);
+}
+
+/* Initialize a cpu table and return a descriptor.
+ It's much like opening a file, and must be the first function called.
+ The arguments are a set of (type/value) pairs, terminated with
+ CGEN_CPU_OPEN_END.
+
+ Currently supported values:
+ CGEN_CPU_OPEN_ISAS: bitmap of values in enum isa_attr
+ CGEN_CPU_OPEN_MACHS: bitmap of values in enum mach_attr
+ CGEN_CPU_OPEN_BFDMACH: specify 1 mach using bfd name
+ CGEN_CPU_OPEN_ENDIAN: specify endian choice
+ CGEN_CPU_OPEN_END: terminates arguments
+
+ ??? Simultaneous multiple isas might not make sense, but it's not (yet)
+ precluded.
+
+ ??? We only support ISO C stdargs here, not K&R.
+ Laziness, plus experiment to see if anything requires K&R - eventually
+ K&R will no longer be supported - e.g. GDB is currently trying this. */
+
+CGEN_CPU_DESC
+@arch@_cgen_cpu_open (enum cgen_cpu_open_arg arg_type, ...)
+{
+ CGEN_CPU_TABLE *cd = (CGEN_CPU_TABLE *) xmalloc (sizeof (CGEN_CPU_TABLE));
+ static int init_p;
+ unsigned int isas = 0; /* 0 = \"unspecified\" */
+ unsigned int machs = 0; /* 0 = \"unspecified\" */
+ enum cgen_endian endian = CGEN_ENDIAN_UNKNOWN;
+ va_list ap;
+
+ if (! init_p)
+ {
+ init_tables ();
+ init_p = 1;
+ }
+
+ memset (cd, 0, sizeof (*cd));
+
+ va_start (ap, arg_type);
+ while (arg_type != CGEN_CPU_OPEN_END)
+ {
+ switch (arg_type)
+ {
+ case CGEN_CPU_OPEN_ISAS :
+ isas = va_arg (ap, unsigned int);
+ break;
+ case CGEN_CPU_OPEN_MACHS :
+ machs = va_arg (ap, unsigned int);
+ break;
+ case CGEN_CPU_OPEN_BFDMACH :
+ {
+ const char *name = va_arg (ap, const char *);
+ const CGEN_MACH *mach =
+ lookup_mach_via_bfd_name (@arch@_cgen_mach_table, name);
+
+ machs |= mach->num << 1;
+ break;
+ }
+ case CGEN_CPU_OPEN_ENDIAN :
+ endian = va_arg (ap, enum cgen_endian);
+ break;
+ default :
+ fprintf (stderr, \"@arch@_cgen_cpu_open: unsupported argument `%d'\\n\",
+ arg_type);
+ abort (); /* ??? return NULL? */
+ }
+ arg_type = va_arg (ap, enum cgen_cpu_open_arg);
+ }
+ va_end (ap);
+
+ /* mach unspecified means \"all\" */
+ if (machs == 0)
+ machs = (1 << MAX_MACHS) - 1;
+ /* base mach is always selected */
+ machs |= 1;
+ /* isa unspecified means \"all\" */
+ if (isas == 0)
+ isas = (1 << MAX_ISAS) - 1;
+ if (endian == CGEN_ENDIAN_UNKNOWN)
+ {
+ /* ??? If target has only one, could have a default. */
+ fprintf (stderr, \"@arch@_cgen_cpu_open: no endianness specified\\n\");
+ abort ();
+ }
+
+ cd->isas = isas;
+ cd->machs = machs;
+ cd->endian = endian;
+ /* FIXME: for the sparc case we can determine insn-endianness statically.
+ The worry here is where both data and insn endian can be independently
+ chosen, in which case this function will need another argument.
+ Actually, will want to allow for more arguments in the future anyway. */
+ cd->insn_endian = endian;
+
+ /* Table (re)builder. */
+ cd->rebuild_tables = @arch@_cgen_rebuild_tables;
+ @arch@_cgen_rebuild_tables (cd);
+
+ /* Default to not allowing signed overflow. */
+ cd->signed_overflow_ok_p = 0;
+
+ return (CGEN_CPU_DESC) cd;
+}
+
+/* Cover fn to @arch@_cgen_cpu_open to handle the simple case of 1 isa, 1 mach.
+ MACH_NAME is the bfd name of the mach. */
+
+CGEN_CPU_DESC
+@arch@_cgen_cpu_open_1 (mach_name, endian)
+ const char *mach_name;
+ enum cgen_endian endian;
+{
+ return @arch@_cgen_cpu_open (CGEN_CPU_OPEN_BFDMACH, mach_name,
+ CGEN_CPU_OPEN_ENDIAN, endian,
+ CGEN_CPU_OPEN_END);
+}
+
+/* Close a cpu table.
+ ??? This can live in a machine independent file, but there's currently
+ no place to put this file (there's no libcgen). libopcodes is the wrong
+ place as some simulator ports use this but they don't use libopcodes. */
+
+void
+@arch@_cgen_cpu_close (cd)
+ CGEN_CPU_DESC cd;
+{
+ if (cd->insn_table.init_entries)
+ free ((CGEN_INSN *) cd->insn_table.init_entries);
+ if (cd->hw_table.entries)
+ free ((CGEN_HW_ENTRY *) cd->hw_table.entries);
+ free (cd);
+}
+
+")
+)
+
+; General initialization C code
+; Code is appended during processing.
+
+(define -cputab-init-code "")
+(define (cputab-add-init! code)
+ (set! -cputab-init-code (string-append -cputab-init-code code))
+)
+
+; Return the C code to define the various initialization functions.
+; This does not include assembler/disassembler specific stuff.
+; Generally, this function doesn't do anything.
+; It exists to allow a global-static-constructor kind of thing should
+; one ever be necessary.
+
+(define (gen-init-fns)
+ (logit 2 "Generating init fns ...\n")
+ (string-append
+ "\
+/* Initialize anything needed to be done once, before any cpu_open call. */
+
+static void
+init_tables ()
+{\n"
+ -cputab-init-code
+ "}\n\n"
+ )
+)
+
+; Top level C code generators
+
+; FIXME: Create enum objects for all the enums we explicitly declare here.
+; Then they'd be usable and we wouldn't have to special case them here.
+
+(define (cgen-desc.h)
+ (logit 1 "Generating " (current-arch-name) "-desc.h ...\n")
+ (string-write
+ (gen-copyright "CPU data header for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#ifndef @ARCH@_CPU_H
+#define @ARCH@_CPU_H
+
+"
+ -gen-hash-defines
+ ; This is defined in arch.h. It's not defined here as there is yet to
+ ; be a need for it in the assembler/disassembler.
+ ;(gen-enum-decl 'model_type "model types"
+ ; "MODEL_"
+ ; (append (map list (map obj:name (current-model-list))) '((max))))
+ ;"#define MAX_MODELS ((int) MODEL_MAX)\n\n"
+ "/* Enums. */\n\n"
+ (string-map gen-decl (current-enum-list))
+ "/* Attributes. */\n\n"
+ (string-map gen-decl (current-attr-list))
+ "/* Number of architecture variants. */\n"
+ ; If there is only 1 isa, leave out special handling. */
+ (if (= (length (current-isa-list)) 1)
+ "#define MAX_ISAS 1\n"
+ "#define MAX_ISAS ((int) ISA_MAX)\n")
+ "#define MAX_MACHS ((int) MACH_MAX)\n\n"
+ gen-ifld-decls
+ gen-hw-decls
+ gen-operand-decls
+ gen-insn-decls
+ "/* cgen.h uses things we just defined. */\n"
+ "#include \"opcode/cgen.h\"\n\n"
+ -gen-attr-table-decls
+ -gen-mach-table-decls
+ gen-hw-table-decls
+ "\n"
+ (lambda () (gen-extra-cpu.h srcdir (current-arch-name))) ; from <arch>.opc
+ "
+
+#endif /* @ARCH@_CPU_H */
+"
+ )
+)
+
+; This file contains the "top level" definitions of the cpu.
+; This includes various elements of the description file, expressed in C.
+;
+; ??? A lot of this file can go in a machine-independent file! However,
+; some simulators don't use the cgen opcodes support so there is currently
+; no place to put this file. To be revisited when we do have such a place.
+
+(define (cgen-desc.c)
+ (logit 1 "Generating " (current-arch-name) "-desc.c ...\n")
+ (string-write
+ (gen-copyright "CPU data for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#include \"sysdep.h\"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include \"ansidecl.h\"
+#include \"bfd.h\"
+#include \"symcat.h\"
+#include \"@prefix@-desc.h\"
+#include \"@prefix@-opc.h\"
+#include \"opintl.h\"
+#include \"libiberty.h\"
+\n"
+ (lambda () (gen-extra-cpu.c srcdir (current-arch-name))) ; from <arch>.opc
+ gen-attr-table-defns
+ -gen-isa-table-defns
+ -gen-mach-table-defns
+ gen-hw-table-defns
+ gen-ifld-defns
+ gen-operand-table
+ gen-insn-table
+ gen-init-fns
+ -gen-cpu-open
+ )
+)
diff --git a/cgen/desc.scm b/cgen/desc.scm
new file mode 100644
index 00000000000..d5ba7529b2e
--- /dev/null
+++ b/cgen/desc.scm
@@ -0,0 +1,238 @@
+; General cpu info generator support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+;
+; This file generates C versions of the more salient parts of the description
+; file. It's currently part of opcodes or simulator support,
+; and doesn't exist as its own "application" (i.e. user of cgen),
+; though that's not precluded.
+
+; strip-mnemonic?: If each mnemonic is constant, the insn table doesn't need
+; to record them in the syntax field as the mnemonic field also contains it.
+; Furthermore, the insn table can be hashed on complete mnemonic.
+; ??? Should live in <derived-arch-data> or some such.
+
+(define strip-mnemonic? #f)
+
+; Attribute support code.
+
+(define (gen-attr-table-defn type attr-list)
+ (string-append
+ "const CGEN_ATTR_TABLE "
+ "@arch@_cgen_" type "_attr_table[] =\n{\n"
+ (string-map (lambda (attr)
+ (gen-obj-sanitize
+ attr
+ (string-append " { "
+ "\""
+ (string-upcase (obj:name attr))
+ "\", "
+ (if (class-instance? <boolean-attribute> attr)
+ "&bool_attr[0], &bool_attr[0]"
+ (string-append "& " (gen-sym attr)
+ "_attr[0], & "
+ (gen-sym attr)
+ "_attr[0]"))
+ " },\n")))
+ attr-list)
+ " { 0, 0, 0 }\n"
+ "};\n\n")
+)
+
+(define (gen-attr-table-defns)
+ (logit 2 "Generating attribute table defns ...\n")
+ (string-append
+ "\
+/* Attributes. */
+
+static const CGEN_ATTR_ENTRY bool_attr[] =
+{
+ { \"#f\", 0 },
+ { \"#t\", 1 },
+ { 0, 0 }
+};
+
+"
+ ; Generate tables mapping names to values for all the non-boolean attrs.
+ (string-map gen-defn (current-attr-list))
+ ; Generate tables for each domain (ifld, insn, etc.) mapping attribute type
+ ; to index.
+ (gen-attr-table-defn "ifield" (current-ifld-attr-list))
+ (gen-attr-table-defn "hardware" (current-hw-attr-list))
+ (gen-attr-table-defn "operand" (current-op-attr-list))
+ (gen-attr-table-defn "insn" (current-insn-attr-list))
+ )
+)
+
+; HW-ASM is the base class for supporting hardware elements in the opcode table
+; (aka assembler/disassembler).
+
+; Return the C declaration.
+; It is up to a derived class to redefine this as necessary.
+
+(method-make! <hw-asm> 'gen-decl (lambda (self) ""))
+
+; Return the C definition.
+; It is up to a derived class to redefine this as necessary.
+
+(method-make! <hw-asm> 'gen-defn (lambda (self) ""))
+
+(method-make! <hw-asm> 'gen-ref (lambda (self) "0"))
+
+(method-make! <hw-asm> 'gen-init (lambda (self) ""))
+
+(method-make! <hw-asm> 'gen-table-entry (lambda (self) "CGEN_ASM_NONE, 0, "))
+
+; Prefix of global variables describing operand values.
+
+(define hw-asm-prefix "@arch@_cgen_opval_")
+
+; Emit a C reference to a value operand.
+; Usually the operand's details are stored in a struct so in the default
+; case return that struct (?correct?). The caller must add the "&" if desired.
+
+(define (gen-hw-asm-ref name)
+ (string-append hw-asm-prefix (gen-c-symbol name))
+)
+
+; Keyword support.
+
+; Keyword operands.
+; Return the C declaration of a keyword list.
+
+(method-make!
+ <keyword> 'gen-decl
+ (lambda (self)
+ (string-append
+ "extern CGEN_KEYWORD "
+ (gen-hw-asm-ref (elm-get self 'name))
+ ";\n"))
+)
+
+; Return the C definition of a keyword list.
+
+(method-make!
+ <keyword> 'gen-defn
+ (lambda (self)
+ (string-append
+ "static CGEN_KEYWORD_ENTRY "
+ (gen-hw-asm-ref (elm-get self 'name)) "_entries"
+ "[] =\n{\n"
+ (string-drop -2 ; Delete trailing ",\n" [don't want the ,]
+ (string-map (lambda (e)
+ (string-append
+ " { "
+ "\"" (car e) "\", " ; operand name
+ (if (string? (cadr e))
+ (cadr e)
+ (number->string (cadr e))) ; value
+ ", {0, {0}}, 0, 0"
+ " },\n"
+ ))
+ (elm-get self 'values)))
+ "\n};\n\n"
+ "CGEN_KEYWORD "
+ (gen-hw-asm-ref (elm-get self 'name))
+ " =\n{\n"
+ " & " (gen-hw-asm-ref (elm-get self 'name)) "_entries[0],\n"
+ " " (number->string (length (elm-get self 'values))) ",\n"
+ " 0, 0, 0, 0\n"
+ "};\n\n"
+ )
+ )
+)
+
+; Return a reference to a keyword table.
+
+(method-make!
+ <keyword> 'gen-ref
+ (lambda (self) (string-append "& " (gen-hw-asm-ref (elm-get self 'name))))
+)
+
+(method-make!
+ <keyword> 'gen-table-entry
+ (lambda (self)
+ (string-append "CGEN_ASM_KEYWORD, (PTR) " (send self 'gen-ref) ", "))
+)
+
+; Return the C code to initialize a keyword.
+; If the `hash' attr is present, the values are hashed. Currently this is
+; done by calling back to GAS to have it add the registers to its symbol table.
+; FIXME: Currently unused. Should be done either in the open routine or
+; lazily upon lookup.
+
+(method-make!
+ <keyword> 'gen-init
+ (lambda (self)
+ (cond ((has-attr? self 'HASH)
+ (string-append
+ " @arch@_cgen_asm_hash_keywords ("
+ (send self 'gen-ref)
+ ");\n"
+ ))
+ (else ""))
+ )
+)
+
+; Operand support.
+
+; Return a reference to the operand's attributes.
+
+(method-make!
+ <operand> 'gen-attr-ref
+ (lambda (self)
+ (string-append "& CGEN_OPERAND_ATTRS (CGEN_SYM (operand_table)) "
+ "[" (op-enum self) "]"))
+)
+
+; Name of C variable that is a pointer to the fields struct.
+
+(define ifields-var "fields")
+
+; Given FIELD, an `ifield' object, return an lvalue for the operand in
+; IFIELDS-VAR.
+
+(define (gen-operand-result-var field)
+ (string-append ifields-var "->" (gen-sym field))
+)
+
+; Basic description init,finish,analyzer support.
+
+; Return a boolean indicating if all insns have a constant mnemonic
+; (ie: no $'s in insn's name in `syntax' field).
+; If constant, one can build the assembler hash table using the entire
+; mnemonic.
+
+(define (constant-mnemonics?)
+ #f ; FIXME
+)
+
+; Initialize any "desc" specific things before loading the .cpu file.
+; N.B. Since "desc" is always a part of another application, that
+; application's init! routine must call this one.
+
+(define (desc-init!)
+ *UNSPECIFIED*
+)
+
+; Finish any "desc" specific things after loading the .cpu file.
+; This is separate from analyze-data! as cpu-load performs some
+; consistency checks in between.
+; N.B. Since "desc" is always a part of another application, that
+; application's finish! routine must call this one.
+
+(define (desc-finish!)
+ *UNSPECIFIED*
+)
+
+; Compute various needed globals and assign any computed fields of
+; the various objects. This is the standard routine that is called after
+; a .cpu file is loaded.
+; N.B. Since "desc" is always a part of another application, that
+; application's analyze! routine must call this one.
+
+(define (desc-analyze!)
+ (set! strip-mnemonic? (constant-mnemonics?))
+
+ *UNSPECIFIED*
+)
diff --git a/cgen/dev.scm b/cgen/dev.scm
new file mode 100644
index 00000000000..66d15624023
--- /dev/null
+++ b/cgen/dev.scm
@@ -0,0 +1,179 @@
+; CGEN Debugging support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; This file is loaded in during an interactive guile session to
+; develop and debug CGEN. The user visible procs are:
+;
+; (use-c)
+; (load-opc)
+; (load-sim)
+; (cload #:arch arch #:machs "mach-list" #:isas "isa-list" #:options "options")
+
+; First load fixup.scm to coerce guile into something we've been using.
+; Guile is always in flux.
+(load "fixup.scm")
+
+(define srcdir ".")
+
+; Utility to enable/disable compiled-in C code.
+
+(define (use-c) (set! CHECK-LOADED? #t))
+(define (no-c) (set! CHECK-LOADED? #f))
+
+; Also defined in read.scm, but we need it earlier.
+(define APPLICATION 'UNKNOWN)
+
+; Supply the path name and suffic for the .cpu file and delete the analyzer
+; arg from cpu-load to lessen the typing.
+(define (cload . args)
+ (let ((arch #f)
+ (keep-mach "all")
+ (keep-isa "all")
+ (options ""))
+
+ ; Doesn't check if (cadr args) exists or if #:arch was specified, but
+ ; this is a debugging tool!
+ (let loop ((args args))
+ (if (null? args)
+ #f ; done
+ (begin
+ (case (car args)
+ ((#:arch) (set! arch (cadr args)))
+ ((#:machs) (set! keep-mach (cadr args)))
+ ((#:isas) (set! keep-isa (cadr args)))
+ ((#:options) (set! options (cadr args)))
+ (else (error "unknown option:" (car args))))
+ (loop (cddr args)))))
+
+ (case APPLICATION
+ ((UNKNOWN) (error "application not loaded"))
+ ((DESC) (cpu-load (string-append arch ".cpu")
+ keep-mach keep-isa options
+ desc-init!
+ desc-finish!
+ desc-analyze!))
+ ((OPCODES) (cpu-load (string-append arch ".cpu")
+ keep-mach keep-isa options
+ opcodes-init!
+ opcodes-finish!
+ opcodes-analyze!))
+ ((GAS-TEST) (cpu-load (string-append arch ".cpu")
+ keep-mach keep-isa options
+ gas-test-init!
+ gas-test-finish!
+ gas-test-analyze!))
+ ((SIMULATOR) (cpu-load (string-append arch ".cpu")
+ keep-mach keep-isa options
+ sim-init!
+ sim-finish!
+ sim-analyze!))
+ ((SIM-TEST) (cpu-load (string-append arch ".cpu")
+ keep-mach keep-isa options
+ sim-test-init!
+ sim-test-finish!
+ sim-test-analyze!))
+ (else (error "unknown application:" APPLICATION))))
+)
+
+; Use the debugging evaluator.
+(if (not (defined? 'DEBUG-EVAL))
+ (define DEBUG-EVAL #t))
+
+; Tell maybe-load to always load the file.
+(if (not (defined? 'CHECK-LOADED?))
+ (define CHECK-LOADED? #f))
+
+(define (load-opc)
+ (load "read")
+ (load "desc")
+ (load "desc-cpu")
+ (load "opcodes")
+ (load "opc-asmdis")
+ (load "opc-ibld")
+ (load "opc-itab")
+ (load "opc-opinst")
+ (set! verbose-level 3)
+ (set! APPLICATION 'OPCODES)
+)
+
+(define (load-gtest)
+ (load-opc)
+ (load "gas-test")
+ (set! verbose-level 3)
+ (set! APPLICATION 'GAS-TEST)
+)
+
+
+(define (load-sim)
+ (load "read")
+ (load "desc")
+ (load "desc-cpu")
+ (load "utils-sim")
+ (load "sim")
+ (load "sim-arch")
+ (load "sim-cpu")
+ (load "sim-model")
+ (load "sim-decode")
+ (set! verbose-level 3)
+ (set! APPLICATION 'SIMULATOR)
+)
+
+(define (load-stest)
+ (load-opc)
+ (load "sim-test")
+ (set! verbose-level 3)
+ (set! APPLICATION 'SIM-TEST)
+)
+
+(display "
+First enable compiled in C code if desired.
+
+(use-c)
+
+Then choose the application via one of:
+
+(load-opc)
+(load-gtest)
+(load-sim)
+(load-stest)
+")
+
+(display "(load-sid)\n")
+
+(display "\
+
+Then load the .cpu file with:
+
+(cload #:arch \"arch\" #:machs \"keep-mach\" #:isas \"keep-isa\" #:options \"options\")
+
+keep-mach:
+comma separated list of machs to keep or `all'
+
+keep-isa:
+comma separated list of isas to keep or `all'
+
+opcode options:
+[none yet]
+
+gas test options:
+[none yet]
+\n")
+
+(display "\
+sim options:
+with-scache
+with-profile=fn
+
+sim test options:
+[none yet]
+\n")
+
+
+; If ~/.cgenrc exists, load it.
+
+(let ((cgenrc (string-append (getenv 'HOME) "/.cgenrc")))
+ (if (file-exists? cgenrc)
+ (load cgenrc))
+)
diff --git a/cgen/doc/Makefile.am b/cgen/doc/Makefile.am
new file mode 100644
index 00000000000..6cfcc78cfa1
--- /dev/null
+++ b/cgen/doc/Makefile.am
@@ -0,0 +1,17 @@
+## Process this file with automake to generate Makefile.in
+
+AUTOMAKE_OPTIONS = cygnus
+
+info_TEXINFOS = cgen.texi
+
+DOCFILES = app.texi cgen.texi intro.texi notes.texi opcodes.texi \
+ pmacros.texi porting.texi \
+ rtl.texi sim.texi
+
+# version.texi is handled by autoconf/automake
+cgen.info: $(DOCFILES) version.texi
+cgen.dvi: $(DOCFILES) version.texi
+
+# This one isn't ready for prime time yet. Not even a little bit.
+
+noinst_TEXINFOS = cgen.texi
diff --git a/cgen/doc/Makefile.in b/cgen/doc/Makefile.in
new file mode 100644
index 00000000000..370b2242d3a
--- /dev/null
+++ b/cgen/doc/Makefile.in
@@ -0,0 +1,335 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+EXEEXT = @EXEEXT@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+arch = @arch@
+
+AUTOMAKE_OPTIONS = cygnus
+
+info_TEXINFOS = cgen.texi
+
+DOCFILES = app.texi cgen.texi intro.texi notes.texi opcodes.texi \
+ pmacros.texi porting.texi \
+ rtl.texi sim.texi
+
+
+# This one isn't ready for prime time yet. Not even a little bit.
+
+noinst_TEXINFOS = cgen.texi
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_CLEAN_FILES =
+TEXI2DVI = `if test -f $(top_srcdir)/../texinfo/util/texi2dvi; then echo $(top_srcdir)/../texinfo/util/texi2dvi; else echo texi2dvi; fi`
+TEXINFO_TEX = $(top_srcdir)/../texinfo/texinfo.tex
+INFO_DEPS = cgen.info
+DVIS = cgen.dvi
+TEXINFOS = cgen.texi
+DIST_COMMON = Makefile.am Makefile.in stamp-vti version.texi
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .dvi .info .ps .texi .texinfo .txi
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --cygnus doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+$(srcdir)/version.texi: @MAINTAINER_MODE_TRUE@stamp-vti
+ @:
+
+$(srcdir)/stamp-vti: cgen.texi $(top_srcdir)/configure.in
+ @echo "@set UPDATED `$(SHELL) $(top_srcdir)/../mdate-sh $(srcdir)/cgen.texi`" > vti.tmp
+ @echo "@set EDITION $(VERSION)" >> vti.tmp
+ @echo "@set VERSION $(VERSION)" >> vti.tmp
+ @cmp -s vti.tmp $(srcdir)/version.texi \
+ || (echo "Updating $(srcdir)/version.texi"; \
+ cp vti.tmp $(srcdir)/version.texi)
+ -@rm -f vti.tmp
+ @cp $(srcdir)/version.texi $@
+
+mostlyclean-vti:
+ -rm -f vti.tmp
+
+clean-vti:
+
+distclean-vti:
+
+maintainer-clean-vti:
+ -@MAINTAINER_MODE_TRUE@rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
+
+cgen.info: cgen.texi version.texi
+cgen.dvi: cgen.texi version.texi
+
+
+DVIPS = dvips
+
+.texi.info:
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(srcdir) $<
+
+.texi.dvi:
+ TEXINPUTS=$(top_srcdir)/../texinfo/texinfo.tex:$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
+
+.texi:
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(srcdir) $<
+
+.texinfo.info:
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(srcdir) $<
+
+.texinfo:
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(srcdir) $<
+
+.texinfo.dvi:
+ TEXINPUTS=$(top_srcdir)/../texinfo/texinfo.tex:$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
+
+.txi.info:
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(srcdir) $<
+
+.txi.dvi:
+ TEXINPUTS=$(top_srcdir)/../texinfo/texinfo.tex:$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
+
+.txi:
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(srcdir) $<
+.dvi.ps:
+ $(DVIPS) $< -o $@
+
+install-info-am: $(INFO_DEPS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(infodir)
+ @list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \
+ if test -f $$d/$$ifile; then \
+ echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \
+ $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \
+ else : ; fi; \
+ done; \
+ done
+ @$(POST_INSTALL)
+ @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\
+ install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\
+ done; \
+ else : ; fi
+
+uninstall-info:
+ $(PRE_UNINSTALL)
+ @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+ ii=yes; \
+ else ii=; fi; \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ test -z "$ii" \
+ || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \
+ done
+ @$(NORMAL_UNINSTALL)
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \
+ done
+
+dist-info: $(INFO_DEPS)
+ list='$(INFO_DEPS)'; \
+ for base in $$list; do \
+ if test -f $$base; then d=.; else d=$(srcdir); fi; \
+ for file in `cd $$d && eval echo $$base*`; do \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file; \
+ done; \
+ done
+
+mostlyclean-aminfo:
+ -rm -f cgen.aux cgen.cp cgen.cps cgen.dvi cgen.fn cgen.fns cgen.ky \
+ cgen.kys cgen.ps cgen.log cgen.pg cgen.toc cgen.tp cgen.tps \
+ cgen.vr cgen.vrs cgen.op cgen.tr cgen.cv cgen.cn
+
+clean-aminfo:
+
+distclean-aminfo:
+
+maintainer-clean-aminfo:
+ for i in $(INFO_DEPS); do \
+ rm -f $$i; \
+ if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \
+ rm -f $$i-[0-9]*; \
+ fi; \
+ done
+clean-info: mostlyclean-aminfo
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info
+info-am: $(INFO_DEPS)
+info: info-am
+dvi-am: $(DVIS)
+dvi: dvi-am
+check-am:
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-info-am:
+install-info: install-info-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-vti mostlyclean-aminfo mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-vti clean-aminfo clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-vti distclean-aminfo distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-vti maintainer-clean-aminfo \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-vti distclean-vti clean-vti maintainer-clean-vti \
+install-info-am uninstall-info mostlyclean-aminfo distclean-aminfo \
+clean-aminfo maintainer-clean-aminfo tags distdir info-am info dvi-am \
+dvi check check-am installcheck-am installcheck install-info-am \
+install-info install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# version.texi is handled by autoconf/automake
+cgen.info: $(DOCFILES) version.texi
+cgen.dvi: $(DOCFILES) version.texi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/cgen/doc/app.texi b/cgen/doc/app.texi
new file mode 100644
index 00000000000..27142e32504
--- /dev/null
+++ b/cgen/doc/app.texi
@@ -0,0 +1,430 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Writing an application
+@chapter Writing an application
+@cindex Writing an application
+
+This chapter contains information for those wishing to write their own
+CGEN application.
+
+@menu
+* File Layout:: Organization of source files
+* File Generation Process:: Workflow in cgen
+* Coding Conventions:: Coding conventions
+* Accessing Loaded Data:: Reading data from loaded .cpu files
+* Name References:: Architecture names in generated code
+* String Building:: Building long strings and writing them out
+* COS:: Cgen's Object System
+@end menu
+
+@node File Layout
+@section File Layout
+
+Source files in cgen are organized in a very specific way.@footnote{As the
+number of source files grows the entire layout may be changed, but until then
+this is how things are.} It makes it easy to find things.
+
+@itemize @bullet
+@item top level file is cgen-<app>.scm
+The best way to create this file is to copy an existing application's file
+(e.g. cgen-opc.scm) and modify to suit.
+@item file <app>.scm contains general app-specific utilities
+@item other files are <app>-foo.scm
+@item add entry to dev.scm (load-<app>)
+@end itemize
+
+@node File Generation Process
+@section File Generation Process
+
+This is an overview of cgen workflow.
+
+@itemize @bullet
+
+@item cgen is started with list of files to generate and code generation
+options
+
+@item source code is loaded
+
+@itemize @minus
+@item application independent code is loaded if not compiled in
+@item application specific code is loaded
+
+Currently app-specific code is never compiled in.
+@itemize @minus
+@item doesn't affect speed as much as application independent stuff
+@item subject to more frequent changes
+@item makes it easier to do application development if changes to .scm
+files are "ready to use"
+@end itemize
+@end itemize
+
+@item ultimately procedure `cpu-load' is called which is the main driver for
+loading .cpu files
+
+@item various data structures are initialized
+
+@item data files are loaded
+
+@itemize @minus
+@item main <arch>.cpu file is loaded
+
+There is a #include-like mechanism for loading other files so big
+architectures can be broken up into several files.
+
+While the architecture description is being loaded, entries not requested
+are discarded. This happens, for example, when building a simulator:
+there's no point in keeping instructions specific to a machine that is
+not being generated. What to keep is based on the MACH and ISA attributes.
+
+@item application specific data files are loaded
+
+e.g. <arch>.sim
+@end itemize
+
+@item builtin elements are created
+
+@item each requested file is generated by calling cgen-<file> generator
+
+The output is written to the output file with @code{with-output-to-file} so
+the code must write to @code{(current-output-port)}.
+
+Some files require heavy duty processing of the cpu description.
+For example the simulator computes the instruction formats from the
+instruction field lists of each instruction. This computation is defered
+to each cgen-<file> procedure that needs it and must be explicitly requested
+by them. The results are cached so this is only done once of course.
+
+@item additional processing for some opcodes files
+
+Several opcodes files are built from three sources.
+
+@itemize @minus
+@item generated code
+
+@item section in <arch>.opc file
+
+It's not appropriate to put large amounts of C (or perhaps any C) in
+cgen description files, yet some things are best expressed in some
+other language (e.g. assembler/disassembler operand parsing/printing).
+
+@item foo.in file
+
+It seems cleaner to put large amounts of non-machine-generated C
+in separate files from code generator.
+@end itemize
+
+@end itemize
+
+@node Coding Conventions
+@section Coding Conventions
+
+@itemize @bullet
+@item unless definition occupies one line, final trailing parenthesis is on
+a line by itself beginning in column one
+@item definitions internal to a source file begin with '-'
+@item global state variables are named *foo-bar*
+[FIXME: current code needs updating]
+@item avoid uppercase (except for ???)
+@item procedures that return a boolean result end in '?'
+@item procedures that modify something end in '!'
+@item classes are named <name>
+@end itemize
+
+@node Accessing Loaded Data
+@section Accessing Loaded Data
+
+Each kind of description file entry (defined with `define-foo') is recorded
+in an object of class <foo>.@footnote{not true for <arch> but will be RSN}
+All the data is collected together in an object of class
+<system>.@footnote{got a better name?}
+@footnote{modes aren't recorded here, should they be?}
+
+Data for the currently selected architecture is obtained with several
+access functions.
+
+@smallexample
+ (current-arch-name)
+ - return symbol that is the name of the arch
+ - this is the name specified with `define-arch'
+
+ (current-arch-comment)
+ - return the comment specified with `define-arch'
+
+ (current-arch-atlist)
+ - return the attributes specified with `define-arch'
+
+ (current-arch-default-alignment)
+ - return a symbol indicated the default aligment
+ - one of aligned, unaligned, forced
+
+ (current-arch-insn-lsb0?)
+ - return a #t if the least significant bit in a word is numbered 0
+ - return a #f if the most significant bit in a word is numbered 0
+
+ (current-arch-mach-name-list)
+ - return a list of names (as symbols) of all machs in the architecture
+
+ (current-arch-isa-name-list)
+ - return a list of names (as symbols) of all isas in the architecture
+
+ - for most of the remaining elements, there are three main accessors
+ [foo is sometimes abbreviated]
+ - current-foo-list - returns list of <foo> objects in the architecture
+ - current-foo-add! - add a <foo> object to the architecture
+ - current-foo-lookup - lookup the <foo> object based on its name
+
+ <atlist>
+ (current-attr-list)
+ (current-attr-add!)
+ (current-attr-lookup)
+
+ <enum>
+ (current-enum-list)
+ (current-enum-add!)
+ (current-enum-lookup)
+
+ <keyword>
+ (current-kw-list)
+ (current-kw-add!)
+ (current-kw-lookup)
+
+ <isa>
+ (current-isa-list)
+ (current-isa-add!)
+ (current-isa-lookup)
+
+ <cpu>
+ (current-cpu-list)
+ (current-cpu-add!)
+ (current-cpu-lookup)
+
+ <mach>
+ (current-mach-list)
+ (current-mach-add!)
+ (current-mach-lookup)
+
+ <model>
+ (current-model-list)
+ (current-model-add!)
+ (current-model-lookup)
+
+ <hardware>
+ (current-hw-list)
+ (current-hw-add!)
+ (current-hw-lookup)
+
+ <ifield>
+ (current-ifld-list)
+ (current-ifld-add!)
+ (current-ifld-lookup)
+
+ <operand>
+ (current-op-list)
+ (current-op-add!)
+ (current-op-lookup)
+
+ <insn>
+ (current-insn-list)
+ (current-insn-add!)
+ (current-insn-lookup)
+
+ <macro-insn>
+ (current-minsn-list)
+ (current-minsn-add!)
+ (current-minsn-lookup)
+
+ (current-ifmt-list)
+ - return list of computed <iformat> objects
+
+ (current-sfmt-list)
+ - return list of computed <sformat> objects
+
+ [there are a few more to be documented, not sure they'll remain as is]
+@end smallexample
+
+@node Name References
+@section Name References
+
+To simplify writing code generators, system names can be
+specified with fixed strings rather than having to compute them.
+The output is post-processed to convert the strings to the actual names.
+Upper and lower case names are supported.
+
+@itemize @bullet
+@item For the architecture name use @@arch@@, @@ARCH@@.
+@item For the cpu family name use @@cpu@@, @@CPU@@.
+@item For the prefix use @@prefix@@, @@PREFIX@@.
+@end itemize
+
+The @samp{prefix} notion is to segregate different code for the same
+cpu family. For example, this is used to segregate the ARM ISA from the
+Thumb ISA.
+
+@node String Building
+@section String Building
+
+Output generation uses a combination of writing text out as it is computed
+and building text for later writing out.
+
+The top level file generator uses @code{string-write}. It takes string-lists
+and thunks as arguments and writes each argument in turn to stdout.
+String-lists are lists of strings (nested arbitrarily deep). It's cheaper
+to @code{cons} long strings together than to use @code{string-append}.
+Thunks return string-lists to write out, but isn't computed until all
+preceeding arguments to `string-write' have been written out. This allows
+defering building up of large amounts of text until it needs to be.
+
+The main procedures for building strings and writing them out are:
+
+@itemize @bullet
+
+@item (string-write string-list-or-thunk1 string-list-or-thunk2 ...)
+
+Loops over arguments writing them out in turn.
+
+@item (string-write-map proc string-list-or-thunk-list)
+
+Apply proc to each element in string-list-or-thunk-list and write out
+the result.
+
+@item (string-list arg1 arg2 ...)
+
+Return list of arguments. This is identical to @code{list} except it
+is intended to take string-lists as arguments.
+
+@item (string-list-map proc arg-list)
+
+Return list of @code{proc} applied to each element of @code{arg-list}.
+This is identical to @code{map} except it is intended to take strings
+as arguments.
+
+@item (string-append string1 string2 ...)
+
+For small arguments it's just as well to use @code{string-append}.
+This is a standard Scheme procedure. The output is also easier to read
+when developing interactively. And some subroutines are used in multiple
+contexts including some where strings are required.
+
+@end itemize
+
+@node COS
+@section COS
+
+COS is Cgen's Object System. It's a simple OO system for Guile that
+was written to provide something useful until Guile had its own.
+COS will be replaced with GOOPs if the Scheme implementation of cgen is kept.
+
+The pure Scheme implementation of COS uses vectors to record objects and
+classes. The C implementation uses smobs (though classes are still
+implemented with vectors).
+
+A complete list of user-visible functions is at the top of @file{cos.scm}.
+
+Here is a list of the frequently used ones.
+
+@itemize @bullet
+
+@item (class-make name parent-name-list element-list method-list)
+
+Use @code{class-make} to define a class.
+
+@smallexample
+name: symbol, <name-of-class>
+parent-name-list: list of symbols, names of each parent class
+element-list: list of either symbols or (symbol . initial-value)
+method-list: list of (symbol . lambda)
+@end smallexample
+
+The result is the class's definition. It is usually assigned to a global
+variable with same name as class's name. Current cgen code always does
+this. It's not a requirement but it is convention.
+
+@item (new <class-name>)
+
+Create a new object with @code{new}.
+@code{<class-name>} is typically the global variable that recorded
+the results of @code{class-make}. The result is a new object of the
+requested class. Class elements have either an "undefined" value
+or an initial value if one was specified when the class was defined.
+
+@item (define-getters class-name prefix element-list)
+
+Elements (aka members) are read/written with "accessors".
+Read accessors are defined with @code{define-getters}, which
+creates one procedure for each element, each defined as
+@code{(prefix-element-name object)}.
+
+This is a macro so don't quote anything.
+
+@item (define-setters class-name prefix element-list)
+
+Write accessors are defined with @code{define-setters}, which
+creates one procedure for each element, each defined as
+@code{(prefix-set-element-name! object new-value)}.
+
+This is a macro so don't quote anything.
+
+@item (elm-get object elm-name)
+
+This can only be used in method definitions (blech, blah blah blah).
+
+@item (elm-set! object elm-name new-value)
+
+This can only be used in method definitions (blech, blah blah blah).
+
+@item (send object method-name arg1 arg2)
+
+Invoke method @code{method-name} on @code{object}.
+
+The convention is to put this in a cover fn:
+@code{(class-name-method-name object arg1 arg2)}.
+
+@item (send-next object method-name arg1 arg2)
+
+Same as @code{send} except only usable in methods and is used to invoke
+the method in the parent class.
+
+@item (make object . args)
+
+One standard way to create a new object is with @code{make}.
+It is a wrapper, defined as
+
+@smallexample
+(define (make object . args)
+ (apply send (cons (new object) (cons 'make! args)))
+)
+@end smallexample
+
+@item (vmake class . args)
+
+The other standard way to create objects is with @code{vmake}.
+
+@code{args} is a list of option names and arguments.
+
+??? Not completely implemented yet.
+
+@item (method-make! class method-name lambda)
+
+The normal way of creating methods is to use @code{method-make!}, not define
+them with the class. It's just easier to define them separately.
+
+@item (method-make-virtual! class method-name lambda)
+
+Create virtual methods created with @code{method-make-virtual!}.
+
+@item (method-make-forward! class elm-name methods) -> unspecified
+
+Forwarding a method invocation on one object to another is extremely
+useful so some utilities have been created to simplify creating forwarding
+methods.
+
+@code{methods} is a list of method names. A method is created for each one
+that forwards the method onto the object contained in element ELM-NAME.
+
+@item (method-make-virtual-forward!)
+
+Same as method-make-forward! except that it creates virtual methods.
+
+@end itemize
diff --git a/cgen/doc/cgen.texi b/cgen/doc/cgen.texi
new file mode 100644
index 00000000000..5b6b54d198c
--- /dev/null
+++ b/cgen/doc/cgen.texi
@@ -0,0 +1,118 @@
+\input texinfo @c -*- Texinfo -*-
+@setfilename cgen.info
+
+@include version.texi
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Cgen: (cgen). The Cpu tools GENerator.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@ifinfo
+Copyright @copyright{} 2000 Red Hat, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@synindex ky cp
+@c
+@c This file documents the Cpu tools GENerator, CGEN.
+@c
+@c Copyright (C) 2000 Red Hat, Inc.
+@c
+
+@setchapternewpage odd
+@settitle CGEN
+@titlepage
+@finalout
+@title The Cpu tools GENerator, CGEN.
+@subtitle Version @value{VERSION}
+@sp 1
+@subtitle @value{UPDATED}
+@author Douglas J. Evans
+@author Red Hat, Inc.
+@page
+
+@tex
+{\parskip=0pt \hfill Red Hat\par \hfill
+\TeX{}info \texinfoversion\par }
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 2000 Red Hat, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end titlepage
+
+@node Top
+@top Introduction
+
+@cindex version
+This brief manual contains preliminary documentation for the CGEN program,
+version @value{VERSION}.
+
+@menu
+* Introduction:: Introduction
+* Running CGEN:: How to run CGEN
+* RTL:: The Register Transfer Language CGEN uses
+* Preprocessor macros:: Macros to simplify description file writing
+* Porting:: Porting
+* Opcodes:: Assembler/disassembler support
+* Simulation:: Simulation support
+* Writing an application:: Writing your own CGEN application
+* Glossary:: Glossary
+* Miscellaneous notes:: Notes needing a better home
+* Credits:: Credits
+* Index:: Index
+@end menu
+
+@include intro.texi
+@include running.texi
+@include rtl.texi
+@include pmacros.texi
+@include porting.texi
+@include opcodes.texi
+@include sim.texi
+@include app.texi
+@include glossary.texi
+@include notes.texi
+@include credits.texi
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@contents
+@bye
diff --git a/cgen/doc/credits.texi b/cgen/doc/credits.texi
new file mode 100644
index 00000000000..91d6e31d29b
--- /dev/null
+++ b/cgen/doc/credits.texi
@@ -0,0 +1,27 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Credits
+@chapter Credits
+
+The following people, listed in alphabetical order, have helped in their own
+way. Thanks!
+
+@itemize @minus
+@item Dave Brolley
+@item Andrew Cagney
+@item Steve Chamberlain
+@item Nick Clifton
+@item Bob Cmelik
+@item Frank Ch. Eigler
+@item Ben Elliston
+@item Kim Knuttila
+@item Ken Raeburn
+@item Jim Wilson
+@end itemize
+
+There's a TV program I watched growing up called ``The Hilarious House
+Of Frightenstein''. The credits at the end had a twist in that Billy
+Van, who played most of the characters, appeared in them again and
+again. I would do the same here for Ian Lance Taylor.
diff --git a/cgen/doc/glossary.texi b/cgen/doc/glossary.texi
new file mode 100644
index 00000000000..932efec1eed
--- /dev/null
+++ b/cgen/doc/glossary.texi
@@ -0,0 +1,29 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Glossary
+@chapter Glossary
+
+@table @asis
+@item arch
+This is the overall architecture. It is the same as BFD's use of
+@emph{arch}.
+
+@item isa
+Acronym for Instruction Set Architecture.
+
+@item mach
+This is a variant of the architecture, short for machine. It is
+essentially the same as BFD's use of @emph{mach}.
+
+@item CPU family
+A group of related mach's. Simulator support is organized along ``CPU
+family'' lines to keep related mach's together under one roof to
+simplify things. The organization is semi-arbitrary and is up to the
+programmer.
+
+@item model
+An implementation of a mach. It is essentially akin to the argument
+to @code{-mtune=} in SPARC GCC (and other GCC ports).
+@end table
diff --git a/cgen/doc/internals.texi b/cgen/doc/internals.texi
new file mode 100644
index 00000000000..381c41da44a
--- /dev/null
+++ b/cgen/doc/internals.texi
@@ -0,0 +1,377 @@
+\input texinfo @c -*- Texinfo -*-
+
+@c This file is work in progress.
+@c Don't expect it to go through texinfo just yet. --bje
+
+@include version.texi
+
+@ifinfo
+Copyright @copyright{} 2000 Red Hat, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ifinfo
+
+@synindex ky cp
+@c
+@c This file documents the internals of the Cpu tools GENerator, CGEN.
+@c
+@c Copyright (C) 2000 Red Hat, Inc.
+@c
+
+@setchapternewpage odd
+@settitle CGEN
+@titlepage
+@finalout
+@title The Cpu tools GENerator, CGEN.
+@subtitle Version @value{VERSION}
+@sp 1
+@subtitle @value{UPDATED}
+@author Ben Elliston
+@author Red Hat, Inc.
+@page
+
+@tex
+{\parskip=0pt \hfill Red Hat, Inc.\par \hfill
+\TeX{}info \texinfoversion\par }
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 2000 Red Hat, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end titlepage
+
+@node Top
+@top Introduction
+
+@cindex version
+This manual documents the internals of CGEN, version @value{VERSION}.
+
+@menu
+* Introduction:: Introduction
+* Guile::
+* Conventions:: Coding conventions
+* Applications::
+* Source file overview::
+* Option processing::
+* Parsing::
+* Version numbering::
+* Glossary:: Glossary
+* Index:: Index
+@end menu
+
+@node Introduction
+@chapter Introduction
+
+This document details the implementation and internals of CGEN, the
+``Cpu tools GENerator''. It focuses on theory of operation and concepts
+rather than extensive details of the implementation--these details
+date too quickly.
+
+@node Conventions
+@chapter Conventions
+
+There are a number of conventions used in the cgen source code. If you
+take the time to absorb these now, the code will be much easier to
+understand.
+
+@itemize @bullet
+@item Procedures and variables local to a file are named @code{-foo}.
+@item Only routines that emit application code begin with @code{gen-}.
+@item Symbols beginning with @code{c-} are either variables containing C code
+ or procedures that generate C code, similarily for C++ and @code{c++-}.
+@item Variables containing C code begin with @code{c-}.
+@item Only routines that emit an entire file begin with @code{cgen-}.
+@item All @file{.cpu} file elements shall have @code{-foo-parse} and
+ @code{-foo-read} procedures.
+@item Global variables containing class definitions shall be named
+ @code{<class-name>}.
+@item Procedures related to a particular class shall be named
+ @code{class-name-proc-name}, where @code{class-name} may be abbreviated.
+@item Procedures that test whether something is an object of a
+ particular class shall be named @code{class-name?}.
+@item In keeping with Scheme conventions, predicates shall have a
+ @code{?} suffix.
+@item In keeping with Scheme conventions, methods and procedures that
+ modify an argument or have other side effects shall have a
+ @code{!} suffix, usually these procs return @code{*UNSPECIFIED*}.
+@item All @code{-foo-parse}, @code{parse-foo} procs shall have @code{context}
+ as the first argument. [FIXME: not all such procs have been
+ converted]
+@end itemize
+
+@node Applications
+@chapter Applications
+
+One of the most importance concepts to grasp with CGEN is that it is not
+a simulator generator. It's a generic tool generator--it can be used to
+generate a simulator, an assembler, a disassembler and so on. These
+``applications'' can then produce different outputs from the same CPU
+description.
+
+When you want to run the cgen framework, an application-specific source
+file is loaded into the Guile interpreter to get cgen running. This
+source file loads in any other source files it needs and then, for
+example, calls:
+
+@example
+ (cgen #:argv argv
+ #:app-name "sim"
+ #:arg-spec sim-arguments
+ #:init sim-init!
+ #:finish sim-finish!
+ #:analyze sim-analyze!)
+ )
+@end example
+
+This gets the whole framework started, in an application-specific way.
+
+node Source file overview
+@chapter Source file overview
+
+@table @file
+
+@item *.cpu, *.opc, *.sim
+Files belonging to each CPU description. .sim files are automatically
+included if they are defined for the given architecture.
+
+@item doc/*.texi
+Texinfo documentation for cgen.
+
+@item slib/*.scm
+Third-party libraries written in Scheme. For example, sort.scm is a
+collection of procedures to sort lists.
+
+@item Makefile.am
+automake Makefile for cgen.
+
+@item NEWS
+News about cgen.
+
+@item README
+Notes to read abot cgen.
+
+@item attr.scm
+Handling of cgen attributes.
+
+@item cgen-gas.scm
+Top-level for GAS testsuite generation.
+
+@item cgen-opc.scm
+Top-level for opcodes generation.
+
+@item cgen-sid.scm
+Top-level for SID simulator generation.
+
+@item cgen-sim.scm
+Top-level for older simulator generation.
+
+@item cgen-stest.scm
+Top-level for simulator testsuite generation.
+
+@item configure.in
+Template for `configure'--process with autoconf.
+
+@item cos.scm
+cgen object system. Adds object oriented features to the Scheme
+language. See the top of @file{cos.scm} for the user-visible
+procedures.
+
+@item decode.scm
+Generic decoder routines.
+
+@item desc-cpu.scm
+???
+
+@item desc.scm
+???
+
+@item dev.scm
+Debugging support.
+
+@item enum.scm
+Enumerations.
+
+@item fixup.scm
+Some procedure definitions to patch up possible differences between
+older and newer versions of Guile:
+
+ * define a (load..) procedure that uses
+ primitive-load-path if load-from-path is not known.
+
+ * define =? and >=? if they aren't already known.
+
+ * define %stat, reverse! and debug-enable in terms of
+ older equivalent procedures, if they aren't already
+ known.
+
+@item gas-test.scm
+GAS testsuite generator.
+
+@item hardware.scm
+Hardware description routines.
+
+@item ifield.scm
+Instruction fields.
+
+@item insn.scm
+Instruction defintions.
+
+@item mach.scm
+Architecture description routines.
+
+@item minsn.scm
+Macro instructions.
+
+@item mode.scm
+Modes.
+
+@item model.scm
+Model specification.
+
+@item opc-asmdis.scm
+For the opcodes applications.
+
+@item opc-ibld.scm
+Ditto.
+
+@item opc-itab.scm
+Ditto.
+
+@item opc-opinst.scm
+Ditto.
+
+@item opcodes.scm
+Ditto.
+
+@item operand.scm
+Operands.
+
+@item pgmr-tools.scm
+Programmer tools--debugging tools, mainly.
+
+@item pmacros.scm
+Preprocessor macros.
+
+@item profile.scm
+Unused?
+
+@item read.scm
+Read and parse .cpu files. @code{maybe_load} is used to load in files
+for required symbols if they are not already present in the environment
+(say, because it was compiled).
+
+@item rtl-c.scm
+RTL to C translation.
+
+@item rtl.scm
+RTL support.
+
+@item rtx-funcs.scm
+RTXs.
+
+@item sem-frags.scm
+Semantic fragments.
+
+@item semantics.scm
+Semantic analysis for the CPU descriptions.
+
+@item sid-cpu.scm
+For the SID application.
+
+@item sid-decode.scm
+Ditto.
+
+@item sid-model.scm
+Ditto.
+
+@item sid.scm
+Ditto.
+
+@item sim-arch.scm
+For the simulator application.
+
+@item sim-cpu.scm
+Ditto.
+
+@item sim-decode.scm
+Ditto.
+
+@item sim-model.scm
+Ditto.
+
+@item sim-test.scm
+For the simulator testsuite application.
+
+@item sim.scm
+For the simulator application.
+
+@item simplify.inc
+Preprocessor macros to simplify CPU description files. This file is not
+loaded by the Scheme interpreter, but is instead included by the .cpu
+file.
+
+@item types.scm
+Low-level types.
+
+@item utils-cgen.scm
+cgen-specific utilities.
+
+@item utils-gen.scm
+Code generation specific utilities.
+
+@item utils-sim.scm
+Simulator specific utilities.
+
+@item utils.scm
+Miscellaneous utilities.
+
+@end table
+
+@code{cgen} is the main entry point called by application file
+generators. It just calls @code{-cgen}, but it does so wrapped inside a
+@code{catch-with-backtrace} procedure to make debugging easier.
+
+@node Version numbering
+@chapter Version numbering
+
+There are two version numbers: the version number of cgen itself and a
+version number for the description language it accepts. These are kept
+in the symbols @code{-CGEN-VERSION} and @code{-CGEN-LANG-VERSION} in
+@file{read.scm}.
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@contents
+@bye
diff --git a/cgen/doc/intro.texi b/cgen/doc/intro.texi
new file mode 100644
index 00000000000..76b6851f522
--- /dev/null
+++ b/cgen/doc/intro.texi
@@ -0,0 +1,759 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Introduction
+@comment node-name, next, previous, up
+@chapter Introduction to CGEN
+
+@menu
+* Overview::
+* CPU description language::
+* Opcodes support::
+* Simulator support::
+* Testing support::
+* Implementation language::
+@end menu
+
+@node Overview
+@section Overview
+
+CGEN is a project to provide a framework and toolkit for writing cpu tools.
+
+@menu
+* Goal:: What CGEN tries to achieve.
+* Why do it?::
+* Maybe it should not be done?::
+* How ambitious is CGEN?::
+* What is missing that should be there soon?::
+@end menu
+
+@node Goal
+@subsection Goal
+
+The goal of CGEN (pronounced @emph{seejen}, and short for
+"Cpu tools GENerator") is to provide a uniform framework and toolkit
+for writing programs like assemblers, disassemblers, and
+simulators without explicitly closing any doors on future things one
+might wish to do. In the end, its scope is the things the software developer
+cares about when writing software for the cpu (compilation, assembly,
+linking, simulation, profiling, debugging, ???).
+
+Achieving the goal is centered around having an application independent
+description of a CPU (plus environment, like ABI) that applications can then
+make use of. In the end that's a lot to ask for from one language. What
+applications can or should be able to use CGEN is left to evolve over time.
+The description language itself is thus also left to evolve over time!
+
+Achieving the goal also involves having a toolkit, libcgen, that contains
+a compiled form of the cpu description plus a suite of routines for working
+with the data.
+
+CGEN is not a new idea. Some GNU ports have done something like this --
+for example, the SH port in its early days. However, the idea never really
+``caught on''. CGEN was started because I think it should.
+
+Since CGEN is a very ambitious project, there are currently lots of
+things that aren't written down, let alone implemented. It will take
+some time to flush all the details out, but in and of itself that doesn't
+necessarily mean they can't be flushed out, or that they haven't been
+considered.
+
+@node Why do it?
+@subsection Why do it?
+
+I think it is important that GNU assembler/disassembler/simulator ports
+be done from a common framework. On some level it's fun doing things
+from scratch, which was and still is to a large extent current
+practice, but this is not the place for that.
+
+@itemize @bullet
+@item the more ports of something one has, the more important it is that they
+be the same.
+
+@item the more complex each of them become, the more important it is
+that they be the same.
+
+@item if they all are the same, a feature added to one is added to all
+of them--within the context of their similarity, of course.
+
+@item with a common framework in place the planning of how to architect
+a port is taken care of, the main part of what's left is simply writing
+the CPU description.
+
+@item the more applications that use the common framework, the fewer
+places the data needs to be typed in and maintained.
+
+@item new applications can take advantage of data and utilities that
+already exist.
+
+@item a common framework provides a better launching point for bigger things.
+@end itemize
+
+@node Maybe it should not be done?
+@subsection Maybe it should not be done?
+
+However, no one has yet succeeded in pushing for such an extensive common
+framework.@footnote{I'm just trying to solicit input here. Maybe these
+questions will help get that input.}
+
+@itemize @bullet
+@item maybe people think it's not worth it?
+
+@item maybe they just haven't had the inclination to see it through?
+(where ``inclination'' includes everything from the time it would take
+to the dealing with the various parties whose turf you would tread on)
+
+@item maybe in the case of assemblers and simulators they're not complex
+enough to see much benefit?
+
+@item maybe the resulting tight coupling among the various applications
+will cause problems that offset any gains?
+
+@item maybe there's too much variance to try to achieve a common
+framework, so that all attempts are doomed to become overly complex?
+
+@item as a corollary of the previous item, maybe in the end trying to
+combine ISA syntax (the assembly language), with ISA semantics (simulation),
+with architecture implementation (performance), would become overly complex?
+@end itemize
+
+@node How ambitious is CGEN?
+@subsection How ambitious is CGEN?
+
+CGEN is a very ambitious project, as future projects can be:
+
+@menu
+* More complicated simulators::
+* Profiling tools::
+* Program analysis tools::
+* ABI description::
+* Machine generated architecture reference material::
+* Tools like what NJMCT provides::
+* Input to a compiler's backend::
+* Hardware/software codesign::
+@end menu
+
+@node More complicated simulators
+@subsubsection More complicated simulators
+
+Current CGEN-based simulators achieve their speed by using GCC's
+"computed goto" facility to implement a threaded interpreter.
+The "main loop" of the cpu engine is contained within one function
+and the administrivia of running the program is reduced to about three
+host instructions per target instruction (one to increment a "virtual pc",
+one to fetch the address of code that implements that next target instruction,
+and one to branch to it). Target instructions can be simulated with as few as
+seven@footnote{Actually, this can be reduced even more by creating copies of
+an instruction specialized for all the various inputs.} instructions for an
+"add" (load address of src1, load src1, load address of src2, load src2, add,
+load address of result, store result). So ignoring overhead (which
+is minimal for frequently executed code) that's ten host instructions per
+"typical" target instruction. Pretty good.@footnote{The actual results
+depend, of course, on the exact mix of target instructions in the application,
+what instructions the host cpu has, and how efficiently the rest of the
+simulator is (e.g. floating point and memory operations can require a hundred
+or more host instructions).}
+
+However, things can still be better. There is still some implementation
+related overhead that can be removed. The two instructions to branch
+to the next instruction would be unnecessary if instruction executors
+were concatenated together. The fetching and storing of target registers
+can be reduced if target registers were kept in host registers across
+instruction boundaries (and the longer one can keep them in host registers
+the better). A consequence of both of these improvements is the number
+of memory operations is drastically reduced. There isn't a lot of ILP
+in the simulation of target instructions to hide memory latencies.
+Another consequence of these improvements is the opportunity to perform
+inter-target-instruction scheduling of the host instructions and other
+optimizations.
+
+There are two ways to achieve these improvements. Both involve converting
+basic blocks (or superblocks) in the target application into the host
+instruction set and compiling that. The first way involves doing this
+"offline". The target program is analyzed and each instruction is converted
+into, for example, C code that implements the instruction. The result is
+compiled and then the new version of the target program is run.
+
+The second way is to do the translation from target instruction set to
+host instruction set while the target program is running. This is often
+refered to as JIT (Just In Time) simulation (FIXME: proper phrasing here?).
+One way to implement this is to simulate instructions the way existing
+CGEN simulators do, but keep track of how frequently a basic block is
+executed. If a block gets executed often enough, then compile a translation
+of it to the host instruction set and switch to using that. This avoids
+the overhead of doing the compilation on code that is rarely executed.
+Note that here is one place where a dual cpu system can be put to good use.
+One cpu handles the simulation and the other handles compilation (translating
+target instructions to host instructions).
+CGEN can@footnote{This hasn't actually been implemented so there is
+some hand waving here.} handle a large part of building the JIT compiler
+because both host and target architectures are recorded in a way that is
+amenable to program manipulation.
+
+A hybrid of these two ways is to translate target basic blocks to
+C code, compile it, and dynamically load the result into the running
+simulation. Problems with this are that one must invoke an external program
+(though one could dynamically load a special form of C compiler I suppose)
+and there's a lot of overhead parsing and optimizing the C code. On the
+other hand one gets to take full advantage of the compiler's optimization
+technology. And if the application takes a long time to simulate, the
+extra cost may be worthwhile. A dual cpu system is of benefit here too.
+
+@node Profiling tools
+@subsubsection Profiling tools
+
+It is useful to know how well an architecture is being utilized.
+For one, this helps build better architectures. It also helps determine
+how well a compilation system is using an architecture.
+
+CGEN-based simulators already compute instruction frequency counts.
+It's straightforward to add register frequency counts.
+Monitoring other aspects of the ISA is also possible. The description
+file provides all the necessary data, all that's needed is to write a
+generator for an application that then performs the desired analysis.
+
+Function unit, pipeline, and other architecture implementation related items
+requires a lot more effort but it is doable. The guideline for this effort
+is again coming up with an application-independent specification of these
+things.
+
+CGEN does not currently support memory or cache profiling.
+Obviously they're important, and support may be added in the future.
+One thing that would be straightforward to add is the building of
+trace data for usage by cache and memory analysis tools.
+The point though is that these tools won't benefit much from CGEN's
+existence.
+
+Another kind of profiling tool is one that takes the program to
+be profiled as input, inserts profiling code into it, and then generates
+a new version of the program which is then run.@footnote{Note that there
+are other uses for such a program modification tool besides profiling.}
+Recorded in CGEN's description files should be all the necessary ISA related
+data to do this. One thing that's missing is code to handle the file format
+and relocations.@xref{ABI description}.
+
+@node Program analysis tools
+@subsubsection Program analysis tools
+
+Related to profiling tools are static program analysis tools.
+By this I mean taking machine code as input and analyzing it in some way.
+Except for symbolic information (which could come from BFD or elsewhere),
+CGEN provides enough information to analyze machine code, both the
+the raw instructions *and* their semantics. Libcgen should contain
+all the basic tools for doing this.
+
+@node ABI description
+@subsubsection ABI description
+
+Several tools need knowledge of not only a cpu's ISA but also of the ABI
+in use. I believe it makes sense to apply the same goals that went into
+CGEN's architecture description language to an ABI description language:
+specify the ABI in an application independent way and then have a basic
+toolkit/library that uses that data and allow the writing of program
+generators for applications that want more than what the toolkit/library
+provides.
+
+Part of what an ABI defines is the file format and relocations.
+This is something that BFD is built for. I think a BFD rewrite
+should happen and should be based, at least in part, on a CGEN-style
+ABI description. This rewrite would be one user of the ABI description,
+but certainly not the only user.
+One problem with this approach is that BFD requires a lot of file format
+specific C code. I doubt all of this code is amenable to being described
+in an application independent way. Careful separation of such things
+will be necessary. It may even be useful to ignore old file formats
+and limit such a BFD rewrite to ELF (not that ELF is free from such
+warts, of course).
+
+@node Machine generated architecture reference material
+@subsubsection Machine generated architecture reference material
+
+Engineers often need to refer to architecture documentation.
+One problem is that there's often only so many hardcopy manuals
+to go around. Since the CPU description contains a lot of the information
+engineers need to find it makes sense to convert that information back
+into a readable form. The manual can then be online available to everyone.
+Furthermore, each architecture will be documented using the same style
+making it easier to move from architecture to architecture.
+
+@node Tools like what NJMCT provides
+@subsubsection Tools like what NJMCT provides
+
+NJMCT is the New Jersey Machine Code Toolkit.
+It focuses exclusively on the encoding and decoding of instructions.
+[FIXME: wip, need to say more].
+
+@node Input to a compiler's backend
+@subsubsection Input to a compiler's backend
+
+One can define a GCC port to include these four things:
+
+@itemize @bullet
+@item cpu architecture description
+@item cpu implementation description
+@item ABI description
+@item miscellaneous
+@end itemize
+
+The CGEN description provides all of the cpu architecture description
+that the compiler needs.
+However, the current design of the CPU description language is geared
+towards going from machine instructions to semantic content, whereas
+what a compiler wants is to do is go from semantic content to machine
+instructions, so in the end this might not be a reasonable thing to
+pursue. On the other hand, that problem can be solved in part by
+specifying two sets of semantics for each instruction: one for the
+compiler side of things, and one for the simulator side of things.
+Frequently they will be the same thing and thus need only be specified once.
+Though specifying them twice, for the two different contexts, is reasonable
+I think. If the two versions of the semantics are used by multiple applications
+this makes even more sense.
+
+The planned rewrite of model support in CGEN will support whatever the
+compiler needs for the implementation description.
+
+Compiler's also need to know the target's ABI, which isn't relevant
+for an architecture description. On the other hand, more than just
+the compiler needs knowledge of the ABI. Thus it makes sense to think
+about how many tools there are that need this knowledge and whether one
+can come up with a unifying description of the ABI. Hence one future
+project is to add the ABI description to CGEN. This would encompass
+in essence most of what is contained in the System V ABI documentation.
+
+That leaves the "miscellaneous" part. Essentially this is a catchall
+for whatever else is needed. This would include things like
+include file directory locations, ???. There's probably no need to
+add these to the CGEN description language.
+
+One can even envision a day when GCC emits object files directly.
+The instruction description contains enough information to build
+the instructions and the ABI support would provide enough
+information on relocations and object file formats.
+Debugging information should be treated as an orthogonal concept.
+At present it is outside the scope of CGEN, though clearly the same
+reasoning behind CGEN applies to debugging support as well.
+
+@node Hardware/software codesign
+@subsubsection Hardware/software codesign
+
+This section isn't very well thought out -- not much time has been put
+into it. The thought is that some interface with VHDL/Verilog could
+be created that would assist hw/sw codesign.
+
+Another related application is to have a feedback mechanism from the
+compilation system that helps improve the architecture description
+(both CGEN and HDL).
+For example, the compiler could determine what instructions would have
+made a significant benefit for a particular application. CGEN descriptions
+for these instructions could be generated, resulting in a new set of
+compilation tools from which the hypothesis of adding the new instructions
+could then be validated. Note that adding these new instructions only
+required writing CGEN descriptions of them (setting aside HDL concerns).
+Once done, all relevant tools would be automagically updated to support
+the new instructions.
+
+@node What is missing that should be there soon?
+@subsection What's missing that should be there soon?
+
+@itemize @bullet
+@item Support for complex ISA's (i386, m68k).
+
+Early versions had the framework of the support, but it's all bit-rotten.
+
+@item ABI description
+
+As discussed elsewhere, one thing that many tools need knowledge of besides
+the ISA is the ABI. Clearly ABI's are orthogonal to ISA's and one cpu
+may have multiple ABI's running on it. Thus the ABI description needs to
+be independent of the architecture description. It would still be useful
+for the ABI to refer to things in the architecture description.
+
+@item Model description
+
+The current design is enough to get reasonable cycle counts from
+the simulator but it doesn't take into account all the uses one would
+want to make of this data.
+
+@item File organization
+
+I believe a lot of what is in libopcodes should be moved to libcgen.
+Libcgen will contain the bulk of the cpu description in processed form.
+It will also contain a suite of utilities for accessing the data.
+
+ABI support could either live in libcgen or separately in libcgenabi.
+libbfd would be a user of this library.
+
+Instruction semantics should also be recorded in libcgen, probably
+in bytecode form. Operand usage tables, needed for example by the
+m32r assembler, can be lazily computed at runtime.
+
+Applications can either make use of libcgen or given the application
+independence of the description language they can write their won code
+generators to tailor the output as needed.
+
+@end itemize
+
+@node CPU description language
+@section CPU description language
+
+The goal of CGEN is to provide a uniform and extensible framework for
+doing assemblers/disassemblers and simulators, as well as allowing
+further tools to be developed as necessary.
+
+With that in mind I think the place to start is in defining a CPU
+description language that is sufficiently powerful for all the current
+and perceived future needs: an application independent description of
+the CPU. From the CPU description, tables and code can be generated
+that an application framework can then use (e.g. opcode table for
+assembly/disassembly, decoder/executor for simulation).
+
+By "application independence" I mean the data is recorded in a way that
+doesn't intentionally close any doors on uses of the data. One example of
+this is using RTL to describe instruction semantics rather than, say, C.
+The assembler can also make use of the instruction semantics. It doesn't
+make use of the semantics, per se, but what it does use is the input and
+output operand information that is machine generated from the semantics.
+Groking operand usage from C is possible I guess, but a lot harder.
+So by writing the semantics in RTL multiple applications can make use if it.
+One can also generate from the RTL code in languages other than C.
+
+@menu
+* Language requirements::
+* Layout::
+* Language problems::
+@end menu
+
+@node Language requirements
+@subsection Language requirements
+
+The CPU description file needs to provide at least the following:
+
+@itemize @bullet
+@item elements of the CPU's architecture (registers, etc.)
+@item elements of a CPU's implementation (e.g. pipeline)
+@item how the bits of an instruction word map to the instruction's semantics
+@item semantic specification in a way that is amenable to being
+understood and manipulated
+@item performance measurement parameters
+@item support for multiple ISA variants
+@item assembler syntax of the instruction set
+@item how that syntax maps to the bits of the instruction word, and back
+@item support for generating test files
+@item ???
+@end itemize
+
+In addition to this, elements of the particular ABI in use is also needed.
+These things will obviously need to be defined separately from the cpu
+for obvious reasons.
+
+@itemize @bullet
+@item file format
+@item relocations
+@item function calling conventions
+@item ???
+@end itemize
+
+Some architectures require knowledge of the pipeline in order to do
+accurate simulation (because, for example, some registers don't have
+interlocks) so that will be required as well, as opposed to being solely
+for performance measurement. Pipeline knowledge is also needed in order
+to achieve accurate profiling information. However, I haven't spent
+much time on this yet. The current design/implementation is a first
+pass in order to get something working, and will be revisited.
+
+Support for generating test files is not complete. Currently the GAS
+test suite generator gets by (barely) without them. The simulator test
+suite generator just generates templates and leaves the programmer to
+fill in the details. But I think this information should be present,
+meaning that for situations where test vectors can't be derived from the
+existing specs, new specs should be added as part of the description
+language. This would make writing testcases an integral part of writing
+the .cpu file. Clearly there is a risk in having machine generated
+testcases - but there are ways to eliminate or control the risk.
+
+The syntax of a suitable description language needs to have these
+properties:
+
+@itemize @bullet
+@item simple
+@item expressive
+@item easily parsed
+@item easy to learn
+@item understandable by program generators
+@item extensible
+@end itemize
+
+It would also help to not start over completely from scratch. GCC's RTL
+satisfies all these goals, and is used as the basis for the description
+language used by CGEN.
+
+Extensibility is achieved by specifying everything as name/value pairs.
+This allows new elements to be added and even CPU specific elements to
+be added without complicating the language or requiring a new element in
+a @code{define_insn} type entry to be added to each existing port.
+Macros can be used to eliminate the verbosity of repetitively specifying
+the ``name'' part, so one can have it both ways. Imagine GCC's
+@file{.md} file elements specified as name/value pairs with macro's
+called @code{define_expand}, @code{define_insn}, etc. that handle the
+common cases and expand the entry to the full @code{(define_full_expand
+(name addsi3) (template ...) (condition ...) ...)}.
+
+Scheme also uses @code{(foo :keyword1 value1 :keyword2 value2 ...)},
+though that isn't implemented yet (or maybe @code{#:keyword} depending
+upon what is enabled in Guile).
+
+@node Layout
+@subsection Layout
+
+Here is a graphical layout of the hierarchy of elements of a @file{.cpu} file.
+
+@example
+ architecture
+ / \
+ cpu-family1 cpu-family2 ...
+ / \
+ machine1 machine2 ...
+ / \
+ model1 model2 ...
+@end example
+
+Each of these elements is explained in more detail in @ref{RTL}. The
+@emph{architecture} is one of @samp{sparc}, @samp{m32r}, etc. Within
+the @samp{sparc} architecture, the @emph{cpu-family} might be
+@samp{sparc32} or @samp{sparc64}. Within the @samp{sparc32} CPU family,
+the @emph{machine} might be @samp{sparc-v8}, @samp{sparclite}, etc.
+Within the @samp{sparc-v8} machine classificiation, the @emph{model}
+might be @samp{hypersparc} or @samp{supersparc}.
+
+Instructions form their own hierarchy as each instruction may be supported
+by more than one machine. Also, some architectures can handle more than
+one instruction set on one chip (e.g. ARM).
+
+@example
+ isa
+ |
+ instruction
+ / \
+ operand1 operand2 ...
+ | |
+ hw1+ifield1 hw2+ifield2 ...
+@end example
+
+Each of these elements is explained in more detail in @ref{RTL}.
+
+@node Language problems
+@subsection Language problems
+
+There are at least two potential problem areas in the language's design.
+
+The first problem is variation in assembly language syntax. Examples of
+this are Intel vs AT&T i386 syntax, and Motorola vs MIT M68k syntax.
+I think there isn't a sufficient number of important cases to warrant
+handling this efficiently. One could either ignore the issue for
+situations where divergence is sufficient to dissuade one from handling
+it in the existing design, or one could provide a front end or
+use/extend the existing macro mechanism.
+
+One can certainly argue that description of assembler syntax should be
+separated from the hardware description. Doing so would prevent
+complications in supporting multiple or even difficult assembler
+syntaxes from complicating the hardware description. On the other hand,
+there is a lot of duplication, and in the end for the intended uses of
+CGEN I think the benefits of combining assembler support with hardware
+description outweigh the disadvantages. Note that the assembler
+portions of the description aren't used by the simulator @footnote{The
+simulator currently uses elements of the opcode table since the opcode
+table is a nice central repository for such things. However, the
+assembler/disassembler isn't part of the simulator, and the
+portions of the opcode table can be generated and recorded elsewhere
+should it prove reasonable to do so. The CPU description file won't
+change, which is the important thing.}, so if one wanted to implement
+the disassembler/assembler via other means one can.
+
+The other potential problem area is relocations. Clearly part of
+processing assembly code is dealing with the relocations involved
+(e.g. GOT table specification). Relocation support necessarily requires
+BFD and GAS support, both of which need cleanup in this area. Rewriting
+BFD to provide a better interface so reloc handling in GAS can be
+cleaned up is believed to be something this project can and should take
+advantage of, and that any attempt at adding relocation support should
+be done by first cleaning up GAS/BFD. That can be left for another day
+though. :-)
+
+One can certainly argue trying to combine an ABI description with a
+hardware description is problematic as there can be more than one ABI.
+However, there often isn't and in the cases where there isn't the
+simplified porting and maintenance is worth it, in the author's opinion.
+Furthermore, the current language doesn't embed ABI elements
+with hardware description elements. Careful segregation of such things
+might ameliorate any problems.
+
+@node Opcodes support
+@section Opcodes support
+
+Opcodes support comes in the form of machine generated opcode tables as
+well as supporting routines.
+
+@node Simulator support
+@section Simulator support
+
+Simulator support comes in the form of machine generated the decoder/executer
+as well as the structure that records CPU state information (ie. registers).
+
+@node Testing support
+@section Testing support
+
+@menu
+* Assembler/disassembler testing::
+* Simulator testing::
+@end menu
+
+Inherent in the design is the ability to machine generate test cases both
+for the assembler/disassembler and for the simulator. Furthermore, it
+is not unreasonable to add to the description file data specifically
+intended to assist or guide the testing process. What kinds of
+additions that will be needed is unknown at present.
+
+@node Assembler/disassembler testing
+@subsection Assembler/disassembler testing
+
+The description of instructions and their fields contains to some extent
+not only the syntax but the possible values for each field. For
+example, in the specification of an immediate field, it is known what
+the allowable range of values is. Thus it is possible to machine
+generate test cases for such instructions. Obviously one wouldn't want
+to test for each number that a number field can contain, however one can
+generate a representative set of any size. Likewise with register
+fields, mnemonic fields, etc. A good starting point would be the edge
+cases, the values at either end of the range of allowable values.
+
+When I first raised the possibility of machine generated test cases the
+first response I got was that this wouldn't be useful because the same
+data was being used to generate both the program and the test cases. An
+error might be propagated to both and thus nullify the test. For
+example if an opcode field was supposed to have the value 1 and the
+description file had the value 2, then this error wouldn't be caught.
+However, this assumes test cases are generated during the testing run!
+And it ignores the profound amount of typing that is saved by machine
+generating test cases! (I discount the argument that this kind of
+exhaustive testing is unnecessary).
+
+One solution to the above problem is to not generate the test cases
+during the testing run (which was implicit in the proposal, but perhaps
+should have been explicit). Another solution is to generate the
+test cases during the test run but first verify them by some external
+means before actually using them in any test. The latter solution is
+only mentioned for completeness sake; its implementation is problematic
+as any external means would necessarily be computer driven and the level
+of confidence in the result isn't 100%.
+
+So how are machine generated test cases verified? By machine, by hand,
+and by time. The test cases are checked into CVS and are not regenerated
+without care. Every time the test cases are regenerated, the diffs are
+examined to ensure the bug triggering the regeneration has been fixed
+and that no new bugs have been introduced. In all likelihood once a
+port is more or less done, regeneration of test cases would stop anyway,
+and all further changes would be done manually.
+
+``By machine'' means that for example in the case of ports with a native
+assembler one can run the test case through the native assembler and use
+that as a good first pass.
+
+``By hand'' means one can go through each test case and verifying them
+manually. This is what is done in the case of non-machine generated
+test cases, the only difference is the perceived difference in quantity.
+And in the case of machine generated test cases comments can be added to
+each test to help with the manual verification (e.g. a comment can be
+added that splits the instruction into its fields and shows their names
+and values).
+
+``By time'' means that this process needn't be done instantaneously.
+This is no different than the non-machine generated case again except in
+the perceived difference in quantity of test cases.
+
+Note that no claim is made that manually generated test cases aren't
+needed. Clearly there will be some cases that the description file
+doesn't describe and thus can't machine generate.
+
+@node Simulator testing
+@subsection Simulator testing
+
+Machine generation of simulator test cases is possible because the
+semantics of each instruction is written in a way that is understandable
+to the generator. At the very least, knowledge of what the instructions
+are is present! Obviously there will be some instructions that can't
+be adequately expressed in RTL and are thus not amenable to having a
+test case being machine generated. There may even be some RTL'd
+semantics that fall into this category. It is believed, however, that
+there will still be a large percentage of instructions amenable to
+having test cases machine generated for them. Such test cases can
+certainly be hand generated, but it is believed that this is a large
+amount of unnecessary typing that typically won't be done due to the
+amount. Again, I discount the argument that this kind of exhaustive
+testing isn't necessary.
+
+An example is the simple arithmetic instructions. These take zero, one,
+or more arguments and produce a result. The description file contains
+sufficient data to generate such an instruction, the hard part is in
+providing the environment to set up the required inputs (e.g. loading
+values into registers) and retrieve the output (e.g. retrieve a value
+from a register).
+
+Certainly at the very least all the administrivia for each test case can
+be machine generated (i.e. a template file can be generated for each
+instruction, leaving the programmer to fill in the details).
+
+The strategy used for assembler/disassembler test cases is also used here.
+Test cases are kept in CVS and are not regenerated without care.
+
+@node Implementation language
+@section Implementation language
+
+The chosen implementation language is Scheme. The reasons for this are:
+
+@itemize @bullet
+@item Parsing RTL in Scheme is real easy, though I did make some albeit
+minor changes to make it easier. While it doesn't take more than a few
+dozen lines of C to parse RTL, it doesn't take any lines of Scheme -
+the parser is built into the interpreter.
+
+@item An interactive environment is a better environment to work in,
+especially in the early stages of an ambitious project like this.
+
+@item Guile is developing as an embeddable interpreter.
+I wanted room for growth in many dimensions, and having the implementation
+language be an embeddable interpreter supports this.
+
+@item I wanted to learn Scheme (Yes, not a technical reason, blah blah blah).
+
+@item Numbers in Scheme can have arbitrary precision so representing 64
+bit (or higher) numbers on a 32 bit host is well defined.
+
+@item It seemed useful to have an implementation language similar to the
+CPU description language. The Scheme implementation seems simpler
+than a C implementation would be.
+@end itemize
+
+One issue that arises with the use of Scheme as the implementation
+language is whether to generate files in the source tree, with the
+issues that involves, or generate the files in the build tree (and thus
+require Guile to build Binutils and the issues that involves). Trying
+to develop something like this is easier in an interactive environment,
+so Scheme as the first implementation language is, to me, a better
+choice than C or C++. In such a big project it also helps to have a
+more expressive language so relatively complex code and be written with
+fewer lines of code.
+
+One consequence is maintenance is more difficult in that the
+generated files (e.g. @file{opcodes/m32r-*.[ch]}) are checked into CVS
+at Red Hat, and a change to a CPU description requires rebuilding the
+generated files and checking them in as well. And a change that affects
+each port requires each port to be regenerated and checked in.
+This is more palatable for maintainer tools such as @code{bison},
+@code{flex}, @code{autoconf} and @code{automake}, as their input files
+don't change as often.
+
+
+Whether to continue with Scheme, convert the code to a compiled
+language, or have both is an important, open issue.
diff --git a/cgen/doc/notes.texi b/cgen/doc/notes.texi
new file mode 100644
index 00000000000..b21a59b0719
--- /dev/null
+++ b/cgen/doc/notes.texi
@@ -0,0 +1,237 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Miscellaneous notes
+@chapter Miscellaneous notes
+@cindex Miscellaneous notes
+
+This chapter is a repository of miscellaneous notes that belong elsewhere
+or nowhere. They're here because I want them written down, for now anyway,
+and I'm not sure where else to put them. There may be duplication here
+with things elsewhere in the docs. I'm not bothering to ensure there isn't.
+It's better to have things written down twice than not at all. If there
+is a conflict between notes here and elsewhere, check the chronology.
+I may have changed my mind. If not, the situation may be complicated and I
+don't have a strong opinion on what's right. No claim is made that these
+notes represent my complete opinion. (Hmmm... lessee what other caveats
+I can throw in here ... :-)
+
+@c ??? Shouldn't have to append " notes" to every menu entry.
+@c It's done because some entries collide with menu entries in other
+@c chapters and texinfo doesn't like that (complains or crashes).
+
+@menu
+* Description language notes::
+* CGEN architecture notes::
+* COS notes::
+* RTL notes::
+* Guile implementation notes::
+* Code generation notes::
+* Machine generated files notes::
+* Implementation language notes::
+@end menu
+
+@node Description language notes
+@section Description language notes
+
+@itemize @minus
+
+@item timing support
+
+The current implementation of timing (aka pipeline, function units, etc.)
+support is a quick hack in order to achieve useful numbers out of the
+simulator. It is intended to be replaced with something a lot more
+sophisticated. Remember to keep in mind cgen's goal of application
+independence when designing the new version. For example, it must handle
+things like code scheduling in a compiler (where speed of analysis is not
+critical) to scheduling in a dynamic compiler (where speed of analysis is
+critical). It must also handle semi-accurate to fully-accurate cycle
+counting in simulators (where the former might trade off accuracy for speed
+which one wouldn't do in the latter, assuming there is a trade-off to be
+made). It must also handle the representation and handling of pipelines
+with program visible hazards.
+
+@item organization of cpu description
+
+One thing that may not be apparent is that the description language
+doesn't preclude one item (say an insn) from having its definition
+spread over several files. One example would be to leave the timing
+elements unspecified in the "main" entry of an insn, and then have
+a machine-specific file providing timing characteristics, etc.
+
+One can even leave the semantics to be defined elsewhere.
+The `=' insn format prefix is not currently used very much (no need).
+It might also need better documentation.
+
+A possible break-up of an item's description into several files should be
+generally supported (where reasonable).
+
+@end itemize
+
+@node CGEN architecture notes
+@section CGEN architecture notes
+
+@itemize @minus
+
+@item compiled form of description in libcgen
+
+The current compiled form of the cpu description has been focused on
+two applications: opcodes and simulator. No doubt there are things present
+that will present problems to future applications.
+One thing on the todo list has been to record semantics with the compiled
+form, probably as bytecode. Maybe it would make sense to record the
+entire cpu description as a kind of bytecode. This would allow apps to
+instantiate it for the task at hand as they please.
+
+@item function-style attributes
+
+Attributes currently only support static (compile-time computed) notions.
+They should also support run-time computed values. The way to do this is
+to record such attributes as bytecode and lazily (or not lazily) evaluate
+them at runtime, perhaps caching the results. It might make sense to
+record all attributes this way (though I currently don't think so).
+
+@item importance of description language
+
+When hacking on cgen, the description language takes priority over
+implementation. That cannot be stressed enough. When faced with
+choices of what to do, put the elegance, maintainability, and application
+independence of the description language first. Implementation will almost
+always take shortcuts due to application specific requirements. Theoretically
+the description language won't have to; at least that's where the effort
+in application independence should be put.
+
+@end itemize
+
+@node COS notes
+@section COS notes
+
+@itemize @minus
+
+@item elm-xget, elm-xset
+
+These procedures are quick hacks and should be avoided.
+Existing uses should be replaced.
+Where they're used it's either because of laziness or because
+I wasn't sure whether I wanted to allow global access to the element,
+so using an easily grep-able hack let's me find them and revisit them.
+
+@end itemize
+
+@node RTL notes
+@section RTL notes
+
+@itemize @minus
+
+@item Where's strict_lowpart? Where's foo?
+
+Elements of gcc's rtl like strict_lowpart, pre_inc, etc. aren't in
+cgen's rtl only because thus far there hasn't been a compelling need
+for them. When there is a compelling need they'll be added.
+
+@item boolean values
+
+Sometimes #f/#t is used for boolean values.
+However the "boolean" mode @code{BI} has values 0 and 1.
+Which one is in use is context dependent.
+Not sure there is a problem but it should be revisited.
+
+@item #f to denote "unspecified" values
+
+Sometimes () is used to specify "unspecified" values.
+Other times #f is used. Should standardize in #f.
+
+@item ifield assertions
+
+Perhaps these should be renamed to "constraints".
+"ifield-assertion" sounds clumsy.
+
+@end itemize
+
+@node Guile implementation notes
+@section Guile implementation notes
+
+@itemize @minus
+
+@item
+Remaining todo is to complete switchover from "errtxt" (a string)
+in .cpu file reader support to "context" (a <context> object).
+
+@item
+Remaining todo is to complete switchover of naming functions from
+"prefix:function" to "prefix-function". One reasonable naming style
+is "prefix-verb-noun". I like it.
+
+@item
+Slib uses "prefix:foo" for "internal" routines. Maybe that would be
+a better choice than the current "-prefix-foo" style.
+
+@end itemize
+
+@node Code generation notes
+@section Code generation notes
+
+@itemize @minus
+
+@item foo
+
+@end itemize
+
+@node Machine generated files notes
+@section Machine generated files notes
+
+@itemize @minus
+
+@item
+In the end I think the best thing is to build the machine generated files
+when the tools themselves are built (same as gcc's gen* -> insn* files).
+
+@end itemize
+
+@node Implementation language notes
+@section Implementation language notes
+
+In the end I think the implementation language (or the Guile
+implementation) will have to change.
+If one compares the speed of gcc's gen* file generators vs cgen's,
+and one envisions the day when machine generated files are
+built at build time, then I think the user community will require
+similar speed in file generation. Guile isn't fast enough.
+And while Guile+Hobbit may be, for the one-time builder the time
+taken to compile Hobbit, run it, and compile the result, will appear
+to swamp any gains. There is also the additional burden of
+building Guile first (though with my prefered Guile implementation
+I'm _hoping_ that wouldn't be a problem).
+
+The pragmatic choice is C. Blech.
+
+A better choice would be C++ but then that would obviously place a
+requirement on having a C++ compiler available in order to build binutils,
+for example (assuming machine generated files are built at build time).
+
+Java would also be a better implementation language than C
+[an interesting experiment would be Kawa]. But it's worse as a pragmatic
+choice than C++.
+
+My prefered choice is a small-and-fast subset of Guile that gets
+distributed with binutils, gdb, etc. IMO Guile is too bloated
+and unmaintainable for the casual maintainer (hacking on its innards
+requires too steep a learning curve, and is one that is easily slipped back
+down should one step away from it for too long). If those can be fixed and
+the speed of cgen's file generation can be made acceptable, then that
+is the path I would choose.
+
+In making the choice people need to look forward rather than look backward.
+We're finally switching the GNU tools to ANSI C. If the host doesn't provide
+an ANSI C compiler the user is expected to get one (GCC).
+Well, G++ is available on most if not all hosts of concern, so
+in this day and age requiring C++ in order to build binutils isn't
+as much of a burden as it use to be. Cgen is a forward looking design.
+At its heart is a goal to close no doors on future uses. That's a
+pretty lofty goal. Forcing people to achieve that goal with C because
+of pragmatic concerns is unjustifiable, IMO.
+
+Note that changing the "implementation language" does _not_ mean
+Guile cannot or will not be used for various things! I think Guile
+should continue to be used for prototyping as well as certain applications.
diff --git a/cgen/doc/opcodes.texi b/cgen/doc/opcodes.texi
new file mode 100644
index 00000000000..4085aa20588
--- /dev/null
+++ b/cgen/doc/opcodes.texi
@@ -0,0 +1,186 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Opcodes
+@chapter Opcodes support
+@cindex Opcodes support
+
+Opcodes support comes in the form of machine generated opcode tables as
+well as supporting routines.
+
+@menu
+* Generated files:: List of generated files
+* The .opc file:: Target specific C code
+* Special assembler parsing needs::
+@end menu
+
+@node Generated files
+@section Generated files
+
+The basic interface is defined by
+@file{include/opcode/cgen.h} which is included by the machine generated
+@file{<arch>-desc.h}. @file{opcode/cgen.h} can stand on its own for the
+target independent stuff, but to get target specific parts of the
+interface use @file{<arch>-desc.h}.
+
+The generated files are:
+
+@table @file
+@item <arch>-desc.h
+Defines macros, enums, and types used to describe the chip.
+@item <arch>-desc.c
+Tables of various things describing the chip.
+This does not include assembler syntax nor semantic information.
+@item <arch>-ibld.c
+Routines for constructing and deconstructing instructions.
+@item <arch>-opc.h
+Declarations necessary for assembly/disassembly that aren't used
+elsewhere and thus left out of @file{<arch>-desc.h}.
+@item <arch>-opc.c
+Assembler syntax tables.
+@item <arch>-asm.c
+Assembler support routines.
+@item <arch>-dis.c
+Disassembler support routines.
+@item <arch>-opinst.c
+Operand instance tables.
+These describe which hardware elements are read and which are written
+for each instruction. This file isn't generated for all architectures,
+only ones that can make use of the data. For example the M32R uses them
+to emit warnings if the output of one parallel instruction is the input
+of another, and to control creating parallel instructions during optimizing
+assembly.
+@end table
+
+@node The .opc file
+@section The .opc file
+
+Files with suffix @file{.opc} (e.g. @file{m32r.opc}) contain target
+specific C code that accompanies the cpu description file.
+The @file{.opc} file is split into 4 sections:
+
+@itemize @minus
+@item opc.h
+
+This section contains additions to the generated @file{$target-opc.h} file.
+
+Typically defined here are these macros:
+
+@itemize @bullet
+@item #define CGEN_DIS_HASH_SIZE N
+
+Specifies the size of the hash table to use during disassembly.
+A hash table is built of the selected mach's instructions in order to
+speed up disassembly.
+@item #define CGEN_DIS_HASH(buffer, value)
+
+Given BUFFER, a pointer to the instruction being disassembled and
+VALUE, the value of the instruction as a host integer, return an
+index into the hash chain for the instruction. The result must be
+in the range 0 to CGEN_DIS_HASH_SIZE-1.
+
+VALUE is only usable if all instructions fit in a portable integer (32 bits).
+
+N.B. The result must depend on opcode portions of the instruction only.
+Normally one wants to use between 6 and 8 bits of opcode info for the hash
+table. However, some instruction sets don't use the same set of bits
+for all insns. Certainly they'll have at least one opcode bit in common
+with all insns, but beyond that it can vary. Here's a possible definition
+for sparc.
+
+@example
+#undef CGEN_DIS_HASH_SIZE
+#define CGEN_DIS_HASH_SIZE 256
+#undef CGEN_DIS_HASH
+extern const unsigned int sparc_cgen_opcode_bits[];
+#define CGEN_DIS_HASH(buffer, insn) \
+((((insn) >> 24) & 0xc0) \
+ | (((insn) & sparc_cgen_opcode_bits[((insn) >> 30) & 3]) >> 19))
+@end example
+
+@code{sparc_cgen_opcode_bits} would be defined in the @samp{asm.c} section as
+
+@example
+/* It is important that we only look at insn code bits
+ as that is how the opcode table is hashed.
+ OPCODE_BITS is a table of valid bits for each of the
+ main types (0,1,2,3). */
+const unsigned int sparc_cgen_opcode_bits[4] = @{
+ 0x01c00000, 0x0, 0x01f80000, 0x01f80000
+@};
+@end example
+@end itemize
+
+@item opc.c
+
+@item asm.c
+
+This section contains additions to the generated @file{$target-asm.c} file.
+Typically defined here are functions used by operands with a @code{parse}
+define-operand handler spec.
+
+@item dis.c
+
+This section contains additions to the generated @file{$target-dis.c} file.
+
+Typically defined here these macros:
+
+@itemize @bullet
+@item #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length)
+@item #define CGEN_PRINT_ADDRESS(cd, info, value, attrs, pc, length)
+@item #define CGEN_PRINT_INSN function_name
+@c FIXME: should be CGEN_PRINT_INSN(cd, pc, info)
+@item #define CGEN_BFD_ARCH bfd_arch_<name>
+@item #define CGEN_COMPUTE_ISA(info)
+@end itemize
+
+@end itemize
+
+@node Special assembler parsing needs
+@section Special assembler parsing needs
+
+Often parsing of assembly instructions requires more than what
+a program-generated assembler can handle. For example one version
+of an instruction may only accept certain registers, rather than
+the entire set.
+
+Here's an example taken from the @samp{m32r} architecture.
+
+32 bit addresses are built up with a two instruction sequence: one to
+load the high 16 bits of a register, and another to @code{or}-in the
+lower 16 bits.
+
+@example
+seth r0,high(some_symbol)
+or3 r0,r0,low(some_symbol)
+@end example
+
+When assembling, special code must be called to recognize the
+@code{high} and @code{low} pseudo-ops and generate the appropriate
+relocations. This is indicated by specifying a "parse handler" for
+the operand in question. Here is the @code{define-operand}
+for the lower 16 bit operand.
+
+@example
+(define-operand
+ (name ulo16)
+ (comment "16 bit unsigned immediate, for low()")
+ (attrs)
+ (type h-ulo16)
+ (index f-uimm16)
+ (handlers (parse "ulo16"))
+)
+@end example
+
+The generated parser will call a function named @code{parse_ulo16}
+for the immediate operand of the @code{or3} instruction.
+The name of the function is constructed by prepended "parse_" to the
+argument of the @code{parse} spec.
+
+@example
+errmsg = parse_ulo16 (cd, strp, M32R_OPERAND_ULO16, &fields->f_uimm16);
+@end example
+
+But where does one put the @code{parse_ulo16} function?
+Answer: in the @samp{asm.c} section of @file{m32r.opc}.
diff --git a/cgen/doc/pmacros.texi b/cgen/doc/pmacros.texi
new file mode 100644
index 00000000000..cc41dd4114e
--- /dev/null
+++ b/cgen/doc/pmacros.texi
@@ -0,0 +1,457 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Preprocessor macros
+@chapter Preprocessor macros
+@cindex Preprocessor macros
+@cindex pmacros
+
+Preprocessor macros provide a way of simplifying the writing of
+@file{.cpu} files and serve the same purpose that macros do in C.
+
+@menu
+* Defining a preprocessor macro:: @code{define-pmacro}
+* Using preprocessor macros::
+* Macro expansion:: The @code{pmacro-expand} procedure
+* Default argument values:: Specifying default values of arguments
+* Multiple output expressions:: Using @code{begin}
+* Symbol concatenation:: The @code{.sym} builtin
+* String concatenation:: The @code{.str} builtin
+* Convert a number to a hex:: The @code{.hex} builtin
+* Convert a string to uppercase:: The @code{.upcase} builtin
+* Convert a string to lowercase:: The @code{.downcase} builtin
+* Getting part of a string:: The @code{.substr} builtin
+* List splicing:: The @code{.splice} builtin
+* Number generation:: The @code{.iota} builtin
+* Mapping a macro over a list:: The @code{.map} builtin
+* Applying a macro to a list:: The @code{.apply} builtin
+* Defining a macro inline:: The @code{.pmacro} builtin
+* Passing macros as arguments:: Passing a macro to another macro
+@end menu
+
+@node Defining a preprocessor macro
+@section Defining a preprocessor macro
+@cindex define-pmacro
+
+Preprocessor macros are defined with:
+
+@smallexample
+(define-pmacro (name parm1 parm2 ... parmN)
+ expansion
+)
+@end smallexample
+
+The result is @samp{expansion} with parameters replaced with the actual
+arguments of the macro invocation. Free variables are left unchanged.
+[A "free variable", as defined here, is one that doesn't appear in the
+parameter list.]
+
+@c ??? This used to be true, but currently isn't.
+@c If the result is another macro invocation, it is expanded in turn.
+
+@samp{expansion} must be exactly one expression.
+
+@node Using preprocessor macros
+@section Using preprocessor macros
+
+Preprocessor macros are invoked in either of two ways: positional arguments
+and arguments by name.
+@c Rather lame wording.
+
+@smallexample
+(define-pmacro (foo arg1 arg2) (bar arg1 arg2))
+
+; Invoke by positional arguments.
+
+(foo abc def) ==> (bar abc def)
+
+; Invoke by naming arguments.
+
+(foo #:arg1 ghi #:arg2 jkl) ==> (bar ghi jkl)
+@end smallexample
+
+@c If you think more should be said here, I agree.
+@c Please think of something.
+
+@node Macro expansion
+@section Macro expansion
+
+At the implementation level, pmacros are expand with the
+@code{pmacro-expand} Scheme procedure.
+
+The following is executed from a Guile shell, as opposed to
+appearing in a cpu description file, hence the extra quoting.
+
+@smallexample
+guile> (define-pmacro '(foo a b) '(+ a b))
+guile> (pmacro-expand '(foo 3 4))
+(+ 3 4)
+@end smallexample
+
+@node Default argument values
+@section Default argument values
+
+Invoking pmacros by specifying argument names allows some, or all,
+arguments to be elided and thus allows for arguments to have default values.
+
+Specify default values with the following syntax.
+
+@smallexample
+(define-pmacro (macro-name (arg1 . default-value)
+ (arg2 . default value) ...)
+ ...
+)
+@end smallexample
+
+Example:
+
+@smallexample
+(define-pmacro (foo (arg1 . 1) (arg2 . 2))
+ (bar arg1 arg2)
+)
+
+(foo #:arg2 33) ==> (bar 1 33)
+@end smallexample
+
+@node Multiple output expressions
+@section Multiple output expressions
+@cindex begin
+
+The result of a preprocessor macro is exactly one expression.
+It is often useful, however, to return multiple expressions, say for
+example when you want one macro to define several instructions.
+
+The way to do this is to enclose all the expressions with @code{begin}.
+@code{begin} is only valid at the top [definition] level.
+
+??? It's moderately clumsy to restrict @code{begin} like this.
+Using @code{sequence} for this purpose might be cleaner except that
+sequence locals don't make sense in this context (though perhaps that's
+a lesser evil). In the end, @code{begin} can be shorthand for a void-mode
+sequence with no locals so I haven't been in a rush to resolve this.
+
+@node Symbol concatenation
+@section Symbol concatenation
+@cindex .sym
+
+Symbol and string concatenation are supported. Symbol concatenation is
+done with:
+
+@code{(.sym arg1 arg2 ...)}
+
+Acceptable arguments are symbols, strings, and numbers.
+The result is a symbol with the arguments concatenated together.
+Numbers are converted to a string, base 10, and then to a symbol.
+The result must be a valid Scheme symbol with the additional restriction
+that the first character must be a letter.
+
+@node String concatenation
+@section String concatenation
+@cindex .str
+
+String concatenation is done with
+
+@code{(.str arg1 arg2 ...)}
+
+Acceptable arguments are symbols, strings, and numbers. The result is a
+string with the arguments concatenated together.
+Numbers are converted base 10.
+
+Example:
+
+@smallexample
+(define-pmacro (bin-op mnemonic op2-op sem-op)
+ (dni mnemonic
+ (.str mnemonic " reg/reg")
+ ()
+ (.str mnemonic " $dr,$sr")
+ (+ OP1_0 op2-op dr sr)
+ (set dr (sem-op dr sr))
+ ())
+)
+(bin-op and OP2_12 and)
+(bin-op or OP2_14 or)
+(bin-op xor OP2_13 xor)
+@end smallexample
+
+@node Convert a number to a hex
+@section Convert a number to a hex
+
+Convert a number to a lowercase hex string with @code{.hex}. If
+@code{width} is present, the result is that many characters beginning
+with the least significant digit. Zeros are prepended as necessary.
+
+Syntax: @code{(.hex number [width])}
+
+Examples:
+
+@smallexample
+(.hex 42) --> "2a"
+(.hex 42 1) --> "a"
+(.hex 42 4) --> "002a"
+@end smallexample
+
+@node Convert a string to uppercase
+@section Convert a string to uppercase
+
+Convert a string to uppercase with @code{.upcase}.
+
+Syntax: @code{(.upcase string)}
+
+Example:
+
+@smallexample
+(.upcase "foo!") --> "FOO!"
+@end smallexample
+
+@node Convert a string to lowercase
+@section Convert a string to lowercase
+
+Convert a string to lowercase with @code{.downcase}.
+
+Syntax: @code{(.downcase string)}
+
+Example:
+
+@smallexample
+(.downcase "BAR?") --> "bar?"
+@end smallexample
+
+@node Getting part of a string
+@section Getting part of a string
+
+Extract a part of a string with @code{.substr}.
+
+Syntax: @code{(.substr string start end)}
+
+where @samp{start} is the starting character, and @samp{end} is one past
+the ending character. Character numbering begins at position 0.
+If @samp{start} and @samp{end} are the same, and both valid, the empty
+string is returned.
+
+Example:
+
+@smallexample
+(.substr "howzitgoineh?" 2 6) --> "wzit"
+@end smallexample
+
+@node List splicing
+@section List splicing
+@cindex .splice
+
+It is often useful to splice a list into a "parent" list.
+This is best explained with an example.
+
+@smallexample
+(define-pmacro (splice-test a b c)
+ (.splice a (.unsplice b) c))
+(pmacro-expand (splice-test (1 (2) 3)))
+
+--> (1 2 3)
+@end smallexample
+
+Note that a level of parentheses around @code{2} has been removed.
+
+This is useful, for example, when one wants to pass a list of fields to
+a macro that defines an instruction. For example:
+
+@smallexample
+(define-pmacro (cond-move-1 name comment mnemonic cc-prefix cc-name cc-opcode
+ src-name src-opcode cond test)
+ (dni name
+ (.str "move %" cc-name " " comment ", v9 page 191")
+ ((MACH64))
+ (.str mnemonic " " cc-prefix cc-name ",$" src-name ",$rd")
+ (.splice + OP_2 rd OP3_MOVCC cond
+ (.unsplice cc-opcode) (.unsplice src-opcode))
+ (if (test cc-name)
+ (set rd src-name))
+ ())
+)
+@end smallexample
+
+This macro, taken from @file{sparc64.cpu}, defines a conditional move
+instruction. Arguments @code{cc-opcode} and @code{src-opcode} are lists
+of fields. The macro is invoked with (simplified from @file{sparc64.cpu}):
+
+@smallexample
+(cond-move-1 mova-icc "blah ..." mova
+ "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
+ rs2 ((f-i 0) (f-fmt4-res10-6 0) rs2)
+ CC_A test-always)
+(cond-move-1 mova-imm-icc "blah ..." mova
+ "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
+ simm11 ((f-i 1) simm11)
+ CC_A test-always)
+@end smallexample
+
+Macro @code{cond-move-1} is being used here to define both the register
+and the immediate value case. Each case has a slightly different list
+of opcode fields. Without the use of @code{.splice}/@code{.unsplice},
+the resulting formats would be:
+
+@smallexample
+(+ OP_2 rd OP3_MOVCC CC_A ((f-fmt4-cc2-1) (f-fmt4-cc1-0 0))
+ ((f-i 0) (f-fmt4-res10-6 0) rs2))
+
+and
+
+(+ OP_2 rd OP3_MOVCC CC_A ((f-fmt4-cc2-1) (f-fmt4-cc1-0 0))
+ ((f-i 1) simm11))
+@end smallexample
+
+respectively. This is not what is wanted. What is wanted is
+
+@smallexample
+(+ OP_2 rd OP3_MOVCC CC_A (f-fmt4-cc2-1) (f-fmt4-cc1-0 0)
+ (f-i 0) (f-fmt4-res10-6 0) rs2)
+
+and
+
+(+ OP_2 rd OP3_MOVCC CC_A (f-fmt4-cc2-1) (f-fmt4-cc1-0 0)
+ (f-i 1) simm11)
+@end smallexample
+
+respectively, which is what @code{.splice} achieves.
+
+@code{.unsplice} is a special reserved symbol that is only recognized inside
+@code{.splice}.
+
+@node Number generation
+@section Number generation
+@cindex .iota
+@cindex Number generation
+
+Machine descriptions often require a list of sequential numbers.
+Generate a list of numbers with the @code{.iota} builtin macro.
+
+The syntax is @samp{(.iota count [start [incr]])}.
+
+Examples:
+
+@smallexample
+(.iota 5) --> 0 1 2 3 4
+(.iota 5 4) --> 4 5 6 7 8
+(.iota 5 5 -1) --> 5 4 3 2 1
+@end smallexample
+
+@node Mapping a macro over a list
+@section Mapping a macro over a list
+@cindex .map
+
+Apply a macro to each element of a list, or set of lists, with @code{.map}.
+
+The syntax is @samp{(.map macro-name list1 [list2 ...])}.
+
+The result is a list with @samp{macro-name} applied to each element of
+@samp{listN}. @samp{macro-name} should take as many arguments as there
+are lists. This is often useful in constructing enum and register name lists.
+
+Example:
+
+@smallexample
+(define-pmacro (foo name number) ((.sym X name) number))
+(.map foo (A B C D E) (.iota 5))
+
+-->
+
+((XA 0) (XB 1) (XC 2) (XD 3) (XE 4))
+@end smallexample
+
+@node Applying a macro to a list
+@section Applying a macro to a list
+
+Invoke a macro with each argument coming from an element of a list,
+with @code{.apply}.
+
+The syntax is @samp{(.apply macro-name list)}.
+
+The result is the result of invoking macro @samp{macro-name}.
+@samp{macro-name} should take as many arguments as there elements in
+@samp{list}. If @samp{macro-name} takes a variable number of trailing
+arguments, there must be at least as many list elements as there are
+fixed arguments.
+@c clumsily worded or what
+
+Example:
+@c need a more useful example
+
+@smallexample
+(.apply .str (.iota 5))
+
+-->
+
+"01234"
+@end smallexample
+
+Note that @code{(.str (.iota 5))} is an error. Here the list
+@samp{(0 1 2 3 4)} is passed as the first argument of @code{.str},
+which is wrong.
+
+@node Defining a macro inline
+@section Defining a macro inline
+
+Define a macro inline with @code{.pmacro}.
+This is only supported when passing macros as arguments to other macros.
+
+@smallexample
+(define-pmacro (load-op suffix op2-op mode ext-op)
+ (begin
+ (dni (.sym ld suffix) (.str "ld" suffix)
+ ()
+ (.str "ld" suffix " $dr,@@$sr")
+ (+ OP1_2 op2-op dr sr)
+ (set dr (ext-op WI (mem: mode sr)))
+ ())
+ )
+)
+
+(load-op "" OP2_12 WI (.pmacro (mode expr) expr))
+(load-op b OP2_8 QI (.pmacro (mode expr) (ext: mode expr)))
+(load-op h OP2_10 HI (.pmacro (mode expr) (ext: mode expr)))
+(load-op ub OP2_9 QI (.pmacro (mode expr) (zext: mode expr)))
+(load-op uh OP2_11 HI (.pmacro (mode expr) (zext: mode expr)))
+@end smallexample
+
+Currently, .pmacro's don't bind the way Scheme lambda expressions do.
+For example, arg2 in the second pmacro is not bound to the arg2 argument
+of the first pmacro.
+
+@smallexample
+(define-pmacro (foo arg1 arg2) ((.pmacro (bar) (+ arg2 bar)) arg1))
+(foo 3 4) ==> (+ arg2 3)
+@end smallexample
+
+One can make an argument either way. I'm not sure what the right thing
+to do here is (leave things as is, or have lexical binding like Scheme).
+
+@node Passing macros as arguments
+@section Passing macros as arguments
+
+Macros may be passed to other macros.
+
+Example:
+
+@smallexample
+(define-pmacro (no-ext-expr mode expr) expr)
+(define-pmacro (ext-expr mode expr) (ext: mode expr))
+(define-pmacro (zext-expr mode expr) (zext: mode expr))
+
+(define-pmacro (load-op suffix op2-op mode ext-op)
+ (begin
+ (dni (.sym ld suffix) (.str "ld" suffix)
+ ()
+ (.str "ld" suffix " $dr,@@$sr")
+ (+ OP1_2 op2-op dr sr)
+ (set dr (ext-op WI (mem: mode sr)))
+ ())
+ )
+)
+
+(load-op "" OP2_12 WI no-ext-expr)
+(load-op b OP2_8 QI ext-expr)
+(load-op h OP2_10 HI ext-expr)
+(load-op ub OP2_9 QI zext-expr)
+(load-op uh OP2_11 HI zext-expr)
+@end smallexample
diff --git a/cgen/doc/porting.texi b/cgen/doc/porting.texi
new file mode 100644
index 00000000000..551953ee845
--- /dev/null
+++ b/cgen/doc/porting.texi
@@ -0,0 +1,863 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Porting
+@chapter Porting
+@cindex Porting
+
+This chapter describes how to do a CGEN port.
+It focuses on doing binutils and simulator ports, but the general
+procedure should be generally applicable.
+
+@menu
+* Introduction to porting::
+* Supported Guile versions::
+* Running configure::
+* Writing a CPU description file::
+* Doing an opcodes port::
+* Doing a GAS port::
+* Building a GAS test suite::
+* Doing a simulator port::
+* Building a simulator test suite::
+@end menu
+
+@node Introduction to porting
+@section Introduction to porting
+
+Doing a GNU tools port for a new processor basically consists of porting the
+following components more or less in order. The order can be changed,
+of course, but the following order is reasonable. Certainly things like
+BFD and opcodes need to be finished earlier than others. Bugs in
+earlier pieces are often not found until testing later pieces so each
+piece isn't necessarily finished until they all are.
+
+@itemize @bullet
+@item DejaGNU
+@item BFD
+@item CGEN
+@item Opcodes
+@item GAS
+@item Binutils
+@item Linker (@code{ld})
+@item newlib
+@item libgloss
+@item simulator
+@item GCC
+@item GDB
+@end itemize
+
+The use of CGEN affects the opcodes, GAS, and simulator portions only.
+As always, the M32R port is a good reference base.
+
+One goal of CGEN is to describe the CPU in an application independent manner
+so that program generators can do all the repetitive work of generating
+code and tables for each CPU that is ported.
+
+For opcodes, several files are generated. No additional code need be
+written in the opcodes directory although as an escape hatch the user
+can add target specific code to file <arch>.opc in the CGEN source
+directory. These functions will be included in the relevant generated
+files. An example of when you need to create an <arch>.opc file is when
+there are special pseudo-ops that need to be parsed, for example the
+high/shigh pseudo-ops of the M32R.
+@xref{Doing an opcodes port}.
+
+For GAS, no files are generated (except test cases!) so the port is done
+more or less like the other GAS ports except that the assembler uses the
+CGEN-built opcode table plus @file{devo/gas/cgen.[ch]}.
+
+For the simulator, several files are built, and other support files need
+to be written. @xref{Doing a simulator port}.
+
+@node Supported Guile versions
+@section Supported Guile versions
+
+In order to avoid suffering from the bug of the day when using
+snapshots, CGEN development has been confined to Guile releases only.
+As of this writing (1999-04-26) only Guile 1.2 and 1.3 are supported.
+At some point in the future older versions of Guile will no longer be
+supported.
+
+If using Guile 1.2, configure it with @code{--enable-guile-debug
+--enable-dynamic-linking} to work around an unknown bug in this version
+of Guile. I ran into this on Solaris 2.6.
+
+@node Running configure
+@section Running @code{configure}
+
+When doing porting or maintenance activity with CGEN, the build tree
+must be configured with the @code{--enable-cgen-maint} option. This
+adds the necessary dependencies to the @file{devo/opcodes} and
+@file{devo/sim} directories.
+
+CGEN uses Guile so it must be installed. At present the CGEN configury
+requires that if Guile isn't installed in @file{/usr/local} then the
+@code{--with-guile=/guile/install/dir} option must be passed to
+@file{configure} to specify where Guile is installed.
+
+@node Writing a CPU description file
+@section Writing a CPU description file
+
+The first step in doing a CGEN port is writing a CPU description file.
+The best way to do that is to take an existing file (such as the M32R)
+and use it as a template.
+
+Writing a CPU description file generally involves writing each of the
+following types of entries, in order. @xref{RTL} for detailed
+descriptions of each type of entry that appears in the description file.
+
+@menu
+* Conventions:: Programming style conventions
+* Writing define-arch:: Architecture wide specs
+* Writing define-isa:: Instruction set characteristics
+* Writing define-cpu:: CPU families
+* Writing define-mach:: Machine variants
+* Writing define-model:: Models of each machine variant
+* Writing define-hardware:: Hardware elements
+* Writing define-ifield:: Instruction fields
+* Writing define-normal-insn-enum:: Instruction enums
+* Writing define-operand:: Instruction operands
+* Writing define-insn:: Instructions
+* Writing define-macro-insn:: Macro instructions
+* Using define-pmacro:: Preprocessor macros
+* Interactive development:: Useful things to do in a Guile shell
+@end menu
+
+@node Conventions
+@subsection Conventions
+
+First a digression on conventions and programming style.
+
+@enumerate 1
+@item @code{define-foo} vs. @code{define-normal-foo}
+
+Each CPU description @code{define-} entry generally provides two forms:
+the normal form and the general form. The normal form has a simple,
+fixed-argument syntax that allows one to specify the most popular
+elements. When one needs to specify more obscure elements of the
+entry one uses the long form which is a list of name/value pairs. The
+naming convention is to call the normal form @code{define-normal-foo}
+and the general form @code{define-foo}.
+
+@item Parentheses placement
+
+Consider:
+
+@example
+(define-normal-insn-enum
+ insn-op1 "insn format enums" () f-op1 OP1_
+ (ADD ADDC SUB SUBC
+ AND OR XOR INV)
+)
+@end example
+
+All Lisp/Scheme code I've read puts the trailing parenthesis on the
+previous line. CGEN programming style says the last trailing
+parenthesis goes on a line by itself. If someone wants to put forth an
+argument of why this should change, please do. I like putting the
+very last parenthesis on a line by itself in column 1 because it makes
+it easier to traverse the file with a parenthesis matching keystroke.
+
+@item @code{StudlyCaps} vs. @code{_} vs. @code{-}
+
+The convention is to have most things lowercase with words separated by
+@samp{-}. Things that are uppercase are fixed and well defined: enum
+values and mode names.
+@c FIXME: Seems to me there's a few others.
+This convention must be followed.
+@end enumerate
+
+@node Writing define-arch
+@subsection Writing define-arch
+
+Various simple and architecture-wide common things like the name of the
+processor must be defined somewhere, so all of this stuff is put under
+@code{define-arch}.
+
+This must be the first entry in the description file.
+
+@node Writing define-isa
+@subsection Writing define-isa
+
+There are two purposes to @code{define-isa}.
+The first is to specify parameters needed to decode instructions.
+
+The second is to give the instruction set a name. This is important for
+architectures like the ARM where one CPU can execute multiple
+instruction sets.
+
+@node Writing define-cpu
+@subsection Writing define-cpu
+
+CPU families are an internal and artificial classification designed to
+collect processor variants that are sufficiently similar together under
+one roof for the simulator. What is ``sufficiently similar'' is up to
+the programmer. For example, if the only difference between two
+processor variants is that one has a few extra instructions, there's no
+point in treating them separately in the simulator.
+
+When simulating the variant without the extra instructions, said
+instructions are marked as ``invalid''. On the other hand, putting 32
+and 64 bit variants of an architecture under one roof is problematic
+since the word size is different. What ``under one roof'' means is left
+fuzzy for now, but basically the simulator engine has a collection of
+structures defining internal state, and ``CPU families'' minimize the
+number of copies of generated code that manipulate this state.
+
+@node Writing define-mach
+@subsection Writing define-mach
+
+CGEN uses ``mach'' in the same sense that BFD uses ``mach''.
+``Mach'', which is short for `machine', defines a variant of
+the architecture.
+
+@c There may be a need for a many-to-one correspondence between CGEN
+@c machs and BFD machs.
+
+@node Writing define-model
+@subsection Writing define-model
+
+When describing a CPU, in any context, there is ``architecture'' and
+there is ``implementation''. In CGEN parlance a ``model'' is an
+implementation of a ``mach''. Models specify pipeline and other
+performance related characteristics of the implementation.
+
+Some architectures bring pipeline details up into the architecture
+(rather than making them an implementation detail). It's not clear
+yet how to handle all the various possibilities so at present this is
+done on a case-by-case basis. Maybe a straightforward solution will
+emerge.
+
+@node Writing define-hardware
+@subsection Writing define-hardware
+
+The registers of the processor are specified with
+@code{define-hardware}. Also, immediate constants and addresses are
+defined to be ``hardware''. By convention, all hardware elements names
+are prefaced with @samp{h-}. This convention must be followed.
+
+Pre-defined hardware elements are:
+
+@table @code
+@item h-memory
+Normal CPU memory@footnote{A temporary simplifying assumption is to treat all
+memory identically. Being able to specify various kinds of memory
+(e.g. on-chip RAM,ROM) is work-in-progress.}
+@item h-sint
+signed integer
+@item h-uint
+unsigned integer
+@item h-addr
+an address
+@item h-iaddr
+an instruction address
+@end table
+
+Where are floats you ask? They'll be defined when the need arises.
+
+The program counter is named @samp{h-pc} and must be specified.
+It is not a builtin element as sometimes architectures need to
+modify its behaviour (in the get/set specs).
+
+@node Writing define-ifield
+@subsection Writing define-ifield
+
+Writing instruction field entries involves analyzing the instruction set
+and creating an entry for each field. If a field has multiple purposes,
+one can create separate entries for each intended purpose. The names
+should generally follow the names used by the architecture reference
+manual.
+
+By convention, all instruction field names are prefaced with @samp{f-}. This
+convention must be followed.
+
+@node Writing define-normal-insn-enum
+@subsection Writing define-normal-insn-enum
+
+Writing instruction enum entries involves analyzing the instruction set
+and attaching names to the opcode fields. For example, if a field named
+@samp{op1} is used to select which of add, addc, sub, subc, and, or,
+xor, and inv instructions, one would write something like the following:
+
+@example
+(define-normal-insn-enum
+ insn-op1 "insn format enums" () f-op1 OP1_
+ (ADD ADDC SUB SUBC
+ AND OR XOR INV)
+)
+@end example
+
+These entries simplify instruction definitions by giving a name to a
+particular value for a particular instruction field. By convention,
+enum names are uppercase. This convention must be followed.
+
+@node Writing define-operand
+@subsection Writing define-operand
+
+Operands are what instruction semantics use to refer to hardware
+elements. The typical use of an operand is to map instruction fields to
+hardware. For example, if field @samp{f-r2} is used to specify one of
+the registers defined by the @code{h-gr} hardware entry, one would
+write:
+
+@code{(dnop sr "source register" () h-gr f-r2)}
+
+@code{dnop} is short for ``define normal operand'' @footnote{A profound
+aversion to typing causes me to often provide brief names of things that
+get typed a lot.}. @xref{RTL} for more information.
+
+@node Writing define-insn
+@subsection Writing define-insn
+
+This involves going through the CPU manual and writing an entry for each
+instruction. Instructions specific to a particular machine variant are
+indicated so with the `MACH' attribute. Example:
+
+@example
+(define-normal-insn
+ add "add instruction
+ ((MACH mach1)) ; or (MACH mach1,mach2,...) for multiple variants
+ ...
+)
+@end example
+
+The `base' machine is a predefined machine variant that includes
+instructions available to all variants, and is the default if no
+`MACH' attribute is specified.
+
+When the @file{.cpu} file is processed, CGEN will analyze the semantics
+to determine:
+
+@itemize @bullet
+@item input operands
+
+The list of hardware elements read by the instruction.
+
+@item output operands
+
+The list of hardware elements written by the instruction.
+
+@item attributes
+
+Instruction attributes that can be computed from the semantics.
+
+CTI: control transfer instruction, generally a branch.
+
+@itemize @bullet
+@item UNCOND-CTI
+
+The instruction unconditionally sets pc.
+
+@item COND-CTI
+
+The instruction conditionally sets pc.
+
+@item SKIP-CTI
+
+NB. This is an expermental attribute. Its usage needs to evolve.
+
+@item DELAY-SLOT
+
+NB. This is an expermental attribute. Its usage needs to evolve.
+@end itemize
+
+@end itemize
+
+CGEN will also try to simplify the semantics as much as possible:
+
+@itemize @bullet
+@item Constant folding
+
+Expressions involving constants are simplified and any resulting
+non-taken paths of conditional expressions are discarded.
+@end itemize
+
+@node Writing define-macro-insn
+@subsection Writing define-macro-insn
+
+Some instructions are really aliases for other instructions, maybe even
+a sequence of them. For example, an architecture that has a general
+decrement-then-store instruction might have a specialized version of
+this instruction called @code{push} supported by the assembler. These
+are handled with ``macro instructions''. Macro instructions are used by
+the assembler/disassembler only. They are not used by the simulator.
+
+@node Using define-pmacro
+@subsection Using define-pmacro
+
+When a group of entries, say instructions, share similar information, a
+macro (in the C preprocessor sense) can be used to simplify the
+description. This can be used to save a lot of typing, which also
+improves readability since often 1 page of code is easier to understand
+than 4.
+
+Here is an example from the M32R port.
+
+@example
+(define-pmacro (bin-op mnemonic op2-op sem-op imm-prefix imm)
+ (begin
+ (dni mnemonic
+ (.str mnemonic " reg/reg")
+ ()
+ (.str mnemonic " $dr,$sr")
+ (+ OP1_0 op2-op dr sr)
+ (set dr (sem-op dr sr))
+ ()
+ )
+ (dni (.sym mnemonic "3")
+ (.str mnemonic " reg/" imm)
+ ()
+ (.str mnemonic "3 $dr,$sr," imm-prefix "$" imm)
+ (+ OP1_8 op2-op dr sr imm)
+ (set dr (sem-op sr imm))
+ ()
+ )
+ )
+)
+(bin-op add OP2_10 add "$hash" slo16)
+(bin-op and OP2_12 and "" uimm16)
+(bin-op or OP2_14 or "$hash" ulo16)
+(bin-op xor OP2_13 xor "" uimm16)
+@end example
+
+@code{.sym/.str} are short for Scheme's @code{symbol-append} and
+@code{string-append} operations and are conceptually the same as the C
+preprocessor's @code{##} concatenation operator. @xref{Symbol
+concatenation} and @xref{String concatenation} for details.
+
+@node Interactive development
+@subsection Interactive development
+
+The normal way@footnote{Normal for me anyway, certainly each person will have
+their own preference} of writing a CPU description file involves starting Guile
+and developing the .CPU file interactively. The basic steps are
+
+@enumerate 1
+@item Run @code{guile}.
+@item @code{(load "dev.scm")}
+@item Load application, e.g. @code{(load-opc)} or @code{(load-sim)}
+@item Load CPU description file, e.g. @code{(cload #:arch "m32r")}
+@item Run generators until output looks reasonable, e.g. @code{(cgen-opc.c)}
+@end enumerate
+
+To assist in the development process and to cut down on some typing,
+@file{dev.scm} looks for @file{$HOME/.cgenrc} and, if present, loads it.
+Typical things that @file{.cgenrc} contains are definitions of procedures
+that combine steps 3 and 4 above.
+
+Example:
+
+@example
+(define (m32r-opc)
+ (load-opc)
+ (cload #:arch "m32r")
+)
+(define (m32r-sim)
+ (load-sim)
+ (cload #:arch "m32r" #:options "with-scache with-profile=fn")
+)
+(define (m32rbf-sim)
+ (load-sim)
+ (cload #:arch "m32r" #:machs "m32r" #:options "with-scache with-profile=fn")
+)
+(define (m32rxf-sim)
+ (load-sim)
+ (cload #:arch "m32r" #:machs "m32rx" #:options "with-scache with-profile=fn")
+)
+@end example
+
+CPU description files are loaded into an interactive guile session with
+@code{cload}. The syntax is:
+
+@example
+(cload #:arch arch
+ [#:machs "mach-list"]
+ [#:isas "isa-list"]
+ [#:options "option-list"])
+@end example
+
+Only the @code{#:arch} argument is mandatory.
+
+@samp{mach-list} is a comma separated string of machines to keep.
+
+@samp{isa-list} is a comma separated string of isas to keep.
+
+@samp{options} is a space separated string of options for the application.
+
+@node Doing an opcodes port
+@section Doing an opcodes port
+
+The best way to begin a port is to take an existing one (preferably one
+that is similar to the new port) and use it as a template.
+
+@enumerate 1
+@item Run @code{guile}.
+@item @code{(load "dev.scm")}. This loads in a set of interactive
+development routines.
+@item @code{(load-opc)}. Load the opcodes support.
+@item Edit your @file{<arch>.cpu} and @file{<arch>.opc} files.
+ @itemize @bullet
+ @item The @file{.cpu} file is the main description file.
+ @item The @file{.opc} file provides additional C support code.
+ @end itemize
+@item @code{(cload #:arch "<arch>")}
+@item Run each of:
+ @itemize @bullet
+ @item @code{(cgen-desc.h)}
+ @item @code{(cgen-desc.c)}
+ @item @code{(cgen-opc.h)}
+ @item @code{(cgen-opc.c)}
+ @item @code{(cgen-ibld.in)}
+ @item @code{(cgen-asm.in)}
+ @item @code{(cgen-dis.in)}
+ @item @code{(cgen-opinst.c)} -- [optional]
+ @end itemize
+@item Repeat steps 4, 5 and 6 until the output looks reasonable.
+@item Add dependencies to @file{opcodes/Makefile.am} to generate the
+eight opcodes files (use the M32R port as an example).
+@item Run @code{make dep} from the @file{opcodes} build directory.
+@item Run @code{make all-opcodes} from the top level build directory.
+@end enumerate
+
+Note that Guile is not currently shipped with Binutils, etc. Until
+Guile is shipped with Binutils, etc. or a C implementation of CGEN is
+done, the generated files are installed in the source directory and
+checked into CVS.
+
+@node Doing a GAS port
+@section Doing a GAS port
+
+A GAS CGEN port is essentially no different than a normal port except
+that the CGEN opcode table is used, and there are extra supporting
+routines available in @file{gas/cgen.[ch]}. As always, a good way to
+get started is to take the M32R port as a template and go from there.
+
+The important CGEN-specific things to keep in mind are:
+@c to be expanded on as time permits
+
+@itemize @bullet
+@item Several support routines are provided by @file{gas/cgen.c}. Some
+must be used, others are available to use if you want to (in general
+they should be used unless it's not possible).
+
+ @itemize @bullet
+ @item @code{gas_cgen_init_parse}
+ @itemize @minus
+ @item Call from @code{md_assemble} before doing anything
+ else.
+ @item Must be used.
+ @end itemize
+ @item @code{gas_cgen_record_fixup}
+ @itemize @minus
+ @item Cover function to @code{fix_new}.
+ @end itemize
+ @item @code{gas_cgen_record_fixup_exp}
+ @itemize @minus
+ @item Cover function to @code{fix_new_exp}.
+ @end itemize
+ @item @code{gas_cgen_parse_operand}
+ @itemize @minus
+ @item Callback for opcode table based parser, set in
+ @code{md_begin}.
+ @end itemize
+ @item @code{gas_cgen_finish_insn}
+ @itemize @minus
+ @item After parsing an instruction, call this to add the
+ instruction to the frag and queue any fixups.
+ @end itemize
+ @item @code{gas_cgen_md_apply_fix3}
+ @itemize @minus
+ @item Provides basic @code{md_apply_fix3} support.
+ @item @code{#define md_apply_fix3
+ gas_cgen_md_apply_fix3} if you're able to use
+ it.
+ @end itemize
+ @item @code{gas_cgen_tc_gen_reloc}
+ @itemize @minus
+ @item Provides basic @code{tc_gen_reloc} support in function.
+ @item @code{#define tc_gen_reloc gas_cgen_tc_gen_reloc}
+ if you're able to use it.
+ @end itemize
+ @end itemize
+
+@item @code{md_begin} should contain the following (plus anything else you
+want of course):
+
+@example
+ /* Set the machine number and endianness. */
+ gas_cgen_opcode_desc =
+ <arch>_cgen_opcode_open (CGEN_CPU_OPEN_MACHS,
+ 0 /* mach number */,
+ CGEN_CPU_OPEN_ENDIAN,
+ (target_big_endian
+ ? CGEN_ENDIAN_BIG
+ : CGEN_ENDIAN_LITTLE),
+ CGEN_CPU_OPEN_END);
+
+ <arch>_cgen_init_asm (gas_cgen_opcode_desc);
+
+ /* This is a callback from cgen to gas to parse operands. */
+ cgen_set_parse_operand_fn (gas_cgen_opcode_desc, gas_cgen_parse_operand);
+@end example
+
+@item @code{md_assemble} should contain the following basic framework:
+
+@example
+@{
+ const CGEN_INSN *insn;
+ char *errmsg;
+ CGEN_FIELDS fields;
+#if CGEN_INT_INSN_P
+ cgen_insn_t buffer[CGEN_MAX_INSN_SIZE / sizeof (CGEN_INSN_INT)];
+#else
+ char buffer[CGEN_MAX_INSN_SIZE];
+#endif
+
+ gas_cgen_init_parse ();
+
+ insn = m32r_cgen_assemble_insn (gas_cgen_opcode_desc, str,
+ &fields, buffer, &errmsg);
+
+ if (! insn)
+ @{
+ as_bad (errmsg);
+ return;
+ @}
+
+ gas_cgen_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (&fields),
+ relax_p, /* non-zero to allow relaxable insns */
+ result); /* non-null if results needed for later */
+@}
+@end example
+
+@end itemize
+
+@node Building a GAS test suite
+@section Building a GAS test suite
+
+CGEN can also build the template for test cases for all instructions. In
+some cases it can also generate the actual instructions. The result is
+then assembled, disassembled, verified, and checked into CVS. Further
+changes are usually done by hand as it's easier. The goal here is to
+save the enormous amount of initial typing that is required.
+
+@enumerate 1
+@item @code{cd} to the CGEN build directory
+@item @code{make gas-test}
+
+At this point two files have been created in the CGEN build directory:
+@file{gas-allinsn.exp} and @file{gas-build.sh}.
+
+@item Copy @file{gas-allinsn.exp} to @file{devo/gas/testsuite/gas/<arch>/allinsn.exp}.
+@item @code{sh gas-build.sh $build/gas}
+
+At this point directory tmpdir contains two files: @file{allinsn.s} and
+@file{allinsn.d}. File @file{allinsn.d} usually needs a bit of massaging.
+
+@item Copy @file{tmpdir/allinsn.[sd]} to @file{devo/gas/testsuite/gas/<arch>}
+@item Run @code{make check} in the @file{gas} build directory and
+massage things until you're satisfied the files are correct.
+@item Check files into CVS.
+@end enumerate
+
+At this point further additions/modifications are usually done by hand.
+
+@node Doing a simulator port
+@section Doing a simulator port
+
+The same basic procedure for opcodes porting applies here.
+
+@enumerate 1
+@item Run @code{guile}.
+@item @code{(load "dev.scm")}
+@item @code{(load-sim)}
+@item Edit your @file{<arch>.cpu} file.
+@item @code{(cload #:arch "<arch>")}
+@item Run each of:
+ @itemize @bullet
+ @item @code{(cgen-arch.h)}
+ @item @code{(cgen-arch.c)}
+ @item @code{(cgen-cpuall.h)}
+ @end itemize
+@item Repeat steps 4,5,6 until the output looks reasonable.
+@item Edit your <arch>.cpu file.
+@item @code{(cload #:arch "<arch>" #:machs "mach1[,mach2[,...]]")}
+@item Run each of:
+ @itemize @bullet
+ @item @code{(cgen-cpu.h)}
+ @item @code{(cgen-cpu.c)}
+ @item @code{(cgen-decode.h)}
+ @item @code{(cgen-decode.c)}
+ @item @code{(cgen-semantics.c)}
+ @item @code{(cgen-sem-switch.c)} -- only if using a switch()
+ version of semantics.
+ @item @code{(cgen-model.c)}
+ @end itemize
+@item Repeat steps 8, 9 and 10 until the output looks reasonable.
+@end enumerate
+
+The following additional files are also needed. These live in the
+@file{sim/<arch>} directory. Administrivia files like
+@file{configure.in} and @file{Makefile.in} are omitted.
+
+@itemize @bullet
+@item @file{sim-main.h}
+
+Main include file required by the ``common'' (@file{sim/common})
+support, and by each target's @file{.c} file.
+This file includes the relevant other headers.
+The order is fairly important.
+@file{m32r/sim-main.h} is a good starting point.
+
+@file{sim-main.h} also defines several types:
+
+@itemize @minus
+@item @code{_sim_cpu} -- a struct containing all state for a
+particular CPU.
+@item @code{sim_state} -- contains all state of the simulator.
+A @code{SIM_DESC} (which is the result of sim_open and is akin
+to a file descriptor) points to one of these.
+@item @code{sim_cia} -- type of an instruction address. For
+CGEN this is generally ``word mode'', in GCC parlance.
+@end itemize
+
+@file{sim-main.h} also defines several macros:
+
+@itemize @minus
+@item @code{CIA_GET(cpu)} -- return ``cia'' of the CPU
+@item @code{CIA_SET(cpu,cia)} -- set the ``cia'' of the CPU
+@end itemize
+
+``cia'' is short for "current instruction address".
+
+The definition of @code{sim_state} is fairly simple. Just copy the M32R
+case. The definition of @code{_sim_cpu} is not simple, so pay
+attention. The complexity comes from trying to create a ``derived
+class'' of @code{sim_cpu} for each CPU family. What is done is define a
+different version of @code{sim_cpu} in each CPU family's set of files,
+with a common ``base class'' structure ``leading part'' for each
+@code{sim_cpu} definition used by non-CPU-family specific files. The
+way this is done is by defining @code{WANT_CPU_<CPU-FAMILY-NAME>} at the
+top of CPU family specific files. The definition of @code{_sim_cpu} is
+then:
+
+@example
+ struct _sim_cpu @{
+ /* sim/common CPU base */
+ sim_cpu_base base;
+ /* Static parts of CGEN. */
+ CGEN_CPU cgen_CPU;
+ #if defined (WANT_CPU_CPUFAM1)
+ CPUFAM1_CPU_DATA CPU_data;
+ #elif defined (WANT_CPU_CPUFAM2)
+ CPUFAM2_CPU_DATA CPU_data;
+ #endif
+ @};
+@end example
+
+@item @file{tconfig.in}
+
+This file predates @file{sim-main.h} and was/is intended to contain
+macros that configure the simulator sources.
+
+@itemize @bullet
+@item @code{SIM_HAVE_MODEL} -- enable @file{common/sim-model.[ch]}
+support.
+@item @code{SIM_HANDLES_LMA} -- makes @file{sim-hload.c} do the right
+thing.
+@item @code{WITH_SCACHE_PBB} -- define this to 1 if using pbb scaching.
+@end itemize
+
+@item @file{<arch>-sim.h}
+
+This file predates @file{sim-main.h} and contains miscellaneous macros
+and definitions used by the simulator.
+
+@item @file{mloop.in}
+
+This file contains code to implement the fetch/execute process. There
+are various ways to do this, and several are supported. Which one to
+choose depends on the environment in which the CPU will be used. For
+example when executing a program in a single-CPU environment without
+devices, most or all available cycles can be devoted to simulation of the
+atarget CPU. However, in an environment with devices or multiple cpus, one
+may wish the CPU to execute one instruction then relinquish control so a
+device operation may be done or an instruction can be simulated on a
+second cpu. Efficient techniques for the former aren't necessarily the best
+for the latter.
+
+Three versions are currently supported:
+
+@enumerate 1
+@item simple -- fetch/decode/execute one insn
+@item scache -- same as simple but results of decoding are cached
+@item pbb -- same as scache but several insns are handled each iteration
+pbb stands for pseudo basic block.
+@end enumerate
+
+This file is processed by @file{common/genmloop.sh} at build time. The
+result is two files: @file{mloop.c} and @file{eng.h}.
+
+@item @file{sim-if.c}
+
+By convention this file contains @code{sim_open}, @code{sim_close},
+@code{sim_create_inferior}, @code{sim_do_command}. These functions can
+live in any file of course. They're here because they're the parts of
+the @code{remote-sim.h} interface that aren't provided by the common
+directory.
+
+@item @file{<cpufam>.c}
+
+By convention this file contains register access and model support
+functions for a CPU family (the name of this file is misnamed in the
+M32R case). The register access functions implement the
+@code{sim_fetch_register} and @code{sim_store_register} interface
+functions (named @code{<cpufam>_@{fetch,store@}_register}), and support
+code for register get/set rtl. The model support functions implement the
+before/after handlers (functions that handle tracing/profiling) and
+timing for each function unit.
+
+@item Other files
+
+The M32R port has two other handwritten files: @file{devices.c} and
+@file{traps.c}. How you wish to organize this is up to you.
+@end itemize
+
+@node Building a simulator test suite
+@section Building a simulator test suite
+
+CGEN can also build the template for test cases for all instructions. In
+some cases it can also generate the actual instructions
+@footnote{Although this hasn't been implemented yet.}. The result is
+then verified and checked into CVS. Further changes are usually done by
+hand as it's easier. The goal here is to save the enormous amount of
+initial typing that is required.
+
+@enumerate 1
+@item @code{cd} to the CGEN build directory
+@item @code{make sim-test}
+
+At this point two files have been created in the CGEN build directory:
+@file{sim-allinsn.exp} and @file{sim-build.sh}.
+
+@item Copy @file{sim-allinsn.exp} to
+@file{devo/sim/testsuite/sim/<arch>/allinsn.exp}.
+@item @code{sh sim-build.sh}
+
+At this point a new subdirectory called @file{tmpdir} will be created
+and will contain one test case for each instruction. The framework has
+been filled in but not the actual test case. It's handy to write an
+``include file'' containing assembler macros that simplify writing test
+cases. See @file{devo/sim/testsuite/sim/m32r/testutils.inc} for an
+example.
+
+@item write testutils.inc
+@item finish each test case
+@item copy @file{tmpdir/*.cgs} to @file{devo/sim/testsuite/sim/<arch>}
+@item run @code{make check} in the sim build directory and massage things until you're satisfied the files are correct
+@item Check files into CVS.
+@end enumerate
+
+@noindent At this point further additions/modifications are usually done
+by hand.
diff --git a/cgen/doc/rtl.texi b/cgen/doc/rtl.texi
new file mode 100644
index 00000000000..3e740dbf31c
--- /dev/null
+++ b/cgen/doc/rtl.texi
@@ -0,0 +1,2276 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node RTL
+@chapter CGEN's Register Transfer Language
+@cindex RTL
+@cindex Register Transfer Language
+
+CGEN uses a variant of GCC's Register Transfer Language as the basis for
+its CPU description language.
+
+@menu
+* RTL Introduction:: Introduction to CGEN's RTL
+* Trade-offs:: Various trade-offs in the design
+* Rules and notes:: Rules and notes common to all entries
+* Definitions:: Definitions in the description file
+* Attributes:: Random data associated with any entry
+* Architecture variants:: Specifying variations of a CPU
+* Model variants:: Specifying variations of a CPU's implementation
+* Hardware elements:: Elements of a CPU
+* Instruction fields:: Fields of an instruction
+* Enumerated constants:: Assigning useful names to important numbers
+* Instruction operands::
+* Derived operands:: Operands for CISC-like architectures
+* Instructions::
+* Macro-instructions::
+* Modes::
+* Expressions::
+* Macro-expressions::
+@end menu
+
+@node RTL Introduction
+@section RTL Introduction
+
+The description language, or RTL
+@footnote{While RTL stands for Register Transfer Language, it is also used
+to denote the CPU description language as a whole.}, needs to support the
+definition of all the
+architectural and implementation features of a CPU, as well as enough
+information for all intended applications. At present this is just the
+opcodes table and an ISA level simulator, but it is not intended that
+applications be restricted to these two areas. The goal is having an
+application independent description of the CPU. In the end that's a lot to
+ask for from one language. Certainly gate level specification of a CPU
+is not attempted!
+
+The syntax of the language is inspired by GCC's RTL and by the Scheme
+programming language, theoretically taking the best of both. To what
+extent that is true, and to what extent that is sufficient inspiration
+is certainly open to discussion. In actuality, there isn't much difference
+here from GCC's RTL that is attributable to being Scheme-ish. One
+important Scheme-derived concept is arbitrary precision of constants.
+Sign or zero extension of constants in GCC has always been a source of
+problems. In CGEN'S RTL constants have modes and there are both signed
+and unsigned modes.
+
+Here is a graphical layout of the hierarchy of elements of a @file{.cpu}
+file.
+
+@example
+ architecture
+ / \
+ cpu-family1 cpu-family2 ...
+ / \ / \
+ machine1 machine2 machine3 ...
+ / \
+ model1 model2 ...
+@end example
+
+Each of these elements is explained in more detail below. The
+@emph{architecture} is one of @samp{sparc}, @samp{m32r}, etc. Within
+the @samp{sparc} architecture, @emph{cpu-family} might be
+@samp{sparc32}, @samp{sparc64}, etc. Within the @samp{sparc32} CPU
+family, the @emph{machine} might be @samp{sparc-v8}, @samp{sparclite},
+etc. Within the @samp{sparc-v8} machine classification, @emph{model}
+might be @samp{hypersparc}, @samp{supersparc}, etc.
+
+Instructions form their own hierarchy as each instruction may be supported
+by more than one machine. Also, some architectures can handle more than
+one instruction set on one chip (e.g. ARM).
+
+@example
+ isa
+ |
+ instruction
+ / \
+ operand1 operand2 ...
+ | |
+ hw1+ifield1 hw2+ifield2 ...
+@end example
+
+Each of these elements is explained in more detail below.
+
+@node Trade-offs
+@section Trade-offs
+
+While CGEN is written in Scheme, this is not a requirement. The
+description language should be considered absent of any particular
+implementation, though certainly some things were done to simplify
+reading @file{.cpu} files with Scheme. Scheme related choices have been
+made in areas that have no serious impact on the usefulness of the CPU
+description language. Places where that is not the case need to be
+revisited, though there currently are no known ones.
+
+One place where the Scheme implementation influenced the design of
+CGEN's RTL is in the handling of modes. The Scheme implementation was
+simplified by treating modes as an explicit argument, rather than as an
+optional suffix of the operation name. For example, compare @code{(add
+SI dr sr)} in CGEN versus @code{(add:SI dr sr)} in GCC RTL. The mode is
+treated as optional so a shorthand form of @code{(add dr sr)} works.
+
+@node Rules and notes
+@section Rules and notes
+
+A few basic guidelines for all entries:
+
+@itemize @bullet
+@item names must be valid Scheme symbols.
+@item comments are used, for example, to comment the generated C code
+@footnote{It is possible to produce a reference manual from
+@file{.cpu} files and such an application wouldn't be a bad idea.}.
+@item comments may be any number of lines, though generally succinct comments
+are preferable@footnote{It would be reasonable to have a short form
+and a long form of comment. Either as two entries are as one entry with
+the short form separated from the long form via some delimiter (say the
+first newline).}.
+@item everything is case sensitive.@footnote{??? This is true in RTL,
+though some apps add symbols and convert case that can cause collisions.}
+@item while "_" is a valid character to use in symbols, "-" is preferred
+@item except for the @samp{comment} and @samp{attrs} fields and unless
+otherwise specified all fields must be present.
+@end itemize
+
+Symbols and strings
+
+Symbols in CGEN are the same as in Scheme.
+Symbols can be used anywhere a string can be used.
+The reverse is not true, and in general strings can't be used in place
+of symbols.
+
+@node Definitions
+@section Definitions
+@cindex Definitions
+
+Each entry has the same format: @code{(define-foo arg1 arg2 ...)}, where
+@samp{foo} designates the type of entry (e.g. @code{define-insn}). In
+the general case each argument is a name/value pair expressed as
+@code{(name value)}.
+(*note: Another style in common use is `:name value' and doesn't require
+parentheses. Maybe that would be a better way to go here. The current
+style is easier to construct from macros though.)
+
+While the general case is flexible, it also is excessively verbose in
+the normal case. To reduce this verbosity, a second version of most
+define-foo's exists that takes positional arguments. To further reduce
+this verbosity, preprocessor macros can be written to simplify things
+further for the normal case. See sections titled ``Simplification
+macros'' below.
+
+@node Attributes
+@section Attributes
+@cindex Attributes
+
+Attributes are used throughout for specifying various properties.
+For portability reasons attributes can only have 32 bit integral values
+(signed or unsigned).
+@c How about an example?
+
+There are four kinds of attributes: boolean, integer, enumerated, and bitset.
+Boolean attributes can be achieved via others, but they occur frequently
+enough that they are special cased (and one bit can be used to record them).
+Bitset attributes are a useful simplification when one wants to indicate an
+object can be in one of many states (e.g. an instruction may be supported by
+multiple machines).
+
+String attributes might be a useful addition.
+Another useful addition might be functional attributes (the attribute
+is computed at run-time - currently all attributes are computed at
+compile time). One way to implement functional attributes would be to
+record the attributes as byte-code and lazily evaluate them, caching the
+results as appropriate. The syntax has been carefully done to not
+preclude either as an upward compatible extension.
+
+Attributes must be defined before they can be used.
+There are several predefined attributes for entry types that need them
+(instruction field, hardware, operand, and instruction). Predefined
+attributes are documented in each relevant section below.
+
+In C applications an enum is created that defines all the attributes.
+Applications that wish to be architecture independent need the attribute
+to have the same value across all architectures. This is achieved by
+giving the attribute the INDEX attribute, which specifies the enum value
+must be fixed across all architectures.
+@c FIXME: Give an example here.
+@c FIXME: Need a better name than `INDEX'.
+
+Convention requires attribute names consist of uppercase letters, numbers,
+"-", and "_", and must begin with a letter.
+To be consistent with Scheme, "-" is preferred over "_".
+
+@subsection Boolean Attributes
+@cindex Attributes, boolean
+
+Boolean attributes are defined with:
+
+@example
+(define-attribute
+ (type boolean)
+ (for user-list)
+ (name attribute-name)
+ (comment "attribute comment")
+ (attrs attribute-attributes)
+)
+@end example
+
+The default value of boolean attributes is always false. This can be
+relaxed, but it's one extra complication that is currently unnecessary.
+Boolean attributes are specified in either of two forms: (NAME expr),
+and NAME, !NAME. The first form is the canonical form. The latter two
+are shorthand versions. `NAME' means "true" and `!NAME' means "false".
+@samp{expr} is an expression that evaluates to 0 for false and non-zero
+for true @footnote{The details of @code{expr} is still undecided.}.
+
+@code{user-list} is a space separated list of entry types that will use
+the attribute. Possible values are: @samp{attr}, @samp{enum},
+@samp{cpu}, @samp{mach}, @samp{model}, @samp{ifield}, @samp{hardware},
+@samp{operand}, @samp{insn} and @samp{macro-insn}. If omitted all are
+considered users of the attribute.
+
+@subsection Integer Attributes
+@cindex Attributes, integer
+
+Integer attributes are defined with:
+
+@example
+(define-attribute
+ (type integer)
+ (for user-list)
+ (name attribute-name)
+ (comment "attribute comment")
+ (attrs attribute-attributes)
+ (default expr)
+)
+@end example
+
+If omitted, the default is 0.
+
+(*note: The details of `expr' is still undecided. For now it must be
+an integer.)
+
+Integer attributes are specified with (NAME expr).
+
+@subsection Enumerated Attributes
+@cindex Attributes, enumerated
+
+Enumerated attributes are the same as integer attributes except the
+range of possible values is restricted and each value has a name.
+Enumerated attributes are defined with
+
+@example
+(define-attribute
+ (type enum)
+ (for user-list)
+ (name attribute-name)
+ (comment "attribute comment")
+ (attrs attribute-attributes)
+ (values enum-value1 enum-value2 ...)
+ (default expr)
+)
+@end example
+
+If omitted, the default is the first specified value.
+
+(*note: The details of `expr' is still undecided. For now it must be the
+name of one of the specified values.)
+
+Enum attributes are specified with (NAME expr).
+
+@subsection Bitset Attributes
+@cindex Attributes, bitset
+
+Bitset attributes are for situations where you want to indicate something
+is a subset of a small set of possibilities. The MACH attribute uses this
+for example to allow specifying which of the various machines support a
+particular insn.
+(*note: At present the maximum number of possibilities is 32.
+This is an implementation restriction which can be relaxed, but there's
+currently no rush.)
+
+Bitset attributes are defined with:
+
+@example
+(define-attribute
+ (type bitset)
+ (for user-list)
+ (name attribute-name)
+ (comment "attribute comment")
+ (attrs attribute-attributes)
+ (values enum-value1 enum-value2 ...)
+ (default default-name)
+)
+@end example
+
+@samp{default-name} must be the name of one of the specified values. If
+omitted, it is the first value.
+
+Bitset attributes are specified with @code{(NAME val1,val2,...)}. There
+must be no spaces in ``@code{val1,val2,...}'' and each value must be a
+valid Scheme symbol.
+
+(*note: it's not clear whether allowing arbitrary expressions will be
+useful here, but doing so is not precluded. For now each value must be
+the name of one of the specified values.)
+
+@node Architecture variants
+@section Architecture Variants
+@cindex Architecture variants
+
+The base architecture and its variants are described in four parts:
+@code{define-arch}, @code{define-isa}, @code{define-cpu}, and
+@code{define-mach}.
+
+@menu
+* define-arch::
+* define-isa::
+* define-cpu::
+* define-mach::
+@end menu
+
+@node define-arch
+@subsection define-arch
+@cindex define-arch
+
+@code{define-arch} describes the overall architecture, and must be
+present.
+
+The syntax of @code{define-arch} is:
+
+@example
+(define-arch
+ (name architecture-name) ; e.g. m32r
+ (comment "description") ; e.g. "Mitsubishi M32R"
+ (attrs attribute-list)
+ (default-alignment aligned|unaligned|forced)
+ (insn-lsb0? #f|#t)
+ (machs mach-name-list)
+ (isas isa-name-list)
+)
+@end example
+
+@subsubsection default-alignment
+
+Specify the default alignment to use when fetching data (and
+instructions) from memory. At present this can't be overridden, but
+support can be added if necessary. The default is @code{aligned}.
+
+@subsubsection insn-lsb0?
+@cindex insn-lsb0?
+
+Specifies whether the most significant or least significant bit in a
+word is bit number 0. Generally this should conform to the convention
+in the architecture manual. This is independent of endianness and is an
+architecture wide specification. There is no support for using
+different bit numbering conventions within an architecture.
+@c Not that such support can't be added of course.
+
+Instruction fields are always numbered beginning with the most
+significant bit. That is, the `start' of a field is always its most
+significant bit. For example, a 4 bit field in the uppermost bits of a
+32 bit instruction would have a start/length of (31 4) when insn-lsb0? =
+@code{#t}, and (0 4) when insn-lsb0? = @code{#f}.
+
+@subsubsection mach-name-list
+
+The list of names of machines in the architecture.
+There should be one entry for each @code{define-mach}.
+
+@subsubsection isa-name-list
+
+The list of names of instruction sets in the architecture.
+There must be one for each @code{define-isa}.
+An example of an architecture with more than one is the ARM which
+has a 32 bit instruction set and a 16 bit "Thumb" instruction set
+(the sizes here refer to instruction size).
+
+@node define-isa
+@subsection define-isa
+@cindex define-isa
+
+@code{define-isa} describes aspects of the instruction set.
+A minimum of one ISA must be defined.
+
+The syntax of @code{define-isa} is:
+
+@example
+(define-isa
+ (name isa-name)
+ (comment "description")
+ (attrs attribute-list)
+ (default-insn-word-bitsize n)
+ (default-insn-bitsize n)
+ (base-insn-bitsize n)
+ (decode-assist (b0 b1 b2 ...))
+ (liw-insns n)
+ (parallel-insns n)
+ (condition ifield-name expr)
+ (setup-semantics expr)
+ (decode-splits decode-split-list)
+ ; ??? missing here are fetch/execute specs
+)
+@end example
+
+@subsubsection default-insn-word-bitsize
+
+Specifies the default size of an instruction word in bits.
+This affects the numbering of field bits in words beyond the
+base instruction.
+@xref{Instruction fields} for more information.
+
+??? There is currently no explicit way to specify a different instruction
+word bitsize for particular instructions, it is derived from the instruction
+field specs.
+
+@subsubsection default-insn-bitsize
+
+The default size of an instruction in bits. It is generally the size of
+the smallest instruction. It is used when parsing instruction fields.
+It is also used by the disassembler to know how many bytes to skip for
+unrecognized instructions.
+
+@subsubsection base-insn-bitsize
+
+The minimum size of an instruction, in bits, to fetch during execution.
+If the architecture has a variable length instruction set, this is the
+size of the initial word to fetch. There is no need to specify the
+maximum length of an instruction, that can be computed from the
+instructions. Examples:
+
+@table @asis
+@item i386
+8
+@item M68k
+16
+@item SPARC
+32
+@item M32R
+32
+@end table
+
+The M32R case is interesting because instructions can be 16 or 32 bits.
+However instructions on 32 bit boundaries can always be fetched 32 bits
+at a time as 16 bit instructions always come in pairs.
+
+@subsubsection decode-assist
+@cindex decode-assist
+
+Which bits to initially use to decode the instruction.
+For example on the SPARC these are bits: 31 30 24 23 22 21 20 19.
+The rest of the decoder is machine generated.
+The intent of @code{decode-assist} is to give the machine generated
+code a head start.
+
+??? It might be useful to provide greater control, but this is sufficient
+for now.
+
+It is okay if the opcode bits are over-specified for some instructions.
+It is also okay if the opcode bits are under-specified for some instructions.
+The machine generated decoder will properly handle both these situations.
+Just pick a useful number of bits that distinguishes most instructions.
+It is usually best to not pick more than 8 bits to keep the size of the
+initial decode table down.
+
+Bit numbering is defined by the @code{insn-lsb0?} field.
+
+@subsubsection liw-insns
+@cindex liw-insns
+
+The number of instructions the CPU always fetches at once. This is
+intended for architectures like the M32R, and does not refer to a CPU's
+ability to pre-fetch instructions. The default is 1.
+
+@subsubsection parallel-insns
+@cindex parallel-insns
+
+The maximum number of instructions the CPU can execute in parallel. The
+default is 1.
+
+??? Rename this to @code{max-parallel-insns}?
+
+@subsubsection condition
+
+Some architectures like ARM and ARC conditionally execute every instruction
+based on the condition specified by one instruction field.
+The @code{condition} spec exists to support these architectures.
+@code{ifield-name} is the name of the instruction field denoting the
+condition and @code{expression} is an RTL expressions that returns
+the value of the condition (false=zero, true=non-zero).
+
+@subsubsection setup-semantics
+
+Specify a statement to be performed prior to executing particular instructions.
+This is used, for example, on the ARM where the value of the program counter
+(general register 15) is a function of the instruction (it is either
+pc+8 or pc+12, depending on the instruction).
+
+@subsubsection decode-splits
+
+Specify a list of field names and values to split instructions up by.
+This is used, for example, on the ARM where the behavior of some instructions
+is quite different when the destination register is r15 (the pc).
+
+The syntax is:
+
+@example
+(decode-splits
+ (ifield1-name
+ constraints
+ ((split1-name (value1 value2 ...)) (split2-name ...)))
+ (ifield2-name
+ ...)
+)
+@end example
+
+@code{constraints} is work-in-progress and should be @code{()} for now.
+
+One copy of each instruction satisfying @code{constraint} is made
+for each specified split. The semantics of each copy are then
+simplified based on the known values of the specified instruction field.
+
+@node define-cpu
+@subsection define-cpu
+@cindex define-cpu
+
+@code{define-cpu} defines a ``CPU family'' which is a programmer
+specified collection of related machines. What constitutes a family is
+work-in-progress however it is intended to distinguish things like
+sparc32 vs sparc64. Machines in a family are sufficiently similar that
+the simulator semantic code can handle any differences at run time. At
+least that's the current idea. A minimum of one CPU family must be
+defined.
+@footnote{FIXME: Using "cpu" in "cpu-family" here is confusing.
+Need a better name. Maybe just "family"?}
+
+The syntax of @code{define-cpu} is:
+
+@example
+(define-cpu
+ (name cpu-name)
+ (comment "description")
+ (attrs attribute-list)
+ (endian big|little|either)
+ (insn-endian big|little|either)
+ (data-endian big|little|either)
+ (float-endian big|little|either)
+ (word-bitsize n)
+ (parallel-insns n)
+ (file-transform transformation)
+)
+@end example
+
+@subsubsection endian
+
+The endianness of the architecture is one of three values: @code{big},
+@code{little} and @code{either}.
+
+An architecture may have multiple endiannesses, including one for each
+of: instructions, integers, and floats (not that that's intended to be the
+complete list). These are specified with @code{insn-endian},
+@code{data-endian}, and @code{float-endian} respectively.
+
+Possible values for @code{insn-endian} are: @code{big}, @code{little},
+and @code{either}. If missing, the value is taken from @code{endian}.
+
+Possible values for @code{data-endian} and @code{float-endian} are: @code{big},
+@code{big-words}, @code{little}, @code{little-words} and @code{either}.
+If @code{big-words} then each word is little-endian.
+If @code{little-words} then each word is big-endian.
+If missing, the value is taken from @code{endian}.
+
+??? Support for these is work-in-progress. All forms are recognized
+by the @file{.cpu} file reader, but not all are supported internally.
+
+@subsubsection word-bitsize
+
+The number of bits in a word. In GCC, this is @code{BITS_PER_WORD}.
+
+@subsubsection parallel-insns
+
+This is the same as the @code{parallel-insns} spec of @code{define-isa}.
+It allows a CPU family to override the value.
+
+@subsubsection file-transform
+
+Specify the file name transformation of generated code.
+
+Each generated file has a named related to the ISA or CPU family.
+Sometimes generated code needs to know the name of another generated
+file (e.g. #include's).
+At present @code{file-transform} specifies the suffix.
+
+For example, M32R/x generated files have an `x' suffix, as in @file{cpux.h}
+for the @file{cpu.h} header. This is indicated with
+@code{(file-transform "x")}.
+
+??? Ideally generated code wouldn't need to know anything about file names.
+This breaks down for #include's. It can be fixed with symlinks or other
+means.
+
+@node define-mach
+@subsection define-mach
+@cindex define-mach
+
+@code{define-mach} defines a distinct variant of a CPU. It currently
+has a one-to-one correspondence with BFD's "mach number". A minimum of
+one mach must be defined.
+
+The syntax of @code{define-mach} is:
+
+@example
+(define-mach
+ (name mach-name)
+ (comment "description")
+ (attrs attribute-list)
+ (cpu cpu-family-name)
+ (bfd-name "bfd-name")
+ (isas isa-name-list)
+)
+@end example
+
+@subsubsection bfd-name
+@cindex bfd-name
+
+The name of the mach as used by BFD. If not specified the name of the
+mach is used.
+
+@subsubsection isas
+
+List of names of ISA's the machine supports.
+
+@node Model variants
+@section Model Variants
+
+For each `machine', as defined here, there is one or more `models'.
+There must be at least one model for each machine.
+(*note: There could be a default, but requiring one doesn't involve that much
+extra typing and forces the programmer to at least think about such things.)
+
+@example
+(define-model
+ (name model-name)
+ (comment "description")
+ (attrs attribute-list)
+ (mach machine-name)
+ (state (variable-name-1 variable-mode-1) ...)
+ (unit name "comment" (attributes)
+ issue done state inputs outputs profile)
+)
+@end example
+
+@subsection mach
+
+The name of the machine the model is an implementation of.
+
+@subsection state
+
+A list of variable-name/mode pairs for recording global function unit
+state. For example on the M32R the value is @code{(state (h-gr UINT))}
+and is a bitmask of which register(s) are the targets of loads and thus
+subject to load stalls.
+
+@subsection unit
+
+Specifies a function unit. Any number of function units may be specified.
+The @code{u-exec} unit must be specified as it is the default.
+
+The syntax is:
+
+@example
+ (unit name "comment" (attributes)
+ issue done state inputs outputs profile)
+@end example
+
+@samp{issue} is the number of operations that may be in progress.
+It originates from GCC function unit specification. In general the
+value should be 1.
+
+@samp{done} is the latency of the unit. The value is the number of cycles
+until the result is ready.
+
+@samp{state} has the same syntax as the global model `state' and is a list of
+variable-name/mode pairs.
+
+@samp{inputs} is a list of inputs to the function unit.
+Each element is @code{(operand-name mode default-value)}.
+
+@samp{outputs} is a list of outputs of the function unit.
+Each element is @code{(operand-name mode default-value)}.
+
+@samp{profile} is an rtl-code sequence that performs function unit
+modeling. At present the only possible value is @code{()} meaning
+invoke a user supplied function named @code{<cpu>_model_<mach>_<unit>}.
+
+The current function unit specification is a first pass in order to
+achieve something that moderately works for the intended purpose (cycle
+counting on the simulator). Something more elaborate is on the todo list
+but there is currently no schedule for it. The new specification must
+try to be application independent. Some known applications are:
+cycle counting in the simulator, code scheduling in a compiler, and code
+scheduling in a JIT simulator (where speed of analysis can be more
+important than getting an optimum schedule).
+
+The inputs/outputs fields are how elements in the semantic code are mapped
+to function units. Each input and output has a name that corresponds
+with the name of the operand in the semantics. Where there is no
+correspondence, a mapping can be made in the unit specification of the
+instruction (see the subsection titled ``Timing'').
+
+Another way to achieve the correspondence is to create separate function
+units that contain the desired input/output names. For example on the
+M32R the u-exec unit is defined as:
+
+@example
+(unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT -1) (sr2 INT -1)) ; inputs
+ ((dr INT -1)) ; outputs
+ () ; profile action (default)
+)
+@end example
+
+This handles instructions that use sr, sr2 and dr as operands. A second
+function unit called @samp{u-cmp} is defined as:
+
+@example
+(unit u-cmp "Compare Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT -1) (src2 INT -1)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+)
+@end example
+
+This handles instructions that use src1 and src2 as operands. The
+organization of units is arbitrary. On the M32R, src1/src2 instructions
+are typically compare instructions so a separate function unit was
+created for them.
+
+@node Hardware elements
+@section Hardware Elements
+
+The elements of hardware that make up a CPU are defined with
+@code{define-hardware}. Examples of hardware elements include
+registers, condition bits, immediate constants and memory.
+
+Instruction fields that provide numerical values (``immediate
+constants'') aren't really elements of the hardware, but it simplifies
+things to think of them this way. Think of them as @emph{constant
+generators}@footnote{A term borrowed from the book on the Bulldog
+compiler and perhaps other sources.}.
+
+Hardware elements are defined with:
+
+@example
+(define-hardware
+ (name hardware-name)
+ (comment "description")
+ (attrs attribute-list)
+ (semantic-name hardware-semantic-name)
+ (type type-name type-arg1 type-arg2 ...)
+ (indices index-type index-arg1 index-arg2 ...)
+ (values values-type values-arg1 values-arg2 ...)
+ (handlers handler1 handler2 ...)
+ (get (args) (expression))
+ (set (args) (expression))
+)
+@end example
+
+The only required members are @samp{name} and @samp{type}. Convention
+requires @samp{hardware-name} begin with @samp{h-}.
+
+@subsection attrs
+
+List of attributes. There are several predefined hardware attributes:
+
+@itemize @minus
+@item MACH
+
+A bitset attribute used to specify which machines have this hardware element.
+Do not specify the MACH attribute if the value is "all machs".
+
+Usage: @code{(MACH mach1,mach2,...)}
+There must be no spaces in ``@code{mach1,mach2,...}''.
+
+@item CACHE-ADDR
+
+A hint to the simulator semantic code generator to tell it it can record the
+address of a selected register in an array of registers. This speeds up
+simulation by moving the array computation to extraction time.
+This attribute is only useful to register arrays and cannot be specified
+with @code{VIRTUAL} (??? revisit).
+
+@item PROFILE
+
+Ignore. This is a work-in-progress to define how to profile references
+to hardware elements.
+
+@item VIRTUAL
+
+The hardware element doesn't require any storage.
+This is used when you want a value that is derived from some other value.
+If @code{VIRTUAL} is specified, @code{get} and @code{set} specs must be
+provided.
+@end itemize
+
+@subsection type
+
+This is the type of hardware. Current values are: @samp{register},
+@samp{memory}, and @samp{immediate}.
+
+For registers the syntax is one of:
+
+@example
+@code{(register mode [(number)])}
+@code{(register (mode bits) [(number)])}
+@end example
+
+where @samp{(number)} is the number of registers and is optional. If
+omitted, the default is @samp{(1)}.
+The second form is useful for describing registers with an odd (as in
+unusual) number of bits.
+@code{mode} for the second form must be one of @samp{INT} or @samp{UINT}.
+Since these two modes don't have an implicit size, they cannot be used for
+the first form.
+
+@c ??? Might wish to remove the mode here and just specify number of bits.
+
+For memory the syntax is:
+
+@example
+@code{(memory mode (size))}
+@end example
+
+where @samp{(size)} is the size of the memory in @samp{mode} units.
+In general @samp{mode} should be @code{QI}.
+
+For immediates the syntax is one of
+
+@example
+@code{(immediate mode)}
+@code{(immediate (mode bits))}
+@end example
+
+The second form is for values for which a mode of that size doesn't exist.
+@samp{mode} for the second form must be one of @code{INT} or @code{UINT}.
+Since these two modes don't have an implicit size, they cannot be used
+for the first form.
+
+??? There's no real reason why a mode like SI can't be used
+for odd-sized immediate values. The @samp{bits} field indicates the size
+and the @samp{mode} field indicates the mode in which the value will be used,
+as well as its signedness. This would allow removing INT/UINT for this
+purpose. On the other hand, a non-width specific mode allows applications
+to choose one (a simulator might prefer to store immediates in an `int'
+rather than, say, char if the specified mode was @code{QI}).
+
+@subsection indices
+
+Specify names for individual elements with the @code{indices} spec.
+It is only valid for registers with more than one element.
+
+The syntax is:
+
+@example
+@code{(indices index-type arg1 arg2 ...)}
+@end example
+
+where @samp{index-type} specifies the kind of index and @samp{arg1 arg2 ...}
+are arguments to @samp{index-type}.
+
+The are two supported values for @samp{index-type}: @code{keyword}
+and @code{extern-keyword}. The difference is that indices defined with
+@code{keyword} are kept internal to the hardware element's definition
+and are not usable elsewhere, whereas @code{extern-keyword} specifies
+a set of indices defined elsewhere.
+
+@subsubsection keyword
+
+@example
+@code{(indices keyword "prefix" ((name1 value1) (name2 value2) ...))}
+@end example
+
+@samp{prefix} is the common prefix for each of the index names.
+For example, SPARC registers usually begin with @samp{"%"}.
+
+Each @samp{(name value)} pair maps a name with an index number.
+An index can be specified multiple times, for example, when a register
+has multiple names.
+
+Example from Thumb:
+
+@example
+(define-hardware
+ (name h-gr-t)
+ (comment "Thumb's general purpose registers")
+ (attrs (ISA thumb) VIRTUAL) ; ??? CACHE-ADDR should be doable
+ (type register WI (8))
+ (indices keyword ""
+ ((r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)))
+ (get (regno) (reg h-gr regno))
+ (set (regno newval) (set (reg h-gr regno) newval))
+)
+@end example
+
+@subsubsection extern-keyword
+
+@example
+@code{(indices extern-keyword keyword-name)}
+@end example
+
+Example from M32R:
+
+@example
+(define-keyword
+ (name gr-names)
+ (print-name h-gr)
+ (prefix "")
+ (values (fp 13) (lr 14) (sp 15)
+ (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15))
+)
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs PROFILE CACHE-ADDR)
+ (type register WI (16))
+ (indices extern-keyword gr-names)
+)
+@end example
+
+@subsection values
+
+Specify a list of valid values with the @code{values} spec.
+@c Clumsy wording.
+
+The syntax is identical to the syntax for @code{indices}.
+It is only valid for immediates.
+
+Example from sparc64:
+
+@example
+(define-hardware
+ (name h-p)
+ (comment "prediction bit")
+ (attrs (MACH64))
+ (type immediate (UINT 1))
+ (values keyword "" (("" 0) (",pf" 0) (",pt" 1)))
+)
+@end example
+
+@subsection handlers
+
+The @code{handlers} spec is an escape hatch for indicating when a
+programmer supplied routine must be called to perform a function.
+
+The syntax is:
+
+@example
+@samp{(handlers (handler-name1 "function_name1")
+ (handler-name2 "function_name2")
+ ...)}
+@end example
+
+@samp{handler-name} must be one of @code{parse} or @code{print}.
+How @samp{function_name} is used is application specific, but in
+general it is the name of a function to call. The only application
+that uses this at present is Opcodes. See the Opcodes documentation for
+a description of each function's expected prototype.
+
+@subsection get
+
+Specify special processing to be performed when a value is read
+with the @code{get} spec.
+
+The syntax for scalar registers is:
+
+@example
+@samp{(get () (expression))}
+@end example
+
+The syntax for vector registers is:
+
+@example
+@samp{(get (index) (expression))}
+@end example
+
+@code{expression} is an RTL expression that computes the value to return.
+The mode of the result must be the mode of the register.
+
+@code{index} is the name of the index as it appears in @code{expression}.
+
+At present, @code{sequence}, @code{parallel}, and @code{case} expressions
+are not allowed here.
+
+@subsection set
+
+Specify special processing to be performed when a value is written
+with the @code{set} spec.
+
+The syntax for scalar registers is:
+
+@example
+@samp{(set (newval) (expression))}
+@end example
+
+The syntax for vector registers is:
+
+@example
+@samp{(set (index newval) (expression))}
+@end example
+
+@code{expression} is an RTL expression that stores @code{newval}
+in the register. This may involve storing values in other registers as well.
+@code{expression} must be one of @code{set}, @code{if}, @code{sequence}, or
+@code{case}.
+
+@code{index} is the name of the index as it appears in @code{expression}.
+
+@subsection Predefined hardware elements
+
+Several hardware types are predefined:
+
+@table @code
+@item h-uint
+unsigned integer
+@item h-sint
+signed integer
+@item h-memory
+main memory, where ``main'' is loosely defined
+@item h-addr
+data address (data only)
+@item h-iaddr
+instruction address (instructions only)
+@end table
+
+@subsection Program counter
+
+The program counter must be defined and is not a builtin.
+If get/set specs are not required, define it as:
+
+@example
+(dnh h-pc "program counter" (PC) (pc) () () ())
+@end example
+
+If get/set specs are required, define it as:
+
+@example
+(define-hardware
+ (name h-pc)
+ (comment "<ARCH> program counter")
+ (attrs PC)
+ (type pc)
+ (get () <insert get code here>)
+ (set (newval) <insert set code here>)
+)
+@end example
+
+If the architecture has multiple instruction sets, all must be specified.
+If they're not, the default is the first one which is not what you want.
+Here's an example from @file{arm.cpu}:
+
+@example
+(define-hardware
+ (name h-pc)
+ (comment "ARM program counter (h-gr reg 15)")
+ (attrs PC (ISA arm,thumb))
+ (type pc)
+ (set (newval)
+ (if (reg h-tbit)
+ (set (raw-reg SI h-pc) (and newval -2))
+ (set (raw-reg SI h-pc) (and newval -4))))
+)
+@end example
+
+@subsection Simplification macros
+
+To simplify @file{.cpu} files, the @code{dnh}
+(@code{define-normal-hardware}) macro exists that takes a fixed set of
+positional arguments for the typical hardware element. The syntax of
+@code{dnh} is:
+
+@code{(dnh name comment attributes type indices values handlers)}
+
+Example:
+
+@example
+(dnh h-gr "general registers"
+ () ; attributes
+ (register WI (16))
+ (keyword "" ((fp 13) (sp 15) (lr 14)
+ (r0 0) (r1 1) (r2 2) (r3 3)
+ (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11)
+ (r12 12) (r13 13) (r14 14) (r15 15)))
+ () ()
+)
+@end example
+
+This defines an array of 16 registers of mode @code{WI} ("word int").
+The names of the registers are @code{r0...r15}, and registers 13, 14 and
+15 also have the names @code{fp}, @code{lr} and @code{sp} respectively.
+
+Scalar registers with no special requirements occur frequently.
+Macro @code{dsh} (@code{define-simple-hardware}) is identical to
+@code{dnh} except does not include the @code{indices}, @code{values},
+or @code{handlers} specs.
+
+@example
+(dsh h-ibit "interrupt enable bit" () (register BI))
+@end example
+
+@node Instruction fields
+@section Instruction Fields
+@cindex Fields, instruction
+
+Instruction fields define the raw bitfields of each instruction.
+Minimal semantic meaning is attributed to them. Support is provided for
+mapping to and from the raw bit pattern and the usable contents, and
+other simple manipulations.
+
+The syntax for defining instruction fields is:
+
+@example
+(define-ifield
+ (name field-name)
+ (comment "description")
+ (attrs attribute-list)
+ (start starting-bit-number)
+ (length number-of-bits)
+ (follows ifield-name)
+ (mode mode-name)
+ (encode (value pc) (rtx to describe encoding))
+ (decode (value pc) (rtx to describe decoding))
+)
+@end example
+
+(*note: Whether to also provide a way to specify instruction formats is not yet
+clear. Currently they are computed from the instructions, so there's no
+current *need* to provided them. However, providing the ability as an
+option may simplify other tools CGEN is used to generate. This
+simplification would come in the form of giving known names to the formats
+which CPU reference manuals often do. Pre-specified instruction formats
+may also simplify expression of more complicated instruction sets.)
+
+(*note: Positional specification simplifies instruction description somewhat
+in that there is no required order of fields, and a disjunct set of fields can
+be referred to as one. On the other hand it can require knowledge of the length
+of the instruction which is inappropriate in cases like the M32R where
+the main fields have the same name and "position" regardless of the length
+of the instruction. Moving positional specification into instruction formats,
+whether machine generated or programmer specified, may be done.)
+
+Convention requires @samp{field-name} begin with @samp{f-}.
+
+@subsection attrs
+
+There are several predefined instruction field attributes:
+
+@table @code
+@item PCREL-ADDR
+The field contains a PC relative address. Various CPUs have various
+offsets from the PC from which the address is calculated. This is
+specified in the encode and decode sections.
+
+@item ABS-ADDR
+The field contains an absolute address.
+
+@item SIGN-OPT
+The field has an optional sign. It is sign-extended during
+extraction. Allowable values are -2^(n-1) to (2^n)-1.
+
+@item RESERVED
+The field is marked as ``reserved'' by the architecture.
+This is an informational attribute. Tools may use it
+to validate programs, either statically or dynamically.
+
+@item VIRTUAL
+The field does not directly contribute to the instruction's value. This
+is used to simplify semantic or assembler descriptions where a fields
+value is based on other values. Multi-ifields are always virtual.
+@end table
+
+@subsection start
+The bit number of the field's most significant bit in the instruction.
+Bit numbering is determined by the @code{insn-lsb0?} field of
+@code{define-arch}.
+
+@subsection length
+The number of bits in the field.
+The field must be contiguous.
+For non-contiguous instruction fields use "multi-ifields".
+(*xref: Non-contiguous fields).
+
+@subsection follows
+Optional. Experimental.
+This should not be used for the specification of RISC-like architectures.
+It is an experiment in supporting CISC-like architectures.
+The argument is the name of the ifield or operand that immediately precedes
+this one. In general the argument is an "anyof" operand. The @code{follows}
+spec allows subsequent ifields to "float".
+
+@subsection mode
+The mode the value is to be interpreted in.
+Usually this is @code{INT} or @code{UINT}.
+
+@c ??? There's no real reason why modes like SI can't be used here.
+The @samp{length} field specifies the number of bits in the field,
+and the @samp{mode} field indicates the mode in which the value will be used,
+as well as its signedness. This would allow removing INT/UINT for this
+purpose. On the other hand, a non-width specific mode allows applications
+to choose one (a simulator might prefer to store immediates in an `int'
+rather than, say, char if the specified mode was @code{QI}).
+
+@subsection encode
+An expression to apply to convert from usable values to raw field
+values. The syntax is @code{(encode (value pc) expression)} or more
+specifically @code{(encode ((<mode1> value) (IAI pc)) <expression>)},
+where @code{<mode1>} is the mode of the the ``incoming'' value, and
+@code{<expression>} is an rtx to convert @code{value} to something that
+can be stored in the field.
+
+Example:
+
+@example
+(encode ((SF value) (IAI pc))
+ (cond WI
+ ((eq value (const SF 1.0)) (const 0))
+ ((eq value (const SF 0.5)) (const 1))
+ ((eq value (const SF -1.0)) (const 2))
+ ((eq value (const SF 2.0)) (const 3))
+ (else (error "invalid floating point value for field foo"))))
+@end example
+
+In this example four floating point immediate values are represented in a
+field of two bits. The above might be expanded to a series of `if' statements
+or the generator could determine a `switch' statement is more appropriate.
+
+@subsection decode
+
+An expression to apply to convert from raw field values to usable
+values. The syntax is @code{(decode (value pc) expression)} or more
+specifically @code{(decode ((WI value) (IAI pc)) <expression>)}, where
+@code{<expression>} is an rtx to convert @code{value} to something
+usable.
+
+Example:
+
+@example
+(decode ((WI value) (IAI pc))
+ (cond SF
+ ((eq value 0) (const SF 1.0))
+ ((eq value 1) (const SF 0.5))
+ ((eq value 2) (const SF -1.0))
+ ((eq value 3) (const SF 2.0))))
+@end example
+
+There's no need to provide an error case as presumably @code{value}
+would never have an invalid value, though certainly one could provide an
+error case if one wanted to.
+
+@subsection Non-contiguous fields
+@cindex Fields, non-contiguous
+
+Non-contiguous fields (e.g. sparc64's 16 bit displacement field) are
+built on top of support for contiguous fields. The syntax for defining
+such fields is:
+
+@example
+(define-multi-ifield
+ (name field-name)
+ (comment "description")
+ (attrs attribute-list)
+ (mode mode-name)
+ (subfields field1-name field2-name ...)
+ (insert (code to set each subfield))
+ (extract (code to set field from subfields))
+)
+@end example
+
+(*note: insert/extract are analogous to encode/decode so maybe these
+fields are misnamed. The operations are subtly different though.)
+
+Example:
+
+@example
+(define-multi-ifield
+ (name f-i20)
+ (comment "20 bit unsigned")
+ (attrs)
+ (mode UINT)
+ (subfields f-i20-4 f-i20-16)
+ (insert (sequence ()
+ (set (ifield f-i20-4) (srl (ifield f-i20) (const 16)))
+ (set (ifield f-i20-16) (and (ifield f-i20) (const #xffff)))
+ ))
+ (extract (sequence ()
+ (set (ifield f-i20) (or (sll (ifield f-i20-4) (const 16))
+ (ifield f-i20-16)))
+ ))
+)
+@end example
+
+@subsection subfields
+The names of the already defined fields that make up the multi-ifield.
+
+@subsection insert
+Code to set the subfields from the multi-ifield. All fields are referred
+to with @code{(ifield <name>)}.
+
+@subsection extract
+Code to set the multi-ifield from the subfields. All fields are referred
+to with @code{(ifield <name>)}.
+
+@subsection Simplification macros
+To simplify @file{.cpu} files, the @code{dnf}, @code{df} and @code{dnmf}
+macros have been created. Each takes a fixed set of positional arguments
+for the typical instruction field. @code{dnf} is short for
+@code{define-normal-field}, @code{df} is short for @code{define-field},
+and @code{dnmf} is short for @code{define-normal-multi-ifield}.
+
+The syntax of @code{dnf} is:
+
+@code{(dnf name comment attributes start length)}
+
+Example:
+
+@code{(dnf f-r1 "register r1" () 4 4)}
+
+This defines a field called @samp{f-r1} that is an unsigned field of 4
+bits beginning at bit 4. All fields defined with @code{dnf} are unsigned.
+
+The syntax of @code{df} is:
+
+@code{(df name comment attributes type start length mode encode decode)}
+
+Example:
+
+@example
+(df f-disp8
+ "disp8, slot unknown" (PCREL-ADDR)
+ INT 8 8
+ ((value pc) (sra WI (sub WI value (and WI pc (const -4))) (const 2)))
+ ((value pc) (add WI (sll WI value (const 2)) (and WI pc (const -4)))))
+@end example
+
+This defines a field called @samp{f-disp8} that is a signed PC-relative
+address beginning at bit 8 of size 8 bits that is left shifted by 2.
+
+The syntax of @code{dnmf} is:
+
+@code{(dnmf name comment attributes mode subfields insert extract)}
+
+@node Enumerated constants
+@section Enumerated constants
+@cindex Enumerated constants
+@cindex Enumerations
+
+Enumerated constants (@emph{enums}) are important enough in instruction
+set descriptions that they are given special treatment. Enums are
+defined with:
+
+@example
+(define-enum
+ (name enum-name)
+ (comment "description")
+ (attrs attribute-list)
+ (prefix prefix)
+ (values val1 val2 ...)
+)
+@end example
+
+Enums in opcode fields are further enhanced by specifying the opcode
+field they are used in. This allows the enum's name to be specified
+in an instruction's @code{format} entry.
+
+@example
+(define-insn-enum
+ (name enum-name)
+ (comment "description")
+ (attrs (attribute list))
+ (prefix prefix)
+ (ifield instruction-field-name)
+ (values val1 val2 ...)
+)
+@end example
+
+(*note: @code{define-insn-enum} isn't implemented yet: use
+@code{define-normal-insn-enum})
+
+Example:
+
+@example
+(define-insn-enum
+ (name insn-op1)
+ (comment "op1 field values")
+ (prefix OP1_)
+ (ifield f-op1)
+ (values "0" "1" "2" "3" "4" "5" "6" "7"
+ "8" "9" "10" "11" "12" "13" "14" "15")
+)
+@end example
+
+@subsection prefix
+Convention requires each enum value to be prefixed with the same text.
+Rather than specifying the prefix in each entry, it is specified once, here.
+Convention requires @samp{prefix} not contain any lowercase characters.
+
+@subsection ifield
+The name of the instruction field that the enum is intended for.
+
+@subsection values
+A list of possible values. Each element has one of the following forms:
+
+@itemize @bullet
+@item @code{name}
+@item @code{(name)}
+@item @code{(name value)}
+@item @code{(name - (attribute-list))}
+@item @code{(name value (attribute-list))}
+@end itemize
+
+The syntax for numbers is Scheme's, so hex numbers are @code{#xnnnn}.
+A value of @code{-} means use the next value (previous value plus 1).
+
+Example:
+
+@example
+(values "a" ("b") ("c" #x12)
+ ("d" - (sanitize foo)) ("e" #x1234 (sanitize bar)))
+@end example
+
+@subsection Simplification macros
+
+@code{(define-normal-enum name comment attrs prefix vals)}
+
+@code{(define-normal-insn-enum name comment attrs prefix ifield vals)}
+
+@node Instruction operands
+@section Instruction Operands
+@cindex Operands, instruction
+
+Instruction operands provide:
+
+@itemize @bullet
+@item a layer between the assembler and the raw hardware description
+@item the main means of manipulating instruction fields in the semantic code
+@c More?
+@end itemize
+
+The syntax is:
+
+@example
+(define-operand
+ (name operand-name)
+ (comment "description")
+ (attrs attribute-list)
+ (type hardware-element)
+ (index instruction-field)
+ (asm asm-spec)
+)
+@end example
+
+@subsection name
+
+This is the name of the operand as a Scheme symbol.
+The name choice is fairly important as it is used in instruction
+syntax entries, instruction format entries, and semantic expressions.
+It can't collide with symbols used in semantic expressions
+(e.g. @code{and}, @code{set}, etc).
+
+The convention is that operands have no prefix (whereas ifields begin
+with @samp{f-} and hardware elements begin with @samp{h-}). A prefix
+like @samp{o-} would avoid collisions with other semantic elements, but
+operands are used often enough that any prefix is a hassle.
+
+@subsection attrs
+
+A list of attributes. In addition to attributes defined for the operand,
+an operand inherits the attributes of its instruction field. There are
+several predefined operand attributes:
+
+@table @code
+@item NEGATIVE
+The operand contains negative values (not used yet so definition is
+still nebulous.
+
+@item RELAX
+This operand contains the changeable field (usually a branch address) of
+a relaxable instruction.
+
+@item SEM-ONLY
+Use the SEM-ONLY attribute for cases where the operand will only be used
+in semantic specification, and not assembly code specification. A
+typical example is condition codes.
+@end table
+
+To refer to a hardware element in semantic code one must either use an
+operand or one of reg/mem/const. Operands generally exist to map
+instruction fields to the selected hardware element and are easier to
+use in semantic code than referring to the hardware element directly
+(e.g. @code{sr} is easier to type and read than @code{(reg h-gr
+<index>)}). Example:
+
+@example
+ (dnop condbit "condition bit" (SEM-ONLY) h-cond f-nil)
+@end example
+
+@code{f-nil} is the value to use when there is no instruction field
+
+@c There might be some language cleanup to be done here regarding f-nil.
+@c It is kind of extraneous.
+
+@subsection type
+The hardware element this operand applies to. This must be the name of a
+hardware element.
+
+@subsection index
+The index of the hardware element. This is used to mate the hardware
+element with the instruction field that selects it, and must be the name
+of an ifield entry. (*note: The index may be other things besides
+ifields in the future.)
+
+@subsection asm
+Sometimes it's necessary to escape to C to parse assembler, or print
+a value. This field is an escape hatch to implement this.
+The current syntax is:
+
+@code{(asm asm-spec)}
+
+where @code{asm-spec} is one or more of:
+
+@code{(parse "function_suffix")} -- a call to function
+@code{parse_<function_suffix>} is generated.
+
+@code{(print "function_suffix")} -- a call to function
+@code{print_<function_suffix>} is generated.
+
+These functions are intended to be provided in a separate @file{.opc}
+file. The prototype of a parse function depends on the hardware type.
+See @file{cgen/*.opc} for examples.
+
+@c FIXME: The following needs review.
+
+For integer it is:
+
+@example
+static const char *
+parse_foo (CGEN_CPU_DESC cd,
+ const char **strp,
+ int opindex,
+ unsigned long *valuep);
+@end example
+
+@code{cd} is the result of @code{<arch>_cgen_opcode_open}.
+@code{strp} is a pointer to a pointer to the assembler and is updated by
+the function.
+@c FIXME
+@code{opindex} is ???.
+@code{valuep} is a pointer to where to record the parsed value.
+@c FIXME
+If a relocation is needed, it is queued with a call to ???. Queued
+relocations are processed after the instruction has been parsed.
+
+The result is an error message or NULL if successful.
+
+The prototype of a print function depends on the hardware type. See
+@file{cgen/*.opc} for examples. For integers it is:
+
+@example
+void print_foo (CGEN_CPU_DESC cd,
+ PTR dis_info,
+ long value,
+ unsigned int attrs,
+ bfd_vma pc,
+ int length);
+@end example
+
+@samp{cd} is the result of @code{<arch>_cgen_opcode_open}.
+@samp{ptr} is the `info' argument to print_insn_<arch>.
+@samp{value} is the value to be printed.
+@samp{attrs} is the set of boolean attributes.
+@samp{pc} is the PC value of the instruction.
+@samp{length} is the length of the instruction.
+
+Actual printing is done by calling @code{((disassemble_info *)
+dis_info)->fprintf_func}.
+
+@node Derived operands
+@section Derived Operands
+@cindex Derived operands
+@cindex Operands, instruction
+@cindex Operands, derived
+
+Derived operands are an experiment in supporting the addressing modes of
+CISC-like architectures. Addressing modes are difficult to support as
+they essentially increase the number of instructions in the architecture
+by an order of magnitude. Defining all the variants requires something
+in addition to the RISC-like architecture support. The theory is that
+since CISC-like instructions are basically "normal" instructions with
+complex operands the place to add the necessary support is in the
+operands.
+
+Two kinds of operands exist to support CISC-like cpus, and they work
+together. "derived-operands" describe one variant of a complex
+argument, and "anyof" operands group them together.
+
+The syntax for defining derived operands is:
+
+@example
+(define-derived-operand
+ (name operand-name)
+ (comment "description")
+ (attrs attribute-list)
+ (mode mode-name)
+ (args arg1-operand-name arg2-operand-name ...)
+ (syntax "syntax")
+ (base-ifield ifield-name)
+ (encoding (+ arg1-operand-name arg2-operand-name ...))
+ (ifield-assertion expression)
+ (getter expression)
+ (setter expression)
+)
+@end example
+
+@cindex anyof operands
+@cindex Operands, anyof
+
+The syntax for defining anyof operands is:
+
+@example
+(define-anyof-operand
+ (name operand-name)
+ (comment "description")
+ (attrs attribute-list)
+ (mode mode-name)
+ (base-ifield ifield-name)
+ (choices derived-operand1-name derived-operand2-name ...)
+)
+@end example
+
+@subsection mode
+
+The name of the mode of the operand.
+
+@subsection args
+
+List of names of operands the derived operand uses.
+The operands must already be defined.
+The argument operands can be any kind of operand: normal, derived, anyof.
+
+@subsection syntax
+
+Assembler syntax of the operand.
+
+??? This part needs more work. Addressing mode specification in assembler
+needn't be localized to the vicinity of the operand.
+
+@subsection base-ifield
+
+The name of the instruction field common to all related derived operands.
+Here related means "used by the same `anyof' operand".
+
+@subsection encoding
+
+The machine encoding of the operand.
+
+@subsection ifield-assertion
+
+An assertion of what values any instruction fields will or will not have
+in the containing instruction.
+
+??? A better name for this might be "constraint".
+
+@subsection getter
+
+RTL expression to get the value of the operand.
+All operands refered to must be specified in @code{args}.
+
+@subsection setter
+
+RTL expression to set the value of the operand.
+All operands refered to must be specified in @code{args}.
+Use @code{newval} to refer to the value to be set.
+
+@subsection choices
+
+For anyof operands, the names of the derived operands.
+The operand may be "any of" the specified choices.
+
+@node Instructions
+@section Instructions
+@cindex Instructions
+
+Each instruction in the instruction set has an entry in the description
+file. For complicated instruction sets this is a lot of typing. However,
+macros can reduce a lot of that typing. The real question is given the
+amount of information that must be expressed, how succinct can one express
+it and still be clean and usable? I'm open to opinions on how to improve
+this, but such improvements must take everything CGEN wishes to be into
+account.
+(*note: Of course no claim is made that the current design is the
+be-all and end-all or that there is one be-all and end-all.)
+
+The syntax for defining an instruction is:
+
+@example
+(define-insn
+ (name insn-name)
+ (comment "description")
+ (attrs attribute-list)
+ (syntax "assembler syntax")
+ (format (+ field-list))
+ (semantics (semantic-expression))
+ (timing timing-data)
+)
+@end example
+
+Instructions specific to a particular cpu variant are denoted as such with
+the MACH attribute.
+
+Possible additions for the future:
+
+@itemize @bullet
+@item a field to describe a final constraint for determining a match
+@item choosing the output from a set of choices
+@end itemize
+
+@subsection attrs
+
+A list of attributes, for which there are several predefined instruction
+attributes:
+
+@table @code
+@item MACH
+A bitset attribute used to specify which machines have this hardware
+element. Do not specify the MACH attribute if the value is for all
+machines.
+
+Usage: @code{(MACH mach1,mach2,...)}
+
+There must be no spaces in ``@code{mach1,mach2,...}''.
+
+@item UNCOND-CTI
+The instruction is an unconditional ``control transfer instruction''.
+
+(*note: This attribute is derived from the semantic code. However if the
+computed value is wrong (dunno if it ever will be) the value can be
+overridden by explicitly mentioning it.)
+
+@item COND-CTI
+The instruction is an conditional "control transfer instruction".
+
+(*note: This attribute is derived from the semantic code. However if the
+computed value is wrong (dunno if it ever will be) the value can be
+overridden by explicitly mentioning it.)
+
+@item SKIP-CTI
+The instruction can cause one or more insns to be skipped. This is
+derived from the semantic code.
+
+@item DELAY-SLOT
+The instruction has one or more delay slots. This is derived from the
+semantic code.
+
+@item RELAXABLE
+The instruction has one or more identical variants. The assembler tries
+this one first and then the relaxation phases switches to larger ones as
+necessary.
+
+@item RELAX
+The instruction is a non-minimal variant of a relaxable instruction. It
+is avoided by the assembler in the first pass.
+
+@item ALIAS
+Internal attribute set for macro-instructions that are an alias for one
+real insn.
+
+@item NO-DIS
+For macro-instructions, don't use during disassembly.
+@end table
+
+@subsection syntax
+
+This is a character string consisting of raw characters and operands.
+Fields are denoted by @code{$operand} or
+@code{$@{operand@}}@footnote{Support for @code{$@{operand@}} is
+work-in-progress.}. If a @samp{$} is required in the syntax, it is
+specified with @samp{\$}. At most one white-space character may be
+present and it must be a blank separating the instruction mnemonic from
+the operands. This doesn't restrict the user's assembler, this is
+@c Is this reasonable?
+just a description file restriction to separate the mnemonic from the
+operands@footnote{The restriction can be relaxed by saying the first
+blank is the one that separates the mnemonic from its operands.}.
+The assembly language accepted by the generated assembler does not
+have to take exactly the same form as the syntax described in this
+field--additional whitespace may be present in the input file.
+
+Operands can refer to registers, constants, and whatever else is necessary.
+
+Instruction mnemonics can take operands. For example, on the SPARC a
+branch instruction can take @code{,a} as an argument to indicate the
+instruction is being annulled (e.g. @code{bge$a $disp22}).
+
+@subsection format
+
+This is a complete list of fields that specify the instruction. At
+present it must be prefaced with @code{+} to allow for future additions.
+Reserved bits must also be specified, gaps are not allowed.
+@c Well, actually I think they are and it could certainly be allowed.
+@c Question: should they be allowed?
+The ordering of the fields is not important.
+
+Format elements can be any of:
+
+@itemize @bullet
+@item instruction field specifiers with a value (e.g. @code{(f-r1 14)})
+@item an instruction field enum, as in @code{OP1_4}
+@item an operand
+@end itemize
+
+@subsection semantics
+@cindex Semantics
+
+This field provides a mathematical description of what the instruction
+does. Its syntax is GCC-RTL-like on purpose since GCC's RTL is well known
+by the intended audience. However, it is not intended that it be precisely
+GCC-RTL.
+
+Obviously there are some instructions that are difficult if not
+impossible to provide a description for (e.g. I/O instructions). Rather
+than create a new semantic function for each quirky operation, escape
+hatches to C are provided to handle all such cases. The @code{c-code},
+@code{c-call} and @code{c-raw-call} semantic functions provide an
+escape-hatch to invoke C code to perform the operation. (*xref:
+Expressions)
+
+@subsection timing
+@cindex Timing
+
+A list of entries for each function unit the instruction uses on each machine
+that supports the instruction. The default function unit is the u-exec unit.
+
+The syntax is:
+
+@example
+(mach-name (unit name (unit-var-name1 insn-operand-name1)
+ (unit-var-name2 insn-operand-name2)
+ ...
+ (cycles cycle-count))
+@end example
+
+unit-var-name/insn-operand-name mappings are optional.
+They map unit inputs/outputs to semantic elements.
+
+@code{cycles} overrides the @code{done} value (latency) of the function
+unit and is optional.
+
+@subsection Simplification macros
+
+To simplify @file{.cpu} files, the @code{dni} macro has been created.
+It takes a fixed set of positional arguments for the typical instruction
+field. @code{dni} is short for @code{define-normal-insn}.
+
+The syntax of @code{dni} is:
+
+@code{(dni name comment attrs syntax format semantics timing)}
+
+Example:
+
+@example
+(dni addi "add 8 bit signed immediate"
+ ()
+ "addi $dr,$simm8"
+ (+ OP1_4 dr simm8)
+ (set dr (add dr simm8))
+ ()
+)
+@end example
+
+@node Macro-instructions
+@section Macro-instructions
+@cindex Macro-instructions
+@cindex Instructions, macro
+
+Macro-instructions are for the assembler side of things and are not used
+by the simulator. The syntax for defining a macro-instruction is:
+
+@example
+(define-macro-insn
+ (name macro-insn-name)
+ (comment "description")
+ (attrs attribute-list)
+ (syntax "assembler syntax")
+ (expansions expansion-spec)
+)
+@end example
+
+@subsection syntax
+
+Syntax of the macro-instruction. This has the same value as the
+@code{syntax} field in @code{define-insn}.
+
+@subsection expansions
+
+An expression to emit code for the instruction. This is intended to be
+general in nature, allowing tests to be done at runtime that choose the
+form of the expansion. Currently the only supported form is:
+
+@code{(emit insn arg1 arg2 ...)}
+
+where @code{insn} is the name of an instruction defined with
+@code{define-insn} and @emph{argn} is the set of operands to
+@code{insn}'s syntax. Each argument is mapped in order to one operand
+in @code{insn}'s syntax and may be any of:
+
+@itemize @bullet
+@item operand specified in @code{syntax}
+@item @code{(operand value)}
+@end itemize
+
+Example:
+
+@example
+(dni st-minus "st-" ()
+ "st $src1,@-$src2"
+ (+ OP1_2 OP2_7 src1 src2)
+ (sequence ((WI new-src2))
+ (set new-src2 (sub src2 (const 4)))
+ (set (mem WI new-src2) src1)
+ (set src2 new-src2))
+ ()
+)
+@end example
+
+@example
+(dnmi push "push" ()
+ "push $src1"
+ (emit st-minus src1 (src2 15)) ; "st %0,@-sp"
+)
+@end example
+
+In this example, the @code{st-minus} instruction is a general
+store-and-decrement instruction and @code{push} is a specialized version
+of it that uses the stack pointer.
+
+@node Modes
+@section Modes
+@cindex Modes
+
+Modes provide a simple and succinct way of specifying data types.
+
+(*note: Should more complex types will be needed (e.g. structs? unions?),
+these can be handled by extending the definition of a mode to encompass them.)
+
+Modes are similar to their usage in GCC, but there are some differences:
+
+@itemize @bullet
+@item modes for boolean values (i.e. bits) are also supported as they are
+useful
+@item integer modes exist in signed and unsigned versions
+@item constants have modes
+@end itemize
+
+Currently supported modes are:
+
+@table @code
+@item VOID
+VOIDmode in GCC.
+
+@item DFLT
+Indicate the default mode is wanted, the value of which depends on context.
+This is a pseudo-mode and never appears in generated code.
+
+@item BI
+Boolean zero/one
+
+@item QI,HI,SI,DI
+Same as GCC.
+
+QI is an 8 bit quantity ("quarter int").
+HI is a 16 bit quantity ("half int").
+SI is a 32 bit quantity ("single int").
+DI is a 64 bit quantity ("double int").
+
+In cases where signedness matters, these modes are signed.
+
+@item UQI,UHI,USI,UDI
+Unsigned versions of QI,HI,SI,DI.
+
+These modes do not appear in semantic RTL. Instead, the RTL function
+specifies the signedness of its operands where necessary.
+
+??? I'm not entirely sure these unsigned modes are needed.
+They are useful in removing any ambiguity in how to sign extend constants
+which has been a source of problems in GCC.
+
+??? Some existing ports use these modes.
+
+@item WI,UWI
+word int, unsigned word int (word_mode in gcc).
+These are aliases for the real mode, typically either @code{SI} or @code{DI}.
+
+@item SF,DF,XF,TF
+Same as GCC.
+
+SF is a 32 bit IEEE float ("single float").
+DF is a 64 bit IEEE float ("double float").
+XF is either an 80 or 96 bit IEEE float ("extended float").
+(*note: XF values on m68k and i386 are different so may
+wish to give them different names).
+TF is a 128 bit IEEE float ("??? float").
+
+@item AI
+Address integer
+
+@item IAI
+Instruction address integer
+
+@item INT,UINT
+Varying width int/unsigned-int. The width is specified by context,
+usually in an instruction field definition.
+
+@end table
+
+@node Expressions
+@section Expressions
+@cindex Expressions
+
+The syntax of CGEN's RTL expressions (or @emph{rtx}) basically follows that of
+GCC's RTL.
+
+The handling of modes is different to simplify the implementation.
+Implementation shouldn't necessarily drive design, but it was a useful
+simplification. Still, it needs to be reviewed. The difference is that
+in GCC @code{(function:MODE arg1 ...)} is written in CGEN as
+@code{(function MODE arg1 ...)}. Note the space after @samp{function}.
+
+GCC RTL allows flags to be recorded with RTL (e.g. MEM_VOLATILE_P).
+This is supported in CGEN RTL by prefixing each RTL function's arguments
+with an optional list of modifiers:
+@code{(function (:mod1 :mod2) MODE arg1 ...)}.
+The list is a set of modifier names prefixed with ':'. They can take
+arguments.
+??? Modifiers are supported by the RTL traversing code, but no use is
+made of them yet.
+
+The currently defined semantic functions are:
+
+@table @code
+@item (set mode destination source)
+Assign @samp{source} to @samp{destination} reference in mode @samp{mode}.
+
+@item (set-quiet mode destination source)
+Assign @samp{source} to @samp{destination} referenced in mode
+@samp{mode}, but do not print any tracing message.
+
+@item (reg mode hw-name [index])
+Return an `operand' of hardware element @samp{hw-name} in mode @samp{mode}.
+If @samp{hw-name} is an array, @samp{index} selects which register.
+
+@item (raw-reg mode hw-name [index])
+Return an `operand' of hardware element @samp{hw-name} in mode @samp{mode},
+bypassing any @code{get} or @code{set} specs of the register.
+If @samp{hw-name} is an array, @samp{index} selects which register.
+This cannot be used with virtual registers (those specified with the
+@samp{VIRTUAL} attribute).
+
+@code{raw-reg} is most often used in @code{get} and @code{set} specs
+of a register: if it weren't read and write operations would infinitely
+recurse.
+
+@item (mem mode address)
+Return an `operand' of memory referenced at @samp{address} in mode
+@samp{mode}.
+
+@item (const mode value)
+Return an `operand' of constant @samp{value} in mode @samp{mode}.
+
+@item (enum mode value-name)
+Return an `operand' of constant @samp{value-name} in mode @samp{mode}.
+The value must be from a previously defined enum.
+
+@item (subword mode value word-num)
+Return part of @samp{value}. Which part is determined by @samp{mode} and
+@samp{word-num}. There are three cases.
+
+If @samp{mode} is the same size as the mode of @samp{value}, @samp{word-num}
+must be @samp{0} and the result is @samp{value} recast in the new mode.
+There is no change in the bits of @samp{value}, they're just interpreted in a
+possibly different mode. This is most often used to interpret an integer
+value as a float and vice versa.
+
+If @samp{mode} is smaller, @samp{value} is divided into N pieces and
+@samp{word-num} picks which piece. All pieces have the size of @samp{mode}
+except possibly the last. If the last piece has a different size,
+it cannot be referenced.
+This follows GCC and is byte order dependent.@footnote{To be
+revisited}.
+Word number 0 is the most significant word if big-endian-words.
+Word number 0 is the least significant word if little-endian-words.
+
+If @samp{mode} is larger, @samp{value} is interpreted in the larger mode
+with the upper most significant bits treated as garbage (their value is
+assumed to be unimportant to the context in which the value will be used).
+@samp{word-num} must be @samp{0}.
+This case is byte order independent.
+
+@item (join out-mode in-mode arg1 . arg-rest)
+Concatenate @samp{arg1[,arg2[,...]]} to create a value of mode @samp{out-mode}.
+@samp{arg1} becomes the most significant part of the result.
+Each argument is interpreted in mode @samp{in-mode}.
+@samp{in-mode} must evenly divide @samp{out-mode}.
+??? Endianness issues have yet to be decided.
+
+@item (sequence mode ((mode1 local1) ...) expr1 expr2 ...)
+Execute @samp{expr1}, @samp{expr2}, etc. sequentially. @samp{mode} is the
+mode of the result, which is defined to be that of the last expression.
+`@code{((mode1 local1) ...)}' is a set of local variables.
+
+@item (parallel mode empty expr1 ...)
+Execute @samp{expr1}, @samp{expr2}, etc. in parallel. All inputs are
+read before any output is written. @samp{empty} must be @samp{()} and
+is present for consistency with @samp{sequence}. @samp{mode} must be
+@samp{VOID} (void mode). @samp{((mode1 local1) ...)} is a set of local
+variables.
+
+@item (unop mode operand)
+Perform a unary arithmetic operation. @samp{unop} is one of @code{neg},
+@code{abs}, @code{inv}, @code{not}, @code{zflag}, @code{nflag}.
+@code{zflag} returns a bit indicating if @samp{operand} is
+zero. @code{nflag} returns a bit indicating if @samp{operand} is
+negative. @code{inv} returns the bitwise complement of @samp{operand},
+whereas @code{not} returns its logical negation.
+
+@item (binop mode operand1 operand2)
+Perform a binary arithmetic operation. @samp{binop} is one of
+@code{add}, @code{sub}, @code{and}, @code{or}, @code{xor}, @code{mul},
+@code{div}, @code{udiv}, @code{mod}, @code{umod}.
+
+@item (binop-with-bit mode operand1 operand2 operand3)
+Same as @samp{binop}, except taking 3 operands. The third operand is
+always a single bit. @samp{binop-with-bit} is one of @code{addc},
+@code{add-cflag}, @code{add-oflag}, @code{subc}, @code{sub-cflag},
+@code{sub-oflag}.
+
+@item (shiftop mode operand1 operand2)
+Perform a shift operation. @samp{shiftop} is one of @code{sll},
+@code{srl}, @code{sra}, @code{ror}, @code{rol}.
+
+@item (boolifop mode operand1 operand2)
+Perform a sequential boolean operation. @samp{operand2} is not processed
+if @samp{operand1} ``fails''. @samp{boolifop} is one of @code{andif},
+@code{orif}.
+
+@item (convop mode operand)
+Perform a mode->mode conversion operation. @samp{convop} is one of
+@code{ext}, @code{zext}, @code{trunc}, @code{float}, @code{ufloat},
+@code{fix}, @code{ufix}.
+
+@item (cmpop mode operand1 operand2)
+Perform a comparison. @samp{cmpop} is one of @code{eq}, @code{ne},
+@code{lt}, @code{le}, @code{gt}, @code{ge}, @code{ltu}, @code{leu},
+@code{gtu}, @code{geu}.
+
+@item (if mode condition then [else])
+Standard @code{if} statement.
+
+@samp{condition} is any arithmetic expression.
+If the value is non-zero the @samp{then} part is executed.
+Otherwise, the @samp{else} part is executed (if present).
+
+@samp{mode} is the mode of the result, not of @samp{condition}.
+If @samp{mode} is not @code{VOID} (void mode), @samp{else} must be present.
+
+@item (cond mode (condition1 expr1a ...) (...) [(else exprNa...)])
+From Scheme: keep testing conditions until one succeeds, and then
+process the associated expressions.
+
+@item (case mode test ((case1 ..) expr1a ..) (..) [(else exprNa ..)])
+From Scheme: Compare @samp{test} with @samp{case1}, @samp{case2},
+etc. and process the associated expressions.
+
+@item (c-code mode "C expression")
+An escape hook to insert arbitrary C code. @samp{mode} must the
+compatible with the result of ``C expression''.
+
+@item (c-call mode symbol operand1 operand2 ...)
+An escape hook to emit a subroutine call to function named @samp{symbol}
+passing operands @samp{operand1}, @samp{operand2}, etc. An implicit
+first argument of @code{current_cpu} is passed to @samp{symbol}.
+@samp{mode} is the mode of the result. Be aware that @samp{symbol} will
+be restricted by reserved words in the C programming language any by
+existing symbols in the generated code.
+
+@item (c-raw-call mode symbol operand1 operand2 ...)
+Same as @code{c-call}: except there is no implicit @code{current_cpu}
+first argument.
+@samp{mode} is the mode of the result.
+
+@item (clobber mode object)
+Indicate that @samp{object} is written in mode @samp{mode}, without
+saying how. This could be useful in conjunction with the C escape hooks.
+
+@item (annul yes?)
+@c FIXME: put annul into the glossary.
+Annul the following instruction if @samp{yes?} is non-zero. This rtx is
+an experiment and will probably change.
+
+@item (skip yes?)
+Skip the next instruction if @samp{yes?} is non-zero. This rtx is
+an experiment and will probably change.
+
+@item (attr mode kind attr-name)
+Return the value of attribute @samp{attr-name} in mode
+@samp{mode}. @samp{kind} must currently be @samp{insn}: the current
+instruction.
+
+@item (symbol name)
+Return a symbol with value @samp{name}, for use in attribute
+processing. This is equivalent to @samp{quote} in Scheme but
+@samp{quote} sounds too jargonish.
+
+@item (eq-attr mode attr-name value)
+Return non-zero if the value of attribute @samp{attr-name} is
+@samp{value}. If @samp{value} is a list return ``true'' if
+@samp{attr-name} is any of the listed values.
+
+@item (nop)
+A no-op.
+
+@item (ifield field-name)
+Return the value of field @samp{field-name}. @samp{field-name} must be a
+field in the instruction. Operands can be any of:
+@c ???
+
+@itemize @bullet
+@item an operand defined in the description file
+@item a register reference, created with (reg mode [index])
+@item a memory reference, created with (mem mode address)
+@item a constant, created with (const mode value)
+@item a `sequence' local variable
+@item another expression
+@end itemize
+
+The @samp{symbol} in a @code{c-call} or @code{c-raw-call} function is
+currently the name of a C function or macro that is invoked by the
+generated semantic code.
+@end table
+
+@node Macro-expressions
+@section Macro-expressions
+@cindex Macro-expressions
+
+Macro RTL expressions started out by wanting to not have to always
+specify a mode for every expression (and sub-expression
+thereof). Whereas the formal way to specify, say, an add is @code{(add
+SI arg1 arg2)} if SI is the default mode of `arg1' then this can be
+simply written as @code{(add arg1 arg2)}. This gets expanded to
+@code{(add DFLT arg1 arg2)} where @code{DFLT} means ``default mode''.
+
+It might be possible to replace macro expressions with preprocessor macros,
+however for the nonce there is no plan to do this.
diff --git a/cgen/doc/running.texi b/cgen/doc/running.texi
new file mode 100644
index 00000000000..644dad183a3
--- /dev/null
+++ b/cgen/doc/running.texi
@@ -0,0 +1,9 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Running CGEN
+@chapter Running CGEN
+
+This chapter needs to explain how to run CGEN, how it fits together, and
+what to expect when you do run it (ie. output, resultant files, etc).
diff --git a/cgen/doc/sim.texi b/cgen/doc/sim.texi
new file mode 100644
index 00000000000..11c08fa6d99
--- /dev/null
+++ b/cgen/doc/sim.texi
@@ -0,0 +1,45 @@
+@c Copyright (C) 2000 Red Hat, Inc.
+@c This file is part of the CGEN manual.
+@c For copying conditions, see the file cgen.texi.
+
+@node Simulation
+@chapter Simulation support
+@cindex Simulation support
+
+Simulator support comes in the form of machine generated the decoder/executer
+as well as the structure that records CPU state information (ie. registers).
+
+There are 3 architecture-wide generated files:
+
+@table @file
+@item arch.h
+Definitions and declarations common to the entire architecture.
+@item arch.c
+Tables and code common to the entire architecture, but which can't be
+put in the common area.
+@item cpuall.h
+Pseudo base classes of various structures.
+@end table
+
+Each ``CPU family'' has its own set of the following files:
+
+@table @file
+@item cpu.h
+Definitions and declarations specific to a particular CPU family.
+@item cpu.c
+Tables and code specific to a particular CPU family.
+@item decode.h
+Decoder definitions and declarations.
+@item decode.c
+Decoder tables and code.
+@item model.c
+Tables and code for each model in the CPU family.
+@item semantics.c
+Code to perform each instruction.
+@item sem-switch.c
+Same as @file{semantics.c} but as one giant @code{switch} statement.
+@end table
+
+A ``CPU family'' is an artificial creation to sort architecture variants
+along whatever lines seem useful. Additional hand-written files must be
+provided. @xref{Porting} for details.
diff --git a/cgen/doc/stamp-vti b/cgen/doc/stamp-vti
new file mode 100644
index 00000000000..3e1e7a5eb20
--- /dev/null
+++ b/cgen/doc/stamp-vti
@@ -0,0 +1,3 @@
+@set UPDATED 11 October 1999
+@set EDITION 1.0
+@set VERSION 1.0
diff --git a/cgen/doc/version.texi b/cgen/doc/version.texi
new file mode 100644
index 00000000000..ef3c4e22488
--- /dev/null
+++ b/cgen/doc/version.texi
@@ -0,0 +1,3 @@
+@set UPDATED 31 July 2000
+@set EDITION 1.0
+@set VERSION 1.0
diff --git a/cgen/enum.scm b/cgen/enum.scm
new file mode 100644
index 00000000000..3e4c9c94e14
--- /dev/null
+++ b/cgen/enum.scm
@@ -0,0 +1,391 @@
+; Enums.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Enums having attribute PREFIX have their symbols prepended with
+; the enum class' name.
+; Member PREFIX is always prepended to the symbol names.
+;
+; Enum values are looked up with `enum-lookup-val'. The value to search for
+; has PREFIX prepended.
+;
+; Enums always have mode INT.
+
+(define <enum>
+ (class-make '<enum>
+ '(<ident>)
+ '(prefix vals)
+ nil)
+)
+
+; FIXME: this make! method is required by <insn-enum> for some reason.
+(method-make!
+ <enum> 'make!
+ (lambda (self name comment attrs prefix vals)
+ (elm-set! self 'name name)
+ (elm-set! self 'comment comment)
+ (elm-set! self 'attrs attrs)
+ (elm-set! self 'prefix prefix)
+ (elm-set! self 'vals vals)
+ self)
+)
+
+(define enum-prefix (elm-make-getter <enum> 'prefix))
+
+(method-make! <enum> 'enum-values (lambda (self) (elm-get self 'vals)))
+
+; Parse a list of enum name/value entries.
+; PREFIX is prepended to each name.
+; Elements are any of: symbol, (symbol), (symbol value)
+; (symbol - attrs), (symbol value attrs).
+; The `-' means use the next value.
+; The result is the same list, except values are filled in where missing,
+; and each symbol is prepended with `prefix'.
+
+(define (parse-enum-vals prefix vals)
+ ; Scan the value list, building up RES-VALS as we go.
+ ; Each element's value is 1+ the previous, unless there's an explicit value.
+ (let loop ((result nil) (last -1) (remaining vals))
+ (if (null? remaining)
+ (reverse! result)
+ (let
+ ; Compute the numeric value the next entry will have.
+ ((val (if (and (pair? (car remaining))
+ (not (null? (cdar remaining))))
+ (if (eq? '- (cadar remaining))
+ (+ last 1)
+ (cadar remaining))
+ (+ last 1))))
+ (if (eq? (car remaining) '-)
+ (loop result val (cdr remaining))
+ (loop (cons (cons (symbol-append prefix
+ (if (pair? (car remaining))
+ (caar remaining)
+ (car remaining)))
+ (cons val
+ ; Pass any attributes through unchanged.
+ (if (and (pair? (car remaining))
+ (pair? (cdar remaining)))
+ (cddar remaining)
+ nil)))
+ result)
+ val
+ (cdr remaining))))))
+)
+
+; Convert the names in the result of parse-enum-vals to uppercase.
+
+(define (enum-vals-upcase vals)
+ (map (lambda (elm)
+ (cons (string->symbol (string-upcase (car elm))) (cdr elm)))
+ vals)
+)
+
+; Parse an enum definition.
+
+; Utility of -enum-parse to parse the prefix.
+
+(define (-enum-parse-prefix errtxt prefix)
+ (if (symbol? prefix)
+ (set! prefix (symbol->string prefix)))
+
+ (if (not (string? prefix))
+ (parse-error errtxt "prefix is not a string" prefix))
+
+ ; Prefix must not contain lowercase chars (enforced style rule, sue me).
+ (if (any-true? (map char-lower-case? (string->list prefix)))
+ (parse-error errtxt "prefix must be uppercase" prefix))
+
+ prefix
+)
+
+; This is the main routine for building an ifield object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-enum-parse errtxt name comment attrs prefix vals)
+ (logit 2 "Processing enum " name " ...\n")
+
+ (let* ((name (parse-name name errtxt))
+ (errtxt (string-append errtxt " " name)))
+
+ (make <enum>
+ name
+ (parse-comment comment errtxt)
+ (atlist-parse attrs "enum" errtxt)
+ (-enum-parse-prefix errtxt prefix)
+ (parse-enum-vals prefix vals)))
+)
+
+; Read an enum description
+; This is the main routine for analyzing enums in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -enum-parse is invoked to create the `enum' object.
+
+(define (-enum-read errtxt . arg-list)
+ (let (; Current enum elements:
+ (name nil) ; name of field
+ (comment "") ; description of field
+ (attrs nil) ; attributes
+ (prefix "") ; prepended to each element's name
+ (values nil) ; enum values
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((prefix) (set! prefix (cadr arg)))
+ ((values) (set! values (cadr arg)))
+ (else (parse-error errtxt "invalid enum arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-enum-parse errtxt name comment attrs prefix values)
+ )
+)
+
+; Define an enum object, name/value pair list version.
+
+(define define-enum
+ (lambda arg-list
+ (let ((e (apply -enum-read (cons "define-enum" arg-list))))
+ (current-enum-add! e)
+ e))
+)
+
+; Define an enum object, all arguments specified.
+
+(define (define-full-enum name comment attrs prefix vals)
+ (let ((e (-enum-parse "define-full-enum" name comment attrs prefix vals)))
+ (current-enum-add! e)
+ e)
+)
+
+; Lookup SYM in all recorded enums.
+; The result is (value . enum-obj) or #f if not found.
+
+(define (enum-lookup-val name)
+ (let loop ((elist (current-enum-list)))
+ (if (null? elist)
+ #f
+ (let ((e (assq name (send (car elist) 'enum-values))))
+ ;(display e) (newline)
+ (if e
+ (begin
+ ; sanity check, ensure the enum has a value
+ (if (null? (cdr e)) (error "enum-lookup-val: enum missing value: " (car e)))
+ (cons (cadr e) (car elist)))
+ (loop (cdr elist)))
+ )
+ )
+ )
+)
+
+; Enums support code.
+
+; Return #t if VALS is a sequential list of enum values.
+; VALS is a list of enums. e.g. ((sym1) (sym2 3) (sym3 '- attr1 (attr2 4)))
+; FIXME: Doesn't handle gaps in specified values.
+; e.g. (sym1 val1) sym2 (sym3 val3)
+
+(define (enum-sequential? vals)
+ (let loop ((last -1) (remaining vals))
+ (if (null? remaining)
+ #t
+ (let ((val (if (and (pair? (car remaining))
+ (not (null? (cdar remaining))))
+ (cadar remaining)
+ (+ last 1))))
+ (if (eq? val '-)
+ (loop (+ last 1) (cdr remaining))
+ (if (not (= val (+ last 1)))
+ #f
+ (loop val (cdr remaining)))))))
+)
+
+; Return C code to declare enum SYM with values VALS.
+; COMMENT is inserted in "/* Enum declaration for <...>. */".
+; PREFIX is added to each element of VALS.
+; All enum symbols are uppercase.
+; If the list of vals is sequential beginning at 0, don't output them.
+; This simplifies the output and is necessary for sanitized values where
+; some values may be cut out.
+; VALS may have '- for the value, signifying use the next value as in C.
+
+(define (gen-enum-decl name comment prefix vals)
+ (logit 2 "Generating enum decl for " name " ...\n")
+ ; Build result up as a list and then flatten it into a string.
+ ; We could just return a string-list but that seems like too much to ask
+ ; of callers.
+ (string-list->string
+ (append!
+ (string-list
+ "/* Enum declaration for " comment ". */\n"
+ "typedef enum "
+ (string-downcase (gen-c-symbol name))
+ " {")
+ (let loop ((n 0) ; `n' is used to track the number of entries per line only
+ (sequential? (enum-sequential? vals))
+ (vals vals)
+ (result (list "")))
+ (if (null? vals)
+ result
+ (let* ((e (car vals))
+ (attrs (if (null? (cdr e)) nil (cddr e)))
+ (san-code (attr-value attrs 'sanitize #f))
+ (san? (and san-code (not (eq? san-code 'none)))))
+ (loop
+ (if san?
+ 4 ; reset to beginning of line (but != 0)
+ (+ n 1))
+ sequential?
+ (cdr vals)
+ (append!
+ result
+ (string-list
+ (if san?
+ (string-append "\n"
+ (if include-sanitize-marker?
+ ; split string to avoid removal
+ (string-append "/* start-"
+ "sanitize-"
+ san-code " */\n")
+ "")
+ " ")
+ "")
+ (string-upcase
+ (string-append
+ (if (and (not san?) (=? (remainder n 4) 0))
+ "\n "
+ "")
+ (if (= n 0)
+ " "
+ ", ")
+ (gen-c-symbol prefix)
+ (gen-c-symbol (car e))
+ (if (or sequential? (null? (cdr e)) (eq? '- (cadr e)))
+ ""
+ (string-append " = "
+ (if (number? (cadr e))
+ (number->string (cadr e))
+ (cadr e))))
+ ))
+ (if (and san? include-sanitize-marker?)
+ ; split string to avoid removal
+ (string-append "\n/* end-"
+ "sanitize-" san-code " */")
+ "")))))))
+ (string-list
+ "\n} "
+ (string-upcase (gen-c-symbol name))
+ ";\n\n")
+ ))
+)
+
+; Return a list of enum value definitions for gen-enum-decl.
+; OBJ-LIST is a list of objects that support obj:name, obj-atlist.
+
+(define (gen-obj-list-enums obj-list)
+ (map (lambda (o)
+ (cons (obj:name o) (cons '- (atlist-attrs (obj-atlist o)))))
+ obj-list)
+)
+
+; Return C code that declares[/defines] an enum.
+
+(method-make!
+ <enum> 'gen-decl
+ (lambda (self)
+ (gen-enum-decl (elm-get self 'name)
+ (elm-get self 'comment)
+ (if (has-attr? self 'PREFIX)
+ (string-append (elm-get self 'name) "_")
+ "")
+ (elm-get self 'vals)))
+)
+
+; Return the C symbol of an enum value named VAL.
+
+(define (gen-enum-sym enum-obj val)
+ (string-upcase (gen-c-symbol (string-append (enum-prefix enum-obj) val)))
+)
+
+; Instruction code enums.
+; These associate an enum with an instruction field so that the enum values
+; can be used in instruction field lists.
+
+(define <insn-enum> (class-make '<insn-enum> '(<enum>) '(fld) nil))
+
+(method-make!
+ <insn-enum> 'make!
+ (lambda (self name comment attrs prefix fld vals)
+ (send (object-parent self <enum>) 'make! name comment attrs prefix vals)
+ (elm-set! self 'fld fld)
+ self
+ )
+)
+
+(define ienum:fld (elm-make-getter <insn-enum> 'fld))
+
+; Same as enum-lookup-val except returned enum must be an insn-enum.
+
+(define (ienum-lookup-val name)
+ (let ((result (enum-lookup-val name)))
+ (if (and result (eq? (object-class-name (cdr result)) '<insn-enum>))
+ result
+ #f))
+)
+
+; Define an insn enum, all arguments specified.
+
+(define (define-full-insn-enum name comment attrs prefix fld vals)
+ (let ((errtxt "define-full-insn-enum")
+ (fld-obj (current-ifld-lookup fld)))
+
+ (if (not fld-obj)
+ (parse-error errtxt "unknown insn field" fld))
+
+ ; Create enum object and add it to the list of enums.
+ (let ((e (make <insn-enum>
+ (parse-name name errtxt)
+ (parse-comment comment errtxt)
+ (atlist-parse attrs "insn-enum" errtxt)
+ (-enum-parse-prefix errtxt prefix)
+ fld-obj
+ (parse-enum-vals prefix vals))))
+ (current-enum-add! e)
+ e))
+)
+
+(define (enum-init!)
+
+ (reader-add-command! 'define-enum
+ "\
+Define an enum, name/value pair list version.
+"
+ nil 'arg-list define-enum)
+ (reader-add-command! 'define-full-enum
+ "\
+Define an enum, all arguments specified.
+"
+ nil '(name comment attrs prefix vals) define-full-enum)
+ (reader-add-command! 'define-full-insn-enum
+ "\
+Define an instruction opcode enum, all arguments specified.
+"
+ nil '(name comment attrs prefix ifld vals)
+ define-full-insn-enum)
+
+ *UNSPECIFIED*
+)
+
+(define (enum-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/fixup.scm b/cgen/fixup.scm
new file mode 100644
index 00000000000..fe06241cd31
--- /dev/null
+++ b/cgen/fixup.scm
@@ -0,0 +1,38 @@
+; Fix up the current interpreter-du-jour to conform to what we've
+; been working with.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; check for newer guile
+
+(if (symbol-bound? #f 'load-from-path)
+ (begin
+ (define (load file)
+ (begin
+ ;(load-from-path file)
+ (primitive-load-path file)
+ ))
+ )
+)
+
+; FIXME: to be deleted
+(define =? =)
+(define >=? >=)
+
+(if (not (symbol-bound? #f '%stat))
+ (begin
+ (define %stat stat)
+ )
+)
+
+(if (symbol-bound? #f 'debug-enable)
+ (debug-enable 'backtrace)
+)
+
+; Guile 1.3 has reverse!, Guile 1.2 has list-reverse!.
+; CGEN uses reverse!
+(if (and (not (symbol-bound? #f 'reverse!))
+ (symbol-bound? #f 'list-reverse!))
+ (define reverse! list-reverse!)
+)
diff --git a/cgen/fr30.cpu b/cgen/fr30.cpu
new file mode 100644
index 00000000000..eb1d39788ab
--- /dev/null
+++ b/cgen/fr30.cpu
@@ -0,0 +1,1845 @@
+; Fujitsu FR30 CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+(include "simplify.inc")
+
+; define-arch must appear first
+
+(define-arch
+ (name fr30) ; name of cpu family
+ (comment "Fujitsu FR30")
+ (default-alignment forced)
+ (insn-lsb0? #f)
+ (machs fr30)
+ (isas fr30)
+)
+
+(define-isa
+ (name fr30)
+ (base-insn-bitsize 16)
+ (decode-assist (0 1 2 3 4 5 6 7)) ; Initial bitnumbers to decode insns by.
+ (liw-insns 1) ; The fr30 fetches 1 insn at a time.
+ (parallel-insns 1) ; The fr30 executes 1 insn at a time.
+)
+
+(define-cpu
+ ; cpu names must be distinct from the architecture name and machine names.
+ ; The "b" suffix stands for "base" and is the convention.
+ ; The "f" suffix stands for "family" and is the convention.
+ (name fr30bf)
+ (comment "Fujitsu FR30 base family")
+ (endian big)
+ (word-bitsize 32)
+)
+
+(define-mach
+ (name fr30)
+ (comment "Generic FR30 cpu")
+ (cpu fr30bf)
+)
+
+; Model descriptions.
+;
+(define-model
+ (name fr30-1) (comment "fr30-1") (attrs)
+ (mach fr30)
+
+ (pipeline all "" () ((fetch) (decode) (execute) (writeback)))
+
+ ; `state' is a list of variables for recording model state
+ (state
+ ; bit mask of h-gr registers loaded from memory by previous insn
+ (load-regs UINT)
+ ; bit mask of h-gr registers loaded from memory by current insn
+ (load-regs-pending UINT)
+ )
+
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((Ri INT -1) (Rj INT -1)) ; inputs
+ ((Ri INT -1)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-cti "Branch Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((Ri INT -1)) ; inputs
+ ((pc)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-load "Memory Load Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((Rj INT -1)
+ ;(ld-mem AI)
+ ) ; inputs
+ ((Ri INT -1)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-store "Memory Store Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((Ri INT -1) (Rj INT -1)) ; inputs
+ () ; ((st-mem AI)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-ldm "LDM Memory Load Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((reglist INT)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+ (unit u-stm "STM Memory Store Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((reglist INT)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+)
+
+; The instruction fetch/execute cycle.
+;
+; This is how to fetch and decode an instruction.
+; Leave it out for now
+
+; (define-extract (const SI 0))
+
+; This is how to execute a decoded instruction.
+; Leave it out for now
+
+; (define-execute (const SI 0))
+
+; Instruction fields.
+;
+; Attributes:
+; PCREL-ADDR: pc relative value (for reloc and disassembly purposes)
+; ABS-ADDR: absolute address (for reloc and disassembly purposes?)
+; RESERVED: bits are not used to decode insn, must be all 0
+
+(dnf f-op1 "1st 4 bits of opcode" () 0 4)
+(dnf f-op2 "2nd 4 bits of opcode" () 4 4)
+(dnf f-op3 "3rd 4 bits of opcode" () 8 4)
+(dnf f-op4 "4th 4 bits of opcode" () 12 4)
+(dnf f-op5 "5th bit of opcode" () 4 1)
+(dnf f-cc "condition code" () 4 4)
+(dnf f-ccc "coprocessor calc code" () 16 8)
+(dnf f-Rj "register Rj" () 8 4)
+(dnf f-Ri "register Ri" () 12 4)
+(dnf f-Rs1 "register Rs" () 8 4)
+(dnf f-Rs2 "register Rs" () 12 4)
+(dnf f-Rjc "register Rj" () 24 4)
+(dnf f-Ric "register Ri" () 28 4)
+(dnf f-CRj "coprocessor register" () 24 4)
+(dnf f-CRi "coprocessor register" () 28 4)
+(dnf f-u4 "4 bit 0 extended" () 8 4)
+(dnf f-u4c "4 bit 0 extended" () 12 4)
+(df f-i4 "4 bit sign extended" () 8 4 INT #f #f)
+(df f-m4 "4 bit minus extended" () 8 4 UINT
+ ((value pc) (and WI value (const #xf)))
+ ; ??? On a 64 bit host this doesn't get completely sign extended
+ ; if the value is recorded in a long, as it is during extraction.
+ ; Various fixes exist, pick one.
+ ((value pc) (or WI value (sll WI (const -1) (const 4))))
+)
+(dnf f-u8 "8 bit unsigned" () 8 8)
+(dnf f-i8 "8 bit unsigned" () 4 8)
+
+(dnf f-i20-4 "upper 4 bits of i20" () 8 4)
+(dnf f-i20-16 "lower 16 bits of i20" () 16 16)
+(dnmf f-i20 "20 bit unsigned" () UINT
+ (f-i20-4 f-i20-16)
+ (sequence () ; insert
+ (set (ifield f-i20-4) (srl (ifield f-i20) (const 16)))
+ (set (ifield f-i20-16) (and (ifield f-i20) (const #xffff)))
+ )
+ (sequence () ; extract
+ (set (ifield f-i20) (or (sll (ifield f-i20-4) (const 16))
+ (ifield f-i20-16)))
+ )
+)
+
+(dnf f-i32 "32 bit immediate" (SIGN-OPT) 16 32)
+
+(df f-udisp6 "6 bit unsigned offset" () 8 4 UINT
+ ((value pc) (srl UWI value (const 2)))
+ ((value pc) (sll UWI value (const 2)))
+)
+(df f-disp8 "8 bit signed offset" () 4 8 INT #f #f)
+(df f-disp9 "9 bit signed offset" () 4 8 INT
+ ((value pc) (sra WI value (const 1)))
+ ((value pc) (sll WI value (const 1)))
+)
+(df f-disp10 "10 bit signed offset" () 4 8 INT
+ ((value pc) (sra WI value (const 2)))
+ ((value pc) (sll WI value (const 2)))
+)
+(df f-s10 "10 bit signed offset" () 8 8 INT
+ ((value pc) (sra WI value (const 2)))
+ ((value pc) (sll WI value (const 2)))
+)
+(df f-u10 "10 bit unsigned offset" () 8 8 UINT
+ ((value pc) (srl UWI value (const 2)))
+ ((value pc) (sll UWI value (const 2)))
+)
+(df f-rel9 "9 pc relative signed offset" (PCREL-ADDR) 8 8 INT
+ ((value pc) (sra WI (sub WI value (add WI pc (const 2))) (const 1)))
+ ((value pc) (add WI (sll WI value (const 1)) (add WI pc (const 2))))
+)
+(dnf f-dir8 "8 bit direct address" () 8 8)
+(df f-dir9 "9 bit direct address" () 8 8 UINT
+ ((value pc) (srl UWI value (const 1)))
+ ((value pc) (sll UWI value (const 1)))
+)
+(df f-dir10 "10 bit direct address" () 8 8 UINT
+ ((value pc) (srl UWI value (const 2)))
+ ((value pc) (sll UWI value (const 2)))
+)
+(df f-rel12 "12 bit pc relative signed offset" (PCREL-ADDR) 5 11 INT
+ ((value pc) (sra WI (sub WI value (add WI pc (const 2))) (const 1)))
+ ((value pc) (add WI (sll WI value (const 1)) (add WI pc (const 2))))
+)
+
+(dnf f-reglist_hi_st "8 bit register mask for stm" () 8 8)
+(dnf f-reglist_low_st "8 bit register mask for stm" () 8 8)
+(dnf f-reglist_hi_ld "8 bit register mask for ldm" () 8 8)
+(dnf f-reglist_low_ld "8 bit register mask for ldm" () 8 8)
+
+; Enums.
+
+; insn-op1: bits 0-3
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op1 "insn op1 enums" () OP1_ f-op1
+ ("0" "1" "2" "3" "4" "5" "6" "7"
+ "8" "9" "A" "B" "C" "D" "E" "F")
+)
+
+; insn-op2: bits 4-7
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op2 "insn op2 enums" () OP2_ f-op2
+ ("0" "1" "2" "3" "4" "5" "6" "7"
+ "8" "9" "A" "B" "C" "D" "E" "F")
+)
+
+; insn-op3: bits 8-11
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op3 "insn op3 enums" () OP3_ f-op3
+ ("0" "1" "2" "3" "4" "5" "6" "7"
+ "8" "9" "A" "B" "C" "D" "E" "F")
+)
+
+; insn-op4: bits 12-15
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op4 "insn op4 enums" () OP4_ f-op4
+ ("0")
+)
+
+; insn-op5: bit 4 (5th bit origin 0)
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op5 "insn op5 enums" () OP5_ f-op5
+ ("0" "1")
+)
+
+; insn-cc: condition codes
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-cc "insn cc enums" () CC_ f-cc
+ ("ra" "no" "eq" "ne" "c" "nc" "n" "p" "v" "nv" "lt" "ge" "le" "gt" "ls" "hi")
+)
+
+; Hardware pieces.
+; These entries list the elements of the raw hardware.
+; They're also used to provide tables and other elements of the assembly
+; language.
+
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(define-keyword
+ (name gr-names)
+ (print-name h-gr)
+ (prefix "")
+ (values (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15)
+ (ac 13) (fp 14) (sp 15))
+)
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs PROFILE CACHE-ADDR)
+ (type register WI (16))
+ (indices extern-keyword gr-names)
+)
+
+(define-keyword
+ (name cr-names)
+ (print-name h-cr)
+ (prefix "")
+ (values (cr0 0) (cr1 1) (cr2 2) (cr3 3)
+ (cr4 4) (cr5 5) (cr6 6) (cr7 7)
+ (cr8 8) (cr9 9) (cr10 10) (cr11 11)
+ (cr12 12) (cr13 13) (cr14 14) (cr15 15))
+)
+
+(define-hardware
+ (name h-cr)
+ (comment "coprocessor registers")
+ (attrs)
+ (type register WI (16))
+ (indices extern-keyword cr-names)
+)
+
+(define-keyword
+ (name dr-names)
+ (print-name h-dr)
+ (prefix "")
+ (values (tbr 0) (rp 1) (ssp 2) (usp 3) (mdh 4) (mdl 5))
+)
+
+(define-hardware
+ (name h-dr)
+ (comment "dedicated registers")
+ (type register WI (6))
+ (indices extern-keyword dr-names)
+ (get (index) (c-call WI "@cpu@_h_dr_get_handler" index))
+ (set (index newval) (c-call VOID "@cpu@_h_dr_set_handler" index newval))
+)
+
+(define-hardware
+ (name h-ps)
+ (comment "processor status")
+ (type register UWI)
+ (indices keyword "" ((ps 0)))
+ (get () (c-call UWI "@cpu@_h_ps_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_ps_set_handler" newval))
+)
+
+(dnh h-r13 "General Register 13 explicitly required"
+ ()
+ (register WI)
+ (keyword "" ((r13 0)))
+ () ()
+)
+
+(dnh h-r14 "General Register 14 explicitly required"
+ ()
+ (register WI)
+ (keyword "" ((r14 0)))
+ () ()
+)
+
+(dnh h-r15 "General Register 15 explicitly required"
+ ()
+ (register WI)
+ (keyword "" ((r15 0)))
+ () ()
+)
+
+; These bits are actually part of the PS register but are accessed more
+; often than the entire register, so define them directly. We can assemble
+; the PS register from its components when necessary.
+
+(dsh h-nbit "negative bit" () (register BI))
+(dsh h-zbit "zero bit" () (register BI))
+(dsh h-vbit "overflow bit" () (register BI))
+(dsh h-cbit "carry bit" () (register BI))
+(dsh h-ibit "interrupt enable bit" () (register BI))
+(define-hardware
+ (name h-sbit)
+ (comment "stack bit")
+ (type register BI)
+ (get () (c-call BI "@cpu@_h_sbit_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_sbit_set_handler" newval))
+)
+(dsh h-tbit "trace trap bit" () (register BI))
+(dsh h-d0bit "division 0 bit" () (register BI))
+(dsh h-d1bit "division 1 bit" () (register BI))
+
+; These represent sub-registers within the program status register
+
+(define-hardware
+ (name h-ccr)
+ (comment "condition code bits")
+ (type register UQI)
+ (get () (c-call UQI "@cpu@_h_ccr_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_ccr_set_handler" newval))
+)
+(define-hardware
+ (name h-scr)
+ (comment "system condition bits")
+ (type register UQI)
+ (get () (c-call UQI "@cpu@_h_scr_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_scr_set_handler" newval))
+)
+(define-hardware
+ (name h-ilm)
+ (comment "interrupt level mask")
+ (type register UQI)
+ (get () (c-call UQI "@cpu@_h_ilm_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_ilm_set_handler" newval))
+)
+
+; Instruction Operands.
+; These entries provide a layer between the assembler and the raw hardware
+; description, and are used to refer to hardware elements in the semantic
+; code. Usually there's a bit of over-specification, but in more complicated
+; instruction sets there isn't.
+
+; FR30 specific operand attributes:
+
+(define-attr
+ (for operand)
+ (type boolean)
+ (name HASH-PREFIX)
+ (comment "immediates have an optional '#' prefix")
+)
+
+; ??? Convention says this should be o-sr, but then the insn definitions
+; should refer to o-sr which is clumsy. The "o-" could be implicit, but
+; then it should be implicit for all the symbols here, but then there would
+; be confusion between (f-)simm8 and (h-)simm8.
+; So for now the rule is exactly as it appears here.
+
+(dnop Ri "destination register" () h-gr f-Ri)
+(dnop Rj "source register" () h-gr f-Rj)
+(dnop Ric "target register coproc insn" () h-gr f-Ric)
+(dnop Rjc "source register coproc insn" () h-gr f-Rjc)
+(dnop CRi "coprocessor register" () h-cr f-CRi)
+(dnop CRj "coprocessor register" () h-cr f-CRj)
+(dnop Rs1 "dedicated register" () h-dr f-Rs1)
+(dnop Rs2 "dedicated register" () h-dr f-Rs2)
+(dnop R13 "General Register 13" () h-r13 f-nil)
+(dnop R14 "General Register 14" () h-r14 f-nil)
+(dnop R15 "General Register 15" () h-r15 f-nil)
+(dnop ps "Program Status register" () h-ps f-nil)
+(dnop u4 "4 bit unsigned immediate" (HASH-PREFIX) h-uint f-u4)
+(dnop u4c "4 bit unsigned immediate" (HASH-PREFIX) h-uint f-u4c)
+(dnop u8 "8 bit unsigned immediate" (HASH-PREFIX) h-uint f-u8)
+(dnop i8 "8 bit unsigned immediate" (HASH-PREFIX) h-uint f-i8)
+(dnop udisp6 "6 bit unsigned immediate" (HASH-PREFIX) h-uint f-udisp6)
+(dnop disp8 "8 bit signed immediate" (HASH-PREFIX) h-sint f-disp8)
+(dnop disp9 "9 bit signed immediate" (HASH-PREFIX) h-sint f-disp9)
+(dnop disp10 "10 bit signed immediate" (HASH-PREFIX) h-sint f-disp10)
+
+(dnop s10 "10 bit signed immediate" (HASH-PREFIX) h-sint f-s10)
+(dnop u10 "10 bit unsigned immediate" (HASH-PREFIX) h-uint f-u10)
+(dnop i32 "32 bit immediate" (HASH-PREFIX) h-uint f-i32)
+
+(define-operand
+ (name m4)
+ (comment "4 bit negative immediate")
+ (attrs HASH-PREFIX)
+ (type h-sint)
+ (index f-m4)
+ (handlers (print "m4"))
+)
+
+(define-operand
+ (name i20)
+ (comment "20 bit immediate")
+ (attrs HASH-PREFIX)
+ (type h-uint)
+ (index f-i20)
+)
+
+(dnop dir8 "8 bit direct address" () h-uint f-dir8)
+(dnop dir9 "9 bit direct address" () h-uint f-dir9)
+(dnop dir10 "10 bit direct address" () h-uint f-dir10)
+
+(dnop label9 "9 bit pc relative address" () h-iaddr f-rel9)
+(dnop label12 "12 bit pc relative address" () h-iaddr f-rel12)
+
+(define-operand
+ (name reglist_low_ld)
+ (comment "8 bit low register mask for ldm")
+ (attrs)
+ (type h-uint)
+ (index f-reglist_low_ld)
+ (handlers (parse "low_register_list_ld")
+ (print "low_register_list_ld"))
+)
+
+(define-operand
+ (name reglist_hi_ld)
+ (comment "8 bit high register mask for ldm")
+ (attrs)
+ (type h-uint)
+ (index f-reglist_hi_ld)
+ (handlers (parse "hi_register_list_ld")
+ (print "hi_register_list_ld"))
+)
+
+(define-operand
+ (name reglist_low_st)
+ (comment "8 bit low register mask for stm")
+ (attrs)
+ (type h-uint)
+ (index f-reglist_low_st)
+ (handlers (parse "low_register_list_st")
+ (print "low_register_list_st"))
+)
+
+(define-operand
+ (name reglist_hi_st)
+ (comment "8 bit high register mask for stm")
+ (attrs)
+ (type h-uint)
+ (index f-reglist_hi_st)
+ (handlers (parse "hi_register_list_st")
+ (print "hi_register_list_st"))
+)
+
+(dnop cc "condition codes" () h-uint f-cc)
+(dnop ccc "coprocessor calc" (HASH-PREFIX) h-uint f-ccc)
+
+(dnop nbit "negative bit" (SEM-ONLY) h-nbit f-nil)
+(dnop vbit "overflow bit" (SEM-ONLY) h-vbit f-nil)
+(dnop zbit "zero bit" (SEM-ONLY) h-zbit f-nil)
+(dnop cbit "carry bit" (SEM-ONLY) h-cbit f-nil)
+(dnop ibit "interrupt bit" (SEM-ONLY) h-ibit f-nil)
+(dnop sbit "stack bit" (SEM-ONLY) h-sbit f-nil)
+(dnop tbit "trace trap bit" (SEM-ONLY) h-tbit f-nil)
+(dnop d0bit "division 0 bit" (SEM-ONLY) h-d0bit f-nil)
+(dnop d1bit "division 1 bit" (SEM-ONLY) h-d1bit f-nil)
+
+(dnop ccr "condition code bits" (SEM-ONLY) h-ccr f-nil)
+(dnop scr "system condition bits" (SEM-ONLY) h-scr f-nil)
+(dnop ilm "interrupt level mask" (SEM-ONLY) h-ilm f-nil)
+
+; Instruction definitions.
+;
+; Notes:
+; - dni is short for "define-normal-instruction"
+
+; FR30 specific insn attributes:
+
+(define-attr
+ (for insn)
+ (type boolean)
+ (name NOT-IN-DELAY-SLOT)
+ (comment "insn can't go in delay slot")
+)
+
+; Sets zbit and nbit based on the value of x
+;
+(define-pmacro (set-z-and-n x)
+ (sequence ()
+ (set zbit (eq x (const 0)))
+ (set nbit (lt x (const 0))))
+)
+
+; Binary integer instruction which sets status bits
+;
+(define-pmacro (binary-int-op name insn comment opc1 opc2 op arg1 arg2)
+ (dni name
+ (.str insn " " comment)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ()
+ (set vbit ((.sym op -oflag) arg2 arg1 (const 0)))
+ (set cbit ((.sym op -cflag) arg2 arg1 (const 0)))
+ (set arg2 (op arg2 arg1))
+ (set-z-and-n arg2))
+ ()
+ )
+)
+
+; Binary integer instruction which does *not* set status bits
+;
+(define-pmacro (binary-int-op-n name insn comment opc1 opc2 op arg1 arg2)
+ (dni name
+ (.str insn " " comment)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (set arg2 (op arg2 arg1))
+ ()
+ )
+)
+
+; Binary integer instruction with carry which sets status bits
+;
+(define-pmacro (binary-int-op-c name insn comment opc1 opc2 op arg1 arg2)
+ (dni name
+ (.str insn " " comment)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ((WI tmp))
+ (set tmp ((.sym op c) arg2 arg1 cbit))
+ (set vbit ((.sym op -oflag) arg2 arg1 cbit))
+ (set cbit ((.sym op -cflag) arg2 arg1 cbit))
+ (set arg2 tmp)
+ (set-z-and-n arg2))
+ ()
+ )
+)
+
+(binary-int-op add add "reg/reg" OP1_A OP2_6 add Rj Ri)
+(binary-int-op addi add "immed/reg" OP1_A OP2_4 add u4 Ri)
+(binary-int-op add2 add2 "immed/reg" OP1_A OP2_5 add m4 Ri)
+(binary-int-op-c addc addc "reg/reg" OP1_A OP2_7 add Rj Ri)
+(binary-int-op-n addn addn "reg/reg" OP1_A OP2_2 add Rj Ri)
+(binary-int-op-n addni addn "immed/reg" OP1_A OP2_0 add u4 Ri)
+(binary-int-op-n addn2 addn2 "immed/reg" OP1_A OP2_1 add m4 Ri)
+
+(binary-int-op sub sub "reg/reg" OP1_A OP2_C sub Rj Ri)
+(binary-int-op-c subc subc "reg/reg" OP1_A OP2_D sub Rj Ri)
+(binary-int-op-n subn subn "reg/reg" OP1_A OP2_E sub Rj Ri)
+
+; Integer compare instruction
+;
+(define-pmacro (int-cmp name insn comment opc1 opc2 arg1 arg2)
+ (dni name
+ (.str insn " " comment)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ((WI tmp1))
+ (set vbit (sub-oflag arg2 arg1 (const 0)))
+ (set cbit (sub-cflag arg2 arg1 (const 0)))
+ (set tmp1 (sub arg2 arg1))
+ (set-z-and-n tmp1)
+ )
+ ()
+ )
+)
+
+(int-cmp cmp cmp "reg/reg" OP1_A OP2_A Rj Ri)
+(int-cmp cmpi cmp "immed/reg" OP1_A OP2_8 u4 Ri)
+(int-cmp cmp2 cmp2 "immed/reg" OP1_A OP2_9 m4 Ri)
+
+; Binary logical instruction
+;
+(define-pmacro (binary-logical-op name insn comment opc1 opc2 op arg1 arg2)
+ (dni name
+ (.str insn " " comment)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ()
+ (set arg2 (op arg2 arg1))
+ (set-z-and-n arg2))
+ ()
+ )
+)
+
+(binary-logical-op and and "reg/reg" OP1_8 OP2_2 and Rj Ri)
+(binary-logical-op or or "reg/reg" OP1_9 OP2_2 or Rj Ri)
+(binary-logical-op eor eor "reg/reg" OP1_9 OP2_A xor Rj Ri)
+
+(define-pmacro (les-units model) ; les: load-exec-store
+ (model (unit u-exec) (unit u-load) (unit u-store))
+)
+
+; Binary logical instruction to memory
+;
+(define-pmacro (binary-logical-op-m name insn comment opc1 opc2 mode op arg1 arg2)
+ (dni name
+ (.str insn " " comment)
+ (NOT-IN-DELAY-SLOT)
+ (.str insn " $" arg1 ",@$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ((mode tmp))
+ (set mode tmp (op mode (mem mode arg2) arg1))
+ (set-z-and-n tmp)
+ (set mode (mem mode arg2) tmp))
+ ((les-units fr30-1))
+ )
+)
+
+(binary-logical-op-m andm and "reg/mem" OP1_8 OP2_4 WI and Rj Ri)
+(binary-logical-op-m andh andh "reg/mem" OP1_8 OP2_5 HI and Rj Ri)
+(binary-logical-op-m andb andb "reg/mem" OP1_8 OP2_6 QI and Rj Ri)
+(binary-logical-op-m orm or "reg/mem" OP1_9 OP2_4 WI or Rj Ri)
+(binary-logical-op-m orh orh "reg/mem" OP1_9 OP2_5 HI or Rj Ri)
+(binary-logical-op-m orb orb "reg/mem" OP1_9 OP2_6 QI or Rj Ri)
+(binary-logical-op-m eorm eor "reg/mem" OP1_9 OP2_C WI xor Rj Ri)
+(binary-logical-op-m eorh eorh "reg/mem" OP1_9 OP2_D HI xor Rj Ri)
+(binary-logical-op-m eorb eorb "reg/mem" OP1_9 OP2_E QI xor Rj Ri)
+
+; Binary logical instruction to low half of byte in memory
+;
+(dni bandl
+ "bandl #u4,@Ri"
+ (NOT-IN-DELAY-SLOT)
+ "bandl $u4,@$Ri"
+ (+ OP1_8 OP2_0 u4 Ri)
+ (set QI (mem QI Ri)
+ (and QI
+ (or QI u4 (const #xf0))
+ (mem QI Ri)))
+ ((les-units fr30-1))
+)
+
+(dni borl
+ "borl #u4,@Ri"
+ (NOT-IN-DELAY-SLOT)
+ "borl $u4,@$Ri"
+ (+ OP1_9 OP2_0 u4 Ri)
+ (set QI (mem QI Ri) (or QI u4 (mem QI Ri)))
+ ((les-units fr30-1))
+)
+
+(dni beorl
+ "beorl #u4,@Ri"
+ (NOT-IN-DELAY-SLOT)
+ "beorl $u4,@$Ri"
+ (+ OP1_9 OP2_8 u4 Ri)
+ (set QI (mem QI Ri) (xor QI u4 (mem QI Ri)))
+ ((les-units fr30-1))
+)
+
+; Binary logical instruction to high half of byte in memory
+;
+(dni bandh
+ "bandh #u4,@Ri"
+ (NOT-IN-DELAY-SLOT)
+ "bandh $u4,@$Ri"
+ (+ OP1_8 OP2_1 u4 Ri)
+ (set QI (mem QI Ri)
+ (and QI
+ (or QI (sll QI u4 (const 4)) (const #x0f))
+ (mem QI Ri)))
+ ((les-units fr30-1))
+)
+
+(define-pmacro (binary-or-op-mh name insn opc1 opc2 op arg1 arg2)
+ (dni name
+ (.str name " #" arg1 ",@" args)
+ (NOT-IN-DELAY-SLOT)
+ (.str name " $" arg1 ",@$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (set QI (mem QI arg2)
+ (insn QI
+ (sll QI arg1 (const 4))
+ (mem QI arg2)))
+ ((les-units fr30-1))
+ )
+)
+
+(binary-or-op-mh borh or OP1_9 OP2_1 or u4 Ri)
+(binary-or-op-mh beorh xor OP1_9 OP2_9 xor u4 Ri)
+
+(dni btstl
+ "btstl #u4,@Ri"
+ (NOT-IN-DELAY-SLOT)
+ "btstl $u4,@$Ri"
+ (+ OP1_8 OP2_8 u4 Ri)
+ (sequence ((QI tmp))
+ (set tmp (and QI u4 (mem QI Ri)))
+ (set zbit (eq tmp (const 0)))
+ (set nbit (const 0)))
+ ((fr30-1 (unit u-load) (unit u-exec (cycles 2))))
+)
+
+(dni btsth
+ "btsth #u4,@Ri"
+ (NOT-IN-DELAY-SLOT)
+ "btsth $u4,@$Ri"
+ (+ OP1_8 OP2_9 u4 Ri)
+ (sequence ((QI tmp))
+ (set tmp (and QI (sll QI u4 (const 4)) (mem QI Ri)))
+ (set zbit (eq tmp (const 0)))
+ (set nbit (lt tmp (const 0))))
+ ((fr30-1 (unit u-load) (unit u-exec (cycles 2))))
+)
+
+(dni mul
+ "mul Rj,Ri"
+ (NOT-IN-DELAY-SLOT)
+ "mul $Rj,$Ri"
+ (+ OP1_A OP2_F Rj Ri)
+ (sequence ((DI tmp))
+ (set tmp (mul DI (ext DI Rj) (ext DI Ri)))
+ (set (reg h-dr 5) (trunc WI tmp))
+ (set (reg h-dr 4) (trunc WI (srl tmp (const 32))))
+ (set nbit (lt (reg h-dr 5) (const 0)))
+ (set zbit (eq tmp (const DI 0)))
+ (set vbit (orif
+ (gt tmp (const DI #x7fffffff))
+ (lt tmp (neg (const DI #x80000000))))))
+ ((fr30-1 (unit u-exec (cycles 5))))
+)
+
+(dni mulu
+ "mulu Rj,Ri"
+ (NOT-IN-DELAY-SLOT)
+ "mulu $Rj,$Ri"
+ (+ OP1_A OP2_B Rj Ri)
+ (sequence ((DI tmp))
+ (set tmp (mul DI (zext DI Rj) (zext DI Ri)))
+ (set (reg h-dr 5) (trunc WI tmp))
+ (set (reg h-dr 4) (trunc WI (srl tmp (const 32))))
+ (set nbit (lt (reg h-dr 4) (const 0)))
+ (set zbit (eq (reg h-dr 5) (const 0)))
+ (set vbit (ne (reg h-dr 4) (const 0))))
+ ((fr30-1 (unit u-exec (cycles 5))))
+)
+
+(dni mulh
+ "mulh Rj,Ri"
+ (NOT-IN-DELAY-SLOT)
+ "mulh $Rj,$Ri"
+ (+ OP1_B OP2_F Rj Ri)
+ (sequence ()
+ (set (reg h-dr 5) (mul (trunc HI Rj) (trunc HI Ri)))
+ (set nbit (lt (reg h-dr 5) (const 0)))
+ (set zbit (ge (reg h-dr 5) (const 0))))
+ ((fr30-1 (unit u-exec (cycles 3))))
+)
+
+(dni muluh
+ "muluh Rj,Ri"
+ (NOT-IN-DELAY-SLOT)
+ "muluh $Rj,$Ri"
+ (+ OP1_B OP2_B Rj Ri)
+ (sequence ()
+ (set (reg h-dr 5) (mul (and Rj (const #xffff))
+ (and Ri (const #xffff))))
+ (set nbit (lt (reg h-dr 5) (const 0)))
+ (set zbit (ge (reg h-dr 5) (const 0))))
+ ((fr30-1 (unit u-exec (cycles 3))))
+)
+
+(dni div0s
+ "div0s Ri"
+ ()
+ "div0s $Ri"
+ (+ OP1_9 OP2_7 OP3_4 Ri)
+ (sequence ()
+ (set d0bit (lt (reg h-dr 5) (const 0)))
+ (set d1bit (xor d0bit (lt Ri (const 0))))
+ (if (ne d0bit (const 0))
+ (set (reg h-dr 4) (const #xffffffff))
+ (set (reg h-dr 4) (const 0))))
+ ()
+)
+
+(dni div0u
+ "div0u Ri"
+ ()
+ "div0u $Ri"
+ (+ OP1_9 OP2_7 OP3_5 Ri)
+ (sequence ()
+ (set d0bit (const 0))
+ (set d1bit (const 0))
+ (set (reg h-dr 4) (const 0)))
+ ()
+)
+
+(dni div1
+ "div1 Ri"
+ ()
+ "div1 $Ri"
+ (+ OP1_9 OP2_7 OP3_6 Ri)
+ (sequence ((WI tmp))
+ (set (reg h-dr 4) (sll (reg h-dr 4) (const 1)))
+ (if (lt (reg h-dr 5) (const 0))
+ (set (reg h-dr 4) (add (reg h-dr 4) (const 1))))
+ (set (reg h-dr 5) (sll (reg h-dr 5) (const 1)))
+ (if (eq d1bit (const 1))
+ (sequence ()
+ (set tmp (add (reg h-dr 4) Ri))
+ (set cbit (add-cflag (reg h-dr 4) Ri (const 0))))
+ (sequence ()
+ (set tmp (sub (reg h-dr 4) Ri))
+ (set cbit (sub-cflag (reg h-dr 4) Ri (const 0)))))
+ (if (not (xor (xor d0bit d1bit) cbit))
+ (sequence ()
+ (set (reg h-dr 4) tmp)
+ (set (reg h-dr 5) (or (reg h-dr 5) (const 1)))))
+ (set zbit (eq (reg h-dr 4) (const 0))))
+ ()
+)
+
+(dni div2
+ "div2 Ri"
+ ()
+ "div2 $Ri"
+ (+ OP1_9 OP2_7 OP3_7 Ri)
+ (sequence ((WI tmp))
+ (if (eq d1bit (const 1))
+ (sequence ()
+ (set tmp (add (reg h-dr 4) Ri))
+ (set cbit (add-cflag (reg h-dr 4) Ri (const 0))))
+ (sequence ()
+ (set tmp (sub (reg h-dr 4) Ri))
+ (set cbit (sub-cflag (reg h-dr 4) Ri (const 0)))))
+ (if (eq tmp (const 0))
+ (sequence ()
+ (set zbit (const 1))
+ (set (reg h-dr 4) (const 0)))
+ (set zbit (const 0))))
+ ()
+)
+
+(dni div3
+ "div3"
+ ()
+ "div3"
+ (+ OP1_9 OP2_F OP3_6 OP4_0)
+ (if (eq zbit (const 1))
+ (set (reg h-dr 5) (add (reg h-dr 5) (const 1))))
+ ()
+)
+
+(dni div4s
+ "div4s"
+ ()
+ "div4s"
+ (+ OP1_9 OP2_F OP3_7 OP4_0)
+ (if (eq d1bit (const 1))
+ (set (reg h-dr 5) (neg (reg h-dr 5))))
+ ()
+)
+
+(define-pmacro (leftshift-op name insn opc1 opc2 arg1 arg2 shift-expr)
+ (dni name
+ (.str insn " " arg1 "," arg2)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ((WI shift))
+ (set shift shift-expr)
+ (if (ne shift (const 0))
+ (sequence ()
+ (set cbit (ne (and arg2
+ (sll (const 1)
+ (sub (const 32) shift)))
+ (const 0)))
+ (set arg2 (sll arg2 shift)))
+ (set cbit (const 0)))
+ (set nbit (lt arg2 (const 0)))
+ (set zbit (eq arg2 (const 0))))
+ ()
+ )
+)
+(leftshift-op lsl lsl OP1_B OP2_6 Rj Ri (and Rj (const #x1f)))
+(leftshift-op lsli lsl OP1_B OP2_4 u4 Ri u4)
+(leftshift-op lsl2 lsl2 OP1_B OP2_5 u4 Ri (add u4 (const #x10)))
+
+(define-pmacro (rightshift-op name insn opc1 opc2 op arg1 arg2 shift-expr)
+ (dni name
+ (.str insn " " arg1 "," arg2)
+ ()
+ (.str insn " $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (sequence ((WI shift))
+ (set shift shift-expr)
+ (if (ne shift (const 0))
+ (sequence ()
+ (set cbit (ne (and arg2
+ (sll (const 1)
+ (sub shift (const 1))))
+ (const 0)))
+ (set arg2 (op arg2 shift)))
+ (set cbit (const 0)))
+ (set nbit (lt arg2 (const 0)))
+ (set zbit (eq arg2 (const 0))))
+ ()
+ )
+)
+(rightshift-op lsr lsr OP1_B OP2_2 srl Rj Ri (and Rj (const #x1f)))
+(rightshift-op lsri lsr OP1_B OP2_0 srl u4 Ri u4)
+(rightshift-op lsr2 lsr2 OP1_B OP2_1 srl u4 Ri (add u4 (const #x10)))
+(rightshift-op asr asr OP1_B OP2_A sra Rj Ri (and Rj (const #x1f)))
+(rightshift-op asri asr OP1_B OP2_8 sra u4 Ri u4)
+(rightshift-op asr2 asr2 OP1_B OP2_9 sra u4 Ri (add u4 (const #x10)))
+
+(dni ldi8
+ "load 8 bit unsigned immediate"
+ ()
+ "ldi:8 $i8,$Ri"
+ (+ OP1_C i8 Ri)
+ (set Ri i8)
+ ()
+)
+
+; Typing ldi:8 in in emacs is a pain.
+(dnmi ldi8m "ldi:8 without the colon"
+ (NO-DIS)
+ "ldi8 $i8,$Ri"
+ (emit ldi8 i8 Ri)
+)
+
+(dni ldi20
+ "load 20 bit unsigned immediate"
+ (NOT-IN-DELAY-SLOT)
+ "ldi:20 $i20,$Ri"
+ (+ OP1_9 OP2_B Ri i20)
+ (set Ri i20)
+ ((fr30-1 (unit u-exec (cycles 2))))
+)
+
+; Typing ldi:20 in in emacs is a pain.
+(dnmi ldi20m "ldi:20 without the colon"
+ (NO-DIS)
+ "ldi20 $i20,$Ri"
+ (emit ldi20 i20 Ri)
+)
+
+(dni ldi32
+ "load 32 bit immediate"
+ (NOT-IN-DELAY-SLOT)
+ "ldi:32 $i32,$Ri"
+ (+ OP1_9 OP2_F OP3_8 Ri i32)
+ (set Ri i32)
+ ((fr30-1 (unit u-exec (cycles 3))))
+)
+
+; Typing ldi:32 in in emacs is a pain.
+(dnmi ldi32m "ldi:32 without the colon"
+ (NO-DIS)
+ "ldi32 $i32,$Ri"
+ (emit ldi32 i32 Ri)
+)
+
+(define-pmacro (basic-ld name insn opc1 opc2 mode arg1 arg2)
+ (dni name
+ (.str name " @" arg1 "," arg2)
+ ()
+ (.str name " @$" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (set arg2 (mem mode arg1))
+ ((fr30-1 (unit u-load)))
+ )
+)
+
+(basic-ld ld ld OP1_0 OP2_4 WI Rj Ri)
+(basic-ld lduh lduh OP1_0 OP2_5 UHI Rj Ri)
+(basic-ld ldub ldub OP1_0 OP2_6 UQI Rj Ri)
+
+(define-pmacro (r13base-ld name insn opc1 opc2 mode arg1 arg2)
+ (dni name
+ (.str insn " @(R13," arg1 ")," arg2)
+ ()
+ (.str insn " @($R13,$" arg1 "),$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (set arg2 (mem mode (add arg1 (reg h-gr 13))))
+ ((fr30-1 (unit u-load)))
+ )
+)
+
+(r13base-ld ldr13 ld OP1_0 OP2_0 WI Rj Ri)
+(r13base-ld ldr13uh lduh OP1_0 OP2_1 UHI Rj Ri)
+(r13base-ld ldr13ub ldub OP1_0 OP2_2 UQI Rj Ri)
+
+(define-pmacro (r14base-ld name insn opc1 mode arg1 arg2)
+ (dni name
+ (.str insn " @(R14," arg1 ")," arg2)
+ ()
+ (.str insn " @($R14,$" arg1 "),$" arg2)
+ (+ opc1 arg1 arg2)
+ (set arg2 (mem mode (add arg1 (reg h-gr 14))))
+ ((fr30-1 (unit u-load)))
+ )
+)
+
+(r14base-ld ldr14 ld OP1_2 WI disp10 Ri)
+(r14base-ld ldr14uh lduh OP1_4 UHI disp9 Ri)
+(r14base-ld ldr14ub ldub OP1_6 UQI disp8 Ri)
+
+(dni ldr15
+ "ld @(R15,udisp6),Ri mem/reg"
+ ()
+ "ld @($R15,$udisp6),$Ri"
+ (+ OP1_0 OP2_3 udisp6 Ri)
+ (set Ri (mem WI (add udisp6 (reg h-gr 15))))
+ ((fr30-1 (unit u-load)))
+)
+
+(dni ldr15gr
+ "ld @R15+,Ri"
+ ()
+ "ld @$R15+,$Ri"
+ (+ OP1_0 OP2_7 OP3_0 Ri)
+ (sequence ()
+ (set Ri (mem WI (reg h-gr 15)))
+ (if (ne (ifield f-Ri) (const 15))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ ((fr30-1 (unit u-load)))
+)
+
+; This insn loads a value from where r15 points into the target register and
+; then increments r15. If the target register is also r15, then the post
+; increment is not performed.
+;
+(dni ldr15dr
+ "ld @R15+,Rs2"
+ ()
+ "ld @$R15+,$Rs2"
+ (+ OP1_0 OP2_7 OP3_8 Rs2)
+; This seems more straight forward, but doesn't work due to a problem in
+; cgen. We're trying to not increment r15 if it is the target register.
+; (sequence ()
+; (set Rs2 (mem WI (reg h-gr 15)))
+; (if (not (or (and (eq (ifield f-Rs2) (const 2))
+; (eq sbit (const 0)))
+; (and (eq (ifield f-Rs2) (const 3))
+; (eq sbit (const 1)))))
+; (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))
+; )
+; )
+ (sequence ((WI tmp))
+ (set tmp (mem WI (reg h-gr 15))) ; save in case target is r15
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))
+ (set Rs2 tmp))
+ ((fr30-1 (unit u-load)))
+)
+
+(dni ldr15ps
+ "ld @R15+,ps mem/reg"
+ (NOT-IN-DELAY-SLOT)
+ "ld @$R15+,$ps"
+ (+ OP1_0 OP2_7 OP3_9 OP4_0)
+ (sequence ()
+ (set ps (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4))))
+ ((fr30-1 (unit u-load)))
+)
+
+(define-pmacro (basic-st name insn opc1 opc2 mode arg1 arg2)
+ (dni name
+ (.str name " " arg1 ",@" arg2)
+ ()
+ (.str name " $" arg1 ",@$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (set (mem mode arg2) arg1)
+ ((fr30-1 (unit u-store)))
+ )
+)
+
+(basic-st st st OP1_1 OP2_4 WI Ri Rj)
+(basic-st sth sth OP1_1 OP2_5 HI Ri Rj)
+(basic-st stb stb OP1_1 OP2_6 QI Ri Rj)
+
+(define-pmacro (r13base-st name insn opc1 opc2 mode arg1 arg2)
+ (dni name
+ (.str insn " " arg1 ",@(R13," arg2 ")")
+ ()
+ (.str insn " $" arg1 ",@($R13,$" arg2 ")")
+ (+ opc1 opc2 arg1 arg2)
+ (set (mem mode (add arg2 (reg h-gr 13))) arg1)
+ ((fr30-1 (unit u-store)))
+ )
+)
+
+(r13base-st str13 st OP1_1 OP2_0 WI Ri Rj)
+(r13base-st str13h sth OP1_1 OP2_1 HI Ri Rj)
+(r13base-st str13b stb OP1_1 OP2_2 QI Ri Rj)
+
+(define-pmacro (r14base-st name insn opc1 mode arg1 arg2)
+ (dni name
+ (.str insn " " arg1 ",@(R14," arg2 ")")
+ ()
+ (.str insn " $" arg1 ",@($R14,$" arg2 ")")
+ (+ opc1 arg1 arg2)
+ (set (mem mode (add arg2 (reg h-gr 14))) arg1)
+ ((fr30-1 (unit u-store)))
+ )
+)
+
+(r14base-st str14 st OP1_3 WI Ri disp10)
+(r14base-st str14h sth OP1_5 HI Ri disp9)
+(r14base-st str14b stb OP1_7 QI Ri disp8)
+
+(dni str15
+ "st Ri,@(R15,udisp6) reg/mem"
+ ()
+ "st $Ri,@($R15,$udisp6)"
+ (+ OP1_1 OP2_3 udisp6 Ri)
+ (set (mem WI (add (reg h-gr 15) udisp6)) Ri)
+ ((fr30-1 (unit u-store)))
+)
+
+; These store insns predecrement r15 and then store the contents of the source
+; register where r15 then points. If the source register is also r15, then the
+; original value of r15 is stored.
+;
+(dni str15gr
+ "st Ri,@-R15 reg/mem"
+ ()
+ "st $Ri,@-$R15"
+ (+ OP1_1 OP2_7 OP3_0 Ri)
+ (sequence ((WI tmp))
+ (set tmp Ri) ; save in case it's r15
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) tmp))
+ ((fr30-1 (unit u-store)))
+)
+
+(dni str15dr
+ "st Rs,@-R15 reg/mem"
+ ()
+ "st $Rs2,@-$R15"
+ (+ OP1_1 OP2_7 OP3_8 Rs2)
+ (sequence ((WI tmp))
+ (set tmp Rs2) ; save in case it's r15
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) tmp))
+ ((fr30-1 (unit u-store)))
+)
+
+(dni str15ps
+ "st ps,@-R15 reg/mem"
+ ()
+ "st $ps,@-$R15"
+ (+ OP1_1 OP2_7 OP3_9 OP4_0)
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) ps))
+ ((fr30-1 (unit u-store)))
+)
+
+(define-pmacro (mov2gr name opc1 opc2 arg1 arg2)
+ (dni name
+ (.str "mov " arg1 "," arg2)
+ ()
+ (.str "mov $" arg1 ",$" arg2)
+ (+ opc1 opc2 arg1 arg2)
+ (set arg2 arg1)
+ ()
+ )
+)
+
+(mov2gr mov OP1_8 OP2_B Rj Ri)
+(mov2gr movdr OP1_B OP2_7 Rs1 Ri)
+
+(dni movps
+ "mov ps,Ri reg/reg"
+ ()
+ "mov $ps,$Ri"
+ (+ OP1_1 OP2_7 OP3_1 Ri)
+ (set Ri ps)
+ ()
+)
+
+(dni mov2dr
+ "mov Ri,Rs reg/reg"
+ ()
+ "mov $Ri,$Rs1"
+ (+ OP1_B OP2_3 Rs1 Ri)
+ (set Rs1 Ri)
+ ()
+)
+
+(dni mov2ps
+ "mov Ri,ps reg/reg"
+ ()
+ "mov $Ri,$ps"
+ (+ OP1_0 OP2_7 OP3_1 Ri)
+ (set ps Ri)
+ ()
+)
+
+(dni jmp
+ "jmp with no delay slot"
+ (NOT-IN-DELAY-SLOT)
+ "jmp @$Ri"
+ (+ OP1_9 OP2_7 OP3_0 Ri)
+ (set pc Ri)
+ ((fr30-1 (unit u-cti)))
+)
+
+(dni jmpd "jmp with delay slot"
+ (NOT-IN-DELAY-SLOT)
+ "jmp:d @$Ri"
+ (+ OP1_9 OP2_F OP3_0 Ri)
+ (delay (const 1)
+ (set pc Ri))
+ ((fr30-1 (unit u-cti)))
+)
+
+; These versions which use registers must appear before the other
+; versions which use relative addresses due to a problem in cgen
+; - DB.
+(dni callr
+ "call @Ri"
+ (NOT-IN-DELAY-SLOT)
+ "call @$Ri"
+ (+ OP1_9 OP2_7 OP3_1 Ri)
+ (sequence ()
+ (set (reg h-dr 1) (add pc (const 2)))
+ (set pc Ri))
+ ((fr30-1 (unit u-cti)))
+)
+(dni callrd
+ "call:d @Ri"
+ (NOT-IN-DELAY-SLOT)
+ "call:d @$Ri"
+ (+ OP1_9 OP2_F OP3_1 Ri)
+ (delay (const 1)
+ (sequence ()
+ (set (reg h-dr 1) (add pc (const 4)))
+ (set pc Ri)))
+ ((fr30-1 (unit u-cti)))
+)
+; end of reordered insns
+
+(dni call
+ "call relative to pc"
+ (NOT-IN-DELAY-SLOT)
+ "call $label12"
+ (+ OP1_D OP5_0 label12)
+ (sequence ()
+ (set (reg h-dr 1) (add pc (const 2)))
+ (set pc label12))
+ ((fr30-1 (unit u-cti)))
+)
+(dni calld
+ "call relative to pc"
+ (NOT-IN-DELAY-SLOT)
+ "call:d $label12"
+ (+ OP1_D OP5_1 label12)
+ (delay (const 1)
+ (sequence ()
+ (set (reg h-dr 1) (add pc (const 4)))
+ (set pc label12)))
+ ((fr30-1 (unit u-cti)))
+)
+
+(dni ret
+ "return from subroutine"
+ (NOT-IN-DELAY-SLOT)
+ "ret"
+ (+ OP1_9 OP2_7 OP3_2 OP4_0)
+ (set pc (reg h-dr 1))
+ ((fr30-1 (unit u-cti)))
+)
+
+(dni ret:d
+ "return from subroutine with delay slot"
+ (NOT-IN-DELAY-SLOT)
+ "ret:d"
+ (+ OP1_9 OP2_F OP3_2 OP4_0)
+ (delay (const 1)
+ (set pc (reg h-dr 1)))
+ ((fr30-1 (unit u-cti)))
+)
+
+(dni int
+ "interrupt"
+ (NOT-IN-DELAY-SLOT)
+ "int $u8"
+ (+ OP1_1 OP2_F u8)
+ (sequence ()
+ ; This is defered to fr30_int because for the breakpoint case
+ ; we want to change as little of the machine state as possible.
+ ; Push PS onto the system stack
+ ;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
+ ;(set UWI (mem UWI (reg h-dr 2)) ps)
+ ; Push the return address onto the system stack
+ ;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
+ ;(set UWI (mem UWI (reg h-dr 2)) (add pc (const 2)))
+ ; Set status bits
+ ;(set ibit (const 0))
+ ;(set sbit (const 0))
+
+ ; We still should indicate what is modified by this insn.
+ (clobber (reg h-dr 2))
+ (clobber ibit)
+ (clobber sbit)
+ ; ??? (clobber memory)?
+
+ ; fr30_int handles operating vs user mode
+ (set WI pc (c-call WI "fr30_int" pc u8))
+ )
+ ; This is more properly a cti, but branch stall calculation is different.
+ ((fr30-1 (unit u-exec (cycles 6))))
+)
+
+(dni inte
+ "interrupt for emulator"
+ (NOT-IN-DELAY-SLOT)
+ "inte"
+ (+ OP1_9 OP2_F OP3_3 OP4_0)
+ (sequence ()
+ ; This is defered to fr30_inte because for the breakpoint case
+ ; we want to change as little of the machine state as possible.
+ ; Push PS onto the system stack
+ ;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
+ ;(set UWI (mem UWI (reg h-dr 2)) ps)
+ ; Push the return address onto the system stack
+ ;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
+ ;(set UWI (mem UWI (reg h-dr 2)) (add pc (const 2)))
+ ; Set status bits
+ ;(set ibit (const 0))
+ ;(set ilm (const 4))
+
+ ; We still should indicate what is modified by this insn.
+ (clobber (reg h-dr 2))
+ (clobber ibit)
+ (clobber ilm)
+ ; ??? (clobber memory)?
+
+ ; fr30_int handles operating vs user mode
+ (set WI pc (c-call WI "fr30_inte" pc))
+ )
+ ; This is more properly a cti, but branch stall calculation is different.
+ ((fr30-1 (unit u-exec (cycles 6))))
+)
+
+(dni reti
+ "return from interrupt"
+ (NOT-IN-DELAY-SLOT)
+ "reti"
+ (+ OP1_9 OP2_7 OP3_3 OP4_0)
+ (if (eq sbit (const 0))
+ (sequence ()
+ ; Pop the return address from the system stack
+ (set UWI pc (mem UWI (reg h-dr 2)))
+ (set (reg h-dr 2) (add (reg h-dr 2) (const 4)))
+ ; Pop PS from the system stack
+ (set UWI ps (mem UWI (reg h-dr 2)))
+ (set (reg h-dr 2) (add (reg h-dr 2) (const 4)))
+ )
+ (sequence ()
+ ; Pop the return address from the user stack
+ (set UWI pc (mem UWI (reg h-dr 3)))
+ (set (reg h-dr 3) (add (reg h-dr 3) (const 4)))
+ ; Pop PS from the user stack
+ (set UWI ps (mem UWI (reg h-dr 3)))
+ (set (reg h-dr 3) (add (reg h-dr 3) (const 4)))
+ )
+ )
+ ; This is more properly a cti, but branch stall calculation is different.
+ ((fr30-1 (unit u-exec (cycles 4))))
+)
+
+; Conditional branches with and without delay slots
+;
+(define-pmacro (cond-branch cc condition)
+ (begin
+ (dni (.sym b cc d)
+ (.str (.sym b cc :d) " label9")
+ (NOT-IN-DELAY-SLOT)
+ (.str (.sym b cc :d) " $label9")
+ (+ OP1_F (.sym CC_ cc) label9)
+ (delay (const 1)
+ (if condition (set pc label9)))
+ ((fr30-1 (unit u-cti)))
+ )
+ (dni (.sym b cc)
+ (.str (.sym b cc) " label9")
+ (NOT-IN-DELAY-SLOT)
+ (.str (.sym b cc) " $label9")
+ (+ OP1_E (.sym CC_ cc) label9)
+ (if condition (set pc label9))
+ ((fr30-1 (unit u-cti)))
+ )
+ )
+)
+
+(cond-branch ra (const BI 1))
+(cond-branch no (const BI 0))
+(cond-branch eq zbit)
+(cond-branch ne (not zbit))
+(cond-branch c cbit)
+(cond-branch nc (not cbit))
+(cond-branch n nbit)
+(cond-branch p (not nbit))
+(cond-branch v vbit)
+(cond-branch nv (not vbit))
+(cond-branch lt (xor vbit nbit))
+(cond-branch ge (not (xor vbit nbit)))
+(cond-branch le (or (xor vbit nbit) zbit))
+(cond-branch gt (not (or (xor vbit nbit) zbit)))
+(cond-branch ls (or cbit zbit))
+(cond-branch hi (not (or cbit zbit)))
+
+(define-pmacro (dir2r13 name insn opc1 opc2 mode arg1)
+ (dni name
+ (.str insn " @" arg1 ",R13")
+ ()
+ (.str insn " @$" arg1 ",$R13")
+ (+ opc1 opc2 arg1)
+ (set (reg h-gr 13) (mem mode arg1))
+ ((fr30-1 (unit u-load)))
+ )
+)
+
+(define-pmacro (dir2r13-postinc name insn opc1 opc2 mode arg1 incr)
+ (dni name
+ (.str insn " @" arg1 ",@R13+")
+ (NOT-IN-DELAY-SLOT)
+ (.str insn " @$" arg1 ",@$R13+")
+ (+ opc1 opc2 arg1)
+ (sequence ()
+ (set (mem mode (reg h-gr 13)) (mem mode arg1))
+ (set (reg h-gr 13) (add (reg h-gr 13) incr)))
+ ((fr30-1 (unit u-load) (unit u-store)))
+ )
+)
+
+(define-pmacro (r132dir name insn opc1 opc2 mode arg1)
+ (dni name
+ (.str insn " R13,@" arg1)
+ ()
+ (.str insn " $R13,@$" arg1)
+ (+ opc1 opc2 arg1)
+ (set (mem mode arg1) (reg h-gr 13))
+ ((fr30-1 (unit u-store)))
+ )
+)
+
+(define-pmacro (r13-postinc2dir name insn opc1 opc2 mode arg1 incr)
+ (dni name
+ (.str insn " @R13+,@" arg1)
+ (NOT-IN-DELAY-SLOT)
+ (.str insn " @$R13+,@$" arg1)
+ (+ opc1 opc2 arg1)
+ (sequence ()
+ (set (mem mode arg1) (mem mode (reg h-gr 13)))
+ (set (reg h-gr 13) (add (reg h-gr 13) incr)))
+ ((fr30-1 (unit u-load) (unit u-store)))
+ )
+)
+
+; These versions which move from reg to mem must appear before the other
+; versions which use immediate addresses due to a problem in cgen
+; - DB.
+(r132dir dmovr13 dmov OP1_1 OP2_8 WI dir10)
+(r132dir dmovr13h dmovh OP1_1 OP2_9 HI dir9)
+(r132dir dmovr13b dmovb OP1_1 OP2_A QI dir8)
+
+(r13-postinc2dir dmovr13pi dmov OP1_1 OP2_C WI dir10 (const 4))
+(r13-postinc2dir dmovr13pih dmovh OP1_1 OP2_D HI dir9 (const 2))
+(r13-postinc2dir dmovr13pib dmovb OP1_1 OP2_E QI dir8 (const 1))
+
+(dni dmovr15pi
+ "dmov @R15+,@dir10"
+ (NOT-IN-DELAY-SLOT)
+ "dmov @$R15+,@$dir10"
+ (+ OP1_1 OP2_B dir10)
+ (sequence ()
+ (set (mem WI dir10) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4))))
+ ((fr30-1 (unit u-load) (unit u-store)))
+)
+; End of reordered insns.
+
+(dir2r13 dmov2r13 dmov OP1_0 OP2_8 WI dir10)
+(dir2r13 dmov2r13h dmovh OP1_0 OP2_9 HI dir9)
+(dir2r13 dmov2r13b dmovb OP1_0 OP2_A QI dir8)
+
+(dir2r13-postinc dmov2r13pi dmov OP1_0 OP2_C WI dir10 (const 4))
+(dir2r13-postinc dmov2r13pih dmovh OP1_0 OP2_D HI dir9 (const 2))
+(dir2r13-postinc dmov2r13pib dmovb OP1_0 OP2_E QI dir8 (const 1))
+
+(dni dmov2r15pd
+ "dmov @dir10,@-R15"
+ (NOT-IN-DELAY-SLOT)
+ "dmov @$dir10,@-$R15"
+ (+ OP1_0 OP2_B dir10)
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (mem WI dir10)))
+ ((fr30-1 (unit u-load) (unit u-store)))
+)
+
+; Leave these insns as stubs for now, except for the increment of $Ri
+;
+(dni ldres
+ "ldres @Ri+,#u4"
+ ()
+ "ldres @$Ri+,$u4"
+ (+ OP1_B OP2_C u4 Ri)
+ (set Ri (add Ri (const 4)))
+ ()
+)
+
+(dni stres
+ "stres #u4,@Ri+"
+ ()
+ "stres $u4,@$Ri+"
+ (+ OP1_B OP2_D u4 Ri)
+ (set Ri (add Ri (const 4)))
+ ()
+)
+
+; Leave the coprocessor insns as stubs for now.
+;
+(define-pmacro (cop-stub name insn opc1 opc2 opc3 arg1 arg2)
+ (dni name
+ (.str insn " u4c,ccc,CRj," arg1 "," arg2)
+ (NOT-IN-DELAY-SLOT)
+ (.str insn " $u4c,$ccc,$" arg1 ",$" arg2)
+ (+ opc1 opc2 opc3 u4c ccc arg1 arg2)
+ (nop) ; STUB
+ ()
+ )
+)
+
+(cop-stub copop copop OP1_9 OP2_F OP3_C CRj CRi)
+(cop-stub copld copld OP1_9 OP2_F OP3_D Rjc CRi)
+(cop-stub copst copst OP1_9 OP2_F OP3_E CRj Ric)
+(cop-stub copsv copsv OP1_9 OP2_F OP3_F CRj Ric)
+
+(dni nop
+ "nop"
+ ()
+ "nop"
+ (+ OP1_9 OP2_F OP3_A OP4_0)
+ (nop)
+ ()
+)
+
+(dni andccr
+ "andccr #u8"
+ ()
+ "andccr $u8"
+ (+ OP1_8 OP2_3 u8)
+ (set ccr (and ccr u8))
+ ()
+)
+
+(dni orccr
+ "orccr #u8"
+ ()
+ "orccr $u8"
+ (+ OP1_9 OP2_3 u8)
+ (set ccr (or ccr u8))
+ ()
+)
+
+(dni stilm
+ "stilm #u8"
+ ()
+ "stilm $u8"
+ (+ OP1_8 OP2_7 u8)
+ (set ilm (and u8 (const #x1f)))
+ ()
+)
+
+(dni addsp
+ "addsp #s10"
+ ()
+ "addsp $s10"
+ (+ OP1_A OP2_3 s10)
+ (set (reg h-gr 15) (add (reg h-gr 15) s10))
+ ()
+)
+
+(define-pmacro (ext-op name opc1 opc2 opc3 op mode mask)
+ (dni name
+ (.str name " Ri")
+ ()
+ (.str name " $Ri")
+ (+ opc1 opc2 opc3 Ri)
+ (set Ri (op WI (and mode Ri mask)))
+ ()
+ )
+)
+
+(ext-op extsb OP1_9 OP2_7 OP3_8 ext QI (const #xff))
+(ext-op extub OP1_9 OP2_7 OP3_9 zext UQI (const #xff))
+(ext-op extsh OP1_9 OP2_7 OP3_A ext HI (const #xffff))
+(ext-op extuh OP1_9 OP2_7 OP3_B zext UHI (const #xffff))
+
+(dni ldm0
+ "ldm0 (reglist_low_ld)"
+ (NOT-IN-DELAY-SLOT)
+ "ldm0 ($reglist_low_ld)"
+ (+ OP1_8 OP2_C reglist_low_ld)
+ (sequence ()
+ (if (and reglist_low_ld (const #x1))
+ (sequence ()
+ (set (reg h-gr 0) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x2))
+ (sequence ()
+ (set (reg h-gr 1) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x4))
+ (sequence ()
+ (set (reg h-gr 2) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x8))
+ (sequence ()
+ (set (reg h-gr 3) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x10))
+ (sequence ()
+ (set (reg h-gr 4) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x20))
+ (sequence ()
+ (set (reg h-gr 5) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x40))
+ (sequence ()
+ (set (reg h-gr 6) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_low_ld (const #x80))
+ (sequence ()
+ (set (reg h-gr 7) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ )
+ ((fr30-1 (unit u-ldm)))
+)
+
+(dni ldm1
+ "ldm1 (reglist_hi_ld)"
+ (NOT-IN-DELAY-SLOT)
+ "ldm1 ($reglist_hi_ld)"
+ (+ OP1_8 OP2_D reglist_hi_ld)
+ (sequence ()
+ (if (and reglist_hi_ld (const #x1))
+ (sequence ()
+ (set (reg h-gr 8) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x2))
+ (sequence ()
+ (set (reg h-gr 9) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x4))
+ (sequence ()
+ (set (reg h-gr 10) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x8))
+ (sequence ()
+ (set (reg h-gr 11) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x10))
+ (sequence ()
+ (set (reg h-gr 12) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x20))
+ (sequence ()
+ (set (reg h-gr 13) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x40))
+ (sequence ()
+ (set (reg h-gr 14) (mem WI (reg h-gr 15)))
+ (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))))
+ (if (and reglist_hi_ld (const #x80))
+ (set (reg h-gr 15) (mem WI (reg h-gr 15))))
+ )
+ ((fr30-1 (unit u-ldm)))
+)
+
+(dni stm0
+ "stm0 (reglist_low_st)"
+ (NOT-IN-DELAY-SLOT)
+ "stm0 ($reglist_low_st)"
+ (+ OP1_8 OP2_E reglist_low_st)
+ (sequence ()
+ (if (and reglist_low_st (const #x1))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 7))))
+ (if (and reglist_low_st (const #x2))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 6))))
+ (if (and reglist_low_st (const #x4))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 5))))
+ (if (and reglist_low_st (const #x8))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 4))))
+ (if (and reglist_low_st (const #x10))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 3))))
+ (if (and reglist_low_st (const #x20))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 2))))
+ (if (and reglist_low_st (const #x40))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 1))))
+ (if (and reglist_low_st (const #x80))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 0))))
+ )
+ ((fr30-1 (unit u-stm)))
+)
+
+(dni stm1
+ "stm1 (reglist_hi_st)"
+ (NOT-IN-DELAY-SLOT)
+ "stm1 ($reglist_hi_st)"
+ (+ OP1_8 OP2_F reglist_hi_st)
+ (sequence ()
+ (if (and reglist_hi_st (const #x1))
+ (sequence ((WI save-r15))
+ (set save-r15 (reg h-gr 15))
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) save-r15)))
+ (if (and reglist_hi_st (const #x2))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 14))))
+ (if (and reglist_hi_st (const #x4))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 13))))
+ (if (and reglist_hi_st (const #x8))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 12))))
+ (if (and reglist_hi_st (const #x10))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 11))))
+ (if (and reglist_hi_st (const #x20))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 10))))
+ (if (and reglist_hi_st (const #x40))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 9))))
+ (if (and reglist_hi_st (const #x80))
+ (sequence ()
+ (set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
+ (set (mem WI (reg h-gr 15)) (reg h-gr 8))))
+ )
+ ((fr30-1 (unit u-stm)))
+)
+
+(dni enter
+ "enter #u10"
+ (NOT-IN-DELAY-SLOT)
+ "enter $u10"
+ (+ OP1_0 OP2_F u10)
+ (sequence ((WI tmp))
+ (set tmp (sub (reg h-gr 15) (const 4)))
+ (set (mem WI tmp) (reg h-gr 14))
+ (set (reg h-gr 14) tmp)
+ (set (reg h-gr 15) (sub (reg h-gr 15) u10)))
+ ((fr30-1 (unit u-exec (cycles 2))))
+)
+
+(dni leave
+ "leave"
+ ()
+ "leave"
+ (+ OP1_9 OP2_F OP3_9 OP4_0)
+ (sequence ()
+ (set (reg h-gr 15) (add (reg h-gr 14) (const 4)))
+ (set (reg h-gr 14) (mem WI (sub (reg h-gr 15) (const 4)))))
+ ()
+)
+
+(dni xchb
+ "xchb @Rj,Ri"
+ (NOT-IN-DELAY-SLOT)
+ "xchb @$Rj,$Ri"
+ (+ OP1_8 OP2_A Rj Ri)
+ (sequence ((WI tmp))
+ (set tmp Ri)
+ (set Ri (mem UQI Rj))
+ (set (mem UQI Rj) tmp))
+ ((fr30-1 (unit u-load) (unit u-store)))
+)
diff --git a/cgen/fr30.opc b/cgen/fr30.opc
new file mode 100644
index 00000000000..a30cb0ac641
--- /dev/null
+++ b/cgen/fr30.opc
@@ -0,0 +1,242 @@
+/* FR30 opcode support. -*- C -*-
+ Copyright (C) 2000 Red Hat, Inc.
+ This file is part of CGEN. */
+
+/* This file is an addendum to fr30.cpu. Heavy use of C code isn't
+ appropriate in .cpu files, so it resides here. This especially applies
+ to assembly/disassembly where parsing/printing can be quite involved.
+ Such things aren't really part of the specification of the cpu, per se,
+ so .cpu files provide the general framework and .opc files handle the
+ nitty-gritty details as necessary.
+
+ Each section is delimited with start and end markers.
+
+ <arch>-opc.h additions use: "-- opc.h"
+ <arch>-opc.c additions use: "-- opc.c"
+ <arch>-asm.c additions use: "-- asm.c"
+ <arch>-dis.c additions use: "-- dis.c"
+ <arch>-ibd.h additions use: "-- ibd.h"
+*/
+
+/* -- opc.h */
+
+/* ??? This can be improved upon. */
+#undef CGEN_DIS_HASH_SIZE
+#define CGEN_DIS_HASH_SIZE 16
+#undef CGEN_DIS_HASH
+#define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 4)
+
+/* -- */
+
+/* -- asm.c */
+/* Handle register lists for LDMx and STMx */
+
+static int
+parse_register_number (strp)
+ const char **strp;
+{
+ int regno;
+ if (**strp < '0' || **strp > '9')
+ return -1; /* error */
+ regno = **strp - '0';
+ ++*strp;
+
+ if (**strp >= '0' && **strp <= '9')
+ {
+ regno = regno * 10 + (**strp - '0');
+ ++*strp;
+ }
+
+ return regno;
+}
+
+static const char *
+parse_register_list (cd, strp, opindex, valuep, high_low, load_store)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+ int high_low; /* 0 == high, 1 == low */
+ int load_store; /* 0 == load, 1 == store */
+{
+ int regno;
+ *valuep = 0;
+ while (**strp && **strp != ')')
+ {
+ if (**strp != 'R' && **strp != 'r')
+ break;
+ ++*strp;
+
+ regno = parse_register_number (strp);
+ if (regno == -1)
+ return "Register number is not valid";
+ if (regno > 7 && !high_low)
+ return "Register must be between r0 and r7";
+ if (regno < 8 && high_low)
+ return "Register must be between r8 and r15";
+
+ if (high_low)
+ regno -= 8;
+
+ if (load_store) /* mask is reversed for store */
+ *valuep |= 0x80 >> regno;
+ else
+ *valuep |= 1 << regno;
+
+ if (**strp == ',')
+ {
+ if (*(*strp + 1) == ')')
+ break;
+ ++*strp;
+ }
+ }
+
+ if (!*strp || **strp != ')')
+ return "Register list is not valid";
+
+ return NULL;
+}
+
+static const char *
+parse_low_register_list_ld (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (cd, strp, opindex, valuep, 0/*low*/, 0/*load*/);
+}
+
+static const char *
+parse_hi_register_list_ld (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (cd, strp, opindex, valuep, 1/*high*/, 0/*load*/);
+}
+
+static const char *
+parse_low_register_list_st (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (cd, strp, opindex, valuep, 0/*low*/, 1/*store*/);
+}
+
+static const char *
+parse_hi_register_list_st (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (cd, strp, opindex, valuep, 1/*high*/, 1/*store*/);
+}
+
+/* -- */
+
+/* -- dis.c */
+
+static void
+print_register_list (dis_info, value, offset, load_store)
+ PTR dis_info;
+ long value;
+ long offset;
+ int load_store; /* 0 == load, 1 == store */
+{
+ disassemble_info *info = dis_info;
+ int mask;
+ int index = 0;
+ char* comma = "";
+
+ if (load_store)
+ mask = 0x80;
+ else
+ mask = 1;
+
+ if (value & mask)
+ {
+ (*info->fprintf_func) (info->stream, "r%i", index + offset);
+ comma = ",";
+ }
+
+ for (index = 1; index <= 7; ++index)
+ {
+ if (load_store)
+ mask >>= 1;
+ else
+ mask <<= 1;
+
+ if (value & mask)
+ {
+ (*info->fprintf_func) (info->stream, "%sr%i", comma, index + offset);
+ comma = ",";
+ }
+ }
+}
+
+static void
+print_hi_register_list_ld (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ print_register_list (dis_info, value, 8, 0/*load*/);
+}
+
+static void
+print_low_register_list_ld (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ print_register_list (dis_info, value, 0, 0/*load*/);
+}
+
+static void
+print_hi_register_list_st (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ print_register_list (dis_info, value, 8, 1/*store*/);
+}
+
+static void
+print_low_register_list_st (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ print_register_list (dis_info, value, 0, 1/*store*/);
+}
+
+static void
+print_m4 (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ disassemble_info *info = (disassemble_info *) dis_info;
+ (*info->fprintf_func) (info->stream, "%ld", value);
+}
+/* -- */
diff --git a/cgen/gas-test.scm b/cgen/gas-test.scm
new file mode 100644
index 00000000000..1883aaee042
--- /dev/null
+++ b/cgen/gas-test.scm
@@ -0,0 +1,227 @@
+; CPU description file generator for the GAS testsuite.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; This is invoked to build allinsn.exp and a script to run to
+; generate allinsn.s and allinsn.d.
+
+; Specify which application.
+(set! APPLICATION 'GAS-TEST)
+
+; Called before/after the .cpu file has been read.
+
+(define (gas-test-init!) (opcodes-init!))
+(define (gas-test-finish!) (opcodes-finish!))
+
+; Called after .cpu file has been read and global error checks are done.
+; We use the `tmp' member to record the syntax split up into its components.
+
+(define (gas-test-analyze!)
+ (opcodes-analyze!)
+ (map (lambda (insn)
+ (elm-xset! insn 'tmp (syntax-break-out (insn-syntax insn))))
+ (non-multi-insns (current-insn-list)))
+ *UNSPECIFIED*
+)
+
+; Methods to compute test data.
+; The result is a list of strings to be inserted in the assembler
+; in the operand's position.
+
+(method-make!
+ <hw-asm> 'test-data
+ (lambda (self n)
+ ; FIXME: floating point support
+ (let ((signed (list 0 1 -1 2 -2))
+ (unsigned (list 0 1 2 3 4))
+ (mode (elm-get self 'mode)))
+ (map number->string
+ (list-take n
+ (if (eq? (mode:class mode) 'UINT)
+ unsigned
+ signed)))))
+)
+
+(method-make!
+ <keyword> 'test-data
+ (lambda (self n)
+ (let* ((values (elm-get self 'values))
+ (n (min n (length values))))
+ ; FIXME: Need to handle mach variants.
+ (map car (list-take n values))))
+)
+
+(method-make!
+ <hw-address> 'test-data
+ (lambda (self n)
+ (let ((test-data '("foodata" "4" "footext" "-4")))
+ (list-take n test-data)))
+)
+
+(method-make!
+ <hw-iaddress> 'test-data
+ (lambda (self n)
+ (let ((test-data '("footext" "4" "foodata" "-4")))
+ (list-take n test-data)))
+)
+
+(method-make-forward! <hw-register> 'indices '(test-data))
+(method-make-forward! <hw-immediate> 'values '(test-data))
+
+; This can't use method-make-forward! as we need to call op:type to
+; resolve the hardware reference.
+
+(method-make!
+ <operand> 'test-data
+ (lambda (self n)
+ (send (op:type self) 'test-data n))
+)
+
+; Given an operand, return a set of N test data.
+; e.g. For a keyword operand, return a random subset.
+; For a number, return N numbers.
+
+(define (operand-test-data op n)
+ (send op 'test-data n)
+)
+
+; Given the broken out assembler syntax string, return the list of operand
+; objects.
+
+(define (extract-operands syntax-list)
+ (let loop ((result nil) (l syntax-list))
+ (cond ((null? l) (reverse! result))
+ ((object? (car l)) (loop (cons (car l) result) (cdr l)))
+ (else (loop result (cdr l)))))
+)
+
+; Given a list of operands for an instruction, return the test set
+; (all possible combinations).
+; N is the number of testcases for each operand.
+; The result has N to-the-power (length OP-LIST) elements.
+
+(define (build-test-set op-list n)
+ (let ((test-data (map (lambda (op) (operand-test-data op n)) op-list))
+ (len (length op-list)))
+ ; FIXME: Make slicker later.
+ (cond ((=? len 0) (list (list)))
+ ((=? len 1) test-data)
+ (else (list (map car test-data)))))
+)
+
+; Given an assembler expression and a set of operands build a testcase.
+; TEST-DATA is a list of strings, one element per operand.
+
+(define (build-asm-testcase syntax-list test-data)
+ (let loop ((result nil) (sl syntax-list) (td test-data))
+ ;(display (list result sl td "\n"))
+ (cond ((null? sl)
+ (string-append "\t"
+ (apply string-append (reverse result))
+ "\n"))
+ ((string? (car sl))
+ (loop (cons (car sl) result) (cdr sl) td))
+ (else (loop (cons (car td) result) (cdr sl) (cdr td)))))
+)
+
+; Generate the testsuite for INSN.
+; FIXME: This needs to be expanded upon.
+
+(define (gen-gas-test insn)
+ (logit 2 "Generating gas test data for " (obj:name insn) " ...\n")
+ (string-append
+ "\t.text\n"
+ "\t.global " (gen-sym insn) "\n"
+ (gen-sym insn) ":\n"
+ (let* ((syntax-list (insn-tmp insn))
+ (op-list (extract-operands syntax-list))
+ (test-set (build-test-set op-list 2)))
+ ;(display test-set) (newline)
+ (string-map (lambda (test-data)
+ (build-asm-testcase syntax-list test-data))
+ test-set))
+ )
+)
+
+; Generate the shell script that builds the .d file.
+; .d files contain the objdump result that is used to see whether the
+; testcase passed.
+; We do this by running gas and objdump.
+; Obviously this isn't quite right - bugs in gas or
+; objdump - the things we're testing - will cause an incorrect testsuite to
+; be built and thus the bugs will be missed. It is *not* intended that this
+; be run immediately before running the testsuite! Rather, this is run to
+; generate the testsuite which is then inspected for accuracy and checked
+; into CVS. As bugs in the testsuite are found they are corrected by hand.
+; Or if they're due to bugs in the generator the generator can be rerun and
+; the output diff'd to ensure no errors have crept back in.
+; The point of doing things this way is TO SAVE A HELL OF A LOT OF TYPING!
+; Clearly some hand generated testcases will also be needed, but this
+; provides a good test for each instruction.
+
+(define (cgen-build.sh)
+ (logit 1 "Generating gas-build.sh ...\n")
+ (string-append
+ "\
+#/bin/sh
+# Generate test result data for " (current-arch-name) " GAS testing.
+# This script is machine generated.
+# It is intended to be run in the testsuite source directory.
+#
+# Syntax: build.sh /path/to/build/gas
+
+BUILD=$1
+
+if [ ! -f $BUILD/as-new ] ; then
+ echo \"$BUILD is not a GAS build directory.\"
+ exit 1
+fi
+
+# Put results here, so we preserve the existing set for comparison.
+rm -rf tmpdir
+mkdir tmpdir
+cd tmpdir
+
+function gentest {
+ rm -f a.out
+ $BUILD/as-new ${1}.s -o a.out
+ echo \"#as:\" >${1}.d
+ echo \"#objdump: -dr\" >>${1}.d
+ echo \"#name: $1\" >>${1}.d
+ $BUILD/../binutils/objdump -dr a.out | \
+ sed -e 's/(/\\\\(/g' -e 's/)/\\\\)/g' -e 's/[+]/\\\\+/g' -e 's/[*]/\\\*/g' | \
+ sed -e 's/^.*file format.*$/.*: +file format .*/' \
+ >>${1}.d
+ rm -f a.out
+}
+
+# Now come all the testcases.
+cat > allinsn.s <<EOF
+ .data
+foodata: .word 42
+ .text
+footext:\n"
+ (string-map (lambda (insn)
+ (gen-gas-test insn))
+ (non-multi-insns (current-insn-list)))
+ "EOF\n"
+ "\n"
+ "# Finally, generate the .d file.\n"
+ "gentest allinsn\n"
+ )
+)
+
+; Generate the dejagnu allinsn.exp file that drives the tests.
+
+(define (cgen-allinsn.exp)
+ (logit 1 "Generating allinsn.exp ...\n")
+ (string-append
+ "\
+# " (string-upcase (current-arch-name)) " assembler testsuite.
+
+if [istarget " (current-arch-name) "*-*-*] {
+ run_dump_test \"allinsn\"
+}\n"
+ )
+)
diff --git a/cgen/hardware.scm b/cgen/hardware.scm
new file mode 100644
index 00000000000..7f8d553a121
--- /dev/null
+++ b/cgen/hardware.scm
@@ -0,0 +1,1172 @@
+; Hardware descriptions.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; This is the base class for all hardware descriptions.
+; The actual hardware objects inherit from this (e.g. register, immediate).
+; This is used to describe registers, memory, and immediates.
+; ??? Maybe other things as well, but this is all that's needed at present.
+; ??? Eventually rename to <hardware> but not yet.
+
+(define <hardware-base>
+ (class-make '<hardware-base>
+ '(<ident>)
+ '(
+ ; Name used in semantics.
+ ; This is for cases where a particular hardware element is
+ ; sufficiently different on different mach's of an architecture
+ ; that it is defined separately for each case. The semantics
+ ; refer to this name (which means that one must use a different
+ ; mechanism if one wants both machs in the same semantic code).
+ sem-name
+
+ ; The type, an object of class <array>.
+ ; (mode + scalar or vector length)
+ type
+
+ ; Indexing support.
+ ; An object of class <hw-asm>, or a subclass of it, or
+ ; #f if there is no special indexing support.
+ ; For register banks, a table of register names.
+ ; ??? Same class as VALUES.
+ ; ??? There are currently no descriptions that require both an
+ ; INDICES and a VALUES specification. It might make sense to
+ ; combine them (which is how things used to be), but it is odd
+ ; to have them combined.
+ (indices . #f)
+
+ ; Table of values.
+ ; An object of class <hw-asm>, or a subclass of it, or
+ ; #f if there is no special values support.
+ ; For immediates with special names, a table of names.
+ ; ??? Same class as INDICES.
+ (values . #f)
+
+ ; Associative list of (symbol . "handler") entries.
+ ; Each entry maps an operation to its handler (which is up to
+ ; the application but is generally a function name).
+ (handlers . ())
+
+ ; Get/set handlers or #f to use the default.
+ (get . #f)
+ (set . #f)
+
+ ; Associative list of get/set handlers for each supported mode,
+ ; or #f to use the default.
+ ; ??? An interesting idea, but not sure it's the best way
+ ; to go. Another way is to explicitly handle it in the insn
+ ; [complicates the RTL]. Another way is to handle this in
+ ; operand get/set handlers. Another way is to have virtual
+ ; regs for each non-default mode. Not sure which is better.
+ ;(getters . #f)
+ ;(setters . #f)
+
+ ; List of <isa> objects that use this hardware element
+ ; or #f if not computed yet.
+ ; This is a derived from the ISA attribute and is for speed.
+ (isas-cache . #f)
+ )
+ nil)
+)
+
+; Accessors
+
+(define-getters <hardware-base> hw
+ (sem-name type indices values handlers
+ ; ??? These might be more properly named hw-get/hw-set, but those names
+ ; seem ambiguous.
+ (get . getter) (set . setter)
+ isas-cache)
+)
+
+; Mode,rank,shape support.
+
+(method-make-forward! <hardware-base> 'type '(get-mode get-rank get-shape get-num-elms))
+(define (hw-mode hw) (send hw 'get-mode))
+(define (hw-rank hw) (send hw 'get-rank))
+(define (hw-shape hw) (send hw 'get-shape))
+(define (hw-num-elms hw) (send hw 'get-num-elms))
+
+; Return default mode to reference HW in.
+
+(define (hw-default-mode hw)
+ (hw-mode hw)
+)
+
+; Return a boolean indicating if X is a hardware object.
+; ??? <hardware-base> to be renamed <hardware> in time.
+
+(define (hardware? x) (class-instance? <hardware-base> x))
+
+; Return #t if HW is a scalar.
+
+(define (hw-scalar? hw) (= (hw-rank hw) 0))
+
+; Return number of bits in an element of HW.
+
+(define (hw-bits hw)
+ (type-bits (hw-type hw))
+)
+
+; Generate the name of the enum for hardware object HW.
+; This uses the semantic name, not obj:name.
+; If HW is a symbol, it is already the semantic name.
+
+(define (hw-enum hw)
+ (if (symbol? hw)
+ (string-upcase (string-append "HW_" (gen-c-symbol hw)))
+ (string-upcase (string-append "HW_" (gen-c-symbol (hw-sem-name hw)))))
+)
+
+; Return a boolean indicating if it's ok to reference SELF in mode
+; NEW-MODE-NAME, index INDEX.
+; Hardware types are required to override this method.
+; VOID and DFLT are never valid for NEW-MODE-NAME.
+
+(method-make!
+ <hardware-base> 'mode-ok?
+ (lambda (self new-mode-name index)
+ (error "mode-ok? method not overridden:" (obj:name self)))
+)
+
+(define (hw-mode-ok? hw new-mode-name index)
+ (send hw 'mode-ok? new-mode-name index)
+)
+
+; Return mode to use for the index or #f if scalar.
+
+(method-make!
+ <hardware-base> 'get-index-mode
+ (lambda (self)
+ (error "get-index-mode method not overridden:" (obj:name self)))
+)
+
+(define (hw-index-mode hw) (send hw 'get-index-mode))
+
+; Compute the isas used by HW and cache the results.
+
+(method-make!
+ <hardware-base> 'get-isas
+ (lambda (self)
+ (or (elm-get self 'isas-cache)
+ (let* ((isas (obj-attr-value self 'ISA))
+ (isa-objs (if (eq? isas 'all) (current-isa-list)
+ (map current-isa-lookup
+ (bitset-attr->list isas)))))
+ (elm-set! self 'isas-cache isa-objs)
+ isa-objs)))
+)
+
+(define (hw-isas hw) (send hw 'get-isas))
+
+; FIXME: replace pc?,memory?,register?,iaddress? with just one method.
+
+; Return boolean indicating if hardware element is the PC.
+
+(method-make! <hardware-base> 'pc? (lambda (self) #f))
+
+; Return boolean indicating if hardware element is some kind of memory.
+; ??? Need to allow multiple kinds of memory and therefore need to allow
+; .cpu files to specify this (i.e. an attribute). We could use has-attr?
+; here, or we could have the code that creates the object override this
+; method if the MEMORY attribute is present.
+; ??? Could also use a member instead of a method.
+
+(method-make! <hardware-base> 'memory? (lambda (self) #f))
+(define (memory? hw) (send hw 'memory?))
+
+; Return boolean indicating if hardware element is some kind of register.
+
+(method-make! <hardware-base> 'register? (lambda (self) #f))
+(define (register? hw) (send hw 'register?))
+
+; Return boolean indicating if hardware element is an address.
+
+(method-make! <hardware-base> 'address? (lambda (self) #f))
+(method-make! <hardware-base> 'iaddress? (lambda (self) #f))
+(define (address? hw) (send hw 'address?))
+(define (iaddress? hw) (send hw 'iaddress?))
+
+; Assembler support.
+
+; Baseclass.
+
+(define <hw-asm>
+ (class-make '<hw-asm> '(<ident>)
+ '(
+ ; The mode to use.
+ ; A copy of the object's mode if we're in the "values"
+ ; member. If we're in the "indices" member this is typically
+ ; UINT.
+ mode
+ )
+ nil)
+)
+
+; Keywords.
+; Keyword lists associate a name with a number and are used for things
+; like register name tables (the `indices' field of a hw spec) and
+; immediate value tables (the `values' field of a hw spec).
+;
+; TODO: For things like the sparc fp regs, have a quasi-keyword that is
+; prefix plus number. This will save having to create a table of each
+; register name.
+
+(define <keyword>
+ (class-make '<keyword> '(<hw-asm>)
+ '(
+ ; Name to use in generated code.
+ print-name
+
+ ; Prefix of each name in VALUES, as a string.
+ prefix
+
+ ; Associative list of values.
+ ; Each element is (name value [attrs]).
+ ; ??? May wish to allow calling a function to compute the
+ ; value at runtime.
+ values
+ )
+ nil)
+)
+
+; Accessors
+
+(define kw-mode (elm-make-getter <keyword> 'mode))
+(define kw-print-name (elm-make-getter <keyword> 'print-name))
+(define kw-prefix (elm-make-getter <keyword> 'prefix))
+(define kw-values (elm-make-getter <keyword> 'values))
+
+; Parse a keyword spec.
+;
+; The syntax of VALUES is: (prefix ((name1 [value1 [(attr-list1)]]) ...))
+; PREFIX is a string prefix for each name.
+; Each value is a number of mode MODE.
+; ??? We have no problem handling any kind of number, we're Scheme.
+; However, it's not clear yet how applications will want to handle it, but
+; that is left to the application. Still, it might be preferable to impose
+; some restrictions which can later be relaxed as necessary.
+
+(define (keyword-parse context name comment attrs mode print-name prefix values)
+ ; FIXME: parse values.
+ (let ((result (make <keyword>
+ (parse-name name context)
+ (parse-comment comment context)
+ (atlist-parse attrs "" context)
+ (parse-mode-name mode (string-append context ": mode"))
+ (parse-string (string-append context ": print-name") print-name)
+ (parse-string (string-append context ": prefix") prefix)
+ values)))
+ result)
+)
+
+; Read a keyword description
+; This is the main routine for analyzing a keyword description in the .cpu
+; file.
+; ARG-LIST is an associative list of field name and field value.
+; keyword-parse is invoked to create the <keyword> object.
+
+(define (-keyword-read context . arg-list)
+ (let ((name #f)
+ (comment "")
+ (attrs nil)
+ (mode INT)
+ (print-name #f)
+ (prefix "")
+ (values nil)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((mode) (set! mode (cadr arg)))
+ ((print-name) (set! print-name (cadr arg)))
+ ((prefix) (set! prefix (cadr arg)))
+ ((values) (set! values (cdr arg)))
+ (else (parse-error context "invalid hardware arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (keyword-parse context name comment attrs mode
+ (or print-name name)
+ prefix values)
+ )
+)
+
+; Define a keyword object, name/value pair list version.
+
+(define define-keyword
+ (lambda arg-list
+ (let ((kw (apply -keyword-read (cons "define-keyword" arg-list))))
+ (if kw
+ (begin
+ (current-kw-add! kw)
+ ; Define an enum so the values are usable everywhere.
+ ; One use is giving names to register numbers and special constants
+ ; to make periphery C/C++ code more legible.
+ (define-full-enum (obj:name kw) (obj:comment kw)
+ (atlist-source-form (obj-atlist kw))
+ (string-upcase (symbol-append (kw-print-name kw) '-))
+ (kw-values kw))))
+ kw))
+)
+
+; Parsing support.
+
+; List of hardware types.
+; This maps names in the `type' entry of define-hardware to the class name.
+
+(define -hardware-types
+ '((register . <hw-register>)
+ (pc . <hw-pc>)
+ (memory . <hw-memory>)
+ (immediate . <hw-immediate>)
+ (address . <hw-address>)
+ (iaddress . <hw-iaddress>))
+)
+
+; Parse an inline keyword spec.
+; These are keywords defined inside something else.
+; CONTAINER is the <ident> object of the container.
+
+(define (-hw-parse-keyword context args container mode)
+ (if (!= (length args) 2)
+ (parse-error context "invalid keyword spec" args))
+
+ ; These are copied from our container object.
+ ; They're needed to output the table.
+ ; ??? This isn't quite right as the container may contain multiple keyword
+ ; instances. To be fixed in time.
+ (keyword-parse context (obj:name container) (obj:comment container)
+ ; PRIVATE: keyword table is implicitly defined and made
+ ; "static" (in the C sense).
+ (cons 'PRIVATE (atlist-source-form (obj-atlist container)))
+ mode
+ (obj:name container) ; print-name
+ (car args) ; prefix
+ (cadr args)) ; value
+)
+
+; Parse an indices spec.
+; CONTAINER is the <ident> object of the container.
+; Currently there is only special support for keywords.
+; Otherwise MODE is used.
+; The syntax is: (keyword keyword-spec) - see <keyword> for details.
+
+(define (-hw-parse-indices errtxt indices container mode)
+ (if (null? indices)
+ (make <hw-asm>
+ (obj:name container) (obj:comment container) (obj-atlist container)
+ mode)
+ (begin
+ (if (not (list? indices))
+ (parse-error errtxt "invalid indices spec" indices))
+ (case (car indices)
+ ((keyword) (-hw-parse-keyword errtxt (cdr indices) container mode))
+ ((extern-keyword) (begin
+ (if (null? (cdr indices))
+ (parse-error errtxt "missing keyword name"
+ indices))
+ (let ((kw (current-kw-lookup (cadr indices))))
+ (if (not kw)
+ (parse-error errtxt "unknown keyword"
+ indices))
+ kw)))
+ (else (parse-error errtxt "unknown indices type" (car indices))))))
+)
+
+; Parse a values spec.
+; CONTAINER is the <ident> object of the container.
+; Currently there is only special support for keywords.
+; Otherwise MODE is used.
+; The syntax is: (keyword keyword-spec) - see <keyword> for details.
+
+(define (-hw-parse-values errtxt values container mode)
+ (if (null? values)
+ (make <hw-asm>
+ (obj:name container) (obj:comment container) (obj-atlist container)
+ mode)
+ (begin
+ (if (not (list? values))
+ (parse-error errtxt "invalid values spec" values))
+ (case (car values)
+ ((keyword) (-hw-parse-keyword errtxt (cdr values) container mode))
+ ((extern-keyword) (begin
+ (if (null? (cdr values))
+ (parse-error errtxt "missing keyword name"
+ values))
+ (let ((kw (current-kw-lookup (cadr values))))
+ (if (not kw)
+ (parse-error errtxt "unknown keyword"
+ values))
+ kw)))
+ (else (parse-error errtxt "unknown values type" (car values))))))
+)
+
+; Parse a handlers spec.
+; Each element is (name "string").
+
+(define (-hw-parse-handlers errtxt handlers)
+ (parse-handlers errtxt '(parse print) handlers)
+)
+
+; Parse a getter spec.
+; The syntax is (([index]) (expression)).
+; Omit `index' for scalar objects.
+; Externally they're specified as `get'. Internally we use `getter'.
+
+(define (-hw-parse-getter errtxt getter scalar?)
+ (if (null? getter)
+ #f ; use default
+ (let ((valid "((index) (expression))")
+ (scalar-valid "(() (expression))"))
+ (if (or (not (list? getter))
+ (!= (length getter) 2)
+ (not (and (list? (car getter))
+ (= (length (car getter)) (if scalar? 0 1)))))
+ (parse-error errtxt
+ (string-append "invalid getter, should be "
+ (if scalar? scalar-valid valid))
+ getter))
+ (if (not (rtx? (cadr getter)))
+ (parse-error errtxt "invalid rtx expression" getter))
+ getter))
+)
+
+; Parse a setter spec.
+; The syntax is (([index] newval) (expression)).
+; Omit `index' for scalar objects.
+; Externally they're specified as `set'. Internally we use `setter'.
+
+(define (-hw-parse-setter errtxt setter scalar?)
+ (if (null? setter)
+ #f ; use default
+ (let ((valid "((index newval) (expression))")
+ (scalar-valid "((newval) (expression))"))
+ (if (or (not (list? setter))
+ (!= (length setter) 2)
+ (not (and (list? (car setter))
+ (= (length (car setter)) (if scalar? 1 2)))))
+ (parse-error errtxt
+ (string-append "invalid setter, should be "
+ (if scalar? scalar-valid valid))
+ setter))
+ (if (not (rtx? (cadr setter)))
+ (parse-error errtxt "invalid rtx expression" setter))
+ setter))
+)
+
+; Parse hardware description
+; This is the main routine for building a hardware object from a hardware
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+;
+; ??? Might want to redo to handle hardware type specific specs more cleanly.
+; E.g. <hw-immediate> shouldn't have to see get/set specs.
+
+(define (-hw-parse errtxt name comment attrs semantic-name type
+ indices values handlers get set layout)
+ (logit 2 "Processing hardware element " name " ...\n")
+
+ (if (null? type)
+ (parse-error errtxt "missing hardware type" name))
+
+ ; Pick out name first 'cus we need it as a string(/symbol).
+ (let ((name (parse-name name "hardware"))
+ (class-name (assq-ref -hardware-types (car type)))
+ (atlist-obj (atlist-parse attrs "cgen_hw" errtxt)))
+
+ (if (not class-name)
+ (parse-error errtxt "unknown hardware type" type))
+
+ (if (keep-atlist? atlist-obj #f)
+
+ (let ((result (new (class-lookup class-name))))
+ (send result 'set-name! name)
+ (send result 'set-comment! (parse-comment comment errtxt))
+ (send result 'set-atlist! atlist-obj)
+ (elm-xset! result 'sem-name semantic-name)
+ (send result 'parse! errtxt
+ (cdr type) indices values handlers get set layout)
+ ; If this is a virtual reg, get/set specs must be provided.
+ (if (and (obj-has-attr? result 'VIRTUAL)
+ (not (and (hw-getter result) (hw-setter result))))
+ (parse-error errtxt "virtual reg requires get/set specs" name))
+ ; If get or set specs are specified, can't have CACHE-ADDR.
+ (if (and (obj-has-attr? result 'CACHE-ADDR)
+ (or (hw-getter result) (hw-setter result)))
+ (parse-error errtxt "can't have CACHE-ADDR with get/set specs" name))
+ result)
+
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read a hardware description
+; This is the main routine for analyzing a hardware description in the .cpu
+; file.
+; ARG-LIST is an associative list of field name and field value.
+; -hw-parse is invoked to create the <hardware> object.
+
+(define (-hw-read errtxt . arg-list)
+ (let ((name nil) ; name of hardware
+ (comment "")
+ (attrs nil)
+ (semantic-name nil) ; name used in semantics, default is `name'
+ (type nil) ; hardware type (register, immediate, etc.)
+ (indices nil)
+ (values nil)
+ (handlers nil)
+ (get nil)
+ (set nil)
+ (layout nil)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((semantic-name) (set! semantic-name (cadr arg)))
+ ((type) (set! type (cdr arg)))
+ ((indices) (set! indices (cdr arg)))
+ ((values) (set! values (cdr arg)))
+ ((handlers) (set! handlers (cdr arg)))
+ ((get) (set! get (cdr arg)))
+ ((set) (set! set (cdr arg)))
+ ((layout) (set! layout (cdr arg)))
+ (else (parse-error errtxt "invalid hardware arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-hw-parse errtxt name comment attrs
+ (if (null? semantic-name) name semantic-name)
+ type indices values handlers get set layout)
+ )
+)
+
+; Define a hardware object, name/value pair list version.
+
+(define define-hardware
+ (lambda arg-list
+ (let ((hw (apply -hw-read (cons "define-hardware" arg-list))))
+ (if hw
+ (current-hw-add! hw))
+ hw))
+)
+
+; Define a hardware object, all arguments specified.
+
+(define (define-full-hardware name comment attrs semantic-name type
+ indices values handlers get set layout)
+ (let ((hw (-hw-parse "define-full-hardware"
+ name comment attrs semantic-name type
+ indices values handlers get set layout)))
+ (if hw
+ (current-hw-add! hw))
+ hw)
+)
+
+; Main routine for modifying existing definitions.
+
+(define modify-hardware
+ (lambda arg-list
+ (let ((errtxt "modify-hardware"))
+
+ ; FIXME: Experiment. This implements the :name/value style by
+ ; converting it to (name value). In the end there shouldn't be two
+ ; styles. People might prefer :name/value, but it's not as amenable
+ ; to macro processing (insert potshots regarding macro usage).
+ (if (keyword-list? (car arg-list))
+ (set! arg-list (keyword-list->arg-list arg-list)))
+
+ ; First find out which element.
+ ; There's no requirement that the name be specified first.
+ (let ((hw-spec (assq 'name arg-list)))
+ (if (not hw-spec)
+ (parse-error errtxt "hardware name not specified"))
+
+ (let ((hw (current-hw-lookup (arg-list-symbol-arg errtxt hw-spec))))
+ (if (not hw)
+ (parse-error errtxt "undefined hardware element" hw-spec))
+
+ ; Process the rest of the args now that we have the affected object.
+ (let loop ((args arg-list))
+ (if (null? args)
+ #f ; done
+ (let ((arg-spec (car args)))
+ (case (car arg-spec)
+ ((name) #f) ; ignore, already processed
+ ((add-attrs)
+ (let ((atlist-obj (atlist-parse (cdr arg-spec)
+ "cgen_hw" errtxt)))
+ ; prepend attrs so new ones override existing ones
+ (obj-prepend-atlist! hw atlist-obj)))
+ (else
+ (parse-error errtxt "invalid/unsupported option" (car arg-spec))))
+ (loop (cdr args))))))))
+
+ *UNSPECIFIED*)
+)
+
+; Lookup a hardware object using its semantic name.
+; The result is a list of elements with SEM-NAME.
+; Callers must deal with cases where there is more than one.
+
+(define (current-hw-sem-lookup sem-name)
+ (find (lambda (hw) (eq? (hw-sem-name hw) sem-name))
+ (current-hw-list))
+)
+
+; Same as current-hw-sem-lookup, but result is 1 hw element or #f if not
+; found. An error is signalled if multiple hw elements are found.
+
+(define (current-hw-sem-lookup-1 sem-name)
+ (let ((hw-objs (current-hw-sem-lookup sem-name)))
+ (case (length hw-objs)
+ ((0) #f)
+ ((1) (car hw-objs))
+ (else (error "ambiguous hardware reference" sem-name))))
+)
+
+; Basic hardware types.
+; These inherit from `hardware-base'.
+; ??? Might wish to allow each target to add more, but we provide enough
+; examples to cover most cpus.
+
+; A register (or an array of them).
+
+(define <hw-register> (class-make '<hw-register> '(<hardware-base>) nil nil))
+
+; Subroutine of -hw-create-[gs]etter-from-layout to validate a layout.
+; Valid values:
+; - 0 or 1
+; - (value length)
+; - hardware-name
+
+(define (-hw-validate-layout errtxt layout width)
+ (if (not (list? layout))
+ (parse-error errtxt "layout is not a list" layout))
+
+ (let loop ((layout layout) (shift 0))
+ (if (null? layout)
+ (begin
+ ; Done. Now see if number of bits in layout matches total width.
+ (if (not (= shift width))
+ (parse-error errtxt (string-append
+ "insufficient number of bits (need "
+ (number->string width)
+ ")")
+ shift)))
+ ; Validate next entry.
+ (let ((val (car layout)))
+ (cond ((number? val)
+ (if (not (memq val '(0 1)))
+ (parse-error errtxt
+ "non 0/1 layout entry requires length"
+ val))
+ (loop (cdr layout) (1+ shift)))
+ ((pair? val)
+ (if (or (not (number? (car val)))
+ (not (pair? (cdr val)))
+ (not (number? (cadr val)))
+ (not (null? (cddr val))))
+ (parse-error errtxt
+ "syntax error in layout, expecting `(value length)'"
+ val))
+ (loop (cdr layout) (+ shift (cadr val))))
+ ((symbol? val)
+ (let ((hw (current-hw-lookup val)))
+ (if (not hw)
+ (parse-error errtxt "unknown hardware element" val))
+ (if (not (hw-scalar? hw))
+ (parse-error errtxt "non-scalar hardware element" val))
+ (loop (cdr layout)
+ (+ shift (hw-bits hw)))))
+ (else
+ (parse-error errtxt "bad layout element" val))))))
+ *UNSPECIFIED*
+)
+
+; Return the getter spec to use for LAYOUT.
+; WIDTH is the width of the combined value in bits.
+;
+; Example:
+; Assuming h-hw[123] are 1 bit registers, and width is 32
+; given ((0 29) h-hw1 h-hw2 h-hw3), return
+; (()
+; (or SI (sll SI (zext SI (reg h-hw1)) 2)
+; (or SI (sll SI (zext SI (reg h-hw2)) 1)
+; (zext SI (reg h-hw3)))))
+
+(define (-hw-create-getter-from-layout errtxt layout width)
+ (let ((add-to-res (lambda (result mode-name val shift)
+ (if (null? result)
+ (rtx-make 'sll mode-name val shift)
+ (rtx-make 'or mode-name
+ (rtx-make 'sll mode-name
+ (rtx-make 'zext mode-name val)
+ shift)
+ result))))
+ (mode-name (obj:name (mode-find width 'UINT))))
+ (let loop ((result nil) (layout (reverse layout)) (shift 0))
+ (if (null? layout)
+ (list nil result) ; getter spec: (get () (expression))
+ (let ((val (car layout)))
+ (cond ((number? val)
+ ; ignore if zero
+ (if (= val 0)
+ (loop result (cdr layout) (1+ shift))
+ (loop (add-to-res result mode-name val shift)
+ (cdr layout)
+ (1+ shift))))
+ ((pair? val)
+ ; ignore if zero
+ (if (= (car val) 0)
+ (loop result (cdr layout) (+ shift (cadr val)))
+ (loop (add-to-res result mode-name (car val) shift)
+ (cdr layout)
+ (+ shift (cadr val)))))
+ ((symbol? val)
+ (let ((hw (current-hw-lookup val)))
+ (loop (add-to-res result mode-name
+ (rtx-make 'reg val)
+ shift)
+ (cdr layout)
+ (+ shift (hw-bits hw)))))
+ (else
+ (assert (begin "bad layout element" #f))))))))
+)
+
+; Return the setter spec to use for LAYOUT.
+; WIDTH is the width of the combined value in bits.
+;
+; Example:
+; Assuming h-hw[123] are 1 bit registers,
+; given (h-hw1 h-hw2 h-hw3), return
+; ((val)
+; (sequence ()
+; (set (reg h-hw1) (and (srl val 2) 1))
+; (set (reg h-hw2) (and (srl val 1) 1))
+; (set (reg h-hw3) (and (srl val 0) 1))
+; ))
+
+(define (-hw-create-setter-from-layout errtxt layout width)
+ (let ((mode-name (obj:name (mode-find width 'UINT))))
+ (let loop ((sets nil) (layout (reverse layout)) (shift 0))
+ (if (null? layout)
+ (list '(val) ; setter spec: (set (val) (expression))
+ (apply rtx-make (cons 'sequence (cons nil sets))))
+ (let ((val (car layout)))
+ (cond ((number? val)
+ (loop sets (cdr layout) (1+ shift)))
+ ((pair? val)
+ (loop sets (cdr layout) (+ shift (cadr val))))
+ ((symbol? val)
+ (let ((hw (current-hw-lookup val)))
+ (loop (cons (rtx-make 'set
+ (rtx-make 'reg val)
+ (rtx-make 'and
+ (rtx-make 'srl 'val shift)
+ (1- (logsll 1 (hw-bits hw)))))
+ sets)
+ (cdr layout)
+ (+ shift (hw-bits hw)))))
+ (else
+ (assert (begin "bad layout element" #f))))))))
+)
+
+; Parse a register spec.
+; .cpu syntax: (register mode [(dimension)])
+; or: (register (mode bits) [(dimension)])
+
+(method-make!
+ <hw-register> 'parse!
+ (lambda (self errtxt type indices values handlers getter setter layout)
+ (if (or (null? type)
+ (> (length type) 2))
+ (parse-error errtxt "invalid register spec" type))
+ (if (and (= (length type) 2)
+ (or (not (list? (cadr type)))
+ (> (length (cadr type)) 1)))
+ (parse-error errtxt "bad register dimension spec" type))
+
+ ; Must parse and set type before analyzing LAYOUT.
+ (elm-set! self 'type (parse-type errtxt type))
+
+ ; LAYOUT is a shorthand way of specifying getter/setter specs.
+ ; For registers that are just a collection of other registers
+ ; (e.g. the status register in mips), it's easier to specify the
+ ; registers that make up the bigger register, rather than to specify
+ ; get/set specs.
+ ; We don't override any provided get/set specs though.
+ (if (not (null? layout))
+ (let ((width (hw-bits self)))
+ (-hw-validate-layout errtxt layout width)
+ (if (null? getter)
+ (set! getter
+ (-hw-create-getter-from-layout errtxt layout width)))
+ (if (null? setter)
+ (set! setter
+ (-hw-create-setter-from-layout errtxt layout width)))
+ ))
+
+ (elm-set! self 'indices (-hw-parse-indices errtxt indices self UINT))
+ (elm-set! self 'values (-hw-parse-values errtxt values self
+ (send (elm-get self 'type)
+ 'get-mode)))
+ (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
+ (elm-set! self 'get (-hw-parse-getter errtxt getter (hw-scalar? self)))
+ (elm-set! self 'set (-hw-parse-setter errtxt setter (hw-scalar? self)))
+ *UNSPECIFIED*)
+)
+
+; Return boolean indicating if hardware element is some kind of register.
+
+(method-make! <hw-register> 'register? (lambda (self) #t))
+
+; Return a boolean indicating if it's ok to reference SELF in mode
+; NEW-MODE-NAME, index INDEX.
+;
+; ??? INDEX isn't currently used. The intent is to use it if it's a known
+; value, and otherwise assume for our purposes it's valid and leave any
+; further error checking to elsewhere.
+;
+; ??? This method makes more sense if we support multiple modes via
+; getters/setters. Maybe we will some day, so this is left as is for now.
+
+(method-make!
+ <hw-register> 'mode-ok?
+ (lambda (self new-mode-name index)
+ (let ((cur-mode (send self 'get-mode))
+ (new-mode (mode:lookup new-mode-name)))
+ (if (mode:eq? new-mode-name cur-mode)
+ #t
+ ; ??? Subject to revisiting.
+ ; Only allow floats if same mode (which is handled above).
+ ; Only allow non-widening if ints.
+ ; On architectures where shortening/widening can refer to a
+ ; quasi-different register, it is up to the target to handle this.
+ ; See the comments for the getter/setter/getters/setters class
+ ; members.
+ (let ((cur-mode-class (mode:class cur-mode))
+ (cur-bits (mode:bits cur-mode))
+ (new-mode-class (mode:class new-mode))
+ (new-bits (mode:bits new-mode)))
+ ; Compensate for registers defined with an unsigned mode.
+ (if (eq? cur-mode-class 'UINT)
+ (set! cur-mode-class 'INT))
+ (if (eq? new-mode-class 'UINT)
+ (set! new-mode-class 'INT))
+ (if (eq? cur-mode-class 'INT)
+ (and (eq? new-mode-class cur-mode-class)
+ (<= new-bits cur-bits))
+ #f)))))
+)
+
+; Return mode to use for the index or #f if scalar.
+
+(method-make!
+ <hw-register> 'get-index-mode
+ (lambda (self)
+ (if (scalar? (hw-type self))
+ #f
+ UINT))
+)
+
+; The program counter (PC) hardware register.
+; This is a separate class as the simulator needs a place to put special
+; get/set methods.
+
+(define <hw-pc> (class-make '<hw-pc> '(<hw-register>) nil nil))
+
+; Parse a pc spec.
+
+(method-make!
+ <hw-pc> 'parse!
+ (lambda (self errtxt type indices values handlers getter setter layout)
+ (if (not (null? type))
+ (elm-set! self 'type (parse-type errtxt type))
+ (elm-set! self 'type (make <scalar> (mode:lookup 'IAI))))
+ (if (not (null? indices))
+ (parse-error errtxt "indices specified for pc" indices))
+ (if (not (null? values))
+ (parse-error errtxt "values specified for pc" values))
+ (if (not (null? layout))
+ (parse-error errtxt "layout specified for pc" values))
+ ; The initial value of INDICES, VALUES is #f which is what we want.
+ (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
+ (elm-set! self 'get (-hw-parse-getter errtxt getter (hw-scalar? self)))
+ (elm-set! self 'set (-hw-parse-setter errtxt setter (hw-scalar? self)))
+ *UNSPECIFIED*)
+)
+
+; Indicate we're the pc.
+
+(method-make! <hw-pc> 'pc? (lambda (self) #t))
+
+; Memory.
+
+(define <hw-memory> (class-make '<hw-memory> '(<hardware-base>) nil nil))
+
+; Parse a memory spec.
+; .cpu syntax: (memory mode [(dimension)])
+; or: (memory (mode bits) [(dimension)])
+
+(method-make!
+ <hw-memory> 'parse!
+ (lambda (self errtxt type indices values handlers getter setter layout)
+ (if (or (null? type)
+ (> (length type) 2))
+ (parse-error errtxt "invalid memory spec" type))
+ (if (and (= (length type) 2)
+ (or (not (list? (cadr type)))
+ (> (length (cadr type)) 1)))
+ (parse-error errtxt "bad memory dimension spec" type))
+ (if (not (null? layout))
+ (parse-error errtxt "layout specified for memory" values))
+ (elm-set! self 'type (parse-type errtxt type))
+ ; Setting INDICES,VALUES here is mostly for experimentation at present.
+ (elm-set! self 'indices (-hw-parse-indices errtxt indices self AI))
+ (elm-set! self 'values (-hw-parse-values errtxt values self
+ (send (elm-get self 'type)
+ 'get-mode)))
+ (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
+ (elm-set! self 'get (-hw-parse-getter errtxt getter (hw-scalar? self)))
+ (elm-set! self 'set (-hw-parse-setter errtxt setter (hw-scalar? self)))
+ *UNSPECIFIED*)
+)
+
+; Return boolean indicating if hardware element is some kind of memory.
+
+(method-make! <hw-memory> 'memory? (lambda (self) #t))
+
+; Return a boolean indicating if it's ok to reference SELF in mode
+; NEW-MODE-NAME, index INDEX.
+
+(method-make!
+ <hw-memory> 'mode-ok?
+ (lambda (self new-mode-name index)
+ ; Allow any mode for now.
+ #t)
+)
+
+; Return mode to use for the index or #f if scalar.
+
+(method-make!
+ <hw-memory> 'get-index-mode
+ (lambda (self)
+ AI)
+)
+
+; Immediate values (numbers recorded in the insn).
+
+(define <hw-immediate> (class-make '<hw-immediate> '(<hardware-base>) nil nil))
+
+; Parse an immediate spec.
+; .cpu syntax: (immediate mode)
+; or: (immediate (mode bits))
+
+(method-make!
+ <hw-immediate> 'parse!
+ (lambda (self errtxt type indices values handlers getter setter layout)
+ (if (not (= (length type) 1))
+ (parse-error errtxt "invalid immediate spec" type))
+ (elm-set! self 'type (parse-type errtxt type))
+ ; An array of immediates may be useful some day, but not yet.
+ (if (not (null? indices))
+ (parse-error errtxt "indices specified for immediate" indices))
+ (if (not (null? layout))
+ (parse-error errtxt "layout specified for immediate" values))
+ (elm-set! self 'values (-hw-parse-values errtxt values self
+ (send (elm-get self 'type)
+ 'get-mode)))
+ (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
+ (if (not (null? getter))
+ (parse-error errtxt "getter specified for immediate" getter))
+ (if (not (null? setter))
+ (parse-error errtxt "setter specified for immediate" setter))
+ *UNSPECIFIED*)
+)
+
+; Return a boolean indicating if it's ok to reference SELF in mode
+; NEW-MODE-NAME, index INDEX.
+
+(method-make!
+ <hw-immediate> 'mode-ok?
+ (lambda (self new-mode-name index)
+ (let ((cur-mode (send self 'get-mode))
+ (new-mode (mode:lookup new-mode-name)))
+ (if (mode:eq? new-mode-name cur-mode)
+ #t
+ ; ??? Subject to revisiting.
+ ; Only allow floats if same mode (which is handled above).
+ ; For ints allow anything.
+ (let ((cur-mode-class (mode:class cur-mode))
+ (new-mode-class (mode:class new-mode)))
+ (->bool (and (memq cur-mode-class '(INT UINT))
+ (memq new-mode-class '(INT UINT))))))))
+)
+
+; Addresses.
+; These are usually symbols.
+
+(define <hw-address> (class-make '<hw-address> '(<hardware-base>) nil nil))
+
+(method-make! <hw-address> 'address? (lambda (self) #t))
+
+; Parse an address spec.
+
+(method-make!
+ <hw-address> 'parse!
+ (lambda (self errtxt type indices values handlers getter setter layout)
+ (if (not (null? type))
+ (parse-error errtxt "invalid address spec" type))
+ (elm-set! self 'type (make <scalar> AI))
+ (if (not (null? indices))
+ (parse-error errtxt "indices specified for address" indices))
+ (if (not (null? values))
+ (parse-error errtxt "values specified for address" values))
+ (if (not (null? layout))
+ (parse-error errtxt "layout specified for address" values))
+ (elm-set! self 'values (-hw-parse-values errtxt values self
+ (send (elm-get self 'type)
+ 'get-mode)))
+ (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
+ (if (not (null? getter))
+ (parse-error errtxt "getter specified for address" getter))
+ (if (not (null? setter))
+ (parse-error errtxt "setter specified for address" setter))
+ *UNSPECIFIED*)
+)
+
+; Return a boolean indicating if it's ok to reference SELF in mode
+; NEW-MODE-NAME, index INDEX.
+
+(method-make!
+ <hw-address> 'mode-ok?
+ (lambda (self new-mode-name index)
+ ; We currently don't allow referencing an address in any mode other than
+ ; the original mode.
+ (mode-compatible? 'samesize new-mode-name (send self 'get-mode)))
+)
+
+; Instruction addresses.
+; These are treated separately from normal addresses as the simulator
+; may wish to treat them specially.
+; FIXME: Doesn't use mode IAI.
+
+(define <hw-iaddress> (class-make '<hw-iaddress> '(<hw-address>) nil nil))
+
+(method-make! <hw-iaddress> 'iaddress? (lambda (self) #t))
+
+; Builtins, attributes, init/fini support.
+
+(define h-memory #f)
+(define h-sint #f)
+(define h-uint #f)
+(define h-addr #f)
+(define h-iaddr #f)
+
+
+; Map a mode to a hardware object that can contain immediate values of that mode
+(define (hardware-for-mode mode)
+ (cond ((mode:eq? mode 'AI) h-addr)
+ ((mode:eq? mode 'IAI) h-addr)
+ ((mode-signed? mode) h-sint)
+ ((mode-unsigned? mode) h-uint)
+ (else (error "Don't know h-object for mode " mode)))
+)
+
+
+; Called before reading a .cpu file in.
+
+(define (hardware-init!)
+ (reader-add-command! 'define-keyword
+ "\
+Define a keyword, name/value pair list version.
+"
+ nil 'arg-list define-keyword)
+ (reader-add-command! 'define-hardware
+ "\
+Define a hardware element, name/value pair list version.
+"
+ nil 'arg-list define-hardware)
+ (reader-add-command! 'define-full-hardware
+ "\
+Define a hardware element, all arguments specified.
+"
+ nil '(name comment attrs semantic-name type
+ indices values handlers get set layout)
+ define-full-hardware)
+ (reader-add-command! 'modify-hardware
+ "\
+Modify a hardware element, name/value pair list version.
+"
+ nil 'arg-list modify-hardware)
+
+ *UNSPECIFIED*
+)
+
+; Install builtin hardware objects.
+
+(define (hardware-builtin!)
+ ; Standard h/w attributes.
+ (define-attr '(for hardware) '(type boolean) '(name CACHE-ADDR)
+ '(comment "cache register address during insn extraction"))
+ ; FIXME: This should be deletable.
+ (define-attr '(for hardware) '(type boolean) '(name PC)
+ '(comment "the program counter"))
+ (define-attr '(for hardware) '(type boolean) '(name PROFILE)
+ '(comment "collect profiling data"))
+
+ (let ((all (stringize (current-arch-isa-name-list) ",")))
+ ; ??? The program counter, h-pc, used to be defined here.
+ ; However, some targets need to modify it (e.g. provide special get/set
+ ; specs). There's still an outstanding issue of how to add things to
+ ; objects after the fact (e.g. model parameters to instructions), but
+ ; that's further down the road.
+ (set! h-memory (define-full-hardware 'h-memory "memory"
+ `((ISA ,all))
+ ; Ensure memory not flagged as a scalar.
+ 'h-memory '(memory UQI (1)) nil nil nil
+ nil nil nil))
+ (set! h-sint (define-full-hardware 'h-sint "signed integer"
+ `((ISA ,all))
+ 'h-sint '(immediate (INT 32)) nil nil nil
+ nil nil nil))
+ (set! h-uint (define-full-hardware 'h-uint "unsigned integer"
+ `((ISA ,all))
+ 'h-uint '(immediate (UINT 32)) nil nil nil
+ nil nil nil))
+ (set! h-addr (define-full-hardware 'h-addr "address"
+ `((ISA ,all))
+ 'h-addr '(address) nil nil '((print "print_address"))
+ nil nil nil))
+ ; Instruction addresses.
+ ; These are different because the simulator may want to do something
+ ; special with them, and some architectures treat them differently.
+ (set! h-iaddr (define-full-hardware 'h-iaddr "instruction address"
+ `((ISA ,all))
+ 'h-iaddr '(iaddress) nil nil '((print "print_address"))
+ nil nil nil)))
+
+ *UNSPECIFIED*
+)
+
+; Called after a .cpu file has been read in.
+
+(define (hardware-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/i960.cpu b/cgen/i960.cpu
new file mode 100644
index 00000000000..6bd641e1487
--- /dev/null
+++ b/cgen/i960.cpu
@@ -0,0 +1,1320 @@
+; Intel 80960 CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Misc CGEN related problems.
+
+; ??? CGEN assumes that the program counter is called PC. On the i960, it
+; is called IP (Instruction Pointer).
+
+; ??? Try using (f-m3 1) instead of M3_1.
+
+; ??? Try using the RESERVED attribute for instruction fields.
+
+(include "simplify.inc")
+
+
+; Architecture and cpu family definitions.
+
+; ??? This should be using (insn-lsb0? #t), but it doesn't work yet.
+
+(define-arch
+ (name i960)
+ (comment "Intel 80960 architecture")
+ (machs i960:ka_sa i960:ca)
+ (isas i960)
+)
+
+(define-isa
+ (name i960)
+ (base-insn-bitsize 32)
+ (decode-assist (0 1 2 3 4 5 6 7))
+ (liw-insns 1)
+ (parallel-insns 1)
+)
+
+(define-cpu
+ (name i960base)
+ (comment "Intel 80960 cpu family")
+ (endian little)
+ (word-bitsize 32)
+)
+
+(define-mach
+ (name i960:ka_sa)
+ (comment "I960 KA and SA processors")
+ (cpu i960base)
+)
+
+; ??? Incomplete. Pipeline and unit info wrong.
+
+(define-model
+ (name i960KA)
+ (comment "I960 KA processor")
+ (mach i960:ka_sa)
+ (pipeline all "" () ((fetch) (decode) (execute) (writeback)))
+ (unit u-exec "Execution Unit" () 1 1
+ () () () ())
+)
+
+(define-mach
+ (name i960:ca)
+ (comment "I960 CA processor")
+ (cpu i960base)
+)
+
+; ??? Incomplete. Pipeline and unit info wrong.
+
+(define-model
+ (name i960CA)
+ (comment "I960 CA processor")
+ (mach i960:ca)
+ (pipeline all "" () ((fetch) (decode) (execute) (writeback)))
+ (unit u-exec "Execution Unit" () 1 1
+ () () () ())
+)
+
+; Instruction fields.
+;
+; Attributes:
+; PCREL-ADDR: pc relative value (for reloc and disassembly purposes)
+; ABS-ADDR: absolute address (for reloc and disassembly purposes?)
+; RESERVED: bits are not used to decode insn, must be all 0
+
+; All of the fields for a REG format instruction.
+
+(dnf f-opcode "opcode" () 0 8)
+(dnf f-srcdst "src/dst" () 8 5)
+(dnf f-src2 "src2" () 13 5)
+(dnf f-m3 "m3" () 18 1)
+(dnf f-m2 "m2" () 19 1)
+(dnf f-m1 "m1" () 20 1)
+(dnf f-opcode2 "opcode2" () 21 4)
+(dnf f-zero "zero" () 25 2)
+(dnf f-src1 "src1" () 27 5)
+
+; Extra fields needed for a MEMA format instruction.
+
+(dnf f-abase "abase" () 13 5)
+(dnf f-modea "modea" () 18 1)
+(dnf f-zeroa "zeroa" () 19 1)
+(dnf f-offset "offset" () 20 12)
+
+; Extra fields needed for a MEMB format instruction.
+
+(dnf f-modeb "modeb" () 18 4)
+(dnf f-scale "scale" () 22 3)
+(dnf f-zerob "zerob" () 25 2)
+(dnf f-index "index" () 27 5)
+(dnf f-optdisp "optional displacement" () 32 32)
+
+; Extra fields needed for a COBR format instruction.
+
+(dnf f-br-src1 "branch src1" () 8 5)
+(dnf f-br-src2 "branch src2" () 13 5)
+(dnf f-br-m1 "branch m1" () 18 1)
+(df f-br-disp "branch displacement" (PCREL-ADDR) 19 11 INT
+ ((value pc) (sra WI (sub WI value pc) (const 2)))
+ ((value pc) (add WI (sll WI value (const 2)) pc)))
+(dnf f-br-zero "branch zero" () 30 2)
+
+; Extra fields needed for a CRTL format instruction.
+
+(df f-ctrl-disp "ctrl branch disp" (PCREL-ADDR) 8 22 INT
+ ((value pc) (sra WI (sub WI value pc) (const 2)))
+ ((value pc) (add WI (sll WI value (const 2)) pc)))
+(dnf f-ctrl-zero "ctrl branch zero" () 30 2)
+
+
+; Enums.
+
+(define-pmacro (build-hex2 num) (.hex num 2))
+
+; insn-opcode
+(define-normal-insn-enum insn-opcode "insn opcode enums" () OPCODE_ f-opcode
+ (.map .upcase (.map build-hex2 (.iota 256))) ; "00" -> "FF"
+)
+
+(define-normal-insn-enum insn-opcode2 "insn opcode2 enums" () OPCODE2_
+ f-opcode2
+ (.map .upcase (.map .hex (.iota 16))) ; "0" -> "F"
+)
+
+(define-normal-insn-enum insn-m3 "insn m3 enums" () M3_
+ f-m3
+ ("0" "1")
+)
+
+(define-normal-insn-enum insn-m2 "insn m3 enums" () M2_
+ f-m2
+ ("0" "1")
+)
+
+(define-normal-insn-enum insn-m1 "insn m1 enums" () M1_
+ f-m1
+ ("0" "1")
+)
+
+(define-normal-insn-enum insn-zero "insn zero enums" () ZERO_
+ f-zero
+ ("0")
+)
+
+(define-normal-insn-enum insn-modea "insn mode a enums" () MODEA_
+ f-modea
+ ("OFFSET" "INDIRECT-OFFSET")
+)
+
+(define-normal-insn-enum insn-zeroa "insn zero a enums" () ZEROA_
+ f-zeroa
+ ("0")
+)
+
+(define-normal-insn-enum insn-modeb "insn mode b enums" () MODEB_
+ f-modeb
+ ("ILL0" "ILL1" "ILL2" "ILL3" "INDIRECT" "IP-DISP" "RES6" "INDIRECT-INDEX"
+ "ILL8" "ILL9" "ILL10" "ILL11" "DISP" "INDIRECT-DISP" "INDEX-DISP"
+ "INDIRECT-INDEX-DISP")
+)
+
+(define-normal-insn-enum insn-zerob "insn zero b enums" () ZEROB_
+ f-zerob
+ ("0")
+)
+
+(define-normal-insn-enum insn-br-m1 "insn branch m1 enums" () BR_M1_
+ f-br-m1
+ ("0" "1")
+)
+
+(define-normal-insn-enum insn-br-zero "insn branch zero enums" () BR_ZERO_
+ f-br-zero
+ ("0")
+)
+
+(define-normal-insn-enum insn-ctrl-zero "insn ctrl zero enums" () CTRL_ZERO_
+ f-ctrl-zero
+ ("0")
+)
+
+
+; Hardware pieces
+
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs PROFILE CACHE-ADDR)
+ (type register WI (32))
+ (indices keyword ""
+ ((fp 31) (sp 1)
+ (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15)
+ (g0 16) (g1 17) (g2 18) (g3 19) (g4 20) (g5 21) (g6 22) (g7 23)
+ (g8 24) (g9 25) (g10 26) (g11 27) (g12 28) (g13 29) (g14 30) (g15 31)
+ ))
+)
+
+; ??? This is actually part of the AC register.
+
+(define-hardware
+ (name h-cc)
+ (comment "condition code")
+ (attrs PROFILE CACHE-ADDR)
+ (type register WI)
+ (indices keyword "" ((cc 0)))
+)
+
+;(define-hardware
+; (name h-pc)
+; (comment "program counter")
+; (attrs PC)
+; (type register WI)
+; ; (handlers (print "ip"))
+;)
+
+; ??? Incomplete.
+
+
+; Instruction Operands.
+; These entries provide a layer between the assembler and the raw hardware
+; description, and are used to refer to hardware elements in the semantic
+; code. Usually there's a bit of over-specification, but in more complicated
+; instruction sets there isn't.
+
+; Operand fields for a REG format instruction.
+
+(dnop src1 "source register 1" () h-gr f-src1)
+(dnop src2 "source register 2" () h-gr f-src2)
+(dnop dst "source/dest register" () h-gr f-srcdst)
+
+(dnop lit1 "literal 1" () h-uint f-src1)
+(dnop lit2 "literal 2" () h-uint f-src2)
+
+; Operand fields for a MEMA format instruction.
+
+(dnop st_src "store src" () h-gr f-srcdst)
+(dnop abase "abase" () h-gr f-abase)
+(dnop offset "offset" () h-uint f-offset)
+
+; Operand fields for a MEMB format instruction.
+
+(dnop scale "scale" () h-uint f-scale)
+(dnop index "index" () h-gr f-index)
+(dnop optdisp "optional displacement" () h-uint f-optdisp)
+
+; Operand fields for a COBR format instruction.
+
+(dnop br_src1 "branch src1" () h-gr f-br-src1)
+(dnop br_src2 "branch src2" () h-gr f-br-src2)
+(dnop br_disp "branch displacement" () h-iaddr f-br-disp)
+
+(dnop br_lit1 "branch literal 1" () h-uint f-br-src1)
+
+; Operand fields for a CRTL format instruction.
+
+(dnop ctrl_disp "ctrl branch disp" () h-iaddr f-ctrl-disp)
+
+
+; Instruction definitions.
+
+; ??? Maybe I should just reverse the operands in the alu-op macro.
+
+(define-pmacro (divo-expr expr1 expr2) (udiv expr2 expr1))
+(define-pmacro (divi-expr expr1 expr2) (div expr2 expr1))
+(define-pmacro (remo-expr expr1 expr2) (umod expr2 expr1))
+(define-pmacro (remi-expr expr1 expr2) (mod expr2 expr1))
+
+(define-pmacro (sub-expr expr1 expr2) (sub expr2 expr1))
+
+(define-pmacro (notbit-expr expr1 expr2)
+ (xor (sll (const 1) expr1) expr2))
+(define-pmacro (andnot-expr expr1 expr2)
+ (and expr2 (inv expr1)))
+(define-pmacro (setbit-expr expr1 expr2)
+ (or (sll (const 1) expr1) expr2))
+(define-pmacro (notand-expr expr1 expr2)
+ (and (inv expr2) expr1))
+(define-pmacro (nor-expr expr1 expr2)
+ (and (inv expr2) (inv expr1)))
+(define-pmacro (xnor-expr expr1 expr2)
+ (inv (xor expr1 expr2)))
+(define-pmacro (not-expr expr1 expr2)
+ (inv expr1))
+(define-pmacro (ornot-expr expr1 expr2)
+ (or expr2 (inv expr1)))
+(define-pmacro (clrbit-expr expr1 expr2)
+ (and (inv (sll (const 1) expr1)) expr2))
+
+; A shift of 32 or more shifts out all input bits.
+
+(define-pmacro (sll-expr expr1 expr2)
+ (cond WI
+ ((geu UWI expr1 (const 32)) (const 0))
+ (else (sll expr2 expr1))))
+(define-pmacro (srl-expr expr1 expr2)
+ (cond WI
+ ((geu UWI expr1 (const 32)) (const 0))
+ (else (srl expr2 expr1))))
+(define-pmacro (sra-expr expr1 expr2)
+ (cond WI
+ ((geu UWI expr1 (const 32)) (sra expr2 (const 31)))
+ (else (sra expr2 expr1))))
+
+(define-pmacro (alu-op mnemonic opcode-op opcode2-op sem-op)
+ (begin
+ (dni mnemonic
+ (.str mnemonic " reg/reg")
+ ()
+ (.str mnemonic " $src1, $src2, $dst")
+ (+ opcode-op dst src2 M3_0 M2_0 M1_0 opcode2-op ZERO_0 src1)
+ (set dst (sem-op src1 src2))
+ ()
+ )
+ (dni (.sym mnemonic "1")
+ (.str mnemonic " lit/reg")
+ ()
+ (.str mnemonic " $lit1, $src2, $dst")
+ (+ opcode-op dst src2 M3_0 M2_0 M1_1 opcode2-op ZERO_0 lit1)
+ (set dst (sem-op lit1 src2))
+ ()
+ )
+ (dni (.sym mnemonic "2")
+ (.str mnemonic " reg/lit")
+ ()
+ (.str mnemonic " $src1, $lit2, $dst")
+ (+ opcode-op dst lit2 M3_0 M2_1 M1_0 opcode2-op ZERO_0 src1)
+ (set dst (sem-op src1 lit2))
+ ()
+ )
+ (dni (.sym mnemonic "3")
+ (.str mnemonic " lit/lit")
+ ()
+ (.str mnemonic " $lit1, $lit2, $dst")
+ (+ opcode-op dst lit2 M3_0 M2_1 M1_1 opcode2-op ZERO_0 lit1)
+ (set dst (sem-op lit1 lit2))
+ ()
+ )
+ )
+)
+
+(alu-op mulo OPCODE_70 OPCODE2_1 mul)
+(alu-op remo OPCODE_70 OPCODE2_8 remo-expr)
+(alu-op divo OPCODE_70 OPCODE2_B divo-expr)
+(alu-op remi OPCODE_74 OPCODE2_8 remi-expr)
+(alu-op divi OPCODE_74 OPCODE2_B divi-expr)
+
+(alu-op addo OPCODE_59 OPCODE2_0 add)
+(alu-op subo OPCODE_59 OPCODE2_2 sub-expr)
+
+(alu-op notbit OPCODE_58 OPCODE2_0 notbit-expr)
+(alu-op and OPCODE_58 OPCODE2_1 and)
+(alu-op andnot OPCODE_58 OPCODE2_2 andnot-expr)
+(alu-op setbit OPCODE_58 OPCODE2_3 setbit-expr)
+(alu-op notand OPCODE_58 OPCODE2_4 notand-expr)
+(alu-op xor OPCODE_58 OPCODE2_6 xor)
+(alu-op or OPCODE_58 OPCODE2_7 or)
+(alu-op nor OPCODE_58 OPCODE2_8 nor-expr)
+(alu-op xnor OPCODE_58 OPCODE2_9 xnor-expr)
+(alu-op not OPCODE_58 OPCODE2_A not-expr)
+(alu-op ornot OPCODE_58 OPCODE2_B ornot-expr)
+(alu-op clrbit OPCODE_58 OPCODE2_C clrbit-expr)
+
+; ??? Incomplete. Does not handle overflow for integer shifts.
+
+(alu-op shlo OPCODE_59 OPCODE2_C sll-expr)
+(alu-op shro OPCODE_59 OPCODE2_8 srl-expr)
+(alu-op shli OPCODE_59 OPCODE2_E sll-expr)
+(alu-op shri OPCODE_59 OPCODE2_B sra-expr)
+
+
+; ??? Does not verify alignment of dest reg.
+
+(define-pmacro (emul-expr dest expr1 expr2)
+ (sequence ((DI temp) (SI dregno))
+ (set temp (mul DI (zext DI expr1) (zext DI expr2)))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set dest (trunc SI temp))
+ (set (reg h-gr (add (index-of dest) (const 1)))
+ (trunc SI (srl temp (const 32))))))
+
+; ??? Needless duplicate of alu-op. Should eliminate alu-op.
+
+(define-pmacro (alu2-op mnemonic opcode-op opcode2-op sem-op)
+ (begin
+ (dni mnemonic
+ (.str mnemonic " reg/reg")
+ ()
+ (.str mnemonic " $src1, $src2, $dst")
+ (+ opcode-op dst src2 M3_0 M2_0 M1_0 opcode2-op ZERO_0 src1)
+ (sem-op dst src1 src2)
+ ()
+ )
+ (dni (.sym mnemonic "1")
+ (.str mnemonic " lit/reg")
+ ()
+ (.str mnemonic " $lit1, $src2, $dst")
+ (+ opcode-op dst src2 M3_0 M2_0 M1_1 opcode2-op ZERO_0 lit1)
+ (sem-op dst lit1 src2)
+ ()
+ )
+ (dni (.sym mnemonic "2")
+ (.str mnemonic " reg/lit")
+ ()
+ (.str mnemonic " $src1, $lit2, $dst")
+ (+ opcode-op dst lit2 M3_0 M2_1 M1_0 opcode2-op ZERO_0 src1)
+ (sem-op dst src1 lit2)
+ ()
+ )
+ (dni (.sym mnemonic "3")
+ (.str mnemonic " lit/lit")
+ ()
+ (.str mnemonic " $lit1, $lit2, $dst")
+ (+ opcode-op dst lit2 M3_0 M2_1 M1_1 opcode2-op ZERO_0 lit1)
+ (sem-op dst lit1 lit2)
+ ()
+ )
+ )
+)
+
+(alu2-op emul OPCODE_67 OPCODE2_0 emul-expr)
+
+
+
+; ??? lit2 must be zero.
+; ??? should verify multi-word reg alignment.
+
+(define-pmacro (mov-expr expr1 expr2)
+ (set expr1 expr2))
+(define-pmacro (movl-expr expr1 expr2)
+ (sequence ((SI dregno) (SI sregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set sregno (ifield f-src1))
+ (set expr1 expr2)
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (reg h-gr (add (index-of expr2) (const 1))))))
+(define-pmacro (movllit-expr expr1 expr2)
+ (sequence ((SI dregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set expr1 expr2)
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (const 0))))
+(define-pmacro (movt-expr expr1 expr2)
+ (sequence ((SI dregno) (SI sregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set sregno (ifield f-src1))
+ (set expr1 expr2)
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (reg h-gr (add (index-of expr2) (const 1))))
+ (set (reg h-gr (add (index-of expr1) (const 2)))
+ (reg h-gr (add (index-of expr2) (const 2))))))
+(define-pmacro (movtlit-expr expr1 expr2)
+ (sequence ((SI dregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set expr1 expr2)
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (const 0))
+ (set (reg h-gr (add (index-of expr1) (const 2)))
+ (const 0))))
+(define-pmacro (movq-expr expr1 expr2)
+ (sequence ((SI dregno) (SI sregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set sregno (ifield f-src1))
+ (set expr1 expr2)
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (reg h-gr (add (index-of expr2) (const 1))))
+ (set (reg h-gr (add (index-of expr1) (const 2)))
+ (reg h-gr (add (index-of expr2) (const 2))))
+ (set (reg h-gr (add (index-of expr1) (const 3)))
+ (reg h-gr (add (index-of expr2) (const 3))))))
+(define-pmacro (movqlit-expr expr1 expr2)
+ (sequence ((SI dregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set expr1 expr2)
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (const 0))
+ (set (reg h-gr (add (index-of expr1) (const 2)))
+ (const 0))
+ (set (reg h-gr (add (index-of expr1) (const 3)))
+ (const 0))))
+
+(define-pmacro (move-op mnemonic opcode-op opcode2-op sem-op semlit-op)
+ (begin
+ (dni mnemonic
+ (.str mnemonic " reg")
+ ()
+ (.str mnemonic " $src1, $dst")
+ (+ opcode-op dst lit2 M3_0 M2_1 M1_0 opcode2-op ZERO_0 src1)
+ (sem-op dst src1)
+ ()
+ )
+ (dni (.sym mnemonic "1")
+ (.str mnemonic " lit")
+ ()
+ (.str mnemonic " $lit1, $dst")
+ (+ opcode-op dst lit2 M3_0 M2_1 M1_1 opcode2-op ZERO_0 lit1)
+ (semlit-op dst lit1)
+ ()
+ )
+ )
+)
+
+(move-op mov OPCODE_5C OPCODE2_C mov-expr mov-expr)
+(move-op movl OPCODE_5D OPCODE2_C movl-expr movllit-expr)
+(move-op movt OPCODE_5E OPCODE2_C movt-expr movtlit-expr)
+(move-op movq OPCODE_5F OPCODE2_C movq-expr movqlit-expr)
+
+; ??? This is very incomplete. This does not handle src1 or src2 as literals.
+; This doesn't implement any of the effects of the instruction.
+(dni modpc "modpc"
+ ()
+ "modpc $src1, $src2, $dst"
+ (+ OPCODE_65 dst src1 M3_0 M2_0 M1_0 OPCODE2_5 ZERO_0 src2)
+ (set dst src2)
+ ()
+)
+
+; ??? This is very incomplete. This does not handle src1 or src2 as literals.
+; This doesn't implement any of the effects of the instruction.
+(dni modac "modac"
+ ()
+ "modac $src1, $src2, $dst"
+ (+ OPCODE_64 dst src1 M3_0 M2_0 M1_0 OPCODE2_5 ZERO_0 src2)
+ (set dst src2)
+ ()
+)
+
+; ??? Incomplete. Only handles 8 of the 10 addressing modes.
+; Does not handle sign/zero extend operations. Does not handle
+; different modes.
+
+; ??? should verify multi-word reg alignment.
+
+; ??? index-index scale disasssembles wrong
+
+; ??? See also the store-op macro below.
+
+(define-pmacro (lda-expr expr1 expr2)
+ (set expr1 expr2))
+
+(define-pmacro (ld-expr expr1 expr2)
+ (set expr1 (mem WI expr2)))
+(define-pmacro (ldob-expr expr1 expr2)
+ (set expr1 (mem UQI expr2)))
+(define-pmacro (ldos-expr expr1 expr2)
+ (set expr1 (mem UHI expr2)))
+(define-pmacro (ldib-expr expr1 expr2)
+ (set expr1 (mem QI expr2)))
+(define-pmacro (ldis-expr expr1 expr2)
+ (set expr1 (mem HI expr2)))
+(define-pmacro (ldl-expr expr1 expr2)
+ (sequence ((WI temp) (SI dregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set temp expr2)
+ (set expr1 (mem WI temp))
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (mem WI (add temp (const 4))))))
+(define-pmacro (ldt-expr expr1 expr2)
+ (sequence ((WI temp) (SI dregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ (set temp expr2)
+ (set expr1 (mem WI temp))
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (mem WI (add temp (const 4))))
+ (set (reg h-gr (add (index-of expr1) (const 2)))
+ (mem WI (add temp (const 8))))))
+(define-pmacro (ldq-expr expr1 expr2)
+ (sequence ((WI temp) (SI dregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set dregno (ifield f-srcdst))
+ ; Evaluate the address first, for correctness, in case an address
+ ; reg will be loaded into. Also, makes the simulator faster.
+ (set temp expr2)
+ (set expr1 (mem WI temp))
+ (set (reg h-gr (add (index-of expr1) (const 1)))
+ (mem WI (add temp (const 4))))
+ (set (reg h-gr (add (index-of expr1) (const 2)))
+ (mem WI (add temp (const 8))))
+ (set (reg h-gr (add (index-of expr1) (const 3)))
+ (mem WI (add temp (const 12))))))
+
+(define-pmacro (load-op suffix opcode-op sem-op)
+ (begin
+ (dni (.sym ld suffix -offset) (.str "ld" suffix "-offset")
+ ()
+ (.str "ld" suffix " $offset, $dst")
+ (+ opcode-op dst abase MODEA_OFFSET ZEROA_0 offset)
+ (sem-op dst offset)
+ ()
+ )
+ (dni (.sym ld suffix -indirect-offset)
+ (.str "ld" suffix "-indirect-offset")
+ ()
+ (.str "ld" suffix " $offset($abase), $dst")
+ (+ opcode-op dst abase MODEA_INDIRECT-OFFSET ZEROA_0 offset)
+ (sem-op dst (add offset abase))
+ ()
+ )
+ (dni (.sym ld suffix -indirect) (.str "ld" suffix "-indirect")
+ ()
+ (.str "ld" suffix " ($abase), $dst")
+ (+ opcode-op dst abase MODEB_INDIRECT scale ZEROB_0 index)
+ (sem-op dst abase)
+ ()
+ )
+ (dni (.sym ld suffix -indirect-index) (.str "ld" suffix "-indirect-index")
+ ()
+ (.str "ld" suffix " ($abase)[$index*S$scale], $dst")
+ (+ opcode-op dst abase MODEB_INDIRECT-INDEX scale ZEROB_0 index)
+ (sem-op dst (add abase (mul index (sll (const 1) scale))))
+ ()
+ )
+ (dni (.sym ld suffix -disp) (.str "ld" suffix "-disp")
+ ()
+ (.str "ld" suffix " $optdisp, $dst")
+ (+ opcode-op dst abase MODEB_DISP scale ZEROB_0 index optdisp)
+ (sem-op dst optdisp)
+ ()
+ )
+ (dni (.sym ld suffix -indirect-disp) (.str "ld" suffix "-indirect-disp")
+ ()
+ (.str "ld" suffix " $optdisp($abase), $dst")
+ (+ opcode-op dst abase MODEB_INDIRECT-DISP scale ZEROB_0 index optdisp)
+ (sem-op dst (add optdisp abase))
+ ()
+ )
+ (dni (.sym ld suffix -index-disp) (.str "ld" suffix "-index-disp")
+ ()
+ (.str "ld" suffix " $optdisp[$index*S$scale], $dst")
+ (+ opcode-op dst abase MODEB_INDEX-DISP scale ZEROB_0 index optdisp)
+ (sem-op dst (add optdisp (mul index (sll (const 1) scale))))
+ ()
+ )
+ (dni (.sym ld suffix -indirect-index-disp)
+ (.str "ld" suffix "-indirect-index-disp")
+ ()
+ (.str "ld" suffix " $optdisp($abase)[$index*S$scale], $dst")
+ (+ opcode-op dst abase MODEB_INDIRECT-INDEX-DISP scale ZEROB_0 index optdisp)
+ (sem-op dst (add optdisp (add abase
+ (mul index (sll (const 1) scale)))))
+ ()
+ )
+ )
+)
+
+(load-op "a" OPCODE_8C lda-expr)
+
+(load-op "" OPCODE_90 ld-expr)
+(load-op "ob" OPCODE_80 ldob-expr)
+(load-op "os" OPCODE_88 ldos-expr)
+(load-op "ib" OPCODE_C0 ldib-expr)
+(load-op "is" OPCODE_C8 ldis-expr)
+(load-op "l" OPCODE_98 ldl-expr)
+(load-op "t" OPCODE_A0 ldt-expr)
+(load-op "q" OPCODE_B0 ldq-expr)
+
+; ??? Incomplete. This is a near duplicate of the above load-op macro.
+
+; ??? For efficiency, should eval the address only once. See the load patterns
+; above.
+
+(define-pmacro (st-expr expr1 expr2)
+ (set (mem WI expr1) expr2))
+(define-pmacro (stob-expr expr1 expr2)
+ (set (mem QI expr1) expr2))
+(define-pmacro (stos-expr expr1 expr2)
+ (set (mem HI expr1) expr2))
+(define-pmacro (stl-expr expr1 expr2)
+ (sequence ((SI sregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set sregno (ifield f-srcdst))
+ (set (mem WI expr1) expr2)
+ (set (mem WI (add expr1 (const 4)))
+ (reg h-gr (add (index-of expr2) (const 1))))))
+(define-pmacro (stt-expr expr1 expr2)
+ (sequence ((SI sregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set sregno (ifield f-srcdst))
+ (set (mem WI expr1) expr2)
+ (set (mem WI (add expr1 (const 4)))
+ (reg h-gr (add (index-of expr2) (const 1))))
+ (set (mem WI (add expr1 (const 8)))
+ (reg h-gr (add (index-of expr2) (const 2))))))
+(define-pmacro (stq-expr expr1 expr2)
+ (sequence ((SI sregno))
+ ; ??? Workaround cgen s-i-o-o bug.
+ (set sregno (ifield f-srcdst))
+ (set (mem WI expr1) expr2)
+ (set (mem WI (add expr1 (const 4)))
+ (reg h-gr (add (index-of expr2) (const 1))))
+ (set (mem WI (add expr1 (const 8)))
+ (reg h-gr (add (index-of expr2) (const 2))))
+ (set (mem WI (add expr1 (const 12)))
+ (reg h-gr (add (index-of expr2) (const 3))))))
+
+(define-pmacro (store-op suffix opcode-op sem-op)
+ (begin
+ (dni (.sym st suffix -offset) (.str "st" suffix "-offset")
+ ()
+ (.str "st" suffix " $st_src, $offset")
+ (+ opcode-op st_src abase MODEA_OFFSET ZEROA_0 offset)
+ (sem-op offset st_src)
+ ()
+ )
+ (dni (.sym st suffix -indirect-offset)
+ (.str "st" suffix "-indirect-offset")
+ ()
+ (.str "st" suffix " $st_src, $offset($abase)")
+ (+ opcode-op st_src abase MODEA_INDIRECT-OFFSET ZEROA_0 offset)
+ (sem-op (add offset abase) st_src)
+ ()
+ )
+ (dni (.sym st suffix -indirect) (.str "st" suffix "-indirect")
+ ()
+ (.str "st" suffix " $st_src, ($abase)")
+ (+ opcode-op st_src abase MODEB_INDIRECT scale ZEROB_0 index)
+ (sem-op abase st_src)
+ ()
+ )
+ (dni (.sym st suffix -indirect-index) (.str "st" suffix "-indirect-index")
+ ()
+ (.str "st" suffix " $st_src, ($abase)[$index*S$scale]")
+ (+ opcode-op st_src abase MODEB_INDIRECT-INDEX scale ZEROB_0 index)
+ (sem-op (add abase (mul index (sll (const 1) scale))) st_src)
+ ()
+ )
+ (dni (.sym st suffix -disp) (.str "st" suffix "-disp")
+ ()
+ (.str "st" suffix " $st_src, $optdisp")
+ (+ opcode-op st_src abase MODEB_DISP scale ZEROB_0 index optdisp)
+ (sem-op optdisp st_src)
+ ()
+ )
+ (dni (.sym st suffix -indirect-disp) (.str "st" suffix "-indirect-disp")
+ ()
+ (.str "st" suffix " $st_src, $optdisp($abase)")
+ (+ opcode-op st_src abase MODEB_INDIRECT-DISP scale ZEROB_0 index optdisp)
+ (sem-op (add optdisp abase) st_src)
+ ()
+ )
+ (dni (.sym st suffix -index-disp) (.str "st" suffix "-index-disp")
+ ()
+ (.str "st" suffix " $st_src, $optdisp[$index*S$scale")
+ (+ opcode-op st_src abase MODEB_INDEX-DISP scale ZEROB_0 index optdisp)
+ (sem-op (add optdisp (mul index (sll (const 1) scale))) st_src)
+ ()
+ )
+ (dni (.sym st suffix -indirect-index-disp)
+ (.str "st" suffix "-indirect-index-disp")
+ ()
+ (.str "st" suffix " $st_src, $optdisp($abase)[$index*S$scale]")
+ (+ opcode-op st_src abase MODEB_INDIRECT-INDEX-DISP scale ZEROB_0 index optdisp)
+ (sem-op (add optdisp (add abase (mul index (sll (const 1) scale))))
+ st_src)
+ ()
+ )
+ )
+)
+
+(store-op "" OPCODE_92 st-expr)
+(store-op "ob" OPCODE_82 stob-expr)
+(store-op "os" OPCODE_8A stos-expr)
+(store-op "l" OPCODE_9A stl-expr)
+(store-op "t" OPCODE_A2 stt-expr)
+(store-op "q" OPCODE_B2 stq-expr)
+
+; ??? Incomplete, does not set condition code register.
+
+; ??? Without these functions, I end up with a call to the undefined
+; function EQUSI, because br_lit1 is an unsigned field. Should be a better
+; way to solve this.
+
+(define-pmacro (eq-expr expr1 expr2) (eq WI expr1 expr2))
+(define-pmacro (ne-expr expr1 expr2) (ne WI expr1 expr2))
+(define-pmacro (ltu-expr expr1 expr2) (ltu UWI expr1 expr2))
+(define-pmacro (leu-expr expr1 expr2) (leu UWI expr1 expr2))
+(define-pmacro (gtu-expr expr1 expr2) (gtu UWI expr1 expr2))
+(define-pmacro (geu-expr expr1 expr2) (geu UWI expr1 expr2))
+(define-pmacro (lt-expr expr1 expr2) (lt WI expr1 expr2))
+(define-pmacro (le-expr expr1 expr2) (le WI expr1 expr2))
+(define-pmacro (gt-expr expr1 expr2) (gt WI expr1 expr2))
+(define-pmacro (ge-expr expr1 expr2) (ge WI expr1 expr2))
+
+; ??? Does not handle shifts greater than 32 correctly.
+
+(define-pmacro (bbc-expr expr1 expr2)
+ (eq WI (and (sll (const 1) expr1) expr2) (const 0)))
+(define-pmacro (bbs-expr expr1 expr2)
+ (ne WI (and (sll (const 1) expr1) expr2) (const 0)))
+
+(define-pmacro (cmp-op mnemonic opcode-op sem-op)
+ (begin
+ (dni (.sym mnemonic -reg)
+ (.str mnemonic " reg")
+ ()
+ (.str mnemonic " $br_src1, $br_src2, $br_disp")
+ (+ opcode-op br_src1 br_src2 BR_M1_0 br_disp BR_ZERO_0)
+ (if (sem-op br_src1 br_src2) (set pc br_disp))
+ ()
+ )
+ (dni (.sym mnemonic -lit)
+ (.str mnemonic " lit")
+ ()
+ (.str mnemonic " $br_lit1, $br_src2, $br_disp")
+ (+ opcode-op br_lit1 br_src2 BR_M1_1 br_disp BR_ZERO_0)
+ (if (sem-op br_lit1 br_src2) (set pc br_disp))
+ ()
+ )
+ )
+)
+
+(cmp-op "cmpobe" OPCODE_32 eq-expr)
+(cmp-op "cmpobne" OPCODE_35 ne-expr)
+(cmp-op "cmpobl" OPCODE_34 ltu-expr)
+(cmp-op "cmpoble" OPCODE_36 leu-expr)
+(cmp-op "cmpobg" OPCODE_31 gtu-expr)
+(cmp-op "cmpobge" OPCODE_33 geu-expr)
+
+(cmp-op "cmpibe" OPCODE_3A eq-expr)
+(cmp-op "cmpibne" OPCODE_3D ne-expr)
+(cmp-op "cmpibl" OPCODE_3C lt-expr)
+(cmp-op "cmpible" OPCODE_3E le-expr)
+(cmp-op "cmpibg" OPCODE_39 gt-expr)
+(cmp-op "cmpibge" OPCODE_3B ge-expr)
+
+(cmp-op "bbc" OPCODE_30 bbc-expr)
+(cmp-op "bbs" OPCODE_37 bbs-expr)
+
+; ??? This is a near copy of alu-op, but without the dst field.
+; ??? Should create fake operands instead of using h-cc.
+; ??? M3 can be either 0 or 1. We only handle a value of 1 here.
+
+; ??? The else clause if not optional.
+
+(define-pmacro (cmpi-expr expr1 expr2)
+ (cond WI
+ ((lt WI expr1 expr2) (const 4))
+ ((eq WI expr1 expr2) (const 2))
+ ; gt: WI
+ (else (const 1))))
+(define-pmacro (cmpo-expr expr1 expr2)
+ (cond WI
+ ((ltu UWI expr1 expr2) (const 4))
+ ((eq WI expr1 expr2) (const 2))
+ ; gtu: UWI
+ (else (const 1))))
+
+(define-pmacro (cc-op mnemonic opcode-op opcode2-op sem-op)
+ (begin
+ (dni mnemonic
+ (.str mnemonic " reg/reg")
+ ()
+ (.str mnemonic " $src1, $src2")
+ (+ opcode-op dst src2 M3_1 M2_0 M1_0 opcode2-op ZERO_0 src1)
+ (set (reg h-cc 0) (sem-op src1 src2))
+ ()
+ )
+ (dni (.sym mnemonic "1")
+ (.str mnemonic " lit/reg")
+ ()
+ (.str mnemonic " $lit1, $src2")
+ (+ opcode-op dst src2 M3_1 M2_0 M1_1 opcode2-op ZERO_0 lit1)
+ (set (reg h-cc 0) (sem-op lit1 src2))
+ ()
+ )
+ (dni (.sym mnemonic "2")
+ (.str mnemonic " reg/lit")
+ ()
+ (.str mnemonic " $src1, $lit2")
+ (+ opcode-op dst lit2 M3_1 M2_1 M1_0 opcode2-op ZERO_0 src1)
+ (set (reg h-cc 0) (sem-op src1 lit2))
+ ()
+ )
+ (dni (.sym mnemonic "3")
+ (.str mnemonic " lit/lit")
+ ()
+ (.str mnemonic " $lit1, $lit2")
+ (+ opcode-op dst lit2 M3_1 M2_1 M1_1 opcode2-op ZERO_0 lit1)
+ (set (reg h-cc 0) (sem-op lit1 lit2))
+ ()
+ )
+ )
+)
+
+(cc-op "cmpi" OPCODE_5A OPCODE2_1 cmpi-expr)
+(cc-op "cmpo" OPCODE_5A OPCODE2_0 cmpo-expr)
+
+; ??? The M1 field should be ignored.
+
+(define-pmacro (testno-expr)
+ (eq WI (reg h-cc 0) (const 0)))
+(define-pmacro (testg-expr)
+ (ne WI (and (reg h-cc 0) (const 1)) (const 0)))
+(define-pmacro (teste-expr)
+ (ne WI (and (reg h-cc 0) (const 2)) (const 0)))
+(define-pmacro (testge-expr)
+ (ne WI (and (reg h-cc 0) (const 3)) (const 0)))
+(define-pmacro (testl-expr)
+ (ne WI (and (reg h-cc 0) (const 4)) (const 0)))
+(define-pmacro (testne-expr)
+ (ne WI (and (reg h-cc 0) (const 5)) (const 0)))
+(define-pmacro (testle-expr)
+ (ne WI (and (reg h-cc 0) (const 6)) (const 0)))
+(define-pmacro (testo-expr)
+ (ne WI (and (reg h-cc 0) (const 7)) (const 0)))
+
+
+(define-pmacro (test-op mnemonic opcode-op sem-op)
+ (dni (.sym mnemonic -reg)
+ (.str mnemonic " reg")
+ ()
+ (.str mnemonic " $br_src1")
+ (+ opcode-op br_src1 br_src2 BR_M1_0 br_disp BR_ZERO_0)
+ (set br_src1 (sem-op))
+ ()
+ )
+)
+
+(test-op "testno" OPCODE_20 testno-expr)
+(test-op "testg" OPCODE_21 testg-expr)
+(test-op "teste" OPCODE_22 teste-expr)
+(test-op "testge" OPCODE_23 testge-expr)
+(test-op "testl" OPCODE_24 testl-expr)
+(test-op "testne" OPCODE_25 testne-expr)
+(test-op "testle" OPCODE_26 testle-expr)
+(test-op "testo" OPCODE_27 testo-expr)
+
+(define-pmacro (branch-op mnemonic opcode-op sem-op)
+ (dni (.sym mnemonic) (.str mnemonic)
+ ()
+ (.str mnemonic " $ctrl_disp")
+ (+ opcode-op ctrl_disp CTRL_ZERO_0)
+ (if (sem-op) (set pc ctrl_disp))
+ ()
+ )
+)
+
+(branch-op "bno" OPCODE_10 testno-expr)
+(branch-op "bg" OPCODE_11 testg-expr)
+(branch-op "be" OPCODE_12 teste-expr)
+(branch-op "bge" OPCODE_13 testge-expr)
+(branch-op "bl" OPCODE_14 testl-expr)
+(branch-op "bne" OPCODE_15 testne-expr)
+(branch-op "ble" OPCODE_16 testle-expr)
+(branch-op "bo" OPCODE_17 testo-expr)
+
+(dni b "b"
+ ()
+ "b $ctrl_disp"
+ (+ OPCODE_08 ctrl_disp CTRL_ZERO_0)
+ (set pc ctrl_disp)
+ ()
+)
+
+; ??? Incomplete. Only handles 5 of 10 addressing modes.
+; Should be a macro.
+
+(dni bx-indirect-offset "bx-indirect-offset"
+ ()
+ "bx $offset($abase)"
+ (+ OPCODE_84 dst abase MODEA_INDIRECT-OFFSET ZEROA_0 offset)
+ (set pc (add offset abase))
+ ()
+)
+
+(dni bx-indirect "bx-indirect"
+ ()
+ "bx ($abase)"
+ (+ OPCODE_84 dst abase MODEB_INDIRECT scale ZEROB_0 index)
+ (set pc abase)
+ ()
+)
+
+(dni bx-indirect-index "bx-indirect-index"
+ ()
+ "bx ($abase)[$index*S$scale]"
+ (+ OPCODE_84 dst abase MODEB_INDIRECT-INDEX scale ZEROB_0 index)
+ (set pc (add abase (mul index (sll (const 1) scale))))
+ ()
+)
+
+(dni bx-disp "bx-disp"
+ ()
+ "bx $optdisp"
+ (+ OPCODE_84 dst abase MODEB_DISP scale ZEROB_0 index optdisp)
+ (set pc optdisp)
+ ()
+)
+
+(dni bx-indirect-disp "bx-indirect-disp"
+ ()
+ "bx $optdisp($abase)"
+ (+ OPCODE_84 dst abase MODEB_INDIRECT-DISP scale ZEROB_0 index optdisp)
+ (set pc (add optdisp abase))
+ ()
+)
+
+; ??? Incomplete. Only handles 3 of 10 addressing modes. Only handles
+; one local register set.
+
+; ??? If we don't want all of the set-quiet calls, then we need to increase
+; SIZE_TRACE_BUF in sim/common/cgen-trace.c.
+
+(dni callx-disp "callx-disp"
+ ()
+ "callx $optdisp"
+ (+ OPCODE_86 dst abase MODEB_DISP scale ZEROB_0 index optdisp)
+ (sequence ((WI temp))
+ (set temp (and (add (reg h-gr 1) (const 63)) (inv (const 63))))
+ ; ??? This doesn't seem right. Why do I have to add 8?.
+ (set (reg h-gr 2) (add pc (const 8)))
+ ; Save current local reg set on stack.
+ (set-quiet (mem WI (add (reg h-gr 31) (const 0)))
+ (reg h-gr 0))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 4)))
+ (reg h-gr 1))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 8)))
+ (reg h-gr 2))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 12)))
+ (reg h-gr 3))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 16)))
+ (reg h-gr 4))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 20)))
+ (reg h-gr 5))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 24)))
+ (reg h-gr 6))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 28)))
+ (reg h-gr 7))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 32)))
+ (reg h-gr 8))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 36)))
+ (reg h-gr 9))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 40)))
+ (reg h-gr 10))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 44)))
+ (reg h-gr 11))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 48)))
+ (reg h-gr 12))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 52)))
+ (reg h-gr 13))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 56)))
+ (reg h-gr 14))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 60)))
+ (reg h-gr 15))
+ (set pc optdisp)
+ ; Allocate new local reg set.
+ (set-quiet (reg h-gr 0) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 1) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 2) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 3) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 4) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 5) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 6) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 7) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 8) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 9) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 10) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 11) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 12) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 13) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 14) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 15) (const #xDEADBEEF))
+ (set (reg h-gr 0) (reg h-gr 31))
+ (set (reg h-gr 31) temp)
+ (set (reg h-gr 1) (add temp (const 64))))
+ ()
+)
+
+; ??? This should be macro-ized somehow.
+
+; ??? This adds 4 to pc. The above pattern adds 8.
+
+(dni callx-indirect "callx-indirect"
+ ()
+ "callx ($abase)"
+ (+ OPCODE_86 dst abase MODEB_INDIRECT scale ZEROB_0 index)
+ (sequence ((WI temp))
+ (set temp (and (add (reg h-gr 1) (const 63)) (inv (const 63))))
+ ; ??? This doesn't seem right. Why do I have to add 4?.
+ (set (reg h-gr 2) (add pc (const 4)))
+ ; Save current local reg set on stack.
+ (set-quiet (mem WI (add (reg h-gr 31) (const 0)))
+ (reg h-gr 0))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 4)))
+ (reg h-gr 1))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 8)))
+ (reg h-gr 2))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 12)))
+ (reg h-gr 3))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 16)))
+ (reg h-gr 4))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 20)))
+ (reg h-gr 5))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 24)))
+ (reg h-gr 6))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 28)))
+ (reg h-gr 7))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 32)))
+ (reg h-gr 8))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 36)))
+ (reg h-gr 9))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 40)))
+ (reg h-gr 10))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 44)))
+ (reg h-gr 11))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 48)))
+ (reg h-gr 12))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 52)))
+ (reg h-gr 13))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 56)))
+ (reg h-gr 14))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 60)))
+ (reg h-gr 15))
+ ; We do this first, because abase might be a local reg.
+ (set pc abase)
+ ; Allocate new local reg set.
+ (set-quiet (reg h-gr 0) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 1) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 2) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 3) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 4) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 5) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 6) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 7) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 8) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 9) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 10) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 11) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 12) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 13) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 14) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 15) (const #xDEADBEEF))
+ (set (reg h-gr 0) (reg h-gr 31))
+ (set (reg h-gr 31) temp)
+ (set (reg h-gr 1) (add temp (const 64))))
+ ()
+)
+
+; ??? This adds 4 to pc.
+
+; ??? This should be macro-ized somehow.
+
+(dni callx-indirect-offset "callx-indirect-offset"
+ ()
+ "callx $offset($abase)"
+ (+ OPCODE_86 dst abase MODEA_INDIRECT-OFFSET ZEROA_0 offset)
+ (sequence ((WI temp))
+ (set temp (and (add (reg h-gr 1) (const 63)) (inv (const 63))))
+ ; ??? This doesn't seem right. Why do I have to add 4?.
+ (set (reg h-gr 2) (add pc (const 4)))
+ ; Save current local reg set on stack.
+ (set-quiet (mem WI (add (reg h-gr 31) (const 0)))
+ (reg h-gr 0))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 4)))
+ (reg h-gr 1))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 8)))
+ (reg h-gr 2))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 12)))
+ (reg h-gr 3))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 16)))
+ (reg h-gr 4))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 20)))
+ (reg h-gr 5))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 24)))
+ (reg h-gr 6))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 28)))
+ (reg h-gr 7))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 32)))
+ (reg h-gr 8))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 36)))
+ (reg h-gr 9))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 40)))
+ (reg h-gr 10))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 44)))
+ (reg h-gr 11))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 48)))
+ (reg h-gr 12))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 52)))
+ (reg h-gr 13))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 56)))
+ (reg h-gr 14))
+ (set-quiet (mem WI (add (reg h-gr 31) (const 60)))
+ (reg h-gr 15))
+ ; We do this first, because abase might be a local reg.
+ (set pc (add offset abase))
+ ; Allocate new local reg set.
+ (set-quiet (reg h-gr 0) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 1) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 2) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 3) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 4) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 5) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 6) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 7) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 8) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 9) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 10) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 11) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 12) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 13) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 14) (const #xDEADBEEF))
+ (set-quiet (reg h-gr 15) (const #xDEADBEEF))
+ (set (reg h-gr 0) (reg h-gr 31))
+ (set (reg h-gr 31) temp)
+ (set (reg h-gr 1) (add temp (const 64))))
+ ()
+)
+
+; ??? Incomplete. Does not handle return status in PFP.
+
+(dni ret "ret"
+ ()
+ "ret"
+ (+ OPCODE_0A ctrl_disp CTRL_ZERO_0)
+ (sequence ()
+ (set (reg h-gr 31) (reg h-gr 0))
+ (set-quiet (reg h-gr 0)
+ (mem WI (add (reg h-gr 31) (const 0))))
+ (set-quiet (reg h-gr 1)
+ (mem WI (add (reg h-gr 31) (const 4))))
+ (set-quiet (reg h-gr 2)
+ (mem WI (add (reg h-gr 31) (const 8))))
+ (set-quiet (reg h-gr 3)
+ (mem WI (add (reg h-gr 31) (const 12))))
+ (set-quiet (reg h-gr 4)
+ (mem WI (add (reg h-gr 31) (const 16))))
+ (set-quiet (reg h-gr 5)
+ (mem WI (add (reg h-gr 31) (const 20))))
+ (set-quiet (reg h-gr 6)
+ (mem WI (add (reg h-gr 31) (const 24))))
+ (set-quiet (reg h-gr 7)
+ (mem WI (add (reg h-gr 31) (const 28))))
+ (set-quiet (reg h-gr 8)
+ (mem WI (add (reg h-gr 31) (const 32))))
+ (set-quiet (reg h-gr 9)
+ (mem WI (add (reg h-gr 31) (const 36))))
+ (set-quiet (reg h-gr 10)
+ (mem WI (add (reg h-gr 31) (const 40))))
+ (set-quiet (reg h-gr 11)
+ (mem WI (add (reg h-gr 31) (const 44))))
+ (set-quiet (reg h-gr 12)
+ (mem WI (add (reg h-gr 31) (const 48))))
+ (set-quiet (reg h-gr 13)
+ (mem WI (add (reg h-gr 31) (const 52))))
+ (set-quiet (reg h-gr 14)
+ (mem WI (add (reg h-gr 31) (const 56))))
+ (set-quiet (reg h-gr 15)
+ (mem WI (add (reg h-gr 31) (const 60))))
+ (set pc (reg h-gr 2)))
+ ()
+)
+
+; ??? Incomplete, does not do any system operations.
+
+; ??? Should accept either reg or lit for src1.
+
+; ??? M3/M2 should not matter.
+
+(dni calls "calls"
+ ()
+ "calls $src1"
+ (+ OPCODE_66 dst src2 M3_1 M2_1 M1_0 OPCODE2_0 ZERO_0 src1)
+ (set WI pc (c-call WI "i960_trap" pc src1))
+ ()
+)
+
+; ??? Incomplete, does not do any system operations.
+
+; ??? M3/M2/M1 should not matter.
+
+(dni fmark "fmark"
+ ()
+ "fmark"
+ (+ OPCODE_66 dst src2 M3_1 M2_1 M1_1 OPCODE2_C ZERO_0 src1)
+ (set WI pc (c-call WI "i960_breakpoint" pc))
+ ()
+)
+
+; ??? Incomplete. This doesn't actually have to do anything, because we
+; currently support only one set of local registers.
+
+; ??? The settings of the M1/2/3 bits shouldn't matter.
+
+(dni flushreg "flushreg"
+ ()
+ "flushreg"
+ (+ OPCODE_66 dst src2 M3_1 M2_1 M1_1 OPCODE2_D ZERO_0 src1)
+ (nop)
+ ()
+)
diff --git a/cgen/i960.opc b/cgen/i960.opc
new file mode 100644
index 00000000000..acfc53dd4b6
--- /dev/null
+++ b/cgen/i960.opc
@@ -0,0 +1,32 @@
+/* Intel 80960 opcode support. -*- C -*-
+ Copyright (C) 2000 Red Hat, Inc.
+ This file is part of CGEN. */
+
+/* This file is an addendum to i960.cpu. Heavy use of C code isn't
+ appropriate in .cpu files, so it resides here. This especially applies
+ to assembly/disassembly where parsing/printing can be quite involved.
+ Such things aren't really part of the specification of the cpu, per se,
+ so .cpu files provide the general framework and .opc files handle the
+ nitty-gritty details as necessary.
+
+ Each section is delimited with start and end markers.
+
+ <arch>-opc.h additions use: "-- opc.h"
+ <arch>-opc.c additions use: "-- opc.c"
+ <arch>-asm.c additions use: "-- asm.c"
+ <arch>-dis.c additions use: "-- dis.c"
+ <arch>-ibd.h additions use: "-- ibd.h"
+*/
+
+/* -- opc.h */
+
+#undef CGEN_DIS_HASH_SIZE
+#define CGEN_DIS_HASH_SIZE 256
+#undef CGEN_DIS_HASH
+#define CGEN_DIS_HASH(buffer, value) ((unsigned char *) (buffer))[3]
+
+/* ??? Until cgen disassembler complete and functioning well, redirect back
+ to old disassembler. */
+#define CGEN_PRINT_INSN(od, pc, info) print_insn_i960_orig (pc, info)
+
+/* -- */
diff --git a/cgen/ia32.cpu b/cgen/ia32.cpu
new file mode 100644
index 00000000000..4f8e84164cb
--- /dev/null
+++ b/cgen/ia32.cpu
@@ -0,0 +1,917 @@
+; Intel IA32 CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+;
+; References:
+;
+; Intel486 Processor Family, Programmer's Reference Manual, Intel
+
+(include "simplify.inc")
+
+; define-arch must appear first
+
+(define-arch
+ (name ia32) ; name of cpu family
+ (comment "Intel IA32 (x86)")
+ (default-alignment unaligned)
+ (insn-lsb0? #t)
+ (machs i386 i486 pentium pentium-ii pentium-iii) ; ??? wip
+ (isas ia32) ; ??? separate 8086 isa?
+)
+
+; Attributes.
+
+; Instruction set parameters.
+
+(define-isa
+ (name ia32)
+
+ (default-insn-bitsize 8)
+
+ ; Number of bytes of insn we can initially fetch.
+ (base-insn-bitsize 8)
+
+ ; Used in computing bit numbers.
+ (default-insn-word-bitsize 32)
+
+ ; Initial bitnumbers to decode insns by.
+ (decode-assist (0 1 2 3 4 5 6 7))
+)
+
+; Cpu family definitions.
+
+(define-cpu
+ ; cpu names must be distinct from the architecture name and machine names.
+ ; The "b" suffix stands for "base" and is the convention.
+ ; The "f" suffix stands for "family" and is the convention.
+ (name ia32bf)
+ (comment "Intel x86 base family")
+ (endian little)
+ (word-bitsize 32)
+)
+
+(define-mach
+ (name pentium-ii)
+ (comment "Pentium II")
+ (cpu ia32bf)
+)
+
+; Model descriptions.
+
+; The meaning of this value is wip but at the moment it's intended to describe
+; the implementation (i.e. what -mtune=foo does in sparc gcc).
+; ??? This is intended to be redesigned later.
+
+(define-model
+ (name pentium-ii)
+ (comment "Pentium II model")
+ (mach pentium-ii)
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () ; state
+ () ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+)
+
+; Instruction fields.
+
+; There currently doesn't exist shorthand macros for CISC ISA's,
+; so define our own.
+; DIF: define-ia32-field
+; DNIF: define-normal-ia32-field
+
+(define-pmacro (dif x-name x-comment x-attrs x-word-offset x-word-length x-start x-length x-mode x-encode x-decode)
+ (define-ifield
+ (name x-name)
+ (comment x-comment)
+ (.splice attrs (.unsplice x-attrs))
+ (word-offset x-word-offset)
+ (word-length x-word-length)
+ (start x-start)
+ (length x-length)
+ (mode x-mode)
+ (encode x-encode)
+ (decode x-decode)
+ )
+)
+
+(define-pmacro (dnif x-name x-comment x-attrs x-word-offset x-word-length x-start x-length)
+ (dif x-name x-comment x-attrs x-word-offset x-word-length x-start x-length
+ UINT #f #f)
+)
+
+(dnif f-opcode "first insn byte" () 0 8 7 8)
+
+; The mod-r/m byte.
+(dnif f-mod "mod field of mod-r/m byte" () 8 8 7 2)
+(dnif f-reg/opcode "reg/opcode field of mod-r/m byte" () 8 8 5 3)
+(dnif f-r/m "r/m field of mod-r/m byte" () 8 8 2 3)
+(dsmf f-mod-r/m "entire mod-r/m byte" () (f-mod f-reg/opcode f-r/m))
+
+(dnif f-simm8 "signed 8 bit immediate" () 8 8 7 8)
+(dnif f-simm16 "signed 16 bit immediate" () 8 16 15 16)
+(dnif f-simm32 "signed 32 bit immediate" () 8 32 31 32)
+
+(dnif f-disp8 "signed 8 bit displacement" () 8 8 7 8)
+(dnif f-disp16 "signed 16 bit displacement" () 8 16 15 16)
+(dnif f-disp32 "signed 32 bit displacement" () 8 32 31 32)
+
+(dnif f-rel8 "signed 8 bit pc-relative displacement" (PCREL-ADDR) 8 8 7 8)
+(dnif f-rel16 "signed 16 bit pc-relative displacement" (PCREL-ADDR) 8 16 15 16)
+(dnif f-rel32 "signed 32 bit pc-relative displacement" (PCREL-ADDR) 8 32 31 32)
+
+; The sib byte.
+(dnif f-sib-ss "sib scale size" () 16 8 7 2)
+(dnif f-sib-base "sib base reg" () 16 8 5 3)
+(dnif f-sib-index "sib index reg" () 16 8 2 3)
+(dsmf f-sib "entire sib byte" () (f-sib-ss f-sib-base f-sib-index))
+
+; Enums.
+
+(define-pmacro (build-hex2 num) (.hex num 2))
+
+; insn-opcode
+; "00" ... "FF"
+(define-normal-insn-enum insn-opcode "insn opcode enums" () OP_ f-opcode
+ (.map .upcase (.map build-hex2 (.iota 256)))
+)
+
+; Hardware pieces.
+; These entries list the elements of the raw hardware.
+; They're also used to provide tables and other elements of the assembly
+; language.
+;
+; ??? Sets of SP have extra-special semantics.
+
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(define-keyword
+ (name gr8-names)
+ (print-name h-gr8)
+ (prefix "%")
+ (values (al 0) (cl 1) (dl 2) (bl 3) (ah 4) (ch 5) (dh 6) (bh 7))
+)
+
+(define-hardware
+ (name h-gr8)
+ (comment "8 bit general registers")
+ (attrs VIRTUAL PROFILE)
+ (type register QI (8))
+ (indices extern-keyword gr8-names)
+ (get (index)
+ (if (lt index 4)
+ (reg QI h-gr index)
+ (bitfield (reg h-gr (sub index 4)) 15 8)))
+ (set (index newval)
+ (if (lt index 4)
+ (set (bitfield (reg h-gr index) 7 8) newval)
+ (set (bitfield (reg h-gr (sub index 4)) 15 8) newval)))
+)
+
+(define-keyword
+ (name gr16-names)
+ (print-name h-gr16)
+ (prefix "%")
+ (values (ax 0) (cx 1) (dx 2) (bx 3) (sp 4) (bp 5) (si 6) (di 7))
+)
+
+(define-hardware
+ (name h-gr16)
+ (comment "16 bit general registers")
+ (attrs VIRTUAL PROFILE)
+ (type register HI (8))
+ (indices extern-keyword gr16-names)
+ (get (index) (reg HI h-gr index))
+ (set (index newval) (set (bitfield (reg h-gr index) 15 16) newval))
+)
+
+(define-keyword
+ (name gr-names)
+ (print-name h-gr)
+ (prefix "%")
+ (values (eax 0) (ecx 1) (edx 2) (ebx 3) (esp 4) (ebp 5) (esi 6) (edi 7))
+)
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs PROFILE CACHE-ADDR)
+ (type register SI (8))
+ (indices extern-keyword gr-names)
+)
+
+(dsh h-cf "carry flag" () (register BI))
+(dsh h-sf "sign flag" () (register BI))
+(dsh h-of "overflow flag" () (register BI))
+(dsh h-zf "zero flag" () (register BI))
+
+; Instruction Operands.
+
+; M32R specific operand attributes:
+; - none yet
+
+; Some registers are refered to explicitly.
+; ??? Might eventually be worth defining them all, but for now we just
+; define the ones we need.
+; ??? Another way to do this is to use pmacros.
+
+(dnop al "%al register" () h-gr8 0)
+(dnop ax "%ax register" () h-gr16 0)
+(dnop eax "%eax register" () h-gr 0)
+
+; Registers specified in the Reg/Opcode field of the r/m byte.
+
+(dnop reg8 "8 bit register" () h-gr8 f-reg/opcode)
+(dnop reg16 "16 bit register" () h-gr16 f-reg/opcode)
+(dnop reg32 "32 bit register" () h-gr f-reg/opcode)
+
+; Various numeric operands.
+
+(dnop simm8 "8 bit signed immediate" () h-sint f-simm8)
+(dnop simm16 "16 bit signed immediate" () h-sint f-simm16)
+(dnop simm32 "32 bit signed immediate" () h-sint f-simm32)
+
+(dnop disp8 "8 bit displacement" () h-sint f-disp8)
+(dnop disp16 "16 bit displacement" () h-sint f-disp16)
+(dnop disp32 "32 bit displacement" () h-sint f-disp32)
+
+(dnop rel8 "8 bit displacement" () h-iaddr f-rel8)
+(dnop rel16 "16 bit displacement" () h-iaddr f-rel16)
+(dnop rel32 "32 bit displacement" () h-iaddr f-rel32)
+
+; The condition code registers.
+
+(dnop cf "carry flag" () h-cf f-nil)
+(dnop sf "sign flag" () h-sf f-nil)
+(dnop of "overflow flag" () h-of f-nil)
+(dnop zf "zero flag" () h-zf f-nil)
+
+; ModRM support.
+
+(dnop r/m-reg8 "8 bit register in r/m field" () h-gr8 f-r/m)
+(dnop r/m-reg16 "16 bit register in r/m field" () h-gr16 f-r/m)
+(dnop r/m-reg32 "32 bit register in r/m field" () h-gr f-r/m)
+
+(define-operand
+ (name mod-r/m-base-reg)
+ (comment "base register for mod-r/m addressing")
+ (mode SI)
+ (type h-gr)
+ (index f-r/m)
+)
+
+(define-operand
+ (name sib-base)
+ (comment "base register for sib addressing")
+ (mode SI)
+ (type h-gr)
+ (index f-sib-base)
+)
+
+(define-operand
+ (name sib-index)
+ (comment "index register for sib addressing")
+ (mode SI)
+ (type h-gr)
+ (index f-sib-index)
+)
+
+; The mod-r/m and sib ifields.
+; These are composed of several ifields and specify a set of choices
+; (addressing modes) to choose from.
+
+(define-pmacro (diff x-name x-comment x-attrs x-start x-length x-follows x-mode)
+ "Define an ia32 ifield that follows another ifield."
+ (define-ifield
+ (name x-name)
+ (comment x-comment)
+ (.splice attrs (.unsplice x-attrs))
+ (start x-start)
+ (length x-length)
+ (follows x-follows)
+ (mode x-mode)
+ )
+)
+
+; These must be defined before they're used and it makes sense to define
+; the operand with the ifield (rather than follow the usual convention of
+; defining all ifields first - not that that convention is necessarily the
+; best).
+
+(dnif f-disp8-@16 "signed 8 bit displacement at offset 16" () 16 8 7 8)
+(dnop disp8-@16 "signed 8 bit displacement at offset 16" () h-sint f-disp8-@16)
+
+(dnif f-disp32-@16 "signed 32 bit displacement at offset 16" () 16 32 31 32)
+(dnop disp32-@16 "signed 32 bit displacement at offset 16" () h-sint f-disp32-@16)
+
+(dnif f-disp32-@24 "signed 32 bit displacement at offset 24" () 24 32 31 32)
+(dnop disp32-@24 "signed 32 bit displacement at offset 24" () h-sint f-disp32-@24)
+
+; The sib operand, used by the mod-r/m operand.
+
+(dndo base+index*1
+ SI
+ (sib-base sib-index)
+ "${sib-base}+${sib-index}"
+ f-sib
+ (+ (f-sib-ss 0) sib-base sib-index)
+ (andif (orif (ne f-mod 0)
+ (ne f-sib-base 5))
+ (ne f-sib-index 4))
+ (add sib-base sib-index)
+ () ; no setter
+)
+
+(dndo base-1
+ SI
+ (sib-base)
+ "${sib-base}"
+ f-sib
+ (+ (f-sib-ss 0) sib-base (f-sib-index 4))
+ (orif (ne f-mod 0)
+ (ne f-sib-base 5))
+ sib-base
+ () ; no setter
+)
+
+(dndo index*1+disp32
+ SI
+ (sib-index disp32)
+ "${disp32-@24}(${sib-index})"
+ f-sib
+ (+ (f-sib-ss 0) (f-sib-base 5) sib-index disp32-@24)
+ (andif (eq f-mod 0)
+ (ne f-sib-index 4))
+ (add sib-index disp32-@24)
+ () ; no setter
+)
+
+(dndo disp32-1
+ SI
+ (disp32)
+ "${disp32-@24}"
+ f-sib
+ (+ (f-sib-ss 0) (f-sib-base 5) (f-sib-index 4) disp32-@24)
+ (eq f-mod 0)
+ disp32-@24
+ () ; no setter
+)
+
+(dndo base+index*2
+ SI
+ (sib-base sib-index)
+ "${sib-base}+${sib-index}*2"
+ f-sib
+ (+ (f-sib-ss 1) sib-base sib-index)
+ (andif (orif (ne f-mod 0)
+ (ne f-sib-base 5))
+ (ne f-sib-index 4))
+ (add sib-base (mul sib-index 2))
+ () ; no setter
+)
+
+(dndo base-2
+ SI
+ (sib-base)
+ "${sib-base}"
+ f-sib
+ (+ (f-sib-ss 1) sib-base (f-sib-index 4))
+ ()
+ sib-base
+ () ; no setter
+)
+
+(dndo index*2+disp32
+ SI
+ (sib-index disp32)
+ "${disp32-@24}(${sib-index})"
+ f-sib
+ (+ (f-sib-ss 1) (f-sib-base 5) sib-index disp32-@24)
+ (andif (eq f-mod 0)
+ (ne f-sib-index 4))
+ (add (mul sib-index 2) disp32-@24)
+ () ; no setter
+)
+
+(dndo disp32-2
+ SI
+ (disp32)
+ "${disp32-@24}"
+ f-sib
+ (+ (f-sib-ss 1) (f-sib-base 5) (f-sib-index 4) disp32-@24)
+ (eq f-mod 0)
+ disp32-@24
+ () ; no setter
+)
+
+(dndo base+index*4
+ SI
+ (sib-base sib-index)
+ "${sib-base}+${sib-index}*4"
+ f-sib
+ (+ (f-sib-ss 2) sib-base sib-index)
+ (andif (orif (ne f-mod 0)
+ (ne f-sib-base 5))
+ (ne f-sib-index 4))
+ (add sib-base (mul sib-index 4))
+ () ; no setter
+)
+
+(dndo base-4
+ SI
+ (sib-base)
+ "${sib-base}"
+ f-sib
+ (+ (f-sib-ss 2) sib-base (f-sib-index 4))
+ ()
+ sib-base
+ () ; no setter
+)
+
+(dndo index*4+disp32
+ SI
+ (sib-index disp32)
+ "${disp32-@24}(${sib-index})"
+ f-sib
+ (+ (f-sib-ss 2) (f-sib-base 5) sib-index disp32-@24)
+ (andif (eq f-mod 0)
+ (ne f-sib-index 4))
+ (add (mul sib-index 4) disp32-@24)
+ () ; no setter
+)
+
+(dndo disp32-4
+ SI
+ (disp32)
+ "${disp32-@24}"
+ f-sib
+ (+ (f-sib-ss 2) (f-sib-base 5) (f-sib-index 4) disp32-@24)
+ (eq f-mod 0)
+ disp32-@24
+ () ; no setter
+)
+
+(dndo base+index*8
+ SI
+ (sib-base sib-index)
+ "${sib-base}+${sib-index}*8"
+ f-sib
+ (+ (f-sib-ss 3) sib-base sib-index)
+ (andif (orif (ne f-mod 0)
+ (ne f-sib-base 5))
+ (ne f-sib-index 4))
+ (add sib-base (mul sib-index 8))
+ () ; no setter
+)
+
+(dndo base-8
+ SI
+ (sib-base)
+ "${sib-base}"
+ f-sib
+ (+ (f-sib-ss 3) sib-base (f-sib-index 4))
+ ()
+ sib-base
+ () ; no setter
+)
+
+(dndo index*8+disp32
+ SI
+ (sib-index disp32)
+ "${disp32-@24}(${sib-index})"
+ f-sib
+ (+ (f-sib-ss 3) (f-sib-base 5) sib-index disp32-@24)
+ (andif (eq f-mod 0)
+ (ne f-sib-index 4))
+ (add (mul sib-index 8) disp32-@24)
+ () ; no setter
+)
+
+(dndo disp32-8
+ SI
+ (disp32)
+ "${disp32-@24}"
+ f-sib
+ (+ (f-sib-ss 3) (f-sib-base 5) (f-sib-index 4) disp32-@24)
+ (eq f-mod 0)
+ disp32-@24
+ () ; no setter
+)
+
+; Now define an "anyof" operand that puts it all together.
+
+(define-anyof-operand
+ (name sib)
+ (comment "base + scaled-index + displacement")
+ (mode SI)
+ ; Each choice must have the same base-ifield.
+ (choices base+index*1
+ base-1
+ index*1+disp32
+ disp32-1
+ base+index*2
+ base-2
+ index*2+disp32
+ disp32-2
+ base+index*4
+ base-4
+ index*4+disp32
+ disp32-4
+ base+index*8
+ base-8
+ index*8+disp32
+ disp32-8
+ )
+)
+
+; Additional ifields/operands used by the mod-r/m byte.
+; It seems cleaner to define the operand with its ifield so they are.
+; Maybe the rest should be organized similarily.
+; Also, the ones that "follow" other ifields must be defined after the latter
+; has been defined.
+
+(diff f-disp8-follows-sib "disp8 ifield after sib ifields"
+ () 7 8 sib INT
+)
+(dnop disp8-follows-sib "disp8 following sib"
+ () h-sint f-disp8-follows-sib
+)
+
+(diff f-disp32-follows-sib "disp32 ifield after sib ifields"
+ () 31 32 sib INT
+)
+(dnop disp32-follows-sib "disp32 following sib"
+ () h-sint f-disp32-follows-sib
+)
+
+; The complete mod-r/m operand, used by instructions.
+; ??? The [] bracketing is for clarity. Match actual assembler later.
+; blah blah blah intel vs at&t blah blah blah
+
+(define-pmacro (define-mod-r/m-choices x-mode x-r/m-reg)
+ (begin
+ (dndo (.sym @reg- x-mode)
+ x-mode
+ (mod-r/m-base-reg)
+ "[${mod-r/m-base-reg}]"
+ f-mod-r/m
+ (+ (f-mod 0) mod-r/m-base-reg)
+ (andif (ne f-r/m 4) (ne f-r/m 5))
+ (mem x-mode mod-r/m-base-reg)
+ ()
+ )
+ (dndo (.sym @sib- x-mode)
+ x-mode
+ (sib)
+ "[$sib]"
+ f-mod-r/m
+ (+ (f-mod 0) (f-r/m 4) sib)
+ ()
+ (mem x-mode sib)
+ ()
+ )
+ (dndo (.sym @disp32- x-mode)
+ x-mode
+ (disp32-@16)
+ "[${disp32-@16}]"
+ f-mod-r/m
+ (+ (f-mod 0) (f-r/m 5) disp32-@16)
+ ()
+ (mem x-mode disp32-@16)
+ ()
+ )
+ (dndo (.sym @reg+disp8- x-mode)
+ x-mode
+ (mod-r/m-base-reg disp8)
+ "[${disp8-@16}(${mod-r/m-base-reg})]"
+ f-mod-r/m
+ (+ (f-mod 1) mod-r/m-base-reg disp8-@16)
+ (ne f-r/m 4)
+ (mem x-mode (add mod-r/m-base-reg disp8-@16))
+ ()
+ )
+ (dndo (.sym @sib+disp8- x-mode)
+ x-mode
+ (sib disp8-follows-sib)
+ "[${disp8-follows-sib}($sib)]"
+ f-mod-r/m
+ (+ (f-mod 1) (f-r/m 4) sib disp8-follows-sib)
+ ()
+ (mem x-mode (add sib disp8-follows-sib))
+ ()
+ )
+ (dndo (.sym @reg+disp32- x-mode)
+ x-mode
+ (mod-r/m-base-reg disp32)
+ "[${disp32-@16}(${mod-r/m-base-reg})]"
+ f-mod-r/m
+ (+ (f-mod 2) mod-r/m-base-reg disp32-@16)
+ (ne f-r/m 4)
+ (mem x-mode (add mod-r/m-base-reg disp32-@16))
+ ()
+ )
+ (dndo (.sym @sib+disp32- x-mode)
+ x-mode
+ (sib disp32-follows-sib)
+ "[${disp32-follows-sib}($sib)]"
+ f-mod-r/m
+ (+ (f-mod 2) (f-r/m 4) sib disp32-follows-sib)
+ ()
+ (mem x-mode (add sib disp32-follows-sib))
+ ()
+ )
+ (dndo (.sym reg- x-mode)
+ x-mode
+ (x-r/m-reg)
+ (.str "${" x-r/m-reg "}")
+ f-mod-r/m
+ (+ (f-mod 3) x-r/m-reg)
+ ()
+ x-r/m-reg
+ ()
+ )
+ )
+)
+
+(define-pmacro (define-mod-r/m-operand x-name x-comment x-mode x-r/m-reg)
+ (begin
+ (define-mod-r/m-choices x-mode x-r/m-reg)
+ (define-anyof-operand
+ (name x-name)
+ (comment x-comment)
+ (mode x-mode)
+ ; Each choice must have the same base-ifield.
+ (choices (.sym @reg- x-mode)
+ (.sym @sib- x-mode)
+ (.sym @disp32- x-mode)
+ (.sym @reg+disp8- x-mode)
+ (.sym @sib+disp8- x-mode)
+ (.sym @reg+disp32- x-mode)
+ (.sym @sib+disp32- x-mode)
+ (.sym reg- x-mode)
+ ))
+ )
+)
+
+(define-mod-r/m-operand mod-r/m-8 "8 bit mod-r/m value" QI r/m-reg8)
+(define-mod-r/m-operand mod-r/m-16 "16 bit mod-r/m value" HI r/m-reg16)
+(define-mod-r/m-operand mod-r/m-32 "32 bit mod-r/m value" SI r/m-reg32)
+
+; Additional ifields/operands used by instructions.
+; These "follow" the mod-r/m byte so must be defined afterwards.
+
+(diff f-simm8-follows-mod-r/m-8 "simm8 ifield after mod-r/m-8 ifields"
+ () 7 8 mod-r/m-8 INT
+)
+(dnop simm8-follows-mod-r/m-8 "simm8 following mod-r/m-8"
+ () h-sint f-simm8-follows-mod-r/m-8
+)
+
+(diff f-simm16-follows-mod-r/m-16 "simm16 ifield after mod-r/m-16 ifields"
+ () 15 16 mod-r/m-16 INT
+)
+(dnop simm16-follows-mod-r/m-16 "simm16 following mod-r/m-16"
+ () h-sint f-simm16-follows-mod-r/m-16
+)
+
+(diff f-simm32-follows-mod-r/m-32 "simm32 ifield after mod-r/m-32 ifields"
+ () 31 32 mod-r/m-32 INT
+)
+(dnop simm32-follows-mod-r/m-32 "simm32 following mod-r/m-32"
+ () h-sint f-simm32-follows-mod-r/m-32
+)
+
+(diff f-simm8-follows-mod-r/m-16 "simm8 ifield after mod-r/m-16 ifields"
+ () 7 8 mod-r/m-16 INT
+)
+(dnop simm8-follows-mod-r/m-16 "simm8 following mod-r/m-16"
+ () h-sint f-simm8-follows-mod-r/m-16
+)
+
+(diff f-simm8-follows-mod-r/m-32 "simm8 ifield after mod-r/m-32 ifields"
+ () 7 8 mod-r/m-32 INT
+)
+(dnop simm8-follows-mod-r/m-32 "simm8 following mod-r/m-32"
+ () h-sint f-simm8-follows-mod-r/m-32
+)
+
+; Some subroutines, to simplify the semantic specs.
+
+(define-pmacro (define-arith-subr x-name x-mode x-fn x-set-cc-fn)
+ (define-subr
+ (name x-name)
+ (mode VOID)
+ (args ((x-mode dst) (x-mode src1) (x-mode src2)))
+ (code (sequence ((x-mode arg1)
+ (x-mode arg2)
+ (x-mode result))
+ (set arg1 src1)
+ (set arg2 src2)
+ (set result (x-fn arg1 arg2))
+ (set dst result)
+ (x-set-cc-fn result arg1 arg2)))
+ )
+)
+
+(define-arith-subr add-QI QI add set-add-cc)
+(define-arith-subr add-HI HI add set-add-cc)
+(define-arith-subr add-SI SI add set-add-cc)
+
+; Instruction definitions.
+
+; IA32 specific instruction attributes:
+; - none yet
+
+(dni nop
+ "nop"
+ ()
+ "nop"
+ (+ OP_90)
+ (nop)
+ ()
+)
+
+; Add, subtract.
+;
+; ??? Insn naming puts destination before addend. Ok?
+
+(dni add-al-simm8
+ "add 8 bit signed immediate to %al"
+ ()
+ "FIXME"
+ (+ OP_04 simm8)
+ (sequence ()
+ (set al (add al simm8))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-ax-simm16
+ "add 16 bit signed immediate to %ax"
+ ()
+ "FIXME"
+ ; ??? Need something like ifield assertions to distinguish from
+ ; 32 bit case.
+ (+ OP_05 simm16)
+ (sequence ()
+ (set ax (add ax simm16))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-eax-simm32
+ "add 32 bit signed immediate to %eax"
+ ()
+ "FIXME"
+ (+ OP_05 simm32)
+ (sequence ()
+ (set eax (add eax simm32))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m8-simm8
+ "add 8 bit immediate"
+ ()
+ "FIXME"
+ (+ OP_80 mod-r/m-8 simm8-follows-mod-r/m-8 (f-reg/opcode 0))
+ (sequence ()
+ (set mod-r/m-8 (add mod-r/m-8 simm8-follows-mod-r/m-8))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m16-simm16
+ "add 16 bit immediate"
+ ()
+ "FIXME"
+ ; ??? Need something akin to ifield-assertions to distinguish from
+ ; 32 bit version.
+ (+ OP_81 mod-r/m-16 simm16-follows-mod-r/m-16 (f-reg/opcode 0))
+ (sequence ()
+ (set mod-r/m-16 (add mod-r/m-16 simm16-follows-mod-r/m-16))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m32-simm32
+ "add 32 bit immediate"
+ ()
+ "FIXME"
+ (+ OP_81 mod-r/m-32 simm32-follows-mod-r/m-32 (f-reg/opcode 0))
+ (sequence ()
+ (set mod-r/m-32 (add mod-r/m-32 simm32-follows-mod-r/m-32))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m16-simm8
+ "add 8 bit signed immediate to 16 bit value"
+ ()
+ "FIXME"
+ ; ??? Need something akin to ifield-assertions to distinguish from
+ ; 32 bit version.
+ (+ OP_83 mod-r/m-16 simm8-follows-mod-r/m-16 (f-reg/opcode 0))
+ (sequence ()
+ (set mod-r/m-16 (add mod-r/m-16 (ext HI simm8-follows-mod-r/m-16)))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m32-simm8
+ "add 8 bit signed immediate to 32 bit value"
+ ()
+ "FIXME"
+ (+ OP_83 mod-r/m-32 simm8-follows-mod-r/m-32 (f-reg/opcode 0))
+ (sequence ()
+ (set mod-r/m-32 (add mod-r/m-32 (ext SI simm8-follows-mod-r/m-32)))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m8-reg8
+ "add 8 bit reg to 8 bit r/m"
+ ()
+ "FIXME"
+ (+ OP_00 mod-r/m-8 reg8)
+ (sequence ()
+ (set mod-r/m-8 (add mod-r/m-8 reg8))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m16-reg16
+ "add 16 bit reg to 16 bit r/m"
+ ()
+ "FIXME"
+ ; ??? Need something akin to ifield-assertions to distinguish from
+ ; 32 bit version.
+ (+ OP_01 mod-r/m-16 reg16)
+ (sequence ()
+ (set mod-r/m-16 (add mod-r/m-16 reg16))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-r/m32-reg32
+ "add 32 bit reg to 32 bit r/m"
+ ()
+ "FIXME"
+ (+ OP_01 mod-r/m-32 reg32)
+ (sequence ()
+ (set mod-r/m-32 (add mod-r/m-32 reg32))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-reg8-r/m8
+ "add 8 bit r/m to 8 bit reg"
+ ()
+ "FIXME"
+ (+ OP_02 mod-r/m-8 reg8)
+ (sequence ()
+ (set reg8 (add reg8 mod-r/m-8))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-reg16-r/m16
+ "add 16 bit r/m to 16 bit reg"
+ ()
+ "FIXME"
+ ; ??? Need something akin to ifield-assertions to distinguish from
+ ; 32 bit version.
+ (+ OP_03 mod-r/m-16 reg16)
+ (sequence ()
+ (set reg16 (add reg16 mod-r/m-16))
+ ; ??? condition codes
+ )
+ ()
+)
+
+(dni add-reg32-r/m32
+ "add 32 bit r/m to 32 bit reg"
+ ()
+ "FIXME"
+ (+ OP_03 mod-r/m-32 reg32)
+ (sequence ()
+ (set reg32 (add reg32 mod-r/m-32))
+ ; ??? condition codes
+ )
+ ()
+)
diff --git a/cgen/ia64.cpu b/cgen/ia64.cpu
new file mode 100644
index 00000000000..270fdf4b224
--- /dev/null
+++ b/cgen/ia64.cpu
@@ -0,0 +1,2355 @@
+;;; Intel IA-64 CPU description. -*- Scheme -*-
+;;; Copyright (C) 2000 Red Hat, Inc.
+;;; This file is part of CGEN.
+;;; See file COPYING.CGEN for details.
+
+(include "simplify.inc")
+
+
+;;; Architecture and cpu family definitions.
+
+(define-arch
+ (name ia64)
+ (comment "Intel IA-64 architecture")
+ (insn-lsb0? #t)
+ (machs ia64)
+ (isas ia64)
+)
+
+(define-isa
+ (name ia64)
+
+ ;; Each instruction in the 128-bit bundle is 41 bits wide.
+ (base-insn-bitsize 41)
+
+ ;; Each bundle is 3 insns wide.
+ (liw-insns 3)
+
+ ;; ??? How to specify "lots", as that's what the architecture's
+ ;; stop bits means;
+ (parallel-insns 3)
+
+ ;; Initial bit numbers to decode by.
+ (decode-assist (40 39 38 37))
+)
+
+(define-cpu
+ (name ia64)
+ (comment "Intel IA-64 family")
+ (insn-endian little)
+ (data-endian either)
+ (word-bitsize 64)
+)
+
+(eval
+ (begin
+ ;; We need 64-bit host support.
+ (set! INT (mode:add! 'INT (mode:lookup 'DI)))
+ (set! UINT (mode:add! 'UINT (mode:lookup 'UDI)))
+
+ ;; ??? This shouldn't be necessary, IMO.
+ (set! WI (mode:add! 'WI (mode:lookup 'DI)))
+ (set! UWI (mode:add! 'UWI (mode:lookup 'UDI)))
+ (set! AI (mode:add! 'AI (mode:lookup 'UDI)))
+ (set! IAI (mode:add! 'IAI (mode:lookup 'UDI)))
+ )
+)
+
+
+(define-mach
+ (name ia64)
+ (comment "Intel IA-64 processors")
+ (cpu ia64)
+)
+
+; ??? Incomplete. Pipeline and unit info wrong.
+
+(define-model
+ (name ia64_itanium)
+ (comment "Intel Itanium processor")
+ (mach ia64)
+ (pipeline all "" () ((fetch) (decode) (execute) (writeback)))
+ (unit u-exec "Execution Unit" () 1 1
+ () () () ())
+)
+
+;;; Attributes.
+;;;
+;;; These are used to mark instructions so that we can decode the
+;;; dependancy violation data in Intel's tables.
+
+(define-attr
+ (name FORMAT)
+ (for insn)
+ (type enum)
+ (attrs META)
+ (values UNKNOWN
+
+ A1 A2 A3 A4 A5 A6 A7 A8 A9 A10
+
+ I1 I2 I3 I4 I5 I6 I7 I8 I9 I10
+ I11 I12 I13 I14 I15 I16 I17 I18 I19 I20
+ I21 I22 I23 I24 I25 I26 I27 I28 I29
+
+ M1 M2 M3 M4 M5 M6 M7 M8 M9 M10
+ M11 M12 M13 M14 M15 M16 M17 M18 M19 M20
+ M21 M22 M23 M24 M25 M26 M27 M28 M29 M30
+ M31 M32 M33 M34 M35 M36 M37 M38 M39 M40
+ M41 M42 M43 M44 M45 M46
+
+ B1 B2 B3 B4 B5 B6 B7 B8 B9
+
+ F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
+ F11 F12 F13 F14 F15
+ )
+ (default UNKNOWN)
+)
+
+;; ??? NONE isn't a valid value, but non-FP insns obviously can't have
+;; a valid value either.
+(define-attr
+ (name FIELD-SF)
+ (for insn)
+ (type enum)
+ (attrs META)
+ (values NONE s0 s1 s2 s3)
+ (default NONE)
+)
+
+(define-attr
+ (name FIELD-LFTYPE)
+ (for insn)
+ (type enum)
+ (attrs META)
+ (values NONE fault)
+ (default NONE)
+)
+
+(define-attr
+ (name FIELD-CTYPE)
+ (for insn)
+ (type enum)
+ (attrs META)
+ (values NONE unc or and or.andcm orcm andcm and.orcm)
+ (default NONE)
+)
+
+;; Field AR3 references a register field.
+;; Field CR3 references a register field.
+;; Field ireg references a register field.
+
+;;; ??? IA-64 specific instruction attributes:
+;;;
+;;; FIRST Must be at the beginning of an instruction group.
+;;; SLOT2 Must be in slot 2 on a bundle.
+;;; LAST Must be at the end of an instruction group.
+;;; I_IN_MLI Insn is allowed in I slot of MLI.
+;;; PRIV Privileged instruction.
+;;; NO_PRED Insn cannot be predicated.
+
+
+;;; Instruction fields.
+;;;
+;;; ??? This is confusing (at least to me) -- note that we specify the _top_
+;;; of the field and a length.
+;;;
+;;; ??? There are only two fields used nearly universally. But the
+;;; instruction formats are very regular in the sense that the same
+;;; field specifications are re-used many times. So we just have the
+;;; raw fields here first.
+
+;; Fields used by most instructions.
+(dnf f-opcode "major opcode" () 40 4)
+(dnf f-qp "qualifying predicate" () 5 6)
+
+;; Random parts used by the 109 (!) instruction formats.
+(dnf f-36-6 "6 @ 36" () 36 6)
+(df f-36-1s "1 @ 36, signed" () 36 1 INT #f #f)
+(dnf f-36-1 "1 @ 36" () 36 1)
+(dnf f-35-9 "9 @ 35" () 35 9)
+(dnf f-35-6 "6 @ 35" () 35 6)
+(dnf f-35-3 "3 @ 35" () 35 3)
+(dnf f-35-2 "2 @ 35" () 35 2)
+(dnf f-35-1 "1 @ 35" () 35 1)
+(dnf f-34-2 "2 @ 34" () 34 2)
+(dnf f-33-1 "1 @ 33" () 33 1)
+(dnf f-32-27 "27 @ 32" () 32 27)
+(dnf f-32-20 "20 @ 32" () 32 20)
+(dnf f-32-13 "13 @ 32" () 32 13)
+(dnf f-32-9 "9 @ 32" () 32 9)
+(dnf f-32-6 "6 @ 32" () 32 6)
+(dnf f-32-4 "4 @ 32" () 32 4)
+(dnf f-32-2 "2 @ 32" () 32 2)
+(dnf f-32-1 "1 @ 32" () 32 1)
+(dnf f-31-8 "8 @ 31" () 31 8)
+(dnf f-31-2 "2 @ 31" () 31 2)
+(dnf f-30-4 "4 @ 30" () 30 4)
+(dnf f-30-19 "19 @ 30" () 30 19)
+(dnf f-29-2 "2 @ 29" () 29 2)
+(dnf f-28-2 "2 @ 28" () 28 2)
+(dnf f-27-8 "8 @ 27" () 27 8)
+(dnf f-27-4 "4 @ 27" () 27 4)
+(dnf f-27-3 "3 @ 27" () 27 3)
+(dnf f-27-1 "1 @ 27" () 27 1)
+(dnf f-26-21 "21 @ 26" () 26 21)
+(dnf f-26-11 "11 @ 26" () 26 11)
+(dnf f-26-7 "7 @ 26" () 26 7)
+(dnf f-26-5 "5 @ 26" () 26 5)
+(dnf f-26-1 "1 @ 26" () 26 1)
+(dnf f-25-20 "20 @ 25" () 25 20)
+(dnf f-25-6 "6 @ 25" () 25 6)
+(dnf f-24-5 "5 @ 24" () 24 5)
+(dnf f-23-4 "4 @ 23" () 23 4)
+(dnf f-23-1 "1 @ 23" () 23 1)
+(dnf f-22-1 "1 @ 22" () 22 1)
+(dnf f-21-2 "2 @ 21" () 21 2)
+(dnf f-21-1 "1 @ 21" () 21 1)
+(dnf f-20-1 "1 @ 20" () 20 1)
+(dnf f-19-7 "7 @ 19" () 19 7)
+(dnf f-19-6 "6 @ 19" () 19 6)
+(dnf f-19-4 "4 @ 19" () 19 4)
+(dnf f-19-1 "1 @ 19" () 19 1)
+(dnf f-18-5 "5 @ 18" () 18 5)
+(dnf f-15-3 "3 @ 15" () 15 3)
+(dnf f-15-1 "1 @ 15" () 15 1)
+(dnf f-14-2 "2 @ 14" () 14 2)
+(dnf f-13-1 "1 @ 13" () 13 1)
+(dnf f-12-7 "7 @ 12" () 12 7)
+(dnf f-12-1 "1 @ 12" () 12 1)
+(dnf f-11-6 "6 @ 11" () 11 6)
+(dnf f-11-3 "3 @ 11" () 11 3)
+(dnf f-8-3 "3 @ 8" () 8 3)
+
+;; The extra field for movl
+(dnf f-81-41 "41 @ 81" () 81 41)
+
+;; Virtual fields of the broken up constants.
+(dnmf fv-sint8 "i8 for A3 A8 I27 M30"
+ () INT
+
+ (f-36-1s f-19-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint8) (const 7)))
+ (set (ifield f-19-7) (and (ifield fv-sint8) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint8)
+ (or (sll (ifield f-36-1s) (const 7))
+ (ifield f-19-7)))
+ )
+)
+
+(dnmf fv-sint9a "i9 for M3 M8 M15"
+ () INT
+ (f-36-1s f-27-1 f-19-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint9a) (const 8)))
+ (set (ifield f-27-1)
+ (and (srl (ifield fv-sint9a) (const 7)) (const 1)))
+ (set (ifield f-19-7) (and (ifield fv-sint9a) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint9a)
+ (or (sll (ifield f-36-1s) (const 8))
+ (or (sll (ifield f-27-1) (const 7))
+ (ifield f-19-7))))
+ )
+)
+
+(dnmf fv-sint9b "i9 for M5 M10"
+ () INT
+ (f-36-1s f-27-1 f-12-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint9b) (const 8)))
+ (set (ifield f-27-1)
+ (and (srl (ifield fv-sint9b) (const 7)) (const 1)))
+ (set (ifield f-12-7) (and (ifield fv-sint9b) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint9b)
+ (or (sll (ifield f-36-1s) (const 8))
+ (or (sll (ifield f-27-1) (const 7))
+ (ifield f-12-7))))
+ )
+)
+
+(dnmf fv-sint14 "i14 for A4"
+ () INT
+ (f-36-1s f-32-6 f-19-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint14) (const 13)))
+ (set (ifield f-32-6)
+ (and (srl (ifield fv-sint14) (const 7)) (const #x3f)))
+ (set (ifield f-19-7) (and (ifield fv-sint14) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint14)
+ (or (sll (ifield f-36-1s) (const 13))
+ (or (sll (ifield f-32-6) (const 7))
+ (ifield f-19-7))))
+ )
+)
+
+(dnmf fv-sint17 "mask17 for I23"
+ () INT
+ (f-36-1s f-31-8 f-12-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint17) (const 16)))
+ (set (ifield f-31-8)
+ (and (srl (ifield fv-sint17) (const 8)) (const #xff)))
+ (set (ifield f-12-7)
+ (and (srl (ifield fv-sint17) (const 1)) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint17)
+ (or (sll (ifield f-36-1s) (const 16))
+ (or (sll (ifield f-31-8) (const 8))
+ (ifield f-12-7))))
+ )
+)
+
+(dnmf fv-sint22 "i22 for A5"
+ () INT
+ (f-36-1s f-35-9 f-26-5 f-19-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint22) (const 21)))
+ (set (ifield f-26-5)
+ (and (srl (ifield fv-sint22) (const 16)) (const #x1f)))
+ (set (ifield f-35-9)
+ (and (srl (ifield fv-sint22) (const 7)) (const #x1ff)))
+ (set (ifield f-19-7) (and (ifield fv-sint22) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint22)
+ (or (or (sll (ifield f-36-1s) (const 21))
+ (sll (ifield f-26-5) (const 16)))
+ (or (sll (ifield f-35-9) (const 7))
+ (ifield f-19-7))))
+ )
+)
+
+(dnmf fv-sint44 "i44 for I24"
+ () INT
+ (f-36-1s f-32-27)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint44) (const 43)))
+ (set (ifield f-19-7)
+ (and (srl (ifield fv-sint44) (const 16))
+ (const #x7ffffff)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint44)
+ (or (sll (ifield f-36-1s) (const 43))
+ (sll (ifield f-32-27) (const 16))))
+ )
+)
+
+(dnmf fv-sint64 "i64 for I18"
+ () INT
+ (f-81-41 f-36-1s f-35-9 f-26-5 f-21-1 f-19-7)
+ (sequence () ; insert
+ (set (ifield f-36-1s) (srl (ifield fv-sint64) (const 63)))
+ (set (ifield f-81-41)
+ (and (srl (ifield fv-sint64) (const 22))
+ (const #x1fffffffff)))
+ (set (ifield f-21-1)
+ (and (srl (ifield fv-sint64) (const 21)) (const 1)))
+ (set (ifield f-26-5)
+ (and (srl (ifield fv-sint64) (const 16)) (const #x1f)))
+ (set (ifield f-35-9)
+ (and (srl (ifield fv-sint64) (const 7)) (const #x1ff)))
+ (set (ifield f-19-7) (and (ifield fv-sint64) (const #x7f)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-sint64)
+ (or (or (or (sll (ifield f-36-1s) (const 63))
+ (sll (ifield f-81-41) (const 22)))
+ (or (sll (ifield f-21-1) (const 21))
+ (sll (ifield f-26-5) (const 16))))
+ (or (sll (ifield f-35-9) (const 7))
+ (ifield f-19-7))))
+ )
+)
+
+(dnmf fv-uint21 "u21 for I19 M37 F15"
+ () UINT
+ (f-36-1 f-25-20)
+ (sequence () ; insert
+ (set (ifield f-36-1) (srl (ifield fv-uint21) (const 20)))
+ (set (ifield f-25-20) (and (ifield fv-uint21) (const #xfffff)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-uint21)
+ (or (sll (ifield f-36-1) (const 20))
+ (ifield f-25-20)))
+ )
+)
+
+(dnmf fv-uint24 "u24 for M44"
+ () UINT
+ (f-36-1 f-32-2 f-26-21)
+ (sequence () ; insert
+ (set (ifield f-36-1) (srl (ifield fv-uint24) (const 23)))
+ (set (ifield f-32-1)
+ (and (srl (ifield fv-uint24) (const 21)) (const 3)))
+ (set (ifield f-26-21)
+ (and (ifield fv-uint24) (const #x1fffff)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-uint24)
+ (or (sll (ifield f-36-1) (const 23))
+ (or (sll (ifield f-32-2) (const 21))
+ (ifield f-26-21))))
+ )
+)
+
+(dnmf fv-tgt25a "target25 for I20 M20 M21"
+ (PCREL-ADDR) INT
+ (f-36-1s f-32-13 f-12-7)
+ (sequence () ; insert
+ ;; ??? Wherefore right shift.
+ (set (ifield f-36-1s) (srl (ifield fv-tgt25a) (const 20)))
+ (set (ifield f-32-13)
+ (and (srl (ifield fv-tgt25a) (const 7)) (const #x1fff)))
+ (set (ifield f-12-7) (and (ifield fv-tgt25a) (const #x7f)))
+ )
+ (sequence () ; extract
+ ;; ??? Where will pc be added.
+ ;; ??? Wherefore left shift.
+ (set (ifield fv-tgt25a)
+ (or (sll (ifield f-36-1s) (const 20))
+ (or (sll (ifield f-32-13) (const 7))
+ (ifield f-12-7))))
+ )
+)
+
+(dnmf fv-tgt25b "target25 for F14"
+ (PCREL-ADDR) INT
+ (f-36-1s f-25-20)
+ (sequence () ; insert
+ ;; ??? Wherefore right shift.
+ (set (ifield f-36-1s) (srl (ifield fv-tgt25b) (const 20)))
+ (set (ifield f-25-20) (and (ifield fv-tgt25b) (const #xfffff)))
+ )
+ (sequence () ; extract
+ ;; ??? Where will pc be added.
+ ;; ??? Wherefore left shift.
+ (set (ifield fv-tgt25b)
+ (or (sll (ifield f-36-1) (const 20))
+ (ifield f-25-20)))
+ )
+)
+
+(dnmf fv-tgt25c "target25 for M22 M23 B1 B2 B3 B6"
+ (PCREL-ADDR) INT
+ (f-36-1s f-32-20)
+ (sequence () ; insert
+ ;; ??? Wherefore right shift.
+ (set (ifield f-36-1s) (srl (ifield fv-tgt25c) (const 20)))
+ (set (ifield f-32-20) (and (ifield fv-tgt25c) (const #xfffff)))
+ )
+ (sequence () ; extract
+ ;; ??? Where will pc be added.
+ ;; ??? Wherefore left shift.
+ (set (ifield fv-tgt25c)
+ (or (sll (ifield f-36-1s) (const 20))
+ (ifield f-32-20)))
+ )
+)
+
+(dnmf fv-tag13a "tag13 for I21"
+ (PCREL-ADDR) INT
+ (f-32-9)
+ (sequence () ; insert
+ ;; ??? Wherefore right shift.
+ (set (ifield f-32-9) (and (ifield fv-tag13a (const #x1ff))))
+ )
+ (sequence () ; extract
+ ;; ??? Where will pc be added.
+ ;; ??? Wherefore left shift.
+ (set (ifield fv-tag13a)
+ (sub (xor (ifield f-32-9) (const #x100)) (const #x100)))
+ )
+)
+
+(dnmf fv-tag13b "tag13 for B6 B7"
+ (PCREL-ADDR) INT
+ (f-34-2 f-12-7)
+ (sequence () ; insert
+ ;; ??? Wherefore right shift.
+ (set (ifield f-34-2)
+ (and (sll (ifield fv-tag13b) (const 7)) (const 3)))
+ (set (ifield f-12-7) (and (ifield fv-tag13b) (const #x7f)))
+ )
+ (sequence () ; extract
+ ;; ??? Where will pc be added.
+ ;; ??? Wherefore left shift.
+ (set (ifield fv-tag13a)
+ (or (sll (sub (xor (ifield f-34-2) (const 2))
+ (const 2))
+ (const 7))
+ (ifield f-12-7)))
+ )
+)
+
+(dnmf fv-uint9 "u9 for F5"
+ () UINT
+ (f-34-2 f-26-7)
+ (sequence () ; insert
+ (set (ifield f-26-7) (srl (ifield fv-uint9) (const 2)))
+ (set (ifield f-34-2) (and (ifield fv-uint9) (const 3)))
+ )
+ (sequence () ; extract
+ (set (ifield fv-uint9)
+ (or (sll (ifield f-26-7) (const 2))
+ (ifield f-34-2)))
+ )
+)
+
+;; Fields with funny arithmetic
+
+(df f-count2a "count2 for A2" () 28 2 UINT
+ ((value pc) (sub WI value (const 1)))
+ ((value pc) (add WI value (const 1)))
+)
+
+(df f-count2b "count2 for A10" () 28 2 UINT
+ ((value pc)
+ (if WI (le value (const 2))
+ (sub WI value (const 1))
+ (error "invalid value for field count2b")))
+ ((value pc) (add WI value (const 1)))
+)
+
+(df f-count2c "count2 for I1" () 31 2 UINT
+ ((value pc)
+ (cond WI
+ ((eq value (const 0)) (const 0))
+ ((eq value (const 7)) (const 1))
+ ((eq value (const 15)) (const 2))
+ ((eq value (const 16)) (const 3))
+ (else (error "invalid value for field count2c"))))
+ ((value pc)
+ (cond WI
+ ((eq value (const 0)) (const 0))
+ ((eq value (const 1)) (const 7))
+ ((eq value (const 2)) (const 15))
+ ((eq value (const 3)) (const 16))))
+)
+
+(df f-ccount5 "ccount5 for I8" () 24 5 UINT
+ ((value pc) (sub WI (const 31) value))
+ ((value pc) (sub WI (const 31) value))
+)
+
+(df f-len4 "len4 for I15" () 30 4 UINT
+ ((value pc) (sub WI value (const 1)))
+ ((value pc) (add WI value (const 1)))
+)
+
+(df f-len6 "len6 for I11 I12 I13 I14" () 32 6 UINT
+ ((value pc) (sub WI value (const 1)))
+ ((value pc) (add WI value (const 1)))
+)
+
+(df f-cpos6a "cpos6 for I12 I13" () 25 6 UINT
+ ((value pc) (sub WI (const 63) value))
+ ((value pc) (sub WI (const 63) value))
+)
+
+(df f-cpos6b "cpos6 for I14" () 19 6 UINT
+ ((value pc) (sub WI (const 63) value))
+ ((value pc) (sub WI (const 63) value))
+)
+
+(df f-cpos6c "cpos6 for I15" () 36 6 UINT
+ ((value pc) (sub WI (const 63) value))
+ ((value pc) (sub WI (const 63) value))
+)
+
+(dnmf fv-inc3 "inc3 for M17" () INT
+ (f-15-1 f-14-2)
+ (sequence () ; insert
+ (set (ifield f-15-1) (lt (ifield fv-inc3) (const 0)))
+ (set (ifield f-14-2) (abs (ifield fv-inc3)))
+ (set (ifield f-14-2)
+ (cond ((eq (ifield f-14-2) (const 1)) (const 3))
+ ((eq (ifield f-14-2) (const 4)) (const 2))
+ ((eq (ifield f-14-2) (const 8)) (const 1))
+ ((eq (ifield f-14-2) (const 16)) (const 0))
+ (else (error "invalid value for field inc3"))))
+ )
+ (sequence () ; extract
+ (set (ifield fv-inc3)
+ (mul (add (mul (neg (ifield f-15-1)) (const 2)) (const 1))
+ (if (eq (ifield f-14-2) (const 3))
+ (const 1)
+ (sll (const 1) (sub (const 4)
+ (ifield f-14-2))))))
+ )
+)
+
+;;; Hardware pieces.
+;;;
+;;; These entries list the elements of the raw hardware. They're also
+;;; used to provide tables and other elements of the assembly language.
+
+;; The normal h-uint only provides 32 bits of integer.
+(dnh h-int64 "64-bit integer" ()
+ (immediate (INT 64))
+ () () ()
+)
+
+;; ??? Intel calls this if IP, but from experience with the i960
+;; simulator using the name "ip", we know that gdb reacts badly.
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(define-pmacro (build-decpair num) ((.dec num) num))
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs CACHE-ADDR)
+ (type register WI (128))
+ (indices keyword "r"
+ (.map build-decpair (.iota 128)))
+)
+
+;; ??? Skip GR NaTs for now, since we're not simulating.
+
+(define-hardware
+ (name h-fr)
+ (comment "floating-point registers")
+ (type register XF (128))
+ (indices keyword "fr"
+ (.map build-decpair (.iota 128)))
+)
+
+(define-hardware
+ (name h-br)
+ (comment "branch registers")
+ (attrs CACHE-ADDR)
+ (type register WI (8))
+ (indices keyword "br"
+ (.map build-decpair (.iota 8)))
+)
+
+(define-hardware
+ (name h-ar)
+ (comment "application registers")
+ (type register WI (128))
+ (indices keyword "ar"
+ (.map build-decpair (.iota 128)))
+)
+
+(define-hardware
+ (name h-pr)
+ (comment "predicate registers")
+ (type register BI (64))
+ (indices keyword "pr"
+ (.map build-decpair (.iota 64)))
+)
+
+(define-hardware
+ (name h-cr)
+ (comment "control registers")
+ (type register WI (128))
+ (indices keyword "cr"
+ (.map build-decpair (.iota 128)))
+)
+
+;; ??? CFM, PSR, PMD, CPUID
+
+;;; Instruction Operands.
+;;;
+;;; These entries provide a layer between the assembler and the raw
+;;; hardware description, and are used to refer to hardware elements
+;;; in the semantic code. Usually there's a bit of over-specification,
+;;; but in more complicated instruction sets there isn't.
+
+(dnop qp "qualifying predicate" () h-pr f-qp)
+
+(dnop r1 "general register 1" () h-gr f-12-7)
+(dnop r2 "general register 2" () h-gr f-19-7)
+(dnop r3 "general register 3" () h-gr f-26-7)
+(dnop r33 "general register 3 for A5" () h-gr f-21-2)
+
+(dnop f1 "floating-point register 1" () h-fr f-12-7)
+(dnop f2 "floating-point register 2" () h-fr f-19-7)
+(dnop f3 "floating-point register 3" () h-fr f-26-7)
+
+(dnop p1 "predicate register 1" () h-pr f-11-6)
+(dnop p2 "predicate register 2" () h-pr f-32-6)
+
+(dnop b1 "branch register 1" () h-br f-8-3)
+(dnop b2 "branch register 2" () h-br f-15-3)
+
+(dnop ar3 "application register 3" () h-ar f-26-7)
+(dnop cr3 "control register 3" () h-cr f-26-7)
+
+(dnop imm1 "imm1 for I14" () h-int64 f-36-1s)
+(dnop imm8 "imm8 for A3 A8 I27 M30" () h-int64 fv-sint8)
+(dnop imm9a "imm9 for M3 M8 M15" () h-int64 fv-sint9a)
+(dnop imm9b "imm9 for M5 M10" () h-int64 fv-sint9b)
+(dnop imm14 "imm14 for A4" () h-int64 fv-sint14)
+(dnop imm17 "mask17 for I23" () h-int64 fv-sint17)
+(dnop imm21 "imm21 for I19" () h-int64 fv-uint21)
+(dnop imm22 "imm22 for A5" () h-int64 fv-sint22)
+(dnop imm44 "imm44 for I24" () h-int64 fv-sint44)
+(dnop imm64 "imm64 for I18" () h-int64 fv-sint64)
+
+(dnop count2a "count2 for A2" () h-int64 f-count2a)
+(dnop count2b "count2 for A10" () h-int64 f-count2b)
+(dnop count2c "count2 for I1" () h-int64 f-count2c)
+(dnop count5 "count5 for I6" () h-int64 f-18-5)
+(dnop count6 "count6 for I10" () h-int64 f-32-6)
+(dnop ccount5 "ccount5 for I8" () h-int64 f-ccount5)
+
+(dnop len4 "len4 for I15" () h-int64 f-len4)
+(dnop len6 "len6 for I11 I12 I13 I14" () h-int64 f-len6)
+
+(dnop pos6 "pos6 for I11" () h-int64 f-19-6)
+(dnop cpos6a "cpos6 for I12 I13" () h-int64 f-cpos6a)
+(dnop cpos6b "cpos6 for I14" () h-int64 f-cpos6b)
+(dnop cpos6c "cpos6 for I15" () h-int64 f-cpos6c)
+
+(dnop inc3 "inc3 for M17" () h-int64 fv-inc3)
+
+(define-operand
+ (name mbtype4)
+ (comment "mbtype4 type for I3")
+ (type h-int64)
+ (index f-23-4)
+ (handlers (parse "mbtype4")
+ (print "mbtype4"))
+)
+
+(dnop mhtype8 "mhtype8 for I4" () h-int64 f-27-8)
+
+(dnop tgt25a "tgt25 for I20 M20 M21" () h-int64 fv-tgt25a)
+(dnop tgt25b "tgt25 for F14" () h-int64 fv-tgt25b)
+(dnop tgt25c "tgt25 for M22 M23 B1 B2 B3 B6" () h-int64 fv-tgt25c)
+
+(dnop tag13a "tag13 for I21" () h-int64 fv-tag13a)
+
+;; Completers
+
+(define-operand
+ (name ldhint)
+ (comment "ldhint completer")
+ (type h-int64)
+ (index f-29-2)
+ (handlers (parse "ldhint")
+ (print "ldhint"))
+)
+
+(define-operand
+ (name sthint)
+ (comment "sthint completer")
+ (type h-int64)
+ (index f-29-2)
+ (handlers (parse "sthint")
+ (print "sthint"))
+)
+
+(define-operand
+ (name movbr_mwh)
+ (comment "mwh completer for mov_br")
+ (type h-int64)
+ (index f-21-2)
+ (handlers (parse "mwh")
+ (print "mwh"))
+)
+
+(define-operand
+ (name movbr_ih)
+ (comment "ih completer for mov_br")
+ (type h-int64)
+ (index f-23-1)
+ (handlers (parse "ih")
+ (print "ih"))
+)
+
+(define-operand
+ (name lfhint)
+ (comment "lfhint for lfetch")
+ (type h-int64)
+ (index f-29-2)
+ (handlers (parse "lfhint")
+ (print "lfhint"))
+)
+
+(define-operand
+ (name sorsolsof)
+ (comment "combined i,l,o,r for alloc")
+ (type h-int64)
+ (index f-30-19)
+ (handlers (parse "sorsolsof")
+ (print "sorsolsof"))
+)
+
+;; These are architecturally ignored bits, as opposed to architecturally
+;; reserved bits. I.e. we should assemble them in with zeros, but we should
+;; ignore them when disassembling.
+
+(dnop ign_36_1 "ignore 1 @ 36" () h-int64 f-36-1)
+(dnop ign_32_2 "ignore 2 @ 32" () h-int64 f-32-2)
+(dnop ign_32_1 "ignore 1 @ 32" () h-int64 f-32-1)
+(dnop ign_29_2 "ignore 2 @ 29" () h-int64 f-29-2)
+(dnop ign_27_4 "ignore 4 @ 27" () h-int64 f-27-4)
+(dnop ign_27_3 "ignore 3 @ 27" () h-int64 f-27-3)
+(dnop ign_27_1 "ignore 1 @ 27" () h-int64 f-27-1)
+(dnop ign_26_11 "ignore 11 @ 26" () h-int64 f-26-11)
+(dnop ign_26_7 "ignore 7 @ 26" () h-int64 f-26-7)
+(dnop ign_26_1 "ignore 1 @ 26" () h-int64 f-26-1)
+(dnop ign_23_4 "ignore 4 @ 23" () h-int64 f-23-4)
+(dnop ign_19_7 "ignore 7 @ 19" () h-int64 f-19-7)
+(dnop ign_19_6 "ignore 6 @ 19" () h-int64 f-19-6)
+(dnop ign_19_4 "ignore 4 @ 19" () h-int64 f-19-4)
+(dnop ign_19_1 "ignore 1 @ 19" () h-int64 f-19-1)
+(dnop ign_13_1 "ignore 1 @ 13" () h-int64 f-13-1)
+(dnop ign_12_7 "ignore 7 @ 12" () h-int64 f-12-7)
+
+;; ??? Add more as needed.
+
+;;; "A" Format Instruction definitions.
+
+(define-pmacro (I-A1 mnemonic maybe-p1 op x2a ve x4 x2b)
+ (dni (.sym mnemonic maybe-p1)
+ (.str "Integer ALU, reg-reg, " mnemonic maybe-p1)
+ ((FORMAT A1))
+ (.str mnemonic " $r1=$r2,$r3" maybe-p1)
+ (+ (f-opcode op) (f-35-2 x2a) (f-33-1 ve) (f-32-4 x4) (f-28-2 x2b)
+ ign_36_1 r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A1 add "" 8 0 0 0 0)
+(I-A1 add ",1" 8 0 0 0 1)
+(I-A1 sub "" 8 0 0 1 1)
+(I-A1 sub ",1" 8 0 0 1 0)
+(I-A1 addp4 "" 8 0 0 2 0)
+(I-A1 and "" 8 0 0 3 0)
+(I-A1 andcm "" 8 0 0 3 1)
+(I-A1 or "" 8 0 0 3 2)
+(I-A1 xor "" 8 0 0 3 3)
+
+(define-pmacro (I-A2 mnemonic op x2a ve x4)
+ (dni mnemonic
+ (.str "Shift Left and Add, " mnemonic)
+ ((FORMAT A2))
+ (.str mnemonic " $r1=$r2,$count2a,$r3")
+ (+ (f-opcode op) (f-35-2 x2a) (f-33-1 ve) (f-32-4 x4)
+ ign_36_1 count2a r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A2 shladd 8 0 0 4)
+(I-A2 shladdp4 8 0 0 6)
+
+(define-pmacro (I-A3 mnemonic op x2a ve x4 x2b)
+ (dni (.sym mnemonic "i")
+ (.str "Integer ALU, imm8-reg, " mnemonic)
+ ((FORMAT A3))
+ (.str mnemonic " $r1=$imm8,$r3")
+ (+ (f-opcode op) (f-35-2 x2a) (f-33-1 ve) (f-32-4 x4) (f-28-2 x2b)
+ r3 imm8 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A3 sub 8 0 0 9 1)
+(I-A3 and 8 0 0 11 0)
+(I-A3 andcm 8 0 0 11 1)
+(I-A3 or 8 0 0 11 2)
+(I-A3 xor 8 0 0 11 3)
+
+(define-pmacro (I-A4 mnemonic op x2a ve)
+ (dni (.str mnemonic "i")
+ (.str "Add imm14, " mnemonic)
+ ((FORMAT A4))
+ (.str mnemonic " $r1=$imm14,$r3")
+ (+ (f-opcode op) (f-35-2 x2a) (f-33-1 ve)
+ r3 imm14 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A4 adds 8 2 0)
+(I-A4 addp4 8 3 0)
+
+(define-pmacro (I-A5 mnemonic op)
+ (dni (.str mnemonic)
+ (.str "Add imm22, " mnemonic)
+ ((FORMAT A5))
+ (.str mnemonic " $r1=$imm22,$r33")
+ (+ (f-opcode op) imm22 r33 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A5 addl 9)
+
+(define-pmacro (I-A6 mnemonic ctype-attr op x2 tb ta c)
+ (dni (.sym mnemonic)
+ (.str "Integer Compare, reg-reg, " mnemonic)
+ ((FORMAT A6) (FIELD-CTYPE ctype-attr))
+ (.str mnemonic " $p1,$p2=$r2,$r3")
+ (+ (f-opcode op) (f-36-1 tb) (f-35-2 x2) (f-33-1 ta) (f-12-1 c)
+ p2 r3 r2 p1 qp)
+ ()
+ ()
+ )
+)
+
+(define-pmacro (I-A6-cmp-cond-ctype cmp cond ctype op x2 ta c)
+ (I-A6 (.sym cmp "." cond
+ (.eval (if (eq? (string-length ctype) 0) "" "."))
+ ctype)
+ (.eval (if (eq? (string-length ctype) 0) 'NONE (string->symbol ctype)))
+ op 0 x2 ta c)
+)
+
+(define-pmacro (I-A6-cmp cmp x2)
+ (begin
+ (I-A6-cmp-cond-ctype cmp lt "" 12 x2 0 0)
+ (I-A6-cmp-cond-ctype cmp ltu "" 13 x2 0 0)
+ (I-A6-cmp-cond-ctype cmp eq "" 14 x2 0 0)
+
+ (I-A6-cmp-cond-ctype cmp lt "unc" 12 x2 0 1)
+ (I-A6-cmp-cond-ctype cmp ltu "unc" 13 x2 0 1)
+ (I-A6-cmp-cond-ctype cmp eq "unc" 14 x2 0 1)
+
+ (I-A6-cmp-cond-ctype cmp eq "and" 12 x2 1 0)
+ (I-A6-cmp-cond-ctype cmp eq "or" 13 x2 1 0)
+ (I-A6-cmp-cond-ctype cmp eq "or.andcm" 14 x2 1 0)
+
+ (I-A6-cmp-cond-ctype cmp ne "and" 12 x2 1 1)
+ (I-A6-cmp-cond-ctype cmp ne "or" 13 x2 1 1)
+ (I-A6-cmp-cond-ctype cmp ne "or.andcm" 14 x2 1 1)
+ )
+)
+
+(I-A6-cmp cmp 0)
+(I-A6-cmp cmp4 1)
+
+(define-pmacro (I-A7 mnemonic ctype-attr op x2 tb ta c)
+ (dni (.sym mnemonic)
+ (.str "Integer Compare, zero-reg, " mnemonic)
+ ((FORMAT A7) (FIELD-CTYPE ctype-attr))
+ (.str mnemonic " $p1,$p2=r0,$r3")
+ (+ (f-opcode op) (f-36-1 tb) (f-35-2 x2) (f-33-1 ta) (f-12-1 c)
+ p2 r3 (f-19-7 0) p1 qp)
+ ()
+ ()
+ )
+)
+
+(define-pmacro (I-A7-cmp-cond-ctype cmp cond ctype op x2 ta c)
+ (I-A7 (.sym cmp "." cond "." ctype) (.sym ctype) op x2 1 ta c)
+)
+
+(define-pmacro (I-A7-cmp-cond cmp cond x2 ta c)
+ (begin
+ (I-A7-cmp-cond-ctype cmp cond and 12 x2 ta c)
+ (I-A7-cmp-cond-ctype cmp cond or 13 x2 ta c)
+ (I-A7-cmp-cond-ctype cmp cond andcm 14 x2 ta c)
+ )
+)
+
+(define-pmacro (I-A7-cmp cmp x2)
+ (begin
+ (I-A7-cmp-cond cmp gt x2 0 0)
+ (I-A7-cmp-cond cmp le x2 0 1)
+ (I-A7-cmp-cond cmp ge x2 1 0)
+ (I-A7-cmp-cond cmp lt x2 1 1)
+ )
+)
+
+(I-A7-cmp cmp 0)
+(I-A7-cmp cmp4 1)
+
+(define-pmacro (I-A8 mnemonic ctype-attr op x2 ta c)
+ (dni (.sym mnemonic)
+ (.str "Integer Compare, imm8-reg, " mnemonic)
+ ((FORMAT A7) (FIELD-CTYPE ctype-attr))
+ (.str mnemonic " $p1,$p2=$imm8,$r3")
+ (+ (f-opcode op) (f-35-2 x2) (f-33-1 ta) (f-12-1 c)
+ p2 r3 imm8 p1 qp)
+ ()
+ ()
+ )
+)
+
+(define-pmacro (I-A8-cmp-cond-ctype cmp cond ctype op x2 ta c)
+ (I-A8 (.sym cmp "." cond
+ (.eval (if (eq? (string-length ctype) 0) "" "."))
+ ctype)
+ (.eval (if (eq? (string-length ctype) 0) 'NONE (string->symbol ctype)))
+ op x2 ta c)
+)
+
+(define-pmacro (I-A8-cmp cmp x2)
+ (begin
+ (I-A8-cmp-cond-ctype cmp lt "" 12 x2 0 0)
+ (I-A8-cmp-cond-ctype cmp ltu "" 13 x2 0 0)
+ (I-A8-cmp-cond-ctype cmp eq "" 14 x2 0 0)
+
+ (I-A8-cmp-cond-ctype cmp lt "unc" 12 x2 0 1)
+ (I-A8-cmp-cond-ctype cmp ltu "unc" 13 x2 0 1)
+ (I-A8-cmp-cond-ctype cmp eq "unc" 14 x2 0 1)
+
+ (I-A8-cmp-cond-ctype cmp eq "and" 12 x2 1 0)
+ (I-A8-cmp-cond-ctype cmp eq "or" 12 x2 1 0)
+ (I-A8-cmp-cond-ctype cmp eq "or.andcm" 12 x2 1 0)
+
+ (I-A8-cmp-cond-ctype cmp ne "and" 12 x2 1 1)
+ (I-A8-cmp-cond-ctype cmp ne "or" 12 x2 1 1)
+ (I-A8-cmp-cond-ctype cmp ne "or.andcm" 12 x2 1 1)
+ )
+)
+
+(I-A8-cmp cmp 2)
+(I-A8-cmp cmp4 3)
+
+(define-pmacro (I-A9 mnemonic op x2a za zb x4 x2b)
+ (dni (.str mnemonic)
+ (.str "Multimetia ALU, " mnemonic)
+ ((FORMAT A9))
+ (.str mnemonic " $r1=$r2,$r3")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-4 x4)
+ (f-28-2 x2b) r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A9 padd1 8 1 0 0 0 0)
+(I-A9 padd2 8 1 0 1 0 0)
+(I-A9 padd4 8 1 1 0 0 0)
+(I-A9 padd1.sss 8 1 0 0 0 1)
+(I-A9 padd2.sss 8 1 0 1 0 1)
+(I-A9 padd1.uuu 8 1 0 0 0 2)
+(I-A9 padd2.uuu 8 1 0 1 0 2)
+(I-A9 padd1.uus 8 1 0 0 0 3)
+(I-A9 padd2.uus 8 1 0 1 0 3)
+
+(I-A9 psub1 8 1 0 0 1 0)
+(I-A9 psub2 8 1 0 1 1 0)
+(I-A9 psub4 8 1 1 0 1 0)
+(I-A9 psub1.sss 8 1 0 0 1 1)
+(I-A9 psub2.sss 8 1 0 1 1 1)
+(I-A9 psub1.uuu 8 1 0 0 1 2)
+(I-A9 psub2.uuu 8 1 0 1 1 2)
+(I-A9 psub1.uus 8 1 0 0 1 3)
+(I-A9 psub2.uus 8 1 0 1 1 3)
+
+(I-A9 pavg1 8 1 0 0 2 2)
+(I-A9 pavg2 8 1 0 1 2 2)
+(I-A9 pavg1.raz 8 1 0 0 2 3)
+(I-A9 pavg2.raz 8 1 0 1 2 3)
+
+(I-A9 pavgsub1 8 1 0 0 3 2)
+(I-A9 pavgsub2 8 1 0 1 3 2)
+
+(I-A9 pcmp1.eq 8 1 0 0 9 0)
+(I-A9 pcmp2.eq 8 1 0 1 9 0)
+(I-A9 pcmp4.eq 8 1 1 0 9 0)
+(I-A9 pcmp1.gt 8 1 0 0 9 1)
+(I-A9 pcmp2.gt 8 1 0 1 9 1)
+(I-A9 pcmp4.gt 8 1 1 0 9 1)
+
+(define-pmacro (I-A10 mnemonic op x2a za zb x4)
+ (dni mnemonic
+ (.str "Multimedia Shift and Add, " mnemonic)
+ ((FORMAT A10))
+ (.str mnemonic " $r1=$r2,$count2b,$r3")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-4 x4)
+ count2b r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-A10 pshladd2 8 1 0 1 4)
+(I-A10 pshradd2 8 1 0 1 6)
+
+;;; "I" Format Instruction definitions.
+
+(define-pmacro (I-I1 mnemonic op za zb ve x2a x2b)
+ (dni mnemonic
+ (.str "Multimedia Multiply and Shift, " mnemonic)
+ ((FORMAT I1))
+ (.str mnemonic " $r1=$r2,$r3,$count2c")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-29-2 x2b) count2c ign_27_1 r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I1 pmpyshr2 7 0 1 0 0 3)
+(I-I1 pmpyshr2.u 7 0 1 0 0 1)
+
+(define-pmacro (I-I2 mnemonic op za zb ve x2a x2b x2c)
+ (dni mnemonic
+ (.str "Multimedia Multiply/Mix/Pack/Unpack, " mnemonic)
+ ((FORMAT I2))
+ (.str mnemonic " $r1=$r2,$r3")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_1 r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I2 pmpy2.r 7 0 1 0 2 1 3)
+(I-I2 pmpy2.l 7 0 1 0 2 3 3)
+
+(I-I2 mix1.r 7 0 0 0 2 0 2)
+(I-I2 mix2.r 7 0 1 0 2 0 2)
+(I-I2 mix4.r 7 1 0 0 2 0 2)
+(I-I2 mix1.l 7 0 0 0 2 2 2)
+(I-I2 mix2.l 7 0 1 0 2 2 2)
+(I-I2 mix4.l 7 1 0 0 2 2 2)
+
+(I-I2 pack2.uss 7 0 1 0 2 0 0)
+(I-I2 pack2.sss 7 0 1 0 2 2 0)
+(I-I2 pack4.sss 7 1 0 0 2 2 0)
+
+(I-I2 unpack1.h 7 0 0 0 2 0 1)
+(I-I2 unpack2.h 7 0 1 0 2 0 1)
+(I-I2 unpack4.h 7 1 0 0 2 0 1)
+(I-I2 unpack1.l 7 0 0 0 2 2 1)
+(I-I2 unpack2.l 7 0 1 0 2 2 1)
+(I-I2 unpack4.l 7 1 0 0 2 2 1)
+
+(I-I2 pmin1.u 7 0 0 0 2 1 0)
+(I-I2 pmax1.u 7 0 0 0 2 1 1)
+(I-I2 pmin2 7 0 1 0 2 3 0)
+(I-I2 pmax2 7 0 1 0 2 3 1)
+
+(I-I2 psad1 7 0 0 0 2 3 2)
+
+(define-pmacro (I-I3 mnemonic op za zb ve x2a x2b x2c)
+ (dni mnemonic
+ (.str "Multimedia Mux1, " mnemonic)
+ ((FORMAT I3))
+ (.str mnemonic " $r1=$r2,$mbtype4")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_4 mbtype4 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I3 mux1 7 0 0 0 3 2 2)
+
+(define-pmacro (I-I4 mnemonic op za zb ve x2a x2b x2c)
+ (dni mnemonic
+ (.str "Multimedia Mux2, " mnemonic)
+ ((FORMAT I4))
+ (.str mnemonic " $r1=$r2,$mhtype8")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) mhtype8 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I4 mux2 7 0 1 0 3 2 2)
+
+(define-pmacro (I-I5 mnemonic op za zb ve x2a x2b x2c)
+ (dni mnemonic
+ (.str "Shift Right, variable, " mnemonic)
+ ((FORMAT I5))
+ (.str mnemonic " $r1=$r3,$r2")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_1 r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I5 pshr2 7 0 1 0 0 2 0)
+(I-I5 pshr4 7 1 0 0 0 2 0)
+(I-I5 shr 7 1 1 0 0 2 0)
+
+(I-I5 pshr2.u 7 0 1 0 0 0 0)
+(I-I5 pshr4.u 7 1 0 0 0 0 0)
+(I-I5 shr.u 7 1 1 0 0 0 0)
+
+(define-pmacro (I-I6 mnemonic op za zb ve x2a x2b x2c)
+ (dni (.sym mnemonic "i")
+ (.str "Shift Right, fixed, " mnemonic)
+ ((FORMAT I6))
+ (.str mnemonic " $r1=$r3,$count5")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_1 r3 ign_19_1 count5 ign_13_1
+ r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I6 pshr2 7 0 1 0 1 3 0)
+(I-I6 pshr4 7 1 0 0 1 3 0)
+(I-I6 pshr2.u 7 0 1 0 1 1 0)
+(I-I6 pshr4.u 7 1 0 0 1 1 0)
+
+(define-pmacro (I-I7 mnemonic op za zb ve x2a x2b x2c)
+ (dni mnemonic
+ (.str "Shift Left, variable, " mnemonic)
+ ((FORMAT I7))
+ (.str mnemonic " $r1=$r2,$r3")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_1 r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I7 pshl2 7 0 1 0 0 0 1)
+(I-I7 pshl4 7 1 0 0 0 0 1)
+(I-I7 shl 7 1 1 0 0 0 1)
+
+(define-pmacro (I-I8 mnemonic op za zb ve x2a x2b x2c)
+ (dni (.sym mnemonic "i")
+ (.str "Shift Left, fixed, " mnemonic)
+ ((FORMAT I8))
+ (.str mnemonic " $r1=$r2,$ccount5")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_3 ccount5 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I8 pshl2 7 0 1 0 0 0 1)
+(I-I8 pshl4 7 1 0 0 0 0 1)
+
+(define-pmacro (I-I9 mnemonic op za zb ve x2a x2b x2c)
+ (dni mnemonic
+ (.str "Population Count, " mnemonic)
+ ((FORMAT I9))
+ (.str mnemonic " $r1=$r3")
+ (+ (f-opcode op) (f-36-1 za) (f-35-2 x2a) (f-33-1 zb) (f-32-1 ve)
+ (f-31-2 x2c) (f-29-2 x2b) ign_27_1 r3 (f-19-7 0) r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I9 popcnt 7 0 1 0 1 1 2)
+
+(define-pmacro (I-I10 mnemonic op x2 x)
+ (dni mnemonic
+ (.str "Shift Right Pair, " mnemonic)
+ ((FORMAT I10))
+ (.str mnemonic " $r1=$r2,$r3,$count6")
+ (+ (f-opcode op) ign_36_1 (f-35-2 x2) (f-33-1 x) count6 r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I10 shrp 5 3 0)
+
+(define-pmacro (I-I11 mnemonic op x2 x y)
+ (dni mnemonic
+ (.str "Extract, " mnemonic)
+ ((FORMAT I11))
+ (.str mnemonic " $r1=$r3,$pos6,$len6")
+ (+ (f-opcode op) ign_36_1 (f-35-2 x2) (f-33-1 x) (f-13-1 y)
+ r3 pos6 len6 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I11 extr.u 5 1 0 0)
+(I-I11 extr 5 1 0 1)
+
+(define-pmacro (I-I12 mnemonic op x2 x y)
+ (dni mnemonic
+ (.str "Zero and Deposit, " mnemonic)
+ ((FORMAT I12))
+ (.str mnemonic " $r1=$r2,$cpos6a,$len6")
+ (+ (f-opcode op) ign_36_1 (f-35-2 x2) (f-33-1 x) (f-26-1 y)
+ r2 cpos6a len6 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I12 dep.z 5 1 1 0)
+
+(define-pmacro (I-I13 mnemonic op x2 x y)
+ (dni (.sym mnemonic "i")
+ (.str "Zero and Deposit Immediate, " mnemonic)
+ ((FORMAT I13))
+ (.str mnemonic " $r1=$imm8,$cpos6a,$len6")
+ (+ (f-opcode op) (f-35-2 x2) (f-33-1 x) (f-26-1 y)
+ imm8 cpos6a len6 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I13 dep.z 5 1 1 0)
+
+(define-pmacro (I-I14 mnemonic op x2 x)
+ (dni (.sym mnemonic "i")
+ (.str "Deposit Immediate, " mnemonic)
+ ((FORMAT I14))
+ (.str mnemonic " $r1=$imm1,$r3,$cpos6b,$len6")
+ (+ (f-opcode op) (f-35-2 x2) (f-33-1 x) ign_13_1
+ imm1 r3 cpos6b len6 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I14 dep 5 3 1)
+
+(define-pmacro (I-I15 mnemonic op)
+ (dni mnemonic
+ (.str "Deposit, " mnemonic)
+ ((FORMAT I15))
+ (.str mnemonic " $r1=$r2,$r3,$cpos6c,$len4")
+ (+ (f-opcode op) cpos6c len4 r2 r3 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I15 dep 4)
+
+(define-pmacro (I-I16 mnemonic ctype-attr op x2 ta tb y c)
+ (dni mnemonic
+ (.str "Test Bit, " mnemonic)
+ ((FORMAT I16) (FIELD-CTYPE ctype-attr))
+ (.str mnemonic " $p1,$p2=$r3,$pos6")
+ (+ (f-opcode op) (f-36-1 tb) (f-35-2 x2) (f-33-1 ta) (f-13-1 y)
+ (f-12-1 c) p2 r3 pos6 p1 qp)
+ ()
+ ()
+ )
+)
+
+(define-pmacro (I-I16-ctype mnemonic ctype op x2 ta tb y c)
+ (I-I16 (.sym mnemonic
+ (.eval (if (eq? (string-length ctype) 0) "" "."))
+ ctype)
+ (.eval (if (eq? (string-length ctype) 0) 'NONE
+ (string->symbol ctype)))
+ op x2 ta tb y c)
+)
+
+(I-I16-ctype tbit.z "" 5 0 0 0 0 0)
+(I-I16-ctype tbit.z "unc" 5 0 0 0 0 1)
+(I-I16-ctype tbit.z "and" 5 0 0 1 0 0)
+(I-I16-ctype tbit.nz "and" 5 0 0 1 0 1)
+(I-I16-ctype tbit.z "or" 5 0 1 0 0 0)
+(I-I16-ctype tbit.nz "or" 5 0 1 0 0 1)
+(I-I16-ctype tbit.z "or.andcm" 5 0 1 1 0 0)
+(I-I16-ctype tbit.nz "or.andcm" 5 0 1 1 0 1)
+
+(define-pmacro (I-I17 mnemonic ctype-attr op x2 ta tb y c)
+ (dni mnemonic
+ (.str "Test Bit, " mnemonic)
+ ((FORMAT I17) (FIELD-CTYPE ctype-attr))
+ (.str mnemonic " $p1,$p2=$r3")
+ (+ (f-opcode op) (f-36-1 tb) (f-35-2 x2) (f-33-1 ta) (f-13-1 y)
+ (f-12-1 c) p2 r3 ign_19_6 p1 qp)
+ ()
+ ()
+ )
+)
+
+(define-pmacro (I-I17-ctype mnemonic ctype op x2 ta tb y c)
+ (I-I17 (.sym mnemonic
+ (.eval (if (eq? (string-length ctype) 0) "" "."))
+ ctype)
+ (.eval (if (eq? (string-length ctype) 0) 'NONE
+ (string->symbol ctype)))
+ op x2 ta tb y c)
+)
+
+(I-I17-ctype tnat.z "" 5 0 0 0 0 0)
+(I-I17-ctype tnat.z "unc" 5 0 0 0 0 1)
+(I-I17-ctype tnat.z "and" 5 0 0 1 0 0)
+(I-I17-ctype tnat.nz "and" 5 0 0 1 0 1)
+(I-I17-ctype tnat.z "or" 5 0 1 0 0 0)
+(I-I17-ctype tnat.nz "or" 5 0 1 0 0 1)
+(I-I17-ctype tnat.z "or.andcm" 5 0 1 1 0 0)
+(I-I17-ctype tnat.nz "or.andcm" 5 0 1 1 0 1)
+
+(define-pmacro (I-I18 mnemonic op vc)
+ (dni mnemonic
+ (.str "Move Long Immediate, " mnemonic)
+ ((FORMAT I18))
+ (.str mnemonic " $r1=$imm64")
+ (+ (f-opcode op) (f-20-1 vc) r1 imm64 qp)
+ ()
+ ()
+ )
+)
+
+(I-I18 movl 6 0)
+
+(define-pmacro (I-I19 mnemonic op x3 x6)
+ (dni mnemonic
+ (.str "Break/Nop, " mnemonic)
+ ((FORMAT I19))
+ (.str mnemonic " $imm21")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_26_1 imm21 qp)
+ ()
+ ()
+ )
+)
+
+(I-I19 break.i 0 0 0)
+(I-I19 nop.i 0 0 1)
+
+(define-pmacro (I-I20 mnemonic op x3)
+ (dni mnemonic
+ (.str "Integer Speculation Check, " mnemonic)
+ ((FORMAT I20))
+ (.str mnemonic " $r2,$tgt25a")
+ (+ (f-opcode op) (f-35-3 x3) tgt25a r2 qp)
+ ()
+ ()
+ )
+)
+
+(I-I20 chk.s.i 0 1)
+
+(define-pmacro (I-I21 mnemonic op x3 x)
+ (dni (.sym mnemonic _tbr)
+ (.str "Move to BR, " mnemonic)
+ ((FORMAT I21))
+ (.str mnemonic
+ "$movbr_mwh$movbr_ih $b1=$r2,$tag13a")
+ (+ (f-opcode op) (f-35-3 x3) movbr_ih (f-22-1 x) movbr_mwh
+ (f-12-1 x) (f-11-3 x3) ign_36_1 b1 r2 tag13a qp)
+ ()
+ ()
+ )
+)
+
+(I-I21 mov 0 7 0)
+(I-I21 mov.ret 0 7 1)
+
+(define-pmacro (I-I22 mnemonic op x3 x6)
+ (dni (.sym mnemonic _fbr)
+ (.str "Move from BR, " mnemonic)
+ ((FORMAT I22))
+ (.str mnemonic " $r1=$b2")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1 ign_26_11
+ r1 b2 qp)
+ ()
+ ()
+ )
+)
+
+(I-I22 mov 0 0 #x31)
+
+(define-pmacro (I-I23 mnemonic op x3)
+ (dni (.sym mnemonic _tpr)
+ (.str "Move to PR, reg, " mnemonic)
+ ((FORMAT I23))
+ (.str mnemonic " pr=$r2,$imm17")
+ (+ (f-opcode op) (f-35-3 x3) ign_32_1 ign_23_4 r2 imm17 qp)
+ ()
+ ()
+ )
+)
+
+(I-I23 mov 0 3)
+
+(define-pmacro (I-I24 mnemonic op x3)
+ (dni (.sym mnemonic _tpri)
+ (.str "Move to PR, imm, " mnemonic)
+ ((FORMAT I24))
+ (.str mnemonic " pr.rot=$imm44")
+ (+ (f-opcode op) (f-35-3 x3) imm44 qp)
+ ()
+ ()
+ )
+)
+
+(I-I24 mov 0 2)
+
+(define-pmacro (I-I25 mnemonic src op x3 x6)
+ (dni (.sym mnemonic _f src)
+ (.str "Move from Pred/IP, " mnemonic)
+ ((FORMAT I25))
+ (.str mnemonic " $r1=" src)
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_26_7 ign_19_7 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I25 mov ip 0 0 #x30)
+(I-I25 mov pr 0 0 #x33)
+
+(define-pmacro (I-I26 mnemonic op x3 x6)
+ (dni (.sym mnemonic _tar)
+ (.str "Move to AR, reg, " mnemonic)
+ ((FORMAT I26))
+ (.str mnemonic " $ar3=$r2")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1 ign_12_7 ar3 r2 qp)
+ ()
+ ()
+ )
+)
+
+(I-I26 mov.i 0 0 #x2A)
+
+(define-pmacro (I-I27 mnemonic op x3 x6)
+ (dni (.sym mnemonic _tari)
+ (.str "Move to AR, imm, " mnemonic)
+ ((FORMAT I27))
+ (.str mnemonic " $ar3=$imm8")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_12_7 ar3 imm8 qp)
+ ()
+ ()
+ )
+)
+
+(I-I27 mov.i 0 0 #x0A)
+
+(define-pmacro (I-I28 mnemonic op x3 x6)
+ (dni (.sym mnemonic _far)
+ (.str "Move from AR, " mnemonic)
+ ((FORMAT I28))
+ (.str mnemonic " $r1=$ar3")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1 ign_19_7 ar3 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I28 mov.i 0 0 #x32)
+
+(define-pmacro (I-I29 mnemonic op x3 x6)
+ (dni mnemonic
+ (.str "Sign/Zero Extend/Compute Zero Index, " mnemonic)
+ ((FORMAT I29))
+ (.str mnemonic " $r1=$r3")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1 ign_19_7 r3 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-I29 zxt1 0 0 #x10)
+(I-I29 zxt2 0 0 #x11)
+(I-I29 zxt4 0 0 #x12)
+
+(I-I29 sxt1 0 0 #x14)
+(I-I29 sxt2 0 0 #x15)
+(I-I29 sxt4 0 0 #x16)
+
+(I-I29 czx1.l 0 0 #x18)
+(I-I29 czx2.l 0 0 #x19)
+(I-I29 czx1.r 0 0 #x1C)
+(I-I29 czx2.r 0 0 #x1D)
+
+;;; "M" Format Instruction definitions.
+
+(define-pmacro (apply-ildspec macro mnemonic x6-2)
+ (begin
+ (.apply macro (.splice mnemonic x6-2))
+ (.apply macro (.splice (.sym mnemonic .s) (.eval (+ x6-2 #x04))))
+ (.apply macro (.splice (.sym mnemonic .a) (.eval (+ x6-2 #x08))))
+ (.apply macro (.splice (.sym mnemonic .sa) (.eval (+ x6-2 #x0C))))
+ (.apply macro (.splice (.sym mnemonic .bias) (.eval (+ x6-2 #x10))))
+ (.apply macro (.splice (.sym mnemonic .acq) (.eval (+ x6-2 #x14))))
+ (.apply macro (.splice (.sym mnemonic .c.clr) (.eval (+ x6-2 #x20))))
+ (.apply macro (.splice (.sym mnemonic .c.nc) (.eval (+ x6-2 #x24))))
+ (.apply macro (.splice (.sym mnemonic .c.clr.acq) (.eval (+ x6-2 #x28))))
+ )
+)
+
+(define-pmacro (I-M1 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Integer Load, " mnemonic)
+ ((FORMAT M1))
+ (.str mnemonic "$ldhint $r1=[$r3]")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) ldhint (f-27-1 x)
+ r3 r1 ign_19_7 qp)
+ ()
+ ()
+ )
+)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M1 mnemonic 4 0 0 x6))
+ ld1 0)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M1 mnemonic 4 0 0 x6))
+ ld2 1)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M1 mnemonic 4 0 0 x6))
+ ld4 2)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M1 mnemonic 4 0 0 x6))
+ ld8 3)
+
+(I-M1 ld8.fill 4 0 0 #x1B)
+
+(define-pmacro (I-M2 mnemonic op m x x6)
+ (dni (.sym mnemonic .ir)
+ (.str "Integer Load, incr reg, " mnemonic)
+ ((FORMAT M2))
+ (.str mnemonic "$ldhint $r1=[$r3],$r2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) ldhint (f-27-1 x)
+ r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M2 mnemonic 4 1 0 x6))
+ ld1 0)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M2 mnemonic 4 1 0 x6))
+ ld2 1)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M2 mnemonic 4 1 0 x6))
+ ld4 2)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M2 mnemonic 4 1 0 x6))
+ ld8 3)
+
+(I-M2 ld8.fill 4 1 0 #x1B)
+
+(define-pmacro (I-M3 mnemonic op x6)
+ (dni (.sym mnemonic .ii)
+ (.str "Integer Load, incr imm, " mnemonic)
+ ((FORMAT M3))
+ (.str mnemonic "$ldhint $r1=[$r3],$imm9a")
+ (+ (f-opcode op) (f-35-6 x6) ldhint r3 imm9a r1 qp)
+ ()
+ ()
+ )
+)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M3 mnemonic 5 x6))
+ ld1 0)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M3 mnemonic 5 x6))
+ ld2 1)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M3 mnemonic 5 x6))
+ ld4 2)
+
+(apply-ildspec
+ (.pmacro (mnemonic x6)
+ (I-M3 mnemonic 5 x6))
+ ld8 3)
+
+(I-M3 ld8.fill 5 #x1B)
+
+(define-pmacro (apply-istspec macro mnemonic x6-2)
+ (begin
+ (.apply macro (.splice mnemonic x6-2))
+ (.apply macro (.splice (.sym mnemonic .rel) (.eval (+ x6-2 #x04))))
+ )
+)
+
+(define-pmacro (I-M4 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Integer Store, " mnemonic)
+ ((FORMAT M4))
+ (.str mnemonic "$sthint [$r3]=$r2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) (f-27-1 x)
+ sthint r3 r2 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M4 mnemonic 4 0 0 x6))
+ st1 #x30)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M4 mnemonic 4 0 0 x6))
+ st2 #x31)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M4 mnemonic 4 0 0 x6))
+ st4 #x32)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M4 mnemonic 4 0 0 x6))
+ st8 #x33)
+
+(I-M4 st8.spill 4 0 0 #x3B)
+
+(define-pmacro (I-M5 mnemonic op x6)
+ (dni (.sym mnemonic .ii)
+ (.str "Integer Store, incr imm, " mnemonic)
+ ((FORMAT M5))
+ (.str mnemonic "$sthint [$r3]=$r2,$imm9b")
+ (+ (f-opcode op) (f-35-6 x6) sthint r3 imm9b r2 qp)
+ ()
+ ()
+ )
+)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M5 mnemonic 5 x6))
+ st1 #x30)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M5 mnemonic 5 x6))
+ st2 #x31)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M5 mnemonic 5 x6))
+ st4 #x32)
+
+(apply-istspec
+ (.pmacro (mnemonic x6)
+ (I-M5 mnemonic 5 x6))
+ st8 #x33)
+
+(I-M5 st8.spill 5 #x3B)
+
+(define-pmacro (apply-fldspec macro mnemonic x6-2)
+ (begin
+ (.apply macro (.splice mnemonic x6-2))
+ (.apply macro (.splice (.sym mnemonic .s) (.eval (+ x6-2 #x04))))
+ (.apply macro (.splice (.sym mnemonic .a) (.eval (+ x6-2 #x08))))
+ (.apply macro (.splice (.sym mnemonic .sa) (.eval (+ x6-2 #x0C))))
+ (.apply macro (.splice (.sym mnemonic .c.clr) (.eval (+ x6-2 #x20))))
+ (.apply macro (.splice (.sym mnemonic .c.nc) (.eval (+ x6-2 #x24))))
+ )
+)
+
+(define-pmacro (I-M6 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Floating-point Load, " mnemonic)
+ ((FORMAT M6))
+ (.str mnemonic "$ldhint $f1=[$r3]")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) ldhint (f-27-1 x)
+ r3 f1 ign_19_7 qp)
+ ()
+ ()
+ )
+)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M6 mnemonic 6 0 0 x6))
+ ldfs 2)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M6 mnemonic 6 0 0 x6))
+ ldfd 3)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M6 mnemonic 6 0 0 x6))
+ ldf8 1)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M6 mnemonic 6 0 0 x6))
+ ldfe 0)
+
+(I-M6 ldf.fill 6 0 0 #x1B)
+
+(define-pmacro (I-M7 mnemonic op m x x6)
+ (dni (.sym mnemonic .ir)
+ (.str "Floating-point Load, incr reg, " mnemonic)
+ ((FORMAT M7))
+ (.str mnemonic "$ldhint $f1=[$r3],$r2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) ldhint (f-27-1 x)
+ r3 r2 f1 qp)
+ ()
+ ()
+ )
+)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M7 mnemonic 6 1 0 x6))
+ ldfs 2)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M7 mnemonic 6 1 0 x6))
+ ldfd 3)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M7 mnemonic 6 1 0 x6))
+ ldf8 1)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M7 mnemonic 6 1 0 x6))
+ ldfe 0)
+
+(I-M7 ldf.fill 6 1 0 #x1B)
+
+(define-pmacro (I-M8 mnemonic op x6)
+ (dni (.sym mnemonic .ii)
+ (.str "Floating-point Load, incr imm, " mnemonic)
+ ((FORMAT M8))
+ (.str mnemonic "$ldhint $f1=[$r3],$imm9a")
+ (+ (f-opcode op) (f-35-6 x6) ldhint r3 imm9a f1 qp)
+ ()
+ ()
+ )
+)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M8 mnemonic 7 x6))
+ ldfs 2)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M8 mnemonic 7 x6))
+ ldfd 3)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M8 mnemonic 7 x6))
+ ldf8 1)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M8 mnemonic 7 x6))
+ ldfe 0)
+
+(I-M8 ldf.fill 7 #x1B)
+
+(define-pmacro (I-M9 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Floating-point Store, " mnemonic)
+ ((FORMAT M9))
+ (.str mnemonic "$sthint [$r3]=$f2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) (f-27-1 x)
+ sthint r3 f2 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M9 stfs 6 0 0 #x32)
+(I-M9 stfd 6 0 0 #x33)
+(I-M9 stf8 6 0 0 #x31)
+(I-M9 stfe 6 0 0 #x30)
+(I-M9 stf.spill 6 0 0 #x3B)
+
+(define-pmacro (I-M10 mnemonic op x6)
+ (dni (.sym mnemonic .ii)
+ (.str "Floating-point Store, incr imm, " mnemonic)
+ ((FORMAT M10))
+ (.str mnemonic "$sthint [$r3]=$f2,$imm9b")
+ (+ (f-opcode op) (f-35-6 x6) sthint r3 imm9b f2 qp)
+ ()
+ ()
+ )
+)
+
+(I-M10 stfs 7 #x32)
+(I-M10 stfd 7 #x33)
+(I-M10 stf8 7 #x31)
+(I-M10 stfe 7 #x30)
+(I-M10 stf.spill 7 #x3B)
+
+(define-pmacro (I-M11 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Floating-point Load Pair, " mnemonic)
+ ((FORMAT M11))
+ (.str mnemonic "$ldhint $f1,$f2=[$r3]")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) ldhint (f-27-1 x)
+ r3 f1 f2 qp)
+ ()
+ ()
+ )
+)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M11 mnemonic 6 0 1 x6))
+ ldfps 2)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M11 mnemonic 6 0 1 x6))
+ ldfpd 3)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M11 mnemonic 6 0 1 x6))
+ ldfp8 1)
+
+(define-pmacro (I-M12 mnemonic n op m x x6)
+ (dni mnemonic
+ (.str "Floating-point Load Pair, incr imm, " mnemonic)
+ ((FORMAT M12))
+ (.str mnemonic "$ldhint $f1,$f2=[$r3]," n)
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) ldhint (f-27-1 x)
+ r3 f1 f2 qp)
+ ()
+ ()
+ )
+)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M12 mnemonic 8 6 1 1 x6))
+ ldfps 2)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M12 mnemonic 16 6 1 1 x6))
+ ldfpd 3)
+
+(apply-fldspec
+ (.pmacro (mnemonic x6)
+ (I-M12 mnemonic 16 6 1 1 x6))
+ ldfp8 1)
+
+(define-pmacro (apply-lftype macro mnemonic)
+ (begin
+ (.apply macro (.splice mnemonic NONE #x2C))
+ (.apply macro (.splice (.sym mnemonic .excl) NONE #x2D))
+ (.apply macro (.splice (.sym mnemonic .fault) fault #x2E))
+ (.apply macro (.splice (.sym mnemonic .fault.excl) fault #x2F))
+ )
+)
+
+(define-pmacro (I-M13 mnemonic fault-attr op m x x6)
+ (dni (.sym mnemonic)
+ (.str "Line Prefetch, " mnemonic)
+ ((FORMAT M13) (FIELD-LFTYPE fault-attr))
+ (.str mnemonic "$lfhint [$r3]")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) lfhint (f-27-1 x)
+ r3 ign_19_7 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(apply-lftype
+ (.pmacro (mnemonic fault-attr x6)
+ (I-M13 mnemonic fault-attr 6 0 0 x6))
+ lfetch)
+
+(define-pmacro (I-M14 mnemonic fault-attr op m x x6)
+ (dni (.sym mnemonic .ir)
+ (.str "Line Prefetch, incr reg" mnemonic)
+ ((FORMAT M14) (FIELD-LFTYPE fault-attr))
+ (.str mnemonic "$lfhint [$r3],$r2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) lfhint (f-27-1 x)
+ r3 r2 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(apply-lftype
+ (.pmacro (mnemonic fault-attr x6)
+ (I-M14 mnemonic fault-attr 6 0 0 x6))
+ lfetch)
+
+(define-pmacro (I-M15 mnemonic fault-attr op x6)
+ (dni (.sym mnemonic .ii)
+ (.str "Line Prefetch, incr imm" mnemonic)
+ ((FORMAT M15) (FIELD-LFTYPE fault-attr))
+ (.str mnemonic "$lfhint [$r3],$imm9a")
+ (+ (f-opcode op) (f-35-6 x6) lfhint r3 imm9a ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(apply-lftype
+ (.pmacro (mnemonic fault-attr x6)
+ (I-M15 mnemonic fault-attr 7 x6))
+ lfetch)
+
+(define-pmacro (I-M16 mnemonic extra op m x x6)
+ (dni mnemonic
+ (.str "Exchange/Compare and Exchange, " mnemonic)
+ ((FORMAT M16))
+ (.str mnemonic "$ldhint $r1=[$r3],$r2" extra)
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) (f-27-1 x)
+ ldhint r3 r2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M16 cmpxchg1.acq ",ar.ccv" 4 0 1 #x00)
+(I-M16 cmpxchg2.acq ",ar.ccv" 4 0 1 #x01)
+(I-M16 cmpxchg4.acq ",ar.ccv" 4 0 1 #x02)
+(I-M16 cmpxchg8.acq ",ar.ccv" 4 0 1 #x03)
+
+(I-M16 cmpxchg1.rel ",ar.ccv" 4 0 1 #x04)
+(I-M16 cmpxchg2.rel ",ar.ccv" 4 0 1 #x05)
+(I-M16 cmpxchg4.rel ",ar.ccv" 4 0 1 #x06)
+(I-M16 cmpxchg8.rel ",ar.ccv" 4 0 1 #x07)
+
+(I-M16 xchg1.rel "" 4 0 1 #x08)
+(I-M16 xchg2.rel "" 4 0 1 #x09)
+(I-M16 xchg4.rel "" 4 0 1 #x0A)
+(I-M16 xchg8.rel "" 4 0 1 #x0B)
+
+(define-pmacro (I-M17 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Fetch and Add, " mnemonic)
+ ((FORMAT M17))
+ (.str mnemonic "$ldhint $r1=[$r3],$inc3")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) (f-27-1 x)
+ ldhint r3 ign_19_4 inc3 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M17 fetchadd4.acq 4 0 1 #x12)
+(I-M17 fetchadd8.acq 4 0 1 #x13)
+(I-M17 fetchadd4.rel 4 0 1 #x16)
+(I-M17 fetchadd8.rel 4 0 1 #x17)
+
+(define-pmacro (I-M18 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Set FR, " mnemonic)
+ ((FORMAT M18))
+ (.str mnemonic " $f1=$r2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) (f-27-1 x)
+ ign_26_7 ign_29_2 r2 f1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M18 setf.sig 6 0 1 #x1C)
+(I-M18 setf.exp 6 0 1 #x1D)
+(I-M18 setf.s 6 0 1 #x1E)
+(I-M18 setf.d 6 0 1 #x1F)
+
+(define-pmacro (I-M19 mnemonic op m x x6)
+ (dni mnemonic
+ (.str "Get FR, " mnemonic)
+ ((FORMAT M19))
+ (.str mnemonic " $r1=$f2")
+ (+ (f-opcode op) (f-36-1 m) (f-35-6 x6) (f-27-1 x)
+ ign_26_7 ign_29_2 f2 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M19 getf.sig 4 0 1 #x1C)
+(I-M19 getf.exp 4 0 1 #x1D)
+(I-M19 getf.s 4 0 1 #x1E)
+(I-M19 getf.d 4 0 1 #x1F)
+
+(define-pmacro (I-M20 mnemonic op x3)
+ (dni mnemonic
+ (.str "Integer Speculation Check, " mnemonic)
+ ((FORMAT M20))
+ (.str mnemonic " $r2,$tgt25a")
+ (+ (f-opcode op) (f-35-3 x3) r2 tgt25a qp)
+ ()
+ ()
+ )
+)
+
+(I-M20 chk.s.m 1 1)
+
+(define-pmacro (I-M21 mnemonic op x3)
+ (dni (.sym mnemonic .f)
+ (.str "Floating-point Speculation Check, " mnemonic)
+ ((FORMAT M21))
+ (.str mnemonic " $f2,$tgt25a")
+ (+ (f-opcode op) (f-35-3 x3) f2 tgt25a qp)
+ ()
+ ()
+ )
+)
+
+(I-M21 chk.s 1 3)
+
+(define-pmacro (I-M22 mnemonic op x3)
+ (dni mnemonic
+ (.str "Integer Advanced Load Check, " mnemonic)
+ ((FORMAT M22))
+ (.str mnemonic " $r1,$tgt25c")
+ (+ (f-opcode op) (f-35-3 x3) tgt25c r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M22 chk.a.nc 0 4)
+(I-M22 chk.a.clr 0 5)
+
+(define-pmacro (I-M23 mnemonic op x3)
+ (dni (.sym mnemonic .f)
+ (.str "Floating-point Advanced Load Check, " mnemonic)
+ ((FORMAT M23))
+ (.str mnemonic " $f1,$tgt25c")
+ (+ (f-opcode op) (f-35-3 x3) tgt25c f1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M22 chk.a.nc 0 6)
+(I-M22 chk.a.clr 0 7)
+
+(define-pmacro (I-M24 mnemonic op x3 x4 x2)
+ (dni mnemonic
+ (.str "Sync/Fence/Serialize/ALAT Control, " mnemonic)
+ ((FORMAT M24))
+ (.str mnemonic)
+ (+ (f-opcode op) (f-35-3 x3) (f-32-2 x2) (f-30-4 x4)
+ ign_36_1 ign_26_7 ign_19_7 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M24 invala 0 0 0 1)
+(I-M24 fwb 0 0 0 2)
+(I-M24 mf 0 0 2 2)
+(I-M24 mf.a 0 0 3 2)
+(I-M24 srlz.d 0 0 0 3)
+(I-M24 srlz.i 0 0 1 3)
+(I-M24 sync.i 0 0 3 3)
+
+(define-pmacro (I-M25 mnemonic op x3 x4 x2)
+ (dni mnemonic
+ (.str "RSE Control, " mnemonic)
+ ((FORMAT M25))
+ (.str mnemonic)
+ (+ (f-opcode op) (f-35-3 x3) (f-32-2 x2) (f-30-4 x4)
+ ign_36_1 ign_26_7 ign_19_7 ign_12_7 (f-qp 0))
+ ()
+ ()
+ )
+)
+
+(I-M25 flushrs 0 0 #xC 0)
+(I-M25 loadrs 0 0 #xA 0)
+
+(define-pmacro (I-M26 mnemonic op x3 x4 x2)
+ (dni mnemonic
+ (.str "Integer ALAT Entry Invalidate, " mnemonic)
+ ((FORMAT M26))
+ (.str mnemonic " $r1")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-2 x2) (f-30-4 x4)
+ ign_36_1 ign_26_7 ign_19_7 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M26 invala.e 0 0 2 1)
+
+(define-pmacro (I-M27 mnemonic op x3 x4 x2)
+ (dni (.sym mnemonic .f)
+ (.str "Floating-point ALAT Entry Invalidate, " mnemonic)
+ ((FORMAT M27))
+ (.str mnemonic " $f1")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-2 x2) (f-30-4 x4)
+ ign_36_1 ign_26_7 ign_19_7 f1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M27 invala.e 0 0 3 1)
+
+(define-pmacro (I-M28 mnemonic op x3 x6)
+ (dni mnemonic
+ (.str "Flush Cache/Purge Translation Cache Entry, " mnemonic)
+ ((FORMAT M28))
+ (.str mnemonic " $r3")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6)
+ ign_36_1 r3 ign_19_7 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M28 fc 1 0 #x30)
+(I-M28 ptc.e 1 0 #x34)
+
+(define-pmacro (I-M29 mnemonic op x3 x6)
+ (dni (.sym mnemonic _tar)
+ (.str "Move to AR, reg, " mnemonic)
+ ((FORMAT M29))
+ (.str mnemonic " $ar3=$r2")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6)
+ ign_36_1 ar3 r2 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M29 mov.m 1 0 #x2A)
+
+(define-pmacro (I-M30 mnemonic op x3 x4 x2)
+ (dni (.sym mnemonic _tari)
+ (.str "Move to AR, imm," mnemonic)
+ ((FORMAT M30))
+ (.str mnemonic " $ar3=$imm8")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-2 x2) (f-30-4 x4)
+ ar3 imm8 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M30 mov.m 0 0 8 2)
+
+(define-pmacro (I-M31 mnemonic op x3 x6)
+ (dni (.sym mnemonic _far)
+ (.str "Move from AR, " mnemonic)
+ ((FORMAT M31))
+ (.str mnemonic " $r1=$ar3")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1 ign_19_7 ar3 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M31 mov.m 1 0 #x22)
+
+(define-pmacro (I-M32 mnemonic op x3 x6)
+ (dni (.sym mnemonic _tcr)
+ (.str "Move to CR, " mnemonic)
+ ((FORMAT M32))
+ (.str mnemonic " $cr3=$r2")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6)
+ ign_36_1 cr3 r2 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M32 mov 1 0 #x2C)
+
+(define-pmacro (I-M33 mnemonic op x3 x6)
+ (dni (.sym mnemonic _fcr)
+ (.str "Move from CR, " mnemonic)
+ ((FORMAT M33))
+ (.str mnemonic " $r1=$cr3")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6)
+ ign_36_1 cr3 ign_19_7 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M33 mov 1 0 #x24)
+
+(define-pmacro (I-M34 mnemonic op x3)
+ (dni mnemonic
+ (.str "Allocate Register Stack Frame, " mnemonic)
+ ((FORMAT M34))
+ (.str mnemonic " $r1=ar.pfs,$sorsolsof")
+ (+ (f-opcode op) (f-35-3 x3) ign_36_1 ign_32_2
+ sorsolsof r1 (f-qp 0))
+ ()
+ ()
+ )
+)
+
+(I-M34 alloc 1 6)
+
+(define-pmacro (I-M35 mnemonic which op x3 x6)
+ (dni (.sym mnemonic _t which)
+ (.str "Move to PSR, " mnemonic)
+ ((FORMAT M35))
+ (.str mnemonic " " which "=$r2")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1
+ r2 ign_26_7 ign_12_7 qp)
+ ()
+ ()
+ )
+)
+
+(I-M35 mov psr.l 1 0 #x2D)
+(I-M35 mov psr.um 1 0 #x29)
+
+(define-pmacro (I-M36 mnemonic which op x3 x6)
+ (dni (.sym mnemonic _f which)
+ (.str "Move from PSR, " mnemonic)
+ ((FORMAT M35))
+ (.str mnemonic " $r1=" which)
+ (+ (f-opcode op) (f-35-3 x3) (f-32-6 x6) ign_36_1
+ ign_26_7 ign_19_7 r1 qp)
+ ()
+ ()
+ )
+)
+
+(I-M36 mov psr 1 0 #x25)
+(I-M36 mov psr.um 1 0 #x21)
+
+(define-pmacro (I-M37 mnemonic op x3 x4 x2)
+ (dni mnemonic
+ (.str "Break/Nop, " mnemonic)
+ ((FORMAT M37))
+ (.str mnemonic " $imm21")
+ (+ (f-opcode op) (f-35-3 x3) (f-32-2 x2) (f-30-4 x4) ign_26_1 imm21 qp)
+ ()
+ ()
+ )
+)
+
+(I-M37 break.m 0 0 0 0)
+(I-M37 nop.m 0 0 1 0)
+
diff --git a/cgen/ifield.scm b/cgen/ifield.scm
new file mode 100644
index 00000000000..0a47f022391
--- /dev/null
+++ b/cgen/ifield.scm
@@ -0,0 +1,1164 @@
+; Instruction fields.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; The `<ifield>' class.
+; (pronounced "I-field")
+;
+; These describe raw data, little semantic content is attributed to them.
+; The goal being to avoid interfering with future applications.
+;
+; FIXME: Move start, word-offset, word-length into the instruction format?
+; - would require proper ordering of fields in insns, but that's ok.
+; (??? though the sparc64 description shows a case where its useful to
+; not have to worry about instruction ordering - different versions of an
+; insn take different fields and these fields are passed via a macro)
+;
+; ??? One could treat all ifields as being unsigned. They could be thought of
+; as indices into a table of values, be they signed, unsigned, floating point,
+; whatever. Just an idea.
+;
+; ??? Split into two? One for definition, and one for value.
+
+(define <ifield>
+ (class-make '<ifield>
+ '(<ident>)
+ '(
+ ; The mode the raw value is to be interpreted in.
+ mode
+
+ ; A <bitrange> object.
+ ; This contains the field's offset, start, length, word-length,
+ ; and orientation (msb==0, lsb==0). The orientation is
+ ; recorded to keep the <bitrange> object self-contained.
+ ; Endianness is not recorded.
+ bitrange
+
+ ; Argument to :follows, as an object.
+ ; FIXME: wip
+ (follows . #f)
+
+ ; ENCODE/DECODE operate on the raw value, absent of any context
+ ; save `pc' and mode of field.
+ ; If #f, no special processing is required.
+ ; ??? It's not clear where the best place to process fields is.
+ ; An earlier version had insert/extract fields in operands to
+ ; handle more complicated cases. Following the goal of
+ ; incremental complication, the special handling for m32r's
+ ; f-disp8 field is handled entirely here, rather than partially
+ ; here and partially in the operand.
+ encode decode
+
+ ; Value of field, if there is one.
+ ; Possible types are: integer, <operand>, ???
+ value
+ )
+ nil)
+)
+
+; {value},{follows} are missing on purpose
+; {value} is handled specially.
+; {follows} is rarely used
+(method-make-make! <ifield> '(name comment attrs mode bitrange encode decode))
+
+; Accessor fns
+; ??? `value' is treated specially, needed anymore?
+
+(define-getters <ifield> ifld (mode encode decode follows))
+
+(define-setters <ifield> ifld (follows))
+
+; internal fn
+(define -ifld-bitrange (elm-make-getter <ifield> 'bitrange))
+
+(define (ifld-word-offset f) (bitrange-word-offset (-ifld-bitrange f)))
+(define (ifld-word-length f) (bitrange-word-length (-ifld-bitrange f)))
+
+; Return the mode of the value passed to the encode rtl.
+; This is the mode of the result of the decode rtl.
+
+(define (ifld-encode-mode f)
+ (if (ifld-decode f)
+ ; cadr/cadr gets WI in ((value pc) (sra WI ...))
+ (mode:lookup (cadr (cadr (ifld-decode f))))
+ (ifld-mode f))
+)
+
+; Return the mode of the value passed to the decode rtl.
+; This is the mode of the field.
+
+(define (ifld-decode-mode f) (ifld-mode f))
+
+; Return start of ifield.
+; WORD-LEN is the length of the word in which to compute the value or
+; #f meaning to use the default length (recorded with the bitrange).
+; WORD-LEN is present for architectures like the m32r where there are insns
+; smaller than the base insn size (LIW).
+; ??? Not sure it'll be applicable to other LIW architectures. The m32r is
+; rather easy as the insns are 16 and 32 bits.
+; ??? Another way to do this would be to either set the base-insn-size for
+; the m32r to be 16 bits, or to add a new field to hold the insn-word-size
+; and set it to 16 for the m32r. The problem here is that there is no
+; canonicalization that works regardless of whether a "word" is shortened
+; or lengthened.
+
+(method-make-virtual!
+ <ifield> 'field-start
+ (lambda (self word-len)
+ (let* ((bitrange (-ifld-bitrange self))
+ (lsb0? (bitrange-lsb0? bitrange))
+ (recorded-word-len (bitrange-word-length bitrange))
+ (wanted-word-len (or word-len recorded-word-len)))
+ ; Note that this is only intended for situations like the m32r.
+ ; If it doesn't work elsewhere, it may be that you need to
+ ; do things different (use two fields instead of one).
+ (cond ((= wanted-word-len recorded-word-len)
+ (bitrange-start bitrange))
+ ((< wanted-word-len recorded-word-len)
+ ; smaller word wanted
+ (if lsb0?
+ (- (bitrange-start bitrange) (- recorded-word-len
+ wanted-word-len))
+ (bitrange-start bitrange)))
+ (else
+ ; larger word wanted
+ (if lsb0?
+ (+ (bitrange-start bitrange) (- wanted-word-len
+ recorded-word-len))
+ (bitrange-start bitrange))))))
+)
+
+(define (ifld-start ifld word-len)
+ (send ifld 'field-start word-len)
+)
+
+(method-make-virtual!
+ <ifield> 'field-length
+ (lambda (self)
+ (bitrange-length (elm-get self 'bitrange)))
+)
+
+(define (ifld-length f) (send f 'field-length))
+
+; FIXME: It might make things more "readable" if enum values were preserved in
+; their symbolic form and the get-field-value method did the lookup.
+
+(method-make!
+ <ifield> 'get-field-value
+ (lambda (self)
+ (elm-get self 'value))
+)
+(define (ifld-get-value self)
+ (send self 'get-field-value)
+)
+(method-make!
+ <ifield> 'set-field-value!
+ (lambda (self new-val)
+ (elm-set! self 'value new-val))
+)
+(define (ifld-set-value! self new-val)
+ (send self 'set-field-value! new-val)
+)
+
+; Return a boolean indicating if X is an <ifield>.
+
+(define (ifield? x) (class-instance? <ifield> x))
+
+; Return ilk of field.
+; ("ilk" sounds klunky but "type" is too ambiguous. Here "ilk" means
+; the kind of the hardware element, enum, etc.)
+; The result is a character string naming the field type.
+
+(define (ifld-ilk fld)
+ (let ((value (elm-xget fld 'value)))
+ ; ??? One could require that the `value' field always be an object.
+ ; I can't get too worked up over it yet.
+ (if (object? value)
+ (obj:name value) ; send's message 'get-name to fetch object's `name'
+ "#")) ; # -> "it's a number"
+)
+
+; Generate the name of the enum for instruction field ifld.
+; If PREFIX? is present and #f, the @ARCH@_ prefix is omitted.
+
+(define (ifld-enum ifld . prefix?)
+ (string-upcase (string-append (if (or (null? prefix?) (car prefix?))
+ "@ARCH@_"
+ "")
+ (gen-sym ifld)))
+)
+
+; Return a boolean indicating if ifield F is an opcode field
+; (has a constant value).
+
+(define (ifld-constant? f)
+ (number? (ifld-get-value f))
+; (and (number? (ifld-get-value f))
+; (if option:reserved-as-opcode?
+; #t
+; (not (has-attr? f 'RESERVED))))
+)
+
+; Return a boolean indicating if ifield F is an operand.
+; FIXME: Should check for operand? or some such.
+
+(define (ifld-operand? f) (not (number? (ifld-get-value f))))
+
+; Return known value table for rtx-simplify of <ifield> list ifld-list.
+
+(define (ifld-known-values ifld-list)
+ (let ((constant-iflds (find ifld-constant? (collect ifld-base-ifields ifld-list))))
+ (map (lambda (f)
+ (cons (obj:name f)
+ (rtx-make-const 'INT (ifld-get-value f))))
+ constant-iflds))
+)
+
+; Return mask to use for a field in <bitrange> CONTAINER.
+; If the bitrange is outside the range of the field, return 0.
+; If CONTAINER is #f, use the recorded bitrange.
+; BASE-LEN, if non-#f, overrides the base insn length of the insn.
+; BASE-LEN is present for architectures like the m32r where there are insns
+; smaller than the base insn size (LIW).
+;
+; Simplifying restrictions [to be relaxed as necessary]:
+; - the field must either be totally contained within CONTAINER or totally
+; outside it, partial overlaps aren't handled
+; - CONTAINER must be an integral number of bytes, beginning on a
+; byte boundary [simplifies things]
+; - both SELF's bitrange and CONTAINER must have the same word length
+; - LSB0? of SELF's bitrange and CONTAINER must be the same
+
+(method-make!
+ <ifield> 'field-mask
+ (lambda (self base-len container)
+ (let* ((container (or container (-ifld-bitrange self)))
+ (bitrange (-ifld-bitrange self))
+ (recorded-word-length (bitrange-word-length bitrange))
+ (word-offset (bitrange-word-offset bitrange)))
+ (let ((lsb0? (bitrange-lsb0? bitrange))
+ (start (bitrange-start bitrange))
+ (length (bitrange-length bitrange))
+ (word-length (or (and (= word-offset 0) base-len)
+ recorded-word-length))
+ (container-word-offset (bitrange-word-offset container))
+ (container-word-length (bitrange-word-length container)))
+ (cond
+ ; must be same lsb0
+ ((not (eq? lsb0? (bitrange-lsb0? container)))
+ (error "field-mask: different lsb0? values"))
+ ((not (= word-length container-word-length))
+ 0)
+ ; container occurs after?
+ ((<= (+ word-offset word-length) container-word-offset)
+ 0)
+ ; container occurs before?
+ ((>= word-offset (+ container-word-offset container-word-length))
+ 0)
+ (else
+ (word-mask start length word-length lsb0? #f))))))
+)
+
+(define (ifld-mask ifld base-len container)
+ (send ifld 'field-mask base-len container)
+)
+
+; Return VALUE inserted into the field's position.
+; BASE-LEN, if non-#f, overrides the base insn length of the insn.
+; BASE-LEN is present for architectures like the m32r where there are insns
+; smaller than the base insn size (LIW).
+
+(method-make!
+ <ifield> 'field-value
+ (lambda (self base-len value)
+ (let* ((bitrange (-ifld-bitrange self))
+ (recorded-word-length (bitrange-word-length bitrange))
+ (word-offset (bitrange-word-offset bitrange))
+ (word-length (or (and (= word-offset 0) base-len)
+ recorded-word-length)))
+ (word-value (ifld-start self base-len)
+ (bitrange-length bitrange)
+ word-length
+ (bitrange-lsb0? bitrange) #f
+ value)))
+)
+
+; FIXME: confusion with ifld-get-value.
+(define (ifld-value f base-len value)
+ (send f 'field-value base-len value)
+)
+
+; Return a list of ifields required to compute <ifield> F's value.
+; Normally this is just F itself. For multi-ifields it will be more.
+; ??? It can also be more if F's value is derived from other fields but
+; that isn't supported yet.
+
+(method-make!
+ <ifield> 'needed-iflds
+ (lambda (self)
+ (list self))
+)
+
+(define (ifld-needed-iflds f)
+ (send f 'needed-iflds)
+)
+
+; Extract <ifield> IFLD's value out of VALUE in <insn> INSN.
+; VALUE is the entire insn's value if it fits in a word, or is a list
+; of values, one per word (not implemented, sigh).
+; ??? The instruction's format should specify where the word boundaries are.
+
+(method-make!
+ <ifield> 'field-extract
+ (lambda (self insn value)
+ (let ((base-len (insn-base-mask-length insn)))
+ (word-extract (ifld-start self base-len)
+ (ifld-length self)
+ base-len
+ (ifld-lsb0? self)
+ #f ; start is msb
+ value)))
+)
+
+(define (ifld-extract ifld value insn)
+ (send ifld 'field-extract value insn)
+)
+
+; Return a boolean indicating if bit 0 is the least significant bit.
+
+(method-make!
+ <ifield> 'field-lsb0?
+ (lambda (self)
+ (bitrange-lsb0? (-ifld-bitrange self)))
+)
+
+(define (ifld-lsb0? f) (send f 'field-lsb0?))
+
+; Return the minimum value of a field.
+
+(method-make!
+ <ifield> 'min-value
+ (lambda (self)
+ (case (mode:class (ifld-mode self))
+ ((INT) (- (integer-expt 2 (- (ifld-length self) 1))))
+ ((UINT) 0)
+ (else (error "unsupported mode class" (mode:class (ifld-mode self))))))
+)
+
+; Return the maximum value of a field.
+
+(method-make!
+ <ifield> 'max-value
+ (lambda (self)
+ (case (mode:class (ifld-mode self))
+ ((INT) (- (integer-expt 2 (- (ifld-length self) 1)) 1))
+ ((UINT) (- (integer-expt 2 (ifld-length self)) 1))
+ (else (error "unsupported mode class" (mode:class (ifld-mode self))))))
+)
+
+; Create a copy of field F with value VALUE.
+; VALUE is either ... ???
+
+(define (ifld-new-value f value)
+ (let ((new-f (object-copy-top f)))
+ (ifld-set-value! new-f value)
+ new-f)
+)
+
+; Change the offset of the word containing an ifield to {word-offset}.
+
+(method-make!
+ <ifield> 'set-word-offset!
+ (lambda (self word-offset)
+ (let ((bitrange (object-copy-top (-ifld-bitrange self))))
+ (bitrange-set-word-offset! bitrange word-offset)
+ (elm-set! self 'bitrange bitrange)
+ *UNSPECIFIED*))
+)
+(define (ifld-set-word-offset! f word-offset)
+ (send f 'set-word-offset! word-offset)
+)
+
+; Return a copy of F with new {word-offset}.
+
+(define (ifld-new-word-offset f word-offset)
+ (let ((new-f (object-copy-top f)))
+ (ifld-set-word-offset! new-f word-offset)
+ new-f)
+)
+
+; Return the bit offset of the word after the word <ifield> F is in.
+; What a `word' here is defined by F in its bitrange.
+
+(method-make!
+ <ifield> 'next-word
+ (lambda (self)
+ (let ((br (-ifld-bitrange f)))
+ (bitrange-next-word br)))
+)
+
+(define (ifld-next-word f) (send f 'next-word))
+
+; Return a boolean indicating if <ifield> F1 precedes <ifield> F2.
+; FIXME: Move into a method as different subclasses will need
+; different handling.
+
+(define (ifld-precedes? f1 f2)
+ (let ((br1 (-ifld-bitrange f1))
+ (br2 (-ifld-bitrange f2)))
+ (cond ((< (bitrange-word-offset br1) (bitrange-word-offset br2))
+ #t)
+ ((= (bitrange-word-offset br1) (bitrange-word-offset br2))
+ (begin
+ (assert (eq? (bitrange-lsb0? br1) (bitrange-lsb0? br2)))
+ (assert (= (bitrange-word-length br1) (bitrange-word-length br1)))
+ ; ??? revisit
+ (if (bitrange-lsb0? br1)
+ (> (bitrange-start br1) (bitrange-start br2))
+ (< (bitrange-start br1) (bitrange-start br2)))))
+ (else
+ #f)))
+)
+
+; Parse an ifield definition.
+; This is the main routine for building an ifield object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+;
+; Two forms of specification are supported, loosely defined as the RISC way
+; and the CISC way. The reason for the distinction is to simplify ifield
+; specification of RISC-like cpus.
+; Note that VLIW's are another way. These are handled like the RISC way, with
+; the possible addition of instruction framing (which is, surprise surprise,
+; wip).
+;
+; RISC:
+; WORD-OFFSET and WORD-LENGTH are #f. Insns are assumed to be N copies of
+; (isa-default-insn-word-bitsize). WORD-OFFSET is computed from START.
+; START is the offset in bits from the start of the insn.
+; FLENGTH is the length of the field in bits.
+;
+; CISC:
+; WORD-OFFSET is the offset in bits from the start to the first byte of the
+; word containing the ifield.
+; WORD-LENGTH is the length in bits of the word containing the ifield.
+; START is the starting bit number in the word. Bit numbering is taken from
+; (current-arch-insn-lsb0?).
+; FLENGTH is the length in bits of the ifield. It is named that way to avoid
+; collision with the proc named `length'.
+;
+; FIXME: More error checking.
+
+(define (-ifield-parse errtxt name comment attrs
+ word-offset word-length start flength follows
+ mode encode decode)
+ (logit 2 "Processing ifield " name " ...\n")
+
+ (let* ((name (parse-name name errtxt))
+ (atlist (atlist-parse attrs "cgen_ifld" errtxt))
+ (isas (bitset-attr->list (atlist-attr-value atlist 'ISA #f))))
+
+ ; Ensure only one isa specified.
+ (if (!= (length isas) 1)
+ (parse-error errtxt "can only specify 1 isa" attrs))
+
+ (if (not (eq? (->bool word-offset)
+ (->bool word-length)))
+ (parse-error errtxt "either both or neither of word-offset,word-length can be specified"))
+
+ (if (keep-isa-atlist? atlist #f)
+
+ (let ((isa (current-isa-lookup (car isas)))
+ (word-offset (and word-offset
+ (parse-number errtxt word-offset '(0 . 256))))
+ (word-length (and word-length
+ (parse-number errtxt word-length '(0 . 128))))
+ ; ??? 0.127 for now
+ (start (parse-number errtxt start '(0 . 127)))
+ ; ??? 0.127 for now
+ (flength (parse-number errtxt flength '(0 . 127)))
+ (lsb0? (current-arch-insn-lsb0?))
+ (mode-obj (parse-mode-name mode errtxt))
+ (follows-obj (-ifld-parse-follows errtxt follows))
+ )
+
+ ; Calculate the <bitrange> object.
+ ; FIXME: word-offset/word-length computation needs work.
+ ; Move positional info to format?
+ (let ((bitrange
+ (if word-offset
+ ; CISC
+ (make <bitrange>
+ word-offset start flength word-length lsb0?)
+ ; RISC
+ (let* ((default-insn-word-bitsize
+ (isa-default-insn-word-bitsize isa))
+ (word-offset
+ (- start
+ (remainder start
+ default-insn-word-bitsize)))
+ (start (remainder start default-insn-word-bitsize)))
+ (make <bitrange>
+ word-offset
+ start
+ flength
+ (if lsb0?
+ (* (quotient (+ start 1
+ (- default-insn-word-bitsize 1))
+ default-insn-word-bitsize)
+ default-insn-word-bitsize)
+ (* (quotient (+ start flength
+ (- default-insn-word-bitsize 1))
+ default-insn-word-bitsize)
+ default-insn-word-bitsize))
+ lsb0?))))
+ )
+
+ (let ((result
+ (make <ifield>
+ name
+ (parse-comment comment errtxt)
+ atlist
+ mode-obj
+ bitrange
+ (-ifld-parse-encode errtxt encode)
+ (-ifld-parse-decode errtxt decode))))
+ (if follows-obj
+ (ifld-set-follows! result follows-obj))
+ result)))
+
+ ; Else ignore entry.
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read an instruction field description.
+; This is the main routine for analyzing instruction fields in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -ifield-parse is invoked to create the <ifield> object.
+
+(define (-ifield-read errtxt . arg-list)
+ (let (; Current ifield elements:
+ (name nil)
+ (comment "")
+ (attrs nil)
+ (word-offset #f)
+ (word-length #f)
+ (start 0)
+ ; FIXME: Hobbit computes the wrong symbol for `length'
+ ; in the `case' expression below because there is a local var
+ ; of the same name ("__1" gets appended to the symbol name).
+ ; As a workaround we name it "length-".
+ (length- 0)
+ (follows #f)
+ (mode 'UINT)
+ (encode #f)
+ (decode #f)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((mode) (set! mode (cadr arg)))
+ ((word-offset) (set! word-offset (cadr arg)))
+ ((word-length) (set! word-length (cadr arg)))
+ ((start) (set! start (cadr arg)))
+ ((length) (set! length- (cadr arg)))
+ ((follows) (set! follows (cadr arg)))
+ ((encode) (set! encode (cdr arg)))
+ ((decode) (set! decode (cdr arg)))
+ (else (parse-error errtxt "invalid ifield arg" arg)))
+ (loop (cdr arg-list)))))
+
+ ; See if encode/decode were specified as "unspecified".
+ ; This happens with shorthand macros.
+ (if (and (pair? encode)
+ (eq? (car encode) #f))
+ (set! encode #f))
+ (if (and (pair? decode)
+ (eq? (car decode) #f))
+ (set! decode #f))
+
+ ; Now that we've identified the elements, build the object.
+ (-ifield-parse errtxt name comment attrs
+ word-offset word-length start length- follows
+ mode encode decode)
+ )
+)
+
+; Parse a `follows' spec.
+
+(define (-ifld-parse-follows errtxt follows)
+ (if follows
+ (let ((follows-obj (current-op-lookup follows)))
+ (if (not follows-obj)
+ (parse-error errtxt "unknown operand to follow" follows))
+ follows-obj)
+ #f)
+)
+
+; Do common parts of <ifield> encode/decode processing.
+
+(define (-ifld-parse-encode-decode errtxt which value)
+ (if value
+ (begin
+ (if (or (not (list? value))
+ (not (= (length value) 2))
+ (not (list? (car value)))
+ (not (= (length (car value)) 2))
+ (not (list? (cadr value))))
+ (parse-error errtxt
+ (string-append "bad ifield " which " spec")
+ value))
+ (if (or (not (> (length (cadr value)) 2))
+ (not (mode:lookup (cadr (cadr value)))))
+ (parse-error errtxt
+ (string-append which " expression must have a mode")
+ value))))
+ value
+)
+
+; Parse an <ifield> encode spec.
+
+(define (-ifld-parse-encode errtxt encode)
+ (-ifld-parse-encode-decode errtxt "encode" encode)
+)
+
+; Parse an <ifield> decode spec.
+
+(define (-ifld-parse-decode errtxt decode)
+ (-ifld-parse-encode-decode errtxt "decode" decode)
+)
+
+; Define an instruction field object, name/value pair list version.
+
+(define define-ifield
+ (lambda arg-list
+ (let ((f (apply -ifield-read (cons "define-ifield" arg-list))))
+ (if f
+ (current-ifld-add! f))
+ f))
+)
+
+; Define an instruction field object, all arguments specified.
+; ??? Leave out word-offset,word-length,follows for now (RISC version).
+; Not sure whether to add another function or leave CISC cpu's to define
+; a shorthand macro if they want.
+
+(define (define-full-ifield name comment attrs start length mode encode decode)
+ (let ((f (-ifield-parse "define-full-ifield" name comment attrs
+ #f #f start length #f mode encode decode)))
+ (if f
+ (current-ifld-add! f))
+ f)
+)
+
+(define (-ifield-add-commands!)
+ (reader-add-command! 'define-ifield
+ "\
+Define an instruction field, name/value pair list version.
+"
+ nil 'arg-list define-ifield)
+ (reader-add-command! 'define-full-ifield
+ "\
+Define an instruction field, all arguments specified.
+"
+ nil '(name comment attrs start length mode encode decode)
+ define-full-ifield)
+ (reader-add-command! 'define-multi-ifield
+ "\
+Define an instruction multi-field, name/value pair list version.
+"
+ nil 'arg-list define-multi-ifield)
+ (reader-add-command! 'define-full-multi-ifield
+ "\
+Define an instruction multi-field, all arguments specified.
+"
+ nil '(name comment attrs mode subflds insert extract)
+ define-full-multi-ifield)
+
+ *UNSPECIFIED*
+)
+
+; Instruction fields consisting of multiple parts.
+
+(define <multi-ifield>
+ (class-make '<multi-ifield>
+ '(<ifield>)
+ '(
+ ; List of <ifield> objects.
+ subfields
+ ; rtl to set SUBFIELDS from self
+ insert
+ ; rtl to set self from SUBFIELDS
+ extract
+ )
+ nil)
+)
+
+; Accessors
+
+(define-getters <multi-ifield> multi-ifld
+ (subfields insert extract)
+)
+
+; Return a boolean indicating if X is an <ifield>.
+
+(define (multi-ifield? x) (class-instance? <multi-ifield> x))
+
+(define (non-multi-ifields ifld-list)
+ (find (lambda (ifld) (not (multi-ifield? ifld))) ifld-list)
+)
+
+(define (non-derived-ifields ifld-list)
+ (find (lambda (ifld) (not (derived-ifield? ifld))) ifld-list)
+)
+
+
+; Return the starting bit number of the first field.
+
+(method-make-virtual!
+ <multi-ifield> 'field-start
+ (lambda (self word-len)
+ (apply min (map (lambda (f) (ifld-start f #f)) (elm-get self 'subfields))))
+)
+
+; Return the total length.
+
+(method-make-virtual!
+ <multi-ifield> 'field-length
+ (lambda (self)
+ (apply + (map ifld-length (elm-get self 'subfields))))
+)
+
+; Return the bit offset of the word after the last word SELF is in.
+; What a `word' here is defined by subfields in their bitranges.
+
+(method-make!
+ <multi-ifield> 'next-word
+ (lambda (self)
+ (apply max (map (lambda (f)
+ (bitrange-next-word (-ifld-bitrange f)))
+ (multi-ifld-subfields self))))
+)
+
+; Return mask of field in bitrange CONTAINER.
+
+(method-make!
+ <multi-ifield> 'field-mask
+ (lambda (self base-len container)
+ (apply + (map (lambda (f) (ifld-mask f base-len container)) (elm-get self 'subfields))))
+)
+
+; Return VALUE inserted into the field's position.
+; The value is spread out over the various subfields in sorted order.
+; We assume the subfields have been sorted by starting bit position.
+
+(method-make!
+ <multi-ifield> 'field-value
+ (lambda (self base-len value)
+ (apply + (map (lambda (f) (ifld-value f base-len value)) (elm-get self 'subfields))))
+)
+
+; Return a list of ifields required to compute the field's value.
+
+(method-make!
+ <multi-ifield> 'needed-iflds
+ (lambda (self)
+ (cons self (elm-get self 'subfields)))
+)
+
+; Extract <ifield> IFLD's value out of VALUE in <insn> INSN.
+; VALUE is the entire insn's value if it fits in a word, or is a list
+; of values, one per word (not implemented, sigh).
+; ??? The instruction's format should specify where the word boundaries are.
+
+(method-make!
+ <multi-ifield> 'field-extract
+ (lambda (self insn value)
+ (let* ((subflds (sort-ifield-list (elm-get self 'subfields)
+ (not (ifld-lsb0? self))))
+ (subvals (map (lambda (subfld)
+ (ifld-extract subfld insn value))
+ subflds))
+ )
+ ; We have each subfield's value, now concatenate them.
+ (letrec ((plus-scan (lambda (lengths current)
+ ; do the -1 drop here as it's easier
+ (if (null? (cdr lengths))
+ nil
+ (cons current
+ (plus-scan (cdr lengths)
+ (+ current (car lengths))))))))
+ (apply + (map logsll
+ subvals
+ (plus-scan (map ifld-length subflds) 0))))))
+)
+
+; Return a boolean indicating if bit 0 is the least significant bit.
+
+(method-make!
+ <multi-ifield> 'field-lsb0?
+ (lambda (self)
+ (ifld-lsb0? (car (elm-get self 'subfields))))
+)
+
+; Multi-ifield parsing.
+
+; Subroutine of -multi-ifield-parse to build the default insert expression.
+
+(define (-multi-ifield-make-default-insert container-name subfields)
+ (let* ((lengths (map ifld-length subfields))
+ (shifts (cons 0 (list-tail-drop 1 (plus-scan (cons 0 lengths))))))
+ ; Build RTL expression to shift and mask each ifield into right spot.
+ (let ((exprs (map (lambda (f length shift)
+ (rtx-make 'and (rtx-make 'srl container-name shift)
+ (mask length)))
+ subfields lengths shifts)))
+ ; Now set each ifield with their respective values.
+ (apply rtx-make (cons 'sequence
+ (cons nil
+ (map (lambda (f expr)
+ (rtx-make-set f expr))
+ subfields exprs))))))
+)
+
+; Subroutine of -multi-ifield-parse to build the default extract expression.
+
+(define (-multi-ifield-make-default-extract container-name subfields)
+ (let* ((lengths (map ifld-length subfields))
+ (shifts (cons 0 (list-tail-drop 1 (plus-scan (cons 0 lengths))))))
+ ; Build RTL expression to shift and mask each ifield into right spot.
+ (let ((exprs (map (lambda (f length shift)
+ (rtx-make 'sll (rtx-make 'and (obj:name f)
+ (mask length))
+ shift))
+ subfields lengths shifts)))
+ ; Now set {container-name} with all the values or'd together.
+ (rtx-make-set container-name
+ (rtx-combine 'or exprs))))
+)
+
+; Parse a multi-ifield spec.
+; This is the main routine for building the object from the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+
+(define (-multi-ifield-parse errtxt name comment attrs mode subfields insert extract encode decode)
+ (logit 2 "Processing multi-ifield element " name " ...\n")
+
+ (let ((name (parse-name name errtxt))
+ (result (new <multi-ifield>))
+ (subfields (map (lambda (subfld)
+ (let ((f (current-ifld-lookup subfld)))
+ (if (not f)
+ (parse-error errtxt "unknown ifield" subfld))
+ f))
+ subfields)))
+
+ (elm-xset! result 'name name)
+ (elm-xset! result 'comment (parse-comment comment errtxt))
+ ; multi-ifields are always VIRTUAL
+ (elm-xset! result 'attrs
+ (atlist-parse (cons 'VIRTUAL attrs) "multi-ifield" errtxt))
+ (elm-xset! result 'mode (parse-mode-name mode errtxt))
+ (elm-xset! result 'encode (-ifld-parse-encode errtxt encode))
+ (elm-xset! result 'decode (-ifld-parse-encode errtxt decode))
+ (if insert
+ (elm-xset! result 'insert insert)
+ (elm-xset! result 'insert
+ (-multi-ifield-make-default-insert name subfields)))
+ (if extract
+ (elm-xset! result 'extract extract)
+ (elm-xset! result 'extract
+ (-multi-ifield-make-default-extract name subfields)))
+ (elm-xset! result 'subfields subfields)
+
+ result)
+)
+
+; Read an instruction multi-ifield.
+
+(define (-multi-ifield-read errtxt . arg-list)
+ (let (; Current multi-ifield elements:
+ (name nil)
+ (comment "")
+ (attrs nil)
+ (mode 'UINT)
+ (subflds nil)
+ (insert #f)
+ (extract #f)
+ (encode #f)
+ (decode #f)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((mode) (set! mode (cadr arg)))
+ ((subfields) (set! subflds (cdr arg)))
+ ((insert) (set! insert (cadr arg)))
+ ((extract) (set! extract (cadr arg)))
+ ((encode) (set! encode (cdr arg)))
+ ((decode) (set! decode (cdr arg)))
+ (else (parse-error errtxt "invalid ifield arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-multi-ifield-parse errtxt name comment attrs mode subflds insert extract encode decode)
+ )
+)
+
+; Define an instruction multi-field object, name/value pair list version.
+
+(define define-multi-ifield
+ (lambda arg-list
+ (let ((f (apply -multi-ifield-read (cons "define-multi-ifield" arg-list))))
+ (current-ifld-add! f)
+ f))
+)
+
+; Define an instruction multi-field object, all arguments specified.
+
+(define (define-full-multi-ifield name comment attrs mode subflds insert extract)
+ (let ((f (-multi-ifield-parse "define-full-multi-ifield" name comment attrs
+ mode subflds insert extract #f #f)))
+ (current-ifld-add! f)
+ f)
+)
+
+; Derived ifields (ifields based on one or more other ifields).
+; These support the complicated requirements of CISC instructions
+; where one "ifield" is actually a placeholder for an addressing mode
+; which can consist of several ifields.
+; These are also intended to support other complex ifield usage.
+;
+; Derived ifields are (currently) always machine generated from other
+; elements of the description file so there is no reader support.
+;
+; ??? experimental and wip!
+; ??? These are kind of like multi-ifields but I don't want to disturb them
+; while this is still experimental.
+
+(define <derived-ifield>
+ (class-make '<derived-ifield>
+ '(<ifield>)
+ '(
+ ; Operand that uses this ifield.
+ ; Unlike other ifields, derived ifields have a one-to-one
+ ; correspondence with the operand that uses them.
+ ; ??? Not true in -anyof-merge-subchoices.
+ owner
+
+ ; List of ifields that make up this ifield.
+ subfields
+ )
+ nil)
+)
+
+(method-make!
+ <derived-ifield> 'make!
+ (lambda (self name comment attrs owner subfields)
+ (elm-set! self 'name name)
+ (elm-set! self 'comment comment)
+ (elm-set! self 'attrs attrs)
+ (elm-set! self 'mode UINT)
+ (elm-set! self 'bitrange (make <bitrange> 0 0 0 0 #f))
+ (elm-set! self 'owner owner)
+ (elm-set! self 'subfields subfields)
+ self)
+)
+
+; Accessors.
+
+(define-getters <derived-ifield> derived-ifield (owner subfields))
+
+(define-setters <derived-ifield> derived-ifield (owner subfields))
+
+(define (derived-ifield? x) (class-instance? <derived-ifield> x))
+
+; Return a boolean indicating if F is a derived ifield with a derived operand
+; for a value.
+; ??? The former might imply the latter so some simplification may be possible.
+
+(define (ifld-derived-operand? f)
+ (and (derived-ifield? f)
+ (derived-operand? (ifld-get-value f)))
+)
+
+; Return the bit offset of the word after the last word SELF is in.
+; What a `word' here is defined by subfields in their bitranges.
+
+(method-make!
+ <derived-ifield> 'next-word
+ (lambda (self)
+ (apply max (map (lambda (f)
+ (bitrange-next-word (-ifld-bitrange f)))
+ (derived-ifield-subfields self))))
+)
+
+
+; Traverse the ifield to collect all base (non-derived) ifields used in it.
+(define (ifld-base-ifields ifld)
+ (cond ((derived-ifield? ifld) (collect (lambda (subfield) (ifld-base-ifields subfield))
+ (derived-ifield-subfields ifld)))
+ ; ((multi-ifield? ifld) (collect (lambda (subfield) (ifld-base-ifields subfield))
+ ; (multi-ifld-subfields ifld)))
+ (else (list ifld)))
+)
+
+
+
+; Misc. utilities.
+
+; Sort a list of fields (sorted by the starting bit number).
+; This must be carefully defined to pass through Hobbit.
+; (define foo (if x bar baz)) is ok.
+; (if x (define foo bar) (define foo baz)) is not ok.
+;
+; ??? Usually there aren't that many fields and the range of values is fixed,
+; so I think this needn't use a general purpose sort routine (should it become
+; an issue).
+
+(define sort-ifield-list
+ (if (and (defined? 'cgh-qsort) (defined? 'cgh-qsort-int-cmp))
+ (lambda (fld-list up?)
+ (cgh-qsort fld-list
+ (if up?
+ (lambda (a b)
+ (cgh-qsort-int-cmp (ifld-start a #f)
+ (ifld-start b #f)))
+ (lambda (a b)
+ (- (cgh-qsort-int-cmp (ifld-start a #f)
+ (ifld-start b #f)))))))
+ (lambda (fld-list up?)
+ (sort fld-list
+ (if up?
+ (lambda (a b) (< (ifld-start a #f)
+ (ifld-start b #f)))
+ (lambda (a b) (> (ifld-start a #f)
+ (ifld-start b #f)))))))
+)
+
+; Return a boolean indicating if field F extends beyond the base insn.
+
+(define (ifld-beyond-base? f base-bitsize total-bitsize)
+ ; old way
+ ;(< base-bitsize (+ (ifld-start f total-bitsize) (ifld-length f)))
+ (> (ifld-word-offset f) 0)
+)
+
+; Return the mode of the decoded value of <ifield> F.
+; ??? This is made easy because we require the decode expression to have
+; an explicit mode.
+
+(define (ifld-decode-mode f)
+ (if (not (elm-bound? f 'decode))
+ (ifld-mode f)
+ (let ((d (ifld-decode f)))
+ (if d
+ (mode:lookup (cadr (cadr d)))
+ (ifld-mode f))))
+)
+
+; Return <hardware> object to use to hold value of <ifield> F.
+; i.e. one of h-uint, h-sint.
+; NB: Should be defined in terms of `hardware-for-mode'.
+(define (ifld-hw-type f)
+ (case (mode:class (ifld-mode f))
+ ((INT) h-sint)
+ ((UINT) h-uint)
+ (else (error "unsupported mode class" (mode:class (ifld-mode f)))))
+)
+
+; Builtin fields, attributes, init/fini support.
+
+; The f-nil field is a placeholder when building operands out of hardware
+; elements that aren't indexed by an instruction field (scalars).
+(define f-nil #f)
+
+(define (ifld-nil? f)
+ (eq? (obj:name f) 'f-nil)
+)
+
+; The f-anyof field is a placeholder when building "anyof" operands.
+(define f-anyof #f)
+
+(define (ifld-anyof? f)
+ (eq? (obj:name f) 'f-anyof)
+)
+
+; Return a boolean indicating if F is an anyof ifield with an anyof operand
+; for a value.
+; ??? The former implies the latter so some simplification is possible.
+
+(define (ifld-anyof-operand? f)
+ (and (ifld-anyof? f)
+ (anyof-operand? (ifld-get-value f)))
+)
+
+; Called before loading the .cpu file to initialize.
+
+(define (ifield-init!)
+ (-ifield-add-commands!)
+
+ *UNSPECIFIED*
+)
+
+; Called before loading the .cpu file to create any builtins.
+
+(define (ifield-builtin!)
+ ; Standard ifield attributes.
+ ; ??? Some of these can be combined into one, booleans are easier to
+ ; work with.
+ (define-attr '(for ifield operand) '(type boolean) '(name PCREL-ADDR)
+ '(comment "pc relative address"))
+ (define-attr '(for ifield operand) '(type boolean) '(name ABS-ADDR)
+ '(comment "absolute address"))
+ (define-attr '(for ifield) '(type boolean) '(name RESERVED)
+ '(comment "field is reserved"))
+ (define-attr '(for ifield operand) '(type boolean) '(name SIGN-OPT)
+ '(comment "value is signed or unsigned"))
+ ; ??? This is an internal attribute for implementation purposes only.
+ ; To be revisited.
+ (define-attr '(for ifield operand) '(type boolean) '(name SIGNED)
+ '(comment "value is unsigned"))
+ ; Also (defined elsewhere): VIRTUAL
+
+ (set! f-nil (make <ifield> 'f-nil "empty ifield"
+ atlist-empty
+ UINT
+ (make <bitrange> 0 0 0 0 #f)
+ #f #f)) ; encode/decode
+ (current-ifld-add! f-nil)
+
+ (set! f-anyof (make <ifield> 'f-anyof "placeholder for anyof operands"
+ atlist-empty
+ UINT
+ (make <bitrange> 0 0 0 0 #f)
+ #f #f)) ; encode/decode
+ (current-ifld-add! f-anyof)
+
+ *UNSPECIFIED*
+)
+
+; Called after the .cpu file has been read in.
+
+(define (ifield-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/iformat.scm b/cgen/iformat.scm
new file mode 100644
index 00000000000..1717f38d2c9
--- /dev/null
+++ b/cgen/iformat.scm
@@ -0,0 +1,614 @@
+; Instruction formats.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Instruction formats are computed after the .cpu file has been read in.
+; ??? May also wish to allow programmer to specify formats, but not sure this
+; will complicate things more than it simplifies them, so it's defered.
+;
+; Two kinds of formats are defined here: iformat and sformat.
+; (pronounced "I-format" and "S-format")
+;
+; Iformats are the instruction format as specified by the instructions' fields,
+; and are the machine computed version of the generally known notion of an
+; "instruction format". No semantic information is attributed to iformats.
+;
+; Sformats are the same as iformats except that semantics are used to
+; distinguish them. For example, if an operand is refered to in one mode by
+; one instruction and in a different mode by another instruction, then these
+; two insns would have different sformats but the same iformat. Sformats
+; are used in simulator extraction code to collapse the number of cases that
+; must be handled. They can also be used to collapse the number of cases
+; in the modeling code.
+;
+; The "base length" is the length of the insn that is initially fetched for
+; decoding purposes.
+; Formats are fixed in length. For variable instruction length architectures
+; there are separate formats for each insn's possible length.
+
+(define <iformat>
+ (class-make '<iformat>
+ '(<ident>)
+ ; From <ident>:
+ ; - NAME is derived from number, but we might have user
+ ; specified formats someday [though I wouldn't add them
+ ; without a clear need].
+ ; - COMMENT is the assembler syntax of an example insn that
+ ; uses the format.
+ '(
+ ; Index into the iformat table.
+ number
+
+ ; Sort key, used to determine insns with identical formats.
+ key
+
+ ; List of <ifield> objects.
+ ifields
+
+ ; min (insn-length, base-insn-size)
+ mask-length
+
+ ; total length of insns with this format
+ length
+
+ ; mask of base part
+ mask
+
+ ; An example insn that uses the format.
+ eg-insn
+ )
+ nil)
+)
+
+; Accessor fns.
+
+(define-getters <iformat> ifmt
+ (number key ifields mask-length length mask eg-insn)
+)
+
+; Traverse the ifield list to collect all base (non-derived) ifields used in it.
+(define (ifields-base-ifields ifld-list)
+ (collect (lambda (ifld)
+ (ifld-base-ifields ifld))
+ ifld-list)
+)
+
+; Return enum cgen_fmt_type value for FMT.
+; ??? Not currently used.
+
+(define (ifmt-enum fmt)
+ (string-append "@CPU@_" (string-upcase (gen-sym fmt)))
+)
+
+; Given FLD-LIST, compute the length of the insn in bits.
+; This is done by adding up all the field sizes.
+; All bits must be represent exactly once.
+
+(define (compute-insn-length fld-list)
+ (apply + (map ifld-length (collect ifld-base-ifields fld-list)))
+)
+
+; Given FLD-LIST, compute the base length in bits.
+; Computing the min of state-base-insn-bitsize and the total-length
+; is for [V]LIW instruction sets.
+
+(define (compute-insn-base-mask-length fld-list)
+ (min (state-base-insn-bitsize) (compute-insn-length fld-list))
+)
+
+; Given FLD-LIST, compute the bitmask of constant values in the base part
+; of the insn (i.e. the opcode field).
+;
+; FIXME: Need to add support for constant fields appearing outside the base
+; insn. One way would be to record with each insn the value for each constant
+; field. That would allow code to straightforwardly fetch it. Another would
+; be to only record constant values appearing outside the base insn.
+;
+; See also (insn-value).
+;
+(define (compute-insn-base-mask fld-list)
+ (let* ((mask-len (compute-insn-base-mask-length fld-list))
+ (lsb0? (ifld-lsb0? (car fld-list)))
+ (mask-bitrange (make <bitrange>
+ 0 ; word-offset
+ (if lsb0? (- mask-len 1) 0) ; start
+ mask-len ; length
+ mask-len ; word-length
+ lsb0?)))
+ (apply +
+ (map (lambda (fld) (ifld-mask fld mask-len mask-bitrange))
+ ; Find the fields that have constant values.
+ (find ifld-constant? (collect ifld-base-ifields fld-list)))
+ )
+ )
+)
+
+; Return the <iformat> search key for a sorted field list.
+; This determines how iformats differ from each other.
+; It also speeds up searching as the search key can be anything
+; (though at present searching isn't as fast as it could be).
+; INSN is passed so that we can include its sanytize attribute, if present,
+; so sanytized sources work (needed formats don't disappear).
+
+(define (-ifmt-search-key insn sorted-ifld-list)
+ (string-map (lambda (ifld)
+ (string-append " ("
+ (or (obj-attr-value insn 'sanitize)
+ "-nosan-")
+ " "
+ (obj:name ifld)
+ " "
+ (ifld-ilk ifld)
+ ")"))
+ sorted-ifld-list)
+)
+
+; Create an <iformat> object for INSN.
+; INDEX is the ordinal to assign to the result or -1 if unknown.
+; SEARCH-KEY is the search key used to determine the iformat's uniqueness.
+; IFLDS is a sorted list of INSN's ifields.
+
+(define (ifmt-build insn index search-key iflds)
+ (make <iformat>
+ (symbol-append 'ifmt- (obj:name insn))
+ (string-append "e.g. " (insn-syntax insn))
+ atlist-empty
+ index
+ search-key
+ iflds
+ (compute-insn-base-mask-length iflds)
+ (compute-insn-length iflds)
+ (compute-insn-base-mask iflds)
+ insn)
+)
+
+; Sformats.
+
+(define <sformat>
+ (class-make '<sformat>
+ '(<ident>)
+ ; From <ident>:
+ ; - NAME is derived from number.
+ ; - COMMENT is the assembler syntax of an example insn that
+ ; uses the format.
+ '(
+ ; Index into the sformat table.
+ number
+
+ ; Sort key, used to determine insns with identical formats.
+ key
+
+ ; Non-#f if insns with this format are cti insns.
+ cti?
+
+ ; IN-OPS is a list of input operands.
+ ; OUT-OPS is a list of output operands.
+ ; These are used to distinguish the format from others,
+ ; so that the extract and read operations can be based on the
+ ; sformat.
+ ; The extract fns use this data to record the necessary
+ ; information for profiling [which isn't necessarily a property
+ ; of the field list]. We could have one extraction function
+ ; per instruction, but there's a *lot* of duplicated code, and
+ ; the semantic operands rarely contribute to extra formats.
+ ; The parallel execution support uses this data to record the
+ ; input (or output) values based on the instruction format,
+ ; again cutting down on duplicated code.
+ in-ops
+ out-ops
+
+ ; Length of all insns with this format.
+ ; Since insns with different iformats can have the same sformat
+ ; we need to ensure ifield extraction works among the various
+ ; iformats. We do this by ensuring all insns with the same
+ ; sformat have the same length.
+ length
+
+ ; Cached list of all ifields used.
+ ; This can be derived from IN-OPS/OUT-OPS but is computed once
+ ; and cached here for speed.
+ iflds
+
+ ; An example insn that uses the format.
+ ; This is used for debugging purposes, but also to help get
+ ; sanytization (spelled wrong on purpose) right.
+ eg-insn
+
+ ; <sformat-argbuf> entry
+ ; FIXME: Temporary location, to be moved elsewhere
+ (sbuf . #f)
+ )
+ nil)
+)
+
+; Accessor fns.
+
+(define-getters <sformat> sfmt
+ (number key cti? in-ops out-ops length iflds eg-insn sbuf)
+)
+
+(define-setters <sformat> sfmt (sbuf))
+
+(method-make-make! <sformat>
+ '(name comment attrs
+ number key cti? in-ops out-ops length iflds eg-insn)
+)
+
+; Return the <sformat> search key for a sorted field list and semantic
+; operands.
+; This determines how sformats differ from each other.
+; It also speeds up searching as the search key can be anything
+; (though at present searching isn't as fast as it could be).
+;
+; INSN is passed so that we can include its sanytize attribute, if present,
+; so sanytized sources work (needed formats don't disappear).
+; SORTED-USED-IFLDS is a sorted list of ifields used by SEM-{IN,OUT}-OPS.
+; Note that it is not the complete set of ifields used by INSN.
+;
+; We assume INSN's <iformat> has been recorded.
+;
+; Note: It's important to minimize the number of created sformats. It keeps
+; the generated code smaller (and sometimes faster - more usable common
+; fragments in pbb simulators). Don't cause spurious differences.
+
+(define (-sfmt-search-key insn cti? sorted-used-iflds sem-in-ops sem-out-ops)
+ (let ((op-key (lambda (op)
+ (string-append " ("
+ (or (obj-attr-value insn 'sanitize)
+ "-nosan-")
+ " "
+ (obj:name op)
+ ; ??? Including memory operands currently
+ ; isn't necessary and it can account for some
+ ; spurious differences. On the other hand
+ ; leaving it out doesn't seem like the right
+ ; thing to do.
+ (if (memory? (op:type op))
+ ""
+ (string-append " "
+ (obj:name (op:mode op))))
+ ; CGEN_OPERAND_INSTANCE_COND_REF is stored
+ ; with the operand in the operand instance
+ ; table thus formats must be distinguished
+ ; by this.
+ (if (op:cond? op) " cond" "")
+ ")")))
+ )
+ (list
+ cti?
+ (insn-length insn)
+ (string-map (lambda (ifld)
+ (string-append " (" (obj:name ifld) " " (ifld-ilk ifld) ")"))
+ sorted-used-iflds)
+ (string-map op-key
+ sem-in-ops)
+ (string-map op-key
+ sem-out-ops)
+ ))
+)
+
+; Create an <sformat> object for INSN.
+; INDEX is the ordinal to assign to the result or -1 if unknown.
+; SEARCH-KEY is the search key used to determine the sformat's uniqueness.
+; {IN,OUT}-OPS are lists of INSN's input/output operands.
+; SORTED-USED-IFLDS is a sorted list of ifields used by {IN,OUT}-OPS.
+; Note that it is not the complete set of ifields used by INSN.
+;
+; We assume INSN's <iformat> has already been recorded.
+
+(define (sfmt-build insn index search-key cti? in-ops out-ops sorted-used-iflds)
+ (make <sformat>
+ (symbol-append 'sfmt- (obj:name insn))
+ (string-append "e.g. " (insn-syntax insn))
+ atlist-empty
+ index
+ search-key
+ cti?
+ in-ops
+ out-ops
+ (insn-length insn)
+ sorted-used-iflds
+ insn)
+)
+
+; Sort IFLDS by dependencies and then by starting bit number.
+
+(define (-sfmt-order-iflds iflds)
+ (let ((up?
+ ; ??? Something like this is preferable.
+ ;(not (ifld-lsb0? (car ifld-list)))
+ (not (current-arch-insn-lsb0?))))
+ (let loop ((independent nil) (dependent nil) (iflds iflds))
+ (cond ((null? iflds)
+ (append (sort-ifield-list independent up?)
+ (sort-ifield-list dependent up?)))
+ ; FIXME: quick hack.
+ ((multi-ifield? (car iflds))
+ (loop independent (cons (car iflds) dependent) (cdr iflds)))
+ (else
+ (loop (cons (car iflds) independent) dependent (cdr iflds))))))
+)
+
+; Return a sorted list of ifields used by IN-OPS, OUT-OPS.
+; The ifields are sorted by dependencies and then by start bit.
+; The important points are to help distinguish sformat's by the ifields used
+; and to put ifields that others depend on first.
+
+(define (-sfmt-used-iflds in-ops out-ops)
+ (let ((in-iflds (map op-iflds-used in-ops))
+ (out-iflds (map op-iflds-used out-ops)))
+ (let ((all-iflds (nub (append (apply append in-iflds)
+ (apply append out-iflds))
+ obj:name)))
+ (-sfmt-order-iflds all-iflds)))
+)
+
+; The format descriptor is used to sort formats.
+; This is a utility class internal to this file.
+; There is one instance per insn.
+
+(define <fmt-desc>
+ (class-make '<fmt-desc>
+ nil
+ '(
+ ; #t if insn is a cti insn
+ cti?
+
+ ; sorted list of insn's ifields
+ iflds
+
+ ; computed set of input/output operands
+ in-ops out-ops
+
+ ; set of ifields used by IN-OPS,OUT-OPS.
+ used-iflds
+
+ ; computed set of attributes
+ attrs
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <fmt-desc> -fmt-desc
+ (cti? iflds in-ops out-ops used-iflds attrs)
+)
+
+; Compute an iformat descriptor used to build an <iformat> object for INSN.
+;
+; If COMPUTE-SFORMAT? is #t compile the semantics and compute the semantic
+; format (same as instruction format except that operands are used to
+; distinguish insns).
+; Attributes derivable from the semantics are also computed.
+; This is all done at the same time to minimize the number of times the
+; semantic code is traversed.
+;
+; The result is (descriptor compiled-semantics attrs).
+; `descriptor' is #f for insns with an empty field list
+; (this happens for virtual insns).
+; `compiled-semantics' is #f if COMPUTE-SFORMAT? is #f.
+; `attrs' is an <attr-list> object of attributes derived from the semantics.
+;
+; ??? We never traverse the semantics of virtual insns.
+
+(define (ifmt-analyze insn compute-sformat?)
+ ; First sort by starting bit number the list of fields in INSN.
+ (let ((sorted-ifields
+ (sort-ifield-list (insn-iflds insn)
+ ; ??? Something like this is preferable, but
+ ; if the first insn is a virtual insn there are
+ ; no fields.
+ ;(not (ifld-lsb0? (car (insn-iflds insn))))
+ (not (current-arch-insn-lsb0?))
+ )))
+
+ (if (null? sorted-ifields)
+
+ ; Field list is unspecified.
+ (list #f #f atlist-empty)
+
+ ; FIXME: error checking (e.g. missing or overlapping bits)
+ (let* (; A list of the various bits of semantic code.
+ (sems (list (insn-semantics insn)))
+ ; Compute list of input and output operands if asked for.
+ (sem-ops (if compute-sformat?
+ (semantic-compile #f ; FIXME: context
+ insn sems)
+ (csem-make #f #f #f
+ (if (insn-semantics insn)
+ (semantic-attrs #f ; FIXME: context
+ insn sems)
+ atlist-empty))))
+ )
+ (let ((compiled-sems (csem-code sem-ops))
+ (in-ops (csem-inputs sem-ops))
+ (out-ops (csem-outputs sem-ops))
+ (attrs (csem-attrs sem-ops))
+ (cti? (or (atlist-cti? (csem-attrs sem-ops))
+ (insn-cti? insn))))
+ (list (make <fmt-desc>
+ cti? sorted-ifields in-ops out-ops
+ (if (and in-ops out-ops)
+ (-sfmt-used-iflds in-ops out-ops)
+ #f)
+ attrs)
+ compiled-sems
+ attrs)))))
+)
+
+; Subroutine of ifmt-compute!, to simplify it.
+; Lookup INSN's iformat in IFMT-LIST and if not found add it.
+; FMT-DESC is INSN's <fmt-desc> object.
+; IFMT-LIST is append!'d to and the found iformat is stored in INSN.
+
+(define (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
+ (let* ((search-key (-ifmt-search-key insn (-fmt-desc-iflds fmt-desc)))
+ (ifmt (find-first (lambda (elm)
+ (equal? (ifmt-key elm) search-key))
+ ifmt-list)))
+
+ (if ifmt
+
+ ; Format was found, use it.
+ (begin
+ (logit 3 "Using iformat " (number->string (ifmt-number ifmt)) ".\n")
+ (insn-set-ifmt! insn ifmt)
+ )
+
+ ; Format wasn't found, create new entry.
+ (let* ((ifmt-index (length ifmt-list))
+ (ifmt (ifmt-build insn ifmt-index search-key
+ (ifields-base-ifields (-fmt-desc-iflds fmt-desc)))))
+ (logit 3 "Creating iformat " (number->string ifmt-index) ".\n")
+ (insn-set-ifmt! insn ifmt)
+ (append! ifmt-list (list ifmt))
+ )
+ ))
+
+ *UNSPECIFIED*
+)
+
+; Subroutine of ifmt-compute!, to simplify it.
+; Lookup INSN's sformat in SFMT-LIST and if not found add it.
+; FMT-DESC is INSN's <fmt-desc> object.
+; SFMT-LIST is append!'d to and the found sformat is stored in INSN.
+;
+; We assume INSN's <iformat> has already been recorded.
+
+(define (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)
+ (let* ((search-key (-sfmt-search-key insn (-fmt-desc-cti? fmt-desc)
+ (-fmt-desc-used-iflds fmt-desc)
+ (-fmt-desc-in-ops fmt-desc)
+ (-fmt-desc-out-ops fmt-desc)))
+ (sfmt (find-first (lambda (elm)
+ (equal? (sfmt-key elm) search-key))
+ sfmt-list)))
+
+ (if sfmt
+
+ ; Format was found, use it.
+ (begin
+ (logit 3 "Using sformat " (number->string (sfmt-number sfmt)) ".\n")
+ (insn-set-sfmt! insn sfmt)
+ )
+
+ ; Format wasn't found, create new entry.
+ (let* ((sfmt-index (length sfmt-list))
+ (sfmt (sfmt-build insn sfmt-index search-key
+ (-fmt-desc-cti? fmt-desc)
+ (-fmt-desc-in-ops fmt-desc)
+ (-fmt-desc-out-ops fmt-desc)
+ (-fmt-desc-used-iflds fmt-desc))))
+ (logit 3 "Creating sformat " (number->string sfmt-index) ".\n")
+ (insn-set-sfmt! insn sfmt)
+ (append! sfmt-list (list sfmt))
+ )
+ ))
+
+ *UNSPECIFIED*
+)
+
+; Main entry point.
+
+; Given a list of insns, compute the set of instruction formats, semantic
+; formats, semantic attributes, and compiled semantics for each insn.
+;
+; The computed <iformat> object is stored in the `ifmt' field of each insn.
+;
+; Attributes derived from the semantic code are added to the insn's attributes,
+; but they don't override any prespecified values.
+;
+; If COMPUTE-SFORMAT? is #t, the computed <sformat> object is stored in the
+; `sfmt' field of each insn, and the processed semantic code is stored in the
+; `compiled-semantics' field of each insn.
+;
+; The `fmt-desc' field of each insn is used to store an <fmt-desc> object
+; which contains the search keys, sorted field list, input-operands, and
+; output-operands, and is not used outside this procedure.
+;
+; The result is a list of two lists: the set of computed iformats, and the
+; set of computed sformats.
+;
+; *** This is the most expensive calculation in CGEN. ***
+; *** (mainly because of the detailed semantic parsing) ***
+
+(define (ifmt-compute! insn-list compute-sformat?)
+ (logit 2 "Computing instruction formats and analyzing semantics ...\n")
+
+ ; First analyze each insn, storing the result in fmt-desc.
+ ; If asked to, convert the semantic code to a compiled form to simplify more
+ ; intelligent processing of it later.
+
+ (for-each (lambda (insn)
+ (logit 3 "Scanning operands of " (obj:name insn) ": "
+ (insn-syntax insn) " ...\n")
+ (let ((sem-ops (ifmt-analyze insn compute-sformat?)))
+ (insn-set-fmt-desc! insn (car sem-ops))
+ (if (and compute-sformat? (cadr sem-ops))
+ (let ((compiled-sems (cadr sem-ops)))
+ (insn-set-compiled-semantics! insn (car compiled-sems))))
+ (obj-set-atlist! insn
+ (atlist-append (obj-atlist insn)
+ (caddr sem-ops)))
+ ))
+ insn-list)
+
+ ; Now for each insn, look up the ifield list in the format table (and if not
+ ; found add it), and set the ifmt/sfmt elements of the insn.
+
+ (let* ((empty-ifmt (make <iformat>
+ 'ifmt-empty
+ "empty iformat for unspecified field list"
+ atlist-empty ; attrs
+ -1 ; number
+ #f ; key
+ nil ; fields
+ 0 ; mask-length
+ 0 ; length
+ 0 ; mask
+ #f)) ; eg-insn
+ (empty-sfmt (make <sformat>
+ 'sfmt-empty
+ "empty sformat for unspecified field list"
+ atlist-empty ; attrs
+ -1 ; number
+ #f ; key
+ #f ; cti?
+ nil ; sem-in-ops
+ nil ; sem-out-ops
+ 0 ; length
+ nil ; used iflds
+ #f)) ; eg-insn
+ (ifmt-list (list empty-ifmt))
+ (sfmt-list (list empty-sfmt))
+ )
+
+ (for-each (lambda (insn)
+ (logit 3 "Processing format for " (obj:name insn) ": "
+ (insn-syntax insn) " ...\n")
+
+ (let ((fmt-desc (insn-fmt-desc insn)))
+
+ (if fmt-desc
+
+ (begin
+ ; Must compute <iformat> before <sformat>, the latter
+ ; needs the former.
+ (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
+ (if compute-sformat?
+ (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)))
+
+ ; No field list present, use empty format.
+ (begin
+ (insn-set-ifmt! insn empty-ifmt)
+ (if compute-sformat?
+ (insn-set-sfmt! insn empty-sfmt))))))
+
+ (non-multi-insns insn-list))
+
+ ; Done. Return the computed iformat and sformat lists.
+ (list ifmt-list sfmt-list)
+ )
+)
diff --git a/cgen/insn.scm b/cgen/insn.scm
new file mode 100644
index 00000000000..bb39a7f6b39
--- /dev/null
+++ b/cgen/insn.scm
@@ -0,0 +1,958 @@
+; Instruction definitions.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Class to hold an insn.
+
+(define <insn>
+ (class-make '<insn>
+ '(<ident>)
+ '(
+ ; Used to explicitly specify mnemonic, now it's computed from
+ ; syntax string. ??? Might be useful as an override someday.
+ ;mnemonic
+
+ ; Instruction syntax string.
+ syntax
+
+ ; The insn fields as specified in the .cpu file.
+ ; Also contains values for constant fields.
+ iflds
+ (iflds-values . #f) ; Lazily computed cache
+
+ ; RTL source of assertions of ifield values or #f if none.
+ ; This is used, for example, by the decoder to help
+ ; distinguish what would otherwise be an ambiguity in the
+ ; specification. It is also used by decode-split support.
+ ; ??? It could also be used the the assembler/disassembler
+ ; some day.
+ (ifield-assertion . #f)
+
+ ; The <fmt-desc> of the insn.
+ ; This is used to help calculate the ifmt,sfmt members.
+ fmt-desc
+
+ ; The <iformat> of the insn.
+ ifmt
+
+ ; The <sformat> of the insn.
+ sfmt
+
+ ; Temp slot for use by applications.
+ ; ??? Will go away in time.
+ tmp
+
+ ; Instruction semantics.
+ ; This is the rtl in source form or #f if there is none.
+ ;
+ ; There are a few issues (ick, I hate that word) to consider
+ ; here:
+ ; - some apps don't need the trap checks (e.g. SIGSEGV)
+ ; - some apps treat the pieces in different ways
+ ; - the simulator tries to merge common fragments among insns
+ ; to reduce code size in a pbb simulator
+ ;
+ ; Some insns don't have any semantics at all, they are defined
+ ; in another insn [akin to anonymous patterns in gcc]. wip.
+ ;
+ ; ??? GCC-like apps will need a new field to allow specifying
+ ; the semantics if a different value is needed. wip.
+ ; ??? May wish to put this and the compiled forms in a
+ ; separate class.
+ ; ??? Contents of trap expressions is wip. It will probably
+ ; be a sequence with an #:errchk modifier or some such.
+ (semantics . #f)
+
+ ; The processed form of the above.
+ ; Each element of rtl is replaced with the associated object.
+ (compiled-semantics . #f)
+
+ ; The mapping of the semantics onto the host.
+ ; FIXME: Not sure what its value will be.
+ ; Another thing that will be needed is [in some cases] a more
+ ; simplified version of the RTL for use by apps like compilers.
+ ; Perhaps that's what this will become.
+ host-semantics
+
+ ; The function unit usage of the instruction.
+ timing
+ )
+ nil)
+)
+
+(method-make-make! <insn>
+ '(name comment attrs syntax iflds ifield-assertion
+ semantics timing)
+)
+
+; Accessor fns
+
+(define-getters <insn> insn
+ (syntax iflds ifield-assertion fmt-desc ifmt sfmt tmp
+ semantics compiled-semantics host-semantics timing)
+)
+
+(define-setters <insn> insn
+ (fmt-desc ifmt sfmt ifield-assertion compiled-semantics)
+)
+
+; Return a boolean indicating if X is an <insn>.
+
+(define (insn? x) (class-instance? <insn> x))
+
+; Return a list of the machs that support INSN.
+
+(define (insn-machs insn)
+ nil ; ??? wip
+)
+
+; Return the length of INSN in bits.
+
+(define (insn-length insn)
+ (ifmt-length (insn-ifmt insn))
+)
+
+; Return the length of INSN in bytes.
+
+(define (insn-length-bytes insn)
+ (bits->bytes (insn-length insn))
+)
+
+; Return instruction mnemonic.
+; This is computed from the syntax string.
+; The mnemonic, as we define it, is everything up to, but not including, the
+; first space or '$'.
+; FIXME: Rename to syntax-mnemonic, and take a syntax string argument.
+
+(define (insn-mnemonic insn)
+ (letrec ((mnem-len (lambda (str len)
+ (cond ((= (string-length str) 0) len)
+ ((char=? #\space (string-ref str 0)) len)
+ ((char=? #\$ (string-ref str 0)) len)
+ (else (mnem-len (string-drop1 str) (+ len 1)))))))
+ (string-take (mnem-len (insn-syntax insn) 0) (insn-syntax insn)))
+)
+
+; Return enum cgen_insn_types value for INSN.
+
+(define (insn-enum insn)
+ (string-upcase (string-append "@ARCH@_INSN_" (gen-sym insn)))
+)
+
+; Return enum for insn named INSN-NAME.
+; This is needed for the `invalid' insn, there is no object for it.
+; [Though obviously having such an object seems like a good idea.]
+
+(define (gen-insn-enum insn-name)
+ (string-upcase (string-append "@ARCH@_INSN_" (gen-c-symbol insn-name)))
+)
+
+; Insns with derived operands (see define-derived-operand).
+; ??? These are [currently] recorded separately to minimize impact on existing
+; code while the design is worked out.
+;
+; The class is called <multi-insn> because the insn has multiple variants,
+; one for each combination of "anyof" alternatives.
+; Internally we create one <insn> per alternative. The theory is that this
+; will remain an internal implementation issue. When appropriate applications
+; will collapse the number of insns in a way that is appropriate for them.
+;
+; ??? Another way to do this is with insn templates. One problem the current
+; way has is that it requires each operand's assembler syntax to be self
+; contained (one way to fix this is to use "fake" operands like before).
+; Insn templates needn't have this problem. On the other hand insn templates
+; [seem to] require more description file entries.
+;
+; ??? This doesn't use all of the members of <insn>.
+; The <multi-insn> class is wip, but should eventually reorganize <insn>.
+; This reorganization might also take into account real, virtual, etc. insns.
+
+(define <multi-insn>
+ (class-make '<multi-insn>
+ '(<insn>)
+ '(
+ ; An <insn> is created for each combination of "anyof"
+ ; alternatives. They are recorded with other insns, but a
+ ; list of them is recorded here as well.
+ ; This is #f if the sub-insns haven't been instantiated yet.
+ (sub-insns . #f)
+ )
+ nil)
+)
+
+(method-make-make! <multi-insn>
+ '(name comment attrs syntax iflds ifield-assertion
+ semantics timing)
+)
+
+(define-getters <multi-insn> multi-insn (sub-insns))
+
+; Return a boolean indicating if X is a <multi-insn>.
+
+(define (multi-insn? x) (class-instance? <multi-insn> x))
+
+; Subroutine of -sub-insn-make! to create the ifield list.
+; Return encoding of {insn} with each element of {anyof-operands} replaced
+; with {new-values}.
+; {value-names} is a list of names of {anyof-operands}.
+
+(define (-sub-insn-ifields insn anyof-operands value-names new-values)
+ ; (debug-repl-env insn anyof-operands value-names new-values)
+
+ ; Delete ifields of {anyof-operands} and add those for {new-values}.
+ (let ((iflds
+ (append!
+ ; Delete ifields in {anyof-operands}.
+ (find (lambda (f)
+ (not (and (ifld-anyof-operand? f)
+ (memq (obj:name (ifld-get-value f))
+ value-names))))
+ (insn-iflds insn))
+ ; Add ifields for {new-values}.
+ (map derived-encoding new-values)))
+
+ ; Return the last ifield of OWNER in IFLD-LIST.
+ ; OWNER is the object that owns the <ifield> we want.
+ ; For ifields, the owner is the ifield itself.
+ ; For operands, the owner is the operand.
+ ; For derived operands, the owner is the "anyof" parent.
+ ; IFLD-LIST is an unsorted list of <ifield> elements.
+ (find-preceder
+ (lambda (ifld-list owner)
+ ;(debug-repl-env ifld-list owner)
+ (cond ((ifield? owner)
+ owner)
+ ((anyof-operand? owner)
+ ; This is the interesting case. The instantiated choice of
+ ; {owner} is in {ifld-list}. We have to find it.
+ (let* ((name (obj:name owner))
+ (result
+ (find-first (lambda (f)
+ (and (derived-ifield? f)
+ (anyof-instance? (derived-ifield-owner f))
+ (eq? name (obj:name (anyof-instance-parent (derived-ifield-owner f))))))
+ ifld-list)))
+ ;(debug-repl-env ifld-list owner)
+ (assert result)
+ result))
+ ((operand? owner) ; derived operands are handled here too
+ (let ((result (op-ifield owner)))
+ (assert result)
+ result))
+ (else
+ (error "`owner' not <ifield>, <operand>, or <derived-operand>")))))
+ )
+
+ ; Resolve any `follows' specs.
+ ; Bad worst case performance but ifield lists aren't usually that long.
+ ; FIXME: Doesn't handle A following B following C.
+ (map (lambda (f)
+ (let ((follows (ifld-follows f)))
+ (if follows
+ (let ((preceder (find-preceder iflds follows)))
+ (ifld-new-word-offset f (ifld-next-word preceder)))
+ f)))
+ iflds))
+)
+
+
+; Subroutine of multi-insn-instantiate! to instantiate one insn.
+; INSN is the parent insn.
+; ANYOF-OPERANDS is a list of the <anyof-operand>'s of INSN.
+; NEW-VALUES is a list of the value to use for each corresponding element in
+; ANYOF-OPERANDS. Each element is a <derived-operand>.
+
+(define (-sub-insn-make! insn anyof-operands new-values)
+ ;(debug-repl-env insn anyof-operands new-values)
+ (assert (= (length anyof-operands) (length new-values)))
+ (assert (all-true? (map anyof-operand? anyof-operands)))
+ (assert (all-true? (map derived-operand? new-values)))
+ (logit 3 "Instantiating "
+ (obj:name insn)
+ ":"
+ (string-map (lambda (op newval)
+ (string-append " "
+ (obj:name op)
+ "="
+ (obj:name newval)))
+ anyof-operands new-values)
+ " ...\n")
+
+; (if (eq? '@sib+disp8-QI-disp32-8
+; (obj:name (car new-values)))
+; (debug-repl-env insn anyof-operands new-values))
+
+ (let* ((value-names (map obj:name anyof-operands))
+ (ifields (-sub-insn-ifields insn anyof-operands value-names new-values))
+ (known-values (ifld-known-values ifields)))
+
+ ; Don't create insn if ifield assertions fail.
+ (if (all-true? (map (lambda (op)
+ (anyof-satisfies-assertions? op known-values))
+ new-values))
+
+ (let ((sub-insn
+ (make <insn>
+ (apply symbol-append
+ (cons (obj:name insn)
+ (map (lambda (anyof)
+ (symbol-append '- (obj:name anyof)))
+ new-values)))
+ (obj:comment insn)
+ (obj-atlist insn)
+ (-anyof-merge-syntax (insn-syntax insn)
+ value-names new-values)
+ ifields
+ (insn-ifield-assertion insn) ; FIXME
+ (anyof-merge-semantics (insn-semantics insn)
+ value-names new-values)
+ (insn-timing insn)
+ )))
+ (logit 3 " instantiated.\n")
+ (current-insn-add! sub-insn))
+
+ (begin
+ logit 3 " failed ifield assertions.\n")))
+
+ *UNSPECIFIED*
+)
+
+; Instantiate all sub-insns of MULTI-INSN.
+; ??? Might be better to return the list of insns, rather than add them to
+; the global list, and leave it to the caller to add them.
+
+(define (multi-insn-instantiate! multi-insn)
+ (logit 2 "Instantiating " (obj:name multi-insn) " ...\n")
+
+ ; We shouldn't get called more than once.
+ ; ??? Though we could ignore second and subsequent calls.
+ (assert (not (multi-insn-sub-insns multi-insn)))
+
+ (let ((iflds (insn-iflds multi-insn)))
+
+ ; What we want to create here is the set of all "anyof" alternatives.
+ ; From that we create one <insn> per alternative.
+
+ (let ((anyof-iflds (find ifld-anyof-operand? iflds)))
+
+ (assert (all-true? (map anyof-operand? (map ifld-get-value anyof-iflds))))
+ ;(display (obj:name multi-insn) (current-error-port))
+ ;(display " anyof: " (current-error-port))
+ ;(display (map obj:name (map ifld-get-value anyof-iflds)) (current-error-port))
+ ;(newline (current-error-port))
+
+ ; Iterate over all combinations.
+ ; TODO is a list with one element for each <anyof-operand>.
+ ; Each element is in turn a list of all choices (<derived-operands>'s)
+ ; for the <anyof-operand>. Note that some of these values may be
+ ; derived from nested <anyof-operand>'s.
+ ; ??? anyof-all-choices should cache the results.
+ ; ??? Need to cache results of assertion processing in addition or
+ ; instead of anyof-all-choices.
+
+ (let* ((anyof-operands (map ifld-get-value anyof-iflds))
+ (todo (map anyof-all-choices anyof-operands))
+ (lengths (map length todo))
+ (total (apply * lengths)))
+ ; ??? One might prefer a `do' loop here, but every time I see one I
+ ; have to spend too long remembering its syntax.
+ (let loop ((i 0))
+ (if (< i total)
+ (let* ((indices (split-value lengths i))
+ (anyof-instances (map list-ref todo indices)))
+ ;(display "derived: " (current-error-port))
+ ;(display (map obj:name anyof-instances) (current-error-port))
+ ;(newline (current-error-port))
+ (-sub-insn-make! multi-insn anyof-operands anyof-instances)
+ (loop (+ i 1))))))))
+
+ *UNSPECIFIED*
+)
+
+; Parse an instruction description.
+; This is the main routine for building an insn object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if insn isn't for selected mach(s).
+
+(define (-insn-parse errtxt name comment attrs syntax fmt ifield-assertion
+ semantics timing)
+ (logit 2 "Processing insn " name " ...\n")
+
+ (let ((name (parse-name name errtxt))
+ (atlist-obj (atlist-parse attrs "cgen_insn" errtxt)))
+
+ (if (keep-atlist? atlist-obj #f)
+
+ (let ((ifield-assertion (if (not (null? ifield-assertion))
+ ifield-assertion
+ #f))
+ (semantics (if (not (null? semantics))
+ semantics
+ #f))
+ (format (-parse-insn-format (string-append errtxt " format")
+ fmt))
+ (comment (parse-comment comment errtxt))
+ ; If there are no semantics, mark this as an alias.
+ ; ??? Not sure this makes sense for multi-insns.
+ (atlist-obj (if semantics
+ atlist-obj
+ (atlist-cons (bool-attr-make 'ALIAS #t)
+ atlist-obj)))
+ (syntax (parse-syntax syntax errtxt))
+ (timing (parse-insn-timing errtxt timing))
+ )
+
+ (if (anyof-operand-format? format)
+
+ (make <multi-insn>
+ name comment atlist-obj
+ syntax
+ format
+ ifield-assertion
+ semantics
+ timing)
+
+ (make <insn>
+ name comment atlist-obj
+ syntax
+ format
+ ifield-assertion
+ semantics
+ timing)))
+
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read an instruction description.
+; This is the main routine for analyzing instructions in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -insn-parse is invoked to create the <insn> object.
+
+(define (insn-read errtxt . arg-list)
+ (let ((name nil)
+ (comment "")
+ (attrs nil)
+ (syntax nil)
+ (fmt nil)
+ (ifield-assertion nil)
+ (semantics nil)
+ (timing nil)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((syntax) (set! syntax (cadr arg)))
+ ((format) (set! fmt (cadr arg)))
+ ((ifield-assertion) (set! ifield-assertion (cadr arg)))
+ ((semantics) (set! semantics (cadr arg)))
+ ((timing) (set! timing (cdr arg)))
+ (else (parse-error errtxt "invalid insn arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-insn-parse errtxt name comment attrs syntax fmt ifield-assertion
+ semantics timing)
+ )
+)
+
+; Define an instruction object, name/value pair list version.
+
+(define define-insn
+ (lambda arg-list
+ (let ((i (apply insn-read (cons "define-insn" arg-list))))
+ (if i
+ (current-insn-add! i))
+ i))
+)
+
+; Define an instruction object, all arguments specified.
+
+(define (define-full-insn name comment attrs syntax fmt ifield-assertion
+ semantics timing)
+ (let ((i (-insn-parse "define-full-insn" name comment attrs
+ syntax fmt ifield-assertion
+ semantics timing)))
+ (if i
+ (current-insn-add! i))
+ i)
+)
+
+; Parsing support.
+
+; Parse an insn syntax field.
+; SYNTAX is either a string or a list of strings, each element of which may
+; in turn be a list of strings.
+; ??? Not sure this extra flexibility is worth it yet.
+
+(define (parse-syntax syntax errtxt)
+ (cond ((list? syntax)
+ (string-map (lambda (elm) (parse-syntax elm errtxt)) syntax))
+ ((or (string? syntax) (symbol? syntax))
+ syntax)
+ (else (parse-error errtxt "improper syntax" syntax)))
+)
+
+; Subroutine of -parse-insn-format to parse a symbol ifield spec.
+
+(define (-parse-insn-format-symbol errtxt sym)
+ ;(debug-repl-env sym)
+ (let ((op (current-op-lookup sym)))
+ (if op
+ (cond ((derived-operand? op)
+ ; There is a one-to-one relationship b/w derived operands and
+ ; the associated derived ifield.
+ (let ((ifld (op-ifld op)))
+ (assert (derived-ifield? ifld))
+ ifld))
+ ((anyof-operand? op)
+ (ifld-new-value f-anyof op))
+ (else
+ (let ((ifld (op-ifield op)))
+ (ifld-new-value ifld op))))
+ ; An insn-enum?
+ (let ((e (ienum-lookup-val sym)))
+ (if e
+ (ifld-new-value (ienum:fld (cdr e)) (car e))
+ (parse-error errtxt "bad format element" sym)))))
+)
+
+; Subroutine of -parse-insn-format to parse an (ifield-name value) ifield spec.
+;
+; The last element is the ifield's value. It must be an integer.
+; ??? Whether it can be negative is still unspecified.
+; ??? While there might be a case where allowing floating point values is
+; desirable, supporting them would require precise conversion routines.
+; They should be rare enough that we instead punt.
+;
+; ??? May wish to support something like "(% startbit bitsize value)".
+;
+; ??? Error messages need improvement, but that's generally true of cgen.
+
+(define (-parse-insn-format-ifield-spec errtxt ifld ifld-spec)
+ (if (!= (length ifld-spec) 2)
+ (parse-error errtxt "bad ifield format, should be (ifield-name value)" ifld-spec))
+
+ (let ((value (cadr ifld-spec)))
+ ; ??? This use to allow (ifield-name operand-name). That's how
+ ; `operand-name' elements are handled, but there's no current need
+ ; to handle (ifield-name operand-name).
+ (if (not (integer? value))
+ (parse-error errtxt "ifield value not an integer" ifld-spec))
+ (ifld-new-value ifld value))
+)
+
+; Subroutine of -parse-insn-format to parse an
+; (ifield-name value) ifield spec.
+; ??? There is room for growth in the specification syntax here.
+; Possibilities are (ifield-name|operand-name [options] [value]).
+
+(define (-parse-insn-format-list errtxt spec)
+ (let ((ifld (current-ifld-lookup (car spec))))
+ (if ifld
+ (-parse-insn-format-ifield-spec errtxt ifld spec)
+ (parse-error errtxt "unknown ifield" spec)))
+)
+
+; Given an insn format field from a .cpu file, replace it with a list of
+; ifield objects with the values assigned.
+;
+; An insn format field is a list of ifields that make up the instruction.
+; All bits must be specified, including reserved bits
+; [at present no checking is made of this, but the rule still holds].
+;
+; A normal entry begins with `+' and then consist of the following:
+; - operand name
+; - (ifield-name [options] value)
+; - (operand-name [options] [value])
+; - insn ifield enum
+;
+; Example: (+ OP1_ADD (f-res2 0) dr src1 (f-src2 1) (f-res1 #xea))
+;
+; where OP1_ADD is an enum, dr and src1 are operands, and f-src2 and f-res1
+; are ifield's. The `+' allows for future extension.
+;
+; The other form of entry begins with `=' and is followed by an instruction
+; name that has the same format. The specified instruction must already be
+; defined. Instructions with this form typically also include an
+; `ifield-assertion' spec to keep them separate.
+;
+; An empty field list is ok. This means it's unspecified.
+; VIRTUAL insns have this.
+;
+; This is one of the more important routines to be efficient.
+; It's called for each instruction, and is one of the more expensive routines
+; in insn parsing.
+
+(define (-parse-insn-format errtxt fld-list)
+ (if (null? fld-list)
+ nil ; field list unspecified
+ (case (car fld-list)
+ ((+) (map (lambda (fld)
+ (let ((f (if (string? fld)
+ (string->symbol fld)
+ fld)))
+ (cond ((symbol? f)
+ (-parse-insn-format-symbol errtxt f))
+ ((and (list? f)
+ ; ??? This use to allow <ifield> objects
+ ; in the `car' position. Checked for below.
+ (symbol? (car f)))
+ (-parse-insn-format-list errtxt f))
+ (else
+ (if (and (list? f)
+ (ifield? (car f)))
+ (parse-error errtxt "FIXME: <ifield> object in format spec"))
+ (parse-error errtxt "bad format element" f)))))
+ (cdr fld-list)))
+ ((=) (begin
+ (if (or (!= (length fld-list) 2)
+ (not (symbol? (cadr fld-list))))
+ (parse-error errtxt
+ "bad `=' format spec, should be `(= insn-name)'"
+ fld-list))
+ (let ((insn (current-insn-lookup (cadr fld-list))))
+ (if (not insn)
+ (parse-error errtxt "unknown insn" (cadr fld-list)))
+ (insn-iflds insn))))
+ (else
+ (parse-error errtxt "format must begin with `+' or `='" fld-list))
+ ))
+)
+
+; Return a boolean indicating if IFLD-LIST contains anyof operands.
+
+(define (anyof-operand-format? ifld-list)
+ (any-true? (map (lambda (f)
+ (or (ifld-anyof? f)
+ (derived-ifield? f)))
+ ifld-list))
+)
+
+; Insn utilities.
+; ??? multi-insn support wip, may require changes here.
+
+; Return a boolean indicating if INSN is an alias insn.
+
+(define (insn-alias? insn)
+ (obj-has-attr? insn 'ALIAS)
+)
+
+; Return a list of instructions that are not aliases in INSN-LIST.
+
+(define (non-alias-insns insn-list)
+ (find (lambda (insn)
+ (not (insn-alias? insn)))
+ insn-list)
+)
+
+; Return a boolean indicating if INSN is a "real" INSN
+; (not ALIAS and not VIRTUAL and not a <multi-insn>).
+
+(define (insn-real? insn)
+ (let ((atlist (obj-atlist insn)))
+ (and (not (atlist-has-attr? atlist 'ALIAS))
+ (not (atlist-has-attr? atlist 'VIRTUAL))
+ (not (multi-insn? insn))))
+)
+
+; Return a list of real instructions in INSN-LIST.
+
+(define (real-insns insn-list)
+ (find insn-real? insn-list)
+)
+
+; Return a boolean indicating if INSN is a virtual insn.
+
+(define (insn-virtual? insn)
+ (obj-has-attr? insn 'VIRTUAL)
+)
+
+; Return a list of virtual instructions in INSN-LIST.
+
+(define (virtual-insns insn-list)
+ (find insn-virtual? insn-list)
+)
+
+; Return a list of non-alias/non-pbb insns in INSN-LIST.
+
+(define (non-alias-pbb-insns insn-list)
+ (find (lambda (insn)
+ (let ((atlist (obj-atlist insn)))
+ (and (not (atlist-has-attr? atlist 'ALIAS))
+ (not (atlist-has-attr? atlist 'PBB)))))
+ insn-list)
+)
+
+; Return a list of multi-insns in INSN-LIST.
+
+(define (multi-insns insn-list)
+ (find multi-insn? insn-list)
+)
+
+; And the opposite:
+
+(define (non-multi-insns insn-list)
+ (find (lambda (insn) (not (multi-insn? insn))) insn-list)
+)
+
+
+; Filter out instructions whose ifield patterns are strict subsets of
+; another. For decoding purpose, it is sufficient to consider the
+; more general cousin.
+
+(define (filter-harmlessly-ambiguous-insns insn-list)
+ (logit 3 "Filtering " (length insn-list) " instructions.\n")
+ (find (lambda (insn)
+ (let* ((i-mask (insn-base-mask insn))
+ (i-mask-len (insn-base-mask-length insn))
+ (i-value (insn-value insn))
+ (superset-insn (find-first
+ (lambda (insn2) ; insn2: possible supermatch (fewer mask bits)
+ (let ((i2-mask (insn-base-mask insn2))
+ (i2-mask-len (insn-base-mask-length insn2))
+ (i2-value (insn-value insn2)))
+ (and (not (eq? insn insn2))
+ (= i-mask-len i2-mask-len)
+ (mask-superset? i2-mask i2-value i-mask i-value))))
+ insn-list))
+ (keep? (not superset-insn)))
+ (if (not keep?)
+ (logit 2
+ "Instruction " (obj:name insn) "ambiguity-filtered by "
+ (obj:name superset-insn) "\n"))
+ keep?))
+ insn-list)
+)
+
+
+; Helper function for above: does (m1,v1) match a superset of (m2,v2) ?
+;
+; eg> mask-superset? #b1100 #b1000 #b1110 #b1010 -> #t
+; eg> mask-superset? #b1100 #b1000 #b1010 #b1010 -> #f
+; eg> mask-superset? #b1100 #b1000 #b1110 #b1100 -> #f
+(define (mask-superset? m1 v1 m2 v2)
+ (let ((result
+ (and (= (cg-logand m1 m2) m1)
+ (= (cg-logand m1 v1) (cg-logand m1 v2)))))
+ (if result (logit 4
+ "(" (number->string m1 16) "," (number->string v1 16) ")"
+ " contains "
+ "(" (number->string m2 16) "," (number->string v2 16) ")"
+ "\n"))
+ result)
+)
+
+
+
+
+; Return a boolean indicating if INSN is a cti [control transfer insn].
+; This includes SKIP-CTI insns even though they don't terminate a basic block.
+; ??? SKIP-CTI insns are wip, waiting for more examples of how they're used.
+
+(define (insn-cti? insn)
+ (atlist-cti? (obj-atlist insn))
+)
+
+; Return a boolean indicating if INSN can be executed in parallel.
+; Such insns are required to have enum attribute PARALLEL != NO.
+; This is worded specifically to allow the PARALLEL attribute to have more
+; than just NO/YES values (should a target want to do so).
+; This specification may not be sufficient, but the intent is explicit.
+
+(define (insn-parallel? insn)
+ (let ((atval (obj-attr-value insn 'PARALLEL)))
+ (and atval (not (eq? atval 'NO))))
+)
+
+; Return a list of the insns that support parallel execution in INSN-LIST.
+
+(define (parallel-insns insn-list)
+ (find insn-parallel? insn-list)
+)
+
+; Instruction field utilities.
+
+; Return a boolean indicating if INSN has ifield named F-NAME.
+
+(define (insn-has-ifield? insn f-name)
+ (->bool (object-assq f-name (insn-iflds insn)))
+)
+
+; Insn opcode value utilities.
+
+; Given INSN, return the length in bits of the base mask (insn-base-mask).
+
+(define (insn-base-mask-length insn)
+ (ifmt-mask-length (insn-ifmt insn))
+)
+
+; Given INSN, return the bitmask of constant values (the opcode field)
+; in the base part.
+
+(define (insn-base-mask insn)
+ (ifmt-mask (insn-ifmt insn))
+)
+
+; Given INSN, return the sum of the constant values in the insn
+; (i.e. the opcode field).
+;
+; See also (compute-insn-base-mask).
+;
+(define (insn-value insn)
+ (if (elm-get insn 'iflds-values)
+ (elm-get insn 'iflds-values)
+ (let* ((base-len (insn-base-mask-length insn))
+ (value (apply +
+ (map (lambda (fld) (ifld-value fld base-len (ifld-get-value fld)))
+ (find ifld-constant?
+ (collect ifld-base-ifields (insn-iflds insn))))
+ )))
+ (elm-set! insn 'iflds-values value)
+ value)
+ )
+ )
+
+; Insn operand utilities.
+
+; Lookup operand SEM-NAME in INSN.
+
+(define (insn-lookup-op insn sem-name)
+ (or (op:lookup-sem-name (sfmt-in-ops (insn-sfmt insn)) sem-name)
+ (op:lookup-sem-name (sfmt-out-ops (insn-sfmt insn)) sem-name))
+)
+
+; Insn syntax utilities.
+
+; Create a list of syntax strings broken up into a list of characters and
+; operand objects.
+
+(define (syntax-break-out syntax)
+ (let ((result nil))
+ ; ??? The style of the following could be more Scheme-like. Later.
+ (let loop ()
+ (if (> (string-length syntax) 0)
+ (begin
+ (cond
+ ; Handle escaped syntax metacharacters
+ ((char=? #\\ (string-ref syntax 0))
+ (set! result (cons (substring syntax 0 1) result))
+ (set! result (cons (substring syntax 1 1) result))
+ (set! syntax (string-drop 2 syntax)))
+ ; Handle operand reference
+ ((char=? #\$ (string-ref syntax 0))
+ ; Extract the symbol from the string, get the operand.
+ (if (char=? #\{ (string-ref syntax 1))
+ (let ((n (string-index syntax #\})))
+ (set! result (cons (current-op-lookup
+ (string->symbol
+ (substring syntax 2 n)))
+ result))
+ (set! syntax (string-drop (+ 1 n) syntax)))
+ (let ((n (id-len (string-drop1 syntax))))
+ (set! result (cons (current-op-lookup
+ (string->symbol
+ (substring syntax 1 (+ 1 n))))
+ result))
+ (set! syntax (string-drop (+ 1 n) syntax)))))
+ ; Handle everything else
+ (else (set! result (cons (substring syntax 0 1) result))
+ (set! syntax (string-drop1 syntax))))
+ (loop))))
+ (reverse result))
+ )
+
+; Given a list of syntax elements (e.g. the result of syntax-break-out),
+; create a syntax string.
+
+(define (syntax-make elements)
+ (apply string-append
+ (map (lambda (e)
+ (cond ((char? e)
+ (string "\\" e))
+ ((string? e)
+ e)
+ (else
+ (assert (operand? e))
+ (string-append "${" (obj:name e) "}"))))
+ elements))
+)
+
+; Called before a .cpu file is read in.
+
+(define (insn-init!)
+ (reader-add-command! 'define-insn
+ "\
+Define an instruction, name/value pair list version.
+"
+ nil 'arg-list define-insn)
+ (reader-add-command! 'define-full-insn
+ "\
+Define an instruction, all arguments specified.
+"
+ nil '(name comment attrs syntax fmt ifield-assertion semantics timing)
+ define-full-insn)
+
+ *UNSPECIFIED*
+)
+
+; Called before a . cpu file is read in to install any builtins.
+
+(define (insn-builtin!)
+ ; Standard insn attributes.
+ ; ??? Some of these can be combined into one.
+
+ (define-attr '(for insn) '(type boolean) '(name UNCOND-CTI) '(comment "unconditional cti"))
+
+ (define-attr '(for insn) '(type boolean) '(name COND-CTI) '(comment "conditional cti"))
+
+ ; SKIP-CTI: one or more immediately following instructions are conditionally
+ ; executed (or skipped)
+ (define-attr '(for insn) '(type boolean) '(name SKIP-CTI) '(comment "skip cti"))
+
+ ; DELAY-SLOT: insn has one or more delay slots (wip)
+ (define-attr '(for insn) '(type boolean) '(name DELAY-SLOT) '(comment "insn has a delay slot"))
+
+ ; RELAXABLE: Insn has one or more identical but larger variants.
+ ; The assembler tries this one first and then the relaxation phase
+ ; switches to the larger ones as necessary.
+ ; All insns of identical behaviour have a RELAX_FOO attribute that groups
+ ; them together.
+ ; FIXME: This is a case where we need one attribute with several values.
+ ; Presently each RELAX_FOO will use up a bit.
+ (define-attr '(for insn) '(type boolean) '(name RELAXABLE) '(comment "insn is relaxable"))
+
+ ; RELAX: Large relaxable variant. Avoided by assembler in first pass.
+ ; FIXME: Rename this to RELAXED.
+ (define-attr '(for insn) '(type boolean) '(name RELAX) '(comment "relaxed form of insn"))
+
+ ; NO-DIS: For macro insns, do not use during disassembly.
+ (define-attr '(for insn) '(type boolean) '(name NO-DIS) '(comment "don't use for disassembly"))
+
+ ; PBB: Virtual insn used for PBB support.
+ (define-attr '(for insn) '(type boolean) '(name PBB) '(comment "virtual insn used for PBB support"))
+
+ ; DECODE-SPLIT: insn resulted from decode-split processing
+ (define-attr '(for insn) '(type boolean) '(name DECODE-SPLIT) '(comment "insn split from another insn for decoding purposes") '(attrs META))
+
+ ; Also (defined elsewhere):
+ ; VIRTUAL: Helper insn used by the simulator.
+
+ *UNSPECIFIED*
+)
+
+; Called after the .cpu file has been read in.
+
+(define (insn-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/m32r.cpu b/cgen/m32r.cpu
new file mode 100644
index 00000000000..047e257bfae
--- /dev/null
+++ b/cgen/m32r.cpu
@@ -0,0 +1,2088 @@
+; Mitsubishi M32R CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+(include "simplify.inc")
+
+; FIXME: Delete sign extension of accumulator results.
+; Sign extension is done when accumulator is read.
+
+; define-arch must appear first
+
+(define-arch
+ (name m32r) ; name of cpu family
+ (comment "Mitsubishi M32R")
+ (default-alignment aligned)
+ (insn-lsb0? #f)
+ (machs m32r m32rx)
+ (isas m32r)
+)
+
+; Attributes.
+
+; An attribute to describe which pipeline an insn runs in.
+(define-attr
+ (for insn)
+ (type enum)
+ (name PIPE)
+ (comment "parallel execution pipeline selection")
+ (values NONE O S OS)
+)
+; A derived attribute that says which insns can be executed in parallel
+; with others. This is a required attribute for architectures with
+; parallel execution.
+(define-attr
+ (for insn)
+ (type enum)
+ (name PARALLEL)
+ (attrs META) ; do not define in any generated file for now
+ (values NO YES)
+ (default (if (eq-attr (current-insn) PIPE NONE) (symbol NO) (symbol YES)))
+)
+
+; Instruction set parameters.
+
+(define-isa
+ (name m32r)
+
+ ; This is 32 because 16 bit insns always appear as pairs.
+ ; ??? See if this can go away. It's only used by the disassembler (right?)
+ ; to decide how long an unknown insn is. One value isn't sufficient (e.g. if
+ ; on a 16 bit (and not 32 bit) boundary, will only want to advance pc by 16.)
+ (default-insn-bitsize 32)
+
+ ; Number of bytes of insn we can initially fetch.
+ ; The M32R is tricky in that insns are either two 16-bit insns
+ ; (executed sequentially or in parallel) or one 32-bit insn.
+ ; So on one hand the base insn size is 16 bits, but on another it's 32.
+ ; 32 is chosen because:
+ ; - if the chip were ever bi-endian it is believed that the byte order would
+ ; be based on 32 bit quantities
+ ; - 32 bit insns are always aligned on 32 bit boundaries
+ ; - the pc will never stop on a 16 bit (and not 32 bit) boundary
+ ; [well actually it can, but there are no branches to such places]
+ (base-insn-bitsize 32)
+
+ ; Used in computing bit numbers.
+ (default-insn-word-bitsize 32)
+
+ ; The m32r fetches 2 insns at a time.
+ (liw-insns 2)
+
+ ; While the m32r can execute insns in parallel, the base mach can't
+ ; (other than nop). The base mach is greatly handicapped by this, but
+ ; we still need to cleanly handle it.
+ (parallel-insns 2)
+
+ ; Initial bitnumbers to decode insns by.
+ (decode-assist (0 1 2 3 8 9 10 11))
+
+ ; Classification of instructions that fit in the various frames.
+ ; wip, not currently used
+ (insn-types (long ; name
+ 31 ; length
+ (eq-attr (current-insn) LENGTH 31) ; matching insns
+ (0 1 2 7 8 9 10) ; decode-assist
+ )
+ (short
+ 15
+ (eq-attr (current-insn) LENGTH 15) ; matching insns
+ (0 1 2 7 8 9 10)
+ )
+ )
+
+ ; Instruction framing.
+ ; Each m32r insn is either one 32 bit insn, two 16 bit insns executed
+ ; serially (left->right), or two 16 bit insns executed parallelly.
+ ; wip, not currently used
+ (frame long32 ; name
+ ((long)) ; list of insns in frame, plus constraint
+ "$0" ; assembler
+ (+ (1 1) (31 $0)) ; value
+ (sequence () (execute $0)) ; action
+ )
+ (frame serial2x16
+ ((short)
+ (short))
+ "$0 -> $1"
+ (+ (1 0) (15 $0) (1 0) (15 $1))
+ (sequence ()
+ (execute $0)
+ (execute $1))
+ )
+ (frame parallel2x16
+ ((short (eq-attr (current-insn) PIPE "O,BOTH"))
+ (short (eq-attr (current-insn) PIPE "S,BOTH")))
+ "$0 || $1"
+ (+ (1 0) (15 $0) (1 1) (15 $1))
+ (parallel ()
+ (execute $0)
+ (execute $1))
+ )
+)
+
+; Cpu family definitions.
+
+; ??? define-cpu-family [and in general "cpu-family"] might be clearer than
+; define-cpu.
+; ??? Have define-arch provide defaults for architecture that define-cpu can
+; then override [reduces duplication in define-cpu].
+; ??? Another way to go is to delete cpu-families entirely and have one mach
+; able to inherit things from another mach (would also need the ability to
+; not only override specific inherited things but also disable some,
+; e.g. if an insn wasn't supported).
+
+(define-cpu
+ ; cpu names must be distinct from the architecture name and machine names.
+ ; The "b" suffix stands for "base" and is the convention.
+ ; The "f" suffix stands for "family" and is the convention.
+ (name m32rbf)
+ (comment "Mitsubishi M32R base family")
+ (endian big)
+ (word-bitsize 32)
+ ; Override isa spec (??? keeps things simpler, though it was more true
+ ; in the early days and not so much now).
+ (parallel-insns 1)
+)
+
+(define-cpu
+ (name m32rxf)
+ (comment "Mitsubishi M32Rx family")
+ (endian big)
+ (word-bitsize 32)
+ ; Generated files have an "x" suffix.
+ (file-transform "x")
+)
+
+(define-mach
+ (name m32r)
+ (comment "Generic M32R cpu")
+ (cpu m32rbf)
+)
+
+(define-mach
+ (name m32rx)
+ (comment "M32RX cpu")
+ (cpu m32rxf)
+)
+
+; Model descriptions.
+
+; The meaning of this value is wip but at the moment it's intended to describe
+; the implementation (i.e. what -mtune=foo does in sparc gcc).
+;
+; Notes while wip:
+; - format of pipeline entry:
+; (pipeline name (stage1-name ...) (stage2-name ...) ...)
+; The contents of a stage description is wip.
+; - each mach must have at least one model
+; - the default model must be the first one
+;- maybe have `retire' support update total cycle count to handle current
+; parallel insn cycle counting problems
+
+(define-model
+ (name m32r/d) (comment "m32r/d") (attrs)
+ (mach m32r)
+
+ ;(prefetch)
+ ;(retire)
+
+ (pipeline p-non-mem "" () ((fetch) (decode) (execute) (writeback)))
+ (pipeline p-mem "" () ((fetch) (decode) (execute) (memory) (writeback)))
+
+ ; `state' is a list of variables for recording model state
+ (state
+ ; bit mask of h-gr registers, =1 means value being loaded from memory
+ (h-gr UINT)
+ )
+
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT -1) (dr INT -1)) ; inputs
+ ((dr INT -1)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-cmp "Compare Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT -1) (src2 INT -1)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+ (unit u-mac "Multiply/Accumulate Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT -1) (src2 INT -1)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+ (unit u-cti "Branch Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT -1)) ; inputs
+ ((pc)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-load "Memory Load Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT)
+ ;(ld-mem AI)
+ ) ; inputs
+ ((dr INT)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-store "Memory Store Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT) (src2 INT)) ; inputs
+ () ; ((st-mem AI)) ; outputs
+ () ; profile action (default)
+ )
+)
+
+(define-model
+ (name test) (comment "test") (attrs)
+ (mach m32r)
+ (pipeline all "" () ((fetch) (decode) (execute) (writeback)))
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () () () ())
+)
+
+; Each mach must have at least one model.
+
+(define-model
+ (name m32rx) (comment "m32rx") (attrs)
+ (mach m32rx)
+
+ ; ??? It's 6 stages but I forget the details right now.
+ (pipeline p-o "" () ((fetch) (decode) (execute) (writeback)))
+ (pipeline p-s "" () ((fetch) (decode) (execute) (writeback)))
+ (pipeline p-o-mem "" () ((fetch) (decode) (execute) (memory) (writeback)))
+
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT -1) (dr INT -1)) ; inputs
+ ((dr INT -1)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-cmp "Compare Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT -1) (src2 INT -1)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+ (unit u-mac "Multiply/Accumulate Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT -1) (src2 INT -1)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+ (unit u-cti "Branch Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT -1)) ; inputs
+ ((pc)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-load "Memory Load Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((sr INT)) ; inputs
+ ((dr INT)) ; outputs
+ () ; profile action (default)
+ )
+ (unit u-store "Memory Store Unit" ()
+ 1 1 ; issue done
+ () ; state
+ ((src1 INT) (src2 INT)) ; inputs
+ () ; outputs
+ () ; profile action (default)
+ )
+)
+
+; The instruction fetch/execute cycle.
+; This is split into two parts as sometimes more than one instruction is
+; decoded at once.
+; The `const SI' argument to decode/execute is used to distinguish
+; multiple instructions processed at the same time (e.g. m32r).
+;
+; ??? This is wip, and not currently used.
+; ??? Needs to be moved to define-isa.
+
+; This is how to fetch and decode an instruction.
+
+;(define-extract
+; (sequence VOID
+; (if VOID (ne AI (and AI pc (const AI 3)) (const AI 0))
+; (sequence VOID
+; (set-quiet USI (scratch UHI insn1) (ifetch UHI pc))
+; (decode VOID pc (and UHI insn1 (const UHI #x7fff))
+; (const SI 0)))
+; (sequence VOID
+; (set-quiet USI (scratch USI insn) (ifetch USI pc))
+; (if VOID (ne USI (and USI insn (const USI #x80000000))
+; (const USI 0))
+; (decode VOID pc (srl USI insn (const WI 16)) (const SI 0))
+; (sequence VOID
+; ; ??? parallel support
+; (decode VOID pc (srl USI insn (const WI 16))
+; (const SI 0))
+; (decode VOID (add AI pc (const AI 2))
+; (and USI insn (const WI #x7fff))
+; (const SI 1))))))
+; )
+;)
+
+; This is how to execute a decoded instruction.
+
+;(define-execute
+; (sequence VOID () ; () is empty option list
+; ((AI new_pc))
+; (set AI new_pc (execute: AI (const 0)) #:quiet)
+; (set AI pc new_pc #:direct)
+; )
+;)
+
+; FIXME: It might simplify things to separate the execute process from the
+; one that updates the PC.
+
+; Instruction fields.
+;
+; Attributes:
+; PCREL-ADDR: pc relative value (for reloc and disassembly purposes)
+; ABS-ADDR: absolute address (for reloc and disassembly purposes?)
+; RESERVED: bits are not used to decode insn, must be all 0
+; RELOC: there is a relocation associated with this field (experiment)
+
+(define-attr
+ (for ifield operand)
+ (type boolean)
+ (name RELOC)
+ (comment "there is a reloc associated with this field (experiment)")
+)
+
+(dnf f-op1 "op1" () 0 4)
+(dnf f-op2 "op2" () 8 4)
+(dnf f-cond "cond" () 4 4)
+(dnf f-r1 "r1" () 4 4)
+(dnf f-r2 "r2" () 12 4)
+(df f-simm8 "simm8" () 8 8 INT #f #f)
+(df f-simm16 "simm16" () 16 16 INT #f #f)
+(dnf f-shift-op2 "shift op2" () 8 3)
+(dnf f-uimm4 "uimm4" () 12 4)
+(dnf f-uimm5 "uimm5" () 11 5)
+(dnf f-uimm16 "uimm16" () 16 16)
+(dnf f-uimm24 "uimm24" (ABS-ADDR RELOC) 8 24)
+(dnf f-hi16 "high 16 bits" (SIGN-OPT) 16 16)
+(df f-disp8 "disp8, slot unknown" (PCREL-ADDR RELOC) 8 8 INT
+ ((value pc) (sra WI (sub WI value (and WI pc (const -4))) (const 2)))
+ ((value pc) (add WI (sll WI value (const 2)) (and WI pc (const -4)))))
+(df f-disp16 "disp16" (PCREL-ADDR RELOC) 16 16 INT
+ ((value pc) (sra WI (sub WI value pc) (const 2)))
+ ((value pc) (add WI (sll WI value (const 2)) pc)))
+(df f-disp24 "disp24" (PCREL-ADDR RELOC) 8 24 INT
+ ((value pc) (sra WI (sub WI value pc) (const 2)))
+ ((value pc) (add WI (sll WI value (const 2)) pc)))
+
+(dnf f-op23 "op2.3" () 9 3)
+(dnf f-op3 "op3" () 14 2)
+(dnf f-acc "acc" () 8 1)
+(dnf f-accs "accs" () 12 2)
+(dnf f-accd "accd" () 4 2)
+(dnf f-bits67 "bits67" () 6 2)
+(dnf f-bit14 "bit14" () 14 1)
+
+(define-ifield (name f-imm1) (comment "1 bit immediate, 0->1 1->2")
+ (attrs)
+ (start 15) (length 1)
+ (encode (value pc) (sub WI value (const WI 1)))
+ (decode (value pc) (add WI value (const WI 1)))
+)
+
+; Enums.
+
+; insn-op1: bits 0-3
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op1 "insn format enums" () OP1_ f-op1
+ ("0" "1" "2" "3" "4" "5" "6" "7"
+ "8" "9" "10" "11" "12" "13" "14" "15")
+)
+
+; insn-op2: bits 8-11
+; FIXME: should use die macro or some such
+(define-normal-insn-enum insn-op2 "op2 enums" () OP2_ f-op2
+ ("0" "1" "2" "3" "4" "5" "6" "7"
+ "8" "9" "10" "11" "12" "13" "14" "15")
+)
+
+; Hardware pieces.
+; These entries list the elements of the raw hardware.
+; They're also used to provide tables and other elements of the assembly
+; language.
+
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(dnh h-hi16 "high 16 bits" ()
+ (immediate (UINT 16))
+ () () ()
+)
+
+; These two aren't technically needed.
+; They're here for illustration sake mostly.
+; Plus they cause the value to be stored in the extraction buffers to only
+; be 16 bits wide (vs 32 or 64). Whoopie ding. But it's fun.
+(dnh h-slo16 "signed low 16 bits" ()
+ (immediate (INT 16))
+ () () ()
+)
+(dnh h-ulo16 "unsigned low 16 bits" ()
+ (immediate (UINT 16))
+ () () ()
+)
+
+(define-keyword
+ (name gr-names)
+ (print-name h-gr)
+ (prefix "")
+ (values (fp 13) (lr 14) (sp 15)
+ (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15))
+)
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs PROFILE CACHE-ADDR)
+ (type register WI (16))
+ (indices extern-keyword gr-names)
+)
+
+(define-keyword
+ (name cr-names)
+ (print-name h-cr)
+ (prefix "")
+ (values (psw 0) (cbr 1) (spi 2) (spu 3)
+ (bpc 6) (bbpsw 8) (bbpc 14)
+ (cr0 0) (cr1 1) (cr2 2) (cr3 3)
+ (cr4 4) (cr5 5) (cr6 6) (cr7 7)
+ (cr8 8) (cr9 9) (cr10 10) (cr11 11)
+ (cr12 12) (cr13 13) (cr14 14) (cr15 15))
+)
+
+(define-hardware
+ (name h-cr)
+ (comment "control registers")
+ (type register UWI (16))
+ (indices extern-keyword cr-names)
+ (get (index) (c-call UWI "@cpu@_h_cr_get_handler" index))
+ (set (index newval) (c-call VOID "@cpu@_h_cr_set_handler" index newval))
+)
+
+; The actual accumulator is only 56 bits.
+; The top 8 bits are sign extended from bit 8 (when counting msb = bit 0).
+; To simplify the accumulator instructions, no attempt is made to keep the
+; top 8 bits properly sign extended (currently there's no point since they
+; all ignore them). When the value is read it is properly sign extended
+; [in the `get' handler].
+(define-hardware
+ (name h-accum)
+ (comment "accumulator")
+ (type register DI)
+ (get () (c-call DI "@cpu@_h_accum_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_accum_set_handler" newval))
+)
+
+; FIXME: Revisit after sanitization can be removed. Remove h-accum.
+(define-hardware
+ (name h-accums)
+ (comment "accumulators")
+ (attrs (MACH m32rx))
+ (type register DI (2))
+ (indices keyword "" ((a0 0) (a1 1)))
+ ; get/set so a0 accesses are redirected to h-accum.
+ ; They're also so reads can properly sign extend the value.
+ ; FIXME: Needn't be a function call.
+ (get (index) (c-call DI "@cpu@_h_accums_get_handler" index))
+ (set (index newval) (c-call VOID "@cpu@_h_accums_set_handler" index newval))
+)
+
+; For condbit operand. FIXME: Need to allow spec of get/set of operands.
+; Having this separate from h-psw keeps the parts that use it simpler
+; [since they greatly outnumber those that use h-psw].
+(dsh h-cond "condition bit" () (register BI))
+
+; The actual values of psw,bpsw,bbpsw are recorded here to allow access
+; to them as a unit.
+(define-hardware
+ (name h-psw)
+ (comment "psw part of psw")
+ (type register UQI)
+ ; get/set to handle cond bit.
+ ; FIXME: missing: use's and clobber's
+ ; FIXME: remove c-call?
+ (get () (c-call UQI "@cpu@_h_psw_get_handler"))
+ (set (newval) (c-call VOID "@cpu@_h_psw_set_handler" newval))
+)
+(dsh h-bpsw "backup psw" () (register UQI))
+(dsh h-bbpsw "backup bpsw" () (register UQI))
+
+; FIXME: Later make add get/set specs and support SMP.
+(dsh h-lock "lock" () (register BI))
+
+; Instruction Operands.
+; These entries provide a layer between the assembler and the raw hardware
+; description, and are used to refer to hardware elements in the semantic
+; code. Usually there's a bit of over-specification, but in more complicated
+; instruction sets there isn't.
+
+; M32R specific operand attributes:
+
+(define-attr
+ (for operand)
+ (type boolean)
+ (name HASH-PREFIX)
+ (comment "immediates have an optional '#' prefix")
+)
+
+; ??? Convention says this should be o-sr, but then the insn definitions
+; should refer to o-sr which is clumsy. The "o-" could be implicit, but
+; then it should be implicit for all the symbols here, but then there would
+; be confusion between (f-)simm8 and (h-)simm8.
+; So for now the rule is exactly as it appears here.
+
+(dnop sr "source register" () h-gr f-r2)
+(dnop dr "destination register" () h-gr f-r1)
+;; The assembler relies upon the fact that dr and src1 are the same field.
+;; FIXME: Revisit.
+(dnop src1 "source register 1" () h-gr f-r1)
+(dnop src2 "source register 2" () h-gr f-r2)
+(dnop scr "source control register" () h-cr f-r2)
+(dnop dcr "destination control register" () h-cr f-r1)
+
+(dnop simm8 "8 bit signed immediate" (HASH-PREFIX) h-sint f-simm8)
+(dnop simm16 "16 bit signed immediate" (HASH-PREFIX) h-sint f-simm16)
+(dnop uimm4 "4 bit trap number" (HASH-PREFIX) h-uint f-uimm4)
+(dnop uimm5 "5 bit shift count" (HASH-PREFIX) h-uint f-uimm5)
+(dnop uimm16 "16 bit unsigned immediate" (HASH-PREFIX) h-uint f-uimm16)
+
+(dnop imm1 "1 bit immediate" ((MACH m32rx) HASH-PREFIX) h-uint f-imm1)
+(dnop accd "accumulator destination register" ((MACH m32rx)) h-accums f-accd)
+(dnop accs "accumulator source register" ((MACH m32rx)) h-accums f-accs)
+(dnop acc "accumulator reg (d)" ((MACH m32rx)) h-accums f-acc)
+
+; slo16,ulo16 are used in both with-hash-prefix/no-hash-prefix cases.
+; e.g. add3 r3,r3,#1 and ld r3,@(4,r4). We could use HASH-PREFIX.
+; Instead we create a fake operand `hash'. The m32r is an illustration port,
+; so we often try out various ways of doing things.
+
+(define-operand (name hash) (comment "# prefix") (attrs)
+ (type h-sint) ; doesn't really matter
+ (index f-nil)
+ (handlers (parse "hash") (print "hash"))
+)
+
+; For high(foo),shigh(foo).
+(define-operand
+ (name hi16)
+ (comment "high 16 bit immediate, sign optional")
+ (attrs)
+ (type h-hi16)
+ (index f-hi16)
+ (handlers (parse "hi16"))
+)
+
+; For low(foo),sda(foo).
+(define-operand
+ (name slo16)
+ (comment "16 bit signed immediate, for low()")
+ (attrs)
+ (type h-slo16)
+ (index f-simm16)
+ (handlers (parse "slo16"))
+)
+
+; For low(foo).
+(define-operand
+ (name ulo16)
+ (comment "16 bit unsigned immediate, for low()")
+ (attrs)
+ (type h-ulo16)
+ (index f-uimm16)
+ (handlers (parse "ulo16"))
+)
+
+(dnop uimm24 "24 bit address" (HASH-PREFIX) h-addr f-uimm24)
+
+(define-operand
+ (name disp8)
+ (comment "8 bit displacement")
+ (attrs RELAX)
+ (type h-iaddr)
+ (index f-disp8)
+ ; ??? Early experiments had insert/extract fields here.
+ ; Moving these to f-disp8 made things cleaner, but may wish to re-introduce
+ ; fields here to handle more complicated cases.
+)
+
+(dnop disp16 "16 bit displacement" () h-iaddr f-disp16)
+(dnop disp24 "24 bit displacement" (RELAX) h-iaddr f-disp24)
+
+; These hardware elements are refered to frequently.
+
+(dnop condbit "condition bit" (SEM-ONLY) h-cond f-nil)
+(dnop accum "accumulator" (SEM-ONLY) h-accum f-nil)
+
+; Instruction definitions.
+;
+; Notes while wip:
+; - dni is a cover macro to the real "this is an instruction" keyword.
+; The syntax of the real one is yet to be determined.
+; At the lowest level (i.e. the "real" one) it will probably take a variable
+; list of arguments where each argument [perhaps after the standard three of
+; name, comment, attrs] is "(keyword arg-to-keyword)". This syntax is simple
+; and yet completely upward extensible. And given the macro facility, one
+; needn't code at that low a level so even though it'll be more verbose than
+; necessary it won't matter. This same reasoning can be applied to most
+; types of entries in this file.
+
+; M32R specific instruction attributes:
+
+; FILL-SLOT: Need next insn to begin on 32 bit boundary.
+; (A "slot" as used here is a 32 bit quantity that can either be filled with
+; one 32 bit insn or two 16 bit insns which go in the "left bin" and "right
+; bin" where the left bin is the one with a lower address).
+
+(define-attr
+ (for insn)
+ (type boolean)
+ (name FILL-SLOT)
+ (comment "fill right bin with `nop' if insn is in left bin")
+)
+
+(define-attr
+ (for insn)
+ (type boolean)
+ (name SPECIAL)
+ (comment "non-public m32rx insn")
+)
+
+(define-pmacro (bin-op mnemonic op2-op sem-op imm-prefix imm)
+ (begin
+ (dni mnemonic
+ (.str mnemonic " reg/reg")
+ ((PIPE OS))
+ (.str mnemonic " $dr,$sr")
+ (+ OP1_0 op2-op dr sr)
+ (set dr (sem-op dr sr))
+ ()
+ )
+ (dni (.sym mnemonic "3")
+ (.str mnemonic " reg/" imm)
+ ()
+ (.str mnemonic "3 $dr,$sr," imm-prefix "$" imm)
+ (+ OP1_8 op2-op dr sr imm)
+ (set dr (sem-op sr imm))
+ ()
+ )
+ )
+)
+(bin-op add OP2_10 add "$hash" slo16)
+; sub isn't present because sub3 doesn't exist.
+(bin-op and OP2_12 and "" uimm16)
+(bin-op or OP2_14 or "$hash" ulo16)
+(bin-op xor OP2_13 xor "" uimm16)
+
+(dni addi "addi"
+ ((PIPE OS))
+ ; #.: experiment
+ #.(string-append "addi " "$dr,$simm8")
+ (+ OP1_4 dr simm8)
+ (set dr (add dr simm8))
+ ((m32r/d (unit u-exec))
+ (m32rx (unit u-exec)))
+)
+
+(dni addv "addv"
+ ((PIPE OS))
+ "addv $dr,$sr"
+ (+ OP1_0 OP2_8 dr sr)
+ (parallel ()
+ (set dr (add dr sr))
+ (set condbit (add-oflag dr sr (const 0))))
+ ()
+)
+
+(dni addv3 "addv3"
+ ()
+ "addv3 $dr,$sr,$simm16"
+ (+ OP1_8 OP2_8 dr sr simm16)
+ (parallel ()
+ (set dr (add sr simm16))
+ (set condbit (add-oflag sr simm16 (const 0))))
+ ()
+)
+
+(dni addx "addx"
+ ((PIPE OS))
+ "addx $dr,$sr"
+ (+ OP1_0 OP2_9 dr sr)
+ (parallel ()
+ (set dr (addc dr sr condbit))
+ (set condbit (add-cflag dr sr condbit)))
+ ()
+)
+
+(dni bc8 "bc with 8 bit displacement"
+ (COND-CTI (PIPE O))
+ "bc.s $disp8"
+ (+ OP1_7 (f-r1 12) disp8)
+ (if condbit (set pc disp8))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bc8r "relaxable bc8"
+ (COND-CTI RELAXABLE (PIPE O))
+ "bc $disp8"
+ (emit bc8 disp8)
+)
+
+(dni bc24 "bc with 24 bit displacement"
+ (COND-CTI)
+ "bc.l $disp24"
+ (+ OP1_15 (f-r1 12) disp24)
+ (if condbit (set pc disp24))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bc24r "relaxable bc24"
+ (COND-CTI RELAX)
+ "bc $disp24"
+ (emit bc24 disp24)
+)
+
+(dni beq "beq"
+ (COND-CTI)
+ "beq $src1,$src2,$disp16"
+ (+ OP1_11 OP2_0 src1 src2 disp16)
+ (if (eq src1 src2) (set pc disp16))
+ ((m32r/d (unit u-cti) (unit u-cmp (cycles 0)))
+ (m32rx (unit u-cti) (unit u-cmp (cycles 0))))
+)
+
+(define-pmacro (cbranch sym comment op2-op comp-op)
+ (dni sym comment (COND-CTI)
+ (.str sym " $src2,$disp16")
+ (+ OP1_11 op2-op (f-r1 0) src2 disp16)
+ (if (comp-op src2 (const WI 0)) (set pc disp16))
+ ((m32r/d (unit u-cti) (unit u-cmp (cycles 0)))
+ (m32rx (unit u-cti) (unit u-cmp (cycles 0))))
+ )
+)
+(cbranch beqz "beqz" OP2_8 eq)
+(cbranch bgez "bgez" OP2_11 ge)
+(cbranch bgtz "bgtz" OP2_13 gt)
+(cbranch blez "blez" OP2_12 le)
+(cbranch bltz "bltz" OP2_10 lt)
+(cbranch bnez "bnez" OP2_9 ne)
+
+(dni bl8 "bl with 8 bit displacement"
+ (UNCOND-CTI FILL-SLOT (PIPE O))
+ "bl.s $disp8"
+ (+ OP1_7 (f-r1 14) disp8)
+ (sequence ()
+ (set (reg h-gr 14)
+ (add (and pc (const -4)) (const 4)))
+ (set pc disp8))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bl8r "relaxable bl8"
+ (UNCOND-CTI FILL-SLOT RELAXABLE (PIPE O))
+ "bl $disp8"
+ (emit bl8 disp8)
+)
+
+(dni bl24 "bl with 24 bit displacement"
+ (UNCOND-CTI)
+ "bl.l $disp24"
+ (+ OP1_15 (f-r1 14) disp24)
+ (sequence ()
+ (set (reg h-gr 14) (add pc (const 4)))
+ (set pc disp24))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bl24r "relaxable bl24"
+ (UNCOND-CTI RELAX)
+ "bl $disp24"
+ (emit bl24 disp24)
+)
+
+(dni bcl8 "bcl with 8 bit displacement"
+ (COND-CTI FILL-SLOT (MACH m32rx) (PIPE O))
+ "bcl.s $disp8"
+ (+ OP1_7 (f-r1 8) disp8)
+ (if condbit
+ (sequence ()
+ (set (reg h-gr 14)
+ (add (and pc (const -4))
+ (const 4)))
+ (set pc disp8)))
+ ((m32rx (unit u-cti)))
+)
+
+(dnmi bcl8r "relaxable bcl8"
+ (COND-CTI FILL-SLOT (MACH m32rx) (PIPE O) RELAXABLE)
+ "bcl $disp8"
+ (emit bcl8 disp8)
+)
+
+(dni bcl24 "bcl with 24 bit displacement"
+ (COND-CTI (MACH m32rx))
+ "bcl.l $disp24"
+ (+ OP1_15 (f-r1 8) disp24)
+ (if condbit
+ (sequence ()
+ (set (reg h-gr 14) (add pc (const 4)))
+ (set pc disp24)))
+ ((m32rx (unit u-cti)))
+)
+
+(dnmi bcl24r "relaxable bcl24"
+ (COND-CTI (MACH m32rx) RELAX)
+ "bcl $disp24"
+ (emit bcl24 disp24)
+)
+
+(dni bnc8 "bnc with 8 bit displacement"
+ (COND-CTI (PIPE O))
+ "bnc.s $disp8"
+ (+ OP1_7 (f-r1 13) disp8)
+ (if (not condbit) (set pc disp8))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bnc8r "relaxable bnc8"
+ (COND-CTI RELAXABLE (PIPE O))
+ "bnc $disp8"
+ (emit bnc8 disp8)
+)
+
+(dni bnc24 "bnc with 24 bit displacement"
+ (COND-CTI)
+ "bnc.l $disp24"
+ (+ OP1_15 (f-r1 13) disp24)
+ (if (not condbit) (set pc disp24))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bnc24r "relaxable bnc24"
+ (COND-CTI RELAX)
+ "bnc $disp24"
+ (emit bnc24 disp24)
+)
+
+(dni bne "bne"
+ (COND-CTI)
+ "bne $src1,$src2,$disp16"
+ (+ OP1_11 OP2_1 src1 src2 disp16)
+ (if (ne src1 src2) (set pc disp16))
+ ((m32r/d (unit u-cti) (unit u-cmp (cycles 0)))
+ (m32rx (unit u-cti) (unit u-cmp (cycles 0))))
+)
+
+(dni bra8 "bra with 8 bit displacement"
+ (UNCOND-CTI FILL-SLOT (PIPE O))
+ "bra.s $disp8"
+ (+ OP1_7 (f-r1 15) disp8)
+ (set pc disp8)
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bra8r "relaxable bra8"
+ (UNCOND-CTI FILL-SLOT RELAXABLE (PIPE O))
+ "bra $disp8"
+ (emit bra8 disp8)
+)
+
+(dni bra24 "bra with 24 displacement"
+ (UNCOND-CTI)
+ "bra.l $disp24"
+ (+ OP1_15 (f-r1 15) disp24)
+ (set pc disp24)
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dnmi bra24r "relaxable bra24"
+ (UNCOND-CTI RELAX)
+ "bra $disp24"
+ (emit bra24 disp24)
+)
+
+(dni bncl8 "bncl with 8 bit displacement"
+ (COND-CTI FILL-SLOT (MACH m32rx) (PIPE O))
+ "bncl.s $disp8"
+ (+ OP1_7 (f-r1 9) disp8)
+ (if (not condbit)
+ (sequence ()
+ (set (reg h-gr 14)
+ (add (and pc (const -4))
+ (const 4)))
+ (set pc disp8)))
+ ((m32rx (unit u-cti)))
+)
+
+(dnmi bncl8r "relaxable bncl8"
+ (COND-CTI FILL-SLOT (MACH m32rx) (PIPE O) RELAXABLE)
+ "bncl $disp8"
+ (emit bncl8 disp8)
+)
+
+(dni bncl24 "bncl with 24 bit displacement"
+ (COND-CTI (MACH m32rx))
+ "bncl.l $disp24"
+ (+ OP1_15 (f-r1 9) disp24)
+ (if (not condbit)
+ (sequence ()
+ (set (reg h-gr 14) (add pc (const 4)))
+ (set pc disp24)))
+ ((m32rx (unit u-cti)))
+)
+
+(dnmi bncl24r "relaxable bncl24"
+ (COND-CTI (MACH m32rx) RELAX)
+ "bncl $disp24"
+ (emit bncl24 disp24)
+)
+
+(dni cmp "cmp"
+ ((PIPE OS))
+ "cmp $src1,$src2"
+ (+ OP1_0 OP2_4 src1 src2)
+ (set condbit (lt src1 src2))
+ ((m32r/d (unit u-cmp))
+ (m32rx (unit u-cmp)))
+)
+
+(dni cmpi "cmpi"
+ ()
+ "cmpi $src2,$simm16"
+ (+ OP1_8 (f-r1 0) OP2_4 src2 simm16)
+ (set condbit (lt src2 simm16))
+ ((m32r/d (unit u-cmp))
+ (m32rx (unit u-cmp)))
+)
+
+(dni cmpu "cmpu"
+ ((PIPE OS))
+ "cmpu $src1,$src2"
+ (+ OP1_0 OP2_5 src1 src2)
+ (set condbit (ltu src1 src2))
+ ((m32r/d (unit u-cmp))
+ (m32rx (unit u-cmp)))
+)
+
+(dni cmpui "cmpui"
+ ()
+ "cmpui $src2,$simm16"
+ (+ OP1_8 (f-r1 0) OP2_5 src2 simm16)
+ (set condbit (ltu src2 simm16))
+ ((m32r/d (unit u-cmp))
+ (m32rx (unit u-cmp)))
+)
+
+(dni cmpeq "cmpeq"
+ ((MACH m32rx) (PIPE OS))
+ "cmpeq $src1,$src2"
+ (+ OP1_0 OP2_6 src1 src2)
+ (set condbit (eq src1 src2))
+ ((m32rx (unit u-cmp)))
+)
+
+(dni cmpz "cmpz"
+ ((MACH m32rx) (PIPE OS))
+ "cmpz $src2"
+ (+ OP1_0 OP2_7 (f-r1 0) src2)
+ (set condbit (eq src2 (const 0)))
+ ((m32rx (unit u-cmp)))
+)
+
+(dni div "div"
+ ()
+ "div $dr,$sr"
+ (+ OP1_9 OP2_0 dr sr (f-simm16 0))
+ (if (ne sr (const 0)) (set dr (div dr sr)))
+ ((m32r/d (unit u-exec (cycles 37)))
+ (m32rx (unit u-exec (cycles 37))))
+)
+
+(dni divu "divu"
+ ()
+ "divu $dr,$sr"
+ (+ OP1_9 OP2_1 dr sr (f-simm16 0))
+ (if (ne sr (const 0)) (set dr (udiv dr sr)))
+ ((m32r/d (unit u-exec (cycles 37)))
+ (m32rx (unit u-exec (cycles 37))))
+)
+
+(dni rem "rem"
+ ()
+ "rem $dr,$sr"
+ (+ OP1_9 OP2_2 dr sr (f-simm16 0))
+ ; FIXME: Check rounding direction.
+ (if (ne sr (const 0)) (set dr (mod dr sr)))
+ ((m32r/d (unit u-exec (cycles 37)))
+ (m32rx (unit u-exec (cycles 37))))
+)
+
+(dni remu "remu"
+ ()
+ "remu $dr,$sr"
+ (+ OP1_9 OP2_3 dr sr (f-simm16 0))
+ ; FIXME: Check rounding direction.
+ (if (ne sr (const 0)) (set dr (umod dr sr)))
+ ((m32r/d (unit u-exec (cycles 37)))
+ (m32rx (unit u-exec (cycles 37))))
+)
+
+(dni divh "divh"
+ ((MACH m32rx))
+ "divh $dr,$sr"
+ (+ OP1_9 OP2_0 dr sr (f-simm16 #x10))
+ (if (ne sr (const 0)) (set dr (div (ext WI (trunc HI dr)) sr)))
+ ((m32rx (unit u-exec (cycles 21))))
+)
+
+(dni jc "jc"
+ (COND-CTI (MACH m32rx) (PIPE O) SPECIAL)
+ "jc $sr"
+ (+ OP1_1 (f-r1 12) OP2_12 sr)
+ (if condbit (set pc (and sr (const -4))))
+ ((m32rx (unit u-cti)))
+)
+
+(dni jnc "jnc"
+ (COND-CTI (MACH m32rx) (PIPE O) SPECIAL)
+ "jnc $sr"
+ (+ OP1_1 (f-r1 13) OP2_12 sr)
+ (if (not condbit) (set pc (and sr (const -4))))
+ ((m32rx (unit u-cti)))
+)
+
+(dni jl "jl"
+ (UNCOND-CTI FILL-SLOT (PIPE O))
+ "jl $sr"
+ (+ OP1_1 (f-r1 14) OP2_12 sr)
+ (parallel ()
+ (set (reg h-gr 14)
+ (add (and pc (const -4)) (const 4)))
+ (set pc (and sr (const -4))))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(dni jmp "jmp"
+ (UNCOND-CTI (PIPE O))
+ "jmp $sr"
+ (+ OP1_1 (f-r1 15) OP2_12 sr)
+ (set pc (and sr (const -4)))
+ ; The above works now so this kludge has been commented out.
+ ; It's kept around because the f-r1 reference in the semantic part
+ ; should work.
+ ; FIXME: kludge, instruction decoding not finished.
+ ; But this should work, so that's another FIXME.
+ ;(sequence VOID (if VOID (eq SI f-r1 (const SI 14))
+ ; FIXME: abuf->insn should be a macro of some sort.
+ ;(sequence VOID
+ ; (if VOID (eq SI (c-code SI "((abuf->insn >> 8) & 15)")
+ ; (const SI 14))
+ ; (set WI (reg WI h-gr 14)
+ ; (add WI (and WI pc (const WI -4)) (const WI 4))))
+ ; (set WI pc sr))
+ ((m32r/d (unit u-cti))
+ (m32rx (unit u-cti)))
+)
+
+(define-pmacro (no-ext-expr mode expr) expr)
+(define-pmacro (ext-expr mode expr) (ext mode expr))
+(define-pmacro (zext-expr mode expr) (zext mode expr))
+
+(define-pmacro (load-op suffix op2-op mode ext-op)
+ (begin
+ (dni (.sym ld suffix) (.str "ld" suffix)
+ ((PIPE O))
+ (.str "ld" suffix " $dr,@$sr")
+ (+ OP1_2 op2-op dr sr)
+ (set dr (ext-op WI (mem mode sr)))
+ ((m32r/d (unit u-load))
+ (m32rx (unit u-load)))
+ )
+ (dnmi (.sym ld suffix "-2") (.str "ld" suffix "-2")
+ (NO-DIS (PIPE O))
+ (.str "ld" suffix " $dr,@($sr)")
+ (emit (.sym ld suffix) dr sr))
+ (dni (.sym ld suffix -d) (.str "ld" suffix "-d")
+ ()
+ (.str "ld" suffix " $dr,@($slo16,$sr)")
+ (+ OP1_10 op2-op dr sr slo16)
+ (set dr (ext-op WI (mem mode (add sr slo16))))
+ ((m32r/d (unit u-load (cycles 2)))
+ (m32rx (unit u-load (cycles 2))))
+ )
+ (dnmi (.sym ld suffix -d2) (.str "ld" suffix "-d2")
+ (NO-DIS)
+ (.str "ld" suffix " $dr,@($sr,$slo16)")
+ (emit (.sym ld suffix -d) dr sr slo16))
+ )
+)
+(load-op "" OP2_12 WI no-ext-expr)
+(load-op b OP2_8 QI ext-expr)
+(load-op h OP2_10 HI ext-expr)
+(load-op ub OP2_9 QI zext-expr)
+(load-op uh OP2_11 HI zext-expr)
+
+(dni ld-plus "ld+"
+ ((PIPE O))
+ "ld $dr,@$sr+"
+ (+ OP1_2 dr OP2_14 sr)
+ (parallel ()
+ ; wip: memory addresses in profiling support
+ ;(set dr (name ld-mem (mem WI sr)))
+ (set dr (mem WI sr))
+ (set sr (add sr (const 4))))
+ ; Note: `pred' is the constraint. Also useful here is (ref name)
+ ; and returns true if operand <name> was referenced
+ ; (where "referenced" means _read_ if input operand and _written_ if
+ ; output operand).
+ ; args to unit are "unit-name (name1 value1) ..."
+ ; - cycles(done),issue,pred are also specified this way
+ ; - if unspecified, default is used
+ ; - for ins/outs, extra arg is passed that says what was specified
+ ; - this is AND'd with `written' for outs
+ ((m32r/d (unit u-load (pred (const 1)))
+ (unit u-exec (in sr #f) (in dr sr) (out dr sr) (cycles 0) (pred (const 1))))
+ (m32rx (unit u-load)
+ (unit u-exec (in sr #f) (in dr sr) (out dr sr) (cycles 0) (pred (const 1))))
+ )
+)
+
+(dnmi pop "pop"
+ ()
+ "pop $dr"
+ (emit ld-plus dr (sr 15)) ; "ld %0,@sp+"
+)
+
+(dni ld24 "ld24"
+ ()
+ "ld24 $dr,$uimm24"
+ (+ OP1_14 dr uimm24)
+ (set dr uimm24)
+ ()
+)
+
+; ldi8 appears before ldi16 so we try the shorter version first
+
+(dni ldi8 "ldi8"
+ ((PIPE OS))
+ "ldi8 $dr,$simm8"
+ (+ OP1_6 dr simm8)
+ (set dr simm8)
+ ()
+)
+
+(dnmi ldi8a "ldi8 alias"
+ ((PIPE OS))
+ "ldi $dr,$simm8"
+ (emit ldi8 dr simm8)
+)
+
+(dni ldi16 "ldi16"
+ ()
+ "ldi16 $dr,$hash$slo16"
+ (+ OP1_9 OP2_15 (f-r2 0) dr slo16)
+ (set dr slo16)
+ ()
+)
+
+(dnmi ldi16a "ldi16 alias"
+ ()
+ "ldi $dr,$hash$slo16"
+ (emit ldi16 dr slo16)
+)
+
+(dni lock "lock"
+ ((PIPE O))
+ "lock $dr,@$sr"
+ (+ OP1_2 OP2_13 dr sr)
+ (sequence ()
+ (set (reg h-lock) (const BI 1))
+ (set dr (mem WI sr)))
+ ((m32r/d (unit u-load))
+ (m32rx (unit u-load)))
+)
+
+(dni machi "machi"
+ (
+ ; (MACH m32r) is a temporary hack. This insn collides with machi-a
+ ; in the simulator so disable it for m32rx.
+ (MACH m32r) (PIPE S)
+ )
+ "machi $src1,$src2"
+ (+ OP1_3 OP2_4 src1 src2)
+ ; FIXME: TRACE_RESULT will print the wrong thing since we
+ ; alter one of the arguments.
+ (set accum
+ (sra DI
+ (sll DI
+ (add DI
+ accum
+ (mul DI
+ (ext DI (and WI src1 (const #xffff0000)))
+ (ext DI (trunc HI (sra WI src2 (const 16))))))
+ (const 8))
+ (const 8)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni machi-a "machi-a"
+ ((MACH m32rx) (PIPE S))
+ "machi $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 4) src2)
+ (set acc
+ (sra DI
+ (sll DI
+ (add DI
+ acc
+ (mul DI
+ (ext DI (and WI src1 (const #xffff0000)))
+ (ext DI (trunc HI (sra WI src2 (const 16))))))
+ (const 8))
+ (const 8)))
+ ((m32rx (unit u-mac)))
+)
+
+(dni maclo "maclo"
+ ((MACH m32r) (PIPE S))
+ "maclo $src1,$src2"
+ (+ OP1_3 OP2_5 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (add DI
+ accum
+ (mul DI
+ (ext DI (sll WI src1 (const 16)))
+ (ext DI (trunc HI src2))))
+ (const 8))
+ (const 8)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni maclo-a "maclo-a"
+ ((MACH m32rx) (PIPE S))
+ "maclo $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 5) src2)
+ (set acc
+ (sra DI
+ (sll DI
+ (add DI
+ acc
+ (mul DI
+ (ext DI (sll WI src1 (const 16)))
+ (ext DI (trunc HI src2))))
+ (const 8))
+ (const 8)))
+ ((m32rx (unit u-mac)))
+)
+
+(dni macwhi "macwhi"
+ ((MACH m32r) (PIPE S))
+ "macwhi $src1,$src2"
+ (+ OP1_3 OP2_6 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (add DI
+ accum
+ (mul DI
+ (ext DI src1)
+ (ext DI (trunc HI (sra WI src2 (const 16))))))
+ (const 8))
+ (const 8)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni macwhi-a "macwhi-a"
+ ((MACH m32rx) (PIPE S) SPECIAL)
+ "macwhi $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 6) src2)
+ ; Note that this doesn't do the sign extension, which is correct.
+ (set acc
+ (add acc
+ (mul (ext DI src1)
+ (ext DI (trunc HI (sra src2 (const 16)))))))
+ ((m32rx (unit u-mac)))
+)
+
+(dni macwlo "macwlo"
+ ((MACH m32r) (PIPE S))
+ "macwlo $src1,$src2"
+ (+ OP1_3 OP2_7 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (add DI
+ accum
+ (mul DI
+ (ext DI src1)
+ (ext DI (trunc HI src2))))
+ (const 8))
+ (const 8)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni macwlo-a "macwlo-a"
+ ((MACH m32rx) (PIPE S) SPECIAL)
+ "macwlo $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 7) src2)
+ ; Note that this doesn't do the sign extension, which is correct.
+ (set acc
+ (add acc
+ (mul (ext DI src1)
+ (ext DI (trunc HI src2)))))
+ ((m32rx (unit u-mac)))
+)
+
+(dni mul "mul"
+ ((PIPE S))
+ "mul $dr,$sr"
+ (+ OP1_1 OP2_6 dr sr)
+ (set dr (mul dr sr))
+ ((m32r/d (unit u-exec (cycles 4)))
+ (m32rx (unit u-exec (cycles 4))))
+)
+
+(dni mulhi "mulhi"
+ ((MACH m32r) (PIPE S))
+ "mulhi $src1,$src2"
+ (+ OP1_3 OP2_0 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI (and WI src1 (const #xffff0000)))
+ (ext DI (trunc HI (sra WI src2 (const 16)))))
+ (const 16))
+ (const 16)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni mulhi-a "mulhi-a"
+ ((MACH m32rx) (PIPE S))
+ "mulhi $src1,$src2,$acc"
+ (+ OP1_3 (f-op23 0) src1 acc src2)
+ (set acc
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI (and WI src1 (const #xffff0000)))
+ (ext DI (trunc HI (sra WI src2 (const 16)))))
+ (const 16))
+ (const 16)))
+ ((m32rx (unit u-mac)))
+)
+
+(dni mullo "mullo"
+ ((MACH m32r) (PIPE S))
+ "mullo $src1,$src2"
+ (+ OP1_3 OP2_1 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI (sll WI src1 (const 16)))
+ (ext DI (trunc HI src2)))
+ (const 16))
+ (const 16)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni mullo-a "mullo-a"
+ ((MACH m32rx) (PIPE S))
+ "mullo $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 1) src2)
+ (set acc
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI (sll WI src1 (const 16)))
+ (ext DI (trunc HI src2)))
+ (const 16))
+ (const 16)))
+ ((m32rx (unit u-mac)))
+)
+
+(dni mulwhi "mulwhi"
+ ((MACH m32r) (PIPE S))
+ "mulwhi $src1,$src2"
+ (+ OP1_3 OP2_2 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI src1)
+ (ext DI (trunc HI (sra WI src2 (const 16)))))
+ (const 8))
+ (const 8)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni mulwhi-a "mulwhi-a"
+ ((MACH m32rx) (PIPE S) SPECIAL)
+ "mulwhi $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 2) src2)
+ ; Note that this doesn't do the sign extension, which is correct.
+ (set acc
+ (mul (ext DI src1)
+ (ext DI (trunc HI (sra src2 (const 16))))))
+ ((m32rx (unit u-mac)))
+)
+
+(dni mulwlo "mulwlo"
+ ((MACH m32r) (PIPE S))
+ "mulwlo $src1,$src2"
+ (+ OP1_3 OP2_3 src1 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI src1)
+ (ext DI (trunc HI src2)))
+ (const 8))
+ (const 8)))
+ ((m32r/d (unit u-mac)))
+)
+
+(dni mulwlo-a "mulwlo-a"
+ ((MACH m32rx) (PIPE S) SPECIAL)
+ "mulwlo $src1,$src2,$acc"
+ (+ OP1_3 src1 acc (f-op23 3) src2)
+ ; Note that this doesn't do the sign extension, which is correct.
+ (set acc
+ (mul (ext DI src1)
+ (ext DI (trunc HI src2))))
+ ((m32rx (unit u-mac)))
+)
+
+(dni mv "mv"
+ ((PIPE OS))
+ "mv $dr,$sr"
+ (+ OP1_1 OP2_8 dr sr)
+ (set dr sr)
+ ()
+)
+
+(dni mvfachi "mvfachi"
+ ((MACH m32r) (PIPE S))
+ "mvfachi $dr"
+ (+ OP1_5 OP2_15 (f-r2 0) dr)
+ (set dr (trunc WI (sra DI accum (const 32))))
+ ((m32r/d (unit u-exec (cycles 2))))
+)
+
+(dni mvfachi-a "mvfachi-a"
+ ((MACH m32rx) (PIPE S))
+ "mvfachi $dr,$accs"
+ (+ OP1_5 dr OP2_15 accs (f-op3 0))
+ (set dr (trunc WI (sra DI accs (const 32))))
+ ((m32rx (unit u-exec (cycles 2))))
+)
+
+(dni mvfaclo "mvfaclo"
+ ((MACH m32r) (PIPE S))
+ "mvfaclo $dr"
+ (+ OP1_5 OP2_15 (f-r2 1) dr)
+ (set dr (trunc WI accum))
+ ((m32r/d (unit u-exec (cycles 2))))
+)
+
+(dni mvfaclo-a "mvfaclo-a"
+ ((MACH m32rx) (PIPE S))
+ "mvfaclo $dr,$accs"
+ (+ OP1_5 dr OP2_15 accs (f-op3 1))
+ (set dr (trunc WI accs))
+ ((m32rx (unit u-exec (cycles 2))))
+)
+
+(dni mvfacmi "mvfacmi"
+ ((MACH m32r) (PIPE S))
+ "mvfacmi $dr"
+ (+ OP1_5 OP2_15 (f-r2 2) dr)
+ (set dr (trunc WI (sra DI accum (const 16))))
+ ((m32r/d (unit u-exec (cycles 2))))
+)
+
+(dni mvfacmi-a "mvfacmi-a"
+ ((MACH m32rx) (PIPE S))
+ "mvfacmi $dr,$accs"
+ (+ OP1_5 dr OP2_15 accs (f-op3 2))
+ (set dr (trunc WI (sra DI accs (const 16))))
+ ((m32rx (unit u-exec (cycles 2))))
+)
+
+(dni mvfc "mvfc"
+ ((PIPE O))
+ "mvfc $dr,$scr"
+ (+ OP1_1 OP2_9 dr scr)
+ (set dr scr)
+ ()
+)
+
+(dni mvtachi "mvtachi"
+ ((MACH m32r) (PIPE S))
+ "mvtachi $src1"
+ (+ OP1_5 OP2_7 (f-r2 0) src1)
+ (set accum
+ (or DI
+ (and DI accum (const DI #xffffffff))
+ (sll DI (ext DI src1) (const 32))))
+ ((m32r/d (unit u-exec (in sr src1))))
+)
+
+(dni mvtachi-a "mvtachi-a"
+ ((MACH m32rx) (PIPE S))
+ "mvtachi $src1,$accs"
+ (+ OP1_5 src1 OP2_7 accs (f-op3 0))
+ (set accs
+ (or DI
+ (and DI accs (const DI #xffffffff))
+ (sll DI (ext DI src1) (const 32))))
+ ((m32rx (unit u-exec (in sr src1))))
+)
+
+(dni mvtaclo "mvtaclo"
+ ((MACH m32r) (PIPE S))
+ "mvtaclo $src1"
+ (+ OP1_5 OP2_7 (f-r2 1) src1)
+ (set accum
+ (or DI
+ (and DI accum (const DI #xffffffff00000000))
+ (zext DI src1)))
+ ((m32r/d (unit u-exec (in sr src1))))
+)
+
+(dni mvtaclo-a "mvtaclo-a"
+ ((MACH m32rx) (PIPE S))
+ "mvtaclo $src1,$accs"
+ (+ OP1_5 src1 OP2_7 accs (f-op3 1))
+ (set accs
+ (or DI
+ (and DI accs (const DI #xffffffff00000000))
+ (zext DI src1)))
+ ((m32rx (unit u-exec (in sr src1))))
+)
+
+(dni mvtc "mvtc"
+ ((PIPE O))
+ "mvtc $sr,$dcr"
+ (+ OP1_1 OP2_10 dcr sr)
+ (set dcr sr)
+ ()
+)
+
+(dni neg "neg"
+ ((PIPE OS))
+ "neg $dr,$sr"
+ (+ OP1_0 OP2_3 dr sr)
+ (set dr (neg sr))
+ ()
+)
+
+(dni nop "nop"
+ ((PIPE OS))
+ "nop"
+ (+ OP1_7 OP2_0 (f-r1 0) (f-r2 0))
+ (c-code VOID "PROFILE_COUNT_FILLNOPS (current_cpu, abuf->addr);\n")
+ ; FIXME: quick hack: parallel nops don't contribute to cycle count.
+ ; Other kinds of nops do however (which we currently ignore).
+ ((m32r/d (unit u-exec (cycles 0)))
+ (m32rx (unit u-exec (cycles 0))))
+)
+
+(dni not "not"
+ ((PIPE OS))
+ "not $dr,$sr"
+ (+ OP1_0 OP2_11 dr sr)
+ (set dr (inv sr))
+ ()
+)
+
+(dni rac "rac"
+ ((MACH m32r) (PIPE S))
+ "rac"
+ (+ OP1_5 OP2_9 (f-r1 0) (f-r2 0))
+ (sequence ((DI tmp1))
+ (set tmp1 (sll DI accum (const 1)))
+ (set tmp1 (add DI tmp1 (const DI #x8000)))
+ (set accum
+ (cond DI
+ ((gt tmp1 (const DI #x00007fffffff0000))
+ (const DI #x00007fffffff0000))
+ ((lt tmp1 (const DI #xffff800000000000))
+ (const DI #xffff800000000000))
+ (else (and tmp1 (const DI #xffffffffffff0000)))))
+ )
+ ((m32r/d (unit u-mac)))
+)
+
+(dni rac-dsi "rac-dsi"
+ ((MACH m32rx) (PIPE S))
+ "rac $accd,$accs,$imm1"
+ (+ OP1_5 accd (f-bits67 0) OP2_9 accs (f-bit14 0) imm1)
+ (sequence ((DI tmp1))
+ (set tmp1 (sll accs imm1))
+ (set tmp1 (add tmp1 (const DI #x8000)))
+ (set accd
+ (cond DI
+ ((gt tmp1 (const DI #x00007fffffff0000))
+ (const DI #x00007fffffff0000))
+ ((lt tmp1 (const DI #xffff800000000000))
+ (const DI #xffff800000000000))
+ (else (and tmp1 (const DI #xffffffffffff0000)))))
+ )
+ ((m32rx (unit u-mac)))
+)
+
+(dnmi rac-d "rac-d"
+ ((MACH m32rx) (PIPE S))
+ "rac $accd"
+ (emit rac-dsi accd (f-accs 0) (f-imm1 0))
+)
+
+(dnmi rac-ds "rac-ds"
+ ((MACH m32rx) (PIPE S))
+ "rac $accd,$accs"
+ (emit rac-dsi accd accs (f-imm1 0))
+)
+
+
+(dni rach "rach"
+ ((MACH m32r) (PIPE S))
+ "rach"
+ (+ OP1_5 OP2_8 (f-r1 0) (f-r2 0))
+ (sequence ((DI tmp1))
+ ; Lop off top 8 bits.
+ ; The sign bit we want to use is bit 55 so the 64 bit value
+ ; isn't properly signed which we deal with in the if's below.
+ (set tmp1 (and accum (const DI #xffffffffffffff)))
+ (if (andif (ge tmp1 (const DI #x003fff80000000))
+ (le tmp1 (const DI #x7fffffffffffff)))
+ (set tmp1 (const DI #x003fff80000000))
+ ; else part
+ (if (andif (ge tmp1 (const DI #x80000000000000))
+ (le tmp1 (const DI #xffc00000000000)))
+ (set tmp1 (const DI #xffc00000000000))
+ (set tmp1 (and (add accum (const DI #x40000000))
+ (const DI #xffffffff80000000)))))
+ (set tmp1 (sll tmp1 (const 1)))
+ ; Sign extend top 8 bits.
+ (set accum
+ ; FIXME: 7?
+ (sra DI (sll DI tmp1 (const 7)) (const 7)))
+ )
+ ((m32r/d (unit u-mac)))
+)
+
+(dni rach-dsi "rach-dsi"
+ ((MACH m32rx) (PIPE S))
+ "rach $accd,$accs,$imm1"
+ (+ OP1_5 accd (f-bits67 0) OP2_8 accs (f-bit14 0) imm1)
+ (sequence ((DI tmp1))
+ (set tmp1 (sll accs imm1))
+ (set tmp1 (add tmp1 (const DI #x80000000)))
+ (set accd
+ (cond DI
+ ((gt tmp1 (const DI #x00007fff00000000))
+ (const DI #x00007fff00000000))
+ ((lt tmp1 (const DI #xffff800000000000))
+ (const DI #xffff800000000000))
+ (else (and tmp1 (const DI #xffffffff00000000)))))
+ )
+ ((m32rx (unit u-mac)))
+)
+
+(dnmi rach-d "rach-d"
+ ((MACH m32rx) (PIPE S))
+ "rach $accd"
+ (emit rach-dsi accd (f-accs 0) (f-imm1 0))
+)
+
+(dnmi rach-ds "rach-ds"
+ ((MACH m32rx) (PIPE S))
+ "rach $accd,$accs"
+ (emit rach-dsi accd accs (f-imm1 0))
+)
+
+(dni rte "rte"
+ (UNCOND-CTI (PIPE O))
+ "rte"
+ (+ OP1_1 OP2_13 (f-r1 0) (f-r2 6))
+ (sequence ()
+ ; pc = bpc & -4
+ (set pc (and (reg h-cr 6) (const -4)))
+ ; bpc = bbpc
+ (set (reg h-cr 6) (reg h-cr 14))
+ ; psw = bpsw
+ (set (reg h-psw) (reg h-bpsw))
+ ; bpsw = bbpsw
+ (set (reg h-bpsw) (reg h-bbpsw))
+ )
+ ()
+)
+
+(dni seth "seth"
+ ()
+ "seth $dr,$hash$hi16"
+ (+ OP1_13 OP2_12 dr (f-r2 0) hi16)
+ (set dr (sll WI hi16 (const 16)))
+ ()
+)
+
+(define-pmacro (shift-op sym op2-r-op op2-3-op op2-i-op sem-op)
+ (begin
+ (dni sym sym ((PIPE O))
+ (.str sym " $dr,$sr")
+ (+ OP1_1 op2-r-op dr sr)
+ (set dr (sem-op dr (and sr (const 31))))
+ ()
+ )
+ (dni (.sym sym "3") sym ()
+ (.str sym "3 $dr,$sr,$simm16")
+ (+ OP1_9 op2-3-op dr sr simm16)
+ (set dr (sem-op sr (and WI simm16 (const 31))))
+ ()
+ )
+ (dni (.sym sym "i") sym ((PIPE O))
+ (.str sym "i $dr,$uimm5")
+ (+ OP1_5 (f-shift-op2 op2-i-op) dr uimm5)
+ (set dr (sem-op dr uimm5))
+ ()
+ )
+ )
+)
+(shift-op sll OP2_4 OP2_12 2 sll)
+(shift-op sra OP2_2 OP2_10 1 sra)
+(shift-op srl OP2_0 OP2_8 0 srl)
+
+(define-pmacro (store-op suffix op2-op mode)
+ (begin
+ (dni (.sym st suffix) (.str "st" suffix)
+ ((PIPE O))
+ (.str "st" suffix " $src1,@$src2")
+ (+ OP1_2 op2-op src1 src2)
+ (set mode (mem mode src2) src1)
+ ((m32r/d (unit u-store (cycles 1)))
+ (m32rx (unit u-store (cycles 1))))
+ )
+ (dnmi (.sym st suffix "-2") (.str "st" suffix "-2")
+ (NO-DIS (PIPE O))
+ (.str "st" suffix " $src1,@($src2)")
+ (emit (.sym st suffix) src1 src2))
+ (dni (.sym st suffix -d) (.str "st" suffix "-d")
+ ()
+ (.str "st" suffix " $src1,@($slo16,$src2)")
+ (+ OP1_10 op2-op src1 src2 slo16)
+ (set mode (mem mode (add src2 slo16)) src1)
+ ((m32r/d (unit u-store (cycles 2)))
+ (m32rx (unit u-store (cycles 2))))
+ )
+ (dnmi (.sym st suffix -d2) (.str "st" suffix "-d2")
+ (NO-DIS)
+ (.str "st" suffix " $src1,@($src2,$slo16)")
+ (emit (.sym st suffix -d) src1 src2 slo16))
+ )
+)
+(store-op "" OP2_4 WI)
+(store-op b OP2_0 QI)
+(store-op h OP2_2 HI)
+
+(dni st-plus "st+"
+ ((PIPE O))
+ "st $src1,@+$src2"
+ (+ OP1_2 OP2_6 src1 src2)
+ ; This has to be coded carefully to avoid an "earlyclobber" of src2.
+ (sequence ((WI new-src2))
+ (set new-src2 (add WI src2 (const WI 4)))
+ (set (mem WI new-src2) src1)
+ (set src2 new-src2))
+ ((m32r/d (unit u-store)
+ (unit u-exec (in dr src2) (out dr src2) (cycles 0)))
+ (m32rx (unit u-store)
+ (unit u-exec (in dr src2) (out dr src2) (cycles 0)))
+ )
+)
+
+(dni st-minus "st-"
+ ((PIPE O))
+ "st $src1,@-$src2"
+ (+ OP1_2 OP2_7 src1 src2)
+ ; This is the original way. It doesn't work for parallel execution
+ ; because of the earlyclobber of src2.
+ ;(sequence ()
+ ; (set src2 (sub src2 (const 4)))
+ ; (set (mem WI src2) src1))
+ (sequence ((WI new-src2))
+ (set new-src2 (sub src2 (const 4)))
+ (set (mem WI new-src2) src1)
+ (set src2 new-src2))
+ ((m32r/d (unit u-store)
+ (unit u-exec (in dr src2) (out dr src2) (cycles 0)))
+ (m32rx (unit u-store)
+ (unit u-exec (in dr src2) (out dr src2) (cycles 0)))
+ )
+)
+
+(dnmi push "push" ()
+ "push $src1"
+ (emit st-minus src1 (src2 15)) ; "st %0,@-sp"
+)
+
+(dni sub "sub"
+ ((PIPE OS))
+ "sub $dr,$sr"
+ (+ OP1_0 OP2_2 dr sr)
+ (set dr (sub dr sr))
+ ()
+)
+
+(dni subv "sub:rv"
+ ((PIPE OS))
+ "subv $dr,$sr"
+ (+ OP1_0 OP2_0 dr sr)
+ (parallel ()
+ (set dr (sub dr sr))
+ (set condbit (sub-oflag dr sr (const 0))))
+ ()
+)
+
+(dni subx "sub:rx"
+ ((PIPE OS))
+ "subx $dr,$sr"
+ (+ OP1_0 OP2_1 dr sr)
+ (parallel ()
+ (set dr (subc dr sr condbit))
+ (set condbit (sub-cflag dr sr condbit)))
+ ()
+)
+
+(dni trap "trap"
+ (UNCOND-CTI FILL-SLOT (PIPE O))
+ "trap $uimm4"
+ (+ OP1_1 OP2_15 (f-r1 0) uimm4)
+ (sequence ()
+ ; bbpc = bpc
+ (set (reg h-cr 14) (reg h-cr 6))
+ ; Set bpc to the return address. Actually it's not quite the
+ ; return address as RTE rounds the address down to a word
+ ; boundary.
+ (set (reg h-cr 6) (add pc (const 4)))
+ ; bbpsw = bpsw
+ (set (reg h-bbpsw) (reg h-bpsw))
+ ; bpsw = psw
+ (set (reg h-bpsw) (reg h-psw))
+ ; sm is unchanged, ie,c are set to zero.
+ (set (reg h-psw) (and (reg h-psw) (const #x80)))
+ ; m32r_trap handles operating vs user mode
+ (set WI pc (c-call WI "m32r_trap" pc uimm4))
+ )
+ ()
+)
+
+(dni unlock "unlock"
+ ((PIPE O))
+ "unlock $src1,@$src2"
+ (+ OP1_2 OP2_5 src1 src2)
+ (sequence ()
+ (if (reg h-lock)
+ (set (mem WI src2) src1))
+ (set (reg h-lock) (const BI 0)))
+ ((m32r/d (unit u-load))
+ (m32rx (unit u-load)))
+)
+
+; Saturate into byte.
+(dni satb "satb"
+ ((MACH m32rx))
+ "satb $dr,$sr"
+ (+ OP1_8 dr OP2_6 sr (f-uimm16 #x0300))
+ (set dr
+ ; FIXME: min/max would simplify this nicely of course.
+ (cond WI
+ ((ge sr (const 127)) (const 127))
+ ((le sr (const -128)) (const -128))
+ (else sr)))
+ ()
+)
+
+; Saturate into half word.
+(dni sath "sath"
+ ((MACH m32rx))
+ "sath $dr,$sr"
+ (+ OP1_8 dr OP2_6 sr (f-uimm16 #x0200))
+ (set dr
+ (cond WI
+ ((ge sr (const 32767)) (const 32767))
+ ((le sr (const -32768)) (const -32768))
+ (else sr)))
+ ()
+)
+
+; Saturate word.
+(dni sat "sat"
+ ((MACH m32rx) SPECIAL)
+ "sat $dr,$sr"
+ (+ OP1_8 dr OP2_6 sr (f-uimm16 0))
+ (set dr
+ (if WI condbit
+ (if WI (lt sr (const 0))
+ (const #x7fffffff)
+ (const #x80000000))
+ sr))
+ ()
+)
+
+; Parallel compare byte zeros.
+; Set C bit in condition register if any byte in source register is zero.
+(dni pcmpbz "pcmpbz"
+ ((MACH m32rx) (PIPE OS) SPECIAL)
+ "pcmpbz $src2"
+ (+ OP1_0 (f-r1 3) OP2_7 src2)
+ (set condbit
+ (cond BI
+ ((eq (and src2 (const #xff)) (const 0)) (const BI 1))
+ ((eq (and src2 (const #xff00)) (const 0)) (const BI 1))
+ ((eq (and src2 (const #xff0000)) (const 0)) (const BI 1))
+ ((eq (and src2 (const #xff000000)) (const 0)) (const BI 1))
+ (else (const BI 0))))
+ ((m32rx (unit u-cmp)))
+)
+
+; Add accumulators
+(dni sadd "sadd"
+ ((MACH m32rx) (PIPE S))
+ "sadd"
+ (+ OP1_5 (f-r1 0) OP2_14 (f-r2 4))
+ (set (reg h-accums 0)
+ (add (sra (reg h-accums 1) (const 16))
+ (reg h-accums 0)))
+ ((m32rx (unit u-mac)))
+)
+
+; Multiply and add into accumulator 1
+(dni macwu1 "macwu1"
+ ((MACH m32rx) (PIPE S))
+ "macwu1 $src1,$src2"
+ (+ OP1_5 src1 OP2_11 src2)
+ (set (reg h-accums 1)
+ (sra DI
+ (sll DI
+ (add DI
+ (reg h-accums 1)
+ (mul DI
+ (ext DI src1)
+ (ext DI (and src2 (const #xffff)))))
+ (const 8))
+ (const 8)))
+ ((m32rx (unit u-mac)))
+)
+
+; Multiply and subtract from accumulator 0
+(dni msblo "msblo"
+ ((MACH m32rx) (PIPE S))
+ "msblo $src1,$src2"
+ (+ OP1_5 src1 OP2_13 src2)
+ (set accum
+ (sra DI
+ (sll DI
+ (sub accum
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI (trunc HI src1))
+ (ext DI (trunc HI src2)))
+ (const 32))
+ (const 16)))
+ (const 8))
+ (const 8)))
+ ((m32rx (unit u-mac)))
+)
+
+; Multiply into accumulator 1
+(dni mulwu1 "mulwu1"
+ ((MACH m32rx) (PIPE S))
+ "mulwu1 $src1,$src2"
+ (+ OP1_5 src1 OP2_10 src2)
+ (set (reg h-accums 1)
+ (sra DI
+ (sll DI
+ (mul DI
+ (ext DI src1)
+ (ext DI (and src2 (const #xffff))))
+ (const 16))
+ (const 16)))
+ ((m32rx (unit u-mac)))
+)
+
+; Multiply and add into accumulator 1
+(dni maclh1 "maclh1"
+ ((MACH m32rx) (PIPE S))
+ "maclh1 $src1,$src2"
+ (+ OP1_5 src1 OP2_12 src2)
+ (set (reg h-accums 1)
+ (sra DI
+ (sll DI
+ (add DI
+ (reg h-accums 1)
+ (sll DI
+ (ext DI
+ (mul SI
+ (ext SI (trunc HI src1))
+ (sra SI src2 (const SI 16))))
+ (const 16)))
+ (const 8))
+ (const 8)))
+ ((m32rx (unit u-mac)))
+)
+
+; skip instruction if C
+(dni sc "sc"
+ ((MACH m32rx) (PIPE O) SPECIAL)
+ "sc"
+ (+ OP1_7 (f-r1 4) OP2_0 (f-r2 1))
+ (skip (zext INT condbit))
+ ()
+)
+
+; skip instruction if not C
+(dni snc "snc"
+ ((MACH m32rx) (PIPE O) SPECIAL)
+ "snc"
+ (+ OP1_7 (f-r1 5) OP2_0 (f-r2 1))
+ (skip (zext INT (not condbit)))
+ ()
+)
diff --git a/cgen/m32r.opc b/cgen/m32r.opc
new file mode 100644
index 00000000000..601ca58d121
--- /dev/null
+++ b/cgen/m32r.opc
@@ -0,0 +1,264 @@
+/* M32R opcode support. -*- C -*-
+ Copyright (C) 2000 Red Hat, Inc.
+ This file is part of CGEN. */
+
+/* This file is an addendum to m32r.cpu. Heavy use of C code isn't
+ appropriate in .cpu files, so it resides here. This especially applies
+ to assembly/disassembly where parsing/printing can be quite involved.
+ Such things aren't really part of the specification of the cpu, per se,
+ so .cpu files provide the general framework and .opc files handle the
+ nitty-gritty details as necessary.
+
+ Each section is delimited with start and end markers.
+
+ <arch>-opc.h additions use: "-- opc.h"
+ <arch>-opc.c additions use: "-- opc.c"
+ <arch>-asm.c additions use: "-- asm.c"
+ <arch>-dis.c additions use: "-- dis.c"
+ <arch>-ibd.h additions use: "-- ibd.h"
+*/
+
+/* -- opc.h */
+
+#undef CGEN_DIS_HASH_SIZE
+#define CGEN_DIS_HASH_SIZE 256
+#undef CGEN_DIS_HASH
+#define X(b) (((unsigned char *) (b))[0] & 0xf0)
+#define CGEN_DIS_HASH(buffer, value) \
+(X (buffer) | \
+ (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
+ : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
+ : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
+ : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
+
+/* -- */
+
+/* -- asm.c */
+
+/* Handle '#' prefixes (i.e. skip over them). */
+
+static const char *
+parse_hash (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ if (**strp == '#')
+ ++*strp;
+ return NULL;
+}
+
+/* Handle shigh(), high(). */
+
+static const char *
+parse_hi16 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (**strp == '#')
+ ++*strp;
+
+ if (strncasecmp (*strp, "high(", 5) == 0)
+ {
+ *strp += 5;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value >>= 16;
+ *valuep = value;
+ return errmsg;
+ }
+ else if (strncasecmp (*strp, "shigh(", 6) == 0)
+ {
+ *strp += 6;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value = (value >> 16) + (value & 0x8000 ? 1 : 0);
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
+}
+
+/* Handle low() in a signed context. Also handle sda().
+ The signedness of the value doesn't matter to low(), but this also
+ handles the case where low() isn't present. */
+
+static const char *
+parse_slo16 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (**strp == '#')
+ ++*strp;
+
+ if (strncasecmp (*strp, "low(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value &= 0xffff;
+ *valuep = value;
+ return errmsg;
+ }
+
+ if (strncasecmp (*strp, "sda(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
+ NULL, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_signed_integer (cd, strp, opindex, valuep);
+}
+
+/* Handle low() in an unsigned context.
+ The signedness of the value doesn't matter to low(), but this also
+ handles the case where low() isn't present. */
+
+static const char *
+parse_ulo16 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (**strp == '#')
+ ++*strp;
+
+ if (strncasecmp (*strp, "low(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value &= 0xffff;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
+}
+
+/* -- */
+
+/* -- dis.c */
+
+/* Immediate values are prefixed with '#'. */
+
+#define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
+do { \
+ if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
+ (*info->fprintf_func) (info->stream, "#"); \
+} while (0)
+
+/* Handle '#' prefixes as operands. */
+
+static void
+print_hash (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ disassemble_info *info = (disassemble_info *) dis_info;
+ (*info->fprintf_func) (info->stream, "#");
+}
+
+#undef CGEN_PRINT_INSN
+#define CGEN_PRINT_INSN my_print_insn
+
+static int
+my_print_insn (cd, pc, info)
+ CGEN_CPU_DESC cd;
+ bfd_vma pc;
+ disassemble_info *info;
+{
+ char buffer[CGEN_MAX_INSN_SIZE];
+ char *buf = buffer;
+ int status;
+ int buflen = (pc & 3) == 0 ? 4 : 2;
+
+ /* Read the base part of the insn. */
+
+ status = (*info->read_memory_func) (pc, buf, buflen, info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, pc, info);
+ return -1;
+ }
+
+ /* 32 bit insn? */
+ if ((pc & 3) == 0 && (buf[0] & 0x80) != 0)
+ return print_insn (cd, pc, info, buf, buflen);
+
+ /* Print the first insn. */
+ if ((pc & 3) == 0)
+ {
+ if (print_insn (cd, pc, info, buf, 2) == 0)
+ (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
+ buf += 2;
+ }
+
+ if (buf[0] & 0x80)
+ {
+ /* Parallel. */
+ (*info->fprintf_func) (info->stream, " || ");
+ buf[0] &= 0x7f;
+ }
+ else
+ (*info->fprintf_func) (info->stream, " -> ");
+
+ /* The "& 3" is to pass a consistent address.
+ Parallel insns arguably both begin on the word boundary.
+ Also, branch insns are calculated relative to the word boundary. */
+ if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
+ (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
+
+ return (pc & 3) ? 2 : 4;
+}
+
+/* -- */
diff --git a/cgen/m68k.cpu b/cgen/m68k.cpu
new file mode 100644
index 00000000000..5a614dd0f2b
--- /dev/null
+++ b/cgen/m68k.cpu
@@ -0,0 +1,253 @@
+; Motorola M68000 family CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; NOTE: this file is still strictly WORK-IN-PROGRESS.
+
+(include "simplify.inc")
+
+(define-arch
+ (name m68k)
+ (comment "Motorola M68000 architecture")
+ (insn-lsb0? #t)
+ (machs m68k16)
+ (isas basic)
+)
+
+(define-isa
+ (name basic)
+ (comment "Basic M68K instruction set")
+ (default-insn-word-bitsize 16)
+ (default-insn-bitsize 16)
+ (base-insn-bitsize 16)
+ (decode-assist (15 14 13 12))
+)
+
+(define-cpu
+ (name m68k)
+ (comment "Motorola M68000 family")
+ (endian big)
+ (word-bitsize 32)
+)
+
+(define-mach
+ (name m68k16)
+ (comment "Motorola M68000 (16-bit bus)")
+ (cpu m68k)
+ (isas basic)
+)
+
+(define-model
+ (name mc68000)
+ (comment "Motorola MC68000 microprocessor")
+ (mach m68k16)
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () () () ())
+)
+
+; Hardware elements.
+
+(dnh h-pc "program counter" (PC PROFILE (ISA basic)) (pc) () () ())
+
+(dsh h-ccr "condition code register" () (register HI))
+
+(define-keyword
+ (name dr-names)
+ (print-name h-dr)
+ (prefix "")
+ (values (d0 0) (d1 1) (d2 2) (d3 3) (d4 4) (d5 5) (d6 6) (d7 7))
+)
+
+(define-keyword
+ (name ar-names)
+ (print-name h-ar)
+ (prefix "")
+ (values (a0 0) (a1 1) (a2 2) (a3 3) (a4 4) (a5 5) (a6 6) (a7 7)
+ (sp 7))
+)
+
+(define-hardware
+ (name h-dr)
+ (comment "data registers")
+ (attrs (ISA basic) CACHE-ADDR)
+ (type register SI (8))
+ (indices extern-keyword dr-names)
+)
+
+(define-hardware
+ (name h-ar)
+ (comment "address registers")
+ (attrs (ISA basic) CACHE-ADDR)
+ (type register SI (8))
+ (indices extern-keyword ar-names)
+)
+
+; FIXME: need three shadowed A7 registers here for:
+; * User stack pointer (USP)
+; * Interrupt stack pointer (ISP)
+; * Master stack pointer (MSP).
+; These can be omitted for now since we intend to only do user mode.
+; c.f. arm.cpu for tips on how to do this. ARM shadows some registers
+; depending on any of its five operating modes.
+
+
+; Instruction fields.
+
+(define-pmacro (d68f x-name x-comment x-attrs x-word-offset x-word-length
+ x-start x-length x-mode x-encode x-decode)
+ (define-ifield
+ (name x-name)
+ (comment x-comment)
+ (.splice attrs (.unsplice x-attrs))
+ (word-offset x-word-offset)
+ (word-length x-word-length)
+ (start x-start)
+ (length x-length)
+ (mode x-mode)
+ (encode x-encode)
+ (decode x-decode)
+ )
+)
+
+(define-pmacro (dn68f x-name x-comment x-attrs x-word-offset
+ x-word-length x-start x-length)
+ (d68f x-name x-comment x-attrs x-word-offset x-word-length x-start
+ x-length UINT #f #f)
+)
+
+(d68f f-simm8 "signed 8 bit immediate" () 16 16 7 8 INT #f #f)
+(d68f f-simm16 "signed 16 bit immediate" () 16 16 15 16 INT #f #f)
+(d68f f-simm32 "signed 32 bit immediate" () 16 32 31 32 INT #f #f)
+
+(dn68f f-uimm8 "unsigned 8 bit immediate" () 16 16 7 8)
+(dn68f f-uimm16 "unsigned 16 bit immediate" () 16 16 15 16)
+(dn68f f-iumm32 "unsigned 32 bit immediate" () 16 32 31 32)
+
+(dn68f f-imm8-filler "unused part of 8 bit immediate" () 16 16 15 8)
+
+(dn68f f-15-4 "4 bits at bit 15" () 0 16 15 4)
+(dn68f f-15-12 "12 bits at bit 15" () 0 16 15 12)
+(dn68f f-15-13 "13 bits at bit 15" () 0 16 15 13)
+(dn68f f-15-16 "16 bits at bit 15" () 0 16 15 16)
+(dn68f f-8-1 "1 bit at bit 8" () 0 16 8 1)
+
+(dnf f-rx "register Rx field" () 11 3)
+(dnf f-ry "register Ry field" () 2 3)
+(dnf f-opmode "operation mode" () 7 5)
+(dnf f-vector "vector field" () 3 4)
+
+(dnf f-imm8 "immediate constant (8 bits)" () 7 8)
+
+; Operands.
+(dnop rx "register Rx operand" () h-uint f-rx)
+(dnop reg-@2 "general reg number (at bit 2)" () h-uint f-rx)
+(dnop reg-@11 "general reg number (at bit 11)" () h-uint f-ry)
+(dnop ry "register Ry operand" () h-uint f-ry)
+(dnop vector "trap vector operand" () h-uint f-vector)
+(dnop imm8 "immediate constant (8 bits)" () h-uint f-imm8)
+
+; Instructions.
+
+(dni nop "no operation" ()
+ "nop"
+ (+ (f-15-16 #x4E71))
+ (nop)
+ ()
+)
+
+(dni exg-data "exchange data registers" ()
+ "FIXME"
+ (+ (f-15-4 #xC) rx (f-8-1 1) (f-opmode 8) ry)
+ (sequence ((SI temp))
+ (set temp (reg h-dr rx))
+ (set (reg h-dr rx) (reg h-dr ry))
+ (set (reg h-dr ry) temp))
+ ()
+)
+
+(dni exg-addr "exchange address registers" ()
+ "FIXME"
+ (+ (f-15-4 #xC) rx (f-8-1 1) (f-opmode 9) ry)
+ (sequence ((SI temp))
+ (set temp (reg h-ar rx))
+ (set (reg h-ar rx) (reg h-ar ry))
+ (set (reg h-ar ry) temp))
+ ()
+)
+
+(dni exg-data-addr "exchange data and address register" ()
+ "FIXME"
+ (+ (f-15-4 #xC) rx (f-8-1 1) (f-opmode #x11) ry)
+ (sequence ((SI temp))
+ (set temp (reg h-dr rx))
+ (set (reg h-dr rx) (reg h-ar ry))
+ (set (reg h-ar ry) temp))
+ ()
+)
+
+(dni illegal "illegal instruction" ()
+ "FIXME"
+ (+ (f-15-16 #x4AFC))
+ (nop)
+ ()
+)
+
+(dni moveq "move quick" ()
+ "FIXME"
+ (+ (f-15-4 7) reg-@2 (f-8-1 0) imm8)
+ ; FIXME: set condition codes.
+ (sequence ()
+ (set (reg h-dr reg-@2) (ext SI imm8)))
+ ()
+)
+
+(dni reset "reset external devices" ()
+ "FIXME"
+ (+ (f-15-16 #x4E70))
+ (nop)
+ ()
+)
+
+(dni rte "return from exception" ()
+ "FIXME"
+ (+ (f-15-16 #x4E73))
+ (nop)
+ ()
+)
+
+(dni rtr "return and restore condition codes" ()
+ "FIXME"
+ (+ (f-15-16 #x4E77))
+ (nop)
+ ()
+)
+
+(dni rts "return from subroutine" ()
+ "RTS"
+ (+ (f-15-16 #x4E75))
+ (nop)
+ ()
+)
+
+(dni trap "trap" ()
+ "FIXME"
+ (+ (f-15-12 #x4E4) vector)
+ (nop)
+ ()
+)
+
+(dni trapv "trap on overflow" ()
+ "FIXME"
+ (+ (f-15-16 #x4E76))
+ (nop)
+ ()
+)
+
+(dni unlk "unlink" ()
+ "FIXME"
+ (+ (f-15-13 #x9CB) reg-@2)
+ (nop)
+ ()
+)
diff --git a/cgen/mach.scm b/cgen/mach.scm
new file mode 100644
index 00000000000..6069788d897
--- /dev/null
+++ b/cgen/mach.scm
@@ -0,0 +1,1473 @@
+; CPU architecture description.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Top level class that records everything about a cpu.
+; FIXME: Rename this to something else and rename <arch-data> to <arch>
+; for consistency with other classes (define-foo -> <foo> object).
+
+(define <arch>
+ (class-make '<arch>
+ nil
+ '(
+ ; An object of type <arch-data>.
+ data
+ (attr-list . (() . ()))
+ (enum-list . ())
+ (kw-list . ())
+ (isa-list . ())
+ (cpu-list . ())
+ (mach-list . ())
+ (model-list . ())
+ (ifld-list . ())
+ (hw-list . ())
+ (op-list . ())
+ (ifmt-list . ())
+ (sfmt-list . ())
+ (insn-list . ())
+ (minsn-list . ())
+ (subr-list . ())
+ (insn-extract . #f) ; FIXME: wip (and move elsewhere)
+ (insn-execute . #f) ; FIXME: wip (and move elsewhere)
+
+ ; standard values derived from the input data
+ derived
+
+ ; #t if instructions have been analyzed
+ (insns-analyzed? . #f)
+ ; #t if semantics were included in the analysis
+ (semantics-analyzed? . #f)
+ ; #t if alias insns were included in the analysis
+ (aliases-analyzed? . #f)
+ )
+ nil)
+)
+
+; Accessors.
+; Each getter is arch-foo.
+; Each setter is arch-set-foo!.
+
+(define-getters <arch> arch
+ (data
+ attr-list enum-list kw-list
+ isa-list cpu-list mach-list model-list
+ ifld-list hw-list op-list ifmt-list sfmt-list
+ insn-list minsn-list subr-list
+ derived
+ insns-analyzed? semantics-analyzed? aliases-analyzed?
+ )
+)
+(define-setters <arch> arch
+ (data
+ attr-list enum-list kw-list
+ isa-list cpu-list mach-list model-list
+ ifld-list hw-list op-list ifmt-list sfmt-list
+ insn-list minsn-list subr-list
+ derived
+ insns-analyzed? semantics-analyzed? aliases-analyzed?
+ )
+)
+
+; Class for recording things specified in `define-arch'.
+; This simplifies define-arch as the global arch object CURRENT-ARCH
+; must exist before loading the .cpu file.
+
+(define <arch-data>
+ (class-make '<arch-data>
+ '(<ident>)
+ '(
+ ; Default alignment of memory operations.
+ ; One of aligned, unaligned, forced.
+ default-alignment
+
+ ; Orientation of insn bit numbering (#f->msb=0, #t->lsb=0).
+ insn-lsb0?
+
+ ; List of all machs.
+ ; Each element is pair of (mach-name . sanitize-key)
+ ; where sanitize-key is #f if there is none.
+ ; blah blah blah ... ooohhh, evil sanitize key, blah blah blah
+ machs
+
+ ; List of all isas (instruction set architecture).
+ ; Each element is a pair of (isa-name . sanitize-key)
+ ; where sanitize-key is #f if there is none.
+ ; There is usually just one. ARM has two (arm, thumb).
+ ; blah blah blah ... ooohhh, evil sanitize key, blah blah blah
+ isas
+
+ ; ??? Defaults for other things should be here.
+ )
+ nil)
+)
+
+(define-getters <arch-data> adata
+ (default-alignment insn-lsb0? machs isas)
+)
+
+; Add, list, lookup accessors for <arch>.
+;
+; For the lookup routines, the result is the object or #f if not found.
+; For some, if X is already an object, return that.
+
+(define (current-arch-name) (obj:name (arch-data CURRENT-ARCH)))
+
+(define (current-arch-comment) (obj:comment (arch-data CURRENT-ARCH)))
+
+(define (current-arch-atlist) (obj-atlist (arch-data CURRENT-ARCH)))
+
+(define (current-arch-default-alignment)
+ (adata-default-alignment (arch-data CURRENT-ARCH)))
+
+(define (current-arch-insn-lsb0?)
+ (adata-insn-lsb0? (arch-data CURRENT-ARCH)))
+
+(define (current-arch-mach-name-list)
+ (map car (adata-machs (arch-data CURRENT-ARCH)))
+)
+
+(define (current-arch-isa-name-list)
+ (map car (adata-isas (arch-data CURRENT-ARCH)))
+)
+
+; Attributes.
+; Recorded as a pair of lists.
+; The car is a list of <attribute> objects.
+; The cdr is an associative list of (name . <attribute>) elements, for lookup.
+; Could use a hash table except that there currently aren't that many.
+
+(define (current-attr-list) (car (arch-attr-list CURRENT-ARCH)))
+(define (current-attr-add! a)
+ (let ((adata (arch-attr-list CURRENT-ARCH)))
+ ; Build list in normal order so we don't have to reverse it at the end
+ ; (since our format is non-trivial).
+ (if (null? (car adata))
+ (arch-set-attr-list! CURRENT-ARCH
+ (cons (cons a nil)
+ (acons (obj:name a) a nil)))
+ (begin
+ (append! (car adata) (cons a nil))
+ (append! (cdr adata) (acons (obj:name a) a nil)))))
+ *UNSPECIFIED*
+)
+(define (current-attr-lookup attr-name)
+ (assq-ref (cdr (arch-attr-list CURRENT-ARCH)) attr-name)
+)
+
+; Enums.
+
+(define (current-enum-list) (arch-enum-list CURRENT-ARCH))
+(define (current-enum-add! e)
+ (arch-set-enum-list! CURRENT-ARCH (cons e (arch-enum-list CURRENT-ARCH)))
+)
+(define (current-enum-lookup enum-name)
+ (object-assq enum-name (current-enum-list))
+)
+
+; Keywords.
+
+(define (current-kw-list) (arch-kw-list CURRENT-ARCH))
+(define (current-kw-add! kw)
+ (arch-set-kw-list! CURRENT-ARCH (cons kw (arch-kw-list CURRENT-ARCH)))
+)
+(define (current-kw-lookup kw-name)
+ (object-assq kw-name (current-kw-list))
+)
+
+; Instruction sets.
+
+(define (current-isa-list) (arch-isa-list CURRENT-ARCH))
+(define (current-isa-add! i)
+ (arch-set-isa-list! CURRENT-ARCH (cons i (arch-isa-list CURRENT-ARCH)))
+)
+(define (current-isa-lookup isa-name)
+ (object-assq isa-name (current-isa-list))
+)
+
+; Cpu families.
+
+(define (current-cpu-list) (arch-cpu-list CURRENT-ARCH))
+(define (current-cpu-add! c)
+ (arch-set-cpu-list! CURRENT-ARCH (cons c (arch-cpu-list CURRENT-ARCH)))
+)
+(define (current-cpu-lookup cpu-name)
+ (object-assq cpu-name (current-cpu-list))
+)
+
+; Machines.
+
+(define (current-mach-list) (arch-mach-list CURRENT-ARCH))
+(define (current-mach-add! m)
+ (arch-set-mach-list! CURRENT-ARCH (cons m (arch-mach-list CURRENT-ARCH)))
+)
+(define (current-mach-lookup mach-name)
+ (object-assq mach-name (current-mach-list))
+)
+
+; Models.
+
+(define (current-model-list) (arch-model-list CURRENT-ARCH))
+(define (current-model-add! m)
+ (arch-set-model-list! CURRENT-ARCH (cons m (arch-model-list CURRENT-ARCH)))
+)
+(define (current-model-lookup model-name)
+ (object-assq model-name (current-model-list))
+)
+
+; Hardware elements.
+
+(define (current-hw-list) (arch-hw-list CURRENT-ARCH))
+(define (current-hw-add! hw)
+ (arch-set-hw-list! CURRENT-ARCH (cons hw (arch-hw-list CURRENT-ARCH)))
+)
+(define (current-hw-lookup hw)
+ (if (object? hw)
+ hw
+ ; This doesn't use object-assq on purpose. Hardware objects handle
+ ; get-name specially.
+ (find-first (lambda (hw-obj) (eq? (send hw-obj 'get-name) hw))
+ (current-hw-list)))
+)
+
+; Instruction fields.
+
+(define (current-ifld-list) (map cdr (arch-ifld-list CURRENT-ARCH)))
+(define (current-ifld-add! f)
+ (arch-set-ifld-list! CURRENT-ARCH
+ (acons (obj:name f) f (arch-ifld-list CURRENT-ARCH)))
+)
+(define (current-ifld-lookup x)
+ (if (ifield? x)
+ x
+ (assq-ref (arch-ifld-list CURRENT-ARCH) x))
+)
+
+; Operands.
+
+(define (current-op-list) (map cdr (arch-op-list CURRENT-ARCH)))
+(define (current-op-add! op)
+ (arch-set-op-list! CURRENT-ARCH
+ (acons (obj:name op) op (arch-op-list CURRENT-ARCH)))
+)
+(define (current-op-lookup name)
+ (assq-ref (arch-op-list CURRENT-ARCH) name)
+)
+
+; Instruction field formats.
+
+(define (current-ifmt-list) (arch-ifmt-list CURRENT-ARCH))
+
+; Semantic formats (akin to ifmt's, except includes semantics to distinguish
+; insns).
+
+(define (current-sfmt-list) (arch-sfmt-list CURRENT-ARCH))
+
+; Instructions.
+
+(define (current-raw-insn-list) (arch-insn-list CURRENT-ARCH))
+(define (current-insn-list) (map cdr (arch-insn-list CURRENT-ARCH)))
+(define (current-insn-add! i)
+ (arch-set-insn-list! CURRENT-ARCH
+ (acons (obj:name i) i (arch-insn-list CURRENT-ARCH)))
+)
+(define (current-insn-lookup name)
+ (assq-ref (arch-insn-list CURRENT-ARCH) name)
+)
+
+; Return the insn in the `car' position of INSN-LIST.
+
+(define insn-list-car cdar)
+
+; Splice INSN into INSN-LIST after (car INSN-LIST).
+; This is useful when creating machine generating insns - it's useful to
+; keep them close to their progenitor.
+; The result is the same list, but beginning at the spliced-in insn.
+
+(define (insn-list-splice! insn-list insn)
+ (set-cdr! insn-list (acons (obj:name insn) insn (cdr insn-list)))
+ (cdr insn-list)
+)
+
+; Macro instructions.
+
+(define (current-minsn-list) (map cdr (arch-minsn-list CURRENT-ARCH)))
+(define (current-minsn-add! m)
+ (arch-set-minsn-list! CURRENT-ARCH
+ (acons (obj:name m) m (arch-minsn-list CURRENT-ARCH)))
+)
+(define (current-minsn-lookup name)
+ (assq-ref (arch-minsn-list CURRENT-ARCH) name)
+)
+
+; rtx subroutines.
+
+(define (current-subr-list) (map cdr (arch-subr-list CURRENT-ARCH)))
+(define (current-subr-add! m)
+ (arch-set-subr-list! CURRENT-ARCH
+ (acons (obj:name m) m (arch-subr-list CURRENT-ARCH)))
+)
+(define (current-subr-lookup name)
+ (assq-ref (arch-subr-list CURRENT-ARCH) name)
+)
+
+; Arch parsing support.
+
+; Parse an alignment spec.
+
+(define (-arch-parse-alignment errtxt alignment)
+ (if (memq alignment '(aligned unaligned forced))
+ alignment
+ (parse-error errtxt "invalid alignment" alignment))
+)
+
+; Parse an arch mach spec.
+; The value is a list of mach names or (mach-name sanitize-key) elements.
+; The result is a list of (mach-name . sanitize-key) elements.
+
+(define (-arch-parse-machs errtxt machs)
+ (for-each (lambda (m)
+ (if (or (symbol? m)
+ (and (list? m) (= (length m) 2)
+ (symbol? (car m)) (symbol? (cadr m))))
+ #t ; ok
+ (parse-error errtxt "bad arch mach spec" m)))
+ machs)
+ (map (lambda (m)
+ (if (symbol? m)
+ (cons m #f)
+ (cons (car m) (cadr m))))
+ machs)
+)
+
+; Parse an arch isa spec.
+; The value is a list of isa names or (isa-name sanitize-key) elements.
+; The result is a list of (isa-name . sanitize-key) elements.
+
+(define (-arch-parse-isas errtxt isas)
+ (for-each (lambda (m)
+ (if (or (symbol? m)
+ (and (list? m) (= (length m) 2)
+ (symbol? (car m)) (symbol? (cadr m))))
+ #t ; ok
+ (parse-error errtxt "bad arch isa spec" m)))
+ isas)
+ (map (lambda (m)
+ (if (symbol? m)
+ (cons m #f)
+ (cons (car m) (cadr m))))
+ isas)
+)
+
+; Parse an architecture description
+; This is the main routine for building an arch object from a cpu
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-arch-parse context name comment attrs
+ default-alignment insn-lsb0?
+ machs isas)
+ (logit 2 "Processing arch " name " ...\n")
+ (make <arch-data>
+ (parse-name name context)
+ (parse-comment comment context)
+ (atlist-parse attrs "arch" context)
+ (-arch-parse-alignment context default-alignment)
+ (parse-boolean context insn-lsb0?)
+ (-arch-parse-machs context machs)
+ (-arch-parse-isas context isas))
+)
+
+; Read an architecture description.
+; This is the main routine for analyzing an arch description in the .cpu file.
+; ARG-LIST is an associative list of field name and field value.
+; parse-arch is invoked to create the `arch' object.
+
+(define -arch-read
+ (lambda arg-list
+ (let ((context "arch-read")
+ ; <arch-data> object members and default values
+ (name "unknown")
+ (comment "")
+ (attrs nil)
+ (default-alignment 'aligned)
+ (insn-lsb0? #f)
+ (machs #f)
+ (isas #f)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((default-alignment) (set! default-alignment (cadr arg)))
+ ((insn-lsb0?) (set! insn-lsb0? (cadr arg)))
+ ((machs) (set! machs (cdr arg)))
+ ((isas) (set! isas (cdr arg)))
+ (else (parse-error context "invalid arch arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Ensure required fields are present.
+ (if (not machs)
+ (parse-error context "missing machs spec"))
+ (if (not isas)
+ (parse-error context "missing isas spec"))
+ ; Now that we've identified the elements, build the object.
+ (-arch-parse context name comment attrs default-alignment insn-lsb0?
+ machs isas)
+ )
+ )
+)
+
+; Define an arch object, name/value pair list version.
+
+(define define-arch
+ (lambda arg-list
+ (let ((a (apply -arch-read arg-list)))
+ (arch-set-data! CURRENT-ARCH a)
+ (def-mach-attr! (adata-machs a))
+ (keep-mach-validate!)
+ (def-isa-attr! (adata-isas a))
+ (keep-isa-validate!)
+ ; Install the builtin objects now that we have an arch, and now that
+ ; attributes MACH and ISA exist.
+ (reader-install-builtin!)
+ a))
+)
+
+; Mach/isa processing.
+
+; Create the MACH attribute.
+; MACHS is the canonicalized machs spec to define-arch: (name . sanitize-key).
+
+(define (def-mach-attr! machs)
+ (let ((mach-enums (append
+ '((base))
+ (map (lambda (mach)
+ (cons (car mach)
+ (cons '-
+ (if (cdr mach)
+ (list (cons 'sanitize (cdr mach)))
+ nil))))
+ machs)
+ '((max)))))
+ (define-attr '(type bitset) '(name MACH)
+ '(comment "machine type selection")
+ '(default base) (cons 'values mach-enums))
+ )
+
+ *UNSPECIFIED*
+)
+
+; Return #t if MACH is supported by OBJ.
+; This is done by looking for the MACH attribute in OBJ.
+; By definition, objects that support the default (base) mach support
+; all machs.
+
+(define (mach-supports? mach obj)
+ (let ((machs (bitset-attr->list (obj-attr-value obj 'MACH)))
+ (name (obj:name mach)))
+ (or (memq name machs)
+ (memq 'base machs)))
+ ;(let ((deflt (attr-lookup-default 'MACH obj)))
+ ; (any-true? (map (lambda (m) (memq m deflt)) machs)))))
+)
+
+; Create the ISA attribute.
+; ISAS is the canonicalized isas spec to define-arch: (name . sanitize-key).
+; ISAS is a list of isa names.
+
+(define (def-isa-attr! isas)
+ (let ((isa-enums (append
+ (map (lambda (isa)
+ (cons (car isa)
+ (cons '-
+ (if (cdr isa)
+ (list (cons 'sanitize (cdr isa)))
+ nil))))
+ isas)
+ '((max)))))
+ ; Using a bitset attribute here implies something could be used by two
+ ; separate isas. This seems highly unlikely but we don't [as yet]
+ ; preclude it. The other thing to consider is whether the cpu table
+ ; would ever want to be opened for multiple isas.
+ (define-attr '(type bitset) '(name ISA)
+ '(comment "instruction set selection")
+ ; If there's only one isa, don't (yet) pollute the tables with a value
+ ; for it.
+ (if (= (length isas) 1)
+ '(for)
+ '(for ifield operand insn))
+ (cons 'values isa-enums))
+ )
+
+ *UNSPECIFIED*
+)
+
+; Return #t if <isa> ISA is supported by OBJ.
+; This is done by looking for the ISA attribute in OBJ.
+
+(define (isa-supports? isa obj)
+ (let ((isas (bitset-attr->list (obj-attr-value obj 'ISA)))
+ (name (obj:name isa)))
+ (->bool (memq name isas)))
+)
+
+; The fetch/decode/execute process.
+; "extract" is a fancy word for fetch/decode.
+; FIXME: wip, not currently used.
+; FIXME: move to inside define-isa, and maybe elsewhere.
+;
+;(defmacro
+; define-extract (code)
+; ;(arch-set-insn-extract! CURRENT-ARCH code)
+; *UNSPECIFIED*
+;)
+;
+;(defmacro
+; define-execute (code)
+; ;(arch-set-insn-execute! CURRENT-ARCH code)
+; *UNSPECIFIED*
+;)
+
+; ISA specification.
+; Each architecture is generally one isa, but in the case of ARM (and a few
+; others) there is more than one.
+;
+; ??? "ISA" has a very well defined meaning, and our usage of it one might
+; want to quibble over. A better name would be welcome.
+
+; Associated with an instruction set is its framing.
+; This refers to how instructions are laid out at the liw level (where several
+; insns are framed together and executed sequentially or in parallel).
+; ??? If one defines the term "format" as being how an individual instruction
+; is laid out then formatting can be thought of as being different from
+; framing. However, it's possible for a particular ISA to intertwine the two.
+; Thus this will need to evolve.
+; ??? Not used yet, wip.
+
+(define <iframe> ; pronounced I-frame
+ (class-make '<iframe> '(<ident>)
+ '(
+ ; list of <itype> objects that make up the frame
+ insns
+
+ ; assembler syntax
+ syntax
+
+ ; list of (length value) elements that make up the format
+ ; Length is in bits. Value is either a number or a $number
+ ; symbol refering to the insn specified in `insns'.
+ value
+
+ ; Initial bitnumbers to decode insns by.
+ ; ??? At present the rest of the decoding is determined
+ ; algorithmically. May wish to give the user more control
+ ; [like psim].
+ decode-assist
+
+ ; rtl that executes instructions in `value'
+ ; Fields specified in `value' can be used here.
+ action
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <iframe> iframe (insns syntax value decode-assist action))
+
+; Instruction types, recorded in <iframe>.
+; ??? Not used yet, wip.
+
+(define <itype>
+ (class-make '<itype> '(<ident>)
+ '(
+ ; length in bits, or initial part if variable length (wip)
+ length
+
+ ; constraint specifying which insns are included
+ constraint
+
+ ; Initial bitnumbers to decode insns by.
+ ; ??? At present the rest of the decoding is determined
+ ; algorithmically. May wish to give the user more control
+ ; [like psim].
+ decode-assist
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <itype> itype (length constraint decode-assist))
+
+; Simulator instruction decode splitting.
+; FIXME: Should live in simulator specific code. Requires class handling
+; cleanup first.
+;
+; Instructions can be split by particular values for an ifield.
+; The ARM port uses this to split insns into those that set the pc and
+; those that don't.
+
+(define <decode-split>
+ (class-make '<decode-split> '()
+ '(
+ ; Name of ifield to split on.
+ name
+
+ ; Constraint. Only insns satifying this constraint are
+ ; split. #f if no constraint.
+ constraint
+
+ ; List of ifield splits.
+ ; Each element is one of (name value) or (name (values)).
+ values
+ )
+ nil
+ )
+)
+
+; Accessors.
+
+(define-getters <decode-split> decode-split (name constraint values))
+
+; Parse a decode-split spec.
+; SPEC is (ifield-name constraint value-list).
+; CONSTRAINT is an rtl expression. Only insns satifying the constraint
+; are split.
+; Each element of VALUE-LIST is one of (name value) or (name (values)).
+; FIXME: All possible values must be specified. Need an `else' clause.
+; Ranges would also be useful.
+
+(define (-isa-parse-decode-split context spec)
+ (if (!= (length spec) 3)
+ (parse-error context "decode-split spec is (ifield-name constraint value-list)" spec))
+
+ (let ((name (parse-name (car spec) context))
+ (constraint (cadr spec))
+ (value-list (caddr spec)))
+
+ ; FIXME: more error checking.
+
+ (make <decode-split>
+ name
+ (if (null? constraint) #f constraint)
+ value-list))
+)
+
+; Parse a list of decode-split specs.
+
+(define (-isa-parse-decode-splits context spec-list)
+ (map (lambda (spec)
+ (-isa-parse-decode-split context spec))
+ spec-list)
+)
+
+; Top level class to describe an isa.
+
+(define <isa>
+ (class-make '<isa> '(<ident>)
+ '(
+ ; Default length to record in ifields.
+ ; This is used in calculations involving bit numbers.
+ default-insn-word-bitsize
+
+ ; Length of an unknown instruction. Used by disassembly
+ ; and by the simulator's invalid insn handler.
+ default-insn-bitsize
+
+ ; Number of bytes of insn that can be initially fetched.
+ ; In non-LIW isas this would be the length of the smallest
+ ; insn. For LIW isas it depends - only one LIW isa is
+ ; currently supported (m32r).
+ base-insn-bitsize
+
+ ; Initial bitnumbers to decode insns by.
+ ; ??? At present the rest of the decoding is determined
+ ; algorithmically. May wish to give the user more control
+ ; [like psim].
+ decode-assist
+
+ ; Number of instructions that can be fetched at a time
+ ; [e.g. 2 on m32r].
+ liw-insns
+
+ ; Maximum number of instructions the cpu can execute in
+ ; parallel.
+ ; FIXME: Rename to max-parallel-insns.
+ parallel-insns
+
+ ; List of <iframe> objects.
+ ;frames
+
+ ; Condition tested before execution of any instruction or
+ ; #f if there is none. For architectures like ARM, ARC.
+ ; If specified it is a pair of
+ ; (condition-field-name . rtl-for-condition)
+ (condition . #f)
+
+ ; Code to execute after CONDITION and prior to SEMANTICS.
+ ; This is rtl in source form or #f if there is none.
+ ; This is generally unused. It is used on the ARM to set
+ ; R15 to the correct value.
+ ; The reason it's not specified with SEMANTICS is that it is
+ ; believed some applications won't need/want this.
+ ; ??? It is a bit of a hack though, as it is used to aid
+ ; implementation of apps (e.g. simulator). Arguably something
+ ; that doesn't belong here. Maybe as more architectures are
+ ; ported that have the PC as a general register, a better way
+ ; to do this will arise.
+ (setup-semantics . #f)
+
+ ; list of simulator instruction splits
+ ; FIXME: should live in simulator file (needs class cleanup).
+ (decode-splits . ())
+
+ ; ??? More may need to migrate here.
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <isa> isa
+ (base-insn-bitsize default-insn-bitsize default-insn-word-bitsize
+ decode-assist liw-insns parallel-insns condition
+ setup-semantics decode-splits)
+)
+
+(define-setters <isa> isa
+ (decode-splits)
+)
+
+(define (isa-enum isa) (string-append "ISA_" (string-upcase (gen-sym isa))))
+
+; Return minimum/maximum size in bits of all insns in the isa.
+
+(define (isa-min-insn-bitsize isa)
+ ; add `65535' in case list is nil (avoids crash)
+ ; [a language with infinite precision can't have min-reduce-iota-0 :-)]
+ (apply min (cons 65535
+ (map insn-length (find (lambda (insn)
+ (and (not (has-attr? insn 'ALIAS))
+ (eq? (obj-attr-value insn 'ISA)
+ (obj:name isa))))
+ (non-multi-insns (current-insn-list))))))
+)
+
+(define (isa-max-insn-bitsize isa)
+ ; add `0' in case list is nil (avoids crash)
+ ; [a language with infinite precision can't have max-reduce-iota-0 :-)]
+ (apply max (cons 0
+ (map insn-length (find (lambda (insn)
+ (and (not (has-attr? insn 'ALIAS))
+ (eq? (obj-attr-value insn 'ISA)
+ (obj:name isa))))
+ (non-multi-insns (current-insn-list))))))
+)
+
+; Return a boolean indicating if instructions in ISA can be kept in a
+; portable int.
+
+(define (isa-integral-insn? isa)
+ (<= (isa-max-insn-bitsize isa) 32)
+)
+
+; Parse an isa condition spec.
+; `condition' here refers to the condition performed by architectures like
+; ARM and ARC before each insn.
+
+(define (-isa-parse-condition context spec)
+ (if (null? spec)
+ #f
+ (begin
+ (if (or (!= (length spec) 2)
+ (not (symbol? (car spec)))
+ (not (form? (cadr spec))))
+ (parse-error context
+ "condition spec not `(ifield-name rtl-code)'" spec))
+ spec))
+)
+
+; Parse a setup-semantics spec.
+
+(define (-isa-parse-setup-semantics context spec)
+ (if (not (null? spec))
+ spec
+ #f)
+)
+
+; Parse an isa spec.
+; The result is the <isa> object.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-isa-parse context name comment attrs
+ base-insn-bitsize default-insn-bitsize default-insn-word-bitsize
+ decode-assist liw-insns parallel-insns condition
+ setup-semantics decode-splits)
+ (logit 2 "Processing isa " name " ...\n")
+
+ (let ((name (parse-name name context)))
+ (if (not (memq name (current-arch-isa-name-list)))
+ (parse-error context "isa name is not present in `define-arch'" name))
+
+ ; Isa's are always kept - we need them to validate later uses, even if
+ ; the then resulting object won't be kept. All isas are also needed to
+ ; compute a proper value for the isas-cache member of <hardware-base>
+ ; for builtin objects.
+ (make <isa>
+ name
+ (parse-comment comment context)
+ (atlist-parse attrs "isa" context)
+ (parse-number (string-append context
+ ": default-insn-word-bitsize")
+ default-insn-word-bitsize '(8 . 128))
+ (parse-number (string-append context
+ ": default-insn-bitsize")
+ default-insn-bitsize '(8 . 128))
+ (parse-number (string-append context
+ ": base-insn-bitsize")
+ base-insn-bitsize '(8 . 128))
+ decode-assist
+ liw-insns
+ parallel-insns
+ (-isa-parse-condition context condition)
+ (-isa-parse-setup-semantics context setup-semantics)
+ (-isa-parse-decode-splits context decode-splits)
+ ))
+)
+
+; Read an isa entry.
+; ARG-LIST is an associative list of field name and field value.
+
+(define -isa-read
+ (lambda arg-list
+ (let ((context "isa-read")
+ ; <isa> object members and default values
+ (name #f)
+ (attrs nil)
+ (comment "")
+ (base-insn-bitsize #f)
+ (default-insn-bitsize #f)
+ (default-insn-word-bitsize #f)
+ (decode-assist nil)
+ (liw-insns 1)
+ ; FIXME: Hobbit computes the wrong symbol for `parallel-insns'
+ ; in the `case' expression below because there is a local var
+ ; of the same name ("__1" gets appended to the symbol name).
+ (parallel-insns- 1)
+ (condition nil)
+ (setup-semantics nil)
+ (decode-splits nil)
+ )
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((default-insn-word-bitsize)
+ (set! default-insn-word-bitsize (cadr arg)))
+ ((default-insn-bitsize) (set! default-insn-bitsize (cadr arg)))
+ ((base-insn-bitsize) (set! base-insn-bitsize (cadr arg)))
+ ((decode-assist) (set! decode-assist (cadr arg)))
+ ((liw-insns) (set! liw-insns (cadr arg)))
+ ((parallel-insns) (set! parallel-insns- (cadr arg)))
+ ((condition) (set! condition (cdr arg)))
+ ((setup-semantics) (set! setup-semantics (cadr arg)))
+ ((decode-splits) (set! decode-splits (cdr arg)))
+ ((insn-types) #t) ; ignore for now
+ ((frame) #t) ; ignore for now
+ (else (parse-error context "invalid isa arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-isa-parse context name comment attrs
+ base-insn-bitsize
+ (if default-insn-word-bitsize
+ default-insn-word-bitsize
+ base-insn-bitsize)
+ (if default-insn-bitsize
+ default-insn-bitsize
+ base-insn-bitsize)
+ decode-assist liw-insns parallel-insns- condition
+ setup-semantics decode-splits)
+ )
+ )
+)
+
+; Define a <isa> object, name/value pair list version.
+
+(define define-isa
+ (lambda arg-list
+ (let ((i (apply -isa-read arg-list)))
+ (if i
+ (current-isa-add! i))
+ i))
+)
+
+; Subroutine of modify-isa to process one add-decode-split spec.
+
+(define (-isa-add-decode-split! context isa spec)
+ (let ((decode-split (-isa-parse-decode-split context spec)))
+ (isa-set-decode-splits! (cons decode-split (isa-decode-splits isa)))
+ *UNSPECIFIED*)
+)
+
+; Main routine for modifying existing isa definitions
+
+(define modify-isa
+ (lambda arg-list
+ (let ((errtxt "modify-isa")
+ (isa-spec (assq 'name arg-list)))
+ (if (not isa-spec)
+ (parse-error errtxt "isa name not specified"))
+
+ (let ((isa (current-isa-lookup (arg-list-symbol-arg errtxt isa-spec))))
+ (if (not isa)
+ (parse-error errtxt "undefined isa" isa-spec))
+
+ (let loop ((args arg-list))
+ (if (null? args)
+ #f ; done
+ (let ((arg-spec (car args)))
+ (case (car arg-spec)
+ ((name) #f) ; ignore, already processed
+ ((add-decode-split)
+ (-isa-add-decode-split! errtxt isa (cdr arg-spec)))
+ (else
+ (parse-error errtxt "invalid/unsupported option" (car arg-spec))))
+ (loop (cdr args)))))))
+
+ *UNSPECIFIED*)
+)
+
+; Return boolean indicating if ISA supports parallel execution.
+
+(define (isa-parallel-exec? isa) (> (isa-parallel-insns isa) 1))
+
+; Return a boolean indicating if ISA supports conditional execution
+; of all instructions.
+
+(define (isa-conditional-exec? isa) (->bool (isa-condition isa)))
+
+; The `<cpu>' object collects together various details about a particular
+; subset of the architecture (e.g. perhaps all 32 bit variants of the sparc
+; architecture).
+; This is called a "cpu-family".
+; ??? May be renamed to <family> (both internally and in the .cpu file).
+; ??? Another way to do this would be to discard the family notion and allow
+; machs to inherit from other machs, as well as use isas to distinguish
+; sufficiently dissimilar machs. This would remove a fuzzy illspecified
+; notion with a concrete one.
+; ??? Maybe a better way to organize sparc32 vs sparc64 is via an isa.
+
+(define <cpu>
+ (class-make '<cpu>
+ '(<ident>)
+ '(
+ ; one of big/little/either/#f.
+ ; If #f, then {insn,data,float}-endian are used.
+ ; Otherwise they're ignored.
+ endian
+
+ ; one of big/little/either.
+ insn-endian
+
+ ; one of big/little/either/big-words/little-words.
+ ; If big-words then each word is little-endian.
+ ; If little-words then each word is big-endian.
+ data-endian
+
+ ; one of big/little/either/big-words/little-words.
+ float-endian
+
+ ; number of bits in a word.
+ word-bitsize
+
+ ; Transformation to use in generated files should one be
+ ; needed. At present the only supported value is a string
+ ; which is the file suffix.
+ ; ??? A dubious element of the description language, but given
+ ; the quantity of generated files, some machine generated
+ ; headers may need to #include other machine generated headers
+ ; (e.g. cpuall.h).
+ file-transform
+
+ ; Allow a cpu family to override the isa parallel-insns spec.
+ ; ??? Concession to the m32r port which can go away, in time.
+ parallel-insns
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <cpu> cpu (word-bitsize file-transform parallel-insns))
+
+; Return endianness of instructions.
+
+(define (cpu-insn-endian cpu)
+ (let ((endian (elm-xget cpu 'endian)))
+ (if endian
+ endian
+ (elm-xget cpu 'insn-endian)))
+)
+
+; Return endianness of data.
+
+(define (cpu-data-endian cpu)
+ (let ((endian (elm-xget cpu 'endian)))
+ (if endian
+ endian
+ (elm-xget cpu 'data-endian)))
+)
+
+; Return endianness of floats.
+
+(define (cpu-float-endian cpu)
+ (let ((endian (elm-xget cpu 'endian)))
+ (if endian
+ endian
+ (elm-xget cpu 'float-endian)))
+)
+
+; Parse a cpu family description
+; This is the main routine for building a <cpu> object from a cpu
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-cpu-parse name comment attrs
+ endian insn-endian data-endian float-endian
+ word-bitsize file-transform parallel-insns)
+ (logit 2 "Processing cpu family " name " ...\n")
+ ; Pick out name first 'cus we need it as a string(/symbol).
+ (let* ((name (parse-name name "cpu"))
+ (errtxt (string-append "cpu " name)))
+ (if (keep-cpu? name)
+ (make <cpu>
+ name
+ (parse-comment comment errtxt)
+ (atlist-parse attrs "cpu" errtxt)
+ endian insn-endian data-endian float-endian
+ word-bitsize
+ file-transform
+ parallel-insns)
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f))) ; cpu is not to be kept
+)
+
+; Read a cpu family description
+; This is the main routine for analyzing a cpu description in the .cpu file.
+; ARG-LIST is an associative list of field name and field value.
+; -cpu-parse is invoked to create the <cpu> object.
+
+(define -cpu-read
+ (lambda arg-list
+ (let ((errtxt "cpu-read")
+ ; <cpu> object members and default values
+ (name nil)
+ (comment nil)
+ (attrs nil)
+ (endian #f)
+ (insn-endian #f)
+ (data-endian #f)
+ (float-endian #f)
+ (word-bitsize nil)
+ (file-transform "")
+ ; FIXME: Hobbit computes the wrong symbol for `parallel-insns'
+ ; in the `case' expression below because there is a local var
+ ; of the same name ("__1" gets appended to the symbol name).
+ (parallel-insns- #f)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((endian) (set! endian (cadr arg)))
+ ((insn-endian) (set! insn-endian (cadr arg)))
+ ((data-endian) (set! data-endian (cadr arg)))
+ ((float-endian) (set! float-endian (cadr arg)))
+ ((word-bitsize) (set! word-bitsize (cadr arg)))
+ ((file-transform) (set! file-transform (cadr arg)))
+ ((parallel-insns) (set! parallel-insns- (cadr arg)))
+ (else (parse-error errtxt "invalid cpu arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-cpu-parse name comment attrs
+ endian insn-endian data-endian float-endian
+ word-bitsize file-transform parallel-insns-)
+ )
+ )
+)
+
+; Define a cpu family object, name/value pair list version.
+
+(define define-cpu
+ (lambda arg-list
+ (let ((c (apply -cpu-read arg-list)))
+ (if c
+ (current-cpu-add! c))
+ c))
+)
+
+; The `<mach>' object describes one member of a `cpu' family.
+
+(define <mach>
+ (class-make '<mach> '(<ident>)
+ '(
+ ; cpu family this mach is a member of
+ cpu
+ ; bfd name of mach
+ bfd-name
+ ; list of <isa> objects
+ isas
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <mach> mach (cpu bfd-name isas))
+
+(define (mach-enum obj)
+ (string-append "MACH_" (string-upcase (gen-sym obj)))
+)
+
+(define (mach-number obj) (mach-enum obj))
+
+; Parse a machine entry.
+; The result is a <mach> object or #f if the mach isn't to be kept.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-mach-parse context name comment attrs cpu bfd-name isas)
+ (logit 2 "Processing mach " name " ...\n")
+
+ (let ((name (parse-name name context)))
+ (if (not (list? isas))
+ (parse-error context "isa spec not a list" isas))
+ (let ((cpu-obj (current-cpu-lookup cpu))
+ (isa-list (map current-isa-lookup isas)))
+ (if (not (memq name (current-arch-mach-name-list)))
+ (parse-error context "mach name is not present in `define-arch'" name))
+ (if (null? cpu)
+ (parse-error context "missing cpu spec" cpu))
+ (if (not cpu-obj)
+ (parse-error context "unknown cpu" cpu))
+ (if (null? isas)
+ (parse-error context "missing isas spec" isas))
+ (if (not (all-true? isa-list))
+ (parse-error context "unknown isa in" isas))
+ (if (not (string? bfd-name))
+ (parse-error context "bfd-name not a string" bfd-name))
+ (if (keep-mach? (list name))
+ (make <mach>
+ name
+ (parse-comment comment context)
+ (atlist-parse attrs "mach" context)
+ cpu-obj
+ bfd-name
+ isa-list)
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))) ; mach is not to be kept
+)
+
+; Read a mach entry.
+; ARG-LIST is an associative list of field name and field value.
+
+(define -mach-read
+ (lambda arg-list
+ (let ((context "mach-read")
+ (name nil)
+ (attrs nil)
+ (comment nil)
+ (cpu nil)
+ (bfd-name #f)
+ (isas #f)
+ )
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((cpu) (set! cpu (cadr arg)))
+ ((bfd-name) (set! bfd-name (cadr arg)))
+ ((isas) (set! isas (cdr arg)))
+ (else (parse-error context "invalid mach arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-mach-parse context name comment attrs cpu
+ ; Default bfd-name is same as object's name.
+ (if bfd-name bfd-name (symbol->string name))
+ ; Default isa is the first one.
+ (if isas isas (list (obj:name (car (current-isa-list))))))
+ )
+ )
+)
+
+; Define a <mach> object, name/value pair list version.
+
+(define define-mach
+ (lambda arg-list
+ (let ((m (apply -mach-read arg-list)))
+ (if m
+ (current-mach-add! m))
+ m))
+)
+
+; Miscellaneous state derived from the input data.
+; FIXME: being redone
+
+; Size of a word in bits.
+; All selected cpu families must have same value or error.
+; FIXME: Only user is opcodes.scm and we don't want this restriction there.
+
+(define (state-word-bitsize)
+ (let ((wb (map cpu-word-bitsize (current-cpu-list))))
+ ; FIXME: ensure all have same value.
+ (car wb))
+)
+
+; Return maximum word bitsize.
+
+(define (state-max-word-bitsize)
+ (apply max (map cpu-word-bitsize (current-cpu-list)))
+)
+
+; Size of normal instruction.
+; All selected isas must have same value or error.
+
+(define (state-default-insn-bitsize)
+ (let ((dib (map isa-default-insn-bitsize (current-isa-list))))
+ ; FIXME: ensure all have same value.
+ (car dib))
+)
+
+; Number of bytes of insn we can initially fetch.
+; All selected isas must have same value or error.
+
+(define (state-base-insn-bitsize)
+ (let ((bib (map isa-base-insn-bitsize (current-isa-list))))
+ ; FIXME: ensure all have same value.
+ (car bib))
+)
+
+; Return parallel-insns spec.
+
+(define (state-parallel-insns)
+ ; Assert only one cpu family has been selected.
+ (assert-keep-one)
+
+ (let ((par-insns (map isa-parallel-insns (current-isa-list)))
+ (cpu-par-insns (cpu-parallel-insns (current-cpu))))
+ ; ??? The m32r does have parallel execution, but to keep support for the
+ ; base mach simpler, a cpu family is allowed to override the isa spec.
+ (or cpu-par-insns
+ ; FIXME: ensure all have same value.
+ (car par-insns)))
+)
+
+; Return boolean indicating if parallel execution support is required.
+
+(define (state-parallel-exec?)
+ (> (state-parallel-insns) 1)
+)
+
+; Return liw-insns spec.
+
+(define (state-liw-insns)
+ (let ((liw-insns (map isa-liw-insns (current-isa-list))))
+ ; FIXME: ensure all have same value.
+ (car liw-insns))
+)
+
+; Return decode-assist spec.
+
+(define (state-decode-assist)
+ (isa-decode-assist (current-isa))
+)
+
+; Return boolean indicating if current isa conditionally executes all insn.
+
+(define (state-conditional-exec?)
+ (isa-conditional-exec? (current-isa))
+)
+
+; Architecture or cpu wide values derived from other data.
+
+(define <derived-arch-data>
+ (class-make '<derived-arch-data>
+ nil
+ '(
+ ; whether all insns can be recorded in a host int
+ integral-insn?
+ )
+ nil)
+)
+
+; Called after the .cpu file has been read in to prime derived value
+; computation.
+; Often this data isn't needed so we only computed it if we have to.
+
+(define (-adata-set-derived! arch)
+ ; Don't compute this data unless we need to.
+ (arch-set-derived!
+ arch
+ (make <derived-arch-data>
+ ; integral-insn?
+ (delay (isa-integral-insn? (current-isa)))
+ ))
+)
+
+; Accessors.
+
+(define (adata-integral-insn? arch)
+ (force (elm-xget (arch-derived arch) 'integral-insn?))
+)
+
+; Instruction analysis control.
+
+; Analyze the instruction set.
+; The name is explicitly vague because it's intended that all insn analysis
+; would be controlled here.
+; If the instruction set has already been sufficiently analyzed, do nothing.
+; INCLUDE-ALIASES? is #t if alias insns are to be included.
+; ANALYZE-SEMANTICS? is #t if insn semantics are to be analyzed.
+;
+; This is a very expensive operation, so we only do it as necessary.
+; There are (currently) two different kinds of users: assemblers and
+; simulators. Assembler style apps don't always need to analyze the semantics.
+; Simulator style apps don't want to include the alias insns.
+
+(define (arch-analyze-insns! arch include-aliases? analyze-semantics?)
+ (if (or (not (arch-insns-analyzed? arch))
+ (not (eq? analyze-semantics? (arch-semantics-analyzed? arch)))
+ (not (eq? include-aliases? (arch-aliases-analyzed? arch))))
+
+ (begin
+ (if (any-true? (map multi-insn? (current-insn-list)))
+ (begin
+ ; Instantiate sub-insns of all multi-insns.
+ (logit 1 "Instantiating multi-insns ...\n")
+ (for-each (lambda (insn)
+ (multi-insn-instantiate! insn))
+ (multi-insns (current-insn-list)))
+ ))
+
+ ; This is expensive so indicate start/finish.
+ (logit 1 "Analyzing instruction set ...\n")
+
+ (let ((fmt-lists
+ (ifmt-compute! (non-multi-insns
+ (if include-aliases?
+ (map cdr (arch-insn-list arch))
+ (non-alias-insns (map cdr (arch-insn-list arch)))))
+ analyze-semantics?)))
+
+ (arch-set-ifmt-list! arch (car fmt-lists))
+ (arch-set-sfmt-list! arch (cadr fmt-lists))
+ (arch-set-insns-analyzed?! arch #t)
+ (arch-set-semantics-analyzed?! arch analyze-semantics?)
+ (arch-set-aliases-analyzed?! arch include-aliases?)
+
+ (logit 1 "Done analysis.\n")
+ ))
+ )
+
+ *UNSPECIFIED*
+)
+
+; Called before a .cpu file is read in.
+
+(define (arch-init!)
+
+ (reader-add-command! 'define-arch
+ "\
+Define an architecture, name/value pair list version.
+"
+ nil 'arg-list define-arch)
+
+ (reader-add-command! 'define-isa
+ "\
+Define an instruction set architecture, name/value pair list version.
+"
+ nil 'arg-list define-isa)
+ (reader-add-command! 'modify-isa
+ "\
+Modify an isa, name/value pair list version.
+"
+ nil 'arg-list modify-isa)
+
+ (reader-add-command! 'define-cpu
+ "\
+Define a cpu family, name/value pair list version.
+"
+ nil 'arg-list define-cpu)
+
+ *UNSPECIFIED*
+)
+
+; Called before a .cpu file is read in.
+
+(define (mach-init!)
+
+ (reader-add-command! 'define-mach
+ "\
+Define a machine, name/value pair list version.
+"
+ nil 'arg-list define-mach)
+
+ *UNSPECIFIED*
+)
+
+; Called after .cpu file is read in.
+
+(define (arch-finish!)
+ (let ((arch CURRENT-ARCH))
+
+ ; Lists are constructed in the reverse order they appear in the file
+ ; [for simplicity and efficiency]. Restore them to file order for the
+ ; human reader/debugger.
+ (arch-set-enum-list! arch (reverse (arch-enum-list arch)))
+ (arch-set-kw-list! arch (reverse (arch-kw-list arch)))
+ (arch-set-isa-list! arch (reverse (arch-isa-list arch)))
+ (arch-set-cpu-list! arch (reverse (arch-cpu-list arch)))
+ (arch-set-mach-list! arch (reverse (arch-mach-list arch)))
+ (arch-set-model-list! arch (reverse (arch-model-list arch)))
+ (arch-set-ifld-list! arch (reverse (arch-ifld-list arch)))
+ (arch-set-hw-list! arch (reverse (arch-hw-list arch)))
+ (arch-set-op-list! arch (reverse (arch-op-list arch)))
+ (arch-set-insn-list! arch (reverse (arch-insn-list arch)))
+ (arch-set-minsn-list! arch (reverse (arch-minsn-list arch)))
+ (arch-set-subr-list! arch (reverse (arch-subr-list arch)))
+ )
+
+ *UNSPECIFIED*
+)
+
+; Called after .cpu file is read in.
+
+(define (mach-finish!)
+ (-adata-set-derived! CURRENT-ARCH)
+
+ *UNSPECIFIED*
+)
diff --git a/cgen/minsn.scm b/cgen/minsn.scm
new file mode 100644
index 00000000000..671c3a1849d
--- /dev/null
+++ b/cgen/minsn.scm
@@ -0,0 +1,259 @@
+; Macro instruction definitions.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Expansion:
+; If the macro expands to a string, arguments in the input string
+; are refered to with %N. Multiple insns are separated with '\n'.
+; String expansion is a special case of the normal form which is a Scheme
+; expression that controls the expansion. The Scheme expression will be able
+; to refer to the current assembly state to decide how to perform the
+; expansion. Special expression `emit' is used to call the assembler emitter
+; for a particular insn. Special expression `expand' is used to return a
+; string to be reparsed (which is special cased).
+
+; Parse a list of macro-instruction expansion descriptions.
+; This is the main routine for building an minsn-expansion object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+
+; ??? At present we only support macros that are aliases of one real insn.
+
+; Object to describe a macro-insn.
+
+(define <macro-insn>
+ (class-make '<macro-insn>
+ '(<ident>)
+ '(
+ ; syntax of the macro
+ syntax
+ ; list of expansion expressions
+ expansions
+ )
+ nil)
+)
+
+; Accessor fns
+
+(define minsn-syntax (elm-make-getter <macro-insn> 'syntax))
+(define minsn-expansions (elm-make-getter <macro-insn> 'expansions))
+
+; Return a list of the machs that support MINSN.
+
+(define (minsn-machs minsn)
+ nil
+)
+
+; Return macro-instruction mnemonic.
+; This is computed from the syntax string.
+
+(define minsn-mnemonic insn-mnemonic)
+
+; Return enum cgen_minsn_types value for MINSN.
+
+(define (minsn-enum minsn)
+ (string-upcase (string-append "@ARCH@_MINSN_" (gen-sym minsn)))
+)
+
+; Parse a macro-insn expansion description.
+; ??? At present we only support unconditional simple expansion.
+
+(define (-minsn-parse-expansion errtxt expn)
+ (if (not (form? expn))
+ (parse-error errtxt "invalid macro expansion" expn))
+ (if (not (eq? 'emit (car expn)))
+ (parse-error errtxt "invalid macro expansion, must be `(emit ...)'" expn))
+ expn
+)
+
+; Parse a macro-instruction description.
+; This is the main routine for building a macro-insn object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+
+(define (-minsn-parse errtxt name comment attrs syntax expansions)
+ (logit 2 "Processing macro-insn " name " ...\n")
+
+ (if (not (list? expansions))
+ (parse-error errtxt "invalid macro expansion list" expansions))
+
+ (let ((name (parse-name name errtxt))
+ (atlist-obj (atlist-parse attrs "cgen_minsn" errtxt)))
+
+ (if (keep-atlist? atlist-obj #f)
+
+ (let ((result (make <macro-insn>
+ name
+ (parse-comment comment errtxt)
+ atlist-obj
+ (parse-syntax syntax errtxt)
+ (map (lambda (e) (-minsn-parse-expansion errtxt e))
+ expansions))))
+ result)
+
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read a macro-insn description
+; This is the main routine for analyzing macro-insns in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -minsn-parse is invoked to create the `macro-insn' object.
+
+(define (-minsn-read errtxt . arg-list)
+ (let (; Current macro-insn elements:
+ (name nil)
+ (comment "")
+ (attrs nil)
+ (syntax "")
+ (expansions nil)
+ )
+ ; Loop over each element in ARG-LIST, recording what's found.
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((syntax) (set! syntax (cadr arg)))
+ ((expansions) (set! expansions (cdr arg)))
+ (else (parse-error errtxt "invalid macro-insn arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-minsn-parse errtxt name comment attrs syntax expansions)
+ )
+)
+
+; Define a macro-insn object, name/value pair list version.
+
+(define define-minsn
+ (lambda arg-list
+ (if (eq? APPLICATION 'SIMULATOR)
+ #f ; don't waste time if simulator
+ (let ((m (apply -minsn-read (cons "define-minsn" arg-list))))
+ (if m
+ (current-minsn-add! m))
+ m)))
+)
+
+; Define a macro-insn object, all arguments specified.
+; This only supports one expansion.
+; Use define-minsn for the general case (??? which is of course not implemented
+; yet :-).
+
+(define (define-full-minsn name comment attrs syntax expansion)
+ (if (eq? APPLICATION 'SIMULATOR)
+ #f ; don't waste time if simulator
+ (let ((m (-minsn-parse "define-full-minsn" name comment
+ (cons 'ALIAS attrs)
+ syntax (list expansion))))
+ (if m
+ (current-minsn-add! m))
+ m))
+)
+
+; Compute the ifield list for an alias macro-insn.
+; This involves making a copy of REAL-INSN's ifield list and assigning
+; known quantities to operands that have fixed values in the macro-insn.
+
+(define (minsn-compute-iflds errtxt minsn-iflds real-insn)
+ (let* ((iflds (list-copy (insn-iflds real-insn)))
+ ; List of "free variables", i.e. operands.
+ (ifld-ops (find ifld-operand? iflds))
+ ; Names of fields in `ifld-ops'. As elements of minsn-iflds are
+ ; parsed the associated element in ifld-names is deleted. At the
+ ; end ifld-names must be empty. delq! can't delete the first
+ ; element in a list, so we insert a fencepost.
+ (ifld-names (cons #f (map obj:name ifld-ops))))
+ ;(logit 3 "Computing ifld list, operand field names: " ifld-names "\n")
+ ; For each macro-insn ifield expression, look it up in the real insn's
+ ; ifield list. If an operand without a prespecified value, leave
+ ; unchanged. If an operand or ifield with a value, assign the value to
+ ; the ifield entry.
+ (for-each (lambda (f)
+ (let* ((op-name (if (pair? f) (car f) f))
+ (op-obj (current-op-lookup op-name))
+ ; If `op-name' is an operand, use its ifield.
+ ; Otherwise `op-name' must be an ifield name.
+ (f-name (if op-obj
+ (obj:name (hw-index:value (op:index op-obj)))
+ op-name))
+ (ifld-pair (object-memq f-name iflds)))
+ ;(logit 3 "Processing ifield " f-name " ...\n")
+ (if (not ifld-pair)
+ (parse-error errtxt "unknown operand" f))
+ ; Ensure `f' is an operand.
+ (if (not (memq f-name ifld-names))
+ (parse-error errtxt "not an operand" f))
+ (if (pair? f)
+ (set-car! ifld-pair (ifld-new-value (car ifld-pair) (cadr f))))
+ (delq! f-name ifld-names)))
+ minsn-iflds)
+ (if (not (equal? ifld-names '(#f)))
+ (parse-error errtxt "incomplete operand list, missing: " (cdr ifld-names)))
+ iflds)
+)
+
+; Create an aliased real insn from an alias macro-insn.
+
+(define (minsn-make-alias errtxt minsn)
+ (if (or (not (has-attr? minsn 'ALIAS))
+ ; Must emit exactly one real insn.
+ (not (eq? 'emit (caar (minsn-expansions minsn)))))
+ (parse-error errtxt "not an alias macro-insn" minsn))
+
+ (let* ((expn (car (minsn-expansions minsn)))
+ (alias-of (current-insn-lookup (cadr expn))))
+
+ (if (not alias-of)
+ (parse-error errtxt "unknown real insn in expansion" minsn))
+
+ (let ((i (make <insn>
+ (obj:name minsn)
+ (obj:comment minsn)
+ (obj-atlist minsn)
+ (minsn-syntax minsn)
+ (minsn-compute-iflds (string-append errtxt
+ ": " (obj:name minsn))
+ (cddr expn) alias-of)
+ #f ; ifield-assertion
+ #f ; semantics
+ #f ; timing
+ )))
+ ; FIXME: use same format entry as real insn,
+ ; build mask and test value at run time.
+ (insn-set-ifmt! i (ifmt-build i -1 #f (insn-iflds i))) ; (car (ifmt-analyze i #f))))
+ ;(insn-set-ifmt! i (insn-ifmt alias-of))
+ i))
+)
+
+; Called before a .cpu file is read in.
+
+(define (minsn-init!)
+ (reader-add-command! 'define-minsn
+ "\
+Define a macro instruction, name/value pair list version.
+"
+ nil 'arg-list define-minsn)
+ (reader-add-command! 'define-full-minsn
+ "\
+Define a macro instruction, all arguments specified.
+"
+ nil '(name comment attrs syntax expansion)
+ define-full-minsn)
+
+ *UNSPECIFIED*
+)
+
+; Called after the .cpu file has been read in.
+
+(define (minsn-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/mode.scm b/cgen/mode.scm
new file mode 100644
index 00000000000..5e0c69effb9
--- /dev/null
+++ b/cgen/mode.scm
@@ -0,0 +1,471 @@
+; Mode objects.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; FIXME: Later allow target to add new modes.
+
+(define <mode>
+ (class-make '<mode>
+ '(<ident>)
+ '(
+ ; One of RANDOM, INT, UINT, FLOAT.
+ class
+
+ ; size in bits
+ bits
+
+ ; size in bytes
+ bytes
+
+ ; NON-MODE-C-TYPE is the C type to use in situations where
+ ; modes aren't available. A somewhat dubious feature, but at
+ ; the moment the opcodes tables use it. It is either the C
+ ; type as a string (e.g. "int") or #f for non-portable modes
+ ; (??? could use other typedefs for #f, e.g. int64 for DI).
+ ; Use of GCC can't be assumed though.
+ non-mode-c-type
+
+ ; PRINTF-TYPE is the %<letter> arg to printf-like functions,
+ ; however we define our own extensions for non-portable modes.
+ ; Values not understood by printf aren't intended to be used
+ ; with printf.
+ ;
+ ; Possible values:
+ ; %x - as always
+ ; %D - DI mode
+ ; %f - SF,DF modes
+ ; %F - XF,TF modes
+ printf-type
+
+ ; SEM-MODE is the mode to use for semantic operations.
+ ; Unsigned modes are not part of the semantic language proper,
+ ; but they can be used in hardware descriptions. This maps
+ ; unusable -> usable modes. It is #f if the mode is usable by
+ ; itself. This prevents circular data structures and makes it
+ ; easy to define since the object doesn't exist before it's
+ ; defined.
+ ; ??? May wish to later remove SEM-MODE (e.g. mips signed add
+ ; is different than mips unsigned add) however for now it keeps
+ ; things simpler (and prevents being wildly dissimilar from
+ ; GCC-RTL. And the mips case needn't be handled with different
+ ; adds anyway.
+ sem-mode
+
+ ; PTR-TO, if non-#f, is the mode being pointed to.
+ ptr-to
+
+ ; HOST? is non-#f if the mode is a portable int for hosts,
+ ; or other host-related value.
+ ; This is used for things like register numbers and small
+ ; odd-sized immediates and registers.
+ ; ??? Not my favorite word choice here, but it's close.
+ host?
+ )
+ nil)
+)
+
+; Accessor fns
+
+(define mode:class (elm-make-getter <mode> 'class))
+(define mode:bits (elm-make-getter <mode> 'bits))
+(define mode:bytes (elm-make-getter <mode> 'bytes))
+(define mode:non-mode-c-type (elm-make-getter <mode> 'non-mode-c-type))
+(define mode:printf-type (elm-make-getter <mode> 'printf-type))
+(define mode:sem-mode (elm-make-getter <mode> 'sem-mode))
+; ptr-to is currently private so there is no accessor.
+(define mode:host? (elm-make-getter <mode> 'host?))
+
+; Return C type to use for values of mode M.
+
+(define (mode:c-type m)
+ (let ((ptr-to (elm-xget m 'ptr-to)))
+ (if ptr-to
+ (string-append (mode:c-type ptr-to) " *")
+ (obj:name m)))
+)
+
+; CM is short for "concat mode". It is a list of modes of the elements
+; of a `concat'.
+; ??? Experiment. Not currently used.
+
+(define <concat-mode>
+ (class-make '<concat-mode> '(<mode>)
+ '(
+ ; List of element modes
+ elm-modes
+ )
+ nil)
+)
+
+; Accessors.
+
+(define cmode-elm-modes (elm-make-getter <concat-mode> 'elm-modes))
+
+; List of all modes.
+
+(define mode-list nil)
+
+; Return list of mode objects.
+; Hides the fact that its stored as an alist from caller.
+
+(define (mode-list-values) (map cdr mode-list))
+
+; Return list of real mode objects (no aliases).
+
+(define (mode-list-non-alias-values)
+ (map cdr
+ (find (lambda (m) (eq? (car m) (obj:name (cdr m))))
+ mode-list))
+)
+
+; Return a boolean indicating if X is a <mode> object.
+
+(define (mode? x) (class-instance? <mode> x))
+
+; Return enum cgen_mode_types value for M.
+
+(define (mode:enum m)
+ (gen-c-symbol (string-append "MODE_" (string-upcase (obj:name m))))
+)
+
+; Return a boolean indicating if MODE1 is equal to MODE2
+; Either may be the name of a mode or a <mode> object.
+; Aliases are handled by refering to their real name.
+
+(define (mode:eq? mode1 mode2)
+ (let ((mode1-name (mode-real-name mode1))
+ (mode2-name (mode-real-name mode2)))
+ (eq? mode1-name mode2-name))
+)
+
+; Return a boolean indicating if CLASS is one of INT/UINT.
+
+(define (mode-class-integral? class) (memq class '(INT UINT)))
+(define (mode-class-signed? class) (eq? class 'INT))
+(define (mode-class-unsigned? class) (eq? class 'UINT))
+
+; Return a boolean indicating if CLASS is floating point.
+
+(define (mode-class-float? class) (memq class '(FLOAT)))
+
+; Return a boolean indicating if CLASS is numeric.
+
+(define (mode-class-numeric? class) (memq class '(INT UINT FLOAT)))
+
+; Return a boolean indicating if MODE has an integral mode class.
+; Similarily for signed/unsigned.
+
+(define (mode-integral? mode) (mode-class-integral? (mode:class mode)))
+(define (mode-signed? mode) (mode-class-signed? (mode:class mode)))
+(define (mode-unsigned? mode) (mode-class-unsigned? (mode:class mode)))
+
+; Return a boolean indicating if MODE has a floating point mode class.
+
+(define (mode-float? mode) (mode-class-float? (mode:class mode)))
+
+; Return a boolean indicating if MODE has a numeric mode class.
+
+(define (mode-numeric? mode) (mode-class-numeric? (mode:class mode)))
+
+; Return a boolean indicating if MODE1 is compatible with MODE2.
+; MODE[12] are either names or <mode> objects.
+; HOW is a symbol indicating how the test is performed:
+; strict: modes must have same name
+; samesize: modes must be both float or both integer (int or uint) and have
+; same size
+; sameclass: modes must be both float or both integer (int or uint)
+; numeric: modes must be both numeric
+
+(define (mode-compatible? how mode1 mode2)
+ (let ((m1 (mode:lookup mode1))
+ (m2 (mode:lookup mode2)))
+ (case how
+ ((strict)
+ (eq? (obj:name m1) (obj:name m2)))
+ ((samesize)
+ (cond ((mode-integral? m1)
+ (and (mode-integral? m2)
+ (= (mode:bits m1) (mode:bits m2))))
+ ((mode-float? m1)
+ (and (mode-float? m2)
+ (= (mode:bits m1) (mode:bits m2))))
+ (else #f)))
+ ((sameclass)
+ (cond ((mode-integral? m1) (mode-integral? m2))
+ ((mode-float? m1) (mode-float? m2))
+ (else #f)))
+ ((numeric)
+ (and (mode-numeric? m1) (mode-numeric? m2)))
+ (else (error "bad `how' arg to mode-compatible?" how))))
+)
+
+; Add MODE named NAME to the list of recognized modes.
+; If NAME is already present, replace it with MODE.
+; MODE is a mode object.
+; NAME exists to allow aliases of modes [e.g. WI, UWI, AI].
+;
+; No attempt to preserve any particular order of entries is done here.
+; That is up to the caller.
+
+(define (mode:add! name mode)
+ (let ((entry (assq name mode-list)))
+ (if entry
+ (set-cdr! entry mode)
+ (set! mode-list (acons name mode mode-list)))
+ mode)
+)
+
+; Parse a mode.
+; This is the main routine for building a mode object.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-mode-parse errtxt name comment attrs class bits bytes
+ non-mode-c-type printf-type sem-mode ptr-to host?)
+ (logit 2 "Processing mode " name " ...\n")
+ (let* ((name (parse-name name errtxt))
+ (errtxt (string-append errtxt " " name))
+ (result (make <mode>
+ name
+ (parse-comment comment errtxt)
+ (atlist-parse attrs "mode" errtxt)
+ class bits bytes non-mode-c-type printf-type
+ sem-mode ptr-to host?)))
+ result)
+)
+
+; ??? At present there is no define-mode that takes an associative list
+; of arguments.
+
+; Define a mode object, all arguments specified.
+
+(define (define-full-mode name comment attrs class bits bytes
+ non-mode-c-type printf-type sem-mode ptr-to host?)
+ (let ((m (-mode-parse "define-full-mode" name comment attrs
+ class bits bytes
+ non-mode-c-type printf-type sem-mode ptr-to host?)))
+ ; Add it to the list of insn modes.
+ (mode:add! name m)
+ m)
+)
+
+; Lookup the mode named X.
+; Return the found object or #f.
+; If X is already a mode object, return that.
+
+(define (mode:lookup x)
+ (if (mode? x)
+ x
+ (let ((result (assq x mode-list)))
+ (if result
+ (cdr result)
+ #f)))
+)
+
+; Return a boolean indicating if X is a valid mode name.
+
+(define (mode-name? x)
+ (and (symbol? x)
+ ; FIXME: Time to make `mode-list' a hash table.
+ (->bool (assq x mode-list)))
+)
+
+; Return the name of the real mode of M.
+; This is a no-op unless M is an alias in which case we return the
+; real mode of the alias.
+
+(define (mode-real-name m)
+ (obj:name (mode:lookup m))
+)
+
+; Return the real mode of M.
+; This is a no-op unless M is an alias in which case we return the
+; real mode of the alias.
+
+(define (mode-real-mode m)
+ (mode:lookup (mode-real-name m))
+)
+
+; Return #t if mode M1-NAME is bigger than mode M2-NAME.
+
+(define (mode-bigger? m1-name m2-name)
+ (> (mode:bits (mode:lookup m1-name))
+ (mode:bits (mode:lookup m2-name)))
+)
+
+; Return a mode in mode class CLASS wide enough to hold BITS.
+
+(define (mode-find bits class)
+ (let ((modes (find (lambda (mode) (eq? (mode:class (cdr mode)) class))
+ mode-list)))
+ (if (null? modes)
+ (error "invalid mode class" class))
+ (let loop ((modes modes))
+ (cond ((null? modes) (error "no modes for bits" bits))
+ ((<= bits (mode:bits (cdar modes))) (cdar modes))
+ (else (loop (cdr modes))))))
+)
+
+; Parse MODE-NAME and return the mode object.
+; An error is signalled if MODE isn't valid.
+
+(define (parse-mode-name mode-name errtxt)
+ (let ((m (mode:lookup mode-name)))
+ (if (not m) (parse-error errtxt "not a valid mode" mode-name))
+ m)
+)
+
+; Make a new INT/UINT mode.
+; These have a variable number of bits (1-32).
+
+(define (mode-make-int bits)
+ (if (or (<= bits 0) (> bits 64))
+ (error "unsupported number of bits" bits))
+ (let ((result (object-copy-top INT)))
+ (elm-xset! result 'bits bits)
+ (elm-xset! result 'bytes (bits->bytes bits))
+ result)
+)
+
+(define (mode-make-uint bits)
+ (if (or (<= bits 0) (> bits 64))
+ (error "unsupported number of bits" bits))
+ (let ((result (object-copy-top UINT)))
+ (elm-xset! result 'bits bits)
+ (elm-xset! result 'bytes (bits->bytes bits))
+ result)
+)
+
+; Initialization.
+
+; Some modes are refered to by the Scheme code.
+; These have global bindings, but we try not to make this the general rule.
+; [Actually I don't think this is all that bad, but it seems reasonable to
+; not create global bindings that we don't have to.]
+
+(define VOID #f)
+(define DFLT #f)
+
+; This is defined by the target. We provide a default def'n.
+(define WI #f)
+(define UWI #f)
+
+; An "address int". This is recorded in addition to a "word int" because it
+; is believed that some target will need it. It also stays consistent with
+; what BFD does.
+; This can also be defined by the target. We provide a default.
+(define AI #f)
+(define IAI #f)
+
+; Variable sized portable ints.
+(define INT #f)
+(define UINT #f)
+
+(define (mode-init!)
+ (set! mode-list nil)
+
+ (reader-add-command! 'define-full-mode
+ "\
+Define a mode, all arguments specified.
+"
+ nil '(name commment attrs class bits bytes
+ non-c-mode-type printf-type sem-mode ptr-to host?)
+ define-full-mode)
+
+ *UNSPECIFIED*
+)
+
+; Called before a . cpu file is read in to install any builtins.
+
+(define (mode-builtin!)
+ ; FN-SUPPORT: In sem-ops.h file, include prototypes as well as macros.
+ ; Elsewhere, functions are defined to perform the operation.
+ (define-attr '(for mode) '(type boolean) '(name FN-SUPPORT))
+
+ (let ((dfm define-full-mode))
+ ; This list must be defined in order of increasing size among each type.
+
+ (dfm 'VOID "void" '() 'RANDOM 0 0 "void" "" #f #f #f) ; VOIDmode
+
+ ; Special marker to indicate "use the default mode".
+ ; ??? Not yet used everywhere it should be.
+ (dfm 'DFLT "default mode" '() 'RANDOM 0 0 "" "" #f #f #f)
+
+ ; Not UINT on purpose.
+ (dfm 'BI "one bit (0,1 not 0,-1)" '() 'INT 1 1 "int" "'x'" #f #f #f)
+
+ (dfm 'QI "8 bit byte" '() 'INT 8 1 "int" "'x'" #f #f #f)
+ (dfm 'HI "16 bit int" '() 'INT 16 2 "int" "'x'" #f #f #f)
+ (dfm 'SI "32 bit int" '() 'INT 32 4 "int" "'x'" #f #f #f)
+ (dfm 'DI "64 bit int" '(FN-SUPPORT) 'INT 64 8 "" "'D'" #f #f #f)
+
+ (dfm 'UQI "8 bit unsigned byte" '() 'UINT
+ 8 1 "unsigned int" "'x'" (mode:lookup 'QI) #f #f)
+ (dfm 'UHI "16 bit unsigned int" '() 'UINT
+ 16 2 "unsigned int" "'x'" (mode:lookup 'HI) #f #f)
+ (dfm 'USI "32 bit unsigned int" '() 'UINT
+ 32 4 "unsigned int" "'x'" (mode:lookup 'SI) #f #f)
+ (dfm 'UDI "64 bit unsigned int" '(FN-SUPPORT) 'UINT
+ 64 8 "" "'D'" (mode:lookup 'DI) #f #f)
+
+ ; Floating point values.
+ (dfm 'SF "32 bit float" '(FN-SUPPORT) 'FLOAT
+ 32 4 "" "'f'" #f #f #f)
+ (dfm 'DF "64 bit float" '(FN-SUPPORT) 'FLOAT
+ 64 8 "" "'f'" #f #f #f)
+ (dfm 'XF "80/96 bit float" '(FN-SUPPORT) 'FLOAT
+ 96 12 "" "'F'" #f #f #f)
+ (dfm 'TF "128 bit float" '(FN-SUPPORT) 'FLOAT
+ 128 16 "" "'F'" #f #f #f)
+
+ ; These are useful modes that represent host values.
+ ; For INT/UINT the sizes indicate maximum portable values.
+ ; These are also used for random width hardware elements (e.g. immediates
+ ; and registers).
+ ; FIXME: Can't be used to represent both host and target values.
+ ; Either remove the distinction or add new modes with the distinction.
+ (dfm 'INT "portable int" '() 'INT 32 4 "int" "'x'"
+ (mode:lookup 'SI) #f #t)
+ (dfm 'UINT "portable unsigned int" '() 'UINT 32 4 "unsigned int" "'x'"
+ (mode:lookup 'SI) #f #t)
+
+ ; ??? Experimental.
+ (dfm 'PTR "host pointer" '() 'RANDOM 0 0 "PTR" "'x'"
+ #f (mode:lookup 'VOID) #t)
+ )
+
+ (set! VOID (mode:lookup 'VOID))
+ (set! DFLT (mode:lookup 'DFLT))
+
+ (set! INT (mode:lookup 'INT))
+ (set! UINT (mode:lookup 'UINT))
+
+ ; To redefine these, use mode:add! again.
+ (set! WI (mode:add! 'WI (mode:lookup 'SI)))
+ (set! UWI (mode:add! 'UWI (mode:lookup 'USI)))
+ (set! AI (mode:add! 'AI (mode:lookup 'USI)))
+ (set! IAI (mode:add! 'IAI (mode:lookup 'USI)))
+
+ *UNSPECIFIED*
+)
+
+(define (mode-finish!)
+ ; Keep the fields sorted for mode-find.
+ (set! mode-list (reverse mode-list))
+
+ (if #f
+ ; ???: Something like this would be nice if it was timed appropriately
+ ; redefine WI/UWI/AI/IAI for this target
+ (case (cpu-word-bitsize (current-cpu))
+ ((32) (begin
+ (display "Recognized 32-bit cpu.\n")))
+ ((64) (begin
+ (display "Recognized 64-bit cpu.\n")
+ (set! WI (mode:add! 'WI (mode:lookup 'DI)))
+ (set! UWI (mode:add! 'UWI (mode:lookup 'UDI)))
+ (set! AI (mode:add! 'AI (mode:lookup 'UDI)))
+ (set! IAI (mode:add! 'IAI (mode:lookup 'UDI)))))
+ (else (error "Unknown word-bitsize for WI/UWI/AI/IAI mode!"))))
+
+ *UNSPECIFIED*
+)
diff --git a/cgen/model.scm b/cgen/model.scm
new file mode 100644
index 00000000000..f57ca557d92
--- /dev/null
+++ b/cgen/model.scm
@@ -0,0 +1,304 @@
+; CPU implementation description.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; A model is an implementation of a mach.
+; NOTE: wip [with all the caveats that implies].
+; The intent here is to define the aspects of a CPU that affect performance,
+; usable by any tool (but for the immediate future a simulator).
+
+; Pipeline specification.
+
+(define <pipeline>
+ (class-make '<pipeline> nil '(name comment atlist elms) nil))
+
+(define (pipeline:length p) (length (elm-xget p 'elms)))
+
+; Function unit specification.
+
+; FIXME: Might wish to record which pipeline element(s) the unit is associated
+; with. At the moment pipeline data isn't used, but later.
+
+(define <unit>
+ (class-make '<unit>
+ '(<ident>)
+ '(
+ ; wip
+ issue done
+ ; Lists of (name mode) pairs that record unit state.
+ state
+ ; Lists of (name mode [default-value]).
+ inputs outputs
+ ; RTL of code to invoke to do profiling.
+ ; `nil' means use the default
+ ; ??? Not currently used since all profiling handlers
+ ; are user-written.
+ profile
+ ; Model this unit is associated with.
+ model-name
+ )
+ nil))
+
+; ??? Rather than create a circularity, we record the model's symbol in
+; the `model' element.
+; FIXME: Shouldn't use current-model-lookup. Guile is better at printing
+; things with circularities now, so should probably put back the circularity
+; and delete the current-model-lookup reference.
+(define (unit:model u) (current-model-lookup (elm-xget u 'model-name)))
+(define unit:issue (elm-make-getter <unit> 'issue))
+(define unit:done (elm-make-getter <unit> 'done))
+(define unit:state (elm-make-getter <unit> 'state))
+(define unit:inputs (elm-make-getter <unit> 'inputs))
+(define unit:outputs (elm-make-getter <unit> 'outputs))
+(define unit:profile (elm-make-getter <unit> 'profile))
+
+; Create a copy of unit U with new values for ISSUE and DONE.
+; This is used when recording an instruction's timing information.
+; ??? This might be better recorded in a different class from UNIT
+; since we're not creating a new unit, we're just special casing it for
+; one instruction.
+; FIXME: No longer used.
+
+(define (unit:make-insn-timing u issue done)
+ (let ((result (object-copy-top u)))
+ (elm-xset! result 'issue issue)
+ (elm-xset! result 'done done)
+ result)
+)
+
+(define (unit:enum u)
+ (gen-c-symbol (string-append "UNIT_"
+ (string-upcase (obj:name (unit:model u)))
+ "_"
+ (string-upcase (obj:name u))))
+)
+
+; The `<model>' class.
+;
+; FETCH is the instruction fetch process as it relates to the implementation.
+; e.g.
+; - how many instructions are fetched at once
+; - how those instructions are initially processed for delivery to the
+; appropriate pipeline
+; RETIRE is used to specify any final processing needed to complete an insn.
+; PIPELINES is a list of pipeline objects.
+; UNITS is a list of function units.
+; STATE is a list of (var mode) pairs.
+;
+; For the more complicated cpus this can get really complicated really fast.
+; No intent is made to get there in one day.
+
+(define <model>
+ (class-make '<model>
+ '(<ident>)
+ '(mach prefetch retire pipelines state units)
+ nil))
+
+(define model:mach (elm-make-getter <model> 'mach))
+(define model:prefetch (elm-make-getter <model> 'prefetch))
+(define model:retire (elm-make-getter <model> 'retire))
+(define model:pipelines (elm-make-getter <model> 'pipelines))
+(define model:state (elm-make-getter <model> 'state))
+(define model:units (elm-make-getter <model> 'units))
+
+(define (model:enum m)
+ (gen-c-symbol (string-append "MODEL_" (string-upcase (obj:name m))))
+)
+
+; Parse a `prefetch' spec.
+
+(define (-prefetch-parse errtxt expr)
+ nil
+)
+
+; Parse a `retire' spec.
+
+(define (-retire-parse errtxt expr)
+ nil
+)
+
+; Parse a `pipeline' spec.
+; ??? Perhaps we should also use name/value pairs here, but that's an
+; unnecessary complication at this point in time.
+
+(define (-pipeline-parse errtxt model-name spec) ; name comments attrs elements)
+ (if (not (= (length spec) 4))
+ (parse-error errtxt "pipeline spec not `name comment attrs elements'" spec))
+ (apply make (cons <pipeline> spec))
+)
+
+; Parse a function `unit' spec.
+; ??? Perhaps we should also use name/value pairs here, but that's an
+; unnecessary complication at this point in time.
+
+(define (-unit-parse errtxt model-name spec) ; name comments attrs elements)
+ (if (not (= (length spec) 9))
+ (parse-error errtxt "unit spec not `name comment attrs issue done state inputs outputs profile'" spec))
+ (apply make (append (cons <unit> spec) (list model-name)))
+)
+
+; Parse a model definition.
+; This is the main routine for building a model object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+
+(define (-model-parse errtxt name comment attrs mach-name prefetch retire pipelines state units)
+ (logit 2 "Processing model " name " ...\n")
+ (let ((name (parse-name name errtxt))
+ ; FIXME: switch to `context' like in cver.
+ (errtxt (string-append errtxt " " name))
+ (mach (current-mach-lookup mach-name)))
+ (if (null? units)
+ (parse-error errtxt "there must be at least one function unit" name))
+ (if mach ; is `mach' being "kept"?
+ (let ((model-obj
+ (make <model>
+ name
+ (parse-comment comment errtxt)
+ (atlist-parse attrs "cpu" errtxt)
+ mach
+ (-prefetch-parse errtxt prefetch)
+ (-retire-parse errtxt retire)
+ (map (lambda (p) (-pipeline-parse errtxt name p)) pipelines)
+ state
+ (map (lambda (u) (-unit-parse errtxt name u)) units))))
+ model-obj)
+ (begin
+ ; MACH wasn't found, ignore this model.
+ (logit 2 "Nonexistant mach " mach-name ", ignoring " name ".\n")
+ #f)))
+)
+
+; Read a model description.
+; This is the main routine for analyzing models in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -model-parse is invoked to create the `model' object.
+
+(define (-model-read errtxt . arg-list)
+ (let (; Current mach elements:
+ (name nil) ; name of model
+ (comment nil) ; description of model
+ (attrs nil) ; attributes
+ (mach nil) ; mach this model implements
+ (prefetch nil) ; instruction prefetch handling
+ (retire nil) ; instruction completion handling
+ (pipelines nil) ; list of pipelines
+ (state nil) ; list of (name mode) pairs to record state
+ (units nil) ; list of function units
+ )
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((mach) (set! mach (cadr arg)))
+ ((prefetch) (set! prefetch (cadr arg)))
+ ((retire) (set! retire (cadr arg)))
+ ((pipeline) (set! pipelines (cons (cdr arg) pipelines)))
+ ((state) (set! state (cdr arg)))
+ ((unit) (set! units (cons (cdr arg) units)))
+ (else (parse-error errtxt "invalid model arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-model-parse errtxt name comment attrs mach prefetch retire pipelines state units)
+ )
+)
+
+; Define a cpu model object, name/value pair list version.
+
+(define define-model
+ (lambda arg-list
+ (let ((m (apply -model-read (cons "define-model" arg-list))))
+ (if m
+ (current-model-add! m))
+ m))
+)
+
+; Instruction timing.
+
+; There is one of these for each model timing description per instruction.
+
+(define <timing> (class-make '<timing> nil '(model units) nil))
+
+(define timing:model (elm-make-getter <timing> 'model))
+(define timing:units (elm-make-getter <timing> 'units))
+
+; timing:units is a list of these.
+; ARGS is a list of (name value) pairs.
+
+(define <iunit> (class-make '<iunit> nil '(unit args) nil))
+
+(define iunit:unit (elm-make-getter <iunit> 'unit))
+(define iunit:args (elm-make-getter <iunit> 'args))
+
+; Return the default unit used by MODEL.
+; ??? For now this is always u-exec.
+
+(define (model-default-unit model)
+ (object-assq 'u-exec (model:units model))
+)
+
+; Subroutine of parse-insn-timing to parse the timing spec for MODEL.
+; The result is a <timing> object.
+
+(define (-insn-timing-parse-model context model spec)
+ (make <timing> model
+ (map (lambda (unit-timing-desc)
+ (let ((type (car unit-timing-desc))
+ (args (cdr unit-timing-desc)))
+ (case type
+ ((unit) ; syntax is `unit name (arg1 val1) ...'
+ (let ((unit (object-assq (car args)
+ (model:units model))))
+ (if (not unit)
+ (parse-error context "unknown function unit" args))
+ (make <iunit> unit (cdr args))))
+ (else (parse-error context "bad unit timing spec"
+ unit-timing-desc)))))
+ spec))
+)
+
+; Given the timing information for an instruction return an associative
+; list of timing objects (one for each specified model).
+; INSN-TIMING-DESC is a list of
+; (model1 (unit unit1-name ...) ...) (model2 (unit unit1-name ...) ...) ...
+; Entries for models not included (because the machine wasn't selected)
+; are returned as (model1), i.e. an empty unit list.
+
+(define (parse-insn-timing context insn-timing-desc)
+ (map (lambda (model-timing-desc)
+ (let* ((model-name (car model-timing-desc))
+ (model (current-model-lookup model-name)))
+ (cons model-name
+ (if model
+ (-insn-timing-parse-model context model
+ (cdr model-timing-desc))
+ ()))))
+ insn-timing-desc)
+)
+
+; Called before a .cpu file is read in.
+
+(define (model-init!)
+
+ (reader-add-command! 'define-model
+ "\
+Define a cpu model, name/value pair list version.
+"
+ nil 'arg-list define-model
+ )
+
+ *UNSPECIFIED*
+)
+
+; Called after a .cpu file has been read in.
+
+(define (model-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/opc-asmdis.scm b/cgen/opc-asmdis.scm
new file mode 100644
index 00000000000..d3a441ce0d8
--- /dev/null
+++ b/cgen/opc-asmdis.scm
@@ -0,0 +1,182 @@
+; Assembler/disassembler support generator.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Assembler support.
+
+(define (-gen-parse-switch)
+ (logit 2 "Generating parse switch ...\n")
+ (string-list
+ "\
+/* Main entry point for operand parsing.
+
+ This function is basically just a big switch statement. Earlier versions
+ used tables to look up the function to use, but
+ - if the table contains both assembler and disassembler functions then
+ the disassembler contains much of the assembler and vice-versa,
+ - there's a lot of inlining possibilities as things grow,
+ - using a switch statement avoids the function call overhead.
+
+ This function could be moved into `parse_insn_normal', but keeping it
+ separate makes clear the interface between `parse_insn_normal' and each of
+ the handlers.
+*/
+
+const char *
+@arch@_cgen_parse_operand (cd, opindex, strp, fields)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ const char ** strp;
+ CGEN_FIELDS * fields;
+{
+ const char * errmsg = NULL;
+ /* Used by scalar operands that still need to be parsed. */
+ " (gen-ifield-default-type) " junk;
+
+ switch (opindex)
+ {
+"
+ (gen-switch 'parse)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while parsing.\\n\"), opindex);
+ abort ();
+ }
+
+ return errmsg;
+}\n\n")
+)
+
+; Assembler initialization C code
+; Code is appended during processing.
+
+(define -asm-init-code "")
+(define (add-asm-init code)
+ (set! -asm-init-code (string-append -asm-init-code code))
+)
+
+; Return C code to define the assembler init function.
+; This is called after opcode_open.
+
+(define (-gen-init-asm-fn)
+ (string-append
+ "\
+void
+@arch@_cgen_init_asm (cd)
+ CGEN_CPU_DESC cd;
+{
+ @arch@_cgen_init_opcode_table (cd);
+ @arch@_cgen_init_ibld_table (cd);
+ cd->parse_handlers = & @arch@_cgen_parse_handlers[0];
+ cd->parse_operand = @arch@_cgen_parse_operand;
+"
+ -asm-init-code
+"}\n\n"
+ )
+)
+
+; Generate C code that is inserted into the assembler source.
+
+(define (cgen-asm.in)
+ (logit 1 "Generating " (current-arch-name) "-asm.in ...\n")
+ (string-write
+ ; No need for copyright, appended to file with one.
+ "\n"
+ (lambda () (gen-extra-asm.c srcdir (current-arch-name))) ; from <arch>.opc
+ "\n"
+ -gen-parse-switch
+ (lambda () (gen-handler-table "parse" opc-parse-handlers))
+ -gen-init-asm-fn
+ )
+)
+
+; Disassembler support.
+
+(define (-gen-print-switch)
+ (logit 2 "Generating print switch ...\n")
+ (string-list
+ "\
+/* Main entry point for printing operands.
+ XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
+ of dis-asm.h on cgen.h.
+
+ This function is basically just a big switch statement. Earlier versions
+ used tables to look up the function to use, but
+ - if the table contains both assembler and disassembler functions then
+ the disassembler contains much of the assembler and vice-versa,
+ - there's a lot of inlining possibilities as things grow,
+ - using a switch statement avoids the function call overhead.
+
+ This function could be moved into `print_insn_normal', but keeping it
+ separate makes clear the interface between `print_insn_normal' and each of
+ the handlers.
+*/
+
+void
+@arch@_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ PTR xinfo;
+ CGEN_FIELDS *fields;
+ void const *attrs;
+ bfd_vma pc;
+ int length;
+{
+ disassemble_info *info = (disassemble_info *) xinfo;
+
+ switch (opindex)
+ {
+"
+ (gen-switch 'print)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while printing insn.\\n\"),
+ opindex);
+ abort ();
+ }
+}\n\n")
+)
+
+; Disassembler initialization C code.
+; Code is appended during processing.
+
+(define -dis-init-code "")
+(define (add-dis-init code)
+ (set! -dis-init-code (string-append -dis-init-code code))
+)
+
+; Return C code to define the disassembler init function.
+
+(define (-gen-init-dis-fn)
+ (string-append
+ "
+void
+@arch@_cgen_init_dis (cd)
+ CGEN_CPU_DESC cd;
+{
+ @arch@_cgen_init_opcode_table (cd);
+ @arch@_cgen_init_ibld_table (cd);
+ cd->print_handlers = & @arch@_cgen_print_handlers[0];
+ cd->print_operand = @arch@_cgen_print_operand;
+"
+ -dis-init-code
+"}\n\n"
+ )
+)
+
+; Generate C code that is inserted into the disassembler source.
+
+(define (cgen-dis.in)
+ (logit 1 "Generating " (current-arch-name) "-dis.in ...\n")
+ (string-write
+ ; No need for copyright, appended to file with one.
+ "\n"
+ (lambda () (gen-extra-dis.c srcdir (current-arch-name))) ; from <arch>.opc
+ "\n"
+ -gen-print-switch
+ (lambda () (gen-handler-table "print" opc-print-handlers))
+ -gen-init-dis-fn
+ )
+)
diff --git a/cgen/opc-ibld.scm b/cgen/opc-ibld.scm
new file mode 100644
index 00000000000..0795187e90a
--- /dev/null
+++ b/cgen/opc-ibld.scm
@@ -0,0 +1,319 @@
+; Instruction builder support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Instruction field support.
+
+(define (-gen-fget-switch)
+ (logit 2 "Generating field get switch ...\n")
+ (string-list
+ "\
+/* Getting values from cgen_fields is handled by a collection of functions.
+ They are distinguished by the type of the VALUE argument they return.
+ TODO: floating point, inlining support, remove cases where result type
+ not appropriate. */
+
+int
+@arch@_cgen_get_int_operand (cd, opindex, fields)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ const CGEN_FIELDS * fields;
+{
+ int value;
+
+ switch (opindex)
+ {
+"
+ (gen-switch 'fget)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while getting int operand.\\n\"),
+ opindex);
+ abort ();
+ }
+
+ return value;
+}
+
+bfd_vma
+@arch@_cgen_get_vma_operand (cd, opindex, fields)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ const CGEN_FIELDS * fields;
+{
+ bfd_vma value;
+
+ switch (opindex)
+ {
+"
+ (gen-switch 'fget)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while getting vma operand.\\n\"),
+ opindex);
+ abort ();
+ }
+
+ return value;
+}
+\n")
+)
+
+(define (-gen-fset-switch)
+ (logit 2 "Generating field set switch ...\n")
+ (string-list
+ "\
+/* Stuffing values in cgen_fields is handled by a collection of functions.
+ They are distinguished by the type of the VALUE argument they accept.
+ TODO: floating point, inlining support, remove cases where argument type
+ not appropriate. */
+
+void
+@arch@_cgen_set_int_operand (cd, opindex, fields, value)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ CGEN_FIELDS * fields;
+ int value;
+{
+ switch (opindex)
+ {
+"
+ (gen-switch 'fset)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while setting int operand.\\n\"),
+ opindex);
+ abort ();
+ }
+}
+
+void
+@arch@_cgen_set_vma_operand (cd, opindex, fields, value)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ CGEN_FIELDS * fields;
+ bfd_vma value;
+{
+ switch (opindex)
+ {
+"
+ (gen-switch 'fset)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while setting vma operand.\\n\"),
+ opindex);
+ abort ();
+ }
+}
+\n")
+)
+
+; Utilities of cgen-ibld.h.
+
+; Return a list of operands the assembler syntax uses.
+; This is a subset of the fields of the insn.
+
+(define (ifmt-opcode-operands ifmt)
+ (map ifld-get-value
+ (find (lambda (elm) (not (number? (ifld-get-value elm))))
+ (ifmt-ifields ifmt)))
+)
+
+; Subroutine of gen-insn-builders to generate the builder for one insn.
+; FIXME: wip.
+
+(define (gen-insn-builder insn)
+ (let* ((ifmt (insn-ifmt insn))
+ (operands (ifmt-opcode-operands ifmt))
+ (length (ifmt-length ifmt)))
+ (gen-obj-sanitize
+ insn
+ (string-append
+ "#define @ARCH@_IBLD_"
+ (string-upcase (gen-sym insn))
+ "(endian, buf, lenp"
+ (gen-c-args (map obj:name operands))
+ ")\n"
+ "\n")))
+)
+
+(define (gen-insn-builders)
+ (string-write
+ "\
+/* For each insn there is an @ARCH@_IBLD_<NAME> macro that builds the
+ instruction in the supplied buffer. For architectures where it's
+ possible to represent all machine codes as host integer values it
+ would be nicer to have these return the instruction rather than store
+ it in BUF. For consistency with variable length ISA's this does not. */
+
+"
+ (lambda () (string-write-map gen-insn-builder (current-insn-list)))
+ )
+)
+
+; Generate the C code for dealing with operands.
+
+(define (-gen-insert-switch)
+ (logit 2 "Generating insert switch ...\n")
+ (string-list
+ "\
+/* Main entry point for operand insertion.
+
+ This function is basically just a big switch statement. Earlier versions
+ used tables to look up the function to use, but
+ - if the table contains both assembler and disassembler functions then
+ the disassembler contains much of the assembler and vice-versa,
+ - there's a lot of inlining possibilities as things grow,
+ - using a switch statement avoids the function call overhead.
+
+ This function could be moved into `parse_insn_normal', but keeping it
+ separate makes clear the interface between `parse_insn_normal' and each of
+ the handlers. It's also needed by GAS to insert operands that couldn't be
+ resolved during parsing.
+*/
+
+const char *
+@arch@_cgen_insert_operand (cd, opindex, fields, buffer, pc)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ CGEN_FIELDS * fields;
+ CGEN_INSN_BYTES_PTR buffer;
+ bfd_vma pc;
+{
+ const char * errmsg = NULL;
+ unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
+
+ switch (opindex)
+ {
+"
+ (gen-switch 'insert)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while building insn.\\n\"),
+ opindex);
+ abort ();
+ }
+
+ return errmsg;
+}\n\n")
+)
+
+(define (-gen-extract-switch)
+ (logit 2 "Generating extract switch ...\n")
+ (string-list
+ "\
+/* Main entry point for operand extraction.
+ The result is <= 0 for error, >0 for success.
+ ??? Actual values aren't well defined right now.
+
+ This function is basically just a big switch statement. Earlier versions
+ used tables to look up the function to use, but
+ - if the table contains both assembler and disassembler functions then
+ the disassembler contains much of the assembler and vice-versa,
+ - there's a lot of inlining possibilities as things grow,
+ - using a switch statement avoids the function call overhead.
+
+ This function could be moved into `print_insn_normal', but keeping it
+ separate makes clear the interface between `print_insn_normal' and each of
+ the handlers.
+*/
+
+int
+@arch@_cgen_extract_operand (cd, opindex, ex_info, insn_value, fields, pc)
+ CGEN_CPU_DESC cd;
+ int opindex;
+ CGEN_EXTRACT_INFO *ex_info;
+ CGEN_INSN_INT insn_value;
+ CGEN_FIELDS * fields;
+ bfd_vma pc;
+{
+ /* Assume success (for those operands that are nops). */
+ int length = 1;
+ unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
+
+ switch (opindex)
+ {
+"
+ (gen-switch 'extract)
+"
+ default :
+ /* xgettext:c-format */
+ fprintf (stderr, _(\"Unrecognized field %d while decoding insn.\\n\"),
+ opindex);
+ abort ();
+ }
+
+ return length;
+}\n\n")
+)
+
+; Utilities of cgen-ibld.in.
+
+; Emit a function to call to initialize the ibld tables.
+
+(define (-gen-ibld-init-fn)
+ (string-write
+ "\
+/* Function to call before using the instruction builder tables. */
+
+void
+@arch@_cgen_init_ibld_table (cd)
+ CGEN_CPU_DESC cd;
+{
+ cd->insert_handlers = & @arch@_cgen_insert_handlers[0];
+ cd->extract_handlers = & @arch@_cgen_extract_handlers[0];
+
+ cd->insert_operand = @arch@_cgen_insert_operand;
+ cd->extract_operand = @arch@_cgen_extract_operand;
+
+ cd->get_int_operand = @arch@_cgen_get_int_operand;
+ cd->set_int_operand = @arch@_cgen_set_int_operand;
+ cd->get_vma_operand = @arch@_cgen_get_vma_operand;
+ cd->set_vma_operand = @arch@_cgen_set_vma_operand;
+}
+"
+ )
+)
+
+; Generate the C header for building instructions.
+
+(define (cgen-ibld.h)
+ (logit 1 "Generating " (current-arch-name) "-ibld.h ...\n")
+ (string-write
+ (gen-copyright "Instruction builder for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#ifndef @ARCH@_IBLD_H
+#define @ARCH@_IBLD_H
+
+"
+ (lambda () (gen-extra-ibld.h srcdir (current-arch-name))) ; from <arch>.opc
+ "\n"
+ gen-insn-builders
+ "
+#endif /* @ARCH@_IBLD_H */
+"
+ )
+)
+
+; Generate the C support for building instructions.
+
+(define (cgen-ibld.in)
+ (logit 1 "Generating " (current-arch-name) "-ibld.in ...\n")
+ (string-write
+ ; No need for copyright, appended to file with one.
+ "\n"
+ -gen-insert-switch
+ -gen-extract-switch
+ (lambda () (gen-handler-table "insert" opc-insert-handlers))
+ (lambda () (gen-handler-table "extract" opc-extract-handlers))
+ -gen-fget-switch
+ -gen-fset-switch
+ -gen-ibld-init-fn
+ )
+)
diff --git a/cgen/opc-itab.scm b/cgen/opc-itab.scm
new file mode 100644
index 00000000000..830b7e0083e
--- /dev/null
+++ b/cgen/opc-itab.scm
@@ -0,0 +1,724 @@
+; Opcode table support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Append code here to be run before insn parsing/etc.
+; These are for internal use and aren't intended to appear in .cpu files.
+; ??? Nothing currently uses them but that might change.
+
+(define parse-init-code "")
+(define insert-init-code "")
+(define extract-init-code "")
+(define print-init-code "")
+
+; Define CGEN_INIT_{PARSE,INSERT,EXTRACT,PRINT} macros.
+; ??? These were early escape hatches. Not currently used.
+
+(define (-gen-init-macros)
+ (logit 2 "Generating init macros ...\n")
+ (string-append
+ "#define CGEN_INIT_PARSE(od) \\
+{\\\n"
+ parse-init-code
+ "}\n"
+ "#define CGEN_INIT_INSERT(od) \\
+{\\\n"
+ insert-init-code
+ "}\n"
+ "#define CGEN_INIT_EXTRACT(od) \\
+{\\\n"
+ extract-init-code
+ "}\n"
+ "#define CGEN_INIT_PRINT(od) \\
+{\\\n"
+ print-init-code
+ "}\n"
+ )
+)
+
+; Instruction field support.
+
+; Return C code to declare various ifield types,decls.
+
+(define (-gen-ifield-decls)
+ (logit 2 "Generating instruction field decls ...\n")
+ (string-append
+ "/* This struct records data prior to insertion or after extraction. */\n"
+ "struct cgen_fields\n{\n"
+ ; A special member `length' is used to record the length.
+ " int length;\n"
+ (string-map gen-ifield-value-decl (non-derived-ifields (current-ifld-list)))
+ "};\n\n"
+ )
+)
+
+; Instruction syntax support.
+
+; Extract the operand fields in SYNTAX-STRING.
+; The result is a list of operand names.
+; ??? Not currently used, but keep awhile.
+
+(define (extract-syntax-operands syntax)
+ (let loop ((syn syntax) (result nil))
+
+ (cond ((= (string-length syn) 0)
+ (reverse! result))
+
+ ((char=? #\\ (string-ref syn 0))
+ (if (= (string-length syn) 1)
+ (error "missing char after '\\'" syntax))
+ (loop (string-drop 2 syn) result))
+
+ ((char=? #\$ (string-ref syn 0))
+ ; Extract the symbol from the string, which will be the name of
+ ; an operand. Append it to the result.
+ (if (= (string-length syn) 1)
+ (error "missing operand name" syntax))
+ (if (char=? (string-ref syn 1) #\{)
+ (let ((n (chars-until-delimiter syn #\})))
+ ; Note that 'n' includes the leading ${.
+ (case n
+ ((0) (error "empty operand name" syntax))
+ ((#f) (error "missing '}'" syntax))
+ (else (loop (string-drop (+ n 1) syn)
+ (cons (string->symbol (substring syn 2 n))
+ result)))))
+ (let ((n (id-len (string-drop1 syn))))
+ (if (= n 0)
+ (error "empty or invalid operand name" syntax))
+ (loop (string-drop (1+ n) syn)
+ (cons (string->symbol (substring syn 1 (1+ n)))
+ result)))))
+
+ (else (loop (string-drop1 syn) result))))
+)
+
+; Strip the mnemonic part from SYNTAX.
+; (ie: everything up to but not including the first space or '$')
+; If STRIP-MNEM-OPERANDS?, strip them too.
+
+(define (strip-mnemonic strip-mnem-operands? syntax)
+ (let ((space (string-index syntax #\space)))
+ (if strip-mnem-operands?
+ (if space
+ (string-drop space syntax)
+ "")
+ (let loop ((syn syntax))
+ (if (= (string-length syn) 0)
+ ""
+ (case (string-ref syn 0)
+ ((#\space) syn)
+ ((#\\) (loop (string-drop 2 syn)))
+ ((#\$) syn)
+ (else (loop (string-drop1 syn))))))))
+)
+
+; Compute the sequence of syntax bytes for SYNTAX.
+; STRIP-MNEMONIC? is #t if the mnemonic part is to be stripped off.
+; STRIP-MNEM-OPERANDS? is #t if any mnemonic operands are to be stripped off.
+; SYNTAX is a string of text and operands.
+; OP-MACRO is the macro to call that computes an operand's value.
+; The resulting syntax is expressed as a sequence of bytes.
+; Values < 128 are characters that must be matched.
+; Values >= 128 are 128 + the index into the operand table.
+
+(define (compute-syntax strip-mnemonic? strip-mnem-operands? syntax op-macro)
+ (let ((context "syntax computation")
+ (syntax (if strip-mnemonic?
+ (strip-mnemonic strip-mnem-operands? syntax)
+ syntax)))
+
+ (let loop ((syn syntax) (result ""))
+
+ (cond ((= (string-length syn) 0)
+ (string-append result "0"))
+
+ ((char=? #\\ (string-ref syn 0))
+ (if (= (string-length syn) 1)
+ (parse-error context "missing char after '\\'" syntax))
+ (let ((escaped-char (string-ref syn 1))
+ (remainder (string-drop 2 syn)))
+ (if (char=? #\\ escaped-char)
+ (loop remainder (string-append result "'\\\\', "))
+ (loop remainder (string-append result "'" (string escaped-char) "', ")))))
+
+ ((char=? #\$ (string-ref syn 0))
+ ; Extract the symbol from the string, which will be the name of
+ ; an operand. Append it to the result.
+ (if (= (string-length syn) 1)
+ (parse-error context "missing operand name" syntax))
+ ; Is it $foo or ${foo}?
+ (if (char=? (string-ref syn 1) #\{)
+ (let ((n (chars-until-delimiter syn #\})))
+ ; Note that 'n' includes the leading ${.
+ ; FIXME: \} not implemented yet.
+ (case n
+ ((0) (parse-error context "empty operand name" syntax))
+ ((#f) (parse-error context "missing '}'" syntax))
+ (else (loop (string-drop (+ n 1) syn)
+ (string-append result op-macro " ("
+ (string-upcase
+ (gen-c-symbol
+ (substring syn 2 n)))
+ "), ")))))
+ (let ((n (id-len (string-drop1 syn))))
+ (loop (string-drop (1+ n) syn)
+ (string-append result op-macro " ("
+ (string-upcase
+ (gen-c-symbol
+ (substring syn 1 (1+ n))))
+ "), ")))))
+
+ ; Append the character to the result.
+ (else (loop (string-drop1 syn)
+ (string-append result
+ "'" (string-take1 syn) "', "))))))
+)
+
+; Return C code to define the syntax string for SYNTAX
+; MNEM is the C value to use to represent the instruction's mnemonic.
+; OP is the C macro to use to compute an operand's syntax value.
+
+(define (gen-syntax-entry mnem op syntax)
+ (string-append
+ "{ { "
+ mnem ", "
+ ; `mnem' is used to represent the mnemonic, so we always want to strip it
+ ; from the syntax string, regardless of the setting of `strip-mnemonic?'.
+ (compute-syntax #t #f syntax op)
+ " } }")
+)
+
+; Instruction format table support.
+
+; Return the table for IFMT, an <iformat> object.
+
+(define (-gen-ifmt-table-1 ifmt)
+ (gen-obj-sanitize
+ (ifmt-eg-insn ifmt) ; sanitize based on the example insn
+ (string-list
+ "static const CGEN_IFMT " (gen-sym ifmt) " = {\n"
+ " "
+ (number->string (ifmt-mask-length ifmt)) ", "
+ (number->string (ifmt-length ifmt)) ", "
+ "0x" (number->string (ifmt-mask ifmt) 16) ", "
+ "{ "
+ (string-list-map (lambda (ifld)
+ (string-list "{ F (" (ifld-enum ifld #f) ") }, "))
+ (ifmt-ifields ifmt))
+ "{ 0 } }\n};\n\n"))
+)
+
+; Generate the insn format table.
+
+(define (-gen-ifmt-table)
+ (string-write
+ "/* Instruction formats. */\n\n"
+ "#define F(f) & @arch@_cgen_ifld_table[CONCAT2 (@ARCH@_,f)]\n\n"
+ (string-list-map -gen-ifmt-table-1 (current-ifmt-list))
+ "#undef F\n\n"
+ )
+)
+
+; Parse/insert/extract/print handlers.
+; Each handler type is recorded in the assembler/disassembler as an array of
+; pointers to functions. The value recorded in the operand table is the index
+; into this array. The first element in the array is reserved as index 0 is
+; special (the "default").
+;
+; The handlers are recorded here as associative lists in case we ever want
+; to record more than just the name.
+;
+; Adding a new handler involves
+; - specifying its name in the .cpu file
+; - getting its name appended to these tables
+; - writing the C code
+;
+; ??? It might be useful to define the handler in Scheme. Later.
+
+(define opc-parse-handlers '((insn-normal)))
+(define opc-insert-handlers '((insn-normal)))
+(define opc-extract-handlers '((insn-normal)))
+(define opc-print-handlers '((insn-normal)))
+
+; FIXME: There currently isn't a spot for specifying special handlers for
+; each instruction. For now assume we always use the same ones.
+
+(define (insn-handlers insn)
+ (string-append
+ (number->string (lookup-index 'insn-normal opc-parse-handlers 0))
+ ", "
+ (number->string (lookup-index 'insn-normal opc-insert-handlers 0))
+ ", "
+ (number->string (lookup-index 'insn-normal opc-extract-handlers 0))
+ ", "
+ (number->string (lookup-index 'insn-normal opc-print-handlers 0))
+ )
+)
+
+; Return C code to define the cgen_opcode_handler struct for INSN.
+; This is intended to be the ultimate escape hatch for the parse/insert/
+; extract/print handlers. Each entry is an index into a table of handlers.
+; The escape hatch isn't used yet.
+
+(define (gen-insn-handlers insn)
+ (string-append
+ "{ "
+ (insn-handlers insn)
+ " }"
+ )
+)
+
+; Handler table support.
+; There are tables for each of parse/insert/extract/print.
+
+; Return C code to define the handler table for NAME with values VALUES.
+
+(define (gen-handler-table name values)
+ (string-append
+ "cgen_" name "_fn * const @arch@_cgen_" name "_handlers[] = \n{\n"
+ (string-map (lambda (elm)
+ (string-append " " name "_"
+ (gen-c-symbol (car elm))
+ ",\n"))
+ values)
+ "};\n\n"
+ )
+)
+
+; Instruction table support.
+
+; Return a declaration of an enum for all insns.
+
+(define (-gen-insn-enum)
+ (logit 2 "Generating instruction enum ...\n")
+ (string-list
+ (gen-enum-decl 'cgen_insn_type "@arch@ instruction types"
+ "@ARCH@_INSN_"
+ (cons '(invalid)
+ (append (gen-obj-list-enums (non-multi-insns (current-insn-list)))
+ '((max)))))
+ "/* Index of `invalid' insn place holder. */\n"
+ "#define CGEN_INSN_INVALID @ARCH@_INSN_INVALID\n\n"
+ "/* Total number of insns in table. */\n"
+ "#define MAX_INSNS ((int) @ARCH@_INSN_MAX)\n\n"
+ )
+)
+
+; Return a reference to the format table entry of INSN.
+
+(define (gen-ifmt-entry insn)
+ (string-append "& " (gen-sym (insn-ifmt insn)))
+)
+
+; Return the definition of an instruction value entry.
+
+(define (gen-ivalue-entry insn)
+ (string-list "{ "
+ "0x" (number->string (insn-value insn) 16)
+ (if #f ; (ifmt-opcodes-beyond-base? (insn-ifmt insn))
+ (string-list ", { "
+ ; ??? wip: opcode values beyond the base insn
+ "0 }")
+ "")
+ " }")
+)
+
+; Generate an insn opcode entry for INSN.
+; ALL-ATTRS is a list of all instruction attributes.
+; NUM-NON-BOOLS is the number of non-boolean insn attributes.
+
+(define (-gen-insn-opcode-entry insn all-attrs num-non-bools)
+ (gen-obj-sanitize
+ insn
+ (string-list
+ "/* " (insn-syntax insn) " */\n"
+ " {\n"
+ " " (gen-insn-handlers insn) ",\n"
+ " " (gen-syntax-entry "MNEM" "OP" (insn-syntax insn)) ",\n"
+ ; ??? 'twould save space to put a pointer here and record format separately
+ " " (gen-ifmt-entry insn) ", "
+ ;"0x" (number->string (insn-value insn) 16) ",\n"
+ (gen-ivalue-entry insn) "\n"
+ " },\n"))
+)
+
+; Generate insn table.
+
+(define (-gen-insn-opcode-table)
+ (logit 2 "Generating instruction opcode table ...\n")
+ (let* ((all-attrs (current-insn-attr-list))
+ (num-non-bools (attr-count-non-bools all-attrs)))
+ (string-write
+ "\
+#define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
+#define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
+#define OPERAND(op) CONCAT2 (@ARCH@_OPERAND_,op)
+#define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
+
+/* The instruction table. */
+
+static const CGEN_OPCODE @arch@_cgen_insn_opcode_table[MAX_INSNS] =
+{
+ /* Special null first entry.
+ A `num' value of zero is thus invalid.
+ Also, the special `invalid' insn resides here. */
+ { { 0, 0, 0, 0 }, {{0}}, 0, {0}},\n"
+
+ (lambda ()
+ (string-write-map (lambda (insn)
+ (logit 3 "Generating insn opcode entry for " (obj:name insn) " ...\n")
+ (-gen-insn-opcode-entry insn all-attrs
+ num-non-bools))
+ (non-multi-insns (current-insn-list))))
+
+ "\
+};
+
+#undef A
+#undef MNEM
+#undef OPERAND
+#undef OP
+
+"
+ )
+ )
+)
+
+; Return assembly/disassembly hashing support.
+
+(define (-gen-hash-fns)
+ (string-list
+ "\
+#ifndef CGEN_ASM_HASH_P
+#define CGEN_ASM_HASH_P(insn) 1
+#endif
+
+#ifndef CGEN_DIS_HASH_P
+#define CGEN_DIS_HASH_P(insn) 1
+#endif
+
+/* Return non-zero if INSN is to be added to the hash table.
+ Targets are free to override CGEN_{ASM,DIS}_HASH_P in the .opc file. */
+
+static int
+asm_hash_insn_p (insn)
+ const CGEN_INSN *insn;
+{
+ return CGEN_ASM_HASH_P (insn);
+}
+
+static int
+dis_hash_insn_p (insn)
+ const CGEN_INSN *insn;
+{
+ /* If building the hash table and the NO-DIS attribute is present,
+ ignore. */
+ if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NO_DIS))
+ return 0;
+ return CGEN_DIS_HASH_P (insn);
+}
+
+#ifndef CGEN_ASM_HASH
+#define CGEN_ASM_HASH_SIZE 127
+#ifdef CGEN_MNEMONIC_OPERANDS
+#define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE)
+#else
+#define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) /*FIXME*/
+#endif
+#endif
+
+/* It doesn't make much sense to provide a default here,
+ but while this is under development we do.
+ BUFFER is a pointer to the bytes of the insn, target order.
+ VALUE is the first base_insn_bitsize bits as an int in host order. */
+
+#ifndef CGEN_DIS_HASH
+#define CGEN_DIS_HASH_SIZE 256
+#define CGEN_DIS_HASH(buf, value) (*(unsigned char *) (buf))
+#endif
+
+/* The result is the hash value of the insn.
+ Targets are free to override CGEN_{ASM,DIS}_HASH in the .opc file. */
+
+static unsigned int
+asm_hash_insn (mnem)
+ const char * mnem;
+{
+ return CGEN_ASM_HASH (mnem);
+}
+
+/* BUF is a pointer to the bytes of the insn, target order.
+ VALUE is the first base_insn_bitsize bits as an int in host order. */
+
+static unsigned int
+dis_hash_insn (buf, value)
+ const char * buf;
+ CGEN_INSN_INT value;
+{
+ return CGEN_DIS_HASH (buf, value);
+}
+\n"
+ )
+)
+
+; Hash support decls.
+
+(define (-gen-hash-decls)
+ (string-list
+ "\
+/* The hash functions are recorded here to help keep assembler code out of
+ the disassembler and vice versa. */
+
+static int asm_hash_insn_p PARAMS ((const CGEN_INSN *));
+static unsigned int asm_hash_insn PARAMS ((const char *));
+static int dis_hash_insn_p PARAMS ((const CGEN_INSN *));
+static unsigned int dis_hash_insn PARAMS ((const char *, CGEN_INSN_INT));
+\n"
+ )
+)
+
+; Macro insn support.
+
+; Return a macro-insn expansion entry.
+
+(define (-gen-miexpn-entry entry)
+ ; FIXME: wip
+ "0, "
+)
+
+; Return a macro-insn table entry.
+; ??? wip, not currently used.
+
+(define (-gen-minsn-table-entry minsn all-attrs num-non-bools)
+ (gen-obj-sanitize
+ minsn
+ (string-list
+ " /* " (minsn-syntax minsn) " */\n"
+ " {\n"
+ " "
+ "-1, " ; macro-insns are not currently enumerated, no current need to
+ "\"" (obj:name minsn) "\", "
+ "\"" (minsn-mnemonic minsn) "\",\n"
+ " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n"
+ " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n"
+ " "
+ (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask)
+ "\n"
+ " },\n"))
+)
+
+; Return a macro-insn opcode table entry.
+; ??? wip, not currently used.
+
+(define (-gen-minsn-opcode-entry minsn all-attrs num-non-bools)
+ (gen-obj-sanitize
+ minsn
+ (string-list
+ " /* " (minsn-syntax minsn) " */\n"
+ " {\n"
+ " "
+ "-1, " ; macro-insns are not currently enumerated, no current need to
+ "\"" (obj:name minsn) "\", "
+ "\"" (minsn-mnemonic minsn) "\",\n"
+ " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n"
+ " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n"
+ " "
+ (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask)
+ "\n"
+ " },\n"))
+)
+
+; Macro insn expansion has one basic form, but we optimize the common case
+; of unconditionally expanding the input text to one instruction.
+; The general form is a Scheme expression that is interpreted at runtime to
+; decide how to perform the expansion. Yes, that means having a (perhaps
+; minimal) Scheme interpreter in the assembler.
+; Another thing to do is have a builder for each real insn so instead of
+; expanding to text, the macro-expansion could invoke the builder for each
+; expanded-to insn.
+
+(define (-gen-macro-insn-table)
+ (logit 2 "Generating macro-instruction table ...\n")
+ (let* ((minsn-list (map (lambda (minsn)
+ (if (has-attr? minsn 'ALIAS)
+ (minsn-make-alias "gen-macro-insn-table" minsn)
+ minsn))
+ (current-minsn-list)))
+ (all-attrs (current-insn-attr-list))
+ (num-non-bools (attr-count-non-bools all-attrs)))
+ (string-write
+ "/* Formats for ALIAS macro-insns. */\n\n"
+ "#define F(f) & @arch@_cgen_ifld_table[CONCAT2 (@ARCH@_,f)]\n\n"
+ (lambda ()
+ (string-write-map -gen-ifmt-table-1
+ (map insn-ifmt (find (lambda (minsn)
+ (has-attr? minsn 'ALIAS))
+ minsn-list))))
+ "#undef F\n\n"
+ "/* Each non-simple macro entry points to an array of expansion possibilities. */\n\n"
+ (lambda ()
+ (string-write-map (lambda (minsn)
+ (if (has-attr? minsn 'ALIAS)
+ ""
+ (string-append
+ "static const CGEN_MINSN_EXPANSION macro_" (gen-sym minsn) "_expansions[] =\n"
+ "{\n"
+ (string-map -gen-miexpn-entry
+ (minsn-expansions minsn))
+ " { 0, 0 }\n};\n\n")))
+ minsn-list))
+ "\
+#define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
+#define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
+#define OPERAND(op) CONCAT2 (@ARCH@_OPERAND_,op)
+#define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
+
+/* The macro instruction table. */
+
+static const CGEN_IBASE @arch@_cgen_macro_insn_table[] =
+{
+"
+ (lambda ()
+ (string-write-map (lambda (minsn)
+ (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n")
+ ; Simple macro-insns are emitted as aliases of real insns.
+ (if (has-attr? minsn 'ALIAS)
+ (gen-insn-table-entry minsn all-attrs num-non-bools)
+ (-gen-minsn-table-entry minsn all-attrs num-non-bools)))
+ minsn-list))
+ "\
+};
+
+/* The macro instruction opcode table. */
+
+static const CGEN_OPCODE @arch@_cgen_macro_insn_opcode_table[] =
+{\n"
+ (lambda ()
+ (string-write-map (lambda (minsn)
+ (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n")
+ ; Simple macro-insns are emitted as aliases of real insns.
+ (if (has-attr? minsn 'ALIAS)
+ (-gen-insn-opcode-entry minsn all-attrs num-non-bools)
+ (-gen-minsn-opcode-entry minsn all-attrs num-non-bools)))
+ minsn-list))
+ "\
+};
+
+#undef A
+#undef MNEM
+#undef OPERAND
+#undef OP
+\n"
+ ))
+)
+
+; Emit a function to call to initialize the opcode table.
+
+(define (-gen-opcode-init-fn)
+ (string-write
+ "\
+/* Set the recorded length of the insn in the CGEN_FIELDS struct. */
+
+static void
+set_fields_bitsize (fields, size)
+ CGEN_FIELDS *fields;
+ int size;
+{
+ CGEN_FIELDS_BITSIZE (fields) = size;
+}
+
+/* Function to call before using the operand instance table.
+ This plugs the opcode entries and macro instructions into the cpu table. */
+
+void
+@arch@_cgen_init_opcode_table (cd)
+ CGEN_CPU_DESC cd;
+{
+ int i;
+ int num_macros = (sizeof (@arch@_cgen_macro_insn_table) /
+ sizeof (@arch@_cgen_macro_insn_table[0]));
+ const CGEN_IBASE *ib = & @arch@_cgen_macro_insn_table[0];
+ const CGEN_OPCODE *oc = & @arch@_cgen_macro_insn_opcode_table[0];
+ CGEN_INSN *insns = (CGEN_INSN *) xmalloc (num_macros * sizeof (CGEN_INSN));
+ memset (insns, 0, num_macros * sizeof (CGEN_INSN));
+ for (i = 0; i < num_macros; ++i)
+ {
+ insns[i].base = &ib[i];
+ insns[i].opcode = &oc[i];
+ }
+ cd->macro_insn_table.init_entries = insns;
+ cd->macro_insn_table.entry_size = sizeof (CGEN_IBASE);
+ cd->macro_insn_table.num_init_entries = num_macros;
+
+ oc = & @arch@_cgen_insn_opcode_table[0];
+ insns = (CGEN_INSN *) cd->insn_table.init_entries;
+ for (i = 0; i < MAX_INSNS; ++i)
+ insns[i].opcode = &oc[i];
+
+ cd->sizeof_fields = sizeof (CGEN_FIELDS);
+ cd->set_fields_bitsize = set_fields_bitsize;
+
+ cd->asm_hash_p = asm_hash_insn_p;
+ cd->asm_hash = asm_hash_insn;
+ cd->asm_hash_size = CGEN_ASM_HASH_SIZE;
+
+ cd->dis_hash_p = dis_hash_insn_p;
+ cd->dis_hash = dis_hash_insn;
+ cd->dis_hash_size = CGEN_DIS_HASH_SIZE;
+}
+"
+ )
+)
+
+; Top level C code generators
+
+; FIXME: Create enum objects for all the enums we explicitly declare here.
+; Then they'd be usable and we wouldn't have to special case them here.
+
+(define (cgen-opc.h)
+ (logit 1 "Generating " (current-arch-name) "-opc.h ...\n")
+ (string-write
+ (gen-copyright "Instruction opcode header for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#ifndef @ARCH@_OPC_H
+#define @ARCH@_OPC_H
+
+"
+ (lambda () (gen-extra-opc.h srcdir (current-arch-name))) ; from <arch>.opc
+ -gen-insn-enum
+ -gen-ifield-decls
+ -gen-init-macros
+ "
+
+#endif /* @ARCH@_OPC_H */
+"
+ )
+)
+
+; This file contains the instruction opcode table.
+
+(define (cgen-opc.c)
+ (logit 1 "Generating " (current-arch-name) "-opc.c ...\n")
+ (string-write
+ (gen-copyright "Instruction opcode table for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#include \"sysdep.h\"
+#include \"ansidecl.h\"
+#include \"bfd.h\"
+#include \"symcat.h\"
+#include \"@prefix@-desc.h\"
+#include \"@prefix@-opc.h\"
+#include \"libiberty.h\"
+\n"
+ (lambda () (gen-extra-opc.c srcdir (current-arch-name))) ; from <arch>.opc
+ -gen-hash-decls
+ -gen-ifmt-table
+ -gen-insn-opcode-table
+ -gen-macro-insn-table
+ -gen-hash-fns
+ -gen-opcode-init-fn
+ )
+)
diff --git a/cgen/opc-opinst.scm b/cgen/opc-opinst.scm
new file mode 100644
index 00000000000..b76392825c8
--- /dev/null
+++ b/cgen/opc-opinst.scm
@@ -0,0 +1,168 @@
+; Operand instance support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Return C code to define one instance of operand object OP.
+; TYPE is one of "INPUT" or "OUTPUT".
+
+(define (-gen-operand-instance op type)
+ (let ((index (op:index op)))
+ (string-append " { "
+ type ", "
+ "\"" (gen-sym op) "\", "
+ (hw-enum (op:type op)) ", "
+ ; FIXME: Revisit CGEN_ prefix, use MODE (FOO) instead.
+ "CGEN_" (mode:enum (op:mode op)) ", "
+ ; FIXME: We don't handle memory properly yet. Later.
+ (cond ((memory? (op:type op))
+ "0, 0")
+ ((has-attr? op 'SEM-ONLY)
+ "0, 0")
+ ((eq? (hw-index:type index) 'ifield)
+ (if (= (ifld-length (hw-index:value index)) 0)
+ "0, 0"
+ (string-append "OP_ENT ("
+ (string-upcase (gen-sym op))
+ "), 0")))
+ ((eq? (hw-index:type index) 'constant)
+ (string-append "0, "
+ (number->string (hw-index:value index))))
+ (else "0, 0"))
+ ", " (if (op:cond? op) "COND_REF" "0")
+ " },\n"))
+)
+
+; Return C code to define arrays of operand instances read from and written
+; to by <sformat> SFMT.
+; This is based on the semantics of the instruction.
+; ??? All runtime chosen values (e.g. a particular register in a register bank)
+; is assumed to be selected statically by the instruction. When some cpu
+; violates this assumption (say because a previous instruction determines
+; which register(s) the next instruction operates on), this will need
+; additional support.
+
+(define (-gen-operand-instance-table sfmt)
+ (let ((ins (sfmt-in-ops sfmt))
+ (outs (sfmt-out-ops sfmt)))
+ ; This used to exclude outputing anything if there were no ins or outs.
+ (gen-obj-sanitize
+ (sfmt-eg-insn sfmt) ; sanitize based on the example insn
+ (string-append
+ "static const CGEN_OPINST "
+ (gen-sym sfmt) "_ops[] = {\n"
+ (string-map (lambda (op) (-gen-operand-instance op "INPUT"))
+ ins)
+ (string-map (lambda (op) (-gen-operand-instance op "OUTPUT"))
+ outs)
+ " { END }\n};\n\n")))
+)
+
+(define (-gen-operand-instance-tables)
+ (string-write
+ "\
+/* Operand references. */
+
+#define INPUT CGEN_OPINST_INPUT
+#define OUTPUT CGEN_OPINST_OUTPUT
+#define END CGEN_OPINST_END
+#define COND_REF CGEN_OPINST_COND_REF
+#define OP_ENT(op) CONCAT2 (@ARCH@_OPERAND_,op)
+
+"
+ (lambda () (string-write-map -gen-operand-instance-table (current-sfmt-list)))
+ "\
+#undef INPUT
+#undef OUTPUT
+#undef END
+#undef COND_REF
+#undef OP_ENT
+
+"
+ )
+)
+
+; Return C code for INSN's operand instance table.
+
+(define (gen-operand-instance-ref insn)
+ (let* ((sfmt (insn-sfmt insn))
+ (ins (sfmt-in-ops sfmt))
+ (outs (sfmt-out-ops sfmt)))
+ (if (and (null? ins) (null? outs))
+ "0"
+ (string-append "& " (gen-sym sfmt) "_ops[0]")))
+)
+
+; Return C code to define a table to lookup an insn's operand instance table.
+
+(define (-gen-insn-opinst-lookup-table)
+ (string-list
+ "/* Operand instance lookup table. */\n\n"
+ "static const CGEN_OPINST *@arch@_cgen_opinst_table[MAX_INSNS] = {\n"
+ " 0,\n" ; null first entry
+ (string-list-map
+ (lambda (insn)
+ (gen-obj-sanitize
+ insn
+ (string-append " & " (gen-sym (insn-sfmt insn)) "_ops[0],\n")))
+ (current-insn-list))
+ "};\n\n"
+ "\
+/* Function to call before using the operand instance table. */
+
+void
+@arch@_cgen_init_opinst_table (cd)
+ CGEN_CPU_DESC cd;
+{
+ int i;
+ const CGEN_OPINST **oi = & @arch@_cgen_opinst_table[0];
+ CGEN_INSN *insns = (CGEN_INSN *) cd->insn_table.init_entries;
+ for (i = 0; i < MAX_INSNS; ++i)
+ insns[i].opinst = oi[i];
+}
+"
+ )
+)
+
+; Return the maximum number of operand instances used by any insn.
+; If not generating the operand instance table, use a heuristic.
+
+(define (max-operand-instances)
+ (if -opcodes-build-operand-instance-table?
+ (apply max
+ (map (lambda (insn)
+ (+ (length (sfmt-in-ops (insn-sfmt insn)))
+ (length (sfmt-out-ops (insn-sfmt insn)))))
+ (current-insn-list)))
+ 8) ; FIXME: for now
+)
+
+; Generate $arch-opinst.c.
+
+(define (cgen-opinst.c)
+ (logit 1 "Generating " (current-arch-name) "-opinst.c ...\n")
+
+ ; If instruction semantics haven't been analyzed, do that now.
+ (if (not (arch-semantics-analyzed? CURRENT-ARCH))
+ (begin
+ (logit 1 "Instruction semantics weren't analyzed when .cpu file was loaded.\n")
+ (logit 1 "Doing so now ...\n")
+ (arch-analyze-insns! CURRENT-ARCH
+ #t ; include aliases
+ #t) ; -opcodes-build-operand-instance-table?
+ ))
+
+ (string-write
+ (gen-copyright "Semantic operand instances for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#include \"sysdep.h\"
+#include \"ansidecl.h\"
+#include \"bfd.h\"
+#include \"symcat.h\"
+#include \"@prefix@-desc.h\"
+#include \"@prefix@-opc.h\"
+\n"
+ -gen-operand-instance-tables
+ -gen-insn-opinst-lookup-table
+ )
+)
diff --git a/cgen/opcodes.scm b/cgen/opcodes.scm
new file mode 100644
index 00000000000..f5ed26f801d
--- /dev/null
+++ b/cgen/opcodes.scm
@@ -0,0 +1,804 @@
+; General cpu info generator support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Global state variables.
+
+; Specify which application.
+(set! APPLICATION 'OPCODES)
+
+; Boolean indicating if we're to build the operand instance table.
+; The default is no, since only the m32r uses it at present.
+; ??? Simulator tracing support could use it.
+; ??? Might be lazily built at runtime by parsing the semantic code
+; (which would be recorded in the insn table).
+(define -opcodes-build-operand-instance-table? #f)
+
+; String containing copyright text.
+(define CURRENT-COPYRIGHT #f)
+
+; String containing text defining the package we're generating code for.
+(define CURRENT-PACKAGE #f)
+
+; Initialize the options.
+
+(define (option-init!)
+ (set! -opcodes-build-operand-instance-table? #f)
+ (set! CURRENT-COPYRIGHT copyright-fsf)
+ (set! CURRENT-PACKAGE package-gnu-binutils-gdb)
+ *UNSPECIFIED*
+)
+
+; Handle an option passed in from the command line.
+
+(define (option-set! name value)
+ (case name
+ ((opinst) (set! -opcodes-build-operand-instance-table? #t))
+ ((copyright) (cond ((equal? value '("fsf"))
+ (set! CURRENT-COPYRIGHT copyright-fsf))
+ ((equal? value '("cygnus"))
+ (set! CURRENT-COPYRIGHT copyright-cygnus))
+ (else (error "invalid copyright value" value))))
+ ((package) (cond ((equal? value '("binutils"))
+ (set! CURRENT-PACKAGE package-gnu-binutils-gdb))
+ ((equal? value '("gnusim"))
+ (set! CURRENT-PACKAGE package-gnu-simulators))
+ ((equal? value '("cygsim"))
+ (set! CURRENT-PACKAGE package-cygnus-simulators))
+ (else (error "invalid package value" value))))
+ (else (error "unknown option" name))
+ )
+ *UNSPECIFIED*
+)
+
+; Instruction fields support code.
+
+; Default type of variable to use to hold ifield value.
+
+(define (gen-ifield-default-type)
+ ; FIXME: Use long for now.
+ "long"
+)
+
+; Given field F, return a C definition of a variable big enough to hold
+; its value.
+
+(define (gen-ifield-value-decl f)
+ (gen-obj-sanitize f (string-append " "
+ (gen-ifield-default-type)
+ " " (gen-sym f) ";\n"))
+)
+
+; Return name of function to call to insert the value of <ifield> F
+; into an insn.
+
+(define (ifld-insert-fn-name f)
+ "insert_normal"
+)
+
+; Return name of function to call to extract the value of <ifield> F
+; into an insn.
+
+(define (ifld-extract-fn-name f)
+ "extract_normal"
+)
+
+; Default routine to emit C code to insert a field in an insn.
+
+(method-make!
+ <ifield> 'gen-insert
+ (lambda (self operand)
+ (let* ((encode (elm-get self 'encode))
+ (need-extra? encode) ; use to also handle operand's `insert' field
+ (varname (gen-operand-result-var self)))
+ (string-append
+ (if need-extra?
+ (string-append " {\n"
+ " "
+ (gen-ifield-default-type)
+ " value = " varname ";\n")
+ "")
+ (if encode
+ (string-append " value = "
+ (let ((expr (cadr encode))
+ (value (caar encode))
+ (pc (cadar encode)))
+ (rtl-c DFLT expr
+ (list (list value (obj:name (ifld-encode-mode self)) "value")
+ (list pc 'IAI "pc"))))
+ ";\n")
+ "")
+ (if need-extra?
+ " "
+ "")
+ " errmsg = "
+ (ifld-insert-fn-name self)
+ " (cd, "
+ (if need-extra?
+ "value"
+ varname)
+ ", "
+ ; We explicitly pass the attributes here rather than look them up
+ ; to give the code more optimization opportunities.
+ ; ??? Maybe when fields are recorded in opc.c, stop doing this, and
+ ; pass a pointer to the recorded attributes instead.
+ (gen-bool-attrs (if (eq? (mode:class (ifld-mode self)) 'INT)
+ (atlist-cons (bool-attr-make 'SIGNED #t)
+ (obj-atlist self))
+ (obj-atlist self))
+ gen-attr-mask)
+ ", " (number->string (ifld-word-offset self))
+ ", " (number->string (ifld-start self #f))
+ ", " (number->string (ifld-length self))
+ ", " (number->string (ifld-word-length self))
+ ", total_length"
+ ", buffer"
+ ");\n"
+ (if need-extra?
+ " }\n"
+ "")
+ )))
+)
+
+; Default routine to emit C code to extract a field from an insn.
+
+(method-make!
+ <ifield> 'gen-extract
+ (lambda (self operand)
+ (let* ((decode (elm-get self 'decode))
+ (need-extra? decode) ; use to also handle operand's `extract' field
+ (varname (gen-operand-result-var self)))
+ (string-append
+ (if need-extra?
+ (string-append " {\n "
+ (gen-ifield-default-type)
+ " value;\n ")
+ "")
+ " length = "
+ (ifld-extract-fn-name self)
+ " (cd, ex_info, insn_value, "
+ ; We explicitly pass the attributes here rather than look them up
+ ; to give the code more optimization opportunities.
+ ; ??? Maybe when fields are recorded in opc.c, stop doing this, and
+ ; pass a pointer to the recorded attributes instead.
+ (gen-bool-attrs (if (eq? (mode:class (ifld-mode self)) 'INT)
+ (atlist-cons (bool-attr-make 'SIGNED #t)
+ (obj-atlist self))
+ (obj-atlist self))
+ gen-attr-mask)
+ ", " (number->string (ifld-word-offset self))
+ ", " (number->string (ifld-start self #f))
+ ", " (number->string (ifld-length self))
+ ", " (number->string (ifld-word-length self))
+ ", total_length"
+ ", pc"
+ ", & "
+ (if need-extra?
+ "value"
+ varname)
+ ");\n"
+ (if decode
+ (string-append " value = "
+ (let ((expr (cadr decode))
+ (value (caar decode))
+ (pc (cadar decode)))
+ (rtl-c DFLT expr
+ (list (list value (obj:name (ifld-decode-mode self)) "value")
+ (list pc 'IAI "pc"))))
+ ";\n")
+ "")
+ (if need-extra?
+ (string-append " " varname " = value;\n"
+ " }\n")
+ "")
+ )))
+)
+
+; gen-insert of multi-ifields
+
+(method-make!
+ <multi-ifield> 'gen-insert
+ (lambda (self operand)
+ (let* ((varname (gen-operand-result-var self))
+ (encode (elm-get self 'encode))
+ (need-extra? encode))
+ (string-list
+ " {\n"
+ (if need-extra?
+ (string-append " " varname " = "
+ (let ((expr (cadr encode))
+ (value (caar encode))
+ (pc (cadar encode)))
+ (rtl-c DFLT expr
+ (list (list value (obj:name (ifld-encode-mode self)) varname)
+ (list pc 'IAI "pc"))))
+ ";\n")
+ "")
+ (let ((expr (elm-get self 'insert)))
+ (rtl-c VOID expr nil))
+ (string-list-map (lambda (subfld)
+ (string-list
+ " "
+ (send subfld 'gen-insert operand)
+ " if (errmsg)\n"
+ " break;\n"))
+ (elm-get self 'subfields))
+ " }\n"
+ )))
+)
+
+; gen-insert of derived-operands
+
+(method-make!
+ <derived-operand> 'gen-insert
+ (lambda (self operand)
+ " abort();\n")
+)
+
+; gen-extract of multi-ifields
+
+(method-make!
+ <multi-ifield> 'gen-extract
+ (lambda (self operand)
+ (let* ((varname (gen-operand-result-var self))
+ (decode (elm-get self 'decode))
+ (need-extra? decode))
+ (string-list
+ " {\n"
+ (string-list-map (lambda (subfld)
+ (string-list
+ " "
+ (send subfld 'gen-extract operand)
+ " if (length <= 0) break;\n"
+ ))
+ (elm-get self 'subfields))
+ (let ((expr (elm-get self 'extract)))
+ (rtl-c VOID expr nil))
+ (if need-extra?
+ (string-append " " varname " = "
+ (let ((expr (cadr decode))
+ (value (caar decode))
+ (pc (cadar decode)))
+ (rtl-c DFLT expr
+ (list (list value (obj:name (ifld-decode-mode self)) varname)
+ (list pc 'IAI "pc"))))
+ ";\n")
+ "")
+ " }\n"
+ )))
+)
+
+
+(method-make!
+ <derived-operand> 'gen-extract
+ (lambda (self operand)
+ " abort();\n")
+)
+
+;(method-make!
+; <derived-operand> 'gen-extract
+; (lambda (self operand)
+; (string-list
+; " {\n"
+; (string-list-map (lambda (subop)
+; (string-list
+; " " (send subop 'gen-extract operand)
+; " if (length <= 0)\n"
+; " break;\n"))
+; (elm-get self 'args))
+; " }\n"
+; ))
+;)
+
+
+; Hardware index support code.
+
+(method-make!
+ <hw-index> 'gen-insert
+ (lambda (self operand)
+ (case (hw-index:type self)
+ ((ifield)
+ (send (hw-index:value self) 'gen-insert operand))
+ (else
+ "")))
+)
+
+(method-make!
+ <hw-index> 'gen-extract
+ (lambda (self operand)
+ (case (hw-index:type self)
+ ((ifield)
+ (send (hw-index:value self) 'gen-extract operand))
+ (else
+ ""))))
+
+; HW-ASM is the base class for supporting hardware elements in the opcode table
+; (aka assembler/disassembler).
+
+; Utility to return C code to parse a number of <mode> MODE for an operand.
+; RESULT-VAR-NAME is a string containing the variable to store the
+; parsed number in.
+; PARSE-FN is the name of the function to call or #f to use the default.
+; OP-ENUM is the enum of the operand.
+
+(define (-gen-parse-number mode parse-fn op-enum result-var-name)
+ (string-append
+ " errmsg = "
+ ; Use operand's special parse function if there is one, otherwise compute
+ ; the function's name from the mode.
+ (or parse-fn
+ (case (obj:name mode)
+ ((QI HI SI INT) "cgen_parse_signed_integer")
+ ((BI UQI UHI USI UINT) "cgen_parse_unsigned_integer")
+ (else (error "unsupported (as yet) mode for parsing"
+ (obj:name mode)))))
+ " (cd, strp, "
+ op-enum
+ ", &" result-var-name
+ ");\n"
+ )
+)
+
+; Utility to return C code to parse an address.
+; RESULT-VAR-NAME is a string containing the variable to store the
+; parsed number in.
+; PARSE-FN is the name of the function to call or #f to use the default.
+; OP-ENUM is the enum of the operand.
+
+(define (-gen-parse-address parse-fn op-enum result-var-name)
+ (string-append
+ " {\n"
+ " bfd_vma value;\n"
+ " errmsg = "
+ ; Use operand's special parse function if there is one.
+ (or parse-fn
+ "cgen_parse_address")
+ " (cd, strp, "
+ op-enum
+ ", 0, " ; opinfo arg
+ "NULL, " ; result_type arg (FIXME)
+ " & value);\n"
+ " " result-var-name " = value;\n"
+ " }\n"
+ )
+)
+
+; Return C code to parse an expression.
+
+(method-make!
+ <hw-asm> 'gen-parse
+ (lambda (self operand)
+ (let ((mode (elm-get self 'mode))
+ (result-var
+ (case (hw-index:type (op:index operand))
+ ((ifield) (gen-operand-result-var (op-ifield operand)))
+ (else "junk"))))
+ (if (address? (op:type operand))
+ (-gen-parse-address (send operand 'gen-function-name 'parse)
+ (op-enum operand)
+ result-var)
+ (-gen-parse-number mode (send operand 'gen-function-name 'parse)
+ (op-enum operand)
+ result-var))))
+)
+
+; Default method to emit C code to print a hardware element.
+
+(method-make!
+ <hw-asm> 'gen-print
+ (lambda (self operand)
+ (let ((value
+ (case (hw-index:type (op:index operand))
+ ((ifield) (gen-operand-result-var (op-ifield operand)))
+ (else "0"))))
+ (string-append
+ " "
+ (or (send operand 'gen-function-name 'print)
+ (and (address? (op:type operand))
+ "print_address")
+ "print_normal")
+; (or (send operand 'gen-function-name 'print)
+; (case (obj:name (elm-get self 'mode))
+; ((QI HI SI INT) "print_signed")
+; ((BI UQI UHI USI UINT) "print_unsigned")
+; (else (error "unsupported (as yet) mode for printing"
+; (obj:name (elm-get self 'mode))))))
+ " (cd, info, "
+ value
+ ", "
+ ; We explicitly pass the attributes here rather than look them up
+ ; to give the code more optimization opportunities.
+ (gen-bool-attrs (if (eq? (mode:class (elm-get self 'mode)) 'INT)
+ (atlist-cons (bool-attr-make 'SIGNED #t)
+ (obj-atlist operand))
+ (obj-atlist operand))
+ gen-attr-mask)
+ ;(gen-bool-attrs (obj-atlist operand) gen-attr-mask)
+ ", pc, length"
+ ");\n"
+ )))
+)
+
+; Keyword support.
+
+; Return C code to parse a keyword.
+
+(method-make!
+ <keyword> 'gen-parse
+ (lambda (self operand)
+ (let ((result-var
+ (case (hw-index:type (op:index operand))
+ ((ifield) (gen-operand-result-var (op-ifield operand)))
+ (else "junk"))))
+ (string-append
+ " errmsg = "
+ (or (send operand 'gen-function-name 'parse)
+ "cgen_parse_keyword")
+ " (cd, strp, "
+ (send self 'gen-ref) ", "
+ ;(op-enum operand) ", "
+ "& " result-var
+ ");\n"
+ )))
+)
+
+; Return C code to print a keyword.
+
+(method-make!
+ <keyword> 'gen-print
+ (lambda (self operand)
+ (let ((value
+ (case (hw-index:type (op:index operand))
+ ((ifield) (gen-operand-result-var (op-ifield operand)))
+ (else "0"))))
+ (string-append
+ " "
+ (or (send operand 'gen-function-name 'print)
+ "print_keyword")
+ " (cd, "
+ "info" ; The disassemble_info argument to print_insn.
+ ", "
+ (send self 'gen-ref)
+ ", " value
+ ", "
+ ; We explicitly pass the attributes here rather than look them up
+ ; to give the code more optimization opportunities.
+ (gen-bool-attrs (obj-atlist operand) gen-attr-mask)
+ ");\n"
+ )))
+)
+
+; Hardware support.
+
+; For registers, use the indices field. Ignore values.
+; ??? Not that that will always be the case.
+
+(method-make-forward! <hw-register> 'indices '(gen-parse gen-print))
+
+; No such support for memory yet.
+
+(method-make!
+ <hw-memory> 'gen-parse
+ (lambda (self operand)
+ (error "gen-parse of memory not supported yet"))
+)
+
+(method-make!
+ <hw-memory> 'gen-print
+ (lambda (self operand)
+ (error "gen-print of memory not supported yet"))
+)
+
+; For immediates, use the values field. Ignore indices.
+; ??? Not that that will always be the case.
+
+(method-make-forward! <hw-immediate> 'values '(gen-parse gen-print))
+
+; For addresses, use the values field. Ignore indices.
+
+(method-make-forward! <hw-address> 'values '(gen-parse gen-print))
+
+; Generate the C code for dealing with operands.
+; This code is inserted into cgen-{ibld,asm,dis}.in above the insn routines
+; so that it can be inlined if desired. ??? Actually this isn't always the
+; case but this is minutiae to be dealt with much later.
+
+; Generate the guts of a C switch to handle an operation for all operands.
+; WHAT is one of fget/fset/parse/insert/extract/print.
+;
+; The "f" prefix (e.g. set -> fset) is for "field" to distinguish the
+; operations from similar ones in other contexts. ??? I'd prefer to come
+; up with better names for fget/fset but I haven't come up with anything
+; satisfactory yet.
+
+(define (gen-switch what)
+ (string-list-map
+ (lambda (ops)
+ ; OPS is a list of operands with the same name that for whatever reason
+ ; were defined separately.
+ (logit 3 (string-append "Processing " (obj:name (car ops)) " " what " ...\n"))
+ (if (= (length ops) 1)
+ (gen-obj-sanitize
+ (car ops)
+ (string-list
+ " case @ARCH@_OPERAND_"
+ (string-upcase (gen-sym (car ops)))
+ " :\n"
+ (send (car ops) (symbol-append 'gen- what) (car ops))
+ " break;\n"))
+ (string-list
+ ; FIXME: operand name doesn't get sanitized.
+ " case @ARCH@_OPERAND_"
+ (string-upcase (gen-sym (car ops)))
+ " :\n"
+ ; There's more than one operand defined with this name, so we
+ ; have to distinguish them.
+ ; FIXME: Unfinished.
+ (string-list-map (lambda (op)
+ (gen-obj-sanitize
+ op
+ (string-list
+ (send op (symbol-append 'gen- what) op)
+ )))
+ ops)
+ " break;\n"
+ )))
+ (op-sort (find (lambda (op) (and (not (has-attr? op 'SEM-ONLY))
+ (not (anyof-operand? op))
+ (not (derived-operand? op))))
+ (current-op-list))))
+)
+
+; Operand support.
+
+; Return the function name to use for WHAT or #f if there isn't a special one.
+; WHAT is one of fget/fset/parse/insert/extract/print.
+
+(method-make!
+ <operand> 'gen-function-name
+ (lambda (self what)
+ (let ((handlers (elm-get self 'handlers)))
+ (let ((fn (assq-ref handlers what)))
+ (and fn (string-append what "_" (car fn))))))
+)
+
+; Interface fns.
+; The default is to forward the request onto TYPE.
+; OP is a copy of SELF so the method we forward to sees it.
+; There is one case in the fget/fset/parse/insert/extract/print
+; switches for each operand.
+; These are invoked via gen-switch.
+
+; Emit C code to get an operand value from the fields struct.
+; Operand values are stored in a struct "indexed" by field name.
+;
+; The "f" prefix (e.g. set -> fset) is for "field" to distinguish the
+; operations from similar ones in other contexts. ??? I'd prefer to come
+; up with better names for fget/fset but I haven't come up with anything
+; satisfactory yet.
+
+(method-make!
+ <operand> 'gen-fget
+ (lambda (self operand)
+ (case (hw-index:type (op:index self))
+ ((ifield)
+ (string-append " value = "
+ (gen-operand-result-var (op-ifield self))
+ ";\n"))
+ (else
+ " value = 0;\n")))
+)
+
+(method-make!
+ <derived-operand> 'gen-fget
+ (lambda (self operand)
+ " abort();\n") ; should never be called
+)
+
+; Emit C code to save an operand value in the fields struct.
+
+(method-make!
+ <operand> 'gen-fset
+ (lambda (self operand)
+ (case (hw-index:type (op:index self))
+ ((ifield)
+ (string-append " "
+ (gen-operand-result-var (op-ifield self))
+ " = value;\n"))
+ (else
+ ""))) ; ignore
+)
+
+(method-make!
+ <derived-operand> 'gen-fset
+ (lambda (self operand)
+ " abort();\n") ; should never be called
+)
+
+
+; Need to call op:type to resolve the hardware reference.
+;(method-make-forward! <operand> 'type '(gen-parse gen-print))
+
+(method-make!
+ <operand> 'gen-parse
+ (lambda (self operand)
+ (send (op:type self) 'gen-parse operand))
+)
+
+(method-make!
+ <derived-operand> 'gen-parse
+ (lambda (self operand)
+ " abort();\n") ; should never be called
+)
+
+(method-make!
+ <operand> 'gen-print
+ (lambda (self operand)
+ (send (op:type self) 'gen-print operand))
+)
+
+(method-make!
+ <derived-operand> 'gen-print
+ (lambda (self operand)
+ " abort();\n") ; should never be called
+)
+
+(method-make-forward! <operand> 'index '(gen-insert gen-extract))
+; But: <derived-operand> has its own gen-insert / gen-extract.
+
+
+; Return the value of PC.
+; Used by insert/extract fields.
+
+(method-make!
+ <pc> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (cx:make IAI "pc"))
+)
+
+; Opcodes init,finish,analyzer support.
+
+; Initialize any opcodes specific things before loading the .cpu file.
+
+(define (opcodes-init!)
+ (desc-init!)
+ *UNSPECIFIED*
+)
+
+; Finish any opcodes specific things after loading the .cpu file.
+; This is separate from analyze-data! as cpu-load performs some
+; consistency checks in between.
+
+(define (opcodes-finish!)
+ (desc-finish!)
+ *UNSPECIFIED*
+)
+
+; Compute various needed globals and assign any computed fields of
+; the various objects. This is the standard routine that is called after
+; a .cpu file is loaded.
+
+(define (opcodes-analyze!)
+ (desc-analyze!)
+
+ ; Initialize the rtl->c translator.
+ (rtl-c-config!)
+
+ ; Only include semantic operands when computing the format tables if we're
+ ; generating operand instance tables.
+ ; ??? Actually, may always be able to exclude the semantic operands.
+ ; Still need to traverse the semantics to derive machine computed attributes.
+ (arch-analyze-insns! CURRENT-ARCH
+ #t ; include aliases
+ -opcodes-build-operand-instance-table?)
+
+ *UNSPECIFIED*
+)
+
+; Extra target specific code generation.
+; For now, such code lives in <arch>.opc.
+
+; Pick out a section from the .opc file.
+; The section is delimited with:
+; /* -- name ... */
+; ...
+; /* -- ... */
+;
+; FIXME: This is a pretty involved bit of code. 'twould be nice to split
+; it up into manageable chunks.
+
+(define (read-cpu.opc srcdir cpu delim)
+ (let ((file (string-append srcdir "/" (current-arch-name) ".opc"))
+ (start-delim (string-append "/* -- " delim))
+ (end-delim "/* -- "))
+ (if (file-exists? file)
+ (let ((port (open-file file "r"))
+ ; Extra amount is added to SIZE so substring's to fetch possible
+ ; delim won't fail, even at end of file
+ (size (+ (file-size file) (string-length start-delim))))
+ (if port
+ (let ((result (make-string size #\space)))
+ (let loop ((start -1) (line 0) (index 0))
+ (let ((char (read-char port)))
+ (if (not (eof-object? char))
+ (string-set! result index char))
+ (cond ((eof-object? char)
+ (begin
+ (close-port port)
+ ; End of file, did we find the text?
+ (if (=? start -1)
+ ""
+ (substring result start index))))
+ ((char=? char #\newline)
+ ; Check for start delim or end delim?
+ (if (=? start -1)
+ (if (string=? (substring result line
+ (+ (string-length start-delim)
+ line))
+ start-delim)
+ (loop line (+ index 1) (+ index 1))
+ (loop -1 (+ index 1) (+ index 1)))
+ (if (string=? (substring result line
+ (+ (string-length end-delim)
+ line))
+ end-delim)
+ (begin
+ (close-port port)
+ (substring result start (+ index 1)))
+ (loop start (+ index 1) (+ index 1)))))
+ (else
+ (loop start line (+ index 1)))))))
+ (error "Unable to open:" file)))
+ "" ; file doesn't exist
+ ))
+)
+
+; FIXME: collapse into one?
+(define (gen-extra-cpu.h srcdir arch)
+ (logit 2 "Generating extra cpu.h stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "cpu.h")
+)
+(define (gen-extra-cpu.c srcdir arch)
+ (logit 2 "Generating extra cpu.c stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "cpu.c")
+)
+(define (gen-extra-opc.h srcdir arch)
+ (logit 2 "Generating extra opc.h stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "opc.h")
+)
+(define (gen-extra-opc.c srcdir arch)
+ (logit 2 "Generating extra opc.c stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "opc.c")
+)
+(define (gen-extra-asm.c srcdir arch)
+ (logit 2 "Generating extra asm.c stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "asm.c")
+)
+(define (gen-extra-dis.c srcdir arch)
+ (logit 2 "Generating extra dis.c stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "dis.c")
+)
+(define (gen-extra-ibld.h srcdir arch)
+ (logit 2 "Generating extra ibld.h stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "ibld.h")
+)
+(define (gen-extra-ibld.c srcdir arch)
+ (logit 2 "Generating extra ibld.c stuff from " arch ".opc ...\n")
+ (read-cpu.opc srcdir arch "ibld.c")
+)
+
+; For debugging.
+
+(define (cgen-all)
+ (string-write
+ cgen-desc.h
+ cgen-desc.c
+ cgen-opinst.c
+ cgen-opc.h
+ cgen-opc.c
+ cgen-ibld.h
+ cgen-ibld.in
+ cgen-asm.in
+ cgen-dis.in
+ )
+)
diff --git a/cgen/operand.scm b/cgen/operand.scm
new file mode 100644
index 00000000000..03a52172985
--- /dev/null
+++ b/cgen/operand.scm
@@ -0,0 +1,1559 @@
+; Operands
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Operands map a set of values (registers, whatever) to an instruction field
+; or other indexing mechanism. Operands are also how the semantic code refers
+; to hardware elements.
+
+; The `<operand>' class.
+;
+; ??? Need a new lighterweight version for instances in semantics.
+; This should only contain the static elements from the description file.
+;
+; ??? Derived operands don't use all the current class members. Perhaps
+; split <operand> into two.
+
+(define <operand>
+ (class-make '<operand>
+ '(<ident>)
+ '(
+ ; Name as used in semantic code.
+ ; Generally this is the same as NAME. It is changed by the
+ ; `operand:' rtx function. One reason is to set a "pretty"
+ ; name in tracing output (most useful in memory operands).
+ ; A more important reason is to help match semantic operands
+ ; with function unit input/output arguments.
+ sem-name
+
+ ; Semantic name of hardware element refered to by this operand.
+ hw-name
+
+ ; Hardware type of operand, a subclass of <hardware-base>.
+ ; This is computed lazily from HW-NAME as many hardware
+ ; elements can have the same semantic name. Applications
+ ; that require a unique hardware element to be refered to are
+ ; required to ensure duplicates are discarded (usually done
+ ; by keeping the appropriate machs).
+ ; FIXME: Rename to hw.
+ (type . #f)
+
+ ; Name of mode, as specified in description file.
+ ; This needn't be the actual mode, as WI will get coerced
+ ; to the actual word int mode.
+ mode-name
+
+ ; The mode TYPE is being referenced in.
+ ; This is also looked up lazily for the same reasons as TYPE.
+ (mode . #f)
+
+ ; Selector.
+ ; A number or #f used to select a variant of the hardware
+ ; element. An example is ASI's on sparc.
+ ; ??? I really need to be better at picking names.
+ (selector . #f)
+
+ ; Index into type, class <hw-index>.
+ ; For example in the case of an array of registers
+ ; it can be an instruction field or in the case of a memory
+ ; reference it can be a register operand (or general rtx).
+ ; ??? At present <hw-index> is a facade over the real index
+ ; type. Not sure what the best way to do this is.
+ (index . #f)
+
+ ; Code to run when the operand is read or #f meaning pass
+ ; the request on to the hardware object.
+ (getter . #f)
+
+ ; Code to run when the operand is written or #f meaning pass
+ ; the request on to the hardware object.
+ (setter . #f)
+
+ ; Associative list of (symbol . "handler") entries.
+ ; Each entry maps an operation to its handler (which is up to
+ ; the application but is generally a function name).
+ (handlers . ())
+
+ ; Ordinal number of the operand in an insn's semantic
+ ; description. There is no relation between the number and
+ ; where in the semantics the operand appears. An operand that
+ ; is both read and written are given separate ordinal numbers
+ ; (inputs are treated separately from outputs).
+ (num . -1)
+
+ ; Boolean indicating if the operand is conditionally
+ ; referenced. #f means the operand is always referenced by
+ ; the instruction.
+ (cond? . #f)
+ )
+ nil)
+)
+
+; The default make! assigns the default h/w selector.
+
+(method-make!
+ <operand> 'make!
+ (lambda (self name comment attrs hw-name mode-name index handlers getter setter)
+ (elm-set! self 'name name)
+ (elm-set! self 'sem-name name)
+ (elm-set! self 'comment comment)
+ (elm-set! self 'attrs attrs)
+ (elm-set! self 'hw-name hw-name)
+ (elm-set! self 'mode-name mode-name)
+ (elm-set! self 'selector hw-selector-default)
+ (elm-set! self 'index index)
+ (elm-set! self 'handlers handlers)
+ (elm-set! self 'getter getter)
+ (elm-set! self 'setter setter)
+ self)
+)
+
+; FIXME: The prefix field- doesn't seem right. Indices needn't be
+; ifields, though for operands defined in .cpu files they usually are.
+(method-make-forward! <operand> 'index '(field-start field-length))
+
+; Accessor fns
+
+(define op:sem-name (elm-make-getter <operand> 'sem-name))
+(define op:set-sem-name! (elm-make-setter <operand> 'sem-name))
+(define op:hw-name (elm-make-getter <operand> 'hw-name))
+(define op:mode-name (elm-make-getter <operand> 'mode-name))
+(define op:selector (elm-make-getter <operand> 'selector))
+; FIXME: op:index should be named op:hwindex.
+(define op:index (elm-make-getter <operand> 'index))
+(define op:handlers (elm-make-getter <operand> 'handlers))
+(define op:getter (elm-make-getter <operand> 'getter))
+(define op:setter (elm-make-getter <operand> 'setter))
+(define op:num (elm-make-getter <operand> 'num))
+(define op:set-num! (elm-make-setter <operand> 'num))
+(define op:cond? (elm-make-getter <operand> 'cond?))
+(define op:set-cond?! (elm-make-setter <operand> 'cond?))
+
+; Compute the hardware type lazily.
+; FIXME: op:type should be named op:hwtype or some such.
+
+(define op:type
+ (let ((getter (elm-make-getter <operand> 'type)))
+ (lambda (op)
+ (let ((type (getter op)))
+ (if type
+ type
+ (let* ((hw-name (op:hw-name op))
+ (hw-objs (current-hw-sem-lookup hw-name)))
+ (if (!= (length hw-objs) 1)
+ (error "can't resolve h/w reference" hw-name))
+ ((elm-make-setter <operand> 'type) op (car hw-objs))
+ (car hw-objs))))))
+)
+
+; Compute the operand's mode lazily (depends on hardware type which is
+; computed lazily).
+
+(define op:mode
+ (let ((getter (elm-make-getter <operand> 'mode)))
+ (lambda (op)
+ (let ((mode (getter op)))
+ (if mode
+ mode
+ (let ((mode-name (op:mode-name op))
+ (type (op:type op)))
+ (let ((mode (if (eq? mode-name 'DFLT)
+ (hw-default-mode type)
+ (mode:lookup mode-name))))
+ ((elm-make-setter <operand> 'mode) op mode)
+ mode))))))
+)
+
+(method-make! <operand> 'get-mode (lambda (self) (op:mode self)))
+
+; FIXME: wip
+; Result is the <ifield> object or #f if there is none.
+
+(define (op-ifield op)
+ (logit 4 "op-ifield op=" (obj:name op) " indx=" (obj:name (op:index op)) "\n")
+ (let ((indx (op:index op)))
+ (if indx
+ (let ((maybe-ifld (hw-index:value (op:index op))))
+ (logit 4 " ifld=" (obj:name maybe-ifld) "\n")
+ (cond ((ifield? maybe-ifld) maybe-ifld)
+ ((derived-ifield? maybe-ifld) maybe-ifld)
+ ((ifield? indx) indx)
+ ((derived-ifield? indx) indx)
+ (else #f)))
+ #f))
+)
+
+; Return mode to use for index or #f if scalar.
+; This can't use method-make-forward! as we need to call op:type to
+; resolve the hardware reference.
+
+(method-make!
+ <operand> 'get-index-mode
+ (lambda (self) (send (op:type self) 'get-index-mode))
+)
+
+; Return the operand's enum.
+
+(define (op-enum op)
+ (string-upcase (string-append "@ARCH@_OPERAND_" (gen-sym op)))
+)
+
+; Return a boolean indicating if X is an operand.
+
+(define (operand? x) (class-instance? <operand> x))
+
+; Default gen-pretty-name method.
+; Return a C string of the name intended for users.
+;
+; FIXME: The current implementation is a quick hack. Parallel execution
+; support can create operands with long names. e.g. h-memory-add-WI-src2-slo16
+; The eventual way this will be handled is to record with each operand the
+; entry number (or some such) in the operand instance table so that for
+; registers we can compute the register's name.
+
+(method-make!
+ <operand> 'gen-pretty-name
+ (lambda (self mode)
+ (let* ((name (op:sem-name self))
+ (pname (cond ((string=? "h-memory" (string-take 8 name)) "memory")
+ ((string=? "h-" (string-take 2 name)) (string-drop 2 name))
+ (else name))))
+ (string-append "\"" pname "\"")))
+)
+
+; PC support.
+; This is a subclass of <operand>, used to give the simulator a place to
+; hang a couple of methods.
+; At the moment we only support one pc, a reasonable place to stop for now.
+
+(define <pc> (class-make '<pc> '(<operand>) nil nil))
+
+(method-make!
+ <pc> 'make!
+ (lambda (self)
+ (send-next self 'make! 'pc "program counter"
+ (atlist-parse '(SEM-ONLY) "cgen_operand" "make! of pc")
+ 'h-pc
+ 'DFLT
+ (make <hw-index> 'anonymous
+ 'ifield 'UINT (current-ifld-lookup 'f-nil))
+ nil ; handlers
+ #f #f) ; getter setter
+ self)
+)
+
+; Return a boolean indicating if operand op is the pc.
+; This must not call op:type. op:type will try to resolve a hardware
+; element that may be multiply specified, and this is used in contexts
+; where that's not possible.
+
+(define (pc? op) (class-instance? <pc> op))
+
+; Mode support.
+
+; Create a copy of operand OP in mode NEW-MODE-NAME.
+; If OP has been subclassed the result must contain the complete class
+; (e.g. the behaviour of `object-copy-top').
+
+(define (op:new-mode op new-mode-name)
+ (let ((result (object-copy-top op)))
+ ; (logit 1 "op:new-mode op=" (op:sem-name op)
+ ; " class=" (object-class-name op)
+ ; " hw-name=" (op:hw-name op)
+ ; " mode=" (op:mode op)
+ ; " newmode=" new-mode-name)
+ (if (or (eq? new-mode-name 'DFLT)
+ (eq? new-mode-name 'VOID) ; temporary: for upward compatibility
+ (mode:eq? new-mode-name (op:mode op)))
+ ; Mode isn't changing.
+ result
+ ; See if new mode is supported by the hardware.
+ (if (hw-mode-ok? (op:type op) new-mode-name (op:index op))
+ (let ((new-mode (mode:lookup new-mode-name)))
+ (if (not new-mode)
+ (error "op:new-mode: internal error, bad mode"
+ new-mode-name))
+ (elm-xset! result 'mode new-mode)
+ result)
+ (parse-error "op:new-mode"
+ (string-append "invalid mode for operand `"
+ (obj:name op)
+ "'")
+ new-mode-name))))
+)
+
+; Ifield support.
+
+; Return list of ifields used by OP.
+
+(define (op-iflds-used op)
+ (if (derived-operand? op)
+ (collect op-iflds-used (derived-args op))
+ ; else
+ (let ((indx (op:index op)))
+ (if (and (eq? (hw-index:type indx) 'ifield)
+ (not (= (ifld-length (hw-index:value indx)) 0)))
+ (ifld-needed-iflds (hw-index:value indx))
+ nil)))
+)
+
+; The `hw-index' class.
+; [Was named `index' but that conflicts with the C library function and caused
+; problems when using Hobbit. And `index' is too generic a name anyway.]
+;
+; An operand combines a hardware object with its index.
+; e.g. in an array of registers an operand serves to combine the register bank
+; with the instruction field that chooses which one.
+; Hardware elements are accessed via other means as well besides instruction
+; fields so we need a way to designate something as being an index.
+; The `hw-index' class does that. It serves as a facade to the underlying
+; details.
+; ??? Not sure whether this is the best way to handle this or not.
+;
+; NAME is the name of the index or 'anonymous.
+; This is used, for example, to give a name to the simulator extraction
+; structure member.
+; TYPE is a symbol that indicates what VALUE is.
+; scalar: the hardware object is a scalar, no index is required
+; [MODE and VALUE are #f to denote "undefined" in this case]
+; constant: a (non-negative) integer
+; str-expr: a C expression as a string
+; rtx: an rtx to be expanded
+; ifield: an ifield object
+; operand: an operand object
+; ??? A useful simplification may be to always record the value as an rtx
+; [which may require extensions to rtl so is deferred].
+; ??? We could use runtime type identification, but doing things this way
+; adds more structure.
+;
+; MODE is the mode of VALUE. If DFLT, mode must be obtained from VALUE.
+; DFLT is only allowable for rtx and operand types.
+
+(define <hw-index> (class-make '<hw-index> nil '(name type mode value) nil))
+
+; Accessors.
+; Use obj:name for `name'.
+(define hw-index:type (elm-make-getter <hw-index> 'type))
+(define hw-index:mode (elm-make-getter <hw-index> 'mode))
+(define hw-index:value (elm-make-getter <hw-index> 'value))
+
+; Allow the mode to be specified by its name.
+(method-make!
+ <hw-index> 'make!
+ (lambda (self name type mode value)
+ (elm-set! self 'name name)
+ (elm-set! self 'type type)
+ (elm-set! self 'mode (mode:lookup mode))
+ (elm-set! self 'value value)
+ self)
+)
+
+; get-name handler
+(method-make!
+ <hw-index> 'get-name
+ (lambda (self)
+ (elm-get self 'name))
+)
+
+; get-atlist handler
+(method-make!
+ <hw-index> 'get-atlist
+ (lambda (self)
+ (case (hw-index:type self)
+ ((ifield) (obj-atlist (hw-index:value self)))
+ (else atlist-empty)))
+)
+
+; ??? Until other things settle.
+(method-make!
+ <hw-index> 'field-start
+ (lambda (self word-len)
+ (if (eq? (hw-index:type self) 'ifield)
+ (send (hw-index:value self) 'field-start #f)
+ 0))
+)
+(method-make!
+ <hw-index> 'field-length
+ (lambda (self)
+ (if (eq? (hw-index:type self) 'ifield)
+ (send (hw-index:value self) 'field-length)
+ 0))
+)
+
+; There only ever needs to be one of these objects, so create one.
+
+(define hw-index-scalar
+ ; We can't use `make' here as the make! method calls mode:lookup which
+ ; (a) doesn't exist if we're compiled with Hobbit and mode.scm isn't
+ ; and (b) will fail anyway since #f isn't a valid mode.
+ (let ((scalar-index (new <hw-index>)))
+ (elm-xset! scalar-index 'type 'scalar)
+ (elm-xset! scalar-index 'mode #f)
+ (elm-xset! scalar-index 'value #f)
+ (lambda () scalar-index))
+)
+
+
+; Placeholder for indices of "anyof" operands.
+; There only needs to be one of these, so we create one and always use that.
+
+(define hw-index-anyof
+ ; We can't use `make' here as the make! method calls mode:lookup which
+ ; (a) doesn't exist if we're compiled with Hobbit and mode.scm isn't
+ ; and (b) will fail anyway since #f isn't a valid mode.
+ (let ((anyof-index (new <hw-index>)))
+ (elm-xset! anyof-index 'type 'scalar)
+ (elm-xset! anyof-index 'mode #f)
+ (elm-xset! anyof-index 'value #f)
+ (lambda () anyof-index))
+)
+
+(define hw-index-derived
+ ; We can't use `make' here as the make! method calls mode:lookup which
+ ; (a) doesn't exist if we're compiled with Hobbit and mode.scm isn't
+ ; and (b) will fail anyway since #f isn't a valid mode.
+ (let ((derived-index (new <hw-index>)))
+ (elm-xset! derived-index 'type 'scalar)
+ (elm-xset! derived-index 'mode #f)
+ (elm-xset! derived-index 'value #f)
+ (lambda () derived-index))
+)
+
+
+
+; Hardware selector support.
+;
+; A hardware "selector" is like an index except is along an atypical axis
+; and thus is rarely used. It exists to support things like ASI's on Sparc.
+
+; What to pass to indicate "default selector".
+; (??? value is temporary choice to be revisited).
+(define hw-selector-default '(symbol NONE))
+
+(define (hw-selector-default? sel) (equal? sel hw-selector-default))
+
+; Hardware support.
+
+; Return list of hardware elements refered to in OP-LIST
+; with no duplicates.
+
+(define (op-nub-hw op-list)
+ ; Build a list of hw elements.
+ (let ((hw-list (map (lambda (op)
+ (if (hw-ref? op) ; FIXME: hw-ref? is undefined
+ op
+ (op:type op)))
+ op-list)))
+ ; Now build an alist of (name . obj) elements, take the nub, then the cdr.
+ ; ??? These lists tend to be small so sorting first is probably overkill.
+ (map cdr
+ (alist-nub (alist-sort (map (lambda (hw) (cons (obj:name hw) hw))
+ hw-list)))))
+)
+
+; Parsing support.
+
+; Utility of -operand-parse-[gs]etter to build the expected syntax,
+; for use in error messages.
+
+(define (-operand-g/setter-syntax rank setter?)
+ (string-append "("
+ (string-drop1
+ (numbers->string (iota rank) " index"))
+ (if setter?
+ (if (>= rank 1)
+ " newval"
+ "newval")
+ "")
+ ") (expression)")
+)
+
+; Parse a getter spec.
+; The syntax is (([index-names]) (... code ...)).
+; Omit `index-names' for scalar objects.
+; {rank} is the required number of elements in {index-names}.
+
+(define (-operand-parse-getter context getter rank)
+ (if (null? getter)
+ #f ; use default
+ (let ()
+ (if (or (not (list? getter))
+ (!= (length getter) 2)
+ (not (and (list? (car getter))
+ (= (length (car getter)) rank))))
+ (context-error context
+ (string-append "invalid getter, should be "
+ (-operand-g/setter-syntax rank #f))
+ getter))
+ (if (not (rtx? (cadr getter)))
+ (context-error context "invalid rtx expression" getter))
+ getter))
+)
+
+; Parse a setter spec.
+; The syntax is (([index-names] newval) (... code ...)).
+; Omit `index-names' for scalar objects.
+; {rank} is the required number of elements in {index-names}.
+
+(define (-operand-parse-setter context setter rank)
+ (if (null? setter)
+ #f ; use default
+ (let ()
+ (if (or (not (list? setter))
+ (!= (length setter) 2)
+ (not (and (list? (car setter))
+ (= (+ 1 (length (car setter)) rank)))))
+ (context-error context
+ (string-append "invalid setter, should be "
+ (-operand-g/setter-syntax rank #t))
+ setter))
+ (if (not (rtx? (cadr setter)))
+ (context-error context "invalid rtx expression" setter))
+ setter))
+)
+
+; Parse an operand definition.
+; This is the main routine for building an operand object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+; ??? This only takes insn fields as the index. May need another proc (or an
+; enhancement of this one) that takes other kinds of indices.
+
+(define (-operand-parse errtxt name comment attrs hw mode ifld handlers getter setter)
+ (logit 2 "Processing operand " name " ...\n")
+
+ (let ((name (parse-name name errtxt))
+ (atlist-obj (atlist-parse attrs "cgen_operand" errtxt)))
+
+ (if (keep-atlist? atlist-obj #f)
+
+ (let ((hw-objs (current-hw-sem-lookup hw))
+ (mode-obj (parse-mode-name mode errtxt))
+ (ifld-val (if (integer? ifld)
+ ifld
+ (current-ifld-lookup ifld)))
+ ; FIXME: quick hack
+ (context (context-make-reader errtxt)))
+
+ (if (not mode-obj)
+ (parse-error errtxt "unknown mode" mode))
+ (if (not ifld-val)
+ (parse-error errtxt "unknown insn field" ifld))
+ ; Disallow some obviously invalid numeric indices.
+ (if (and (integer? ifld-val)
+ (< ifld-val 0))
+ (parse-error errtxt "invalid integer index" ifld-val))
+ ; Don't validate HW until we know whether this operand will be kept
+ ; or not. If not, HW may have been discarded too.
+ (if (null? hw-objs)
+ (parse-error errtxt "unknown hardware element" hw))
+
+ ; At this point IFLD-VAL is either an integer or an <ifield> object.
+ ; Since we can't look up the hardware element at this time
+ ; [well, actually we should be able to with a bit of work],
+ ; we determine scalarness from the index.
+ (let* ((scalar? (or (integer? ifld-val) (ifld-nil? ifld-val)))
+ (hw-index
+ (if (integer? ifld-val)
+ (make <hw-index> (symbol-append 'i- name)
+ ; FIXME: constant -> const
+ 'constant 'UINT ifld-val)
+ (if scalar?
+ (hw-index-scalar)
+ (make <hw-index> (symbol-append 'i- name)
+ 'ifield 'UINT ifld-val)))))
+ (make <operand>
+ name
+ (parse-comment comment errtxt)
+ ; Copy FLD's attributes so one needn't duplicate attrs like
+ ; PCREL-ADDR, etc. An operand inherits the attributes of
+ ; its field. They are overridable of course, which is why we use
+ ; `atlist-append' here.
+ (if (integer? ifld-val)
+ atlist-obj
+ (atlist-append atlist-obj (obj-atlist ifld-val)))
+ hw ; note that this is the hw's name, not an object
+ mode ; ditto, this is a name, not an object
+ hw-index
+ (parse-handlers errtxt '(parse print) handlers)
+ (-operand-parse-getter context getter (if scalar? 0 1))
+ (-operand-parse-setter context setter (if scalar? 0 1))
+ )))
+
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read an operand description.
+; This is the main routine for analyzing operands in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -operand-parse is invoked to create the <operand> object.
+
+(define (-operand-read errtxt . arg-list)
+ (let (; Current operand elements:
+ (name nil)
+ (comment nil)
+ (attrs nil)
+ (type nil)
+ (mode 'DFLT) ; use default mode of TYPE
+ (index nil)
+ (handlers nil)
+ (getter nil)
+ (setter nil)
+ )
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((type) (set! type (cadr arg)))
+ ((mode) (set! mode (cadr arg)))
+ ((index) (set! index (cadr arg)))
+ ((handlers) (set! handlers (cdr arg)))
+ ((getter) (set! getter (cdr arg)))
+ ((setter) (set! setter (cdr arg)))
+ (else (parse-error errtxt "invalid operand arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-operand-parse errtxt name comment attrs type mode index handlers
+ getter setter)
+ )
+)
+
+; Define an operand object, name/value pair list version.
+
+(define define-operand
+ (lambda arg-list
+ (let ((op (apply -operand-read (cons "define-operand" arg-list))))
+ (if op
+ (current-op-add! op))
+ op))
+)
+
+; Define an operand object, all arguments specified.
+
+(define (define-full-operand name comment attrs type mode index handlers getter setter)
+ (let ((op (-operand-parse "define-full-operand" name comment attrs
+ type mode index handlers getter setter)))
+ (if op
+ (current-op-add! op))
+ op)
+)
+
+; Derived operands.
+;
+; Derived operands are used to implement operands more complex than just
+; the mapping of an instruction field to a register bank. Their present
+; raison d'etre is to create a new axis on which to implement the complex
+; addressing modes of the i386 and m68k. The brute force way of describing
+; these instruction sets would be to have one `dni' per addressing mode
+; per instruction. What's needed is to abstract away the various addressing
+; modes within something like operands.
+;
+; ??? While internally we end up with the "brute force" approach, in and of
+; itself that's ok because it's an internal implementation issue.
+; See <multi-insn>.
+;
+; ??? Another way to go is to have one dni per addressing mode. That seems
+; less clean though as one dni would be any of add, sub, and, or, xor, etc.
+;
+; ??? Some addressing modes have side-effects (e.g. pre-dec, etc. like insns).
+; This can be represented, but if two operands have side-effects special
+; trickery may be required to get the order of side-effects right. Need to
+; avoid any "trickery" at all.
+;
+; ??? Not yet handled are modelling parameters.
+; ??? Not yet handled are the handlers,getter,setter spec of normal operands.
+;
+; ??? Division of class members b/w <operand> and <derived-operand> is wip.
+; ??? As is potential introduction of other classes to properly organize
+; things.
+
+(define <derived-operand>
+ (class-make '<derived-operand>
+ '(<operand>)
+ '(
+ ; Args (list of <operands> objects).
+ args
+
+ ; Syntax string.
+ syntax
+
+ ; Base ifield, common to all choices.
+ ; ??? experiment
+ base-ifield
+
+ ; <derived-ifield> object.
+ encoding
+
+ ; Assertions of any ifield values or #f if none.
+ (ifield-assertion . #f)
+ )
+ ())
+)
+
+(method-make-make! <derived-operand>
+ '(name comment attrs mode
+ args syntax base-ifield encoding ifield-assertion
+ getter setter)
+)
+
+(define (derived-operand? x) (class-instance? <derived-operand> x))
+
+(define-getters <derived-operand> derived
+ (args syntax base-ifield encoding ifield-assertion)
+)
+
+; "anyof" operands are subclassed from derived operands.
+; They typically handle multiple addressing modes of CISC architectures.
+
+(define <anyof-operand>
+ (class-make '<anyof-operand>
+ '(<operand>)
+ '(
+ ; Base ifield, common to all choices.
+ ; FIXME: wip
+ base-ifield
+
+ ; List of <derived-operand> objects.
+ ; ??? Maybe allow <operand>'s too?
+ choices
+ )
+ ())
+)
+
+(define (anyof-operand? x) (class-instance? <anyof-operand> x))
+
+(method-make!
+ <anyof-operand> 'make!
+ (lambda (self name comment attrs mode base-ifield choices)
+ (elm-set! self 'name name)
+ (elm-set! self 'comment comment)
+ (elm-set! self 'attrs attrs)
+ (elm-set! self 'mode-name mode)
+ (elm-set! self 'base-ifield base-ifield)
+ (elm-set! self 'choices choices)
+ ; Set index to a special marker value.
+ (elm-set! self 'index (hw-index-anyof))
+ self)
+)
+
+(define-getters <anyof-operand> anyof (choices))
+
+; Derived/Anyof parsing support.
+
+; Subroutine of -derived-operand-parse to parse the encoding.
+; The result is a <derived-ifield> object.
+; The {owner} member still needs to be set!
+
+(define (-derived-parse-encoding context operand-name encoding)
+ (if (or (null? encoding)
+ (not (list? encoding)))
+ (context-error context "encoding not a list" encoding))
+ (if (not (eq? (car encoding) '+))
+ (context-error context "encoding must begin with `+'" encoding))
+
+ ; ??? Calling -parse-insn-format is a quick hack.
+ ; It's an internal routine of some other file.
+ (let ((iflds (-parse-insn-format "anyof encoding" encoding)))
+ (make <derived-ifield>
+ operand-name
+ (string-append "<derived-ifield> for " operand-name)
+ atlist-empty
+ #f ; owner
+ iflds ; subfields
+ ))
+)
+
+; Subroutine of -derived-operand-parse to parse the ifield assertion.
+; The ifield assertion is either () or an RTL expression asserting something
+; about the ifield values of the containing insn.
+; Operands are specified by name, but what is used is their indices (there's
+; an implicit `index-of' going on).
+
+(define (-derived-parse-ifield-assertion context args ifield-assertion)
+ ; FIXME: for now
+ (if (null? ifield-assertion)
+ #f
+ ifield-assertion)
+)
+
+; Parse a derived operand definition.
+; This is the main routine for building a derived operand object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+;
+; ??? Currently no support for handlers(,???) found in normal operands.
+; Later, when necessary.
+
+(define (-derived-operand-parse errtxt name comment attrs mode
+ args syntax
+ base-ifield encoding ifield-assertion
+ getter setter)
+ (logit 2 "Processing derived operand " name " ...\n")
+
+ (let ((name (parse-name name errtxt))
+ (atlist-obj (atlist-parse attrs "cgen_operand" errtxt)))
+
+ (if (keep-atlist? atlist-obj #f)
+
+ (let* ((mode-obj (parse-mode-name mode errtxt))
+ ; FIXME: quick hack
+ (context (context-make-reader errtxt))
+ (parsed-encoding (-derived-parse-encoding context name encoding))
+ )
+ (if (not mode-obj)
+ (parse-error errtxt "unknown mode" mode))
+
+ (let ((result
+ (make <derived-operand>
+ name
+ (parse-comment comment errtxt)
+ atlist-obj
+ mode-obj
+ (map (lambda (a)
+ (if (not (symbol? a))
+ (parse-error errtxt "arg not a symbol" a))
+ (let ((op (current-op-lookup a)))
+ (if (not op)
+ (parse-error errtxt "not an operand" a))
+ op))
+ args)
+ syntax
+ base-ifield ; FIXME: validate
+ parsed-encoding
+ (-derived-parse-ifield-assertion context args ifield-assertion)
+ (if (null? getter)
+ #f
+ (-operand-parse-getter context
+ (list args
+ (rtx-canonicalize context getter))
+ (length args)))
+ (if (null? setter)
+ #f
+ (-operand-parse-setter context
+ (list (append args '(newval))
+ (rtx-canonicalize context setter))
+ (length args)))
+ )))
+ (elm-set! result 'hw-name (obj:name (hardware-for-mode mode-obj)))
+ (elm-set! result 'index parsed-encoding)
+ ; (elm-set! result 'index (hw-index-derived)) ; A temporary dummy
+ (logit 1 "new derived-operand; name=" name " hw-name= " (op:hw-name result)
+ " index=" (obj:name parsed-encoding) "\n")
+ (derived-ifield-set-owner! parsed-encoding result)
+ result))
+
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read a derived operand description.
+; This is the main routine for analyzing derived operands in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -derived-operand-parse is invoked to create the <derived-operand> object.
+
+(define (-derived-operand-read errtxt . arg-list)
+ (let (; Current derived-operand elements:
+ (name nil)
+ (comment nil)
+ (attrs nil)
+ (mode 'DFLT) ; use default mode of TYPE
+ (args nil)
+ (syntax nil)
+ (base-ifield nil)
+ (encoding nil)
+ (ifield-assertion nil)
+ (getter nil)
+ (setter nil)
+ )
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((mode) (set! mode (cadr arg)))
+ ((args) (set! args (cadr arg)))
+ ((syntax) (set! syntax (cadr arg)))
+ ((base-ifield) (set! base-ifield (cadr arg)))
+ ((encoding) (set! encoding (cadr arg)))
+ ((ifield-assertion) (set! ifield-assertion (cadr arg)))
+ ((getter) (set! getter (cadr arg)))
+ ((setter) (set! setter (cadr arg)))
+ (else (parse-error errtxt "invalid derived-operand arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-derived-operand-parse errtxt name comment attrs mode args
+ syntax base-ifield encoding ifield-assertion
+ getter setter)
+ )
+)
+
+; Define a derived operand object, name/value pair list version.
+
+(define define-derived-operand
+ (lambda arg-list
+ (let ((op (apply -derived-operand-read
+ (cons "define-derived-operand" arg-list))))
+ (if op
+ (current-op-add! op))
+ op))
+)
+
+; Define a derived operand object, all arguments specified.
+; ??? Not supported (yet).
+;
+;(define (define-full-derived-operand name comment attrs mode ...)
+; (let ((op (-derived-operand-parse "define-full-derived-operand"
+; name comment attrs
+; mode ...)))
+; (if op
+; (current-op-add! op))
+; op)
+;)
+
+; Parse an "anyof" choice, which is a derived-operand name.
+; The result is {choice} unchanged.
+
+(define (-anyof-parse-choice context choice)
+ (if (not (symbol? choice))
+ (context-error context "anyof choice not a symbol" choice))
+ (let ((op (current-op-lookup choice)))
+ (if (not (derived-operand? op))
+ (context-error context "anyof choice not a derived-operand" choice))
+ op)
+)
+
+; Parse an "anyof" derived operand.
+; This is the main routine for building a derived operand object from a
+; description in the .cpu file.
+; All arguments are in raw (non-evaluated) form.
+; The result is the parsed object or #f if object isn't for selected mach(s).
+;
+; ??? Currently no support for handlers(,???) found in normal operands.
+; Later, when necessary.
+
+(define (-anyof-operand-parse errtxt name comment attrs mode
+ base-ifield choices)
+ (logit 2 "Processing anyof operand " name " ...\n")
+
+ (let ((name (parse-name name errtxt))
+ (atlist-obj (atlist-parse attrs "cgen_operand" errtxt)))
+
+ (if (keep-atlist? atlist-obj #f)
+
+ (let ((mode-obj (parse-mode-name mode errtxt))
+ ; FIXME: quick hack
+ (context (context-make-reader errtxt)))
+ (if (not mode-obj)
+ (parse-error errtxt "unknown mode" mode))
+
+ (make <anyof-operand>
+ name
+ (parse-comment comment errtxt)
+ atlist-obj
+ mode
+ base-ifield
+ (map (lambda (c)
+ (-anyof-parse-choice context c))
+ choices)))
+
+ (begin
+ (logit 2 "Ignoring " name ".\n")
+ #f)))
+)
+
+; Read an anyof operand description.
+; This is the main routine for analyzing anyof operands in the .cpu file.
+; ERRTXT is prepended to error messages to provide context.
+; ARG-LIST is an associative list of field name and field value.
+; -anyof-operand-parse is invoked to create the <anyof-operand> object.
+
+(define (-anyof-operand-read errtxt . arg-list)
+ (let (; Current operand elements:
+ (name nil)
+ (comment nil)
+ (attrs nil)
+ (mode 'DFLT) ; use default mode of TYPE
+ (base-ifield nil)
+ (choices nil)
+ )
+ (let loop ((arg-list arg-list))
+ (if (null? arg-list)
+ nil
+ (let ((arg (car arg-list))
+ (elm-name (caar arg-list)))
+ (case elm-name
+ ((name) (set! name (cadr arg)))
+ ((comment) (set! comment (cadr arg)))
+ ((attrs) (set! attrs (cdr arg)))
+ ((mode) (set! mode (cadr arg)))
+ ((base-ifield) (set! base-ifield (cadr arg)))
+ ((choices) (set! choices (cdr arg)))
+ (else (parse-error errtxt "invalid anyof-operand arg" arg)))
+ (loop (cdr arg-list)))))
+ ; Now that we've identified the elements, build the object.
+ (-anyof-operand-parse errtxt name comment attrs mode base-ifield choices)
+ )
+)
+
+; Define an anyof operand object, name/value pair list version.
+
+(define define-anyof-operand
+ (lambda arg-list
+ (let ((op (apply -anyof-operand-read
+ (cons "define-anyof-operand" arg-list))))
+ (if op
+ (current-op-add! op))
+ op))
+)
+
+; Utilities to flatten out the <anyof-operand> derivation heirarchy.
+
+; Utility class used when instantiating insns with derived operands.
+; This collects together in one place all the appropriate data of an
+; instantiated "anyof" operand.
+
+(define <anyof-instance>
+ (class-make '<anyof-instance>
+ '(<derived-operand>)
+ '(
+ ; <anyof-operand> object we were instantiated from.
+ parent
+ )
+ nil)
+)
+
+(method-make-make! <anyof-instance>
+ '(name comment attrs mode
+ args syntax base-ifield encoding ifield-assertion
+ getter setter parent)
+)
+
+(define-getters <anyof-instance> anyof-instance (parent))
+
+(define (anyof-instance? x) (class-instance? <anyof-instance> x))
+
+; Return initial list of known ifield values in {anyof-instance}.
+
+(define (-anyof-initial-known anyof-instance)
+ (assert (derived-operand? anyof-instance))
+ (let ((encoding (derived-encoding anyof-instance)))
+ (assert (derived-ifield? encoding))
+ (ifld-known-values (derived-ifield-subfields encoding)))
+)
+
+; Return true if {anyof-instance} satisfies its ifield assertions.
+; {known-values} is the {known} argument to rtx-solve.
+
+(define (anyof-satisfies-assertions? anyof-instance known-values)
+ (assert (derived-operand? anyof-instance))
+ (let ((assertion (derived-ifield-assertion anyof-instance)))
+ (if assertion
+ (rtx-solve #f ; FIXME: context
+ anyof-instance ; owner
+ assertion
+ known-values)
+ #t))
+)
+
+; Subroutine of -anyof-merge-subchoices.
+; Merge syntaxes of VALUE-NAMES/VALUES into SYNTAX.
+;
+; Example:
+; If SYNTAX is "$a+$b", and VALUE-NAMES is (b), and VALUES is
+; ("$c+$d"-object), then return "$a+$c+$d".
+
+(define (-anyof-syntax anyof-instance)
+ (elm-get anyof-instance 'syntax)
+)
+
+(define (-anyof-name anyof-instance)
+ (elm-get anyof-instance 'name)
+)
+
+
+(define (-anyof-merge-syntax syntax value-names values)
+ (let ((syntax-elements (syntax-break-out syntax)))
+ (syntax-make (map (lambda (e)
+ (if (anyof-operand? e)
+ (let* ((name (obj:name e))
+ (indx (element-lookup-index name value-names 0)))
+ (assert indx)
+ (-anyof-syntax (list-ref values indx)))
+ e))
+ syntax-elements)))
+)
+
+; Subroutine of -anyof-merge-subchoices.
+; Merge syntaxes of {value-names}/{values} into <derived-ifield> {encoding}.
+; The result is a new <derived-ifield> object with subfields matching
+; {value-names} replaced with {values}.
+; {container} is the containing <anyof-operand>.
+;
+; Example:
+; If {encoding} is (a-ifield-object b-anyof-ifield-object), and {value-names}
+; is (b), and {values} is (c-choice-of-b-object), then return
+; (a-ifield-object c-choice-of-b-ifield-object).
+
+(define (-anyof-merge-encoding container encoding value-names values)
+ (assert (derived-ifield? encoding))
+ (let ((subfields (derived-ifield-subfields encoding))
+ (result (object-copy-top encoding)))
+ ; Delete all the elements that are being replaced with ifields from
+ ; {values} and add the new ifields.
+ (derived-ifield-set-subfields! result
+ (append
+ (find (lambda (f)
+ (not (memq (obj:name f) value-names)))
+ subfields)
+ (map derived-encoding values)))
+ result)
+)
+
+; Subroutine of -anyof-merge-subchoices.
+; Merge semantics of VALUE-NAMES/VALUES into GETTER.
+;
+; Example:
+; If GETTER is (mem QI foo), and VALUE-NAMES is (foo), and VALUES is
+; ((add a b)-object), then return (mem QI (add a b)).
+
+(define (-anyof-merge-getter getter value-names values)
+ ;(debug-repl-env getter value-names values)
+ ; ??? This implementation is a quick hack, intended to evolve or be replaced.
+ (cond ((not getter)
+ #f)
+ (else
+ (map (lambda (e)
+ (cond ((symbol? e)
+ (let ((indx (element-lookup-index e value-names 0)))
+ (if indx
+ (op:getter (list-ref values indx))
+ e)))
+ ((pair? e) ; pair? -> cheap non-null-list?
+ (-anyof-merge-getter e value-names values))
+ (else
+ e)))
+ getter)))
+)
+
+; Subroutine of -anyof-merge-subchoices.
+; Merge semantics of VALUE-NAMES/VALUES into SETTER.
+;
+; Example:
+; If SETTER is (set (mem QI foo) newval), and VALUE-NAMES is (foo),
+; and VALUES is ((add a b)-object), then return
+; (set (mem QI (add a b)) newval).
+;
+; ??? `newval' in this context is a reserved word.
+
+(define (-anyof-merge-setter setter value-names values)
+ ;(debug-repl-env setter value-names values)
+ ; ??? This implementation is a quick hack, intended to evolve or be replaced.
+ (cond ((not setter)
+ #f)
+ ((rtx-single-set? setter)
+ (let ((src (rtx-set-src setter))
+ (dest (rtx-set-dest setter))
+ (mode (rtx-mode setter))
+ (options (rtx-options setter)))
+ (if (rtx-kind 'mem dest)
+ (set! dest
+ (rtx-change-address dest
+ (-anyof-merge-getter
+ (rtx-mem-addr dest)
+ value-names values))))
+ (set! src (-anyof-merge-getter src value-names values))
+ (rtx-make 'set options mode dest src)))
+ (else
+ (error "-anyof-merge-setter: unsupported form" (car setter))))
+)
+
+; Subroutine of -sub-insn-make!.
+; Merge semantics of VALUE-NAMES/VALUES into SEMANTICS.
+; Defined here and not in insn.scm to keep it with the getter/setter mergers.
+;
+; Example:
+; If SEMANTICS is (mem QI foo), and VALUE-NAMES is (foo), and VALUES is
+; ((add a b)-object), then return (mem QI (add a b)).
+
+(define (anyof-merge-semantics semantics value-names values)
+ ;(debug-repl-env semantics value-names values)
+ ; ??? This implementation is a quick hack, intended to evolve or be replaced.
+ (let ((result
+ (cond ((not semantics)
+ #f)
+ (else
+ (map (lambda (e)
+ (cond ((symbol? e)
+ (let ((indx (element-lookup-index e value-names 0)))
+ (if indx
+ (-anyof-name (list-ref values indx))
+ ; (op:sem-name (list-ref values indx))
+ e)))
+ ((pair? e) ; pair? -> cheap non-null-list?
+ (anyof-merge-semantics e value-names values))
+ (else
+ e)))
+ semantics)))))
+ (logit 4 "Merged semantics [" semantics "] -> [" result "]\n")
+ result)
+)
+
+; Subroutine of -anyof-merge-subchoices.
+; Merge assertion of VALUE-NAMES/VALUES into ASSERTION.
+;
+; Example:
+; If ASSERTION is (ne f-base-reg 5), and VALUE-NAMES is
+; (foo), and VALUES is ((ne f-mod 0)), then return
+; (andif (ne f-base-reg 5) (ne f-mod 0)).
+;
+; FIXME: Perform simplification pass, based on combined set of known
+; ifield values.
+
+(define (-anyof-merge-ifield-assertion assertion value-names values)
+ (let ((assertions (find identity
+ (cons assertion
+ (map derived-ifield-assertion values)))))
+ (if (null? assertions)
+ #f
+ (rtx-combine 'andif assertions)))
+)
+
+; Subroutine of -anyof-all-subchoices.
+; Return a copy of <derived-operand> CHOICE with NEW-ARGS from ANYOF-ARGS
+; merged in. This is for when a derived operand is itself composed of
+; anyof operands.
+; ANYOF-ARGS is a list of <anyof-operand>'s to be replaced in CHOICE.
+; NEW-ARGS is a corresponding list of values (<derived-operands>'s) of each
+; element in ANYOF-ARGS.
+; CONTAINER is the <anyof-operand> containing CHOICE.
+
+(define (-anyof-merge-subchoices container choice anyof-args new-args)
+ (assert (all-true? (map anyof-operand? anyof-args)))
+ (assert (all-true? (map derived-operand? new-args)))
+
+ (let* ((arg-names (map obj:name anyof-args))
+ (encoding (-anyof-merge-encoding container (derived-encoding choice)
+ arg-names new-args))
+ (result
+ (make <anyof-instance>
+ (apply symbol-append
+ (cons (obj:name choice)
+ (map (lambda (anyof)
+ (symbol-append '- (obj:name anyof)))
+ new-args)))
+ (obj:comment choice)
+ (obj-atlist choice)
+ (op:mode choice)
+ (derived-args choice)
+ (-anyof-merge-syntax (derived-syntax choice)
+ arg-names new-args)
+ (derived-base-ifield choice)
+ encoding
+ (-anyof-merge-ifield-assertion (derived-ifield-assertion choice)
+ anyof-args new-args)
+ (-anyof-merge-getter (op:getter choice)
+ arg-names new-args)
+ (-anyof-merge-setter (op:setter choice)
+ arg-names new-args)
+ container)))
+ ;
+ (elm-set! result 'index encoding)
+ ; Creating the link from {encoding} to {result}.
+ (derived-ifield-set-owner! encoding result)
+ result)
+)
+
+; Subroutine of -anyof-all-choices-1.
+; Return a list of all possible subchoices of <derived-operand> ANYOF-CHOICE,
+; known to use <anyof-operand>'s itself.
+; CONTAINER is the containing <anyof-operand>.
+
+(define (-anyof-all-subchoices container anyof-choice)
+ ; Split args into anyof and non-anyof elements.
+ (let* ((args (derived-args anyof-choice))
+ (anyof-args (find anyof-operand? args)))
+
+ (assert (not (null? anyof-args)))
+
+ ; Iterate over all combinations.
+ ; {todo} is a list with one element for each anyof argument.
+ ; Each element is in turn a list of all <derived-operand> choices for the
+ ; <anyof-operand>. The result we want is every possible combination.
+ ; Example:
+ ; If {todo} is ((1 2 3) (a) (B C)) the result we want is
+ ; ((1 a B) (1 a C) (2 a B) (2 a C) (3 a B) (3 a C)).
+ ;
+ ; Note that some of these values may be derived from nested
+ ; <anyof-operand>'s which is why we recursively call -anyof-all-choices-1.
+ ; ??? -anyof-all-choices-1 should cache the results.
+
+ (let* ((todo (map -anyof-all-choices-1 anyof-args))
+ (lengths (map length todo))
+ (total (apply * lengths))
+ (result nil))
+
+ ; ??? One might prefer a `do' loop here, but every time I see one I
+ ; have to spend too long remembering its syntax.
+ (let loop ((i 0))
+ (if (< i total)
+ (let* ((indices (split-value lengths i))
+ (new-args (map list-ref todo indices)))
+ ;(display "new-args: " (current-error-port))
+ ;(display (map obj:name new-args) (current-error-port))
+ ;(newline (current-error-port))
+ (set! result
+ (cons (-anyof-merge-subchoices container
+ anyof-choice
+ anyof-args
+ new-args)
+ result))
+ (loop (+ i 1)))))
+
+ result))
+)
+
+; Return an <anyof-instance> object from <derived-operand> {derop}, which is a
+; choice of {anyof-operand}.
+
+(define (-anyof-instance-from-derived anyof-operand derop)
+ (let* ((encoding (object-copy-top (derived-encoding derop)))
+ (result
+ (make <anyof-instance>
+ (obj:name derop)
+ (obj:comment derop)
+ (obj-atlist derop)
+ (op:mode derop)
+ (derived-args derop)
+ (derived-syntax derop)
+ (derived-base-ifield derop)
+ encoding
+ (derived-ifield-assertion derop)
+ (op:getter derop)
+ (op:setter derop)
+ anyof-operand)))
+ ; Creating the link from {encoding} to {result}.
+ (derived-ifield-set-owner! encoding result)
+ result)
+)
+
+; Return list of <anyof-instance> objects, one for each possible variant of
+; ANYOF-OPERAND.
+;
+; One could move this up into the cpu description file using pmacros.
+; However, that's not the right way to go. How we currently implement
+; the notion of derived operands is separate from the notion of having them
+; in the description language. pmacros are not "in" the language (to the
+; extent that the cpu description file reader "sees" them), they live
+; above it. And the right way to do this is with something "in" the language.
+; Derived operands are the first cut at it. They'll evolve or be replaced
+; (and it's the implementation of them that will evolve first).
+
+(define (-anyof-all-choices-1 anyof-operand)
+ (assert (anyof-operand? anyof-operand))
+
+ (let ((result nil))
+
+ ; For each choice, scan the operands for further derived operands.
+ ; If found, replace the choice with the list of its subchoices.
+ ; If not found, create an <anyof-instance> object for it. This is basically
+ ; just a copy of the object, but {anyof-operand} is recorded with it so
+ ; that we can later resolve `follows' specs.
+
+ (let loop ((choices (anyof-choices anyof-operand)))
+ (if (not (null? choices))
+ (let* ((this (car choices))
+ (args (derived-args this)))
+
+ (if (any-true? (map anyof-operand? args))
+
+ ; This operand has "anyof" operands so we need to turn this
+ ; choice into a list of all possible subchoices.
+ (let ((subchoices (-anyof-all-subchoices anyof-operand this)))
+ (set! result
+ (append subchoices result)))
+
+ ; No <anyof-operand> arguments.
+ (set! result
+ (cons (-anyof-instance-from-derived anyof-operand this)
+ result)))
+
+ (loop (cdr choices)))))
+
+ (assert (all-true? (map anyof-instance? result)))
+ result)
+)
+
+; Cover fn of -anyof-all-choices-1.
+; Return list of <anyof-instance> objects, one for each possible variant of
+; ANYOF-OPERAND.
+; We want to delete choices that fail their ifield assertions, but since
+; -anyof-all-choices-1 can recursively call itself, assertion checking is
+; defered until it returns.
+
+(define (anyof-all-choices anyof-operand)
+ (let ((all-choices (-anyof-all-choices-1 anyof-operand)))
+
+ ; Delete ones that fail their ifield assertions.
+ ; Sometimes there isn't enough information yet to completely do this.
+ ; When that happens it is the caller's responsibility to deal with it.
+ ; However, it is our responsibility to assert as much as we can.
+ (find (lambda (op)
+ (anyof-satisfies-assertions? op
+ (-anyof-initial-known op)))
+ all-choices))
+)
+
+; Operand utilities.
+
+; Look up operand NAME in the operand table.
+; This proc isolates the strategy we use to record operand objects.
+
+; Look up an operand via SEM-NAME.
+
+(define (op:lookup-sem-name op-list sem-name)
+ (let loop ((op-list op-list))
+ (cond ((null? op-list) #f)
+ ((eq? sem-name (op:sem-name (car op-list))) (car op-list))
+ (else (loop (cdr op-list)))))
+)
+
+; Given an operand, return the starting bit number.
+; Note that the field isn't necessarily contiguous.
+
+(define (op:start operand) (send operand 'field-start #f))
+
+; Given an operand, return the total length in bits.
+; Note that the field isn't necessarily contiguous.
+
+(define (op:length operand) (send operand 'field-length))
+
+; Return the nub of a list of operands, base on their names.
+
+(define (op-nub op-list)
+ (nub op-list obj:name)
+)
+
+; Return a sorted list of operand lists.
+; Each element in the inner list is an operand with the same name, but for
+; whatever reason were defined separately.
+; The outer list is sorted by name.
+
+(define (op-sort op-list)
+ ; We assume there is at least one operand.
+ (if (null? op-list)
+ (error "op-sort: no operands!"))
+ ; First sort by name.
+ (let ((sorted-ops (sort op-list
+ (lambda (a b)
+ (string<? (obj:name a) (obj:name b)))))
+ )
+ (let loop ((result nil)
+ ; Current set of operands with same name.
+ (this-elm (list (car sorted-ops)))
+ (ops (cdr sorted-ops))
+ )
+ (if (null? ops)
+ ; Reverse things to keep them in file order (minimizes random
+ ; changes in generated files).
+ (reverse! (cons (reverse! this-elm) result))
+ ; Not done. Check for new set.
+ (if (eq? (obj:name (car ops)) (obj:name (car this-elm)))
+ (loop result (cons (car ops) this-elm) (cdr ops))
+ (loop (cons (reverse! this-elm) result) (list (car ops))
+ (cdr ops))))))
+)
+
+; FIXME: Not used anymore but leave in for now.
+; Objects used in assembler syntax ($0, $1, ...).
+;
+;(define <syntax-operand>
+; (class-make '<syntax-operand> nil '(number value) nil))
+;(method-make-make! <syntax-operand> '(number))
+;
+;(define $0 (make <syntax-operand> 0))
+;(define $1 (make <syntax-operand> 1))
+;(define $2 (make <syntax-operand> 2))
+;(define $3 (make <syntax-operand> 3))
+
+; Called before/after loading the .cpu file to initialize/finalize.
+
+; Builtins.
+; The pc operand used in rtl expressions.
+(define pc nil)
+
+; Called before reading a .cpu file in.
+
+(define (operand-init!)
+ (reader-add-command! 'define-operand
+ "\
+Define an operand, name/value pair list version.
+"
+ nil 'arg-list define-operand)
+ (reader-add-command! 'define-full-operand
+ "\
+Define an operand, all arguments specified.
+"
+ nil '(name comment attrs hw-type mode hw-index handlers getter setter)
+ define-full-operand)
+
+ (reader-add-command! 'define-derived-operand
+ "\
+Define a derived operand, name/value pair list version.
+"
+ nil 'arg-list define-derived-operand)
+
+ (reader-add-command! 'define-anyof-operand
+ "\
+Define an anyof operand, name/value pair list version.
+"
+ nil 'arg-list define-anyof-operand)
+
+ *UNSPECIFIED*
+)
+
+; Install builtin operands.
+
+(define (operand-builtin!)
+ ; Standard operand attributes.
+ ; ??? Some of these can be combined into one.
+
+ (define-attr '(for operand) '(type boolean) '(name NEGATIVE)
+ '(comment "value is negative"))
+ (define-attr '(for operand) '(type boolean) '(name RELAX)
+ '(comment "operand is relaxable"))
+
+ ; ??? Might be able to make SEM-ONLY go away (or machine compute it)
+ ; by scanning which operands are refered to by the insn syntax strings.
+ (define-attr '(for operand) '(type boolean) '(name SEM-ONLY)
+ '(comment "operand is for semantic use only"))
+
+ ; Also (defined elsewhere): PCREL-ADDR ABS-ADDR.
+
+ (set! pc (make <pc>))
+ (current-op-add! pc)
+
+ *UNSPECIFIED*
+)
+
+; Called after a .cpu file has been read in.
+
+(define (operand-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/pgmr-tools.scm b/cgen/pgmr-tools.scm
new file mode 100644
index 00000000000..c945aea7577
--- /dev/null
+++ b/cgen/pgmr-tools.scm
@@ -0,0 +1,183 @@
+; Programmer development tools.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+;
+; This file contains a collection of programmer debugging tools.
+; They're mainly intended for using cgen to debug other things,
+; but any kind of debugging tool can go here.
+; All routines require the application independent part of cgen to be loaded
+; and the .cpu file to be loaded. They do not require any particular
+; application though (opcodes, simulator, etc.). If they do, that's a bug.
+; It may be that the appication has a generally useful routine that should
+; live elsewhere, but that's it.
+;
+; These tools don't have to be particularily efficient (within reason).
+; It's more important that they be simple and clear.
+;
+; Some tools require ifmt-compute! to be run.
+; They will run it if necessary.
+;
+; Table of contents:
+;
+; pgmr-pretty-print-insn-format
+; cgen debugging tool, pretty prints the iformat of an <insn> object
+;
+; pgmr-pretty-print-insn-value
+; break out an instruction's value into its component fields
+;
+; pgmr-lookup-insn
+; given a random bit pattern for an instruction, lookup the insn and return
+; its <insn> object
+
+; Pretty print the instruction's opcode value, for debugging.
+; INSN is an <insn> object.
+
+(define (pgmr-pretty-print-insn-format insn)
+
+ (define (to-width width n-str)
+ (string-take-with-filler (- width)
+ n-str
+ #\0))
+
+ (define (dump-insn-mask mask insn-length)
+ (string-append "0x" (to-width (quotient insn-length 4)
+ (number->string mask 16))
+ ", "
+ (string-map
+ (lambda (n)
+ (string-append " " (to-width 4 (number->string n 2))))
+ (reverse
+ (split-bits (make-list (quotient insn-length 4) 4)
+ mask)))))
+
+ ; Print VALUE with digits not in MASK printed as "X".
+ (define (dump-insn-value value mask insn-length)
+ (string-append "0x" (to-width (quotient insn-length 4)
+ (number->string value 16))
+ ", "
+ (string-map
+ (lambda (n mask)
+ (string-append
+ " "
+ (list->string
+ (map (lambda (char in-mask?)
+ (if in-mask? char #\X))
+ (string->list (to-width 4 (number->string n 2)))
+ (bits->bools mask 4)))))
+ (reverse
+ (split-bits (make-list (quotient insn-length 4) 4)
+ value))
+ (reverse
+ (split-bits (make-list (quotient insn-length 4) 4)
+ mask)))))
+
+ (define (dump-ifield f)
+ (string-append " Name: "
+ (obj:name f)
+ ", "
+ "Start: "
+ (number->string
+ (+ (bitrange-word-offset (-ifld-bitrange f))
+ (bitrange-start (-ifld-bitrange f))))
+ ", "
+ "Length: "
+ (number->string (ifld-length f))
+ "\n"))
+
+ (let* ((iflds (sort-ifield-list (insn-iflds insn)
+ (not (current-arch-insn-lsb0?))))
+ (mask (compute-insn-base-mask iflds))
+ (mask-length (compute-insn-base-mask-length iflds)))
+
+ (display
+ (string-append
+ "Instruction: " (obj:name insn)
+ "\n"
+ "Syntax: "
+ (insn-syntax insn)
+ "\n"
+ "Fields:\n"
+ (string-map dump-ifield iflds)
+ "Instruction length (computed from ifield list): "
+ (number->string (apply + (map ifld-length iflds)))
+ "\n"
+ "Mask: "
+ (dump-insn-mask mask mask-length)
+ "\n"
+ "Value: "
+ (let ((value (apply +
+ (map (lambda (fld)
+ (ifld-value fld mask-length
+ (ifld-get-value fld)))
+ (find ifld-constant? (collect ifld-base-ifields (insn-iflds insn)))))))
+ (dump-insn-value value mask mask-length))
+ ; TODO: Print value spaced according to fields.
+ "\n"
+ )))
+)
+
+; Pretty print an instruction's value.
+
+(define (pgmr-pretty-print-insn-value insn value)
+ (define (dump-ifield ifld value name-width)
+ (string-append
+ (string-take name-width (obj:name ifld))
+ ": "
+ (number->string value)
+ ", 0x"
+ (number->hex value)
+ "\n"))
+
+ (let ((ifld-values (map (lambda (ifld)
+ (ifld-extract ifld insn value))
+ (insn-iflds insn)))
+ (max-name-length (apply max
+ (map string-length
+ (map obj:name
+ (insn-iflds insn)))))
+ )
+
+ (display
+ (string-append
+ "Instruction: " (obj:name insn)
+ "\n"
+ "Fields:\n"
+ (string-map (lambda (ifld value)
+ (dump-ifield ifld value max-name-length))
+ (insn-iflds insn)
+ ifld-values)
+ )))
+)
+
+; Return the <insn> object matching VALUE.
+; VALUE is either a single number of size base-insn-bitsize,
+; or a list of numbers for variable length ISAs.
+; LENGTH is the total length of VALUE in bits.
+
+(define (pgmr-lookup-insn length value)
+ (arch-analyze-insns! CURRENT-ARCH
+ #t ; include aliases
+ #f) ; don't need to analyze semantics
+
+ ; Return a boolean indicating if BASE matches the base part of <insn> INSN.
+ (define (match-base base insn)
+ (let ((mask (compute-insn-base-mask (insn-iflds insn)))
+ (ivalue (insn-value insn)))
+ ; return (value & mask) == ivalue
+ (= (logand base mask) ivalue)))
+
+ (define (match-rest value insn)
+ #t)
+
+ (let ((base (if (list? value) (car value) value)))
+ (let loop ((insns (current-insn-list)))
+ (if (null? insns)
+ #f
+ (let ((insn (car insns)))
+ (if (and (= length (insn-length insn))
+ (match-base base insn)
+ (match-rest value insn))
+ insn
+ (loop (cdr insns)))))))
+)
diff --git a/cgen/play.cpu b/cgen/play.cpu
new file mode 100644
index 00000000000..3ef3775f22a
--- /dev/null
+++ b/cgen/play.cpu
@@ -0,0 +1,265 @@
+; cpu description for debugging and experimental purposes. -*- Scheme -*-
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+; Copyright (C) 2000 Red Hat, Inc.
+;
+; This file is for experimental purposes. Don't expect it to be correct
+; or up to date.
+
+(include "simplify.inc")
+
+(define-arch
+ (name play) ; name of cpu
+ (comment "experimental .cpu file")
+ (insn-lsb0? #f)
+ (machs playb)
+ (isas play)
+)
+
+(define-isa
+ (name play)
+ (base-insn-bitsize 16)
+ (decode-assist (0 1 2 3))
+)
+
+(define-cpu
+ (name cpuf)
+ (comment "experimental cpu family")
+ (endian little)
+ (word-bitsize 32)
+)
+
+(define-mach
+ (name playb)
+ (comment "experimental mach")
+ (cpu cpuf)
+)
+
+(define-model
+ (name test) (comment "test") (attrs)
+ (mach playb)
+ ;(pipeline all "" () ((fetch) (decode) (execute) (writeback)))
+ (unit u-exec "Execution Unit" () 1 1
+ () () () ())
+)
+
+; Instruction fields.
+
+(dnf f-op1 "op1" () 0 4)
+(dnf f-op2 "op2" () 4 4)
+(dnf f-op3 "op3" () 8 4)
+(dnf f-op4 "op4" () 12 4)
+(dnf f-r1 "r1" () 8 4)
+(dnf f-r2 "r2" () 12 4)
+(df f-simm16 "simm16" () 16 16 INT #f #f)
+
+(define-normal-insn-enum insn-op1 "insn format enums" () OP1_ f-op1
+ (.map .str (.iota 16))
+)
+
+(define-normal-insn-enum insn-op2 "insn format enums (2)" () OP2_ f-op2
+ (.map .str (.iota 16))
+)
+
+(define-normal-insn-enum insn-op3 "insn format enums (3)" () OP3_ f-op3
+ (.map .str (.iota 16))
+)
+
+(define-normal-insn-enum insn-op4 "insn format enums (4)" () OP4_ f-op4
+ (.map .str (.iota 16))
+)
+
+; Hardware.
+
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(define-hardware
+ (name h-gr)
+ (comment "general registers")
+ (attrs PROFILE );CACHE-ADDR)
+ (type register WI (16))
+ (indices keyword ""
+ ( (fp 13) (lr 14) (sp 15)
+ (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
+ (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15)
+ ))
+)
+
+(define-hardware
+ (name h-status)
+ (comment "status reg")
+ (type register SI)
+ (get () (const 0))
+ (set (newval) (nop))
+)
+
+; These bits are actualy part of the PS register
+(dsh h-nbit "negative bit" () (register BI))
+(dsh h-zbit "zero bit" () (register BI))
+(dsh h-vbit "overflow bit" () (register BI))
+(dsh h-cbit "carry bit" () (register BI))
+
+(dsh h-df "df test" () (register DF))
+(dsh h-tf "tf test" () (register TF))
+
+; Operand attributes.
+
+(define-attr
+ (for operand)
+ (type boolean)
+ (name HASH-PREFIX)
+ (comment "immediates have a '#' prefix")
+)
+
+; Operands.
+
+(dnop nbit "negative bit" (SEM-ONLY) h-nbit f-nil)
+(dnop vbit "overflow bit" (SEM-ONLY) h-vbit f-nil)
+(dnop zbit "zero bit" (SEM-ONLY) h-zbit f-nil)
+(dnop cbit "carry bit" (SEM-ONLY) h-cbit f-nil)
+
+(dnop dr "destination register" () h-gr f-r1)
+(dnop sr "source register" () h-gr f-r2)
+(dnop simm-16 "16 bit signed immediate" (HASH-PREFIX) h-sint f-simm16)
+
+; Note that `df' doesn't work as that is a pmacro.
+(dnop df-reg "df reg" () h-df f-nil)
+(dnop tf-reg "tf reg" () h-tf f-nil)
+
+; Instructions.
+
+(dni add "add"
+ ()
+ "add $dr,$sr"
+ (+ OP1_4 OP2_0 dr sr)
+ (sequence ()
+ (set vbit (add-oflag dr sr (const 0)))
+ (set cbit (add-cflag dr sr (const 0)))
+ (set dr (add dr sr))
+ (set zbit (zflag dr))
+ (set nbit (nflag dr)))
+ ()
+)
+
+(dni addv2 "add version 2"
+ ()
+ "add $dr,$sr"
+ (+ OP1_4 OP2_1 dr sr)
+ (sequence ((WI tmp1))
+ (parallel ()
+ (set tmp1 (add dr sr))
+ (set vbit (add-oflag dr sr (const 0)))
+ (set cbit (add-cflag dr sr (const 0))))
+ (set zbit (zflag tmp1))
+ (set nbit (nflag tmp1))
+ (set dr tmp1)
+ )
+ ()
+)
+
+(dni addi "addi"
+ ()
+ "addi $dr,$sr,$simm-16"
+ (+ OP1_4 OP2_2 dr sr simm-16)
+ (set dr (add sr simm-16))
+ ()
+)
+
+(define-pmacro (reg+ oprnd n)
+ (reg h-gr (add (index-of oprnd) (const n)))
+)
+
+(dni ldm "ldm"
+ ()
+ "ldm $dr,$sr"
+ (+ OP1_5 OP2_2 dr sr)
+ (sequence ()
+ (set dr sr)
+ (set (reg+ dr 1) (reg+ sr 1))
+ )
+ ()
+)
+
+(dni use-ifield "use-ifield"
+ ()
+ "foo $dr,$sr"
+ (+ OP1_5 OP2_3 dr sr)
+ (sequence ()
+ (set dr (ifield f-r2))
+ )
+ ()
+)
+
+(dni use-index-of "index-of"
+ ()
+ "index-of $dr,$sr"
+ (+ OP1_5 OP2_4 dr sr)
+ (set dr (reg h-gr (add (index-of sr) (const 1))))
+ ()
+)
+
+(dni load-df "use df"
+ ()
+ "load-df df,[$sr]"
+ (+ OP1_6 OP2_0 OP3_0 sr)
+ (set df-reg (mem DF sr))
+ ()
+)
+
+(dni make-df "use df"
+ ()
+ "make-df df,[$sr]"
+ (+ OP1_6 OP2_1 OP3_0 sr)
+ (set df-reg (join DF SI (mem SI sr) (mem SI (add sr (const 4)))))
+ ()
+)
+
+(dni split-df "use df"
+ ()
+ "split-df df,[$sr]"
+ (+ OP1_6 OP2_2 OP3_0 sr)
+ (sequence ((DF temp))
+ (set temp df-reg)
+ (set (concat (SI SI)
+ sr
+ (reg h-gr (add (regno sr) (const 1))))
+ (split DF SI temp))
+ )
+ ()
+)
+
+(dni load-tf "use tf"
+ ()
+ "load-tf tf,[$sr]"
+ (+ OP1_6 OP2_3 OP3_0 sr)
+ (set tf-reg (mem TF sr))
+ ()
+)
+
+(dni make-tf "use tf"
+ ()
+ "make-tf tf,[$sr]"
+ (+ OP1_6 OP2_4 OP3_0 sr)
+ (set tf-reg (join TF SI
+ sr
+ (reg h-gr (add (regno sr) (const 1)))
+ (reg h-gr (add (regno sr) (const 2)))
+ (reg h-gr (add (regno sr) (const 3)))))
+ ()
+)
+
+(dni split-tf "use tf"
+ ()
+ "split-tf tf,[$sr]"
+ (+ OP1_6 OP2_5 OP3_0 sr)
+ (sequence ((TF temp))
+ (set temp tf-reg)
+ (set (concat (SI SI SI SI)
+ sr
+ (reg h-gr (add (regno sr) (const 1)))
+ (reg h-gr (add (regno sr) (const 2)))
+ (reg h-gr (add (regno sr) (const 3))))
+ (split TF SI temp))
+ )
+ ()
+)
diff --git a/cgen/pmacros.scm b/cgen/pmacros.scm
new file mode 100644
index 00000000000..67e84806d2f
--- /dev/null
+++ b/cgen/pmacros.scm
@@ -0,0 +1,562 @@
+; Preprocessor-like macro support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; TODO:
+; - Like C preprocessor macros, there is no scoping [one can argue
+; there should be]. Maybe in time (??? Hmmm... done?)
+; On the other hand these macros aren't intended for use outside
+; the cpu description file.
+; - Support for multiple macro tables.
+; - Comments for .pmacros.
+
+; Required routines:
+; make-hash-table, hashq-ref, hashq-set!
+; string-append, symbol-append, map, apply, number?, number->string,
+; eval, num-args-ok?, *UNSPECIFIED*.
+; `num-args-ok?' and `*UNSPECIFIED*' are defined in cgen's utils.scm.
+
+; The convention we use says `-' begins "local" objects.
+; At some point this might also use the Guile module system.
+
+; Exported routines:
+;
+; pmacro-init! - initialize the pmacro system
+;
+; define-pmacro - define a symbolic or procedural macro
+;
+; (define-pmacro symbol "comment" expansion)
+; (define-pmacro (symbol [args]) "comment" (expansion))
+;
+; ARGS is a list of `symbol' or `(symbol default-value)' elements.
+;
+; pmacro-expand - expand all macros in an expression
+;
+; (pmacro-expand expression)
+;
+; pmacro-trace - same as pmacro-expand, but print debugging messages
+;
+; (pmacro-trace expression)
+
+; Builtin macros:
+;
+; (.sym symbol1 symbol2 ...) - symbol-append
+; (.str string1 string2 ...) - string-append
+; (.hex number) - convert to hex string
+; (.upcase string) - convert to uppercase
+; (.downcase string) - convert to lowercase
+; (.substring string start end) - get part of a string
+; (.splice a b (.unsplice c) d e ...) - quasi-quote/unquote-splicing
+; (.iota count [start [increment]]) - number generator
+; (.map macro-name arg1 ...) - map
+; (.apply macro-name arg) - apply
+; (.pmacro (arg-list) expansion) - lambda (??? call it .lambda?)
+; (.eval (expr)) - eval (experimental)
+;
+; .sym and .str convert numbers to symbols/strings as necessary (base 10).
+;
+; .pmacro is for constructing pmacros on-the-fly, like lambda, and is currently
+; only valid as arguments to other macros.
+; ??? Nested pmacros don't bind their arguments the way nested lambda's do.
+; Should they?
+;
+; .eval is an experiment. Ports that consider themselves to be of beta
+; quality or better don't use it.
+;
+; ??? Methinks .foo isn't a valid R5RS symbol. May need to change
+; to something else. Where's Quad when you need it?! :-)
+
+(define -pmacro-trace? #f)
+
+(define -pmacro-table #f)
+(define (-pmacro-lookup name) (hashq-ref -pmacro-table name))
+(define (-pmacro-set! name val) (hashq-set! -pmacro-table name val))
+
+; Marker to indicate a value is a pmacro.
+(define -pmacro-marker '<pmacro>)
+
+; Utilities to create and access pmacros.
+(define (-pmacro-make name arg-spec default-values transformer comment)
+ (vector -pmacro-marker name arg-spec default-values transformer comment)
+)
+(define (-pmacro? x) (and (vector? x) (eq? (vector-ref x 0) -pmacro-marker)))
+(define (-pmacro-name pmac) (vector-ref pmac 1))
+(define (-pmacro-arg-spec pmac) (vector-ref pmac 2))
+(define (-pmacro-default-values pmac) (vector-ref pmac 3))
+(define (-pmacro-transformer pmac) (vector-ref pmac 4))
+(define (-pmacro-comment pmac) (vector-ref pmac 5))
+
+; Cover functions to manage an "environment" in case a need or desire for
+; another method arises.
+
+(define (-pmacro-env-make names values) (map cons names values))
+(define (-pmacro-env-ref env name) (assq name env))
+
+; Error message generator.
+
+(define (-pmacro-error msg expr)
+ (error (string-append
+ (or (port-filename (current-input-port)) "<input>")
+ ":"
+ (number->string (port-line (current-input-port)))
+ ":"
+ msg
+ ":")
+ expr)
+)
+
+; Process list of keyword/value specified arguments.
+
+(define (-pmacro-process-keyworded-args arg-spec default-values args)
+ ; Build a list of default values, then override ones specified in ARGS,
+ (let ((result-alist (alist-copy default-values)))
+ (let loop ((args args))
+ (cond ((null? args)
+ #f) ; done
+ ((and (pair? args) (keyword? (car args)))
+ (let ((elm (assq (car args) result-alist)))
+ (if (not elm)
+ (-pmacro-error "not an argument name" (car args)))
+ (if (null? (cdr args))
+ (-pmacro-error "missing argument to #:keyword" (car args)))
+ (set-cdr! elm (cadr args))
+ (loop (cddr args))))
+ (else
+ (-pmacro-error "bad keyword/value argument list" args))))
+
+ ; Ensure each element has a value.
+ (let loop ((to-scan result-alist))
+ (if (null? to-scan)
+ #f ; done
+ (begin
+ (if (not (cdar to-scan))
+ (-pmacro-error "argument value not specified" (caar to-scan)))
+ (loop (cdr to-scan)))))
+
+ ; If varargs pmacro, adjust result.
+ (if (list? arg-spec)
+ (map cdr result-alist) ; not varargs
+ (let ((nr-args (length (result-alist))))
+ (append! (map cdr (list-head result-alist (- nr-args 1)))
+ (cdr (list-tail result-alist (- nr-args 1)))))))
+)
+
+; Process a pmacro argument list.
+; ARGS is either a fully specified position dependent argument list,
+; or is a list of keyword/value pairs with missing values coming from
+; DEFAULT-VALUES.
+
+(define (-pmacro-process-args arg-spec default-values args)
+ (if (and (pair? args) (keyword? (car args)))
+ (-pmacro-process-keyworded-args arg-spec default-values args)
+ args)
+)
+
+; Invoke a procedural macro.
+; ??? A better name might be -pmacro-apply but that is taken by the
+; .apply handler.
+
+(define (-pmacro-invoke macro args)
+ (let ((arg-spec (-pmacro-arg-spec macro))
+ (default-values (-pmacro-default-values macro)))
+ (let ((processed-args (-pmacro-process-args arg-spec default-values args)))
+ (if (not (num-args-ok? (length processed-args) arg-spec))
+ (-pmacro-error (string-append
+ "wrong number of arguments to pmacro "
+ (with-output-to-string
+ (lambda ()
+ (write (cons (-pmacro-name macro)
+ (-pmacro-arg-spec macro))))))
+ args))
+ (apply (-pmacro-transformer macro) processed-args)))
+)
+
+; Expand expression EXP using ENV, an alist of variable assignments.
+
+(define (-pmacro-expand exp env)
+
+ (define cep (current-error-port))
+
+ ; If the symbol is in `env', return its value.
+ ; Otherwise see if symbol is a globally defined pmacro.
+ ; Otherwise return the symbol unchanged.
+ (define (scan-symbol sym)
+ (let ((val (-pmacro-env-ref env sym)))
+ (if val
+ (cdr val) ; cdr is value of (name . value) pair
+ (let ((val (-pmacro-lookup sym)))
+ (if val
+ ; Symbol is a macro.
+ ; If this is a procedural macro, let caller perform expansion.
+ ; Otherwise, return the macro's value.
+ (if (procedure? (-pmacro-transformer val))
+ val
+ (-pmacro-transformer val))
+ ; Return symbol unchanged.
+ sym)))))
+
+ ; See if (car exp) is a macro.
+ ; Return macro or #f.
+ (define (check-macro exp)
+ (if -pmacro-trace?
+ (begin
+ (display "macro? " cep)
+ (write exp cep)
+ (newline cep)))
+ (and (-pmacro? (car exp)) (car exp)))
+
+ ; Scan each element in EXP and see if the result is a macro invocation.
+ (define (scan-list exp)
+ ; Check for syntactic forms.
+ (case (car exp)
+ ((.pmacro)
+ (if (not (= (length exp) 3))
+ (-pmacro-error "wrong number of arguments to .pmacro" exp))
+ (-pmacro-pmacro (cadr exp) (caddr exp)))
+ (else
+ (let ((scanned-exp (map scan exp)))
+ (let ((macro (check-macro scanned-exp)))
+ (if macro
+ (if (procedure? (-pmacro-transformer macro))
+ (-pmacro-invoke macro (cdr scanned-exp))
+ (cons (-pmacro-transformer macro) (cdr scanned-exp)))
+ scanned-exp))))))
+
+ ; Scan EXP, an arbitrary value.
+ (define (scan exp)
+ (let ((result (cond ((symbol? exp) (scan-symbol exp))
+ ((and (list? exp) (not (null? exp))) (scan-list exp))
+ ; Not a symbol or expression, return unchanged.
+ (else exp))))
+ ; ??? We use to re-examine `result' to see if it was another pmacro
+ ; invocation. This allowed doing things like ((.sym a b c) arg1 arg2)
+ ; where `abc' is a pmacro. Scheme doesn't work this way, so it was
+ ; removed. It can be put back should it ever be warranted.
+ result))
+
+ (if -pmacro-trace?
+ (begin
+ ; We use `write' to display `exp' to see strings quoted.
+ (display "expand: " cep) (write exp cep) (newline cep)
+ (display " env: " cep) (display env cep) (newline cep)))
+
+ (let ((result (scan exp)))
+ (if -pmacro-trace?
+ (begin
+ (display "result: " cep) (write result cep) (newline cep)))
+ result)
+)
+
+; Return the argument spec from ARGS.
+; ARGS is a [possibly improper] list of `symbol' or `(symbol default-value)'
+; elements. For varargs pmacros, ARGS must be an improper list
+; (e.g. (a b . c)) with the last element being a symbol.
+
+(define (-pmacro-get-arg-spec args)
+ (let ((parse-arg
+ (lambda (arg)
+ (cond ((symbol? arg)
+ arg)
+ ((and (pair? arg) (symbol? (car arg)))
+ (car arg))
+ (else
+ (-pmacro-error "argument not `symbol' or `(symbol . default-value)'"
+ arg))))))
+ (if (list? args)
+ (map parse-arg args)
+ (letrec ((parse-improper-list
+ (lambda (args)
+ (cond ((symbol? args)
+ args)
+ ((pair? args)
+ (cons (parse-arg (car args))
+ (parse-improper-list (cdr args))))
+ (else
+ (-pmacro-error "argument not `symbol' or `(symbol . default-value)'"
+ args))))))
+ (parse-improper-list args))))
+)
+
+; Return the default values specified in ARGS.
+; The result is an alist of (#:arg-name . default-value) elements.
+; ARGS is a [possibly improper] list of `symbol' or `(symbol . default-value)'
+; elements. For varargs pmacros, ARGS must be an improper list
+; (e.g. (a b . c)) with the last element being a symbol.
+; Unspecified default values are recorded as #f.
+
+(define (-pmacro-get-default-values args)
+ (let ((parse-arg
+ (lambda (arg)
+ (cond ((symbol? arg)
+ (cons (symbol->keyword arg) #f))
+ ((and (pair? arg) (symbol? (car arg)))
+ (cons (symbol->keyword (car arg)) (cdr arg)))
+ (else
+ (-pmacro-error "argument not `symbol' or `(symbol . default-value)'"
+ arg))))))
+ (if (list? args)
+ (map parse-arg args)
+ (letrec ((parse-improper-list
+ (lambda (args)
+ (cond ((symbol? args)
+ (cons (parse-arg args) nil))
+ ((pair? args)
+ (cons (parse-arg (car args))
+ (parse-improper-list (cdr args))))
+ (else
+ (-pmacro-error "argument not `symbol' or `(symbol . default-value)'"
+ args))))))
+ (parse-improper-list args))))
+)
+
+; Build a procedure that performs a pmacro expansion.
+
+(define (-pmacro-build-lambda params expansion)
+ (eval `(lambda ,params
+ (-pmacro-expand ',expansion (-pmacro-env-make ',params (list ,@params)))))
+)
+
+; ??? I'd prefer to use `define-macro', but boot-9.scm uses it and
+; I'd rather not risk a collision. I could of course make the association
+; during parsing, maybe later.
+; ??? On the other hand, calling them pmacros removes all ambiguity.
+;
+; The syntax is one of:
+; (define (name args ...) expansion)
+; (define (name args ...) "documentation" expansion)
+;
+; If `expansion' is the name of a pmacro, its value is used (rather than its
+; name).
+; ??? The goal here is to follow Scheme's define/lambda, but not all variants
+; are supported yet. There's also the difference that we treat undefined
+; symbols as being themselves.
+
+(define (define-pmacro header arg1 . arg-rest)
+ (let ((name (if (symbol? header) header (car header)))
+ (arg-spec (if (symbol? header) #f (-pmacro-get-arg-spec (cdr header))))
+ (default-values (if (symbol? header) #f (-pmacro-get-default-values (cdr header))))
+ (comment (if (null? arg-rest) "" arg1))
+ (expansion (if (null? arg-rest) arg1 (car arg-rest))))
+ (if (symbol? header)
+ (if (symbol? expansion)
+ (let ((maybe-pmacro (-pmacro-lookup expansion)))
+ (if maybe-pmacro
+ (-pmacro-set! name
+ (-pmacro-make name
+ (-pmacro-arg-spec maybe-pmacro)
+ (-pmacro-default-values maybe-pmacro)
+ (-pmacro-transformer maybe-pmacro)
+ comment))
+ (-pmacro-set! name (-pmacro-make name #f #f expansion comment))))
+ (-pmacro-set! name (-pmacro-make name #f #f expansion comment)))
+ (-pmacro-set! name
+ (-pmacro-make name arg-spec default-values
+ (-pmacro-build-lambda arg-spec expansion)
+ comment))))
+ *UNSPECIFIED*
+)
+
+; Expand any pmacros in EXPR.
+
+(define (pmacro-expand expr)
+ (-pmacro-expand expr '())
+)
+
+; Debugging routine to trace macro expansion.
+
+(define (pmacro-trace expr)
+ ; ??? Need unwind protection.
+ (let ((old -pmacro-trace?))
+ (set! -pmacro-trace? #t)
+ (let ((result (-pmacro-expand expr '())))
+ (set! -pmacro-trace? old)
+ result))
+)
+
+; Builtin macros.
+
+; .sym - symbol-append, auto-convert numbers
+
+(define -pmacro-sym
+ (lambda args
+ (apply symbol-append
+ (map (lambda (elm)
+ (if (number? elm)
+ (number->string elm)
+ elm))
+ args)))
+)
+
+; .str - string-append, auto-convert numbers
+
+(define -pmacro-str
+ (lambda args
+ (apply string-append
+ (map (lambda (elm)
+ (if (number? elm)
+ (number->string elm)
+ elm))
+ args)))
+)
+
+; .hex - convert number to hex string
+; WIDTH, if present, is the number of characters in the result, beginning
+; from the least significant digit.
+
+(define (-pmacro-hex num . width)
+ (if (> (length width) 1)
+ (-pmacro-error "wrong number of arguments to .hex"
+ (cons '.hex (cons num width))))
+ (let ((str (number->string num 16)))
+ (if (null? width)
+ str
+ (let ((len (string-length str)))
+ (substring (string-append (make-string (car width) #\0) str)
+ len (+ len (car width))))))
+)
+
+; .upcase - convert a string to uppercase
+
+(define (-pmacro-upcase str)
+ (string-upcase str)
+)
+
+; .downcase - convert a string to lowercase
+
+(define (-pmacro-downcase str)
+ (string-downcase str)
+)
+
+; .substring - get part of a string
+
+(define (-pmacro-substring str start end)
+ (substring str start end)
+)
+
+; .splice - splicing support
+; Splice lists into the outer list.
+;
+; E.g. (define-pmacro '(splice-test a b c) '(.splice a (.unsplice b) c))
+; (pmacro-expand '(splice-test (1 (2) 3))) --> (1 2 3)
+;
+; Similar to `(1 ,@'(2) 3) in Scheme, though the terminology is slightly
+; different (??? may need to revisit). In Scheme we have quasi-quote,
+; unquote, unquote-splicing. Here we have splice, unsplice.
+
+(define -pmacro-splice
+ (lambda arg-list
+ ; ??? Not the most efficient implementation, but will the difference
+ ; ever be measureable?
+ (let loop ((arg-list arg-list) (result '()))
+ (cond ((null? arg-list) result)
+ ((and (pair? (car arg-list)) (eq? '.unsplice (caar arg-list)))
+ (if (= (length (car arg-list)) 2)
+ (if (list? (cadar arg-list))
+ (loop (cdr arg-list) (append result (cadar arg-list)))
+ (-pmacro-error "argument to .unsplice must be a list"
+ (car arg-list)))
+ (-pmacro-error "wrong number of arguments to .unsplice"
+ (car arg-list))))
+ (else
+ (loop (cdr arg-list) (append result (list (car arg-list))))))))
+)
+
+; .iota
+; Usage:
+; (.iota count) ; start=0, incr=1
+; (.iota count start) ; incr=1
+; (.iota count start incr)
+
+(define (-pmacro-iota count . start-incr)
+ (if (> (length start-incr) 2)
+ (-pmacro-error "wrong number of arguments to .iota"
+ (cons '.iota (cons count start-incr))))
+ (if (< count 0)
+ (-pmacro-error "count must be non-negative"
+ (cons '.iota (cons count start-incr))))
+ (let ((start (if (pair? start-incr) (car start-incr) 0))
+ (incr (if (= (length start-incr) 2) (cadr start-incr) 1)))
+ (let loop ((i start) (count count) (result '()))
+ (if (= count 0)
+ (reverse! result)
+ (loop (+ i incr) (- count 1) (cons i result)))))
+)
+
+; .map
+
+(define (-pmacro-map pmacro arg1 . arg-rest)
+ (if (not (-pmacro? pmacro))
+ (-pmacro-error "not a pmacro" pmacro))
+ (let ((transformer (-pmacro-transformer pmacro)))
+ (if (not (procedure? transformer))
+ (-pmacro-error "not a procedural macro" pmacro))
+ (apply map (cons transformer (cons arg1 arg-rest))))
+)
+
+; .apply
+
+(define (-pmacro-apply pmacro arg-list)
+ (if (not (-pmacro? pmacro))
+ (-pmacro-error "not a pmacro" pmacro))
+ (let ((transformer (-pmacro-transformer pmacro)))
+ (if (not (procedure? transformer))
+ (-pmacro-error "not a procedural macro" pmacro))
+ (apply transformer arg-list))
+)
+
+; .pmacro
+
+(define (-pmacro-pmacro params expansion)
+ (if (not (list? params))
+ (-pmacro-error "bad parameter list" params))
+ (-pmacro-make '.anonymous params #f (-pmacro-build-lambda params expansion) "")
+)
+
+; Initialization.
+
+(define (pmacros-init!)
+ (set! -pmacro-table (make-hash-table 127))
+
+ ; Some "predefined" macros.
+
+ (-pmacro-set! '.sym
+ (-pmacro-make '.sym 'symbols #f -pmacro-sym "symbol-append"))
+ (-pmacro-set! '.str
+ (-pmacro-make '.str 'strings #f -pmacro-str "string-append"))
+ (-pmacro-set! '.hex
+ (-pmacro-make '.hex '(number . width) #f -pmacro-hex
+ "convert to hex, with optional width"))
+ (-pmacro-set! '.upcase
+ (-pmacro-make '.upcase '(string) #f
+ -pmacro-upcase "string-upcase"))
+ (-pmacro-set! '.downcase
+ (-pmacro-make '.downcase '(string) #f
+ -pmacro-downcase "string-downcase"))
+ (-pmacro-set! '.substring
+ (-pmacro-make '.substring '(string start end) #f
+ -pmacro-substring "get part of a string"))
+ (-pmacro-set! '.splice
+ (-pmacro-make '.splice 'arg-list #f -pmacro-splice
+ "splice lists into the outer list"))
+ (-pmacro-set! '.iota
+ (-pmacro-make '.iota '(count . start-incr) #f -pmacro-iota
+ "iota number generator"))
+ (-pmacro-set! '.map
+ (-pmacro-make '.map '(macro-name arg1 . arg-rest) #f
+ -pmacro-map
+ "map a macro over a list of arguments"))
+ (-pmacro-set! '.apply
+ (-pmacro-make '.apply '(macro-name arg-list) #f -pmacro-apply
+ "apply a macro, taking arguments from a list"))
+ (-pmacro-set! '.pmacro
+ (-pmacro-make '.pmacro '(params expansion) #f -pmacro-pmacro
+ "create a pmacro on-the-fly"))
+
+ ; doesn't work, Hobbit creates "eval" variable
+ ;(-pmacro-set! '.eval (-pmacro-make '.eval '(expr) #f eval "eval"))
+ (-pmacro-set! '.eval (-pmacro-make '.eval '(expr) #f (eval 'eval) "eval"))
+)
+
+; Initialize so we're ready to use after loading.
+(pmacros-init!)
diff --git a/cgen/profile.scm b/cgen/profile.scm
new file mode 100644
index 00000000000..02fdee8cc57
--- /dev/null
+++ b/cgen/profile.scm
@@ -0,0 +1,180 @@
+;;; {Profile}
+;;;
+;;; This code is just an experimental prototype (e. g., it is not
+;;; thread safe), but since it's at the same time useful, it's
+;;; included anyway.
+;;;
+;;; This is copied from the tracing support in debug.scm.
+;;; If merged into the main distribution it will need an efficiency
+;;; and layout cleanup pass.
+
+; FIXME: Prefix "proc-" added to not collide with cgen stuff.
+
+; Put this stuff in the debug module since we need the trace facilities.
+(define-module (ice-9 profile) :use-module (ice-9 debug))
+
+(define profiled-procedures '())
+
+(define-public (profile-enable . args)
+ (if (null? args)
+ (nameify profiled-procedures)
+ (begin
+ (for-each (lambda (proc)
+ (if (not (procedure? proc))
+ (error "profile: Wrong type argument:" proc))
+ ; `trace' is a magic property understood by guile
+ (set-procedure-property! proc 'trace #t)
+ (if (not (memq proc profiled-procedures))
+ (set! profiled-procedures
+ (cons proc profiled-procedures))))
+ args)
+ (set! apply-frame-handler profile-entry)
+ (set! exit-frame-handler profile-exit)
+ (debug-enable 'trace)
+ (nameify args))))
+
+(define-public (profile-disable . args)
+ (if (and (null? args)
+ (not (null? profiled-procedures)))
+ (apply profile-disable profiled-procedures)
+ (begin
+ (for-each (lambda (proc)
+ (set-procedure-property! proc 'trace #f)
+ (set! profiled-procedures (delq! proc profiled-procedures)))
+ args)
+ (if (null? profiled-procedures)
+ (debug-disable 'trace))
+ (nameify args))))
+
+(define (nameify ls)
+ (map (lambda (proc)
+ (let ((name (procedure-name proc)))
+ (or name proc)))
+ ls))
+
+; Subroutine of profile-entry to find the calling procedure.
+; Result is name of calling procedure or #f.
+
+(define (find-caller frame)
+ (let ((prev (frame-previous frame)))
+ (if prev
+ ; ??? Not sure this is right. The goal is to find the real "caller".
+ (if (and (frame-procedure? prev)
+ ;(or (frame-real? prev) (not (frame-evaluating-args? prev)))
+ (not (frame-evaluating-args? prev))
+ )
+ (let ((name (procedure-name (frame-procedure prev))))
+ (if name name 'lambda))
+ (find-caller prev))
+ 'top-level))
+)
+
+; Return the current time.
+; The result is a black box understood only by elapsed-time.
+
+(define (current-time) (gettimeofday))
+
+; Return the elapsed time in milliseconds since START.
+
+(define (elapsed-time start)
+ (let ((now (gettimeofday)))
+ (+ (* (- (car now) (car start)) 1000)
+ (quotient (- (cdr now) (cdr start)) 1000)))
+)
+
+; Handle invocation of profiled procedures.
+
+(define (profile-entry key cont tail)
+ (if (eq? (stack-id cont) 'repl-stack)
+ (let* ((stack (make-stack cont))
+ (frame (stack-ref stack 0))
+ (proc (frame-procedure frame)))
+ (if proc
+ ; procedure-property returns #f if property not present
+ (let ((counts (procedure-property proc 'profile-count)))
+ (set-procedure-property! proc 'entry-time (current-time))
+ (if counts
+ (let* ((caller (find-caller frame))
+ (count-elm (assq caller counts)))
+ (if count-elm
+ (set-cdr! count-elm (1+ (cdr count-elm)))
+ (set-procedure-property! proc 'profile-count
+ (acons caller 1 counts)))))))))
+
+ ; SCM_TRACE_P is reset each time by the interpreter
+ ;(display "entry\n" (current-error-port))
+ (debug-enable 'trace)
+ ;; It's not necessary to call the continuation since
+ ;; execution will continue if the handler returns
+ ;(cont #f)
+)
+
+; Handle exiting of profiled procedures.
+
+(define (profile-exit key cont retval)
+ ;(display "exit\n" (current-error-port))
+ (display (list key cont retval)) (newline)
+ (display (stack-id cont)) (newline)
+ (if (eq? (stack-id cont) 'repl-stack)
+ (let* ((stack (make-stack cont))
+ (frame (stack-ref stack 0))
+ (proc (frame-procedure frame)))
+ (display stack) (newline)
+ (display frame) (newline)
+ (if proc
+ (set-procedure-property!
+ proc 'total-time
+ (+ (procedure-property proc 'total-time)
+ (elapsed-time (procedure-property proc 'entry-time)))))))
+
+ ; ??? Need to research if we have to do this or not.
+ ; SCM_TRACE_P is reset each time by the interpreter
+ (debug-enable 'trace)
+)
+
+; Called before something is to be profiled.
+; All desired procedures to be profiled must have been previously selected.
+; Property `profile-count' is an association list of caller name and call
+; count.
+; ??? Will eventually want to use a hash table or some such.
+
+(define-public (profile-init)
+ (for-each (lambda (proc)
+ (set-procedure-property! proc 'profile-count '())
+ (set-procedure-property! proc 'total-time 0))
+ profiled-procedures)
+)
+
+; Called after execution to print profile counts.
+; If ARGS contains 'all, stats on all profiled procs are printed, not just
+; those that were actually called.
+
+(define-public (profile-stats . args)
+ (let ((stats (map (lambda (proc)
+ (cons (procedure-name proc)
+ (procedure-property proc 'profile-count)))
+ profiled-procedures))
+ (all? (memq 'all args))
+ (sort (if (defined? 'sort) (local-ref '(sort)) (lambda args args))))
+
+ (display "Profiling results:\n\n")
+
+ ; Print the procs in sorted order.
+ (let ((stats (sort stats (lambda (a b) (string<? (car a) (car b))))))
+ (for-each (lambda (proc-stats)
+ (if (or all? (not (null? (cdr proc-stats))))
+ ; Print by decreasing frequency.
+ (let ((calls (sort (cdr proc-stats) (lambda (a b) (> (cdr a) (cdr b))))))
+ (display (string-append (car proc-stats) "\n"))
+ (for-each (lambda (call)
+ (display (string-append " "
+ (number->string (cdr call))
+ " "
+ (car call)
+ "\n")))
+ calls)
+ (display " ")
+ (display (apply + (map cdr calls)))
+ (display " -- total\n\n"))))
+ stats)))
+)
diff --git a/cgen/read.scm b/cgen/read.scm
new file mode 100644
index 00000000000..2b2ef008b05
--- /dev/null
+++ b/cgen/read.scm
@@ -0,0 +1,1198 @@
+; Top level file for reading and recording .cpu file contents.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; This file [and its subordinates] contain no C code (well, as little as
+; possible). That lives at a layer above us.
+
+; A .cpu file consists of several sections:
+;
+; - basic definitions (e.g. cpu variants, word size, endianness, etc.)
+; - enums (enums are used throughout so by convention there is a special
+; section in which they're defined)
+; - attributes
+; - instruction fields and formats
+; - hardware descriptions (e.g. registers, allowable immediate values)
+; - model descriptions (e.g. pipelines, latencies, etc.)
+; - instruction operands (mapping of insn fields to associated hardware)
+; - instruction definitions
+; - macro instruction definitions
+
+; TODO:
+; - memory access, layout, etc.
+; - floating point quirks
+; - ability to describe an ABI
+; - anything else that comes along
+
+; Notes:
+; - by convention most objects are subclasses of <ident> (having name, comment,
+; and attrs elements and they are the first three elements of any .cpu file
+; entry
+
+; Guidelines:
+; - Try to conform to R5RS, try to limit guile-ness.
+; The current code is undoubtedly off in many places.
+
+; Conventions:
+; [I want there to be a plethora of conventions and I want them strictly
+; adhered to. ??? There's probably a few violations here and there.
+; No big deal - fix them!]
+; These conventions are subject to revision.
+;
+; - procs/vars local to a file are named "-foo"
+; - only routines that emit application code begin with "gen-"
+; - symbols beginning with "c-" are either variables containing C code
+; or procedures that generate C code, similarily for C++ and "c++-"
+; - variables containing C code begin with "c-"
+; - only routines that emit an entire file begin with "cgen-"
+; - all .cpu file elements shall have -foo-parse and -foo-read procedures
+; - global vars containing class definitions shall be named "<class-name>"
+; - procs related to a particular class shall be named "class-name-proc-name",
+; class-name may be abbreviated
+; - procs that test whether something is an object of a particular class
+; shall be named "class-name?"
+; - in keeping with Scheme conventions, predicates shall have a "?" suffix
+; - in keeping with Scheme conventions, methods and procedures that modify an
+; argument or have other side effects shall have a "!" suffix,
+; usually these procs return "*UNSPECIFIED*"
+; - all -foo-parse,parse-foo procs shall have `context' as the first arg
+; [FIXME: not all such procs have been converted]
+; - stay away from non-portable C symbols, it makes using hobbit more difficult
+; e.g. don't have anything named `index', sigh.
+
+; Variables representing misc. global constants.
+
+; A list of three numbers designating the cgen version: major minor fixlevel.
+(define -CGEN-VERSION '(0 7 2))
+(define (cgen-major) (car -CGEN-VERSION))
+(define (cgen-minor) (cadr -CGEN-VERSION))
+(define (cgen-fixlevel) (caddr -CGEN-VERSION))
+
+; A list of three numbers designating the description language version.
+; Note that this is different from -CGEN-VERSION.
+(define -CGEN-LANG-VERSION '(0 7 2))
+(define (cgen-lang-major) (car -CGEN-LANG-VERSION))
+(define (cgen-lang-minor) (cadr -CGEN-LANG-VERSION))
+(define (cgen-lang-fixlevel) (caddr -CGEN-LANG-VERSION))
+
+; Which application is in use (UNKNOWN, DESC, OPCODES, SIMULATOR, ???).
+; This is mostly for descriptive purposes.
+(define APPLICATION 'UNKNOWN)
+
+; Things are organized so that files can be compiled with Hobbit for
+; experimentation. Thus we need one file that loads all the other files.
+; This is that file, though it would make sense to move the code in this
+; file to another.
+
+; If a routine to initialize compiled-in code is defined, run it.
+(if (defined? 'cgen-init-c) (cgen-init-c))
+
+; Don't use the debugging evaluator unless asked for.
+(if (not (defined? 'DEBUG-EVAL))
+ (define DEBUG-EVAL #f))
+
+(if (and (not DEBUG-EVAL)
+ (memq 'debug-extensions *features*))
+ (begin
+ (debug-disable 'debug)
+ (read-disable 'positions)
+ ))
+
+; If this is set to #f, the file is always loaded.
+; Don't override any current setting, e.g. from dev.scm.
+(if (not (defined? 'CHECK-LOADED?))
+ (define CHECK-LOADED? #t))
+
+; Unlink file if we're reloaded (say in an interactive session).
+; Dynamic loading is enabled by setting LIBCPU.SO to the pathname of the .so.
+(if (and (defined? 'libcpu.so) (dynamic-object? libcpu.so))
+ (dynamic-unlink libcpu.so))
+(define libcpu.so #f)
+(if (and (defined? 'LIBCPU.SO)
+ (file-exists? LIBCPU.SO))
+ (set! libcpu.so (dynamic-link LIBCPU.SO))
+)
+
+; List of loaded files.
+
+(if (not (defined? '-loaded-file-list))
+ (define -loaded-file-list '()))
+
+; Return non-zero if FILE was loaded last time through.
+
+(define (-loaded-file? file)
+ (->bool (memq (string->symbol file) -loaded-file-list))
+)
+
+; Record FILE as compiled in.
+
+(define (-loaded-file-record! file)
+ (let ((file (string->symbol file)))
+ (if (not (memq file -loaded-file-list))
+ (set! -loaded-file-list (cons file -loaded-file-list))))
+)
+
+; Load FILE if SYM is not compiled in.
+
+(define (maybe-load file init-func sym)
+ ; Return non-#f if FUNC is present in DYNOBJ.
+ (define (dynamic-func? func dynobj)
+ (catch #t
+ (lambda () (dynamic-func func dynobj))
+ (lambda args #f))
+ )
+
+ (let ((init-func (string-append "init_" (if init-func init-func file))))
+ (cond ((and libcpu.so
+ (dynamic-func? init-func libcpu.so))
+ (dynamic-call init-func libcpu.so)
+ (display (string-append "Skipping " file ", dynamically loaded.\n")))
+ ((or (not CHECK-LOADED?)
+ (not (defined? sym))
+ (-loaded-file? file))
+ (-loaded-file-record! file)
+ (load file))
+ (else
+ (display (string-append "Skipping " file ", already loaded.\n")))))
+)
+
+(maybe-load "pmacros" #f 'define-pmacro)
+(maybe-load "cos" #f 'make)
+(maybe-load "slib/sort" #f 'sort)
+; Used to pretty-print debugging messages.
+(maybe-load "slib/pp" #f 'pretty-print)
+; Used by pretty-print.
+(maybe-load "slib/genwrite" #f 'generic-write)
+(maybe-load "utils" #f 'logit)
+(maybe-load "utils-cgen" "utils_cgen" 'obj:name)
+(maybe-load "attr" #f '<attribute>)
+(maybe-load "enum" #f '<enum>)
+(maybe-load "mach" #f '<mach>)
+(maybe-load "model" #f '<model>)
+(maybe-load "types" #f '<scalar>)
+(maybe-load "mode" #f '<mode>)
+(maybe-load "ifield" #f '<ifield>)
+(maybe-load "iformat" #f '<iformat>)
+(maybe-load "hardware" #f '<hardware-base>)
+(maybe-load "operand" #f '<operand>)
+(maybe-load "insn" #f '<insn>)
+(maybe-load "minsn" #f '<macro-insn>)
+(maybe-load "decode" #f 'decode-build-table)
+(maybe-load "rtl" "rtl" '<rtx-func>)
+(maybe-load "rtx-funcs" "rtx_funcs" 'def-rtx-funcs)
+(maybe-load "rtl-c" "rtl_c" '<c-expr>)
+(maybe-load "semantics" #f 'semantic-compile)
+(maybe-load "sem-frags" "sem_frags" 'gen-threaded-engine)
+(maybe-load "utils-gen" "utils_gen" 'attr-gen-decl)
+(maybe-load "pgmr-tools" "pgmr_tools" 'pgmr-pretty-print-insn-format)
+
+; Reader state data.
+; All state regarding the reading of a .cpu file is kept in an object of
+; class <reader>.
+
+; Class to record info for each top-level `command' (for lack of a better
+; word) in the description file.
+; Top level commands are things like define-*.
+
+(define <command>
+ (class-make '<command>
+ '(<ident>)
+ '(
+ ; argument spec to `lambda'
+ arg-spec
+ ; lambda that processes the entry
+ handler
+ )
+ nil)
+)
+
+(define command-arg-spec (elm-make-getter <command> 'arg-spec))
+(define command-handler (elm-make-getter <command> 'handler))
+
+; Return help text for COMMAND.
+
+(define (command-help cmd)
+ (string-append
+ (obj:comment cmd)
+ "Arguments: "
+ (with-output-to-string (lambda () (write (command-arg-spec cmd))))
+ "\n")
+)
+
+; A pair of two lists: machs to keep, machs to drop.
+; Keep all machs, drop none.
+
+(define -keep-all-machs '((all)))
+
+; Main reader state class.
+
+(define <reader>
+ (class-make '<reader>
+ nil
+ (list
+ ; Selected machs to keep.
+ ; A pair of two lists: the car lists the machs to keep, the cdr
+ ; lists the machs to drop. Two special entries are `all' and
+ ; `base'. Both are only valid in the keep list. `base' is a
+ ; place holder for objects that are common to all machine
+ ; variants in the architecture, it is the default value of the
+ ; MACH attribute. If `all' is present the drop list is still
+ ; processed.
+ (cons 'keep-mach -keep-all-machs)
+
+ ; Selected isas to keep or `all'.
+ '(keep-isa . (all))
+
+ ; Currently select cpu family, computed from `keep-mach'.
+ ; Some applications don't care, and this is moderately
+ ; expensive to compute so we use delay/force.
+ 'current-cpu
+
+ ; Associative list of file entry commands
+ ; (e.g. define-insn, etc.).
+ ; Each entry is (name . command-object).
+ (cons 'commands nil)
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <reader> reader (keep-mach keep-isa current-cpu commands))
+(define-setters <reader> reader (keep-mach keep-isa current-cpu commands))
+
+(define (reader-add-command! name comment attrs arg-spec handler)
+ (reader-set-commands! CURRENT-READER
+ (acons name
+ (make <command> name comment attrs
+ arg-spec handler)
+ (reader-commands CURRENT-READER)))
+)
+
+(define (reader-lookup-command name)
+ (assq-ref (reader-commands CURRENT-READER) name)
+)
+
+; Reader state for current .cpu file.
+
+(define CURRENT-READER #f)
+
+; Signal an error while reading a .cpu file.
+
+(define (reader-error msg expr help-text)
+ (let ((errmsg
+ (string-append (or (port-filename (current-input-port))
+ "<input>")
+ ":"
+ (number->string (port-line (current-input-port)))
+ ": "
+ msg
+ ":")))
+ (error (string-append errmsg "\n" help-text)
+ expr))
+)
+
+; Signal a parse error while reading a .cpu file.
+
+(define (parse-error errtxt message . args)
+ (reader-error (string-append errtxt ": " message ":") args "")
+)
+
+; Process a macro-expanded entry.
+
+(define (-reader-process-expanded-1 entry)
+ (logit 4 (with-output-to-string (lambda () (pretty-print entry))))
+ (let ((command (reader-lookup-command (car entry))))
+ (if command
+ (let* ((handler (command-handler command))
+ (arg-spec (command-arg-spec command))
+ (num-args (num-args arg-spec)))
+ (if (cdr num-args)
+ ; Variable number of trailing arguments.
+ (if (< (length (cdr entry)) (car num-args))
+ (reader-error (string-append "Incorrect number of arguments to "
+ (car entry)
+ ", expecting at least "
+ (number->string (car num-args)))
+ entry
+ (command-help command))
+ (apply handler (cdr entry)))
+ ; Fixed number of arguments.
+ (if (!= (length (cdr entry)) (car num-args))
+ (reader-error (string-append "Incorrect number of arguments to "
+ (car entry)
+ ", expecting "
+ (number->string (car num-args)))
+ entry
+ (command-help command))
+ (apply handler (cdr entry)))))
+ (reader-error "unknown entry type" entry "")))
+ *UNSPECIFIED*
+)
+
+; Process 1 or more macro-expanded entries.
+
+(define (-reader-process-expanded entry)
+ ; `begin' is used to group a collection of entries into one, since pmacro
+ ; can only return one expression (borrowed from Scheme of course).
+ ; ??? Maybe someday (begin ...) will be equivalent to (sequence () ...)
+ ; but not yet.
+ ; Recurse in case there are nested begins.
+ (if (eq? (car entry) 'begin)
+ (for-each -reader-process-expanded
+ (cdr entry))
+ (-reader-process-expanded-1 entry))
+)
+
+; Process file entry ENTRY.
+
+(define (reader-process entry)
+ (if (not (form? entry))
+ (reader-error "improperly formed entry" entry ""))
+
+ ; First do macro expansion, but not if define-pmacro of course.
+ (let ((expansion (if (eq? (car entry) 'define-pmacro)
+ entry
+ (pmacro-expand entry))))
+ (-reader-process-expanded expansion))
+)
+
+; Read in and process FILE.
+;
+; It would be nice to get the line number of the beginning of the object,
+; but that's extra work, so for now we do the simple thing and use
+; port-line after we've read an entry.
+
+(define (reader-read-file! file)
+ (let ((readit (lambda ()
+ (let loop ((entry (read)))
+ (if (eof-object? entry)
+ #t ; done
+ (begin
+ (reader-process entry)
+ (loop (read)))))))
+ )
+
+ (with-input-from-file file readit)
+ *UNSPECIFIED*)
+)
+
+; Cpu data is recorded in an object of class <arch>.
+; This is necessary as we need to allow recording of multiple cpu descriptions
+; simultaneously.
+; Class <arch> is defined in mach.scm.
+
+; Global containing all data of the currently selected architecture.
+
+(define CURRENT-ARCH #f)
+
+; `keep-mach' processing.
+
+; Return the currently selected cpu family.
+; If a specific cpu family has been selected, each machine that is kept must
+; be in that cpu family [so there's no ambiguity in the result].
+; This is a moderately expensive computation so use delay/force.
+
+(define (current-cpu) (force (reader-current-cpu CURRENT-READER)))
+
+; Return a boolean indicating if CPU-NAME is to be kept.
+; ??? Currently this is always true. Note that this doesn't necessarily apply
+; to machs in CPU-NAME.
+
+(define (keep-cpu? cpu-name) #t)
+
+; Cover proc to set `keep-mach'.
+; MACH-NAME-LIST is a comma separated string of machines to keep and drop
+; (if prefixed with !).
+
+(define (-keep-mach-set! mach-name-list)
+ (let* ((mach-name-list (string-cut mach-name-list #\,))
+ (keep (find (lambda (name) (not (char=? (string-ref name 0) #\!)))
+ mach-name-list))
+ (drop (map (lambda (name) (string->symbol (string-drop 1 name)))
+ (find (lambda (name) (char=? (string-ref name 0) #\!))
+ mach-name-list))))
+ (reader-set-keep-mach! CURRENT-READER
+ (cons (map string->symbol keep)
+ (map string->symbol drop)))
+ ; Reset current-cpu.
+ (reader-set-current-cpu!
+ CURRENT-READER
+ (delay (let ((selected-machs (find (lambda (mach)
+ (keep-mach? (list (obj:name mach))))
+ (current-mach-list))))
+ (if (= (length selected-machs) 0)
+ (error "no machs selected"))
+ (if (not (all-true? (map (lambda (mach)
+ (eq? (obj:name (mach-cpu mach))
+ (obj:name (mach-cpu (car selected-machs)))))
+ selected-machs)))
+ (error "machs from different cpu families selected"))
+ (mach-cpu (car selected-machs)))))
+
+ *UNSPECIFIED*)
+)
+
+; Validate the user-provided keep-mach list against the list of machs
+; specified in the .cpu file (in define-arch).
+
+(define (keep-mach-validate!)
+ (let ((mach-names (cons 'all (current-arch-mach-name-list)))
+ (keep-mach (reader-keep-mach CURRENT-READER)))
+ (for-each (lambda (mach)
+ (if (not (memq mach mach-names))
+ (error "unknown mach to keep:" mach)))
+ (car keep-mach))
+ (for-each (lambda (mach)
+ (if (not (memq mach mach-names))
+ (error "unknown mach to drop:" mach)))
+ (cdr keep-mach))
+ )
+ *UNSPECIFIED*
+)
+
+; Return #t if a machine in MACH-LIST, a list of symbols, is to be kept.
+; If any machine in MACH-LIST is to be kept, the result is #t.
+; If MACH-LIST is the empty list (no particular mach specified, thus the base
+; mach), the result is #t.
+
+(define (keep-mach? mach-list)
+ (if (null? mach-list)
+ #t
+ (let* ((keep-mach (reader-keep-mach CURRENT-READER))
+ (keep (cons 'base (car keep-mach)))
+ (drop (cdr keep-mach))
+ (keep? (map (lambda (m) (memq m keep)) mach-list))
+ (all? (memq 'all keep))
+ (drop? (map (lambda (m) (memq m drop)) mach-list)))
+ (any-true? (map (lambda (k d)
+ ; keep if K(ept) or ALL? and not D(ropped)
+ (->bool (and (or k all?) (not d))))
+ keep? drop?))))
+)
+
+; Return non-#f if the object containing ATLIST is to be kept.
+; OBJ is the container object or #f if there is none.
+; The object is kept if its attribute list specifies a `MACH' that is
+; kept (and not dropped) or does not have the `MACH' attribute (which means
+; it has the default value which means it's for use with all machines).
+
+(define (keep-mach-atlist? atlist obj)
+ ; The MACH attribute is not created until the .cpu file is read in which
+ ; is too late for us [we will get called for builtin objects].
+ ; Thus we peek inside the attribute list directly.
+ ; ??? Maybe postpone creation of builtins until after define-arch?
+ (let ((machs (atlist-attr-value-no-default atlist 'MACH obj)))
+ (if (null? machs)
+ #t
+ (keep-mach? (map string->symbol (string-cut machs #\,)))))
+)
+
+; Return a boolean indicating if the object containing ATLIST is to be kept.
+; OBJ is the container object or #f if there is none.
+; The object is kept if both its isa and its mach are kept.
+
+(define (keep-atlist? atlist obj)
+ (and (keep-mach-atlist? atlist obj)
+ (keep-isa-atlist? atlist obj))
+)
+
+; Return a boolean indicating if multiple cpu families are being kept.
+
+(define (keep-multiple?)
+ (let ((selected-machs (find (lambda (mach)
+ (keep-mach? (list (obj:name mach))))
+ (current-mach-list))))
+ (not (all-true? (map (lambda (mach)
+ (eq? (obj:name (mach-cpu mach))
+ (obj:name (mach-cpu (car selected-machs)))))
+ selected-machs))))
+)
+
+; Return a boolean indicating if everything is kept.
+
+(define (keep-all?)
+ (equal? (reader-keep-mach CURRENT-READER) -keep-all-machs)
+)
+
+; Ensure all cpu families were kept, necessary for generating files that
+; encompass the entire architecture.
+
+(define (assert-keep-all)
+ (if (not (keep-all?))
+ (error "no can do, all cpu families not selected"))
+ *UNSPECIFIED*
+)
+
+; Ensure exactly one cpu family was kept, necessary for generating files that
+; are specific to one cpu family.
+
+(define (assert-keep-one)
+ (if (keep-multiple?)
+ (error "no can do, multiple cpu families selected"))
+ *UNSPECIFIED*
+)
+
+; `keep-isa' processing.
+
+; Cover proc to set `keep-isa'.
+; ISA-NAME-LIST is a comma separated string of isas to keep.
+; ??? We don't support the !drop notation of keep-mach processing.
+; Perhaps we should as otherwise there are two different styles the user
+; has to remember. On the other hand, !drop support is moderately complicated,
+; and it can be added in an upward compatible manner later.
+
+(define (-keep-isa-set! isa-name-list)
+ (let ((isa-name-list (map string->symbol (string-cut isa-name-list #\,))))
+ (reader-set-keep-isa! CURRENT-READER isa-name-list)
+ )
+ *UNSPECIFIED*
+)
+
+; Validate the user-provided keep-isa list against the list of isas
+; specified in the .cpu file (in define-arch).
+
+(define (keep-isa-validate!)
+ (let ((isa-names (cons 'all (current-arch-isa-name-list)))
+ (keep-isa (reader-keep-isa CURRENT-READER)))
+ (for-each (lambda (isa)
+ (if (not (memq isa isa-names))
+ (error "unknown isa to keep:" isa)))
+ keep-isa)
+ )
+ *UNSPECIFIED*
+)
+
+; Return currently selected isa (there must be exactly one).
+
+(define (current-isa)
+ (let ((keep-isa (reader-keep-isa CURRENT-READER)))
+ (if (equal? keep-isa '(all))
+ (let ((isas (current-isa-list)))
+ (if (= (length isas) 1)
+ (car isas)
+ (error "multiple isas selected" keep-isa)))
+ (if (= (length keep-isa) 1)
+ (current-isa-lookup (car keep-isa))
+ (error "multiple isas selected" keep-isa))))
+)
+
+; Return #t if an isa in ISA-LIST, a list of symbols, is to be kept.
+; If any isa in ISA-LIST is to be kept, the result is #t.
+; If ISA-LIST is the empty list (no particular isa specified) use the default
+; isa.
+
+(define (keep-isa? isa-list)
+ (if (null? isa-list)
+ (set! isa-list (list (car (current-arch-isa-name-list)))))
+ (let* ((keep (reader-keep-isa CURRENT-READER))
+ (keep? (map (lambda (i)
+ (or (memq i keep)
+ (memq 'all keep)))
+ isa-list)))
+ (any-true? keep?))
+)
+
+; Return #t if the object containing ATLIST is to be kept.
+; OBJ is the container object or #f if there is none.
+; The object is kept if its attribute list specifies an `ISA' that is
+; kept or does not have the `ISA' attribute (which means it has the default
+; value) and the default isa is being kept.
+
+(define (keep-isa-atlist? atlist obj)
+ (let ((isas (atlist-attr-value atlist 'ISA obj)))
+ (keep-isa? (map string->symbol (string-cut isas #\,))))
+)
+
+; Return non-#f if object OBJ is to be kept, according to its ISA attribute.
+
+(define (keep-isa-obj? obj)
+ (keep-isa-atlist? (obj-atlist obj) obj)
+)
+
+; Return a boolean indicating if multiple isas are being kept.
+
+(define (keep-isa-multiple?)
+ (let ((keep (reader-keep-isa CURRENT-READER)))
+ (or (> (length keep) 1)
+ (and (memq 'all keep)
+ (> (length (current-arch-isa-name-list)) 1))))
+)
+
+; Return list of isa names currently being kept.
+
+(define (current-keep-isa-name-list)
+ (reader-keep-isa CURRENT-READER)
+)
+
+; If #f, treat reserved fields as operands and extract them with the insn.
+; Code can then be emitted in the extraction routines to validate them.
+; If #t, treat reserved fields as part of the opcode.
+; This complicates the decoding process as these fields have to be
+; checked too.
+; ??? Unimplemented.
+
+(define option:reserved-as-opcode? #f)
+
+; Process options passed in on the command line.
+; OPTIONS is a space separated string of name=value values.
+; Each application is required to provide: option-init!, option-set!.
+
+(define (set-cgen-options! options)
+ (option-init!)
+ (for-each (lambda (opt)
+ (if (null? opt)
+ #t ; ignore extraneous spaces
+ (let ((name (string->symbol (car opt)))
+ (value (cdr opt)))
+ (logit 1 "Setting option `" name "' to \""
+ (apply string-append value) "\".\n")
+ (option-set! name value))))
+ (map (lambda (opt) (string-cut opt #\=))
+ (string-cut options #\space)))
+)
+
+; Application specific object creation support.
+;
+; Each entry in the .cpu file has a basic container class.
+; Each application adds functionality by subclassing the container
+; and registering with set-for-new! the proper class to create.
+; ??? Not sure this is the best way to handle this, but it does keep the
+; complexity down while not requiring as dynamic a language as I had before.
+; ??? Class local variables would provide a more efficient way to do this.
+; Assuming one wants to continue on this route.
+
+(define -cpu-new-class-list nil)
+
+(define (set-for-new! parent child)
+ (set! -cpu-new-class-list (acons parent child -cpu-new-class-list))
+)
+
+; Lookup the class registered with set-for-new!
+; If none registered, return PARENT.
+
+(define (lookup-for-new parent)
+ (let ((child (assq-ref -cpu-new-class-list parent)))
+ (if child
+ child
+ parent))
+)
+
+; .cpu file loader support
+
+; Prepare to parse a .cpu file.
+; This initializes the application independent tables.
+; KEEP-MACH specifies what machs to keep.
+; KEEP-ISA specifies what isas to keep.
+; OPTIONS is a list of options to control code generation.
+; The values are application dependent.
+
+(define (-init-parse-cpu! keep-mach keep-isa options)
+ (set! -cpu-new-class-list nil)
+
+ (set! CURRENT-READER (new <reader>))
+ (set! CURRENT-ARCH (new <arch>))
+ (-keep-mach-set! keep-mach)
+ (-keep-isa-set! keep-isa)
+ (set-cgen-options! options)
+
+ (reader-add-command! 'include
+ "Include a file.\n"
+ nil '(file) include
+ )
+ (reader-add-command! 'if
+ "(if test then . else)\n"
+ nil '(test then . else) cmd-if
+
+ )
+
+ ; Rather than add cgen specific stuff to pmacros.scm, we create
+ ; a define-pmacro command here.
+ (pmacros-init!)
+ (reader-add-command! 'define-pmacro
+ "\
+Define a preprocessor-style macro.
+"
+ nil '(name arg1 . arg-rest) define-pmacro)
+
+ ; The order here is important.
+ (arch-init!) ; Must be done first.
+ (enum-init!)
+ (attr-init!)
+ (types-init!)
+ (mach-init!)
+ (model-init!)
+ (mode-init!)
+ (ifield-init!)
+ (hardware-init!)
+ (operand-init!)
+ (insn-init!)
+ (minsn-init!)
+ (rtl-init!)
+ (rtl-c-init!)
+ (utils-init!)
+
+ *UNSPECIFIED*
+)
+
+; Install any builtin objects.
+; This is defered until define-arch is read.
+; One reason is that attributes MACH and ISA don't exist until then.
+
+(define (reader-install-builtin!)
+ ; The order here is important.
+ (attr-builtin!)
+ (mode-builtin!)
+ (ifield-builtin!)
+ (hardware-builtin!)
+ (operand-builtin!)
+ ; This is mainly for the insn attributes.
+ (insn-builtin!)
+ (rtl-builtin!)
+ *UNSPECIFIED*
+)
+
+; Do anything necessary for the application independent parts after parsing
+; a .cpu file.
+; The lists get cons'd in reverse order. One thing this does is change them
+; back to file order, it makes things easier for the human viewer.
+
+(define (-finish-parse-cpu!)
+ ; The order here is generally the reverse of init-parse-cpu!.
+ (rtl-finish!)
+ (minsn-finish!)
+ (insn-finish!)
+ (operand-finish!)
+ (hardware-finish!)
+ (ifield-finish!)
+ (mode-finish!)
+ (model-finish!)
+ (mach-finish!)
+ (types-finish!)
+ (attr-finish!)
+ (enum-finish!)
+ (arch-finish!) ; Must be done last.
+
+ *UNSPECIFIED*
+)
+
+; Perform a global error checking pass after the .cpu file has been read in.
+
+(define (-global-error-checks)
+ ; ??? None yet.
+ ; TODO:
+ ; - all hardware elements with same name must have same rank and
+ ; compatible modes (which for now means same float mode or all int modes)
+ #f
+)
+
+; .cpu file include mechanism
+
+(define (include file)
+ (display (string-append "Including file " file " ...\n"))
+ (reader-read-file! (string-append srcdir "/" file))
+ (logit 2 "Resuming previous file ...\n")
+)
+
+; Version of `if' invokable at the top level of a description file.
+; This is a work-in-progress. Its presence in the description file is ok,
+; but the implementation will need to evolve.
+
+(define (cmd-if test then . else)
+ (if (> (length else) 1)
+ (reader-error "wrong number of arguments to `if'"
+ (cons 'if (cons test (cons then else)))
+ ""))
+ ; ??? rtx-eval test
+ (if (not (memq (car test) '(keep-isa? keep-mach?)))
+ (reader-error "only (if (keep-mach?|keep-isa? ...) ...) is currently supported"))
+ (case (car test)
+ ((keep-isa?)
+ (if (keep-isa? (cadr test))
+ (eval then)
+ (if (null? else)
+ #f
+ (eval (car else)))))
+ ((keep-mach?)
+ (if (keep-mach? (cadr test))
+ (eval then)
+ (if (null? else)
+ #f
+ (eval (car else))))))
+)
+
+; Top level routine for loading .cpu files.
+; FILE is the name of the .cpu file to load.
+; KEEP-MACH is a string of comma separated machines to keep
+; (or not keep if prefixed with !).
+; KEEP-ISA is a string of comma separated isas to keep.
+; OPTIONS is the OPTIONS argument to -init-parse-cpu!.
+; APP-INITER! is an application specific zero argument proc (thunk)
+; to call after -init-parse-cpu!
+; APP-FINISHER! is an application specific zero argument proc to call after
+; -finish-parse-cpu!
+; ANALYZER! is a zero argument proc to call after loading the .cpu file.
+; It is expected to set up various tables and things useful for the application
+; in question.
+
+(define (cpu-load file keep-mach keep-isa options
+ app-initer! app-finisher! analyzer!)
+ (-init-parse-cpu! keep-mach keep-isa options)
+
+ (app-initer!)
+
+ ; This used to be done here, but is now defered until define-arch.
+ ;(reader-install-builtin!)
+
+ (display (string-append "Loading cpu file " file " ...\n"))
+
+ (reader-read-file! file)
+
+ (display (string-append "Processing cpu file " file " ...\n"))
+ (-finish-parse-cpu!)
+ (app-finisher!)
+ (-global-error-checks)
+ (analyzer!)
+ *UNSPECIFIED*
+)
+
+; Argument parsing utilities.
+
+; Generate a usage message.
+; ERRTYPE is one of 'help, 'unknown, 'missing.
+; OPTION is the option that had the error or "" if ERRTYPE is 'help.
+
+(define (cgen-usage errtype option arguments)
+ (let ((cep (current-error-port)))
+ (case errtype
+ ((help) #f)
+ ((unknown) (display (string-append "Unknown option: " option "\n") cep))
+ ((missing) (display (string-append "Missing argument: " option "\n") cep))
+ (else (display "Unknown error!\n" cep)))
+ (display "Usage: cgen arguments ...\n" cep)
+ (for-each (lambda (arg)
+ (display (string-append (car arg)
+ " " (if (cadr arg) (cadr arg) "")
+ " - " (caddr arg)
+ "\n")
+ cep))
+ arguments)
+ (display "...\n" cep)
+ (case errtype
+ ((help) (quit 0))
+ ((unknown missing) (quit 1))
+ (else (quit 2))))
+)
+
+; Poor man's getopt.
+; [We don't know where to find the real one until we've parsed the args,
+; and this isn't something we need to get too fancy about anyways.]
+; The result is always ((a . b) . c).
+; If the argument is valid, the result is ((opt-spec . arg) . remaining-argv),
+; or (('unknown . option) . remaining-argv) if `option' isn't recognized,
+; or (('missing . option) . remaining argv) if `option' is missing a required
+; argument,
+; or ((#f . #f) . #f) if there are no more arguments.
+; OPT-SPEC is a list of option specs.
+; Each element is an alist of at least 3 elements: option argument help-text.
+; `option' is a string or symbol naming the option. e.g. -a, --help, "-i".
+; symbols are supported for backward compatibility, -i is a complex number.
+; `argument' is a string naming the argument or #f if the option takes no
+; arguments.
+; `help-text' is a string that is printed with the usage information.
+; Elements beyond `help-text' are ignored.
+
+(define (-getopt argv opt-spec)
+ (if (null? argv)
+ (cons (cons #f #f) #f)
+ (let ((opt (assoc (car argv) opt-spec)))
+ (cond ((not opt) (cons (cons 'unknown (car argv)) (cdr argv)))
+ ((and (cadr opt) (null? (cdr argv)))
+ (cons (cons 'missing (car argv)) (cdr argv)))
+ ((cadr opt) (cons (cons opt (cadr argv)) (cddr argv)))
+ (else ; must be option that doesn't take an argument
+ (cons (cons opt #f) (cdr argv))))))
+)
+
+; Convert old style option spec to new style.
+; This involves converting a symbol option name to a string.
+
+(define (-opt-spec-update spec-list)
+ (map (lambda (spec)
+ (if (symbol? (car spec))
+ (cons (symbol->string (car spec)) (cdr spec))
+ spec))
+ spec-list)
+)
+
+; Used to ensure backtraces are printed if an error occurs.
+
+(define (catch-with-backtrace thunk)
+ (lazy-catch #t thunk
+ (lambda args
+ ;(display args (current-error-port))
+ ;(newline (current-error-port))
+ ; display-error takes 6 arguments.
+ ; If `quit' is called from elsewhere, it may not have 6
+ ; arguments. Not sure how best to handle this.
+ (if (= (length args) 5)
+ (begin
+ (apply display-error #f (current-error-port) (cdr args))
+ (save-stack)
+ (backtrace)))
+ (quit 1)))
+)
+
+; Return (cadr args) or print a pretty error message if not possible.
+
+(define (option-arg args)
+ (if (and (pair? args) (pair? (cdr args)))
+ (cadr args)
+ (parse-error "option processing" "missing argument to" (car args)))
+)
+
+; Record of arguments passed to debug-repl, so they can be accessed in
+; the repl loop.
+
+(define debug-env #f)
+
+; Return list of recorded variables for debugging.
+
+(define (debug-var-names) (map car debug-env))
+
+; Return value of recorded var NAME.
+
+(define (debug-var name) (assq-ref debug-env name))
+
+; Enter a repl loop for debugging purposes.
+; Use (quit) to exit cgen completely.
+; Use (debug-quit) or (quit 0) to exit the debugging session and
+; resume argument processing.
+;
+; ENV-ALIST can be anything, but it is intended to be an alist of values
+; the caller will want to be able to access in the repl loop.
+; It is stored in global `debug-env'.
+;
+; FIXME: Move to utils.scm.
+
+(define (debug-repl env-alist)
+ (set! debug-env env-alist)
+ (let loop ()
+ (let ((rc (top-repl)))
+ (if (null? rc)
+ (quit 1)) ; indicate error to `make'
+ (if (not (equal? rc '(0)))
+ (loop))))
+)
+
+; Utility for debug-repl.
+
+(define (debug-quit)
+ ; Keep around for later debugging.
+ ;(set! debug-env #f)
+
+ (quit 0)
+)
+
+; Macro to simplify calling debug-repl.
+; Usage: (debug-repl-env var-name1 var-name2 ...)
+
+(defmacro debug-repl-env var-names
+ (let ((env (map (lambda (var-name)
+ (list 'cons (list 'quote var-name) var-name))
+ var-names)))
+ (list 'debug-repl (cons 'list env)))
+)
+
+; List of common arguments.
+;
+; ??? Another useful arg would be one that says "do file generation with
+; arguments specified up til now, then continue with next batch of args".
+
+(define common-arguments
+ '(("-a" "arch" "set arch, specifies name of .cpu file to load")
+ ("-b" #f "use debugging evaluator, for backtraces")
+ ("-d" #f "start interactive debugging session")
+ ("-f" "flags" "specify a set of flags to control code generation")
+ ("-h" #f "print usage information")
+ ("--help" #f "print usage information")
+ ("-i" "isa-list" "specify isa-list entries to keep")
+ ("-m" "mach-list" "specify mach-list entries to keep")
+ ("-s" "srcdir" "set srcdir")
+ ("-v" #f "increment verbosity level")
+ ("--version" #f "print version info")
+ )
+)
+
+; Parse options and call generators.
+; ARGS is a #:keyword delimited list of arguments.
+; #:app-name name
+; #:arg-spec optspec ; FIXME: rename to #:opt-spec
+; #:init init-routine
+; #:finish finish-routine
+; #:analyze analysis-routine
+; #:argv command-line-arguments
+;
+; ARGSPEC is a list of (option option-arg comment option-handler) elements.
+; OPTION-HANDLER is either (lambda () ...) or (lambda (arg) ...) and
+; processes the option.
+
+(define -cgen
+ (lambda args
+ (let ((app-name "unknown")
+ (opt-spec nil)
+ (app-init! (lambda () #f))
+ (app-finish! (lambda () #f))
+ (app-analyze! (lambda () #f))
+ (argv (list "cgen"))
+ )
+ (let loop ((args args))
+ (if (not (null? args))
+ (case (car args)
+ ((#:app-name) (begin
+ (set! app-name (option-arg args))
+ (loop (cddr args))))
+ ((#:arg-spec) (begin
+ (set! opt-spec (option-arg args))
+ (loop (cddr args))))
+ ((#:init) (begin
+ (set! app-init! (option-arg args))
+ (loop (cddr args))))
+ ((#:finish) (begin
+ (set! app-finish! (option-arg args))
+ (loop (cddr args))))
+ ((#:analyze) (begin
+ (set! app-analyze! (option-arg args))
+ (loop (cddr args))))
+ ((#:argv) (begin
+ (set! argv (option-arg args))
+ (loop (cddr args))))
+ (else (error "cgen: unknown argument" (car args))))))
+
+ ; ARGS has been processed, now we can process ARGV.
+
+ (let (
+ (opt-spec (append common-arguments (-opt-spec-update opt-spec)))
+ (app-args nil) ; application's args are queued here
+ (repl? #f)
+ (arch #f)
+ (keep-mach "all") ; default is all machs
+ (keep-isa "all") ; default is all isas
+ (flags "")
+ (moreopts? #t)
+ (cep (current-error-port))
+ (str=? string=?)
+ )
+
+ (let loop ((argv (cdr argv)))
+ (let* ((new-argv (-getopt argv opt-spec))
+ (opt (caar new-argv))
+ (arg (cdar new-argv)))
+ (case opt
+ ((#f) (set! moreopts? #f))
+ ((unknown) (cgen-usage 'unknown arg opt-spec))
+ ((missing) (cgen-usage 'missing arg opt-spec))
+ (else
+ (cond ((str=? "-a" (car opt))
+ (set! arch arg)
+ )
+ ((str=? "-b" (car opt))
+ (if (memq 'debug-extensions *features*)
+ (begin
+ (debug-enable 'backtrace)
+ (debug-enable 'debug)
+ (debug-enable 'backwards)
+ (debug-set! depth 200)
+ (debug-set! frames 10)
+ (read-enable 'positions)))
+ )
+ ((str=? "-d" (car opt))
+ (let ((prompt (string-append "cgen-" app-name "> ")))
+ (set! repl? #t)
+ (set-repl-prompt! prompt)
+ (if (feature? 'readline)
+ (set-readline-prompt! prompt))
+ ))
+ ((str=? "-f" (car opt))
+ (set! flags arg)
+ )
+ ((str=? "-h" (car opt))
+ (cgen-usage 'help "" opt-spec)
+ )
+ ((str=? "--help" (car opt))
+ (cgen-usage 'help "" opt-spec)
+ )
+ ((str=? "-i" (car opt))
+ (set! keep-isa arg)
+ )
+ ((str=? "-m" (car opt))
+ (set! keep-mach arg)
+ )
+ ((str=? "-s" (car opt))
+ #f ; ignore, already processed by caller
+ )
+ ((str=? "-v" (car opt))
+ (verbose-inc!)
+ )
+ ((str=? "--version" (car opt))
+ (begin
+ (display "Cpu tools GENerator version ")
+ (display (cgen-major))
+ (display ".")
+ (display (cgen-minor))
+ (display ".")
+ (display (cgen-fixlevel))
+ (newline)
+ (quit 0)
+ ))
+ ; Else this is an application specific option.
+ (else
+ ; Record it for later processing. Note that they're
+ ; recorded in reverse order (easier). This is undone
+ ; later.
+ (set! app-args (acons opt arg app-args)))
+ )))
+ (if moreopts? (loop (cdr new-argv)))
+ )
+ ) ; end of loop
+
+ ; All arguments have been parsed.
+
+ (if (not arch)
+ (error "-a option missing, no architecture specified"))
+
+ (if repl?
+ (debug-repl nil))
+ (cpu-load (string-append srcdir "/" arch ".cpu")
+ keep-mach keep-isa flags
+ app-init! app-finish! app-analyze!)
+ ; Start another repl loop if -d.
+ ; Awkward. Both places are useful, though this is more useful.
+ (if repl?
+ (debug-repl nil))
+
+ ; Done with processing the arguments. Call the application's
+ ; file generators.
+
+ (for-each (lambda (opt-arg)
+ (let ((opt (car opt-arg))
+ (arg (cdr opt-arg)))
+ (if (cadr opt)
+ ((cadddr opt) arg)
+ ((cadddr opt)))))
+ (reverse app-args))
+ )
+ )
+ #f) ; end of lambda
+)
+
+; Main entry point called by application file generators.
+; Cover fn to -cgen that uses catch-with-backtrace.
+; ??? (debug-enable 'backtrace) might also work except I seem to remember
+; having problems with it. They may be fixed now.
+
+(define cgen
+ (lambda args
+ (catch-with-backtrace (lambda () (apply -cgen args))))
+)
diff --git a/cgen/rtl-c.scm b/cgen/rtl-c.scm
new file mode 100644
index 00000000000..0469c9be6d6
--- /dev/null
+++ b/cgen/rtl-c.scm
@@ -0,0 +1,1662 @@
+; RTL->C translation support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Generating C from RTL
+; ---------------------
+; The main way to generate C code from an RTL expression is:
+;
+; (rtl-c mode '(func mode ...) nil)
+;
+; E.g.
+; (rtl-c DFLT '(add SI (const SI 1) (const SI 2)) nil)
+; -->
+; "ADDSI (1, 2)"
+; Mode `DFLT' (DEFAULTmode) means "use the default/natural mode".
+;
+; The expression is in source form or may be already compiled (with
+; rtx-compile).
+;
+; The `set' rtx needs to be handled a little carefully.
+; Both the dest and src are processed first, and then code to perform the
+; assignment is computed. However, the dest may require more than a simple
+; C assignment. Therefore set dests are converted to the specified object
+; (e.g. a hardware operand) and then a message is sent to this object to
+; perform the actual code generation.
+;
+; All interesting operands (e.g. regs, mem) are `operand' objects.
+; The following messages must be supported by operand objects.
+; - get-mode - return mode of operand
+; - cxmake-get - return <c-expr> object containing operand's value
+; - gen-set-quiet - return string of C code to set operand's value (no tracing)
+; - gen-set-trace - return string of C code to set operand's value
+;
+; Instruction fields are refered to by name.
+; (estate-owner estate) must be an instruction that has the field.
+; Instruction ifields must have these methods:
+; - get-mode
+; - cxmake-get
+;
+; Conventions used in this file:
+; - see rtl.scm
+
+; The <c-expr> object.
+; This is a fully translated expression (i.e. C code).
+
+(define <c-expr>
+ (class-make '<c-expr> nil
+ '(
+ ; The mode of C-CODE.
+ mode
+ ; The translated C code.
+ c-code
+ ; The source expression, for debugging.
+ expr
+ ; Attributes of the expression.
+ atlist
+ ; List of temporaries required to compute the expression.
+ ; ??? wip. These would be combined as the expression is
+ ; built up. Then in sets and other statements, the temporaries
+ ; would be declared.
+ ;(tmps . nil)
+ )
+ nil)
+)
+
+(method-make!
+ <c-expr> 'make!
+ (lambda (self mode c-code atlist)
+ ; FIXME: Extend COS to allow specifying member predicates.
+ (assert (mode? mode))
+ (assert (string? c-code))
+ ;(assert (atlist? atlist)) ; FIXME: What should this be?
+ (elm-set! self 'mode mode)
+ (elm-set! self 'c-code c-code)
+ (elm-set! self 'atlist atlist)
+ self)
+)
+
+; Accessor fns
+
+(define cx:mode (elm-make-getter <c-expr> 'mode))
+(define cx:c-code (elm-make-getter <c-expr> 'c-code))
+(define cx:expr (elm-make-getter <c-expr> 'expr))
+(define cx:atlist (elm-make-getter <c-expr> 'atlist))
+;(define cx:tmps (elm-make-getter <c-expr> 'tmps))
+
+; Any object with attributes requires the get-atlist method.
+
+(method-make! <c-expr> 'get-atlist (lambda (self) (elm-get self 'atlist)))
+
+; Respond to 'get-mode messages.
+
+(method-make! <c-expr> 'get-mode (lambda (self) (elm-get self 'mode)))
+
+; Respond to 'get-name messages for rtx-dump.
+
+(method-make!
+ <c-expr> 'get-name
+ (lambda (self)
+ (string-append "(" (obj:name (elm-get self 'mode)) ") "
+ (cx:c self)))
+)
+
+; Return C code to perform an assignment.
+; NEWVAL is a <c-expr> object of the value to be assigned to SELF.
+
+(method-make! <c-expr> 'gen-set-quiet
+ (lambda (self estate mode indx selector newval)
+ (string-append " " (cx:c self) " = " (cx:c newval) ";\n"))
+)
+
+(method-make! <c-expr> 'gen-set-trace
+ (lambda (self estate mode indx selector newval)
+ (string-append " " (cx:c self) " = " (cx:c newval) ";\n"))
+)
+
+; Return the C code of CX.
+; ??? This used to handle lazy evaluation of the expression.
+; Maybe it will again, so it's left in, as a cover fn to cx:c-code.
+
+(define (cx:c cx)
+ (cx:c-code cx)
+)
+
+; Main routine to create a <c-expr> node object.
+; MODE is either the mode's symbol (e.g. 'QI) or a mode object.
+; CODE is a string of C code.
+
+(define (cx:make mode code)
+ (make <c-expr> (mode:lookup mode) code nil)
+)
+
+; Make copy of CX in new mode MODE.
+; MODE must be a <mode> object.
+
+(define (cx-new-mode mode cx)
+ (make <c-expr> mode (cx:c cx) (cx:atlist cx))
+)
+
+; Same as cx:make except with attributes.
+
+(define (cx:make-with-atlist mode code atlist)
+ (make <c-expr> (mode:lookup mode) code atlist)
+)
+
+; Return a boolean indicated if X is a <c-expr> object.
+
+(define (c-expr? x) (class-instance? <c-expr> x))
+
+; RTX environment support.
+
+(method-make!
+ <rtx-temp> 'cxmake-get
+ (lambda (self estate mode indx selector)
+ (cx:make mode (rtx-temp-value self)))
+)
+
+(method-make!
+ <rtx-temp> 'gen-set-quiet
+ (lambda (self estate mode indx selector src)
+ (string-append " " (rtx-temp-value self) " = " (cx:c src) ";\n"))
+)
+
+(method-make!
+ <rtx-temp> 'gen-set-trace
+ (lambda (self estate mode indx selector src)
+ (string-append " " (rtx-temp-value self) " = " (cx:c src) ";\n"))
+)
+
+(define (gen-temp-defs estate env)
+ (string-map (lambda (temp)
+ (let ((temp-obj (cdr temp)))
+ (string-append " " (mode:c-type (rtx-temp-mode temp-obj))
+ " " (rtx-temp-value temp-obj) ";\n")))
+ env)
+)
+
+; Top level routines to handle rtl->c translation.
+
+; rtl->c configuration parameters
+
+; #t -> emit calls to rtl cover fns, otherwise emit plain C where possible.
+(define -rtl-c-rtl-cover-fns? #f)
+
+; Called before emitting code to configure the generator.
+; ??? I think this can go away now (since cover-fn specification is also
+; done at each call to rtl-c).
+
+(define (rtl-c-config! . args)
+ (set! -rtl-c-rtl-cover-fns? #f)
+ (let loop ((args args))
+ (if (null? args)
+ #f ; done
+ (begin
+ (case (car args)
+ ((#:rtl-cover-fns?)
+ (set! -rtl-c-rtl-cover-fns? (cadr args)))
+ (else (error "rtl-c-config: unknown option:" (car args))))
+ (loop (cddr args)))))
+ *UNSPECIFIED*
+)
+
+; Subclass of <eval-state> to record additional things needed for rtl->c.
+
+(define <rtl-c-eval-state>
+ (class-make '<rtl-c-eval-state> '(<eval-state>)
+ '(
+ ; #t -> emit calls to rtl cover fns.
+ (rtl-cover-fns? . #f)
+
+ ; name of output language, "c" or "c++"
+ (output-language . "c")
+
+ ; #t if generating code for a macro.
+ ; Each newline is then preceeded with '\\'.
+ (macro? . #f)
+
+ ; #f -> reference ifield values using FLD macro.
+ ; #t -> use C variables.
+ ; ??? This is only needed to get correct ifield references
+ ; in opcodes, decoder, and semantics. Maybe a better way to
+ ; go would be to specify the caller's name so there'd be just
+ ; one of these, rather than an increasing number. However,
+ ; for now either way is the same.
+ ; An alternative is to specify a callback to try first.
+ (ifield-var? . #f)
+ )
+ nil)
+)
+
+; FIXME: involves upcasting.
+(define-getters <rtl-c-eval-state> estate
+ (rtl-cover-fns? output-language macro? ifield-var?)
+)
+
+; Return booleans indicating if output language is C/C++.
+
+(define (estate-output-language-c? estate)
+ (string=? (estate-output-language estate) "c")
+)
+(define (estate-output-language-c++? estate)
+ (string=? (estate-output-language estate) "c++")
+)
+
+(method-make!
+ <rtl-c-eval-state> 'vmake!
+ (lambda (self args)
+ ; Initialize parent class first.
+ (let loop ((args (send-next self 'vmake! args)) (unrecognized nil))
+ (if (null? args)
+ (reverse! unrecognized) ; ??? Could invoke method to initialize here.
+ (begin
+ (case (car args)
+ ((#:rtl-cover-fns?)
+ (elm-set! self 'rtl-cover-fns? (cadr args)))
+ ((#:output-language)
+ (elm-set! self 'output-language (cadr args)))
+ ((#:macro?)
+ (elm-set! self 'macro? (cadr args)))
+ ((#:ifield-var?)
+ (elm-set! self 'ifield-var? (cadr args)))
+ (else
+ ; Build in reverse order, as we reverse it back when we're done.
+ (set! unrecognized
+ (cons (cadr args) (cons (car args) unrecognized)))))
+ (loop (cddr args) unrecognized)))))
+)
+
+; Build an estate for use in generating C.
+; CONTEXT is a <context> object or #f if there is none.
+; OWNER is the owner of the expression or #f if there is none.
+; EXTRA-VARS-ALIST is an association list of (symbol <mode> value)
+; elements to be used during value lookup.
+; OVERRIDES is a #:keyword/value list of parameters to apply last.
+
+(define (estate-make-for-rtl-c context owner extra-vars-alist
+ rtl-cover-fns? macro? overrides)
+ (apply vmake
+ (append!
+ (list
+ <rtl-c-eval-state>
+ #:context context
+ #:owner owner
+ #:expr-fn (lambda (rtx-obj expr mode estate)
+ (rtl-c-generator rtx-obj))
+ #:env (rtx-env-init-stack1 extra-vars-alist)
+ #:rtl-cover-fns? rtl-cover-fns?
+ #:macro? macro?)
+ overrides))
+)
+
+(define (estate-make-for-normal-rtl-c extra-vars-alist overrides)
+ (estate-make-for-rtl-c
+ #f ; FIXME: context
+ #f ; FIXME: owner
+ extra-vars-alist
+ -rtl-c-rtl-cover-fns?
+ #f ; macro?
+ overrides)
+)
+
+; Translate RTL expression EXPR to C.
+; ESTATE is the current rtx evaluation state.
+
+(define (rtl-c-with-estate estate mode expr)
+ (cx:c (rtl-c-get estate mode (rtx-eval-with-estate expr mode estate)))
+)
+
+; Translate parsed RTL expression X to a string of C code.
+; X must have already been fed through rtx-parse/rtx-compile.
+; MODE is the desired mode of the value or DFLT for "natural mode".
+; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value)
+; elements to be used during value lookup.
+; OVERRIDES is a #:keyword/value list of arguments to build the eval state
+; with.
+; ??? Maybe EXTRA-VARS-ALIST should be handled this way.
+
+(define (rtl-c-parsed mode x extra-vars-alist . overrides)
+ (let ((estate (estate-make-for-normal-rtl-c extra-vars-alist overrides)))
+ (rtl-c-with-estate estate mode x))
+)
+
+; Same as rtl-c-parsed but X is unparsed.
+
+(define (rtl-c mode x extra-vars-alist . overrides)
+ ; ??? rtx-compile could return a closure, then we wouldn't have to
+ ; pass EXTRA-VARS-ALIST to two routines here.
+ (let ((estate (estate-make-for-normal-rtl-c extra-vars-alist overrides)))
+ (rtl-c-with-estate estate mode (rtx-compile #f x extra-vars-alist)))
+)
+
+; C++ versions of rtl-c routines.
+
+; Build an estate for use in generating C++.
+; EXTRA-VARS-ALIST is an association list of (symbol <mode> value)
+; elements to be used during value lookup.
+; OVERRIDES is a #:keyword/value list of parameters to apply last.
+
+(define (estate-make-for-normal-rtl-c++ extra-vars-alist overrides)
+ (estate-make-for-rtl-c
+ #f ; FIXME: context
+ #f ; FIXME: owner
+ extra-vars-alist
+ -rtl-c-rtl-cover-fns?
+ #f ; macro?
+ (cons #:output-language (cons "c++" overrides)))
+)
+
+; Translate parsed RTL expression X to a string of C++ code.
+; X must have already been fed through rtx-parse/rtx-compile.
+; MODE is the desired mode of the value or DFLT for "natural mode".
+; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value)
+; elements to be used during value lookup.
+; OVERRIDES is a #:keyword/value list of arguments to build the eval state
+; with.
+; ??? Maybe EXTRA-VARS-ALIST should be handled this way.
+
+(define (rtl-c++-parsed mode x extra-vars-alist . overrides)
+ (let ((estate (estate-make-for-normal-rtl-c++ extra-vars-alist overrides)))
+ (rtl-c-with-estate estate mode x))
+)
+
+; Same as rtl-c-parsed but X is unparsed.
+
+(define (rtl-c++ mode x extra-vars-alist . overrides)
+ ; ??? rtx-compile could return a closure, then we wouldn't have to
+ ; pass EXTRA-VARS-ALIST to two routines here.
+ (let ((estate (estate-make-for-normal-rtl-c++ extra-vars-alist overrides)))
+ (rtl-c-with-estate estate mode (rtx-compile #f x extra-vars-alist)))
+)
+
+; Top level routines for getting/setting values.
+
+; Return a <c-expr> node to get the value of SRC in mode MODE.
+; ESTATE is the current rtl evaluation state.
+; SRC is one of:
+; - <c-expr> node
+; - rtl expression (e.g. '(add WI dr sr))
+; - sequence's local variable name
+; - sequence's local variable object
+; - operand name
+; - operand object
+; - a string of C code
+; FIXME: Reduce acceptable values of SRC.
+; The result has mode MODE, unless MODE is the "default mode indicator"
+; (DFLT) in which case the mode of the result is derived from SRC.
+; If SRC is a string, MODE can't be VOID or DFLT.
+;
+; ??? mode compatibility checks are wip
+
+(define (rtl-c-get estate mode src)
+ (logit 4 "(rtl-c-get " (mode-real-name mode) " " (rtx-strdump src) ")\n")
+
+ (let ((mode (mode:lookup mode)))
+
+ (cond ((c-expr? src)
+ (cond ((or (mode:eq? 'VOID mode)
+ (mode:eq? 'DFLT mode)
+ (mode:eq? (cx:mode src) mode))
+ src)
+ ((-rtx-mode-compatible? mode (cx:mode src))
+ (cx-new-mode mode src))
+ (else
+ (error (string-append "incompatible mode for "
+ "(" (obj:name (cx:mode src)) ") "
+ "\"" (cx:c src) "\""
+ ": ")
+ (obj:name mode)))))
+
+ ; The recursive call to rtl-c-get is in case the result of rtx-eval
+ ; is a hardware object, rtx-func object, or another rtl expression.
+ ((rtx? src)
+ (let ((evald-src (rtx-eval-with-estate src mode estate)))
+ ; There must have been some change, otherwise we'll loop forever.
+ (assert (not (eq? src evald-src)))
+ (rtl-c-get estate mode evald-src)))
+
+ ((or (and (symbol? src) (current-op-lookup src))
+ (operand? src))
+ (begin
+ (if (symbol? src)
+ (set! src (current-op-lookup src)))
+ (cond ((mode:eq? 'DFLT mode)
+ ; FIXME: If we fetch the mode here, operands can assume
+ ; they never get called with "default mode".
+ (send src 'cxmake-get estate mode #f #f))
+ ((-rtx-mode-compatible? mode (op:mode src))
+ (let ((mode (-rtx-lazy-sem-mode mode)))
+ (send src 'cxmake-get estate mode #f #f)))
+ (else
+ (error (string-append "operand " (obj:name src)
+ " referenced in incompatible mode: ")
+ (obj:name mode))))))
+
+ ((or (and (symbol? src) (rtx-temp-lookup (estate-env estate) src))
+ (rtx-temp? src))
+ (begin
+ (if (symbol? src)
+ (set! src (rtx-temp-lookup (estate-env estate) src)))
+ (cond ((mode:eq? 'DFLT mode)
+ (send src 'cxmake-get estate (rtx-temp-mode src) #f #f))
+ ((-rtx-mode-compatible? mode (rtx-temp-mode src))
+ (let ((mode (-rtx-lazy-sem-mode mode)))
+ (send src 'cxmake-get estate mode #f #f)))
+ (else (error (string-append "sequence temp " (rtx-temp-name src)
+ " referenced in incompatible mode: ")
+ (obj:name mode))))))
+
+ ((integer? src)
+ ; Default mode of string argument is INT.
+ (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode))
+ (cx:make INT (number->string src))
+ (cx:make mode (number->string src))))
+
+ ((string? src)
+ ; Default mode of string argument is INT.
+ (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode))
+ (cx:make INT src)
+ (cx:make mode src)))
+
+ (else (error "rtl-c-get: invalid argument:" src))))
+)
+
+; Return a <c-expr> object to set the value of DEST to SRC.
+; ESTATE is the current rtl evaluation state.
+; DEST is one of:
+; - <c-expr> node
+; - rtl expression (e.g. '(mem QI dr))
+; SRC is a <c-expr> object.
+; The mode of the result is always VOID (void).
+
+(define (rtl-c-set-quiet estate mode dest src)
+ ;(display (list 'rtl-c-set-quiet mode dest src)) (newline)
+ (let ((xdest (cond ((c-expr? dest)
+ dest)
+ ((rtx? dest)
+ (rtx-eval-with-estate dest mode estate))
+ (else
+ (error "rtl-c-set-quiet: invalid dest:" dest)))))
+ (if (not (object? xdest))
+ (error "rtl-c-set-quiet: invalid dest:" dest))
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (-rtx-obj-mode xdest)
+ (-rtx-lazy-sem-mode mode))))
+ (assert (mode? mode))
+ (cx:make VOID (send xdest 'gen-set-quiet
+ estate mode #f #f
+ (rtl-c-get estate mode src)))))
+)
+
+; Same as rtl-c-set-quiet except also print TRACE_RESULT message.
+; ??? One possible change is to defer the (rtl-c-get src) call to dest's
+; set handler. Such sources would be marked accordingly and rtl-c-get
+; would recognize them. This would allow, for example, passing the address
+; of the result to the computation.
+
+(define (rtl-c-set-trace estate mode dest src)
+ ;(display (list 'rtl-c-set-trace mode dest src)) (newline)
+ (let ((xdest (cond ((c-expr? dest)
+ dest)
+ ((rtx? dest)
+ (rtx-eval-with-estate dest mode estate))
+ (else
+ (error "rtl-c-set-trace: invalid dest:" dest)))))
+ (if (not (object? xdest))
+ (error "rtl-c-set-trace: invalid dest:" dest))
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (-rtx-obj-mode xdest) ; FIXME: internal routines
+ (-rtx-lazy-sem-mode mode))))
+ (assert (mode? mode))
+ (cx:make VOID (send xdest 'gen-set-trace
+ estate mode #f #f
+ (rtl-c-get estate mode src)))))
+)
+
+; Emit C code for each rtx function.
+
+; Table mapping rtx function to C generator.
+
+(define -rtl-c-gen-table #f)
+
+; Return the C generator for <rtx-func> F.
+
+(define (rtl-c-generator f)
+ (vector-ref -rtl-c-gen-table (rtx-num f))
+)
+
+; Support for explicit C/C++ code.
+; ??? Actually, "support for explicit foreign language code".
+; s-c-call needs a better name but "unspec" seems like obfuscation.
+; ??? Need to distinguish owner of call (cpu, ???).
+
+(define (s-c-call estate mode name . args)
+ (cx:make mode
+ (string-append
+ (if (estate-output-language-c++? estate)
+ (string-append "current_cpu->" name " (")
+ ; FIXME: Prepend @cpu@_ to name here, and delete @cpu@_ from
+ ; description file.
+ (string-append name " (current_cpu"))
+ (let ((c-args
+ (string-map (lambda (arg)
+ (string-append
+ ", "
+ (cx:c (rtl-c-get estate DFLT arg))))
+ args)))
+ (if (estate-output-language-c++? estate)
+ (string-drop 2 c-args)
+ c-args))
+ ; If the mode is VOID, this is a statement.
+ ; Otherwise it's an expression.
+ (if (or (mode:eq? 'DFLT mode)
+ (mode:eq? 'VOID mode))
+ ");\n"
+ ")")
+ ))
+)
+
+; Same as c-call except there is no particular owner of the call.
+; In general this means making a call to a non-member function,
+; whereas c-call makes calls to member functions (in C++ parlance).
+
+(define (s-c-raw-call estate mode name . args)
+ (cx:make mode
+ (string-append
+ name " ("
+ (string-drop 2
+ (string-map (lambda (elm)
+ (string-append
+ ", " (cx:c (rtl-c-get estate DFLT elm))))
+ args))
+ ; If the mode is VOID, this is a statement.
+ ; Otherwise it's an expression.
+ (if (or (mode:eq? 'DFLT mode)
+ (mode:eq? 'VOID mode))
+ ");\n"
+ ")")
+ ))
+)
+
+; Standard arithmetic operations.
+
+; Return a boolean indicating if a cover function/macro should be emitted
+; to perform an operation.
+; C-OP is a string containing the C operation or #f if there is none.
+; MODE is the mode of the operation.
+
+(define (-rtx-use-sem-fn? estate c-op mode)
+ ; If no C operation has been provided, use a macro, or
+ ; if this is the simulator and MODE is not a host mode, use a macro.
+; (or (not c-op)
+; (and (estate-rtl-cover-fns? estate)
+; (not (mode:host? mode))))
+ ; FIXME: The current definition is a temporary hack while host/target-ness
+ ; of INT/UINT is unresolved.
+ (and (not (obj-has-attr? mode 'FORCE-C))
+ (or (not c-op)
+ (and (estate-rtl-cover-fns? estate)
+ (or (insn? (estate-owner estate))
+ (not (mode:host? mode))))))
+)
+
+; One operand referenced, result is in same mode.
+
+(define (s-unop estate name c-op mode src)
+ (let* ((val (rtl-c-get estate mode src))
+ ; Refetch mode in case it was DFLT and ensure unsigned->signed.
+ (mode (cx:mode val))
+ (sem-mode (-rtx-sem-mode mode)))
+ ; FIXME: Argument checking.
+
+ (if (-rtx-use-sem-fn? estate c-op mode)
+ (if (mode-float? mode)
+ (cx:make sem-mode
+ (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->"
+ (string-downcase name)
+ (string-downcase (obj:name sem-mode))
+ ") (CGEN_CPU_FPU (current_cpu), "
+ (cx:c val) ")"))
+ (cx:make sem-mode
+ (string-append name (obj:name sem-mode)
+ " (" (cx:c val) ")")))
+ (cx:make mode ; not sem-mode on purpose
+ (string-append "(" c-op " ("
+ (cx:c val) "))"))))
+)
+
+; Two operands referenced in the same mode producing a result in the same mode.
+; If MODE is DFLT, use the mode of SRC1.
+;
+; ??? Will eventually want to handle floating point modes specially. Since
+; bigger modes may get clumsily passed (there is no pass by reference in C) and
+; since we want to eventually handle lazy transformation, FP values could be
+; passed by reference. This is easy in C++. C requires more work and is
+; defered until it's warranted.
+; Implementing this should probably be via a new cxmake-get-ref method,
+; rather then complicating cxmake-get. Ditto for rtl-c-get-ref/rtl-c-get.
+
+(define (s-binop estate name c-op mode src1 src2)
+ (let* ((val1 (rtl-c-get estate mode src1))
+ ; Refetch mode in case it was DFLT and ensure unsigned->signed.
+ (mode (cx:mode val1))
+ (sem-mode (-rtx-sem-mode mode))
+ (val2 (rtl-c-get estate mode src2)))
+ ; FIXME: Argument checking.
+
+ (if (-rtx-use-sem-fn? estate c-op mode)
+ (if (mode-float? mode)
+ (cx:make sem-mode
+ (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->"
+ (string-downcase name)
+ (string-downcase (obj:name sem-mode))
+ ") (CGEN_CPU_FPU (current_cpu), "
+ (cx:c val1) ", "
+ (cx:c val2) ")"))
+ (cx:make sem-mode
+ (string-append name (obj:name sem-mode)
+ " (" (cx:c val1) ", "
+ (cx:c val2) ")")))
+ (cx:make mode ; not sem-mode on purpose
+ (string-append "(("
+ (cx:c val1)
+ ") " c-op " ("
+ (cx:c val2)
+ "))"))))
+)
+
+; Same as s-binop except there's a third argument which is always one bit.
+
+(define (s-binop-with-bit estate name mode src1 src2 src3)
+ (let* ((val1 (rtl-c-get estate mode src1))
+ ; Refetch mode in case it was DFLT and ensure unsigned->signed.
+ (mode (-rtx-sem-mode (cx:mode val1)))
+ (val2 (rtl-c-get estate mode src2))
+ (val3 (rtl-c-get estate 'BI src3)))
+ ; FIXME: Argument checking.
+ (cx:make mode
+ (string-append name (obj:name mode)
+ " ("
+ (cx:c val1) ", "
+ (cx:c val2) ", "
+ (cx:c val3)
+ ")")))
+)
+
+; Shift operations are slightly different than binary operations:
+; the mode of src2 is any integral mode.
+; ??? Note that some cpus have a signed shift left that is semantically
+; different from a logical one. May need to create `sla' some day. Later.
+
+(define (s-shop estate name c-op mode src1 src2)
+ (let* ((val1 (rtl-c-get estate mode src1))
+ ; Refetch mode in case it was DFLT and ensure unsigned->signed
+ ; [sign of operation is determined from operation name, not mode].
+ (mode (cx:mode val1))
+ (sem-mode (-rtx-sem-mode mode))
+ (val2 (rtl-c-get estate mode src2)))
+ ; FIXME: Argument checking.
+
+ (if (-rtx-use-sem-fn? estate c-op mode)
+ (cx:make sem-mode
+ (string-append name (obj:name sem-mode)
+ " (" (cx:c val1) ", "
+ (cx:c val2) ")"))
+ (cx:make mode ; not sem-mode on purpose
+ (string-append "("
+ ; Ensure correct sign of shift.
+ (cond ((equal? name "SRL")
+ (string-append "("
+ (if (eq? (mode:class mode) 'UINT)
+ ""
+ "unsigned ")
+ (mode:non-mode-c-type mode)
+ ") "))
+ ((equal? name "SRA")
+ (string-append "("
+ (mode:non-mode-c-type mode)
+ ") "))
+ (else ""))
+ "(" (cx:c val1) ") "
+ c-op
+ " (" (cx:c val2) "))"))))
+)
+
+; Process andif, orif.
+; SRC1 and SRC2 have any arithmetic mode.
+; The result has mode BI.
+; ??? May want to use INT as BI may introduce some slowness
+; in the generated code.
+
+(define (s-boolifop estate name c-op src1 src2)
+ (let* ((val1 (rtl-c-get estate DFLT src1))
+ (val2 (rtl-c-get estate DFLT src2)))
+ ; FIXME: Argument checking.
+ ; If this is the simulator and MODE is not a host mode, use a macro.
+ ; ??? MODE here being the mode of SRC1. Maybe later.
+ (if (estate-rtl-cover-fns? estate)
+ (cx:make (mode:lookup 'BI)
+ (string-append name ; "BI", leave off mode, no need for it
+ " (" (cx:c val1) ", "
+ (cx:c val2) ")"))
+ (cx:make (mode:lookup 'BI)
+ (string-append "(("
+ (cx:c val1)
+ ") " c-op " ("
+ (cx:c val2)
+ "))"))))
+)
+
+; Mode conversions.
+
+(define (s-convop estate name mode s1)
+ ; Get S1 in its normal mode, then convert.
+ (let ((s (rtl-c-get estate DFLT s1))
+ (mode (mode:lookup mode)))
+ (if (and (not (estate-rtl-cover-fns? estate))
+ (mode:host? (cx:mode s)))
+ (cx:make mode
+ (string-append "((" (obj:name mode) ")"
+ " (" (obj:name (cx:mode s)) ")"
+ " (" (cx:c s) "))"))
+ (if (or (mode-float? mode)
+ (mode-float? (cx:mode s)))
+ (cx:make mode
+ (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->"
+ (string-downcase name)
+ (string-downcase (obj:name (-rtx-sem-mode (cx:mode s))))
+ (string-downcase (obj:name (-rtx-sem-mode mode)))
+ ") (CGEN_CPU_FPU (current_cpu), "
+ (cx:c s) ")"))
+ (cx:make mode
+ (string-append name
+ (obj:name (-rtx-sem-mode (cx:mode s)))
+ (obj:name (-rtx-sem-mode mode))
+ " (" (cx:c s) ")")))))
+)
+
+; Compare SRC1 and SRC2 in mode MODE. The result has mode BI.
+; NAME is one of eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu.
+; ??? May want a host int mode result as BI may introduce some slowness
+; in the generated code.
+
+(define (s-cmpop estate name c-op mode src1 src2)
+ (let* ((val1 (rtl-c-get estate mode src1))
+ ; Refetch mode in case it was DFLT.
+ (mode (cx:mode val1))
+ (val2 (rtl-c-get estate mode src2)))
+ ; FIXME: Argument checking.
+
+ ; If no C operation has been provided, use a macro, or
+ ; if this is the simulator and MODE is not a host mode, use a macro.
+ (if (-rtx-use-sem-fn? estate c-op mode)
+ (if (mode-float? mode)
+ (cx:make (mode:lookup 'BI)
+ (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->"
+ (string-downcase name)
+ (string-downcase (obj:name (-rtx-sem-mode mode)))
+ ") (CGEN_CPU_FPU (current_cpu), "
+ (cx:c val1) ", "
+ (cx:c val2) ")"))
+ (cx:make (mode:lookup 'BI)
+ (string-append (string-upcase name)
+ (if (memq name '(eq ne))
+ (obj:name (-rtx-sem-mode mode))
+ (obj:name mode))
+ " (" (cx:c val1) ", "
+ (cx:c val2) ")")))
+ (cx:make (mode:lookup 'BI)
+ (string-append "(("
+ (cx:c val1)
+ ") " c-op " ("
+ (cx:c val2)
+ "))"))))
+)
+
+; Conditional execution.
+
+; `if' in RTL has a result, like ?: in C.
+; We support both: one with a result (non VOID mode), and one without (VOID mode).
+; The non-VOID case must have an else part.
+; MODE is the mode of the result, not the comparison.
+; The comparison is expected to return a zero/non-zero value.
+; ??? Perhaps this should be a syntax-expr. Later.
+
+(define (s-if estate mode cond then . else)
+ (if (> (length else) 1)
+ (error "if: too many elements in `else' part" else))
+ (let ()
+ (if (or (mode:eq? 'DFLT mode)
+ (mode:eq? 'VOID mode))
+ (cx:make mode
+ (string-append "if (" (cx:c (rtl-c-get estate DFLT cond)) ")"
+ " {\n" (cx:c (rtl-c-get estate mode then)) "}"
+ (if (not (null? else))
+ (string-append " else {\n"
+ (cx:c (rtl-c-get estate mode (car else)))
+ "}\n")
+ "\n")
+ ))
+ (if (= (length else) 1)
+ (cx:make mode
+ (string-append "(("
+ (cx:c (rtl-c-get estate DFLT cond))
+ ") ? ("
+ (cx:c (rtl-c-get estate mode then))
+ ") : ("
+ (cx:c (rtl-c-get estate mode (car else)))
+ "))"))
+ (error "non-VoidMode `if' must have `else' part"))))
+)
+
+; A multiway `if'.
+; If MODE is VOID emit a series of if/else's.
+; If MODE is not VOID, emit a series of ?:'s.
+; COND-CODE-LIST is a list of lists, each sublist is a list of two elements:
+; condition, code. The condition part must return a zero/non-zero value, and
+; the code part is treated as a `sequence'.
+; This defer argument evaluation, the syntax
+; ((... condition ...) ... action ...)
+; needs special parsing.
+; FIXME: Need more error checking of arguments.
+
+(define (s-cond estate mode . cond-code-list)
+ (let ((vm? (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode))))
+ (if (null? cond-code-list)
+ (error "empty `cond'"))
+ (let ((if-part (if vm? "if (" "("))
+ (then-part (if vm? ") " ") ? "))
+ (elseif-part (if vm? " else if (" " : ("))
+ (else-part (if vm? " else " " : "))
+ (fi-part (if vm? "" ")")))
+ (let loop ((result
+ (string-append
+ if-part
+ (cx:c (rtl-c-get estate DFLT (caar cond-code-list)))
+ then-part
+ (cx:c (apply s-sequence
+ (cons estate
+ (cons mode
+ (cons nil
+ (cdar cond-code-list))))))))
+ (ccl (cdr cond-code-list)))
+ (cond ((null? ccl) (cx:make mode result))
+ ((eq? (caar ccl) 'else)
+ (cx:make mode
+ (string-append
+ result
+ else-part
+ (cx:c (apply s-sequence
+ (cons estate
+ (cons mode
+ (cons nil
+ (cdar ccl)))))))))
+ (else (loop (string-append
+ result
+ elseif-part
+ (cx:c (rtl-c-get estate DFLT (caar ccl)))
+ then-part
+ (cx:c (apply s-sequence
+ (cons estate
+ (cons mode
+ (cons nil
+ (cdar ccl)))))))
+ (cdr ccl)))))))
+)
+
+; Utility of s-case to print a case prefix (for lack of a better term).
+
+(define (-gen-case-prefix val)
+ (string-append " case "
+ (cond ((number? val)
+ (number->string val))
+ ((symbol? val)
+ (string-upcase (gen-c-symbol val))) ; yes, upcase
+ ((string? val) val)
+ (else
+ (parse-error "case:" "bad case" val)))
+ " : ")
+)
+
+; Utility of s-case to handle a void result.
+
+(define (s-case-vm estate test case-list)
+ (cx:make
+ VOID
+ (string-append
+ " switch ("
+ (cx:c (rtl-c-get estate DFLT test))
+ ")\n"
+ " {\n"
+ (string-map (lambda (case-entry)
+ (let ((caseval (car case-entry))
+ (code (cdr case-entry)))
+ (string-append
+ (cond ((list? caseval)
+ (string-map -gen-case-prefix caseval))
+ ((eq? 'else caseval)
+ (string-append " default : "))
+ (else
+ (-gen-case-prefix caseval)))
+ (cx:c (apply s-sequence
+ (cons estate (cons VOID (cons nil code)))))
+ " break;\n")))
+ case-list)
+ " }\n"))
+)
+
+; Utility of s-case-non-vm to generate code to perform the test.
+
+(define (-gen-non-vm-case-test estate mode test cases)
+ (assert (not (null? cases)))
+ (let loop ((result "") (cases cases))
+ (if (null? cases)
+ result
+ (let ((case (cond ((number? (car cases))
+ (car cases))
+ ((symbol? (car cases))
+ (if (enum-lookup-val (car cases))
+ (rtx-make 'enum mode (car cases))
+ (context-error (estate-context estate)
+ "symbol not an enum"
+ (car cases))))
+ (else (error "invalid case" (car cases))))))
+ (loop (string-append
+ result
+ (if (= (string-length result) 0)
+ ""
+ " || ")
+ (cx:c (rtl-c-get estate mode test))
+ " == "
+ (cx:c (rtl-c-get estate mode case)))
+ (cdr cases)))))
+)
+
+; Utility of s-case to handle a non-void result.
+; This is expanded as a series of ?:'s.
+
+(define (s-case-non-vm estate mode test case-list)
+ (let ((if-part "(")
+ (then-part ") ? ")
+ (elseif-part " : (")
+ (else-part " : ")
+ (fi-part ")"))
+ (let loop ((result
+ (string-append
+ if-part
+ (-gen-non-vm-case-test estate mode test (caar case-list))
+ then-part
+ (cx:c (apply s-sequence
+ (cons estate
+ (cons mode
+ (cons nil
+ (cdar case-list))))))))
+ (cl (cdr case-list)))
+ (cond ((null? cl) (cx:make mode result))
+ ((eq? (caar cl) 'else)
+ (cx:make mode
+ (string-append
+ result
+ else-part
+ (cx:c (apply s-sequence
+ (cons estate
+ (cons mode
+ (cons nil
+ (cdar cl)))))))))
+ (else (loop (string-append
+ result
+ elseif-part
+ (-gen-non-vm-case-test estate mode test (caar cl))
+ then-part
+ (cx:c (apply s-sequence
+ (cons estate
+ (cons mode
+ (cons nil
+ (cdar cl)))))))
+ (cdr cl))))))
+)
+
+; C switch statement
+; To follow convention, MODE is the first arg.
+; FIXME: What to allow for case choices is wip.
+
+(define (s-case estate mode test . case-list)
+ (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode))
+ (s-case-vm estate test case-list)
+ (s-case-non-vm estate mode test case-list))
+)
+
+; Parallels and Sequences
+
+; Temps for `parallel' are recorded differently than for `sequence'.
+; ??? I believe this is because there was an interaction between the two.
+
+(define -par-temp-list nil)
+
+; Record a temporary needed for a parallel in mode MODE.
+; We just need to record the mode with a unique name so we use a <c-expr>
+; object where the "expression" is the variable's name.
+
+(define (-par-new-temp! mode)
+ (set! -par-temp-list
+ (cons (cx:make mode (string-append "temp"
+ (number->string
+ (length -par-temp-list))))
+ -par-temp-list))
+ (car -par-temp-list)
+)
+
+; Return the next temp from the list, and leave the list pointing to the
+; next one.
+
+(define (-par-next-temp!)
+ (let ((result (car -par-temp-list)))
+ (set! -par-temp-list (cdr -par-temp-list))
+ result)
+)
+
+(define (-gen-par-temp-defns temp-list)
+ ;(display temp-list) (newline)
+ (string-append
+ " "
+ ; ??? mode:c-type
+ (string-map (lambda (temp) (string-append (obj:name (cx:mode temp)) " " (cx:c temp) ";"))
+ temp-list)
+ "\n")
+)
+
+; Parallels are handled by converting them into two sequences. The first has
+; all set destinations replaced with temps, and the second has all set sources
+; replaced with those temps.
+; ??? Revisit later to see if (if ...) and (set pc ...) is ok.
+; How about disallowing if's and jump's inside parallels?
+; One can still put a parallel inside an `if' however.
+
+(define (-par-replace-set-dests estate exprs)
+ (let ((sets (list 'set 'set-quiet
+ (rtx-lookup 'set) (rtx-lookup 'set-quiet))))
+ (letrec ((replace
+ (lambda (expr)
+ (let ((name (car expr))
+ (options (rtx-options expr))
+ (mode (rtx-mode expr)))
+ (if (memq name sets)
+ (list name
+ options
+ mode
+ (-par-new-temp! ; replace dest with temp
+ (if (mode:eq? 'DFLT mode)
+ (rtx-lvalue-mode-name estate (rtx-set-dest expr))
+ mode))
+ (rtx-set-src expr))
+ (cons name
+ (cons options
+ (cons mode (replace (rtx-args expr)))))))))
+ )
+ (map replace exprs)))
+)
+
+; This must process expressions in the same order as -par-replace-set-dests!
+
+(define (-par-replace-set-srcs estate exprs)
+ (let ((sets (list 'set 'set-quiet
+ (rtx-lookup 'set) (rtx-lookup 'set-quiet))))
+ (letrec ((replace
+ (lambda (expr)
+ (let ((name (car expr))
+ (options (rtx-options expr))
+ (mode (rtx-mode expr)))
+ (if (memq name sets)
+ (list name
+ options
+ mode
+ (rtx-set-dest expr)
+ (-par-next-temp!)) ; the source's temp
+ (cons name
+ (cons options
+ (cons mode (replace (cddr expr)))))))))
+ )
+ (map replace exprs)))
+)
+
+; Return a <c-expr> node for a `parallel'.
+
+(define (s-parallel estate . exprs)
+ (begin
+ ; Initialize -par-temp-list for -par-replace-set-dests.
+ (set! -par-temp-list nil)
+ (let* ((set-dests (string-map (lambda (e)
+ (rtl-c-with-estate estate VOID e))
+ (-par-replace-set-dests estate exprs)))
+ (temps (reverse! -par-temp-list)))
+ ; Initialize -par-temp-list for -par-replace-set-srcs.
+ (set! -par-temp-list temps)
+ (cx:make VOID
+ (string-append
+ ; FIXME: do {} while (0); doesn't get "optimized out"
+ ; internally by gcc, meaning two labels and a loop are
+ ; created for it to have to process. We can generate pretty
+ ; big files and can cause gcc to require *lots* of memory.
+ ; So let's try just {} ...
+ "{\n"
+ (-gen-par-temp-defns temps)
+ set-dests
+ (string-map (lambda (e)
+ (rtl-c-with-estate estate VOID e))
+ (-par-replace-set-srcs estate exprs))
+ "}\n")
+ )))
+)
+
+; Return a <c-expr> node for a `sequence'.
+
+(define (s-sequence estate mode env . exprs)
+ (let* ((env (rtx-env-make-locals env)) ; compile env
+ (estate (estate-push-env estate env)))
+ (if (or (mode:eq? 'DFLT mode)
+ (mode:eq? 'VOID mode))
+ (cx:make mode
+ (string-append
+ ; FIXME: do {} while (0); doesn't get "optimized out"
+ ; internally by gcc, meaning two labels and a loop are
+ ; created for it to have to process. We can generate pretty
+ ; big files and can cause gcc to require *lots* of memory.
+ ; So let's try just {} ...
+ "{\n"
+ (gen-temp-defs estate env)
+ (string-map (lambda (e)
+ (rtl-c-with-estate estate DFLT e))
+ exprs)
+ "}\n"))
+ (cx:make mode
+ (string-append
+ ; Don't use GCC extension unless necessary.
+ (if (rtx-env-empty? env) "(" "({ ")
+ (gen-temp-defs estate env)
+ (string-drop 2
+ (string-map
+ (lambda (e)
+ (string-append
+ ", "
+ (rtl-c-with-estate estate DFLT e)))
+ exprs))
+ (if (rtx-env-empty? env) ")" "; })")))))
+)
+
+; *****************************************************************************
+;
+; RTL->C generators for each rtx function.
+
+; Return code to set FN as the generator for RTX.
+
+(defmacro define-fn (rtx args expr . rest)
+ `(begin
+ (assert (rtx-lookup (quote ,rtx)))
+ (vector-set! table (rtx-num (rtx-lookup (quote ,rtx)))
+ (lambda ,args ,@(cons expr rest))))
+)
+
+(define (rtl-c-init!)
+ (set! -rtl-c-gen-table (rtl-c-build-table))
+ *UNSPECIFIED*
+)
+
+; The rest of this file is one big function to return the rtl->c lookup table.
+
+(define (rtl-c-build-table)
+ (let ((table (make-vector (rtx-max-num) #f)))
+
+; Error generation
+
+(define-fn error (estate options mode message)
+ (let ((c-call (s-c-call estate mode "cgen_rtx_error"
+ (string-append "\""
+ (backslash "\"" message)
+ "\""))))
+ (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode))
+ c-call
+ (cx:make mode (string-append "(" (cx:c c-call) ", 0)"))))
+)
+
+; Enum support
+
+(define-fn enum (estate options mode name)
+ (cx:make mode (string-upcase (gen-c-symbol name)))
+)
+
+; Instruction field support.
+; ??? This should build an operand object like -build-ifield-operand! does
+; in semantics.scm.
+; ??? Mode support is wip.
+
+(define-fn ifield (estate options mode ifld-name)
+ (if (estate-ifield-var? estate)
+ (cx:make 'UINT (gen-c-symbol ifld-name))
+ (cx:make 'UINT (string-append "FLD (" (gen-c-symbol ifld-name) ")")))
+; (let ((f (current-ifld-lookup ifld-name)))
+; (make <operand> ifld-name ifld-name
+; (atlist-cons (bool-attr-make 'SEM-ONLY #t)
+; (obj-atlist f))
+; (obj:name (ifld-hw-type f))
+; (obj:name (ifld-mode f))
+; (make <hw-index> 'anonymous
+; 'ifield (ifld-mode f) f)
+; nil #f #f))
+)
+
+; Operand support
+
+(define-fn operand (estate options mode object-or-name)
+ (cond ((operand? object-or-name)
+ object-or-name)
+ ((symbol? object-or-name)
+ (let ((object (current-op-lookup object-or-name)))
+ (if (not object)
+ (context-error (estate-context estate)
+ "undefined operand" object-or-name))
+ object))
+ (else
+ (context-error (estate-context estate)
+ "bad arg to `operand'" object-or-name)))
+)
+
+(define-fn xop (estate options mode object) object)
+
+(define-fn local (estate options mode object-or-name)
+ (cond ((rtx-temp? object-or-name)
+ object-or-name)
+ ((symbol? object-or-name)
+ (let ((object (rtx-temp-lookup (estate-env estate) object-or-name)))
+ (if (not object)
+ (context-error (estate-context estate)
+ "undefined local" object-or-name))
+ object))
+ (else
+ (context-error (estate-context estate)
+ "bad arg to `local'" object-or-name)))
+)
+
+(define-fn reg (estate options mode hw-elm . indx-sel)
+ (let ((indx (or (list-maybe-ref indx-sel 0) 0))
+ (sel (or (list-maybe-ref indx-sel 1) hw-selector-default)))
+ (s-hw estate mode hw-elm indx sel))
+)
+
+(define-fn raw-reg (estate options mode hw-elm . indx-sel)
+ (let ((indx (or (list-maybe-ref indx-sel 0) 0))
+ (sel (or (list-maybe-ref indx-sel 1) hw-selector-default)))
+ (let ((result (s-hw estate mode hw-elm indx sel)))
+ (obj-cons-attr! result (bool-attr-make 'RAW #t))
+ result))
+)
+
+(define-fn mem (estate options mode addr . sel)
+ (s-hw estate mode 'h-memory addr
+ (if (pair? sel) (car sel) hw-selector-default))
+)
+
+(define-fn pc (estate options mode)
+ s-pc
+)
+
+(define-fn ref (estate options mode name)
+ (if (not (insn? (estate-owner estate)))
+ (error "ref: not processing an insn"))
+ (cx:make 'UINT
+ (string-append
+ "(referenced & (1 << "
+ (number->string
+ (op:num (insn-lookup-op (estate-owner estate) name)))
+ "))"))
+)
+
+; ??? Maybe this should return an operand object.
+(define-fn index-of (estate options mode op)
+ (send (op:index (rtx-eval-with-estate op 'DFLT estate)) 'cxmake-get estate 'DFLT)
+)
+
+(define-fn clobber (estate options mode object)
+ (cx:make VOID "; /*clobber*/\n")
+)
+
+(define-fn delay (estate options mode n rtx)
+ (s-sequence (estate-with-modifiers estate '((#:delay))) VOID '() rtx) ; wip!
+)
+
+; Gets expanded as a macro.
+;(define-fn annul (estate yes?)
+; (s-c-call estate 'VOID "SEM_ANNUL_INSN" "pc" yes?)
+;)
+
+(define-fn skip (estate options mode yes?)
+ (send pc 'cxmake-skip estate yes?)
+ ;(s-c-call estate 'VOID "SEM_SKIP_INSN" "pc" yes?)
+)
+
+(define-fn eq-attr (estate options mode obj attr-name value)
+ (cx:make 'INT
+ (string-append "(GET_ATTR ("
+ (gen-c-symbol attr-name)
+ ") == "
+ (gen-c-symbol value)
+ ")"))
+)
+
+(define-fn attr (estate options mode owner attr-name)
+ (cond ((equal? owner '(current-insn () DFLT))
+ (s-c-raw-call estate 'INT "GET_ATTR"
+ (string-upcase (gen-c-symbol attr-name))))
+ (else (error "attr: unsupported object type:" owner)))
+)
+
+(define-fn const (estate options mode c)
+ (assert (not (mode:eq? 'VOID mode)))
+ (if (mode:eq? 'DFLT mode)
+ (set! mode 'INT))
+ (let ((mode (mode:lookup mode)))
+ (cx:make mode
+ (cond ((or (mode:eq? 'DI mode)
+ (mode:eq? 'UDI mode))
+ (string-append "MAKEDI ("
+ (gen-integer (high-part c)) ", "
+ (gen-integer (low-part c))
+ ")"))
+ ((and (<= #x-80000000 c) (> #x80000000 c))
+ (number->string c))
+ ((and (<= #x80000000 c) (>= #xffffffff c))
+ ; ??? GCC complains if not affixed with "U" but that's not k&r.
+ ;(string-append (number->string val) "U"))
+ (string-append "0x" (number->string c 16)))
+ ; Else punt.
+ (else (number->string c)))))
+)
+
+(define-fn join (estate options out-mode in-mode arg1 . arg-rest)
+ ; FIXME: Endianness issues undecided.
+ ; FIXME: Ensure correct number of args for in/out modes.
+ ; Ensure compatible modes.
+ (apply s-c-raw-call (cons estate
+ (cons out-mode
+ (cons (string-append "JOIN"
+ in-mode
+ out-mode)
+ (cons arg1 arg-rest)))))
+)
+
+(define-fn subword (estate options mode value word-num)
+ (let* ((mode (mode:lookup mode))
+ (val (rtl-c-get estate DFLT value))
+ ; Refetch mode in case it was DFLT.
+ (val-mode (cx:mode val)))
+ (cx:make mode
+ (string-append "SUBWORD" (obj:name val-mode) (obj:name mode)
+ " (" (cx:c val)
+ (if (mode-bigger? val-mode mode)
+ (string-append
+ ", "
+ (if (number? word-num)
+ (number->string word-num)
+ (cx:c (rtl-c-get estate DFLT word-num))))
+ "")
+ ")")))
+)
+
+(define-fn c-code (estate options mode text)
+ (cx:make mode text)
+)
+
+(define-fn c-call (estate options mode name . args)
+ (apply s-c-call (cons estate (cons mode (cons name args))))
+)
+
+(define-fn c-raw-call (estate options mode name . args)
+ (apply s-c-raw-call (cons estate (cons mode (cons name args))))
+)
+
+(define-fn nop (estate options mode)
+ (cx:make VOID "((void) 0); /*nop*/\n")
+)
+
+(define-fn set (estate options mode dst src)
+ (if (insn? (estate-owner estate))
+ (rtl-c-set-trace estate mode dst (rtl-c-get estate mode src))
+ (rtl-c-set-quiet estate mode dst (rtl-c-get estate mode src)))
+)
+
+(define-fn set-quiet (estate options mode dst src)
+ (rtl-c-set-quiet estate mode dst (rtl-c-get estate mode src))
+)
+
+(define-fn neg (estate options mode s1)
+ (s-unop estate "NEG" "-" mode s1)
+)
+
+(define-fn abs (estate options mode s1)
+ (s-unop estate "ABS" #f mode s1)
+)
+
+(define-fn inv (estate options mode s1)
+ (s-unop estate "INV" "~" mode s1)
+)
+
+(define-fn not (estate options mode s1)
+ (s-unop estate "NOT" "!" mode s1)
+)
+
+(define-fn add (estate options mode s1 s2)
+ (s-binop estate "ADD" "+" mode s1 s2)
+)
+(define-fn sub (estate options mode s1 s2)
+ (s-binop estate "SUB" "-" mode s1 s2)
+)
+
+(define-fn addc (estate options mode s1 s2 s3)
+ (s-binop-with-bit estate "ADDC" mode s1 s2 s3)
+)
+(define-fn add-cflag (estate options mode s1 s2 s3)
+ (s-binop-with-bit estate "ADDCF" mode s1 s2 s3)
+)
+(define-fn add-oflag (estate options mode s1 s2 s3)
+ (s-binop-with-bit estate "ADDOF" mode s1 s2 s3)
+)
+(define-fn subc (estate options mode s1 s2 s3)
+ (s-binop-with-bit estate "SUBC" mode s1 s2 s3)
+)
+(define-fn sub-cflag (estate options mode s1 s2 s3)
+ (s-binop-with-bit estate "SUBCF" mode s1 s2 s3)
+)
+(define-fn sub-oflag (estate options mode s1 s2 s3)
+ (s-binop-with-bit estate "SUBOF" mode s1 s2 s3)
+)
+
+;(define-fn zflag (estate options mode value)
+; (list 'eq mode value (list 'const mode 0))
+;)
+
+;(define-fn nflag (estate options mode value)
+; (list 'lt mode value (list 'const mode 0))
+;)
+
+(define-fn mul (estate options mode s1 s2)
+ (s-binop estate "MUL" "*" mode s1 s2)
+)
+(define-fn div (estate options mode s1 s2)
+ (s-binop estate "DIV" "/" mode s1 s2)
+)
+(define-fn udiv (estate options mode s1 s2)
+ (s-binop estate "UDIV" "/" mode s1 s2)
+)
+(define-fn mod (estate options mode s1 s2)
+ (s-binop estate "MOD" "%" mode s1 s2)
+)
+(define-fn umod (estate options mode s1 s2)
+ (s-binop estate "UMOD" "%" mode s1 s2)
+)
+
+(define-fn sqrt (estate options mode s1)
+ (s-unop estate "SQRT" #f mode s1)
+)
+(define-fn cos (estate options mode s1)
+ (s-unop estate "COS" #f mode s1)
+)
+(define-fn sin (estate options mode s1)
+ (s-unop estate "SIN" #f mode s1)
+)
+
+(define-fn min (estate options mode s1 s2)
+ (s-binop estate "MIN" #f mode s1 s2)
+)
+(define-fn max (estate options mode s1 s2)
+ (s-binop estate "MAX" #f mode s1 s2)
+)
+(define-fn umin (estate options mode s1 s2)
+ (s-binop estate "UMIN" #f mode s1 s2)
+)
+(define-fn umax (estate options mode s1 s2)
+ (s-binop estate "UMAX" #f mode s1 s2)
+)
+
+(define-fn and (estate options mode s1 s2)
+ (s-binop estate "AND" "&" mode s1 s2)
+)
+(define-fn or (estate options mode s1 s2)
+ (s-binop estate "OR" "|" mode s1 s2)
+)
+(define-fn xor (estate options mode s1 s2)
+ (s-binop estate "XOR" "^" mode s1 s2)
+)
+
+(define-fn sll (estate options mode s1 s2)
+ (s-shop estate "SLL" "<<" mode s1 s2)
+)
+(define-fn srl (estate options mode s1 s2)
+ (s-shop estate "SRL" ">>" mode s1 s2)
+)
+(define-fn sra (estate options mode s1 s2)
+ (s-shop estate "SRA" ">>" mode s1 s2)
+)
+(define-fn ror (estate options mode s1 s2)
+ (s-shop estate "ROR" #f mode s1 s2)
+)
+(define-fn rol (estate options mode s1 s2)
+ (s-shop estate "ROL" #f mode s1 s2)
+)
+
+(define-fn andif (estate options mode s1 s2)
+ (s-boolifop estate "ANDIF" "&&" s1 s2)
+)
+(define-fn orif (estate options mode s1 s2)
+ (s-boolifop estate "ORIF" "||" s1 s2)
+)
+
+(define-fn ext (estate options mode s1)
+ (s-convop estate "EXT" mode s1)
+)
+(define-fn zext (estate options mode s1)
+ (s-convop estate "ZEXT" mode s1)
+)
+(define-fn trunc (estate options mode s1)
+ (s-convop estate "TRUNC" mode s1)
+)
+(define-fn fext (estate options mode s1)
+ (s-convop estate "FEXT" mode s1)
+)
+(define-fn ftrunc (estate options mode s1)
+ (s-convop estate "FTRUNC" mode s1)
+)
+(define-fn float (estate options mode s1)
+ (s-convop estate "FLOAT" mode s1)
+)
+(define-fn ufloat (estate options mode s1)
+ (s-convop estate "UFLOAT" mode s1)
+)
+(define-fn fix (estate options mode s1)
+ (s-convop estate "FIX" mode s1)
+)
+(define-fn ufix (estate options mode s1)
+ (s-convop estate "UFIX" mode s1)
+)
+
+(define-fn eq (estate options mode s1 s2)
+ (s-cmpop estate 'eq "==" mode s1 s2)
+)
+(define-fn ne (estate options mode s1 s2)
+ (s-cmpop estate 'ne "!=" mode s1 s2)
+)
+
+(define-fn lt (estate options mode s1 s2)
+ (s-cmpop estate 'lt "<" mode s1 s2)
+)
+(define-fn le (estate options mode s1 s2)
+ (s-cmpop estate 'le "<=" mode s1 s2)
+)
+(define-fn gt (estate options mode s1 s2)
+ (s-cmpop estate 'gt ">" mode s1 s2)
+)
+(define-fn ge (estate options mode s1 s2)
+ (s-cmpop estate 'ge ">=" mode s1 s2)
+)
+
+(define-fn ltu (estate options mode s1 s2)
+ (s-cmpop estate 'ltu "<" mode s1 s2)
+)
+(define-fn leu (estate options mode s1 s2)
+ (s-cmpop estate 'leu "<=" mode s1 s2)
+)
+(define-fn gtu (estate options mode s1 s2)
+ (s-cmpop estate 'gtu ">" mode s1 s2)
+)
+(define-fn geu (estate options mode s1 s2)
+ (s-cmpop estate 'geu ">=" mode s1 s2)
+)
+
+(define-fn member (estate options mode value set)
+ ; FIXME: Multiple evalutions of VALUE.
+ (let ((c-value (rtl-c-get estate 'DFLT value))
+ (set (rtx-number-list-values set)))
+ (let loop ((set (cdr set))
+ (code (string-append "(" (cx:c c-value)
+ " == "
+ (gen-integer (car set))
+ ")")))
+ (if (null? set)
+ (cx:make (mode:lookup 'BI) (string-append "(" code ")"))
+ (loop (cdr set)
+ (string-append code
+ " || ("
+ (cx:c c-value)
+ " == "
+ (gen-integer (car set))
+ ")")))))
+)
+
+(define-fn if (estate options mode cond then . else)
+ (apply s-if (append! (list estate mode cond then) else))
+)
+
+(define-fn cond (estate options mode . cond-code-list)
+ (apply s-cond (cons estate (cons mode cond-code-list)))
+)
+
+(define-fn case (estate options mode test . case-list)
+ (apply s-case (cons estate (cons mode (cons test case-list))))
+)
+
+(define-fn parallel (estate options mode ignore expr . exprs)
+ (apply s-parallel (cons estate (cons expr exprs)))
+)
+
+(define-fn sequence (estate options mode locals expr . exprs)
+ (apply s-sequence
+ (cons estate (cons mode (cons locals (cons expr exprs)))))
+)
+
+(define-fn closure (estate options mode expr env)
+ ; ??? estate-push-env?
+ (rtl-c-with-estate (estate-new-env estate env) DFLT expr)
+)
+
+; The result is the rtl->c generator table.
+table
+)) ; End of rtl-c-build-table
diff --git a/cgen/rtl.scm b/cgen/rtl.scm
new file mode 100644
index 00000000000..c6c55b40bd3
--- /dev/null
+++ b/cgen/rtl.scm
@@ -0,0 +1,2205 @@
+; Basic RTL support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; The name for the description language has been changed a couple of times.
+; RTL isn't my favorite because of perceived confusion with GCC
+; (and perceived misinterpretation of intentions!).
+; On the other hand my other choices were taken (and believed to be
+; more confusing).
+;
+; RTL functions are described by class <rtx-func>.
+; The complete list of rtl functions is defined in doc/rtl.texi.
+
+; Conventions used in this file:
+; - procs that perform the basic rtl or semantic expression manipulation that
+; is for public use shall be prefixed with "s-" or "rtl-" or "rtx-"
+; - no other procs shall be so prefixed
+; - rtl globals and other rtx-func object support shall be prefixed with
+; "-rtx[-:]"
+; - no other procs shall be so prefixed
+
+; Class for defining rtx nodes.
+
+; FIXME: Add new members that are lambda's to perform the argument checking
+; specified by `arg-types' and `arg-modes'. This will save a lookup during
+; traversing. It will also allow custom versions for oddballs (e.g. for
+; `member' we want to verify the 2nd arg is a `number-list' rtx).
+; ??? Still useful?
+
+(define <rtx-func>
+ (class-make '<rtx-func> nil
+ '(
+ ; name as it appears in RTL
+ name
+
+ ; argument list
+ args
+
+ ; types of each argument, as symbols
+ ; This is #f for macros.
+ ; Possible values:
+ ; OPTIONS - optional list of :-prefixed options.
+ ; ANYMODE - any mode
+ ; INTMODE - any integer mode
+ ; FLOATMODE - any floating point mode
+ ; NUMMODE - any numeric mode
+ ; EXPLNUMMODE - explicit numeric mode, can't be DFLT or VOID
+ ; NONVOIDMODE - can't be `VOID'
+ ; VOIDMODE - must be `VOID'
+ ; DFLTMODE - must be `DFLT', used when any mode is inappropriate
+ ; RTX - any rtx
+ ; SETRTX - any rtx allowed to be `set'
+ ; TESTRTX - the test of an `if'
+ ; CONDRTX - a cond expression ((test) rtx ... rtx)
+ ; CASERTX - a case expression ((symbol .. symbol) rtx ... rtx)
+ ; LOCALS - the locals list of a sequence
+ ; ENV - environment stack
+ ; ATTRS - attribute list
+ ; SYMBOL - operand must be a symbol
+ ; STRING - operand must be a string
+ ; NUMBER - operand must be a number
+ ; SYMORNUM - operand must be a symbol or number
+ ; OBJECT - operand is an object
+ arg-types
+
+ ; required mode of each argument
+ ; This is #f for macros.
+ ; Possible values include any mode name and:
+ ; ANY - any mode
+ ; NA - not applicable
+ ; OP0 - mode is specified in operand 0
+ ; unless it is DFLT in which case use the default mode
+ ; of the operand
+ ; MATCH1 - must match mode of operand 1
+ ; which will have OP0 for its mode spec
+ ; MATCH2 - must match mode of operand 2
+ ; which will have OP0 for its mode spec
+ ; <MODE-NAME> - must match specified mode
+ arg-modes
+
+ ; The class of rtx.
+ ; This is #f for macros.
+ ; ARG - operand, local, const
+ ; SET - set
+ ; UNARY - not, inv, etc.
+ ; BINARY - add, sub, etc.
+ ; TRINARY - addc, subc, etc.
+ ; IF - if
+ ; COND - cond, case
+ ; SEQUENCE - sequence, parallel
+ ; UNSPEC - c-call
+ ; MISC - everything else
+ class
+
+ ; A symbol indicating the flavour of rtx node this is.
+ ; function - normal function
+ ; syntax - don't pre-eval arguments
+ ; operand - result is an operand
+ ; macro - converts one rtx expression to another
+ ; The word "style" was chosen to be sufficiently different
+ ; from "type", "kind", and "class".
+ style
+
+ ; A function to perform the rtx.
+ evaluator
+
+ ; Ordinal number of rtx. Used to index into tables.
+ num
+ )
+ nil)
+)
+
+; Predicate.
+
+(define (rtx-func? x) (class-instance? <rtx-func> x))
+
+; Accessor fns
+
+(define-getters <rtx-func> rtx
+ (name args arg-types arg-modes class style evaluator num)
+)
+
+(define (rtx-class-arg? rtx) (eq? (rtx-class rtx) 'ARG))
+(define (rtx-class-set? rtx) (eq? (rtx-class rtx) 'SET))
+(define (rtx-class-unary? rtx) (eq? (rtx-class rtx) 'UNARY))
+(define (rtx-class-binary? rtx) (eq? (rtx-class rtx) 'BINARY))
+(define (rtx-class-trinary? rtx) (eq? (rtx-class rtx) 'TRINARY))
+(define (rtx-class-if? rtx) (eq? (rtx-class rtx) 'IF))
+(define (rtx-class-cond? rtx) (eq? (rtx-class rtx) 'COND))
+(define (rtx-class-sequence? rtx) (eq? (rtx-class rtx) 'SEQUENCE))
+(define (rtx-class-unspec? rtx) (eq? (rtx-class rtx) 'UNSPEC))
+(define (rtx-class-misc? rtx) (eq? (rtx-class rtx) 'MISC))
+
+(define (rtx-style-function? rtx) (eq? (rtx-style rtx) 'function))
+(define (rtx-style-syntax? rtx) (eq? (rtx-style rtx) 'syntax))
+(define (rtx-style-operand? rtx) (eq? (rtx-style rtx) 'operand))
+(define (rtx-style-macro? rtx) (eq? (rtx-style rtx) 'macro))
+
+; Add standard `get-name' method since this isn't a subclass of <ident>.
+
+(method-make! <rtx-func> 'get-name (lambda (self) (elm-get self 'name)))
+
+; List of valid values for arg-types, not including mode names.
+
+(define -rtx-valid-types
+ '(OPTIONS
+ ANYMODE INTMODE FLOATMODE NUMMODE EXPLNUMMODE NONVOIDMODE VOIDMODE DFLTMODE
+ RTX TESTRTX CONDRTX CASERTX
+ LOCALS ENV ATTRS SYMBOL STRING NUMBER SYMORNUM OBJECT)
+)
+
+; List of valid mode matchers, excluding mode names.
+
+(define -rtx-valid-matches
+ '(ANY NA OP0 MATCH1 MATCH2)
+)
+
+; List of all defined rtx names. This can be map'd over without having
+; to know the innards of -rtx-func-table (which is a hash table).
+
+(define -rtx-name-list nil)
+(define (rtx-name-list) -rtx-name-list)
+
+; Table of rtx function objects.
+; This is set in rtl-init!.
+
+(define -rtx-func-table nil)
+
+; Look up the <rtx-func> object for RTX-KIND.
+; Returns the object or #f if not found.
+; RTX-KIND may already be an <rtx-func> object. FIXME: delete?
+
+(define (rtx-lookup rtx-kind)
+ (cond ((symbol? rtx-kind)
+ (hashq-ref -rtx-func-table rtx-kind))
+ ((rtx-func? rtx-kind)
+ rtx-kind)
+ (else #f))
+)
+
+; Table of rtx macro objects.
+; This is set in rtl-init!.
+
+(define -rtx-macro-table nil)
+
+; Table of operands, modes, and other non-functional aspects of RTL.
+; This is defined in rtl-finish!, after all operands have been read in.
+
+(define -rtx-operand-table nil)
+
+; Number of next rtx to be defined.
+
+(define -rtx-num-next #f)
+
+; Return the number of rtx's.
+
+(define (rtx-max-num)
+ -rtx-num-next
+)
+
+; Define Rtx Node
+;
+; Add an entry to the rtx function table.
+; NAME-ARGS is a list of the operation name and arguments.
+; The mode of the result must be the first element in `args' (if there are
+; any arguments).
+; ARG-TYPES is a list of argument types (-rtx-valid-types).
+; ARG-MODES is a list of mode matchers (-rtx-valid-matches).
+; ACTION is a list of Scheme expressions to perform the operation.
+;
+; ??? Note that we can support variables. Not sure it should be done.
+
+(define (def-rtx-node name-args arg-types arg-modes class action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args
+ arg-types arg-modes
+ class
+ 'function
+ (if action
+ (eval (list 'lambda (cons '*estate* args) action))
+ #f)
+ -rtx-num-next)))
+ ; Add it to the table of rtx handlers.
+ (hashq-set! -rtx-func-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-node arg-list)
+ nil))
+)
+
+; Same as define-rtx-node but don't pre-evaluate the arguments.
+; Remember that `mode' must be the first argument.
+
+(define (def-rtx-syntax-node name-args arg-types arg-modes class action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args
+ arg-types arg-modes
+ class
+ 'syntax
+ (if action
+ (eval (list 'lambda (cons '*estate* args) action))
+ #f)
+ -rtx-num-next)))
+ ; Add it to the table of rtx handlers.
+ (hashq-set! -rtx-func-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-syntax-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-syntax-node arg-list)
+ nil))
+)
+
+; Same as define-rtx-node but return an operand (usually an <operand> object).
+; ??? `mode' must be the first argument?
+
+(define (def-rtx-operand-node name-args arg-types arg-modes class action)
+ ; Operand nodes must specify an action.
+ (assert action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args
+ arg-types arg-modes
+ class
+ 'operand
+ (eval (list 'lambda (cons '*estate* args) action))
+ -rtx-num-next)))
+ ; Add it to the table of rtx handlers.
+ (hashq-set! -rtx-func-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-operand-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-operand-node arg-list)
+ nil))
+)
+
+; Convert one rtx expression into another.
+; NAME-ARGS is a list of the operation name and arguments.
+; ACTION is a list of Scheme expressions to perform the operation.
+; The result of ACTION must be another rtx expression (a list).
+
+(define (def-rtx-macro-node name-args action)
+ ; macro nodes must specify an action
+ (assert action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args #f #f
+ #f ; class
+ 'macro
+ (eval (list 'lambda args action))
+ -rtx-num-next)))
+ ; Add it to the table of rtx macros.
+ (hashq-set! -rtx-macro-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-macro-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-macro-node arg-list)
+ nil))
+)
+
+; RTL macro expansion.
+; RTL macros are different than pmacros. The difference is that the expansion
+; happens internally, RTL macros are part of the language.
+
+; Lookup MACRO-NAME and return its <rtx-func> object or #f if not found.
+
+(define (-rtx-macro-lookup macro-name)
+ (hashq-ref -rtx-macro-table macro-name)
+)
+
+; Lookup (car exp) and return the macro's lambda if it is one or #f.
+
+(define (-rtx-macro-check exp fn-getter)
+ (let ((macro (hashq-ref -rtx-macro-table (car exp))))
+ (if macro
+ (fn-getter macro)
+ #f))
+)
+
+; Expand a list.
+
+(define (-rtx-macro-expand-list exp fn-getter)
+ (let ((macro (-rtx-macro-check exp fn-getter)))
+ (if macro
+ (apply macro (map (lambda (x) (-rtx-macro-expand x fn-getter))
+ (cdr exp)))
+ (map (lambda (x) (-rtx-macro-expand x fn-getter))
+ exp)))
+)
+
+; Main entry point to expand a macro invocation.
+
+(define (-rtx-macro-expand exp fn-getter)
+ (if (pair? exp) ; pair? -> cheap (and (not (null? exp)) (list? exp))
+ (let ((result (-rtx-macro-expand-list exp fn-getter)))
+ ; If the result is a new macro invocation, recurse.
+ (if (pair? result)
+ (let ((macro (-rtx-macro-check result fn-getter)))
+ (if macro
+ (-rtx-macro-expand (apply macro (cdr result)) fn-getter)
+ result))
+ result))
+ exp)
+)
+
+; Publically accessible version.
+
+(define rtx-macro-expand -rtx-macro-expand)
+
+; RTX canonicalization.
+; ??? wip
+
+; Subroutine of rtx-canonicalize.
+; Return canonical form of rtx expression EXPR.
+; CONTEXT is a <context> object or #f if there is none.
+; It is used for error message.
+; RTX-OBJ is the <rtx-func> object of (car expr).
+
+(define (-rtx-canonicalize-expr context rtx-obj expr)
+ #f
+)
+
+; Return canonical form of EXPR.
+; CONTEXT is a <context> object or #f if there is none.
+; It is used for error message.
+;
+; Does:
+; - operand shortcuts expanded
+; - numbers -> (const number)
+; - operand-name -> (operand operand-name)
+; - ifield-name -> (ifield ifield-name)
+; - no options -> null option list
+; - absent result mode of those that require a mode -> DFLT
+; - rtx macros are expanded
+;
+; EXPR is returned in source form. We could speed up future processing by
+; transforming it into a more compiled form, but that makes debugging more
+; difficult, so for now we don't.
+
+(define (rtx-canonicalize context expr)
+ ; FIXME: wip
+ (cond ((integer? expr)
+ (rtx-make-const 'INT expr))
+ ((symbol? expr)
+ (let ((op (current-op-lookup expr)))
+ (if op
+ (rtx-make-operand expr)
+ (context-error context "can't canonicalize" expr))))
+ ((pair? expr)
+ expr)
+ (else
+ (context-error context "can't canonicalize" expr)))
+)
+
+; RTX mode support.
+
+; Get implied mode of X, either an operand expression, sequence temp, or
+; a hardware reference expression.
+; The result is the name of the mode.
+
+(define (rtx-lvalue-mode-name estate x)
+ (assert (rtx? x))
+ (case (car x)
+; ((operand) (obj:name (op:mode (current-op-lookup (cadr x)))))
+ ((xop) (obj:name (send (rtx-xop-obj x) 'get-mode)))
+; ((opspec)
+; (if (eq? (rtx-opspec-mode x) 'VOID)
+; (rtx-lvalue-mode-name estate (rtx-opspec-hw-ref x))
+; (rtx-opspec-mode x)))
+; ((reg mem) (cadr x))
+; ((local) (obj:name (rtx-temp-mode (rtx-temp-lookup (estate-env estate)
+; (cadr x)))))
+ (else
+ (error "rtx-lvalue-mode-name: not an operand or hardware reference:" x)))
+)
+
+; Lookup the mode to use for semantic operations (unsigned modes aren't
+; allowed since we don't have ANDUSI, etc.).
+; ??? I have actually implemented both ways (full use of unsigned modes
+; and mostly hidden use of unsigned modes). Neither makes me real
+; comfortable, though I liked bringing unsigned modes out into the open
+; even if it doubled the number of semantic operations.
+
+(define (-rtx-sem-mode m) (or (mode:sem-mode m) m))
+
+; MODE is a mode name or <mode> object.
+(define (-rtx-lazy-sem-mode mode) (-rtx-sem-mode (mode:lookup mode)))
+
+; Return the mode of object OBJ.
+
+(define (-rtx-obj-mode obj) (send obj 'get-mode))
+
+; Return a boolean indicating of modes M1,M2 are compatible.
+
+(define (-rtx-mode-compatible? m1 m2)
+ (let ((mode1 (-rtx-lazy-sem-mode m1))
+ (mode2 (-rtx-lazy-sem-mode m2)))
+ ;(eq? (obj:name mode1) (obj:name mode2)))
+ ; ??? This is more permissive than is perhaps proper.
+ (mode-compatible? 'sameclass mode1 mode2))
+)
+
+; Environments (sequences with local variables).
+
+; Temporaries are created within a sequence.
+; e.g. (sequence ((WI tmp)) (set tmp reg0) ...)
+; ??? Perhaps what we want here is `let' but for now I prefer `sequence'.
+; This isn't exactly `let' either as no initial value is specified.
+; Environments are also used to specify incoming values from the top level.
+
+(define <rtx-temp> (class-make '<rtx-temp> nil '(name mode value) nil))
+
+;(define cx-temp:name (elm-make-getter <c-expr-temp> 'name))
+;(define cx-temp:mode (elm-make-getter <c-expr-temp> 'mode))
+;(define cx-temp:value (elm-make-getter <c-expr-temp> 'value))
+
+(define-getters <rtx-temp> rtx-temp (name mode value))
+
+(method-make!
+ <rtx-temp> 'make!
+ (lambda (self name mode value)
+ (elm-set! self 'name name)
+ (elm-set! self 'mode mode)
+ (elm-set! self 'value (if value value (gen-temp name)))
+ self)
+)
+
+(define (gen-temp name)
+ ; ??? calls to gen-c-symbol don't belong here
+ (string-append "tmp_" (gen-c-symbol name))
+)
+
+; Return a boolean indicating if X is an <rtx-temp>.
+
+(define (rtx-temp? x) (class-instance? <rtx-temp> x))
+
+; Respond to 'get-mode messages.
+
+(method-make! <rtx-temp> 'get-mode (lambda (self) (elm-get self 'mode)))
+
+; Respond to 'get-name messages.
+
+(method-make! <rtx-temp> 'get-name (lambda (self) (elm-get self 'name)))
+
+; An environment is a list of <rtx-temp> objects.
+; An environment stack is a list of environments.
+
+(define (rtx-env-stack-empty? env-stack) (null? env-stack))
+(define (rtx-env-stack-head env-stack) (car env-stack))
+(define (rtx-env-var-list env) env)
+(define (rtx-env-empty-stack) nil)
+(define (rtx-env-init-stack1 vars-alist)
+ (if (null? vars-alist)
+ nil
+ (cons (rtx-env-make vars-alist) nil))
+)
+(define (rtx-env-empty? env) (null? env))
+
+; Create an initial environment.
+; VAR-LIST is a list of (name <mode> value) elements.
+
+(define (rtx-env-make var-list)
+ ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
+ (map (lambda (var-spec)
+ (cons (car var-spec)
+ (make <rtx-temp>
+ (car var-spec) (cadr var-spec) (caddr var-spec))))
+ var-list)
+)
+
+; Create an initial environment with local variables.
+; VAR-LIST is a list of (mode-name name) elements (the argument to `sequence').
+
+(define (rtx-env-make-locals var-list)
+ ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
+ (map (lambda (var-spec)
+ (cons (cadr var-spec)
+ (make <rtx-temp>
+ (cadr var-spec) (mode:lookup (car var-spec)) #f)))
+ var-list)
+)
+
+; Push environment ENV onto the front of environment stack ENV-STACK,
+; returning a new object. ENV-STACK is not modified.
+
+(define (rtx-env-push env-stack env)
+ (cons env env-stack)
+)
+
+(define (rtx-temp-lookup env name)
+ ;(display "looking up:") (display name) (newline)
+ (let loop ((stack (rtx-env-var-list env)))
+ (if (null? stack)
+ #f
+ (let ((temp (assq-ref (car stack) name)))
+ (if temp
+ temp
+ (loop (cdr stack))))))
+)
+
+; Create a "closure" of EXPR using the current temp stack.
+
+(define (-rtx-closure-make estate expr)
+ (rtx-make 'closure expr (estate-env estate))
+)
+
+(define (rtx-env-dump env)
+ (let ((stack env))
+ (if (rtx-env-stack-empty? stack)
+ (display "rtx-env stack (empty):\n")
+ (let loop ((stack stack) (level 0))
+ (if (null? stack)
+ #f ; done
+ (begin
+ (display "rtx-env stack, level ")
+ (display level)
+ (display ":\n")
+ (for-each (lambda (var)
+ (display " ")
+ ;(display (obj:name (rtx-temp-mode (cdr var))))
+ ;(display " ")
+ (display (rtx-temp-name (cdr var)))
+ (newline))
+ (car stack))
+ (loop (cdr stack) (+ level 1)))))))
+)
+
+; Build, test, and analyze various kinds of rtx's.
+; ??? A lot of this could be machine generated except that I don't yet need
+; that much.
+
+(define (rtx-make kind . args)
+ (cons kind (-rtx-munge-mode&options args))
+)
+
+(define rtx-name car)
+(define (rtx-kind? kind rtx) (eq? kind (rtx-name rtx)))
+
+(define (rtx-make-const mode value) (rtx-make 'const mode value))
+(define (rtx-make-enum mode value) (rtx-make 'enum mode value))
+
+(define (rtx-constant? rtx) (memq (rtx-name rtx) '(const enum)))
+
+; Return value of constant RTX (either const or enum).
+(define (rtx-constant-value rtx)
+ (case (rtx-name rtx)
+ ((const) (rtx-const-value rtx))
+ ((enum) (enum-lookup-val (rtx-enum-value rtx)))
+ (else (error "rtx-constant-value: not const or enum" rtx)))
+)
+
+(define rtx-options cadr)
+(define rtx-mode caddr)
+(define rtx-args cdddr)
+(define rtx-arg1 cadddr)
+(define (rtx-arg2 rtx) (car (cddddr rtx)))
+
+(define rtx-const-value rtx-arg1)
+(define rtx-enum-value rtx-arg1)
+
+(define rtx-reg-name rtx-arg1)
+
+; Return register number or #f if absent.
+; (reg options mode hw-name [regno [selector]])
+(define (rtx-reg-number rtx) (list-maybe-ref rtx 4))
+
+; Return register selector or #f if absent.
+(define (rtx-reg-selector rtx) (list-maybe-ref rtx 5))
+
+; Return both register number and selector.
+(define rtx-reg-index-sel cddddr)
+
+; Return memory address.
+(define rtx-mem-addr rtx-arg1)
+
+; Return memory selector or #f if absent.
+(define (rtx-mem-sel mem) (list-maybe-ref mem 4))
+
+; Return both memory address and selector.
+(define rtx-mem-index-sel cdddr)
+
+; Return MEM with new address NEW-ADDR.
+; ??? Complicate as necessary.
+(define (rtx-change-address mem new-addr)
+ (rtx-make 'mem
+ (rtx-options mem)
+ (rtx-mode mem)
+ new-addr
+ (rtx-mem-sel mem))
+)
+
+; Return argument to `symbol' rtx.
+(define rtx-symbol-name rtx-arg1)
+
+(define (rtx-make-ifield ifield-name) (rtx-make 'ifield ifield-name))
+(define (rtx-ifield? rtx) (eq? 'ifield (rtx-name rtx)))
+(define (rtx-ifield-name rtx)
+ (let ((ifield (rtx-arg1 rtx)))
+ (if (symbol? ifield)
+ ifield
+ (obj:name ifield)))
+)
+(define (rtx-ifield-obj rtx)
+ (let ((ifield (rtx-arg1 rtx)))
+ (if (symbol? ifield)
+ (current-ifield-lookup ifield)
+ ifield))
+)
+
+(define (rtx-make-operand op-name) (rtx-make 'operand op-name))
+(define (rtx-operand? rtx) (eq? 'operand (rtx-name rtx)))
+(define (rtx-operand-name rtx)
+ (let ((operand (rtx-arg1 rtx)))
+ (if (symbol? operand)
+ operand
+ (obj:name operand)))
+)
+(define (rtx-operand-obj rtx)
+ (let ((operand (rtx-arg1 rtx)))
+ (if (symbol? operand)
+ (current-op-lookup operand)
+ operand))
+)
+
+(define (rtx-make-local local-name) (rtx-make 'local local-name))
+(define (rtx-local? rtx) (eq? 'local (rtx-name rtx)))
+(define (rtx-local-name rtx)
+ (let ((local (rtx-arg1 rtx)))
+ (if (symbol? local)
+ local
+ (obj:name local)))
+)
+(define (rtx-local-obj rtx)
+ (let ((local (rtx-arg1 rtx)))
+ (if (symbol? local)
+ (error "can't use rtx-local-obj on local name")
+ local))
+)
+
+(define rtx-xop-obj rtx-arg1)
+
+;(define (rtx-opspec? rtx) (eq? 'opspec (rtx-name rtx)))
+;(define (rtx-opspec-mode rtx) (rtx-mode rtx))
+;(define (rtx-opspec-hw-ref rtx) (list-ref rtx 5))
+;(define (rtx-opspec-set-op-num! rtx num) (set-car! (cddddr rtx) num))
+
+(define rtx-index-of-value rtx-arg1)
+
+(define (rtx-make-set dest src) (rtx-make 'set dest src))
+(define rtx-set-dest rtx-arg1)
+(define rtx-set-src rtx-arg2)
+(define (rtx-single-set? rtx) (eq? (car rtx) 'set))
+
+(define rtx-alu-op-mode rtx-mode)
+(define (rtx-alu-op-arg rtx n) (list-ref rtx (+ n 3)))
+
+(define (rtx-boolif-op-arg rtx n) (list-ref rtx (+ n 3)))
+
+(define rtx-cmp-op-mode rtx-mode)
+(define (rtx-cmp-op-arg rtx n) (list-ref rtx (+ n 3)))
+
+(define rtx-number-list-values cdddr)
+
+(define rtx-member-value rtx-arg1)
+(define (rtx-member-set rtx) (list-ref rtx 4))
+
+(define rtx-if-mode rtx-mode)
+(define (rtx-if-test rtx) (rtx-arg1 rtx))
+(define (rtx-if-then rtx) (list-ref rtx 4))
+; If `else' clause is missing the result is #f.
+(define (rtx-if-else rtx) (list-maybe-ref rtx 5))
+
+(define (rtx-eq-attr-owner rtx) (list-ref rtx 3))
+(define (rtx-eq-attr-attr rtx) (list-ref rtx 4))
+(define (rtx-eq-attr-value rtx) (list-ref rtx 5))
+
+(define (rtx-sequence-locals rtx) (cadddr rtx))
+(define (rtx-sequence-exprs rtx) (cddddr rtx))
+
+; Same as rtx-sequence-locals except return in assq'able form.
+
+(define (rtx-sequence-assq-locals rtx)
+ (let ((locals (rtx-sequence-locals rtx)))
+ (map (lambda (local)
+ (list (cadr local) (car local)))
+ locals))
+)
+
+; Return a semi-pretty symbol describing RTX.
+; This is used by hw to include the index in the element's name.
+
+(define (rtx-pretty-name rtx)
+ (if (pair? rtx)
+ (case (car rtx)
+ ((const) (number->string (rtx-const-value rtx)))
+ ((operand) (obj:name (rtx-operand-obj rtx)))
+ ((local) (rtx-local-name rtx))
+ ((xop) (obj:name (rtx-xop-obj rtx)))
+ (else
+ (if (null? (cdr rtx))
+ (car rtx)
+ (apply string-append
+ (cons (car rtx)
+ (map (lambda (elm)
+ (string-append "-" (rtx-pretty-name elm)))
+ (cdr rtx)))))))
+ (stringize rtx "-"))
+)
+
+; RTL expression traversal support.
+; Traversal (and compilation) involves validating the source form and
+; converting it to internal form.
+; ??? At present the internal form is also the source form (easier debugging).
+
+; Set to #t to debug rtx traversal.
+
+(define -rtx-traverse-debug? #f)
+
+; Container to record the current state of traversal.
+; This is initialized before traversal, and modified (in a copy) as the
+; traversal state changes.
+; This doesn't record all traversal state, just the more static elements.
+; There's no point in recording things like the parent expression and operand
+; position as they change for every sub-traversal.
+; The main raison d'etre for this class is so we can add more state without
+; having to modify all the traversal handlers.
+; ??? At present it's not a proper "class" as there's no real need.
+;
+; CONTEXT is a <context> object or #f if there is none.
+; It is used for error messages.
+;
+; EXPR-FN is a dual-purpose beast. The first purpose is to just process
+; the current expression and return the result. The second purpose is to
+; lookup the function which will then process the expression.
+; It is applied recursively to the expression and each sub-expression.
+; It must be defined as
+; (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff) ...).
+; If the result of EXPR-FN is a lambda, it is applied to
+; (cons TSTATE (cdr EXPR)). TSTATE is prepended to the arguments.
+; For syntax expressions if the result of EXPR-FN is #f, the operands are
+; processed using the builtin traverser.
+; So to repeat: EXPR-FN can process the expression, and if its result is a
+; lambda then it also processes the expression. The arguments to EXPR-FN
+; are (rtx-obj expr mode parent-expr op-pos tstate appstuff). The format
+; of the result of EXPR-FN are (cons TSTATE (cdr EXPR)).
+; The reason for the duality is that when trying to understand EXPR (e.g. when
+; computing the insn format) EXPR-FN processes the expression itself, and
+; when evaluating EXPR it's the result of EXPR-FN that computes the value.
+;
+; ENV is the current environment. This is a stack of sequence locals.
+;
+; COND? is a boolean indicating if the current expression is on a conditional
+; execution path. This is for optimization purposes only and it is always ok
+; to pass #t, except for the top-level caller which must pass #f (since the top
+; level expression obviously isn't subject to any condition).
+; It is used, for example, to speed up the simulator: there's no need to keep
+; track of whether an operand has been assigned to (or potentially read from)
+; if it's known it's always assigned to.
+;
+; SET? is a boolean indicating if the current expression is an operand being
+; set.
+;
+; OWNER is the owner of the expression or #f if there is none.
+; Typically it is an <insn> object.
+;
+; KNOWN is an alist of known values. This is used by rtx-simplify.
+; Each element is (name . value) where
+; NAME is either an ifield or operand name (in the future it might be a
+; sequence local name), and
+; VALUE is either (const mode value) or (numlist mode value1 value2 ...).
+;
+; DEPTH is the current traversal depth.
+
+(define (tstate-make context owner expr-fn env cond? set? known depth)
+ (vector context owner expr-fn env cond? set? known depth)
+)
+
+(define (tstate-context state) (vector-ref state 0))
+(define (tstate-set-context! state newval) (vector-set! state 0 newval))
+(define (tstate-owner state) (vector-ref state 1))
+(define (tstate-set-owner! state newval) (vector-set! state 1 newval))
+(define (tstate-expr-fn state) (vector-ref state 2))
+(define (tstate-set-expr-fn! state newval) (vector-set! state 2 newval))
+(define (tstate-env state) (vector-ref state 3))
+(define (tstate-set-env! state newval) (vector-set! state 3 newval))
+(define (tstate-cond? state) (vector-ref state 4))
+(define (tstate-set-cond?! state newval) (vector-set! state 4 newval))
+(define (tstate-set? state) (vector-ref state 5))
+(define (tstate-set-set?! state newval) (vector-set! state 5 newval))
+(define (tstate-known state) (vector-ref state 6))
+(define (tstate-set-known! state newval) (vector-set! state 6 newval))
+(define (tstate-depth state) (vector-ref state 7))
+(define (tstate-set-depth! state newval) (vector-set! state 7 newval))
+
+; Create a copy of STATE.
+
+(define (tstate-copy state)
+ ; A fast vector-copy would be nice, but this is simple and portable.
+ (list->vector (vector->list state))
+)
+
+; Create a copy of STATE with a new environment ENV.
+
+(define (tstate-new-env state env)
+ (let ((result (tstate-copy state)))
+ (tstate-set-env! result env)
+ result)
+)
+
+; Create a copy of STATE with environment ENV pushed onto the existing
+; environment list.
+; There's no routine to pop the environment list as there's no current
+; need for it: we make a copy of the state when we push.
+
+(define (tstate-push-env state env)
+ (let ((result (tstate-copy state)))
+ (tstate-set-env! result (cons env (tstate-env result)))
+ result)
+)
+
+; Create a copy of STATE with a new COND? value.
+
+(define (tstate-new-cond? state cond?)
+ (let ((result (tstate-copy state)))
+ (tstate-set-cond?! result cond?)
+ result)
+)
+
+; Create a copy of STATE with a new SET? value.
+
+(define (tstate-new-set? state set?)
+ (let ((result (tstate-copy state)))
+ (tstate-set-set?! result set?)
+ result)
+)
+
+; Lookup NAME in the known value table. Returns the value or #f if not found.
+
+(define (tstate-known-lookup tstate name)
+ (let ((known (tstate-known tstate)))
+ (assq-ref known name))
+)
+
+; Increment the recorded traversal depth of TSTATE.
+
+(define (tstate-incr-depth! tstate)
+ (tstate-set-depth! tstate (1+ (tstate-depth tstate)))
+)
+
+; Decrement the recorded traversal depth of TSTATE.
+
+(define (tstate-decr-depth! tstate)
+ (tstate-set-depth! tstate (1- (tstate-depth tstate)))
+)
+
+; Traversal/compilation support.
+
+; Return a boolean indicating if X is a mode.
+
+(define (-rtx-any-mode? x)
+ (->bool (mode:lookup x))
+)
+
+; Return a boolean indicating if X is a symbol or rtx.
+
+(define (-rtx-symornum? x)
+ (or (symbol? x) (number? x))
+)
+
+; Traverse a list of rtx's.
+
+(define (-rtx-traverse-rtx-list rtx-list mode expr op-num tstate appstuff)
+ (map (lambda (rtx)
+ ; ??? Shouldn't OP-NUM change for each element?
+ (-rtx-traverse rtx 'RTX mode expr op-num tstate appstuff))
+ rtx-list)
+)
+
+; Cover-fn to context-error for signalling an error during rtx traversal.
+
+(define (-rtx-traverse-error tstate errmsg expr op-num)
+; (parse-error context (string-append errmsg ", operand number "
+; (number->string op-num))
+; (rtx-dump expr))
+ (context-error (tstate-context tstate)
+ (string-append errmsg ", operand #" (number->string op-num))
+ (rtx-strdump expr))
+)
+
+; Rtx traversers.
+; These are defined as individual functions that are then built into a table
+; so that we can use Hobbit's "fastcall" support.
+;
+; The result is either a pair of the parsed VAL and new TSTATE,
+; or #f meaning there is no change (saves lots of unnecessarying cons'ing).
+
+(define (-rtx-traverse-options val mode expr op-num tstate appstuff)
+ #f
+)
+
+(define (-rtx-traverse-anymode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (not val-obj)
+ (-rtx-traverse-error tstate "expecting a mode"
+ expr op-num))
+ #f)
+)
+
+(define (-rtx-traverse-intmode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (and val-obj
+ (or (memq (mode:class val-obj) '(INT UINT))
+ (eq? val 'DFLT)))
+ #f
+ (-rtx-traverse-error tstate "expecting an integer mode"
+ expr op-num)))
+)
+
+(define (-rtx-traverse-floatmode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (and val-obj
+ (or (memq (mode:class val-obj) '(FLOAT))
+ (eq? val 'DFLT)))
+ #f
+ (-rtx-traverse-error tstate "expecting a float mode"
+ expr op-num)))
+)
+
+(define (-rtx-traverse-nummode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (and val-obj
+ (or (memq (mode:class val-obj) '(INT UINT FLOAT))
+ (eq? val 'DFLT)))
+ #f
+ (-rtx-traverse-error tstate "expecting a numeric mode"
+ expr op-num)))
+)
+
+(define (-rtx-traverse-explnummode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (not val-obj)
+ (-rtx-traverse-error tstate "expecting a mode"
+ expr op-num))
+ (if (memq val '(DFLT VOID))
+ (-rtx-traverse-error tstate "DFLT and VOID not allowed here"
+ expr op-num))
+ #f)
+)
+
+(define (-rtx-traverse-nonvoidmode val mode expr op-num tstate appstuff)
+ (if (eq? val 'VOID)
+ (-rtx-traverse-error tstate "mode can't be VOID"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-voidmode val mode expr op-num tstate appstuff)
+ (if (memq val '(DFLT VOID))
+ #f
+ (-rtx-traverse-error tstate "expecting mode VOID"
+ expr op-num))
+)
+
+(define (-rtx-traverse-dfltmode val mode expr op-num tstate appstuff)
+ (if (eq? val 'DFLT)
+ #f
+ (-rtx-traverse-error tstate "expecting mode DFLT"
+ expr op-num))
+)
+
+(define (-rtx-traverse-rtx val mode expr op-num tstate appstuff)
+; Commented out 'cus it doesn't quite work yet.
+; (if (not (rtx? val))
+; (-rtx-traverse-error tstate "expecting an rtx"
+; expr op-num))
+ (cons (-rtx-traverse val 'RTX mode expr op-num tstate appstuff)
+ tstate)
+)
+
+(define (-rtx-traverse-setrtx val mode expr op-num tstate appstuff)
+ ; FIXME: Still need to turn it off for sub-exprs.
+ ; e.g. (mem (reg ...))
+; Commented out 'cus it doesn't quite work yet.
+; (if (not (rtx? val))
+; (-rtx-traverse-error tstate "expecting an rtx"
+; expr op-num))
+ (cons (-rtx-traverse val 'SETRTX mode expr op-num
+ (tstate-new-set? tstate #t)
+ appstuff)
+ tstate)
+)
+
+; This is the test of an `if'.
+
+(define (-rtx-traverse-testrtx val mode expr op-num tstate appstuff)
+; Commented out 'cus it doesn't quite work yet.
+; (if (not (rtx? val))
+; (-rtx-traverse-error tstate "expecting an rtx"
+; expr op-num))
+ (cons (-rtx-traverse val 'RTX mode expr op-num tstate appstuff)
+ (tstate-new-cond?
+ tstate
+ (not (rtx-compile-time-constant? val))))
+)
+
+(define (-rtx-traverse-condrtx val mode expr op-num tstate appstuff)
+ (if (not (pair? val))
+ (-rtx-traverse-error tstate "expecting an expression"
+ expr op-num))
+ (if (eq? (car val) 'else)
+ (begin
+ (if (!= (+ op-num 2) (length expr))
+ (-rtx-traverse-error tstate
+ "`else' clause not last"
+ expr op-num))
+ (cons (cons 'else
+ (-rtx-traverse-rtx-list
+ (cdr val) mode expr op-num
+ (tstate-new-cond? tstate #t)
+ appstuff))
+ (tstate-new-cond? tstate #t)))
+ (cons (cons
+ ; ??? Entries after the first are conditional.
+ (-rtx-traverse (car val) 'RTX 'ANY expr op-num tstate appstuff)
+ (-rtx-traverse-rtx-list
+ (cdr val) mode expr op-num
+ (tstate-new-cond? tstate #t)
+ appstuff))
+ (tstate-new-cond? tstate #t)))
+)
+
+(define (-rtx-traverse-casertx val mode expr op-num tstate appstuff)
+ (if (or (not (list? val))
+ (< (length val) 2))
+ (-rtx-traverse-error tstate
+ "invalid `case' expression"
+ expr op-num))
+ ; car is either 'else or list of symbols/numbers
+ (if (not (or (eq? (car val) 'else)
+ (and (list? (car val))
+ (not (null? (car val)))
+ (all-true? (map -rtx-symornum?
+ (car val))))))
+ (-rtx-traverse-error tstate
+ "invalid `case' choice"
+ expr op-num))
+ (if (and (eq? (car val) 'else)
+ (!= (+ op-num 2) (length expr)))
+ (-rtx-traverse-error tstate "`else' clause not last"
+ expr op-num))
+ (cons (cons (car val)
+ (-rtx-traverse-rtx-list
+ (cdr val) mode expr op-num
+ (tstate-new-cond? tstate #t)
+ appstuff))
+ (tstate-new-cond? tstate #t))
+)
+
+(define (-rtx-traverse-locals val mode expr op-num tstate appstuff)
+ (if (not (list? val))
+ (-rtx-traverse-error tstate "bad locals list"
+ expr op-num))
+ (for-each (lambda (var)
+ (if (or (not (list? var))
+ (!= (length var) 2)
+ (not (-rtx-any-mode? (car var)))
+ (not (symbol? (cadr var))))
+ (-rtx-traverse-error tstate
+ "bad locals list"
+ expr op-num)))
+ val)
+ (let ((env (rtx-env-make-locals val)))
+ (cons val (tstate-push-env tstate env)))
+)
+
+(define (-rtx-traverse-env val mode expr op-num tstate appstuff)
+ ; VAL is an environment stack.
+ (if (not (list? val))
+ (-rtx-traverse-error tstate "environment not a list"
+ expr op-num))
+ (cons val (tstate-new-env tstate val))
+)
+
+(define (-rtx-traverse-attrs val mode expr op-num tstate appstuff)
+; (cons val ; (atlist-source-form (atlist-parse val "" "with-attr"))
+; tstate)
+ #f
+)
+
+(define (-rtx-traverse-symbol val mode expr op-num tstate appstuff)
+ (if (not (symbol? val))
+ (-rtx-traverse-error tstate "expecting a symbol"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-string val mode expr op-num tstate appstuff)
+ (if (not (string? val))
+ (-rtx-traverse-error tstate "expecting a string"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-number val mode expr op-num tstate appstuff)
+ (if (not (number? val))
+ (-rtx-traverse-error tstate "expecting a number"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-symornum val mode expr op-num tstate appstuff)
+ (if (not (or (symbol? val) (number? val)))
+ (-rtx-traverse-error tstate
+ "expecting a symbol or number"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-object val mode expr op-num tstate appstuff)
+ #f
+)
+
+; Table of rtx traversers.
+; This is a vector of size rtx-max-num.
+; Each entry is a list of (arg-type-name . traverser) elements
+; for rtx-arg-types.
+
+(define -rtx-traverser-table #f)
+
+; Return a hash table of standard operand traversers.
+; The result of each traverser is a pair of the compiled form of `val' and
+; a possibly new traversal state or #f if there is no change.
+
+(define (-rtx-make-traverser-table)
+ (let ((hash-tab (make-hash-table 31))
+ (traversers
+ (list
+ ; /fastcall-make is recognized by Hobbit and handled specially.
+ ; When not using Hobbit it is a macro that returns its argument.
+ (cons 'OPTIONS (/fastcall-make -rtx-traverse-options))
+ (cons 'ANYMODE (/fastcall-make -rtx-traverse-anymode))
+ (cons 'INTMODE (/fastcall-make -rtx-traverse-intmode))
+ (cons 'FLOATMODE (/fastcall-make -rtx-traverse-floatmode))
+ (cons 'NUMMODE (/fastcall-make -rtx-traverse-nummode))
+ (cons 'EXPLNUMMODE (/fastcall-make -rtx-traverse-explnummode))
+ (cons 'NONVOIDFLTODE (/fastcall-make -rtx-traverse-nonvoidmode))
+ (cons 'VOIDFLTODE (/fastcall-make -rtx-traverse-voidmode))
+ (cons 'DFLTMODE (/fastcall-make -rtx-traverse-dfltmode))
+ (cons 'RTX (/fastcall-make -rtx-traverse-rtx))
+ (cons 'SETRTX (/fastcall-make -rtx-traverse-setrtx))
+ (cons 'TESTRTX (/fastcall-make -rtx-traverse-testrtx))
+ (cons 'CONDRTX (/fastcall-make -rtx-traverse-condrtx))
+ (cons 'CASERTX (/fastcall-make -rtx-traverse-casertx))
+ (cons 'LOCALS (/fastcall-make -rtx-traverse-locals))
+ (cons 'ENV (/fastcall-make -rtx-traverse-env))
+ (cons 'ATTRS (/fastcall-make -rtx-traverse-attrs))
+ (cons 'SYMBOL (/fastcall-make -rtx-traverse-symbol))
+ (cons 'STRING (/fastcall-make -rtx-traverse-string))
+ (cons 'NUMBER (/fastcall-make -rtx-traverse-number))
+ (cons 'SYMORNUM (/fastcall-make -rtx-traverse-symornum))
+ (cons 'OBJECT (/fastcall-make -rtx-traverse-object))
+ )))
+
+ (for-each (lambda (traverser)
+ (hashq-set! hash-tab (car traverser) (cdr traverser)))
+ traversers)
+
+ hash-tab)
+)
+
+; Traverse the operands of EXPR, a canonicalized RTL expression.
+; Here "canonicalized" means that -rtx-munge-mode&options has been called to
+; insert an option list and mode if they were absent in the original
+; expression.
+
+(define (-rtx-traverse-operands rtx-obj expr tstate appstuff)
+ (if -rtx-traverse-debug?
+ (begin
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "Traversing operands of: ")
+ (display (rtx-dump expr))
+ (newline)
+ (rtx-env-dump (tstate-env tstate))
+ (force-output)
+ ))
+
+ (let loop ((operands (cdr expr))
+ (op-num 0)
+ (arg-types (vector-ref -rtx-traverser-table (rtx-num rtx-obj)))
+ (arg-modes (rtx-arg-modes rtx-obj))
+ (result nil)
+ )
+
+ (let ((varargs? (and (pair? arg-types) (symbol? (car arg-types)))))
+
+ (if -rtx-traverse-debug?
+ (begin
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (if (null? operands)
+ (display "end of operands")
+ (begin
+ (display "op-num ") (display op-num) (display ": ")
+ (display (rtx-dump (car operands)))
+ (display ", ")
+ (display (if varargs? (car arg-types) (caar arg-types)))
+ (display ", ")
+ (display (if varargs? arg-modes (car arg-modes)))
+ ))
+ (newline)
+ (force-output)
+ ))
+
+ (cond ((null? operands)
+ ; Out of operands, check if we have the expected number.
+ (if (or (null? arg-types)
+ varargs?)
+ (reverse! result)
+ (context-error (tstate-context tstate)
+ "missing operands" (rtx-strdump expr))))
+
+ ((null? arg-types)
+ (context-error (tstate-context tstate)
+ "too many operands" (rtx-strdump expr)))
+
+ (else
+ (let ((type (if varargs? arg-types (car arg-types)))
+ (mode (let ((mode-spec (if varargs?
+ arg-modes
+ (car arg-modes))))
+ ; This is small enough that this is fast enough,
+ ; and the number of entries should be stable.
+ ; FIXME: for now
+ (case mode-spec
+ ((ANY) 'DFLT)
+ ((NA) #f)
+ ((OP0) (rtx-mode expr))
+ ((MATCH1)
+ ; If there is an explicit mode, use it.
+ ; Otherwise we have to look at operand 1.
+ (if (eq? (rtx-mode expr) 'DFLT)
+ 'DFLT
+ (rtx-mode expr)))
+ ((MATCH2)
+ ; If there is an explicit mode, use it.
+ ; Otherwise we have to look at operand 2.
+ (if (eq? (rtx-mode expr) 'DFLT)
+ 'DFLT
+ (rtx-mode expr)))
+ (else mode-spec))))
+ (val (car operands))
+ )
+
+ ; Look up the traverser for this kind of operand and perform it.
+ (let ((traverser (cdr type)))
+ (let ((traversed-val (fastcall6 traverser val mode expr op-num tstate appstuff)))
+ (if traversed-val
+ (begin
+ (set! val (car traversed-val))
+ (set! tstate (cdr traversed-val))))))
+
+ ; Done with this operand, proceed to the next.
+ (loop (cdr operands)
+ (+ op-num 1)
+ (if varargs? arg-types (cdr arg-types))
+ (if varargs? arg-modes (cdr arg-modes))
+ (cons val result)))))))
+)
+
+; Publically accessible version of -rtx-traverse-operands as EXPR-FN may
+; need to call it.
+
+(define rtx-traverse-operands -rtx-traverse-operands)
+
+; Subroutine of -rtx-munge-mode&options.
+; Return boolean indicating if X is an rtx option.
+
+(define (-rtx-option? x)
+ (and (symbol? x)
+ (char=? (string-ref x 0) #\:))
+)
+
+; Subroutine of -rtx-munge-mode&options.
+; Return boolean indicating if X is an rtx option list.
+
+(define (-rtx-option-list? x)
+ (or (null? x)
+ (and (pair? x)
+ (-rtx-option? (car x))))
+)
+
+; Subroutine of -rtx-traverse-expr to fill in the mode if absent and to
+; collect the options into one list.
+; ARGS is the list of arguments to the rtx function
+; (e.g. (1 2) in (add 1 2)).
+; ??? "munge" is an awkward name to use here, but I like it for now because
+; it's easy to grep for.
+; ??? An empty option list requires a mode to be present so that the empty
+; list in `(sequence () foo bar)' is unambiguously recognized as the locals
+; list. Icky, sure, but less icky than the alternatives thus far.
+
+(define (-rtx-munge-mode&options args)
+ (let ((options nil)
+ (mode-name 'DFLT))
+ ; Pick off the option list if present.
+ (if (and (pair? args)
+ (-rtx-option-list? (car args))
+ ; Handle `(sequence () foo bar)'. If empty list isn't followed
+ ; by a mode, it is not an option list.
+ (or (not (null? (car args)))
+ (and (pair? (cdr args))
+ (mode-name? (cadr args)))))
+ (begin
+ (set! options (car args))
+ (set! args (cdr args))))
+ ; Pick off the mode if present.
+ (if (and (pair? args)
+ (mode-name? (car args)))
+ (begin
+ (set! mode-name (car args))
+ (set! args (cdr args))))
+ ; Now put option list and mode back.
+ (cons options (cons mode-name args)))
+)
+
+; Traverse an expression.
+; For syntax expressions arguments are not pre-evaluated before calling the
+; user's expression handler. Otherwise they are.
+; If EXPR-FN wants to just scan the operands, rather than evaluating them,
+; one thing it can do is call back to rtx-traverse-operands.
+; If EXPR-FN returns #f, traverse the operands normally and return
+; (rtx's-name traversed-operand1 ...).
+; This is for semantic-compile's sake and all traversal handlers are
+; required to do this if EXPR-FN returns #f.
+
+(define (-rtx-traverse-expr rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (let* ((expr2 (cons (car expr)
+ (-rtx-munge-mode&options (cdr expr))))
+ (fn (fastcall7 (tstate-expr-fn tstate)
+ rtx-obj expr2 mode parent-expr op-pos tstate appstuff)))
+ (if fn
+ (if (procedure? fn)
+ ; Don't traverse operands for syntax expressions.
+ (if (rtx-style-syntax? rtx-obj)
+ (apply fn (cons tstate (cdr expr2)))
+ (let ((operands (-rtx-traverse-operands rtx-obj expr2 tstate appstuff)))
+ (apply fn (cons tstate operands))))
+ fn)
+ (let ((operands (-rtx-traverse-operands rtx-obj expr2 tstate appstuff)))
+ (cons (car expr2) operands))))
+)
+
+; Main entry point for expression traversal.
+; (Actually rtx-traverse is, but it's just a cover function for this.)
+;
+; The result is the result of the lambda EXPR-FN looks up in the case of
+; expressions or an operand object (usually <operand>) in the case of operands.
+;
+; EXPR is the expression to be traversed.
+;
+; MODE is the name of the mode of EXPR.
+;
+; PARENT-EXPR is the expression EXPR is contained in. The top-level
+; caller must pass #f for it.
+;
+; OP-POS is the position EXPR appears in PARENT-EXPR. The
+; top-level caller must pass 0 for it.
+;
+; EXPECTED is one of `-rtx-valid-types' and indicates the expected rtx type
+; or #f if it doesn't matter.
+;
+; TSTATE is the current traversal state.
+;
+; APPSTUFF is for application specific use.
+;
+; All macros are expanded here. User code never sees them.
+; All operand shortcuts are also expand here. User code never sees them.
+; These are:
+; - operands, ifields, and numbers appearing where an rtx is expected are
+; converted to use `operand', `ifield', or `const'.
+
+(define (-rtx-traverse expr expected mode parent-expr op-pos tstate appstuff)
+ (if -rtx-traverse-debug?
+ (begin
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "Traversing expr: ")
+ (display expr)
+ (newline)
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "-expected: ")
+ (display expected)
+ (newline)
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "-mode: ")
+ (display mode)
+ (newline)
+ (force-output)
+ ))
+
+ (if (pair? expr) ; pair? -> cheap non-null-list?
+
+ (let ((rtx-obj (rtx-lookup (car expr))))
+ (tstate-incr-depth! tstate)
+ (let ((result
+ (if rtx-obj
+ (-rtx-traverse-expr rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (let ((rtx-obj (-rtx-macro-lookup (car expr))))
+ (if rtx-obj
+ (-rtx-traverse (-rtx-macro-expand expr rtx-evaluator)
+ expected mode parent-expr op-pos tstate appstuff)
+ (context-error (tstate-context tstate) "unknown rtx function"
+ expr))))))
+ (tstate-decr-depth! tstate)
+ result))
+
+ ; EXPR is not a list.
+ ; See if it's an operand shortcut.
+ (if (memq expected '(RTX SETRTX))
+
+ (cond ((symbol? expr)
+ (cond ((current-op-lookup expr)
+ (-rtx-traverse
+ (rtx-make-operand expr) ; (current-op-lookup expr))
+ expected mode parent-expr op-pos tstate appstuff))
+ ((rtx-temp-lookup (tstate-env tstate) expr)
+ (-rtx-traverse
+ (rtx-make-local expr) ; (rtx-temp-lookup (tstate-env tstate) expr))
+ expected mode parent-expr op-pos tstate appstuff))
+ ((current-ifld-lookup expr)
+ (-rtx-traverse
+ (rtx-make-ifield expr)
+ expected mode parent-expr op-pos tstate appstuff))
+ ((enum-lookup-val expr)
+ (-rtx-traverse
+ (rtx-make-enum 'INT expr)
+ expected mode parent-expr op-pos tstate appstuff))
+ (else
+ (context-error (tstate-context tstate)
+ "unknown operand" expr))))
+ ((integer? expr)
+ (-rtx-traverse (rtx-make-const 'INT expr)
+ expected mode parent-expr op-pos tstate appstuff))
+ (else
+ (context-error (tstate-context tstate)
+ "unexpected operand"
+ expr)))
+
+ ; Not expecting RTX or SETRTX.
+ (context-error (tstate-context tstate)
+ "unexpected operand"
+ expr)))
+)
+
+; User visible procedures to traverse an rtl expression.
+; These calls -rtx-traverse to do most of the work.
+; See tstate-make for an explanation of EXPR-FN.
+; CONTEXT is a <context> object or #f if there is none.
+; LOCALS is a list of (mode . name) elements (the locals arg to `sequence').
+; APPSTUFF is for application specific use.
+
+(define (rtx-traverse context owner expr expr-fn appstuff)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context owner expr-fn (rtx-env-empty-stack)
+ #f #f nil 0)
+ appstuff)
+)
+
+(define (rtx-traverse-with-locals context owner expr expr-fn locals appstuff)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context owner expr-fn
+ (rtx-env-push (rtx-env-empty-stack)
+ (rtx-env-make-locals locals))
+ #f #f nil 0)
+ appstuff)
+)
+
+; Traverser debugger.
+
+(define (rtx-traverse-debug expr)
+ (rtx-traverse
+ #f #f expr
+ (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (display "-expr: ")
+ (display (string-append "rtx=" (obj:name rtx-obj)))
+ (display " expr=")
+ (display expr)
+ (display " mode=")
+ (display mode)
+ (display " parent=")
+ (display parent-expr)
+ (display " op-pos=")
+ (display op-pos)
+ (display " cond?=")
+ (display (tstate-cond? tstate))
+ (newline)
+ #f)
+ #f
+ )
+)
+
+; Convert rtl expression EXPR from source form to compiled form.
+; The expression is validated and rtx macros are expanded as well.
+; CONTEXT is a <context> object or #f if there is none.
+; It is used in error messages.
+; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value)
+; elements to be used during value lookup.
+;
+; This does the same operation that rtx-traverse does, except that it provides
+; a standard value for EXPR-FN.
+;
+; ??? In the future the compiled form may be the same as the source form
+; except that all elements would be converted to their respective objects.
+
+(define (-compile-expr-fn rtx-obj expr mode parent-expr op-pos tstate appstuff)
+; (cond
+; The intent of this is to handle sequences/closures, but is it needed?
+; ((rtx-style-syntax? rtx-obj)
+; ((rtx-evaluator rtx-obj) rtx-obj expr mode
+; parent-expr op-pos tstate))
+; (else
+ (cons (car expr) ; rtx-obj
+ (-rtx-traverse-operands rtx-obj expr tstate appstuff))
+)
+
+(define (rtx-compile context expr extra-vars-alist)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context #f
+ (/fastcall-make -compile-expr-fn)
+ (rtx-env-init-stack1 extra-vars-alist)
+ #f #f nil 0)
+ #f)
+)
+
+; Various rtx utilities.
+
+; Dump an rtx expression.
+
+(define (rtx-dump rtx)
+ (cond ((list? rtx) (map rtx-dump rtx))
+ ((object? rtx) (string-append "#<object "
+ (object-class-name rtx)
+ " "
+ (obj:name rtx)
+ ">"))
+ (else rtx))
+)
+
+; Dump an expression to a string.
+
+(define (rtx-strdump rtx)
+ (with-output-to-string
+ (lambda ()
+ (display (rtx-dump rtx))))
+)
+
+; Return a boolean indicating if EXPR is known to be a compile-time constant.
+
+(define (rtx-compile-time-constant? expr)
+ (cond ((pair? expr)
+ (case (car expr)
+ ((const enum) #t)
+ (else #f)))
+ ((memq expr '(FALSE TRUE)) #t)
+ (else #f))
+)
+
+; Return boolean indicating if EXPR has side-effects.
+; FIXME: for now punt.
+
+(define (rtx-side-effects? expr)
+ #f
+)
+
+; Return a boolean indicating if EXPR is a "true" boolean value.
+;
+; ??? In RTL, #t is a synonym for (const 1). This is confusing for Schemers,
+; so maybe RTL's #t should be renamed to TRUE.
+
+(define (rtx-true? expr)
+ (cond ((pair? expr)
+ (case (car expr)
+ ((const enum) (!= (rtx-constant-value expr) 0))
+ (else #f)))
+ ((eq? expr 'TRUE) #t)
+ (else #f))
+)
+
+; Return a boolean indicating if EXPR is a "false" boolean value.
+;
+; ??? In RTL, #f is a synonym for (const 0). This is confusing for Schemers,
+; so maybe RTL's #f should be renamed to FALSE.
+
+(define (rtx-false? expr)
+ (cond ((pair? expr)
+ (case (car expr)
+ ((const enum) (= (rtx-constant-value expr) 0))
+ (else #f)))
+ ((eq? expr 'FALSE) #t)
+ (else #f))
+)
+
+; Return canonical boolean values.
+
+(define (rtx-false) (rtx-make-const 'BI 0))
+(define (rtx-true) (rtx-make-const 'BI 1))
+
+; Convert EXPR to a canonical boolean if possible.
+
+(define (rtx-canonical-bool expr)
+ (cond ((rtx-side-effects? expr) expr)
+ ((rtx-false? expr) (rtx-false))
+ ((rtx-true? expr) (rtx-true))
+ (else expr))
+)
+
+; Return rtx values for #f/#t.
+
+(define (rtx-make-bool value)
+ (if value
+ (rtx-true)
+ (rtx-false))
+)
+
+; Return #t if X is an rtl expression.
+; e.g. '(add WI dr simm8);
+
+(define (rtx? x)
+ (->bool
+ (and (pair? x) ; pair? -> cheap non-null-list?
+ (or (hashq-ref -rtx-func-table (car x))
+ (hashq-ref -rtx-macro-table (car x)))))
+)
+
+; RTL evaluation state.
+; Applications may subclass <eval-state> if they need to add things.
+;
+; This is initialized before evaluation, and modified (in a copy) as the
+; evaluation state changes.
+; This doesn't record all evaluation state, just the less dynamic elements.
+; There's no point in recording things like the parent expression and operand
+; position as they change for every sub-eval.
+; The main raison d'etre for this class is so we can add more state without
+; having to modify all the eval handlers.
+
+(define <eval-state>
+ (class-make '<eval-state> nil
+ '(
+ ; <context> object or #f if there is none
+ (context . #f)
+
+ ; Current object rtl is being evaluated for.
+ ; We need to be able to access the current instruction while
+ ; generating semantic code. However, the semantic description
+ ; doesn't specify it as an argument to anything (and we don't
+ ; want it to). So we record the value here.
+ (owner . #f)
+
+ ; EXPR-FN is a dual-purpose beast. The first purpose is to
+ ; just process the current expression and return the result.
+ ; The second purpose is to lookup the function which will then
+ ; process the expression. It is applied recursively to the
+ ; expression and each sub-expression. It must be defined as
+ ; (lambda (rtx-obj expr mode estate) ...).
+ ; If the result of EXPR-FN is a lambda, it is applied to
+ ; (cons ESTATE (cdr EXPR)). ESTATE is prepended to the
+ ; arguments.
+ ; For syntax expressions if the result of EXPR-FN is #f,
+ ; the operands are processed using the builtin evaluator.
+ ; FIXME: This special handling of syntax expressions is
+ ; not currently done.
+ ; So to repeat: EXPR-FN can process the expression, and if its
+ ; result is a lambda then it also processes the expression.
+ ; The arguments to EXPR-FN are
+ ; (rtx-obj expr mode estate).
+ ; The arguments to the result of EXPR-FN are
+ ; (cons ESTATE (cdr EXPR)).
+ ; The reason for the duality is mostly history.
+ ; In time things should be simplified.
+ (expr-fn . #f)
+
+ ; Current environment. This is a stack of sequence locals.
+ (env . ())
+
+ ; Current evaluation depth. This is used, for example, to
+ ; control indentation in generated output.
+ (depth . 0)
+
+ ; Associative list of modifiers.
+ ; This is here to support things like `delay'.
+ (modifiers . ())
+ )
+ nil)
+)
+
+; Create an <eval-state> object using a list of keyword/value elements.
+; ARGS is a list of #:keyword/value elements.
+; The result is a list of the unrecognized elements.
+; Subclasses should override this method and send-next it first, then
+; see if they recognize anything in the result, returning what isn't
+; recognized.
+
+(method-make!
+ <eval-state> 'vmake!
+ (lambda (self args)
+ (let loop ((args args) (unrecognized nil))
+ (if (null? args)
+ (reverse! unrecognized) ; ??? Could invoke method to initialize here.
+ (begin
+ (case (car args)
+ ((#:context)
+ (elm-set! self 'context (cadr args)))
+ ((#:owner)
+ (elm-set! self 'owner (cadr args)))
+ ((#:expr-fn)
+ (elm-set! self 'expr-fn (cadr args)))
+ ((#:env)
+ (elm-set! self 'env (cadr args)))
+ ((#:depth)
+ (elm-set! self 'depth (cadr args)))
+ ((#:modifiers)
+ (elm-set! self 'modifiers (cadr args)))
+ (else
+ ; Build in reverse order, as we reverse it back when we're done.
+ (set! unrecognized
+ (cons (cadr args) (cons (car args) unrecognized)))))
+ (loop (cddr args) unrecognized)))))
+)
+
+; Accessors.
+
+(define-getters <eval-state> estate
+ (context owner expr-fn env depth modifiers)
+)
+(define-setters <eval-state> estate
+ (context owner expr-fn env depth modifiers)
+)
+
+; Build an estate for use in producing a value from rtl.
+; CONTEXT is a <context> object or #f if there is none.
+; OWNER is the owner of the expression or #f if there is none.
+
+(define (estate-make-for-eval context owner)
+ (vmake <eval-state>
+ #:context context
+ #:owner owner
+ #:expr-fn (lambda (rtx-obj expr mode estate)
+ (rtx-evaluator rtx-obj)))
+)
+
+; Create a copy of ESTATE.
+
+(define (estate-copy estate)
+ (object-copy-top estate)
+)
+
+; Create a copy of STATE with a new environment ENV.
+
+(define (estate-new-env state env)
+ (let ((result (estate-copy state)))
+ (estate-set-env! result env)
+ result)
+)
+
+; Create a copy of STATE with environment ENV pushed onto the existing
+; environment list.
+; There's no routine to pop the environment list as there's no current
+; need for it: we make a copy of the state when we push.
+
+(define (estate-push-env state env)
+ (let ((result (estate-copy state)))
+ (estate-set-env! result (cons env (estate-env result)))
+ result)
+)
+
+; Create a copy of STATE with modifiers MODS.
+
+(define (estate-with-modifiers state mods)
+ (let ((result (estate-copy state)))
+ (estate-set-modifiers! result (append mods (estate-modifiers result)))
+ result)
+)
+
+; Convert a tstate to an estate.
+
+(define (tstate->estate t)
+ (vmake <eval-state>
+ #:context (tstate-context t)
+ #:env (tstate-env t))
+)
+
+; RTL expression evaluation.
+;
+; ??? These used eval2 at one point. Not sure which is faster but I suspect
+; eval2 is by far. On the otherhand this has yet to be compiled. And this way
+; is more portable, more flexible, and works with guile 1.2 (which has
+; problems with eval'ing self referential vectors, though that's one reason to
+; use smobs).
+
+; Set to #t to debug rtx evaluation.
+
+(define -rtx-eval-debug? #f)
+
+; RTX expression evaluator.
+;
+; EXPR is the expression to be eval'd. It must be in compiled form.
+; MODE is the mode of EXPR, a <mode> object or its name.
+; ESTATE is the current evaluation state.
+
+(define (rtx-eval-with-estate expr mode estate)
+ (if -rtx-eval-debug?
+ (begin
+ (display "Traversing ")
+ (display expr)
+ (newline)
+ (rtx-env-dump (estate-env estate))
+ ))
+
+ (if (pair? expr) ; pair? -> cheap non-null-list?
+
+ (let* ((rtx-obj (rtx-lookup (car expr)))
+ (fn ((estate-expr-fn estate) rtx-obj expr mode estate)))
+ (if fn
+ (if (procedure? fn)
+ (apply fn (cons estate (cdr expr)))
+; ; Don't eval operands for syntax expressions.
+; (if (rtx-style-syntax? rtx-obj)
+; (apply fn (cons estate (cdr expr)))
+; (let ((operands
+; (-rtx-eval-operands rtx-obj expr estate)))
+; (apply fn (cons estate operands))))
+ fn)
+ ; Leave expr unchanged.
+ expr))
+; (let ((operands
+; (-rtx-traverse-operands rtx-obj expr estate)))
+; (cons rtx-obj operands))))
+
+ ; EXPR is not a list
+ (error "argument to rtx-eval-with-estate is not a list" expr))
+)
+
+; Evaluate rtx expression EXPR and return the computed value.
+; EXPR must already be in compiled form (the result of rtx-compile).
+; OWNER is the owner of the value, used for attribute computation,
+; or #f if there isn't one.
+; FIXME: context?
+
+(define (rtx-value expr owner)
+ (rtx-eval-with-estate expr 'DFLT (estate-make-for-eval #f owner))
+)
+
+; Instruction field support.
+
+; Return list of ifield names refered to in EXPR.
+; Assumes EXPR is more than just (ifield x).
+
+(define (rtl-find-ifields expr)
+ (let ((ifields nil))
+ (letrec ((scan! (lambda (arg-list)
+ (for-each (lambda (arg)
+ (if (pair? arg)
+ (if (eq? (car arg) 'ifield)
+ (set! ifields
+ (cons (rtx-ifield-name arg)
+ ifields))
+ (scan! (cdr arg)))))
+ arg-list))))
+ (scan! (cdr expr))
+ (nub ifields identity)))
+)
+
+; Hardware rtx handlers.
+
+; Subroutine of hw to compute the object's name.
+; The name of the operand must include the index so that multiple copies
+; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
+; We make some attempt to make the name pretty as it appears in generated
+; files.
+
+(define (-rtx-hw-name hw hw-name index-arg)
+ (cond ((hw-scalar? hw)
+ hw-name)
+ ((rtx? index-arg)
+ (symbol-append hw-name '- (rtx-pretty-name index-arg)))
+ (else
+ (symbol-append hw-name ; (obj:name (op:type self))
+ '-
+ ; (obj:name (op:index self)))))
+ (stringize index-arg "-"))))
+)
+
+; Return the <operand> object described by
+; HW-NAME/MODE-NAME/SELECTOR/INDEX-ARG.
+;
+; HW-NAME is the name of the hardware element.
+; INDEX-ARG is an rtx or number of the index.
+; In the case of scalar hardware elements, pass 0 for INDEX-ARG.
+; MODE-NAME is the name of the mode.
+; In the case of a vector of registers, INDEX-ARG is the vector index.
+; In the case of a scalar register, the value is ignored, but pass 0 (??? #f?).
+; SELECTOR is an rtx or number and is passed to HW-NAME to allow selection of a
+; particular variant of the hardware. It's kind of like an INDEX, but along
+; an atypical axis. An example is memory ASI's on Sparc. Pass
+; hw-selector-default if there is no selector.
+; ESTATE is the current rtx evaluation state.
+;
+; e.g. (hw estate WI h-gr #f (const INT 14))
+; selects register 14 of the h-gr set of registers.
+;
+; *** The index is passed unevaluated because for parallel execution support
+; *** a variable is created with a name based on the hardware element and
+; *** index, and we want a reasonably simple and stable name. We get this by
+; *** stringize-ing it.
+; *** ??? Though this needs to be redone anyway.
+;
+; ??? The specified hardware element must be either a scalar or a vector.
+; Maybe in the future allow arrays although there's significant utility in
+; allowing only at most a scalar index.
+
+(define (hw estate mode-name hw-name index-arg selector)
+ ; Enforce some rules to keep things in line with the current design.
+ (if (not (symbol? mode-name))
+ (parse-error "hw" "invalid mode name" mode-name))
+ (if (not (symbol? hw-name))
+ (parse-error "hw" "invalid hw name" hw-name))
+ (if (not (or (number? index-arg)
+ (rtx? index-arg)))
+ (parse-error "hw" "invalid index" index-arg))
+ (if (not (or (number? selector)
+ (rtx? selector)))
+ (parse-error "hw" "invalid selector" selector))
+
+ (let ((hw (current-hw-sem-lookup-1 hw-name)))
+ (if (not hw)
+ (parse-error "hw" "invalid hardware element" hw-name))
+
+ (let ((mode (if (eq? mode-name 'DFLT) (hw-mode hw) (mode:lookup mode-name)))
+ (result (new <operand>))) ; ??? lookup-for-new?
+
+ (if (not mode)
+ (parse-error "hw" "invalid mode" mode-name))
+
+ ; Record the selector.
+ (elm-xset! result 'selector selector)
+
+ ; Create the index object.
+ (elm-xset! result 'index
+ (cond ((number? index-arg)
+ (make <hw-index> 'anonymous 'constant UINT index-arg))
+ ((rtx? index-arg)
+ ; For the simulator the following could be done which
+ ; would save having to create a closure.
+ ; ??? Old code, left in for now.
+ ; (rtx-get estate DFLT
+ ; (rtx-eval (estate-context estate)
+ ; (estate-econfig estate)
+ ; index-arg rtx-evaluator))
+ ; Make sure constant indices are recorded as such.
+ (if (rtx-constant? index-arg)
+ (make <hw-index> 'anonymous 'constant UINT
+ (rtx-constant-value index-arg))
+ (make <hw-index> 'anonymous 'rtx DFLT
+ (-rtx-closure-make estate index-arg))))
+ (else (parse-error "hw" "invalid index" index-arg))))
+
+ (if (not (hw-mode-ok? hw (obj:name mode) (elm-xget result 'index)))
+ (parse-error "hw" "invalid mode for hardware" mode-name))
+
+ (elm-xset! result 'type hw)
+ (elm-xset! result 'mode mode)
+
+ ; The name of the operand must include the index so that multiple copies
+ ; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
+ (let ((name (-rtx-hw-name hw hw-name index-arg)))
+ (send result 'set-name! name)
+ (op:set-sem-name! result name))
+
+ ; Empty comment and attribute.
+ ; ??? Stick the arguments in the comment for debugging purposes?
+ (send result 'set-comment! "")
+ (send result 'set-atlist! atlist-empty)
+
+ result))
+)
+
+; This is shorthand for (hw estate mode hw-name regno selector).
+; ESTATE is the current rtx evaluation state.
+; INDX-SEL is an optional register number and possible selector.
+; The register number, if present, is (car indx-sel) and must be a number or
+; unevaluated RTX expression.
+; The selector, if present, is (cadr indx-sel) and must be a number or
+; unevaluated RTX expression.
+; ??? A register selector isn't supported yet. It's just an idea that's
+; been put down on paper for future reference.
+
+(define (reg estate mode hw-name . indx-sel)
+ (s-hw estate mode hw-name
+ (if (pair? indx-sel) (car indx-sel) 0)
+ (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
+ (cadr indx-sel)
+ hw-selector-default))
+)
+
+; This is shorthand for (hw estate mode h-memory addr selector).
+; ADDR must be an unevaluated RTX expression.
+; If present (car sel) must be a number or unevaluated RTX expression.
+
+(define (mem estate mode addr . sel)
+ (s-hw estate mode 'h-memory addr
+ (if (pair? sel) (car sel) hw-selector-default))
+)
+
+; For the rtx nodes to use.
+
+(define s-hw hw)
+
+; The program counter.
+; When this code is loaded, global `pc' is nil, it hasn't been set to the
+; pc operand yet (see operand-init!). We can't use `pc' inside the drn as the
+; value is itself. So we use s-pc. rtl-finish! must be called after
+; operand-init!.
+
+(define s-pc pc)
+
+; Conditional execution.
+
+; `if' in RTL has a result, like ?: in C.
+; We support both: one with a result (non VOID mode), and one without (VOID mode).
+; The non-VOID case must have an else part.
+; MODE is the mode of the result, not the comparison.
+; The comparison is expected to return a zero/non-zero value.
+; ??? Perhaps this should be a syntax-expr. Later.
+
+(define (e-if estate mode cond then . else)
+ (if (> (length else) 1)
+ (error "if: too many elements in `else' part" else))
+ (if (null? else)
+ (if cond then)
+ (if cond then (car else)))
+)
+
+; Subroutines.
+; ??? Not sure this should live here.
+
+(define (-subr-read errtxt . arg-list)
+ #f
+)
+
+(define define-subr
+ (lambda arg-list
+ (let ((s (apply -subr-read (cons "define-subr" arg-list))))
+ (if s
+ (current-subr-add! s))
+ s))
+)
+
+; Misc. utilities.
+
+; The argument to drn,drmn,drsn must be Scheme code (or a fixed subset
+; thereof). .str/.sym are used in pmacros so it makes sense to include them
+; in the subset.
+(define .str string-append)
+(define .sym symbol-append)
+
+; Given (expr1 expr2 expr3 expr4), for example,
+; return (fn (fn (fn expr1 expr2) expr3) expr4).
+
+(define (rtx-combine fn exprs)
+ (assert (not (null? exprs)))
+ (letrec ((-rtx-combine (lambda (fn exprs result)
+ (if (null? exprs)
+ result
+ (-rtx-combine fn
+ (cdr exprs)
+ (rtx-make fn
+ result
+ (car exprs)))))))
+ (-rtx-combine fn (cdr exprs) (car exprs)))
+)
+
+; Called before a .cpu file is read in.
+
+(define (rtl-init!)
+ (set! -rtx-func-table (make-hash-table 127))
+ (set! -rtx-macro-table (make-hash-table 127))
+ (set! -rtx-num-next 0)
+ (def-rtx-funcs)
+ (reader-add-command! 'define-subr
+ "\
+Define an rtx subroutine, name/value pair list version.
+"
+ nil 'arg-list define-subr)
+ *UNSPECIFIED*
+)
+
+; Install builtins
+
+(define (rtl-builtin!)
+ *UNSPECIFIED*
+)
+
+; Called after cpu files are loaded to add misc. remaining entries to the
+; rtx handler table for use during evaluation.
+; rtl-finish! must be done before ifmt-compute!, the latter will
+; construct hardware objects which is done by rtx evaluation.
+
+(define (rtl-finish!)
+ (logit 2 "Building rtx operand table ...\n")
+
+ ; Update s-pc, must be called after operand-init!.
+ (set! s-pc pc)
+
+ ; Table of traversers for the various rtx elements.
+ (let ((hash-table (-rtx-make-traverser-table)))
+ (set! -rtx-traverser-table (make-vector (rtx-max-num) #f))
+ (for-each (lambda (rtx-name)
+ (let ((rtx (rtx-lookup rtx-name)))
+ (if rtx
+ (vector-set! -rtx-traverser-table (rtx-num rtx)
+ (map1-improper
+ (lambda (arg-type)
+ (cons arg-type
+ (hashq-ref hash-table arg-type)))
+ (rtx-arg-types rtx))))))
+ (rtx-name-list)))
+
+ ; Initialize the operand hash table.
+ (set! -rtx-operand-table (make-hash-table 127))
+
+ ; Add the operands to the eval symbol table.
+ (for-each (lambda (op)
+ (hashq-set! -rtx-operand-table (obj:name op) op)
+ )
+ (current-op-list))
+
+ ; Add ifields to the eval symbol table.
+ (for-each (lambda (f)
+ (hashq-set! -rtx-operand-table (obj:name f) f)
+ )
+ (non-derived-ifields (current-ifld-list)))
+
+ *UNSPECIFIED*
+)
diff --git a/cgen/rtx-funcs.scm b/cgen/rtx-funcs.scm
new file mode 100644
index 00000000000..47bd0582264
--- /dev/null
+++ b/cgen/rtx-funcs.scm
@@ -0,0 +1,1002 @@
+; Standard RTL functions.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; THIS FILE CONTAINS ONE BIG FUNCTION: def-rtx-funcs.
+;
+; It is ok for this file to use procs "internal" to rtl.scm.
+;
+; Each rtx functions has two leading operands: &options, &mode;
+; though `&mode' may be spelled differently.
+; The "&" prefix is to indicate that the parsing of these operands is handled
+; differently. They are optional and are written with leading colons
+; (e.g. :SI). The leading ":" is to help the parser - all leading optional
+; operands begin with ":". The order of the arguments is &options then &mode
+; though there is no imposed order in written RTL.
+
+(define (def-rtx-funcs)
+
+; Do not change the indentation here.
+(let
+(
+ ; These are defined in rtl.scm.
+ (drn define-rtx-node)
+ (drsn define-rtx-syntax-node)
+ (dron define-rtx-operand-node)
+ (drmn define-rtx-macro-node)
+)
+
+; The reason for the odd indenting above is so that emacs begins indenting the
+; following code at column 1.
+
+; Error reporting.
+; MODE is present for use in situations like non-VOID mode cond's.
+
+(drn (error &options &mode message)
+ (OPTIONS ANYMODE STRING) (NA NA NA)
+ MISC
+ (context-error (estate-context *estate*) message)
+)
+
+; Enums
+; Default mode is INT.
+
+(drn (enum &options &mode enum-name)
+ (OPTIONS NUMMODE SYMBOL) (NA NA NA)
+ ARG
+ ; When computing a value, return the enum's value.
+ (enum-lookup-val enum-name)
+)
+
+; Instruction fields
+; These are used in the encode/decode specs of other ifields as well as in
+; instruction semantics.
+; Ifields are normally specified by name, but they are subsequently wrapped
+; in this.
+
+(dron (ifield &options &mode ifld-name)
+ (OPTIONS DFLTMODE SYMBOL) (NA NA NA)
+ ARG
+ (let ((f (current-ifld-lookup ifld-name)))
+ (make <operand> ifld-name (string-append ifld-name " used as operand")
+ (atlist-cons (bool-attr-make 'SEM-ONLY #t)
+ (obj-atlist f))
+ (obj:name (ifld-hw-type f))
+ (obj:name (ifld-mode f))
+ (make <hw-index> 'anonymous 'ifield (ifld-mode f) f)
+ nil #f #f))
+)
+
+; Specify an operand.
+; Operands are normally specified by name, but they are subsequently wrapped
+; in this.
+
+(dron (operand &options &mode op-name)
+ (OPTIONS DFLTMODE SYMBOL) (NA NA NA)
+ ARG
+ (current-op-lookup op-name)
+)
+
+; Operand naming/numbering.
+; Operands are given names so that the operands as used in the semantics can
+; be matched with arguments of function units. With good name choices of
+; operands and function unit arguments, this is rarely necessary, but
+; sometimes it is.
+;
+; ??? This obfuscates the semantic code a fair bit. Another way to do this
+; would be to add new elements to <insn> to specify operands outside of
+; the semantic code. E.g.
+; (define-insn ...
+; (inputs (in-gr1 src1) (in-gr2 src2))
+; (outputs (out-pc pc) (out-gr dr) (reg-14 (reg WI h-gr 14)))
+; ...)
+; The intent here is to continue to allow the semantic code to use names
+; of operands, and not overly complicate the input/output description.
+;
+; In instructions, operand numbers are recorded as well, to implement
+; profiling and result writeback of parallel insns.
+
+; Rename operand VALUE to NEW-NAME.
+; VALUE is an expression whose result is an object of type <operand>.
+; It can be the name of an existing operand.
+; ??? Might also support numbering by allowing NEW-NAME to be a number.
+
+(drsn (name &options &mode new-name value)
+ (OPTIONS DFLTMODE SYMBOL RTX) (NA NA NA ANY)
+ ARG
+ (let ((result (object-copy (rtx-get 'DFLT value))))
+ (op:set-sem-name! result new-name)
+ result)
+)
+
+; Operands are generally compiled to an internal form first.
+; There is a fair bit of state associated with them, and it's easier to
+; work with an object than source [which might get fairly complicated if
+; it expresses all the state].
+; Compiled operands are wrapped in this so that they still look like rtx.
+
+(dron (xop &options &mode object)
+ (OPTIONS DFLTMODE OBJECT) (NA NA NA)
+ ARG
+ object
+)
+
+;(dron (opspec: &options &mode op-name op-num hw-ref attrs)
+; (OPTIONS ANYMODE SYMBOL NUMBER RTX ATTRS) (NA NA NA NA ANY NA)
+; ARG
+; (let ((opval (rtx-eval-with-estate hw-ref mode *estate*)))
+; (assert (operand? opval))
+; ; Set the specified mode, ensuring it's ok.
+; ; This also makes a copy as we don't want to modify predefined
+; ; operands.
+; (let ((operand (op:new-mode opval mode)))
+; (op:set-sem-name! operand op-name)
+; (op:set-num! operand op-num)
+; (op:set-cond?! operand (attr-value attrs 'COND-REF #f))
+; operand))
+;)
+
+; Specify a reference to a local variable.
+; Local variables are normally specified by name, but they are subsequently
+; wrapped in this.
+
+(dron (local &options &mode local-name)
+ (OPTIONS DFLTMODE SYMBOL) (NA NA NA)
+ ARG
+ (rtx-temp-lookup (tstate-env *tstate*) local-name)
+)
+
+; FIXME: This doesn't work. See s-operand.
+;(define (s-dup estate op-name)
+; (if (not (insn? (estate-owner estate)))
+; (error "dup: not processing an insn"))
+; (vector-ref (insn:operands (current-current-context))
+; (op:lookup-num (insn:operands (estate-owner estate)) op-name))
+;)
+;
+; ??? Since operands are given names and not numbers this isn't currently used.
+;
+;(drsn (dup &options &mode op-name)
+; (OPTIONS DFLTMODE SYMBOL) (NA NA NA)
+; ;(s-dup *estate* op-name)
+; (begin
+; (if (not (insn? (estate-owner *estate*)))
+; (error "dup: not processing an insn"))
+; (vector-ref (insn:operands (estate-owner *estate*))
+; (op:lookup-num (insn:operands (estate-owner *estate*)) op-name)))
+; #f
+;)
+
+; Returns non-zero if operand NAME was referenced (read if input operand
+; and written if output operand).
+; ??? What about input/output operands.
+
+(drsn (ref &options &mode name)
+ (OPTIONS DFLTMODE SYMBOL) (NA NA NA)
+ ARG
+ #f
+)
+
+; Return the index of an operand.
+; For registers this is the register number.
+; ??? Mode handling incomplete.
+
+(dron (index-of &options &mode op-rtx)
+ (OPTIONS DFLTMODE RTX) (NA NA ANY)
+ ARG
+ (let* ((operand (rtx-eval-with-estate op-rtx 'DFLT *estate*))
+ (f (hw-index:value (op:index operand)))
+ (f-name (obj:name f)))
+ (make <operand> f-name f-name
+ (atlist-cons (bool-attr-make 'SEM-ONLY #t)
+ (obj-atlist f))
+ (obj:name (ifld-hw-type f))
+ (obj:name (ifld-mode f))
+ (make <hw-index> 'anonymous
+ 'ifield
+ (ifld-mode f)
+ ; (send (op:type op) 'get-index-mode)
+ f)
+ nil #f #f))
+)
+
+; Same as index-of, but improves readability for registers.
+
+(drmn (regno reg)
+ (list 'index-of reg)
+)
+
+; Hardware elements.
+
+; Describe a random hardware object.
+; If INDX is missing, assume the element is a scalar. We pass 0 so s-hw
+; doesn't have to unpack the list that would be passed if it were defined as
+; (hw mode hw-name . indx). This is an internal implementation detail
+; and thus harmless to the description language.
+; These are implemented as syntax nodes as we must pass INDX to `s-hw'
+; unevaluated.
+; ??? Not currently supported. Not sure whether it should be.
+;(drsn (hw &options &mode hw-elm . indx-sel)
+; (OPTIONS ANYMODE SYMBOL . RTX) (NA NA NA . INT)
+; ARG
+; (let ((indx (if (pair? indx-sel) (car indx-sel) 0))
+; (selector (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
+; (cadr indx-sel)
+; hw-selector-default))))
+; (s-hw *estate* mode hw-elm indx selector)
+;)
+
+; Register accesses.
+; INDX-SEL is an optional index and possible selector.
+(dron (reg &options &mode hw-elm . indx-sel)
+ (OPTIONS ANYMODE SYMBOL . RTX) (NA NA NA . INT)
+ ARG
+ (let ((indx (if (pair? indx-sel) (car indx-sel) 0))
+ (selector (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
+ (cadr indx-sel)
+ hw-selector-default)))
+ (s-hw *estate* mode hw-elm indx selector))
+)
+
+; A raw-reg bypasses the getter/setter stuff. It's usually used in
+; getter/setter definitions.
+
+(dron (raw-reg &options &mode hw-elm . indx-sel)
+ (OPTIONS ANYMODE SYMBOL . RTX) (NA NA NA . INT)
+ ARG
+ (let ((indx (if (pair? indx-sel) (car indx-sel) 0))
+ (selector (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
+ (cadr indx-sel)
+ hw-selector-default)))
+ (let ((result (s-hw *estate* mode hw-elm indx selector)))
+ (obj-cons-attr! result (bool-attr-make 'RAW #t))
+ result))
+)
+
+; Memory accesses.
+(dron (mem &options &mode addr . sel)
+ (OPTIONS EXPLNUMMODE RTX . RTX) (NA NA AI . INT)
+ ARG
+ (s-hw *estate* mode 'h-memory addr
+ (if (pair? sel) (car sel) hw-selector-default))
+)
+
+; Instruction execution support.
+; There are no jumps, per se. A jump is a set of `pc'.
+
+; The program counter.
+; ??? Hmmm... needed? The pc is usually specified as `pc' which is shorthand
+; for (operand pc).
+(dron (pc) () () ARG s-pc)
+
+; Fetch bytes from the instruction stream of size MODE.
+; FIXME: Later need to augment this by passing an indicator to the mem-fetch
+; routines that we're doing an ifetch.
+; ??? wip!
+
+(drmn (ifetch mode pc)
+ (list 'mem mode pc) ; hw-selector-ispace
+)
+
+; NUM is the instruction number. Generally it is zero but if more than one
+; insn is decoded at a time, it is non-zero. This is used, for example, to
+; index into the scache [as an offset from the first insn].
+; ??? wip!
+
+(drmn (decode mode pc insn num)
+ (list 'c-call mode 'EXTRACT pc insn num)
+)
+
+; NUM is the same number passed to `decode'.
+; ??? wip!
+
+(drmn (execute mode num)
+ (list 'c-call mode 'EXECUTE num)
+)
+
+; Control Transfer Instructions
+
+; Sets of pc are handled like other sets so there are no branch rtx's.
+
+; Indicate there are N delay slots in the processing of RTX.
+; N is a `const' node.
+; ??? wip!
+
+(drn (delay &options &mode n rtx)
+ (OPTIONS DFLTMODE RTX RTX) (NA NA INT ANY)
+ MISC
+ #f ; (s-sequence *estate* VOID '() rtx) ; wip!
+)
+
+; Annul the following insn if YES? is non-zero.
+; PC is the address of the annuling insn.
+; The target is required to define SEM_ANNUL_INSN.
+; ??? wip!
+
+(drmn (annul yes?)
+ ; The pc reference here is hidden in c-code to not generate a spurious
+ ; pc input operand.
+ (list 'c-call 'VOID "SEM_ANNUL_INSN" (list 'c-code 'AI "pc") yes?)
+)
+
+; Skip the following insn if YES? is non-zero.
+; The target is required to define SEM_SKIP_INSN.
+; ??? This is similar to annul. Deletion of one of them defered.
+; ??? wip!
+
+(drn (skip &options &mode yes?)
+ (OPTIONS DFLTMODE RTX) (NA NA INT)
+ MISC
+ #f
+)
+
+; Attribute support.
+
+; Return a boolean indicating if attribute named ATTR is VALUE in OWNER.
+; If VALUE is a list, return "true" if ATTR is any of the listed values.
+; ??? Don't yet support !VALUE.
+; OWNER is the result of either (current-insn) or (current-mach)
+; [note that canonicalization will turn them into
+; (current-{insn,mach} () DFLT)].
+; The result is always of mode INT.
+; FIXME: wip
+;
+; This is a syntax node so the args are not pre-evaluated.
+; We just want the symbols.
+; FIXME: Hmmm... it currently isn't a syntax node.
+
+(drn (eq-attr &options &mode owner attr value)
+ (OPTIONS DFLTMODE RTX SYMBOL SYMORNUM) (NA NA ANY NA NA)
+ MISC
+ (let ((atval (if owner
+ (obj-attr-value owner attr)
+ (attr-lookup-default attr #f))))
+ (if (list? value)
+ (->bool (memq atval value))
+ (eq? atval value)))
+)
+
+; Get the value of attribute ATTR-NAME.
+; OBJ is the result of either (current-insn) or (current-mach)
+; [note that canonicalization will turn them into
+; (current-{insn,mach} () DFLT)].
+; FIXME:wip
+
+(drn (attr &options &mode obj attr-name)
+ (OPTIONS DFLTMODE RTX SYMBOL) (NA NA NA NA)
+ MISC
+ #f
+)
+
+; Same as `quote', for use in attributes cus "quote" sounds too jargonish.
+; [Ok, not a strong argument for using "symbol", but so what?]
+
+(drsn (symbol &options &mode name)
+ (OPTIONS DFLTMODE SYMBOL) (NA NA NA)
+ ARG
+ name
+)
+
+; Return the current instruction.
+
+(drn (current-insn &options &mode)
+ (OPTIONS DFLTMODE) (NA NA)
+ MISC
+ (let ((obj (estate-owner *estate*)))
+ (if (not (insn? obj))
+ (error "current context not an insn"))
+ obj)
+)
+
+; Return the currently selected machine.
+; This can either be a compile-time or run-time value.
+
+(drn (current-mach &options &mode)
+ (OPTIONS DFLTMODE) (NA NA)
+ MISC
+ -rtx-current-mach
+)
+
+; Constants.
+
+; FIXME: Need to consider 64 bit hosts.
+(drn (const &options &mode c)
+ (OPTIONS NUMMODE NUMBER) (NA NA NA)
+ ARG
+ ; When computing a value, just return the constant unchanged.
+ c
+)
+
+; Large mode support.
+
+; Combine smaller modes into a larger one.
+; Arguments are specified most significant to least significant.
+; ??? May also want an endian dependent argument order. That can be
+; implemented on top of or beside this.
+; ??? Not all of the combinations are supported in the simulator.
+; They'll get added as necessary.
+(drn (join &options &out-mode in-mode arg1 . arg-rest)
+ (OPTIONS NUMMODE NUMMODE RTX . RTX) (NA NA NA ANY . ANY)
+ MISC
+ ; FIXME: Ensure correct number of args for in/out modes.
+ ; FIXME: Ensure compatible modes.
+ #f
+)
+
+; GCC's subreg.
+; Called subword 'cus it's not exactly subreg.
+; Word numbering is from most signficant (word 0) to least (word N-1).
+; ??? May also want an endian dependent word ordering. That can be
+; implemented on top of or beside this.
+; ??? GCC plans to switch to SUBREG_BYTE. Keep an eye out for the switch
+; (which is extensive so probably won't happen anytime soon).
+
+(drn (subword &options &mode value word-num)
+ (OPTIONS NUMMODE RTX RTX) (NA NA OP0 INT)
+ ARG
+ #f
+)
+
+; ??? The split and concat stuff is just an experiment and should not be used.
+; What's there now is just "thoughts put down on paper."
+
+(drmn (split split-mode in-mode di)
+ ; FIXME: Ensure compatible modes
+ ;(list 'c-raw-call 'BLK (string-append "SPLIT" in-mode split-mode) di)
+ '(const 0)
+)
+
+(drmn (concat modes arg1 . arg-rest)
+ ; FIXME: Here might be the place to ensure
+ ; (= (length modes) (length (cons arg1 arg-rest))).
+ ;(cons 'c-raw-call (cons modes (cons "CONCAT" (cons arg1 arg-rest))))
+ '(const 0)
+)
+
+; Support for explicit C code.
+; ??? GCC RTL calls this "unspec" which is arguably a more application
+; independent name.
+
+(drn (c-code &options &mode text)
+ (OPTIONS ANYMODE STRING) (NA NA NA)
+ UNSPEC
+ #f
+)
+
+; Invoke C functions passing them arguments from the semantic code.
+; The arguments are passed as is, no conversion is done here.
+; Usage is:
+; (c-call mode name arg1 arg2 ...)
+; which is converted into a C function call:
+; name (current_cpu, arg1, arg2, ...)
+; Mode is the mode of the result.
+; If it is VOID this call is a statement and ';' is appended.
+; Otherwise it is part of an expression.
+
+(drn (c-call &options &mode name . args)
+ (OPTIONS ANYMODE STRING . RTX) (NA NA NA . ANY)
+ UNSPEC
+ #f
+)
+
+; Same as c-call but without implicit first arg of `current_cpu'.
+
+(drn (c-raw-call &options &mode name . args)
+ (OPTIONS ANYMODE STRING . RTX) (NA NA NA . ANY)
+ UNSPEC
+ #f
+)
+
+; Set/get/miscellaneous
+
+(drn (nop &options &mode)
+ (OPTIONS VOIDFLTODE) (NA NA)
+ MISC
+ #f
+)
+
+; Clobber - mark an object as modified without explaining why or how.
+
+(drn (clobber &options &mode object)
+ (OPTIONS ANYMODE RTX) (NA NA OP0)
+ MISC
+ #f
+)
+
+; The `set' rtx.
+; MODE is the mode of DST. If DFLT, use DST's default mode.
+; The mode of the result is always VOID.
+;
+; ??? It might be more consistent to rename set -> set-trace, but that's
+; too wordy. The `set' rtx is the normal one and we want the normal one to
+; be the verbose one (prints result tracing messages). `set-quiet' is the
+; atypical one, it doesn't print tracing messages. It may also turn out that
+; a different mechanism (rather than the name "set-quiet") is used some day.
+; One way would be to record the "quietness" state with the traversal state and
+; use something like (with-quiet (set foo bar)) akin to with-output-to-string
+; in Guile.
+;
+; i.e. set -> gen-set-trace
+; set-quiet -> gen-set-quiet
+;
+; ??? One might want a `!' suffix as in `set!', but methinks that's following
+; Scheme too closely.
+
+(drn (set &options &mode dst src)
+ (OPTIONS ANYMODE SETRTX RTX) (NA NA OP0 MATCH1)
+ SET
+ #f
+)
+
+(drn (set-quiet &options &mode dst src)
+ (OPTIONS ANYMODE SETRTX RTX) (NA NA OP0 MATCH1)
+ SET
+ #f
+)
+
+; Standard arithmetic operations.
+
+; It's nice emitting macro calls to the actual C operation in that the RTX
+; expression is preserved, albeit in C. On the one hand it's one extra thing
+; the programmer has to know when looking at the code. But on the other it's
+; trivial stuff, and having a layer between RTX and C allows the
+; macros/functions to be modified to handle unexpected situations.
+;
+; We do emit C directly for cases other than cpu semantics
+; (e.g. the assembler).
+;
+; The language is defined such that we assume ANSI C semantics while avoiding
+; implementation defined areas, with as few exceptions as possible.
+;
+; Current exceptions:
+; - signed shift right assumes the sign bit is replicated.
+;
+; Additional notes [perhaps repeating what's in ANSI C for emphasis]:
+; - callers of division and modulus fns must test for 0 beforehand
+; if necessary
+; - division and modulus fns have unspecified behavior for negative args
+; [yes I know the C standard says implementation defined, here its
+; unspecified]
+; - later add versions of div/mod that have an explicit behaviour for -ve args
+; - signedness is part of the rtx operation name, and is not determined
+; from the arguments [elsewhere is a description of the tradeoffs]
+; - ???
+
+(drn (neg &options &mode s1)
+ (OPTIONS ANYMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+(drn (abs &options &mode s1)
+ (OPTIONS ANYMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+; For integer values this is a bitwise operation (each bit inverted).
+; For floating point values this produces 1/x.
+; ??? Might want different names.
+(drn (inv &options &mode s1)
+ (OPTIONS ANYMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+; This is a boolean operation.
+; MODE is the mode of S1. The result always has mode BI.
+; ??? Perhaps `mode' shouldn't be here.
+(drn (not &options &mode s1)
+ (OPTIONS ANYMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+(drn (add &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (sub &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+; "OF" for "overflow flag", "CF" for "carry flag",
+; "s3" here must have type BI.
+; For the *flag rtx's, MODE is the mode of S1,S2; the result always has
+; mode BI.
+(drn (addc &options &mode s1 s2 s3)
+ (OPTIONS ANYMODE RTX RTX RTX) (NA NA OP0 MATCH1 BI)
+ TRINARY
+ #f
+)
+(drn (add-cflag &options &mode s1 s2 s3) ; FIXME: rename to addc-cflag
+ (OPTIONS ANYMODE RTX RTX RTX) (NA NA OP0 MATCH1 BI)
+ TRINARY
+ #f
+)
+(drn (add-oflag &options &mode s1 s2 s3) ; FIXME: rename to addc-vflag
+ (OPTIONS ANYMODE RTX RTX RTX) (NA NA OP0 MATCH1 BI)
+ TRINARY
+ #f
+)
+(drn (subc &options &mode s1 s2 s3)
+ (OPTIONS ANYMODE RTX RTX RTX) (NA NA OP0 MATCH1 BI)
+ TRINARY
+ #f
+)
+(drn (sub-cflag &options &mode s1 s2 s3) ; FIXME: rename to subc-cflag
+ (OPTIONS ANYMODE RTX RTX RTX) (NA NA OP0 MATCH1 BI)
+ TRINARY
+ #f
+)
+(drn (sub-oflag &options &mode s1 s2 s3) ; FIXME: rename to subc-vflag
+ (OPTIONS ANYMODE RTX RTX RTX) (NA NA OP0 MATCH1 BI)
+ TRINARY
+ #f
+)
+
+; Usurp these names so that we have consistent rtl should a program generator
+; ever want to infer more about what the semantics are doing.
+; For now these are just macros that expand to real rtl to perform the
+; operation.
+
+; Return bit indicating if VALUE is zero/non-zero.
+(drmn (zflag arg1 . rest) ; mode value)
+ (if (null? rest) ; mode missing?
+ (list 'eq 'DFLT arg1 0)
+ (list 'eq arg1 (car rest) 0))
+)
+
+; Return bit indicating if VALUE is negative/non-negative.
+(drmn (nflag arg1 . rest) ; mode value)
+ (if (null? rest) ; mode missing?
+ (list 'lt 'DFLT arg1 0)
+ (list 'lt arg1 (car rest) 0))
+)
+
+; Multiply/divide.
+
+(drn (mul &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+; ??? In non-sim case, ensure s1,s2 is in right C type for right result.
+; ??? Need two variants, one that avoids implementation defined situations
+; [both host and target], and one that specifies implementation defined
+; situations [target].
+(drn (div &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (udiv &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (mod &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (umod &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+; wip: mixed mode mul/div
+
+; various floating point routines
+
+(drn (sqrt &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+(drn (cos &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+(drn (sin &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA OP0)
+ UNARY
+ #f
+)
+
+; min/max
+
+(drn (min &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+(drn (max &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+(drn (umin &options &mode s1 s2)
+ (OPTIONS INTMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+(drn (umax &options &mode s1 s2)
+ (OPTIONS INTMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+; These are bitwise operations.
+(drn (and &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (or &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (xor &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+; Shift operations.
+
+(drn (sll &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 INT)
+ BINARY
+ #f
+)
+(drn (srl &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 INT)
+ BINARY
+ #f
+)
+; ??? In non-sim case, ensure s1 is in right C type for right result.
+(drn (sra &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 INT)
+ BINARY
+ #f
+)
+; Rotates don't really have a sign, so doesn't matter what we say.
+(drn (ror &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 INT)
+ BINARY
+ #f
+)
+(drn (rol &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 INT)
+ BINARY
+ #f
+)
+; ??? Will also need rotate-with-carry [duh...].
+
+; These are boolean operations (e.g. C &&, ||).
+; The result always has mode BI.
+; ??? 'twould be more Schemey to take a variable number of args.
+; ??? 'twould also simplify several .cpu description entries.
+; On the other hand, handling an arbitrary number of args isn't supported by
+; ISA's, which the main goal of what we're trying to represent.
+(drn (andif &options &mode s1 s2)
+ (OPTIONS DFLTMODE RTX RTX) (NA NA ANY ANY)
+ BINARY ; IF?
+ #f
+)
+(drn (orif &options &mode s1 s2)
+ (OPTIONS DFLTMODE RTX RTX) (NA NA ANY ANY)
+ BINARY ; IF?
+ #f
+)
+
+; `bitfield' is an experimental operation.
+; It's not really needed but it might help simplify some things.
+;
+;(drn (bitfield mode src start length)
+; ...
+; ...
+;)
+
+; Conversions.
+
+(drn (ext &options &mode s1)
+ (OPTIONS INTMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (zext &options &mode s1)
+ (OPTIONS INTMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (trunc &options &mode s1)
+ (OPTIONS INTMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (fext &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (ftrunc &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (float &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (ufloat &options &mode s1)
+ (OPTIONS FLOATMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (fix &options &mode s1)
+ (OPTIONS INTMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+(drn (ufix &options &mode s1)
+ (OPTIONS INTMODE RTX) (NA NA ANY)
+ UNARY
+ #f
+)
+
+; Comparisons.
+; MODE is the mode of S1,S2. The result always has mode BI.
+
+(drn (eq &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (ne &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+; ??? In non-sim case, ensure s1,s2 is in right C type for right result.
+(drn (lt &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (le &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (gt &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (ge &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+; ??? In non-sim case, ensure s1,s2 is in right C type for right result.
+(drn (ltu &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (leu &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (gtu &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+(drn (geu &options &mode s1 s2)
+ (OPTIONS ANYMODE RTX RTX) (NA NA OP0 MATCH1)
+ BINARY
+ #f
+)
+
+; Set membership.
+; Useful in ifield assertions.
+
+; Return a boolean (BI mode) indicating if VALUE is in SET.
+; VALUE is any constant rtx. SET is a `number-list' rtx.
+
+(drn (member &options &mode value set)
+ (OPTIONS DFLTMODE RTX RTX) (NA NA INT INT)
+ MISC
+ (begin
+ (if (not (rtx-constant? value))
+ (context-error (estate-context *estate*) "value is not a constant" value))
+ (if (not (rtx-kind? 'number-list set))
+ (context-error (estate-context *estate*) "set is not a `number-list' rtx" set))
+ (if (memq (rtx-constant-value value) (rtx-number-list-values set))
+ (rtx-true)
+ (rtx-false)))
+)
+
+(drn (number-list &options &mode value-list)
+ (OPTIONS INTMODE NUMBER . NUMBER) (NA NA NA . NA)
+ MISC
+ #f
+)
+
+; Conditional execution.
+
+; FIXME: make syntax node?
+(drn (if &options &mode cond then . else)
+ (OPTIONS ANYMODE TESTRTX RTX . RTX) (NA NA ANY OP0 . MATCH2)
+ IF
+ (apply e-if (append! (list *estate* mode cond then) else))
+)
+
+; ??? The syntax here isn't quite that of Scheme. A condition must be
+; followed by a result expression.
+; ??? Intermediate expressions (the ones before the last one) needn't have
+; the same mode as the result.
+(drsn (cond &options &mode . cond-code-list)
+ (OPTIONS ANYMODE . CONDRTX) (NA NA . OP0)
+ COND
+ #f
+)
+
+; ??? Intermediate expressions (the ones before the last one) needn't have
+; the same mode as the result.
+(drn (case &options &mode test . case-list)
+ (OPTIONS ANYMODE RTX . CASERTX) (NA NA ANY . OP0)
+ COND
+ #f
+)
+
+; Parallels and Sequences
+
+; This has to be a syntax node as we don't want EXPRS to be pre-evaluated.
+; All semantic ops must have a mode, though here it must be VOID.
+; IGNORE is for consistency with sequence. ??? Delete some day.
+; ??? There's no real need for mode either.
+
+(drsn (parallel &options &mode ignore expr . exprs)
+ (OPTIONS VOIDFLTODE LOCALS RTX . RTX) (NA NA NA VOID . VOID)
+ SEQUENCE
+ #f
+)
+
+; This has to be a syntax node to handle locals properly: they're not defined
+; yet and thus pre-evaluating the expressions doesn't work.
+; ??? This should create a closure.
+
+(drsn (sequence &options &mode locals expr . exprs)
+ (OPTIONS ANYMODE LOCALS RTX . RTX) (NA NA NA OP0 . OP0)
+ SEQUENCE
+ #f
+)
+
+; Internal rtx to create a closure.
+; Internal, so it does not appear in rtl.texi.
+
+(drsn (closure &options &mode expr env)
+ (OPTIONS DFLTMODE RTX ENV) (NA NA NA NA)
+ MISC
+ #f
+)
+
+)) ; End of def-rtx-funcs
diff --git a/cgen/sem-frags.scm b/cgen/sem-frags.scm
new file mode 100644
index 00000000000..7e50bd0a817
--- /dev/null
+++ b/cgen/sem-frags.scm
@@ -0,0 +1,1236 @@
+; Semantic fragments.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Background info:
+; Some improvement in pbb simulator efficiency is obtained in cases like
+; the ARM where for example operand2 computation is expensive in terms of
+; cpu cost, code size, and subroutine call overhead if the code is put in
+; a subroutine. It could be inlined, but there are numerous occurences
+; resulting in poor icache usage.
+; If the computation is put in its own fragment then code size is reduced
+; [improving icache usage] and subroutine call overhead is removed in a
+; computed-goto simulator [arguments are passed in machine generated local
+; variables].
+;
+; The basic procedure here is to:
+; - break all insns up into a set of statements
+; This is either one statement in the case of insns that don't begin with a
+; sequence, or a list of statements, one for each element in the sequence.
+; - find a profitable set of common leading statements (called the "header")
+; and a profitable set of common trailing statements (called the "trailer")
+; What is "profitable" depends on
+; - how expensive the statement is
+; - how long the statement is
+; - the number of insns using the statement
+; - what fraction of the total insn the statement is
+; - rewrite insn semantics in terms of the new header and trailer fragments
+; plus a "middle" part that is whatever is left over
+; - there is always a header, the middle and trailer parts are optional
+; - cti insns require a header and trailer, though they can be the same
+; fragment
+;
+; TODO:
+; - check ARM orr insns which come out as header, tiny middle, trailer
+; - the tiny middle seems like a waste (combine with trailer?)
+; - there are 8 trailers consisting of just `nop' for ARM
+; - rearranging statements to increase number and length of common sets
+; - combine common middle fragments
+; - parallel's not handled yet (only have to handle parallel's at the
+; top level)
+; - insns can also be split on timing-sensitive boundaries (pipeline, memory,
+; whatever) though that is not implemented yet. This may involve rtl
+; additions.
+;
+; Usage:
+; - call sim-sfrag-init! first, to initialize
+; - call sim-sfrag-analyze-insns! to create the semantic fragments
+; - afterwards, call
+; - sim-sfrag-insn-list
+; - sim-sfrag-frag-table
+; - sim-sfrag-usage-table
+; - sim-sfrag-locals-list
+
+; Statement computation.
+
+; Set to #t to collect various statistics.
+
+(define -stmt-stats? #f)
+
+; Collection of computed stats. Only set if -stmt-stats? = #t.
+
+(define -stmt-stats #f)
+
+; Collection of computed statement data. Only set if -stmt-stats? = #t.
+
+(define -stmt-stats-data #f)
+
+; Create a structure recording data of all statements.
+; A pair of (next-ordinal . table).
+
+(define (-stmt-data-make hash-size)
+ (cons 0 (make-vector hash-size nil))
+)
+
+; Accessors.
+
+(define (-stmt-data-table data) (cdr data))
+(define (-stmt-data-next-num data) (car data))
+(define (-stmt-data-set-next-num! data newval) (set-car! data newval))
+(define (-stmt-data-hash-size data) (vector-length (cdr data)))
+
+; A single statement.
+; INSN semantics either consist of a single statement or a sequence of them.
+
+(define <statement>
+ (class-make '<statement> nil
+ '(
+ ; RTL code
+ expr
+
+ ; Local variables of the sequence `expr' is in.
+ locals
+
+ ; Ordinal of the statement.
+ num
+
+ ; Costs.
+ ; SPEED-COST is the cost of executing fragment, relative to a
+ ; simple add.
+ ; SIZE-COST is the size of the fragment, relative to a simple
+ ; add.
+ ; ??? The cost numbers are somewhat arbitrary and subject to
+ ; review.
+ speed-cost
+ size-cost
+
+ ; Users of this statement.
+ ; Each element is (owner-number . owner-object),
+ ; where owner-number is an index into the initial insn table
+ ; (e.g. insn-list arg of sfrag-create-cse-mapping), and
+ ; owner-object is the corresponding object.
+ users
+ )
+ nil)
+)
+
+(define-getters <statement> -stmt (expr locals num speed-cost size-cost users))
+
+(define-setters <statement> -stmt (users))
+
+; Make a <statement> object of EXPR.
+; LOCALS is a list of local variables of the sequence EXPR is in.
+; NUM is the ordinal of EXPR.
+; SPEED-COST is the cost of executing the statement, relative to a simple add.
+; SIZE-COST is the size of the fragment, relative to a simple add.
+; ??? The cost numbers are somewhat arbitrary and subject to review.
+;
+; The user list is set to nil.
+
+(define (-stmt-make expr locals num speed-cost size-cost)
+ (make <statement> expr locals num speed-cost size-cost nil)
+)
+
+; Add a user of STMT.
+
+(define (-stmt-add-user! stmt user-num user-obj)
+ (-stmt-set-users! stmt (cons (cons user-num user-obj) (-stmt-users stmt)))
+ *UNSPECIFIED*
+)
+
+; Lookup STMT in DATA.
+; CHAIN-NUM is an argument so it need only be computed once.
+; The result is the found <statement> object or #f.
+
+(define (-frag-lookup-stmt data chain-num stmt)
+ (let ((table (-stmt-data-table data)))
+ (let loop ((stmts (vector-ref table chain-num)))
+ (cond ((null? stmts)
+ #f)
+ ; ??? equal? should be appropriate rtx-equal?, blah blah blah.
+ ((equal? (-stmt-expr (car stmts)) stmt)
+ (car stmts))
+ (else
+ (loop (cdr stmts))))))
+)
+
+; Hash a statement.
+
+; Computed hash value.
+; Global 'cus -frag-hash-compute! is defined globally so we can use
+; /fastcall (FIXME: Need /fastcall to work on non-global procs).
+
+(define -frag-hash-value-tmp 0)
+
+(define (-frag-hash-string str)
+ (let loop ((chars (map char->integer (string->list str))) (result 0))
+ (if (null? chars)
+ result
+ (loop (cdr chars) (modulo (+ (* result 7) (car chars)) #xfffffff))))
+)
+
+(define (-frag-hash-compute! rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (let ((h 0))
+ (case (rtx-name expr)
+ ((operand)
+ (set! h (-frag-hash-string (symbol->string (rtx-operand-name expr)))))
+ ((local)
+ (set! h (-frag-hash-string (symbol->string (rtx-local-name expr)))))
+ ((const)
+ (set! h (rtx-const-value expr)))
+ (else
+ (set! h (rtx-num rtx-obj))))
+ (set! -frag-hash-value-tmp
+ ; Keep number small.
+ (modulo (+ (* -frag-hash-value-tmp 3) h op-pos)
+ #xfffffff)))
+
+ ; #f -> "continue with normal traversing"
+ #f
+)
+
+(define (-frag-hash-stmt stmt locals size)
+ (set! -frag-hash-value-tmp 0)
+ (rtx-traverse-with-locals #f #f stmt -frag-hash-compute! locals #f) ; FIXME: (/fastcall-make -frag-hash-compute!))
+ (modulo -frag-hash-value-tmp size)
+)
+
+; Compute the speed/size costs of a statement.
+
+; Compute speed/size costs.
+; Global 'cus -frag-cost-compute! is defined globally so we can use
+; /fastcall (FIXME: Need /fastcall to work on non-global procs).
+
+(define -frag-speed-cost-tmp 0)
+(define -frag-size-cost-tmp 0)
+
+(define (-frag-cost-compute! rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ ; FIXME: wip
+ (let ((speed 0)
+ (size 0))
+ (case (rtx-class rtx-obj)
+ ((ARG)
+ #f) ; these don't contribute to costs (at least for now)
+ ((SET)
+ ; FIXME: speed/size = 0?
+ (set! speed 1)
+ (set! size 1))
+ ((UNARY BINARY TRINARY)
+ (set! speed 1)
+ (set! size 1))
+ ((IF)
+ (set! speed 2)
+ (set! size 2))
+ (else
+ (set! speed 4)
+ (set! size 4)))
+ (set! -frag-speed-cost-tmp (+ -frag-speed-cost-tmp speed))
+ (set! -frag-size-cost-tmp (+ -frag-size-cost-tmp size)))
+
+ ; #f -> "continue with normal traversing"
+ #f
+)
+
+(define (-frag-stmt-cost stmt locals)
+ (set! -frag-speed-cost-tmp 0)
+ (set! -frag-size-cost-tmp 0)
+ (rtx-traverse-with-locals #f #f stmt -frag-cost-compute! locals #f) ; FIXME: (/fastcall-make -frag-cost-compute!))
+ (cons -frag-speed-cost-tmp -frag-size-cost-tmp)
+)
+
+; Add STMT to statement table DATA.
+; CHAIN-NUM is the chain in the hash table to add STMT to.
+; {SPEED,SIZE}-COST are passed through to -stmt-make.
+; The result is the newly created <statement> object.
+
+(define (-frag-add-stmt! data chain-num stmt locals speed-cost size-cost)
+ (let ((stmt (-stmt-make stmt locals (-stmt-data-next-num data) speed-cost size-cost))
+ (table (-stmt-data-table data)))
+ (vector-set! table chain-num (cons stmt (vector-ref table chain-num)))
+ (-stmt-data-set-next-num! data (+ 1 (-stmt-data-next-num data)))
+ stmt)
+)
+
+; Return the locals in EXPR.
+; If a sequence, return locals.
+; Otherwise, return nil.
+; The result is in assq'able form.
+
+(define (-frag-expr-locals expr)
+ (if (rtx-kind? 'sequence expr)
+ (rtx-sequence-assq-locals expr)
+ nil)
+)
+
+; Return the statements in EXPR.
+; If a sequence, return the sequence's expressions.
+; Otherwise, return (list expr).
+
+(define (-frag-expr-stmts expr)
+ (if (rtx-kind? 'sequence expr)
+ (rtx-sequence-exprs expr)
+ (list expr))
+)
+
+; Analyze statement STMT.
+; If STMT is already in STMT-DATA increment its frequency count.
+; Otherwise add it.
+; LOCALS are locals of the sequence STMT is in.
+; USAGE-TABLE is a vector of statement index lists for each expression.
+; USAGE-INDEX is the index of USAGE-TABLE to use.
+; OWNER is the object of the owner of the statement.
+
+(define (-frag-analyze-expr-stmt! locals stmt stmt-data usage-table expr-num owner)
+ (logit 3 "Analyzing statement: " (rtx-strdump stmt) "\n")
+ (let* ((chain-num
+ (-frag-hash-stmt stmt locals (-stmt-data-hash-size stmt-data)))
+ (stmt-obj (-frag-lookup-stmt stmt-data chain-num stmt)))
+
+ (logit 3 " chain #" chain-num "\n")
+
+ (if (not stmt-obj)
+ (let* ((costs (-frag-stmt-cost stmt locals))
+ (speed-cost (car costs))
+ (size-cost (cdr costs)))
+ (set! stmt-obj (-frag-add-stmt! stmt-data chain-num stmt locals
+ speed-cost size-cost))
+ (logit 3 " new statement, #" (-stmt-num stmt-obj) "\n"))
+ (logit 3 " existing statement, #" (-stmt-num stmt-obj) "\n"))
+
+ (-stmt-add-user! stmt-obj expr-num owner)
+
+ ; If first entry, initialize list, otherwise append to existing list.
+ (if (null? (vector-ref usage-table expr-num))
+ (vector-set! usage-table expr-num (list (-stmt-num stmt-obj)))
+ (append! (vector-ref usage-table expr-num)
+ (list (-stmt-num stmt-obj)))))
+
+ *UNSPECIFIED*
+)
+
+; Analyze each statement in EXPR and add it to STMT-DATA.
+; OWNER is the object of the owner of the expression.
+; USAGE-TABLE is a vector of statement index lists for each expression.
+; USAGE-INDEX is the index of the USAGE-TABLE entry to use.
+; As each statement's ordinal is computed it is added to the usage list.
+
+(define (-frag-analyze-expr! expr owner stmt-data usage-table usage-index)
+ (logit 3 "Analyzing " (obj:name owner) ": " (rtx-strdump expr) "\n")
+ (let ((locals (-frag-expr-locals expr))
+ (stmt-list (-frag-expr-stmts expr)))
+ (for-each (lambda (stmt)
+ (-frag-analyze-expr-stmt! locals stmt stmt-data
+ usage-table usage-index owner))
+ stmt-list))
+ *UNSPECIFIED*
+)
+
+; Compute statement data from EXPRS, a list of expressions.
+; OWNERS is a vector of objects that "own" each corresponding element in EXPRS.
+; The owner is usually an <insn> object. Actually it'll probably always be
+; an <insn> object but for now I want the disassociation.
+;
+; The result contains:
+; - vector of statement lists of each expression
+; - each element is (stmt1-index stmt2-index ...) where each stmtN-index is
+; an index into the statement table
+; - vector of statements (the statement table of the previous item)
+; - each element is a <statement> object
+
+(define (-frag-compute-statements exprs owners)
+ (logit 2 "Computing statement table ...\n")
+ (let* ((num-exprs (length exprs))
+ (hash-size
+ ; FIXME: This is just a quick hack to put something down on paper.
+ ; blah blah blah. Revisit as necessary.
+ (cond ((> num-exprs 300) 1019)
+ ((> num-exprs 100) 511)
+ (else 127))))
+
+ (let (; Hash table of expressions.
+ (stmt-data (-stmt-data-make hash-size))
+ ; Statement index lists for each expression.
+ (usage-table (make-vector num-exprs nil)))
+
+ ; Scan each expr, filling in stmt-data and usage-table.
+ (let loop ((exprs exprs) (exprnum 0))
+ (if (not (null? exprs))
+ (let ((expr (car exprs))
+ (owner (vector-ref owners exprnum)))
+ (-frag-analyze-expr! expr owner stmt-data usage-table exprnum)
+ (loop (cdr exprs) (+ exprnum 1)))))
+
+ ; Convert statement hash table to vector.
+ (let ((stmt-hash-table (-stmt-data-table stmt-data))
+ (end (vector-length (-stmt-data-table stmt-data)))
+ (stmt-table (make-vector (-stmt-data-next-num stmt-data) #f)))
+ (let loop ((i 0))
+ (if (< i end)
+ (begin
+ (map (lambda (stmt)
+ (vector-set! stmt-table (-stmt-num stmt) stmt))
+ (vector-ref stmt-hash-table i))
+ (loop (+ i 1)))))
+
+ ; All done. Compute stats if asked to.
+ (if -stmt-stats?
+ (begin
+ ; See how well the hashing worked.
+ (set! -stmt-stats-data stmt-data)
+ (set! -stmt-stats
+ (make-vector (vector-length stmt-hash-table) #f))
+ (let loop ((i 0))
+ (if (< i end)
+ (begin
+ (vector-set! -stmt-stats i
+ (length (vector-ref stmt-hash-table i)))
+ (loop (+ i 1)))))))
+
+ ; Result.
+ (cons usage-table stmt-table))))
+)
+
+; Semantic fragment selection.
+;
+; "semantic fragment" is the name assigned to each header/middle/trailer
+; "fragment" as each may consist of more than one statement, though not
+; necessarily all statements of the original sequence.
+
+(define <sfrag>
+ (class-make '<sfrag> '(<ident>)
+ '(
+ ; List of insn's using this frag.
+ users
+
+ ; Ordinal's of each element of `users'.
+ user-nums
+
+ ; Semantic format of insns using this fragment.
+ sfmt
+
+ ; List of statement numbers that make up `semantics'.
+ ; Each element is an index into the stmt-table arg of
+ ; -frag-pick-best.
+ ; This is #f if the sfrag wasn't derived from some set of
+ ; statements.
+ stmt-numbers
+
+ ; Raw rtl source of fragment.
+ semantics
+
+ ; Compiled source.
+ compiled-semantics
+
+ ; Boolean indicating if this frag is for parallel exec support.
+ parallel?
+
+ ; Boolean indicating if this is a header frag.
+ ; This includes all frags that begin a sequence.
+ header?
+
+ ; Boolean indicating if this is a trailer frag.
+ ; This includes all frags that end a sequence.
+ trailer?
+ )
+ nil)
+)
+
+(define-getters <sfrag> sfrag
+ (users user-nums sfmt stmt-numbers semantics compiled-semantics
+ parallel? header? trailer?)
+)
+
+(define-setters <sfrag> sfrag
+ (header? trailer?)
+)
+
+; Sorter to merge common fragments together.
+; A and B are lists of statement numbers.
+
+(define (-frag-sort a b)
+ (cond ((null? a)
+ (not (null? b)))
+ ((null? b)
+ #f)
+ ((< (car a) (car b))
+ #t)
+ ((> (car a) (car b))
+ #f)
+ (else ; =
+ (-frag-sort (cdr a) (cdr b))))
+)
+
+; Return a boolean indicating if L1,L2 match in the first LEN elements.
+; Each element is an integer.
+
+(define (-frag-list-match? l1 l2 len)
+ (cond ((= len 0)
+ #t)
+ ((or (null? l1) (null? l2))
+ #f)
+ ((= (car l1) (car l2))
+ (-frag-list-match? (cdr l1) (cdr l2) (- len 1)))
+ (else
+ #f))
+)
+
+; Return the number of expressions that match in the first LEN statements.
+
+(define (-frag-find-matching expr-table indices stmt-list len)
+ (let loop ((num-exprs 0) (indices indices))
+ (cond ((null? indices)
+ num-exprs)
+ ((-frag-list-match? stmt-list
+ (vector-ref expr-table (car indices)) len)
+ (loop (+ num-exprs 1) (cdr indices)))
+ (else
+ num-exprs)))
+)
+
+; Return a boolean indicating if making STMT-LIST a common fragment
+; among several owners is profitable.
+; STMT-LIST is a list of statement numbers, indices into STMT-TABLE.
+; NUM-EXPRS is the number of expressions with STMT-LIST in common.
+
+(define (-frag-merge-profitable? stmt-table stmt-list num-exprs)
+ ; FIXME: wip
+ (and (>= num-exprs 2)
+ (or ; No need to include speed costs yet.
+ ;(>= (-frag-list-speed-cost stmt-table stmt-list) 10)
+ (>= (-frag-list-size-cost stmt-table stmt-list) 4)))
+)
+
+; Return the cost of executing STMT-LIST.
+; STMT-LIST is a list of statment numbers, indices into STMT-TABLE.
+;
+; FIXME: The yardstick to use is wip. Currently we measure things relative
+; to a simple add insn which is given the value 1.
+
+(define (-frag-list-speed-cost stmt-table stmt-list)
+ ; FIXME: wip
+ (apply + (map (lambda (stmt-num)
+ (-stmt-speed-cost (vector-ref stmt-table stmt-num)))
+ stmt-list))
+)
+
+(define (-frag-list-size-cost stmt-table stmt-list)
+ ; FIXME: wip
+ (apply + (map (lambda (stmt-num)
+ (-stmt-size-cost (vector-ref stmt-table stmt-num)))
+ stmt-list))
+)
+
+; Compute the longest set of fragments it is desirable/profitable to create.
+; The result is (number-of-matching-exprs . stmt-number-list)
+; or #f if there isn't one (the longest set is the empty set).
+;
+; What is desirable depends on a few things:
+; - how often is it used?
+; - how expensive is it (size-wise and speed-wise)
+; - relationship to other frags
+;
+; STMT-TABLE is a vector of all statements.
+; STMT-USAGE-TABLE is a vector of all expressions. Each element is a list of
+; statement numbers (indices into STMT-TABLE).
+; INDICES is a sorted list of indices into STMT-USAGE-TABLE.
+; STMT-USAGE-TABLE is processed in the order specified by INDICES.
+;
+; FIXME: Choosing a statement list should depend on whether there are existing
+; chosen statement lists only slightly shorter.
+
+(define (-frag-longest-desired stmt-table stmt-usage-table indices)
+ ; STMT-LIST is the list of statements in the first expression.
+ (let ((stmt-list (vector-ref stmt-usage-table (car indices))))
+
+ (let loop ((len 1) (prev-num-exprs 0))
+
+ ; See how many subsequent expressions match at length LEN.
+ (let ((num-exprs (-frag-find-matching stmt-usage-table (cdr indices)
+ stmt-list len)))
+ ; If there aren't any, we're done.
+ ; If LEN-1 is usable, return that.
+ ; Otherwise there is no profitable list of fragments.
+ (if (= num-exprs 0)
+
+ (let ((matching-stmt-list (list-take (- len 1) stmt-list)))
+ (if (-frag-merge-profitable? stmt-table matching-stmt-list
+ prev-num-exprs)
+ (cons prev-num-exprs matching-stmt-list)
+ #f))
+
+ ; Found at least 1 subsequent matching expression.
+ ; Extend LEN and see if we still find matching expressions.
+ (loop (+ len 1) num-exprs)))))
+)
+
+; Return list of lists of objects for each unique <sformat-argbuf> in
+; USER-LIST.
+; Each element of USER-LIST is (insn-num . <insn> object).
+; The result is a list of lists. Each element in the top level list is
+; a list of elements of USER-LIST that have the same <sformat-argbuf>.
+; Insns are also distinguished by being a CTI insn vs a non-CTI insn.
+; CTI insns require special handling in the semantics.
+
+(define (-frag-split-by-sbuf user-list)
+ ; Sanity check.
+ (if (not (elm-bound? (cdar user-list) 'sfmt))
+ (error "sformats not computed"))
+ (if (not (elm-bound? (insn-sfmt (cdar user-list)) 'sbuf))
+ (error "sformat argbufs not computed"))
+
+ (let ((result nil)
+ ; Find INSN in SFMT-LIST. The result is the list INSN belongs in
+ ; or #f.
+ (find-obj (lambda (sbuf-list insn)
+ (let ((name (obj:name (sfmt-sbuf (insn-sfmt insn)))))
+ (let loop ((sbuf-list sbuf-list))
+ (cond ((null? sbuf-list)
+ #f)
+ ((and (eq? name
+ (obj:name (sfmt-sbuf (insn-sfmt (cdaar sbuf-list)))))
+ (eq? (insn-cti? insn)
+ (insn-cti? (cdaar sbuf-list))))
+ (car sbuf-list))
+ (else
+ (loop (cdr sbuf-list))))))))
+ )
+ (let loop ((users user-list))
+ (if (not (null? users))
+ (let ((try (find-obj result (cdar users))))
+ (if try
+ (append! try (list (car users)))
+ (set! result (cons (list (car users)) result)))
+ (loop (cdr users)))))
+
+ ; Done
+ result)
+)
+
+; Return a list of desired fragments to create.
+; These consist of the longest set of profitable leading statements in EXPRS.
+; Each element of the result is an <sfrag> object.
+;
+; STMT-TABLE is a vector of all statements.
+; STMT-USAGE-TABLE is a vector of statement number lists of each expression.
+; OWNER-TABLE is a vector of owner objects of each corresponding expression
+; in STMT-USAGE-TABLE.
+; KIND is one of 'header or 'trailer.
+;
+; This works for trailing fragments too as we do the computation based on the
+; reversed statement lists.
+
+(define (-frag-compute-desired-frags stmt-table stmt-usage-table owner-table kind)
+ (logit 2 "Computing desired " kind " frags ...\n")
+
+ (let* (
+ (stmt-usage-list
+ (if (eq? kind 'header)
+ (vector->list stmt-usage-table)
+ (map reverse (vector->list stmt-usage-table))))
+ ; Sort STMT-USAGE-TABLE. That will bring exprs with common fragments
+ ; together.
+ (sorted-indices (sort-grade stmt-usage-list -frag-sort))
+ ; List of statement lists that together yield the fragment to create,
+ ; plus associated users.
+ (desired-frags nil)
+ )
+
+ ; Update STMT-USAGE-TABLE in case we reversed the contents.
+ (set! stmt-usage-table (list->vector stmt-usage-list))
+
+ (let loop ((indices sorted-indices) (iteration 1))
+ (logit 3 "Iteration " iteration "\n")
+ (if (not (null? indices))
+ (let ((longest (-frag-longest-desired stmt-table stmt-usage-table indices)))
+
+ (if longest
+
+ ; Found an acceptable frag to create.
+ (let* ((num-exprs (car longest))
+ ; Reverse statement numbers back if trailer.
+ (stmt-list (if (eq? kind 'header)
+ (cdr longest)
+ (reverse (cdr longest))))
+ (picked-indices (list-take num-exprs indices))
+ ; Need one copy of the frag for each sbuf, as structure
+ ; offsets will be different in generated C/C++ code.
+ (sfmt-users (-frag-split-by-sbuf
+ (map (lambda (expr-num)
+ (cons expr-num
+ (vector-ref owner-table
+ expr-num)))
+ picked-indices))))
+
+ (logit 3 "Creating frag of length " (length stmt-list) ", " num-exprs " users\n")
+ (logit 3 "Indices: " picked-indices "\n")
+
+ ; Create an sfrag for each sbuf.
+ (for-each
+ (lambda (users)
+ (let* ((first-owner (cdar users))
+ (sfrag
+ (make <sfrag>
+ (symbol-append (obj:name first-owner)
+ (if (eq? kind 'header)
+ '-hdr
+ '-trlr))
+ ""
+ atlist-empty
+ (map cdr users)
+ (map car users)
+ (insn-sfmt first-owner)
+ stmt-list
+ (apply
+ rtx-make
+ (cons 'sequence
+ (cons 'VOID
+ (cons nil
+ (map (lambda (stmt-num)
+ (-stmt-expr
+ (vector-ref stmt-table
+ stmt-num)))
+ stmt-list)))))
+ #f ; compiled-semantics
+ #f ; parallel?
+ (eq? kind 'header)
+ (eq? kind 'trailer)
+ )))
+ (set! desired-frags (cons sfrag desired-frags))))
+ sfmt-users)
+
+ ; Continue, dropping statements we've put into the frag.
+ (loop (list-drop num-exprs indices) (+ iteration 1)))
+
+ ; Couldn't find an acceptable statement list.
+ ; Try again with next one.
+ (begin
+ (logit 3 "No acceptable frag found.\n")
+ (loop (cdr indices) (+ iteration 1)))))))
+
+ ; Done.
+ desired-frags)
+)
+
+; Return the set of desired fragments to create.
+; STMT-TABLE is a vector of each statement.
+; STMT-USAGE-TABLE is a vector of (stmt1-index stmt2-index ...) elements for
+; each expression, where each stmtN-index is an index into STMT-TABLE.
+; OWNER-TABLE is a vector of owner objects of each corresponding expression
+; in STMT-USAGE-TABLE.
+;
+; Each expression is split in up to three pieces: header, middle, trailer.
+; This computes pseudo-optimal headers and trailers (if they exist).
+; The "middle" part is whatever is leftover.
+;
+; The result is a vector of 4 elements:
+; - vector of (header middle trailer) semantic fragments for each expression
+; - each element is an index into the respective table or #f if not present
+; - list of header fragments, each element is an <sfrag> object
+; - same but for trailer fragments
+; - same but for middle fragments
+;
+; ??? While this is a big function, each piece is simple and straightforward.
+; It's kept as one big function so we can compute each expression's sfrag list
+; as we go. Though it's not much extra expense to not do this.
+
+(define (-frag-pick-best stmt-table stmt-usage-table owner-table)
+ (let (
+ (num-stmts (vector-length stmt-table))
+ (num-exprs (vector-length stmt-usage-table))
+ ; FIXME: Shouldn't have to do vector->list.
+ (stmt-usage-list (vector->list stmt-usage-table))
+ ; Specify result holders here, simplifies code.
+ (desired-header-frags #f)
+ (desired-trailer-frags #f)
+ (middle-frags #f)
+ ; Also allocate space for expression sfrag usage table.
+ ; We compute it as we go to save scanning the header and trailer
+ ; lists twice.
+ ; copy-tree is needed to avoid shared storage.
+ (expr-sfrags (copy-tree (make-vector (vector-length stmt-usage-table)
+ #(#f #f #f))))
+ )
+
+ ; Compute desired headers.
+ (set! desired-header-frags
+ (-frag-compute-desired-frags stmt-table stmt-usage-table owner-table
+ 'header))
+
+ ; Compute the header used by each expression.
+ (let ((expr-hdrs-v (make-vector num-exprs #f))
+ (num-hdrs (length desired-header-frags)))
+ (let loop ((hdrs desired-header-frags) (hdrnum 0))
+ (if (< hdrnum num-hdrs)
+ (let ((hdr (car hdrs)))
+ (for-each (lambda (expr-num)
+ (vector-set! (vector-ref expr-sfrags expr-num) 0
+ hdrnum)
+ (vector-set! expr-hdrs-v expr-num hdr))
+ (sfrag-user-nums hdr))
+ (loop (cdr hdrs) (+ hdrnum 1)))))
+
+ ; Truncate each expression by the header it will use and then find
+ ; the set of desired trailers.
+ (let ((expr-hdrs (vector->list expr-hdrs-v)))
+
+ (set! desired-trailer-frags
+ (-frag-compute-desired-frags
+ stmt-table
+ ; FIXME: Shouldn't have to use list->vector.
+ ; [still pass a vector, but use vector-map here instead of map]
+ (list->vector
+ (map (lambda (expr hdr)
+ (if hdr
+ (list-drop (length (sfrag-stmt-numbers hdr)) expr)
+ expr))
+ stmt-usage-list expr-hdrs))
+ owner-table
+ 'trailer))
+
+ ; Record the trailer used by each expression.
+ (let ((expr-trlrs-v (make-vector num-exprs #f))
+ (num-trlrs (length desired-trailer-frags)))
+ (let loop ((trlrs desired-trailer-frags) (trlrnum 0))
+ (if (< trlrnum num-trlrs)
+ (let ((trlr (car trlrs)))
+ (for-each (lambda (expr-num)
+ (vector-set! (vector-ref expr-sfrags expr-num) 2
+ trlrnum)
+ (vector-set! expr-trlrs-v expr-num trlr))
+ (sfrag-user-nums trlr))
+ (loop (cdr trlrs) (+ trlrnum 1)))))
+
+ ; We have the desired headers and trailers, now compute the middle
+ ; part for each expression. This is just what's left over.
+ ; ??? We don't try to cse the middle part. Though we can in the
+ ; future should it prove useful enough.
+ (logit 2 "Computing middle frags ...\n")
+ (let* ((expr-trlrs (vector->list expr-trlrs-v))
+ (expr-middle-stmts
+ (map (lambda (expr hdr trlr)
+ (list-tail-drop
+ (if trlr (length (sfrag-stmt-numbers trlr)) 0)
+ (list-drop
+ (if hdr (length (sfrag-stmt-numbers hdr)) 0)
+ expr)))
+ stmt-usage-list expr-hdrs expr-trlrs)))
+
+ ; Finally, record the middle sfrags used by each expression.
+ (let loop ((tmp-middle-frags nil)
+ (next-middle-frag-num 0)
+ (expr-num 0)
+ (expr-middle-stmts expr-middle-stmts))
+
+ (if (null? expr-middle-stmts)
+
+ ; Done!
+ ; [The next statement executed after this is the one at the
+ ; end that builds the result. Maybe it should be built here
+ ; and this should be the last statement, but I'm trying this
+ ; style out for awhile.]
+ (set! middle-frags (reverse! tmp-middle-frags))
+
+ ; Does this expr have a middle sfrag?
+ (if (null? (car expr-middle-stmts))
+ ; Nope.
+ (loop tmp-middle-frags
+ next-middle-frag-num
+ (+ expr-num 1)
+ (cdr expr-middle-stmts))
+ ; Yep.
+ (let ((owner (vector-ref owner-table expr-num)))
+ (vector-set! (vector-ref expr-sfrags expr-num)
+ 1 next-middle-frag-num)
+ (loop (cons (make <sfrag>
+ (symbol-append (obj:name owner) '-mid)
+ (string-append (obj:comment owner)
+ ", middle part")
+ (obj-atlist owner)
+ (list owner)
+ (list expr-num)
+ (insn-sfmt owner)
+ (car expr-middle-stmts)
+ (apply
+ rtx-make
+ (cons 'sequence
+ (cons 'VOID
+ (cons nil
+ (map (lambda (stmt-num)
+ (-stmt-expr
+ (vector-ref stmt-table stmt-num)))
+ (car expr-middle-stmts))))))
+ #f ; compiled-semantics
+ #f ; parallel?
+ #f ; header?
+ #f ; trailer?
+ )
+ tmp-middle-frags)
+ (+ next-middle-frag-num 1)
+ (+ expr-num 1)
+ (cdr expr-middle-stmts))))))))))
+
+ ; Result.
+ (vector expr-sfrags
+ desired-header-frags
+ desired-trailer-frags
+ middle-frags))
+)
+
+; Given a list of expressions, return list of locals in top level sequences.
+; ??? Collisions will be handled by rewriting rtl (renaming locals).
+;
+; This has to be done now as the cse pass must (currently) take into account
+; the rewritten rtl.
+; ??? This can be done later, with an appropriate enhancement to rtx-equal?
+; ??? cse can be improved by ignoring local variable name (of course).
+
+(define (-frag-compute-locals! expr-list)
+ (logit 2 "Computing common locals ...\n")
+ (let ((result nil)
+ (lookup-local (lambda (local local-list)
+ (assq (car local) local-list)))
+ (local-equal? (lambda (l1 l2)
+ (and (eq? (car l1) (car l2))
+ (mode:eq? (cadr l1) (cadr l2)))))
+ )
+ (for-each (lambda (expr)
+ (let ((locals (-frag-expr-locals expr)))
+ (for-each (lambda (local)
+ (let ((entry (lookup-local local result)))
+ (if (and entry
+ (local-equal? local entry))
+ #f ; already present
+ (set! result (cons local result)))))
+ locals)))
+ expr-list)
+ ; Done.
+ result)
+)
+
+; Common subexpression computation.
+
+; Given a list of rtl expressions and their owners, return a pseudo-optimal
+; set of fragments and a usage list for each owner.
+; Common fragments are combined and the original expressions become a sequence
+; of these fragments. The result is "pseudo-optimal" in the sense that the
+; desired result is somewhat optimal, though no attempt is made at precise
+; optimality.
+;
+; OWNERS is a list of objects that "own" each corresponding element in EXPRS.
+; The owner is usually an <insn> object. Actually it'll probably always be
+; an <insn> object but for now I want the disassociation.
+;
+; The result is a vector of six elements:
+; - sfrag usage table for each owner #(header middle trailer)
+; - statement table (vector of all statements, made with -stmt-make)
+; - list of sequence locals used by header sfrags
+; - these locals are defined at the top level so that all fragments have
+; access to them
+; - ??? Need to handle collisions among incompatible types.
+; - header sfrags
+; - trailer sfrags
+; - middle sfrags
+
+(define (-sem-find-common-frags-1 exprs owners)
+ ; Sanity check.
+ (if (not (elm-bound? (car owners) 'sfmt))
+ (error "sformats not computed"))
+
+ ; A simple procedure that calls, in order:
+ ; -frag-compute-locals!
+ ; -frag-compute-statements
+ ; -frag-pick-best
+ ; The rest is shuffling of results.
+
+ ; Internally it's easier if OWNERS is a vector.
+ (let ((owners (list->vector owners))
+ (locals (-frag-compute-locals! exprs)))
+
+ ; Collect statement usage data.
+ (let ((stmt-usage (-frag-compute-statements exprs owners)))
+ (let ((stmt-usage-table (car stmt-usage))
+ (stmt-table (cdr stmt-usage)))
+
+ ; Compute the frags we want to create.
+ ; These are in general sequences of statements.
+ (let ((desired-frags
+ (-frag-pick-best stmt-table stmt-usage-table owners)))
+ (let (
+ (expr-sfrags (vector-ref desired-frags 0))
+ (headers (vector-ref desired-frags 1))
+ (trailers (vector-ref desired-frags 2))
+ (middles (vector-ref desired-frags 3))
+ )
+ ; Result.
+ (vector expr-sfrags stmt-table locals
+ headers trailers middles))))))
+)
+
+; Cover proc of -sem-find-common-frags-1.
+; See its documentation.
+
+(define (sem-find-common-frags insn-list)
+ (-sem-find-common-frags-1
+ (begin
+ (logit 2 "Simplifying/canonicalizing rtl ...\n")
+ (map (lambda (insn)
+ ; Must pass canonicalized and macro-expanded rtl.
+ (rtx-simplify #f insn (insn-semantics insn)
+ (-build-known-values insn)))
+ insn-list))
+ insn-list)
+)
+
+; Subroutine of sfrag-create-cse-mapping to compute INSN's fragment list.
+; FRAG-USAGE is a vector of 3 elements: #(header middle trailer).
+; Each element is a fragment number or #f if not present.
+; Numbers in FRAG-USAGE are indices relative to their respective subtables
+; of FRAG-TABLE (which is a vector of all 3 tables concatenated together).
+; NUM-HEADERS,NUM-TRAILERS are used to compute absolute indices.
+;
+; No header may have been created. This happens when
+; it's not profitable (or possible) to merge this insn's
+; leading statements with other insns. Ditto for
+; trailer. However, each cti insn must have a header
+; and a trailer (for pc handling setup and change).
+; Try to use the middle fragment if present. Otherwise,
+; use the x-header,x-trailer virtual insns.
+
+(define (-sfrag-compute-frag-list! insn frag-usage frag-table num-headers num-trailers x-header-relnum x-trailer-relnum)
+ ; `(list #f)' is so append! works. The #f is deleted before returning.
+ (let ((result (list #f))
+ (header (vector-ref frag-usage 0))
+ (middle (and (vector-ref frag-usage 1)
+ (+ (vector-ref frag-usage 1)
+ num-headers num-trailers)))
+ (trailer (and (vector-ref frag-usage 2)
+ (+ (vector-ref frag-usage 2)
+ num-headers)))
+ (x-header-num x-header-relnum)
+ (x-trailer-num (+ x-trailer-relnum num-headers))
+ )
+
+ ; cse'd header created?
+ (if header
+ ; Yep.
+ (append! result (list header))
+ ; Nope. Use the middle frag if present, otherwise use x-header.
+ ; Can't use the trailer fragment because by definition it is shared
+ ; among several insns.
+ (if middle
+ ; Mark the middle frag as the header frag.
+ (sfrag-set-header?! (vector-ref frag-table middle) #t)
+ ; No middle, use x-header.
+ (append! result (list x-header-num))))
+
+ ; middle fragment present?
+ (if middle
+ (append! result (list middle)))
+
+ ; cse'd trailer created?
+ (if trailer
+ ; Yep.
+ (append! result (list trailer))
+ ; Nope. Use the middle frag if present, otherwise use x-trailer.
+ ; Can't use the header fragment because by definition it is shared
+ ; among several insns.
+ (if middle
+ ; Mark the middle frag as the trailer frag.
+ (sfrag-set-trailer?! (vector-ref frag-table middle) #t)
+ ; No middle, use x-trailer.
+ (append! result (list x-trailer-num))))
+
+ ; Done.
+ (cdr result))
+)
+
+; Subroutine of sfrag-create-cse-mapping to find the fragment number of the
+; x-header/x-trailer virtual frags.
+
+(define (-frag-lookup-virtual frag-list name)
+ (let loop ((i 0) (frag-list frag-list))
+ (if (null? frag-list)
+ (assert (not "expected virtual insn not present"))
+ (if (eq? name (obj:name (car frag-list)))
+ i
+ (loop (+ i 1) (cdr frag-list)))))
+)
+
+; Handle complex case, find set of common header and trailer fragments.
+; The result is a vector of:
+; - fragment table (a vector)
+; - table mapping used fragments for each insn (a list)
+; - locals list
+
+(define (sfrag-create-cse-mapping insn-list)
+ (logit 1 "Creating semantic fragments for pbb engine ...\n")
+
+ (let ((cse-data (sem-find-common-frags insn-list)))
+
+ ; Extract the results of sem-find-common-frags.
+ (let ((sfrag-usage-table (vector-ref cse-data 0))
+ (stmt-table (vector-ref cse-data 1))
+ (locals-list (vector-ref cse-data 2))
+ (header-list1 (vector-ref cse-data 3))
+ (trailer-list1 (vector-ref cse-data 4))
+ (middle-list (vector-ref cse-data 5)))
+
+ ; Create two special frags: x-header, x-trailer.
+ ; These are used by insns that don't have one or the other.
+ ; Header/trailer table indices are already computed for each insn
+ ; so append x-header/x-trailer to the end.
+ (let ((header-list
+ (append header-list1
+ (list
+ (make <sfrag>
+ 'x-header
+ "header fragment for insns without one"
+ (atlist-parse '(VIRTUAL) "" "semantic frag computation")
+ nil ; users
+ nil ; user ordinals
+ (insn-sfmt (current-insn-lookup 'x-before))
+ #f ; stmt-numbers
+ (rtx-make 'nop)
+ #f ; compiled-semantics
+ #f ; parallel?
+ #t ; header?
+ #f ; trailer?
+ ))))
+ (trailer-list
+ (append trailer-list1
+ (list
+ (make <sfrag>
+ 'x-trailer
+ "trailer fragment for insns without one"
+ (atlist-parse '(VIRTUAL) "" "semantic frag computation")
+ nil ; users
+ nil ; user ordinals
+ (insn-sfmt (current-insn-lookup 'x-before))
+ #f ; stmt-numbers
+ (rtx-make 'nop)
+ #f ; compiled-semantics
+ #f ; parallel?
+ #f ; header?
+ #t ; trailer?
+ )))))
+
+ (let ((num-headers (length header-list))
+ (num-trailers (length trailer-list))
+ (num-middles (length middle-list)))
+
+ ; Combine the three sfrag tables (headers, trailers, middles) into
+ ; one big one.
+ (let ((frag-table (list->vector (append header-list
+ trailer-list
+ middle-list)))
+ (x-header-relnum (-frag-lookup-virtual header-list 'x-header))
+ (x-trailer-relnum (-frag-lookup-virtual trailer-list 'x-trailer))
+ )
+ ; Convert sfrag-usage-table to one that refers to the one big
+ ; sfrag table.
+ (logit 2 "Computing insn frag usage ...\n")
+ (let ((insn-frags
+ (map (lambda (insn frag-usage)
+ (-sfrag-compute-frag-list! insn frag-usage
+ frag-table
+ num-headers num-trailers
+ x-header-relnum
+ x-trailer-relnum))
+ insn-list
+ ; FIXME: vector->list
+ (vector->list sfrag-usage-table)))
+ )
+ (logit 1 "Done fragment creation.\n")
+ (vector frag-table insn-frags locals-list)))))))
+)
+
+; Data analysis interface.
+
+(define -sim-sfrag-init? #f)
+(define (sim-sfrag-init?) -sim-sfrag-init?)
+
+; Keep in globals for now, simplifies debugging.
+; evil globals, blah blah blah.
+(define -sim-sfrag-insn-list #f)
+(define -sim-sfrag-frag-table #f)
+(define -sim-sfrag-usage-table #f)
+(define -sim-sfrag-locals-list #f)
+
+(define (sim-sfrag-insn-list)
+ (assert -sim-sfrag-init?)
+ -sim-sfrag-insn-list
+)
+(define (sim-sfrag-frag-table)
+ (assert -sim-sfrag-init?)
+ -sim-sfrag-frag-table
+)
+(define (sim-sfrag-usage-table)
+ (assert -sim-sfrag-init?)
+ -sim-sfrag-usage-table
+)
+(define (sim-sfrag-locals-list)
+ (assert -sim-sfrag-init?)
+ -sim-sfrag-locals-list
+)
+
+(define (sim-sfrag-init!)
+ (set! -sim-sfrag-init? #f)
+ (set! -sim-sfrag-insn-list #f)
+ (set! -sim-sfrag-frag-table #f)
+ (set! -sim-sfrag-usage-table #f)
+ (set! -sim-sfrag-locals-list #f)
+)
+
+(define (sim-sfrag-analyze-insns!)
+ (if (not -sim-sfrag-init?)
+ (begin
+ (set! -sim-sfrag-insn-list (non-multi-insns (non-alias-insns (current-insn-list))))
+ (let ((frag-data (sfrag-create-cse-mapping -sim-sfrag-insn-list)))
+ (set! -sim-sfrag-frag-table (vector-ref frag-data 0))
+ (set! -sim-sfrag-usage-table (vector-ref frag-data 1))
+ (set! -sim-sfrag-locals-list (vector-ref frag-data 2)))
+ (set! -sim-sfrag-init? #t)))
+
+ *UNSPECIFIED*
+)
+
+; Testing support.
+
+(define (-frag-small-test-data)
+ '(
+ (a . (sequence VOID ((SI tmp)) (set DFLT tmp rm) (set DFLT rd rm)))
+ (b . (sequence VOID ((SI tmp)) (set DFLT tmp rm) (set DFLT rd rm)))
+ (c . (set DFLT rd rm))
+ )
+)
+
+(define (-frag-test-data)
+ (cons
+ (map (lambda (insn)
+ ; Must pass canonicalized and macro-expanded rtl.
+ (rtx-simplify #f insn (insn-semantics insn)
+ (-build-known-values insn)))
+ (non-multi-insns (non-alias-insns (current-insn-list))))
+ (non-multi-insns (non-alias-insns (current-insn-list))))
+)
+
+(define test-sfrag-table #f)
+(define test-stmt-table #f)
+(define test-locals-list #f)
+(define test-header-list #f)
+(define test-trailer-list #f)
+(define test-middle-list #f)
+
+(define (frag-test-run)
+ (let* ((test-data (-frag-test-data))
+ (frag-data (sem-find-common-frags (car test-data) (cdr test-data))))
+ (set! test-sfrag-table (vector-ref frag-data 0))
+ (set! test-stmt-table (vector-ref frag-data 1))
+ (set! test-locals-list (vector-ref frag-data 2))
+ (set! test-header-list (vector-ref frag-data 3))
+ (set! test-trailer-list (vector-ref frag-data 4))
+ (set! test-middle-list (vector-ref frag-data 5))
+ )
+ *UNSPECIFIED*
+)
diff --git a/cgen/semantics.scm b/cgen/semantics.scm
new file mode 100644
index 00000000000..11595876f03
--- /dev/null
+++ b/cgen/semantics.scm
@@ -0,0 +1,879 @@
+; Routines for instruction semantic analysis (including rtx-simplify).
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Semantic expression compilation.
+; This is more involved than normal rtx compilation as we need to keep
+; track of the inputs and outputs. Various attributes that can be derived
+; from the code are also computed.
+
+; Subroutine of -simplify-expr-fn to compare two values for equality.
+; If both are constants and they're equal return #f/#t.
+; INVERT? = #f -> return #t if equal, #t -> return #f if equal.
+; Returns 'unknown if either argument is not a constant.
+
+(define (rtx-const-equal arg0 arg1 invert?)
+ (if (and (rtx-constant? arg0)
+ (rtx-constant? arg1))
+ (if invert?
+ (!= (rtx-constant-value arg0)
+ (rtx-constant-value arg1))
+ (= (rtx-constant-value arg0)
+ (rtx-constant-value arg1)))
+ 'unknown)
+)
+
+; Subroutine of -simplify-expr-fn to see if MAYBE-CONST is one of NUMBER-LIST.
+; NUMBER-LIST is a `number-list' rtx.
+; INVERT? is #t if looking for non-membership.
+; #f/#t is only returned for definitive answers.
+; If INVERT? is #f:
+; - return #f if MAYBE-CONST is not in NUMBER-LIST
+; - return #t if MAYBE-CONST is in NUMBER-LIST and it has only one member
+; - return 'member if MAYBE-CONST is in NUMBER-LIST and it has many members
+; - otherwise return 'unknown
+; If INVERT? is #t:
+; - return #t if MAYBE-CONST is not in NUMBER-LIST
+; - return #f if MAYBE-CONST is in NUMBER-LIST and it has only one member
+; - return 'member if MAYBE-CONST is in NUMBER-LIST and it has many members
+; - otherwise return 'unknown
+
+(define (rtx-const-list-equal maybe-const number-list invert?)
+ (assert (rtx-kind? 'number-list number-list))
+ (if (rtx-constant? maybe-const)
+ (let ((values (rtx-number-list-values number-list)))
+ (if invert?
+ (if (memq (rtx-constant-value maybe-const) values)
+ (if (= (length values) 1)
+ #f
+ 'member)
+ #t)
+ (if (memq (rtx-constant-value maybe-const) values)
+ (if (= (length values) 1)
+ #t
+ 'member)
+ #f)))
+ 'unknown)
+)
+
+; Subroutine of -simplify-expr-fn to simplify an eq-attr of (current-mach).
+; CONTEXT is a <context> object or #f if there is none.
+
+(define (rtx-simplify-eq-attr-mach rtx context)
+ (let ((attr (rtx-eq-attr-attr rtx))
+ (value (rtx-eq-attr-value rtx)))
+ ; If all currently selected machs will yield the same value
+ ; for the attribute, we can simplify.
+ (let ((values (map (lambda (m)
+ (obj-attr-value m attr))
+ (current-mach-list))))
+ ; Ensure at least one mach is selected.
+ (if (null? values)
+ (context-error context "rtx simplification, no machs selected"
+ (rtx-strdump rtx)))
+ ; All values equal to the first one?
+ (if (all-true? (map (lambda (val)
+ (equal? val (car values)))
+ values))
+ (if (equal? value
+ ; Convert internal boolean attribute value
+ ; #f/#t to external value FALSE/TRUE.
+ ; FIXME:revisit.
+ (case (car values)
+ ((#f) 'FALSE)
+ ((#t) 'TRUE)
+ (else (car values))))
+ (rtx-true)
+ (rtx-false))
+ ; couldn't simplify
+ rtx)))
+)
+
+; Subroutine of -simplify-expr-fn to simplify an eq-attr of (current-insn).
+
+(define (rtx-simplify-eq-attr-insn rtx insn context)
+ (let ((attr (rtx-eq-attr-attr rtx))
+ (value (rtx-eq-attr-value rtx)))
+ (if (not (insn? insn))
+ (context-error context
+ "No current insn for `(current-insn)'"
+ (rtx-strdump rtx)))
+ (let ((attr-value (obj-attr-value insn attr)))
+ (if (eq? value attr-value)
+ (rtx-true)
+ (rtx-false))))
+)
+
+; Subroutine of rtx-simplify.
+; This is the EXPR-FN argument to rtx-traverse.
+
+(define (-simplify-expr-fn rtx-obj expr mode parent-expr op-pos tstate appstuff)
+
+ ;(display "Processing ") (display (rtx-dump expr)) (newline)
+
+ (case (rtx-name expr)
+
+ ((not)
+ (let* ((arg (-rtx-traverse (rtx-alu-op-arg expr 0)
+ 'RTX
+ (rtx-alu-op-mode expr)
+ expr 1 tstate appstuff))
+ (no-side-effects? (not (rtx-side-effects? arg))))
+ (cond ((and no-side-effects? (rtx-false? arg))
+ (rtx-true))
+ ((and no-side-effects? (rtx-true? arg))
+ (rtx-false))
+ (else (rtx-make 'not (rtx-alu-op-mode expr) arg)))))
+
+ ((orif)
+ (let ((arg0 (-rtx-traverse (rtx-boolif-op-arg expr 0)
+ 'RTX 'DFLT expr 0 tstate appstuff))
+ (arg1 (-rtx-traverse (rtx-boolif-op-arg expr 1)
+ 'RTX 'DFLT expr 1 tstate appstuff)))
+ (let ((no-side-effects-0? (not (rtx-side-effects? arg0)))
+ (no-side-effects-1? (not (rtx-side-effects? arg1))))
+ (cond ((and no-side-effects-0? (rtx-true? arg0))
+ (rtx-true))
+ ((and no-side-effects-0? (rtx-false? arg0))
+ (rtx-canonical-bool arg1))
+ ; Value of arg0 is unknown or has side-effects.
+ ((and no-side-effects-1? (rtx-true? arg1))
+ (if no-side-effects-0?
+ (rtx-true)
+ (rtx-make 'orif arg0 (rtx-true))))
+ ((and no-side-effects-1? (rtx-false? arg1))
+ arg0)
+ (else
+ (rtx-make 'orif arg0 arg1))))))
+
+ ((andif)
+ (let ((arg0 (-rtx-traverse (rtx-boolif-op-arg expr 0)
+ 'RTX 'DFLT expr 0 tstate appstuff))
+ (arg1 (-rtx-traverse (rtx-boolif-op-arg expr 1)
+ 'RTX 'DFLT expr 1 tstate appstuff)))
+ (let ((no-side-effects-0? (not (rtx-side-effects? arg0)))
+ (no-side-effects-1? (not (rtx-side-effects? arg1))))
+ (cond ((and no-side-effects-0? (rtx-false? arg0))
+ (rtx-false))
+ ((and no-side-effects-0? (rtx-true? arg0))
+ (rtx-canonical-bool arg1))
+ ; Value of arg0 is unknown or has side-effects.
+ ((and no-side-effects-1? (rtx-false? arg1))
+ (if no-side-effects-0?
+ (rtx-false)
+ (rtx-make 'andif arg0 (rtx-false))))
+ ((and no-side-effects-1? (rtx-true? arg1))
+ arg0)
+ (else
+ (rtx-make 'andif arg0 arg1))))))
+
+ ; Fold if's to their then or else part if we can determine the
+ ; result of the test.
+ ((if)
+ (let ((test
+ ; ??? Was this but that calls rtx-traverse again which
+ ; resets the temp stack!
+ ; (rtx-simplify context (caddr expr))))
+ (-rtx-traverse (rtx-if-test expr) 'RTX 'DFLT expr 1 tstate appstuff)))
+ (cond ((rtx-true? test)
+ (-rtx-traverse (rtx-if-then expr) 'RTX mode expr 2 tstate appstuff))
+ ((rtx-false? test)
+ (if (rtx-if-else expr)
+ (-rtx-traverse (rtx-if-else expr) 'RTX mode expr 3 tstate appstuff)
+ ; Sanity check, mode must be VOID.
+ (if (or (mode:eq? 'DFLT (rtx-mode expr))
+ (mode:eq? 'VOID (rtx-mode expr)))
+ (rtx-make 'nop)
+ (error "rtx-simplify: non-void-mode `if' missing `else' part" expr))))
+ ; Can't simplify.
+ ; We could traverse the then/else clauses here, but it's simpler
+ ; to have our caller do it. The cost is retraversing `test'.
+ (else #f))))
+
+ ((eq ne)
+ (let ((name (rtx-name expr))
+ (cmp-mode (rtx-cmp-op-mode expr))
+ (arg0 (-rtx-traverse (rtx-cmp-op-arg expr 0) 'RTX
+ (rtx-cmp-op-mode expr)
+ expr 1 tstate appstuff))
+ (arg1 (-rtx-traverse (rtx-cmp-op-arg expr 1) 'RTX
+ (rtx-cmp-op-mode expr)
+ expr 2 tstate appstuff)))
+ (if (or (rtx-side-effects? arg0) (rtx-side-effects? arg1))
+ (rtx-make name cmp-mode arg0 arg1)
+ (case (rtx-const-equal arg0 arg1 (rtx-kind? 'ne expr))
+ ((#f) (rtx-false))
+ ((#t) (rtx-true))
+ (else
+ ; That didn't work. See if we have an ifield/operand with a
+ ; known range of values.
+ (case (rtx-name arg0)
+ ((ifield)
+ (let ((known-val (tstate-known-lookup tstate
+ (rtx-ifield-name arg0))))
+ (if (and known-val (rtx-kind? 'number-list known-val))
+ (case (rtx-const-list-equal arg1 known-val (rtx-kind? 'ne expr))
+ ((#f) (rtx-false))
+ ((#t) (rtx-true))
+ (else
+ (rtx-make name cmp-mode arg0 arg1)))
+ (rtx-make name cmp-mode arg0 arg1))))
+ ((operand)
+ (let ((known-val (tstate-known-lookup tstate
+ (rtx-operand-name arg0))))
+ (if (and known-val (rtx-kind? 'number-list known-val))
+ (case (rtx-const-list-equal arg1 known-val (rtx-kind? 'ne expr))
+ ((#f) (rtx-false))
+ ((#t) (rtx-true))
+ (else
+ (rtx-make name cmp-mode arg0 arg1)))
+ (rtx-make name cmp-mode arg0 arg1))))
+ (else
+ (rtx-make name cmp-mode arg0 arg1))))))))
+
+ ; Recognize attribute requests of current-insn, current-mach.
+ ((eq-attr)
+ (cond ((rtx-kind? 'current-mach (rtx-eq-attr-owner expr))
+ (rtx-simplify-eq-attr-mach expr (tstate-context tstate)))
+ ((rtx-kind? 'current-insn (rtx-eq-attr-owner expr))
+ (rtx-simplify-eq-attr-insn expr (tstate-owner tstate) (tstate-context tstate)))
+ (else expr)))
+
+ ((ifield)
+ (let ((known-val (tstate-known-lookup tstate (rtx-ifield-name expr))))
+ ; If the value is a single number, return that.
+ ; It can be one of several, represented as a number list.
+ (if (and known-val (rtx-constant? known-val))
+ known-val ; (rtx-make 'const 'INT known-val)
+ #f)))
+
+ ((operand)
+ (let ((known-val (tstate-known-lookup tstate (rtx-operand-name expr))))
+ ; If the value is a single number, return that.
+ ; It can be one of several, represented as a number list.
+ (if (and known-val (rtx-constant? known-val))
+ known-val ; (rtx-make 'const 'INT known-val)
+ #f)))
+
+ ; Leave EXPR unchanged and continue.
+ (else #f))
+)
+
+; Simplify an rtl expresion.
+; EXPR must be in source form.
+; The result is a possibly simplified EXPR, still in source form.
+;
+; CONTEXT is a <context> object, used for error messages.
+; OWNER is the owner of the expression (e.g. <insn>) or #f if there is none.
+;
+; KNOWN is an alist of known values. Each element is (name . value) where
+; NAME is an ifield/operand name and VALUE is a const/number-list rtx.
+; FIXME: Need ranges, later.
+;
+; The following operations are performed:
+; - unselected machine dependent code is removed (eq-attr of (current-mach))
+; - if's are reduced to either then/else if we can determine that the test is
+; a compile-time constant
+; - orif/andif
+; - eq/ne
+; - not
+;
+; ??? Will become more intelligent as needed.
+
+(define (rtx-simplify context owner expr known)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context owner
+ (/fastcall-make -simplify-expr-fn)
+ (rtx-env-empty-stack)
+ #f #f known 0)
+ #f)
+)
+
+; Utilities for equation solving.
+; ??? At the moment this is only focused on ifield assertions.
+; ??? That there exist more sophisticated versions than this one can take
+; as a given. This works for the task at hand and will evolve or be replaced
+; as necessary.
+; ??? This makes the simplifying assumption that no expr has side-effects.
+
+; Subroutine of rtx-solve.
+; This is the EXPR-FN argument to rtx-traverse.
+
+(define (-solve-expr-fn rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ #f ; wip
+)
+
+; Return a boolean indicating if {expr} equates to "true".
+; If the expression can't be reduced to #f/#t, return '?.
+; ??? Use rtx-eval instead of rtx-traverse?
+;
+; EXPR must be in source form.
+; CONTEXT is a <context> object, used for error messages.
+; OWNER is the owner of the expression (e.g. <insn>) or #f if there is none.
+; KNOWN is an alist of known values. Each element is (name . value) where
+; NAME is an ifield/operand name and VALUE is a const/number-list rtx.
+; FIXME: Need ranges, later.
+;
+; This is akin to rtx-simplify except it's geared towards solving ifield
+; assertions. It's not unreasonable to combine them. The worry is the
+; efficiency lost.
+; ??? Will become more intelligent as needed.
+
+(define (rtx-solve context owner expr known)
+ ; First simplify, then solve.
+ (let* ((simplified-expr (rtx-simplify context owner expr known))
+ (maybe-solved-expr
+ simplified-expr) ; FIXME: for now
+; (-rtx-traverse simplified-expr #f 'DFLT #f 0
+; (tstate-make context owner
+; (/fastcall-make -solve-expr-fn)
+; (rtx-env-empty-stack)
+; #f #f known 0)
+; #f))
+ )
+ (cond ((rtx-true? maybe-solved-expr) #t)
+ ((rtx-false? maybe-solved-expr) #f)
+ (else '?)))
+)
+
+; Subroutine of -rtx-find-op to determine if two modes are equivalent.
+; Two modes are equivalent if they're equal, or if their sem-mode fields
+; are equal.
+
+(define (-rtx-mode-equiv? m1 m2)
+ (or (eq? m1 m2)
+ (let ((mode1 (mode:lookup m1))
+ (mode2 (mode:lookup m2)))
+ (let ((s1 (mode:sem-mode mode1))
+ (s2 (mode:sem-mode mode2)))
+ (eq? (if s1 (obj:name s1) m1) (if s2 (obj:name s2) m2)))))
+)
+
+; Subroutine of semantic-compile to find OP in OP-LIST.
+; OP-LIST is a list of operand expressions: (type expr mode name indx-sel).
+; The result is the list element or #f if not found.
+; TYPE is one of -op- reg mem.
+; EXPR is the constructed `xop' rtx expression for the operand,
+; ignored in the search.
+; MODE must match, as defined by -rtx-mode-equiv?.
+; NAME is the hardware element name, ifield name, or '-op-'.
+; INDX-SEL must match if present in either.
+;
+; ??? Does this need to take "conditionally-referenced" into account?
+
+(define (-rtx-find-op op op-list)
+ (let ((type (car op))
+ (mode (caddr op))
+ (name (cadddr op))
+ (indx-sel (car (cddddr op))))
+ ; The first cdr is to drop the dummy first arg.
+ (let loop ((op-list (cdr op-list)))
+ (cond ((null? op-list) #f)
+ ((eq? type (caar op-list))
+ (let ((try (car op-list)))
+ (if (and (eq? name (cadddr try))
+ (-rtx-mode-equiv? mode (caddr try))
+ (equal? indx-sel (car (cddddr try))))
+ try
+ (loop (cdr op-list)))))
+ (else (loop (cdr op-list))))))
+)
+
+; Subroutine of semantic-compile to determine how the operand in
+; position OP-POS of EXPR is used.
+; The result is one of 'use, 'set, 'set-quiet.
+; "use" means "input operand".
+
+(define (-rtx-ref-type expr op-pos)
+ ; operand 0 is the option list, operand 1 is the mode
+ ; (if you want to complain, fine, it's not like it would be unexpected)
+ (if (= op-pos 2)
+ (case (car expr)
+ ((set) 'set)
+ ((set-quiet clobber) 'set-quiet)
+ (else 'use))
+ 'use)
+)
+
+; Subroutine of semantic-compile:process-expr!, to simplify it.
+; Looks up the operand in the current set, returns it if found,
+; otherwise adds it.
+; REF-TYPE is one of 'use, 'set, 'set-quiet.
+; Adds COND-CTI/UNCOND-CTI to SEM-ATTRS if the operand is a set of the pc.
+
+(define (-build-operand! op-name op mode tstate ref-type op-list sem-attrs)
+ ;(display (list op-name mode ref-type)) (newline) (force-output)
+ (let* ((mode (mode-real-name (if (eq? mode 'DFLT)
+ (op:mode op)
+ mode)))
+ ; The first #f is a placeholder for the object.
+ (try (list '-op- #f mode op-name #f))
+ (existing-op (-rtx-find-op try op-list)))
+
+ (if (and (pc? op)
+ (memq ref-type '(set set-quiet)))
+ (append! sem-attrs
+ (list (if (tstate-cond? tstate) 'COND-CTI 'UNCOND-CTI))))
+
+ ; If already present, return the object, otherwise add it.
+ (if existing-op
+
+ (cadr existing-op)
+
+ ; We can't set the operand number yet 'cus we don't know it.
+ ; However, when it's computed we'll need to set all associated
+ ; operands. This is done by creating shared rtx (a la gcc) - the
+ ; operand number then need only be updated in one place.
+
+ (let ((xop (op:new-mode op mode)))
+ (op:set-cond?! xop (tstate-cond? tstate))
+ ; Set the object rtx in `try', now that we have it.
+ (set-car! (cdr try) (rtx-make 'xop xop))
+ ; Add the operand to in/out-ops.
+ (append! op-list (list try))
+ (cadr try))))
+)
+
+; Subroutine of semantic-compile:process-expr!, to simplify it.
+
+(define (-build-reg-operand! expr tstate op-list)
+ (let* ((hw-name (rtx-reg-name expr))
+ (hw (current-hw-sem-lookup-1 hw-name)))
+
+ (if hw
+ ; If the mode is DFLT, use the object's natural mode.
+ (let* ((mode (mode-real-name (if (eq? (rtx-mode expr) 'DFLT)
+ (obj:name (hw-mode hw))
+ (rtx-mode expr))))
+ (indx-sel (rtx-reg-index-sel expr))
+ ; #f is a place-holder for the object (filled in later)
+ (try (list 'reg #f mode hw-name indx-sel))
+ (existing-op (-rtx-find-op try op-list)))
+
+ ; If already present, return the object, otherwise add it.
+ (if existing-op
+
+ (cadr existing-op)
+
+ (let ((xop (apply reg (cons (tstate->estate tstate)
+ (cons mode
+ (cons hw-name indx-sel))))))
+ (op:set-cond?! xop (tstate-cond? tstate))
+ ; Set the object rtx in `try', now that we have it.
+ (set-car! (cdr try) (rtx-make 'xop xop))
+ ; Add the operand to in/out-ops.
+ (append! op-list (list try))
+ (cadr try))))
+
+ (parse-error "FIXME" "unknown reg" expr)))
+)
+
+; Subroutine of semantic-compile:process-expr!, to simplify it.
+
+(define (-build-mem-operand! expr tstate op-list)
+ (let ((mode (rtx-mode expr))
+ (indx-sel (rtx-mem-index-sel expr)))
+
+ (if (memq mode '(DFLT VOID))
+ (parse-error "FIXME" "memory must have explicit mode" expr))
+
+ (let* ((try (list 'mem #f mode 'h-memory indx-sel))
+ (existing-op (-rtx-find-op try op-list)))
+
+ ; If already present, return the object, otherwise add it.
+ (if existing-op
+
+ (cadr existing-op)
+
+ (let ((xop (apply mem (cons (tstate->estate tstate)
+ (cons mode indx-sel)))))
+ (op:set-cond?! xop (tstate-cond? tstate))
+ ; Set the object in `try', now that we have it.
+ (set-car! (cdr try) (rtx-make 'xop xop))
+ ; Add the operand to in/out-ops.
+ (append! op-list (list try))
+ (cadr try)))))
+)
+
+; Subroutine of semantic-compile:process-expr!, to simplify it.
+
+(define (-build-ifield-operand! expr tstate op-list)
+ (let* ((f-name (rtx-ifield-name expr))
+ (f (current-ifld-lookup f-name)))
+
+ (if (not f)
+ (parse-error "FIXME" "unknown ifield" f-name))
+
+ (let* ((mode (obj:name (ifld-mode f)))
+ (try (list '-op- #f mode f-name #f))
+ (existing-op (-rtx-find-op try op-list)))
+
+ ; If already present, return the object, otherwise add it.
+ (if existing-op
+
+ (cadr existing-op)
+
+ (let ((xop (make <operand> f-name f-name
+ (atlist-cons (bool-attr-make 'SEM-ONLY #t)
+ (obj-atlist f))
+ (obj:name (ifld-hw-type f))
+ mode
+ (make <hw-index> 'anonymous
+ 'ifield (ifld-mode f) f)
+ nil #f #f)))
+ (set-car! (cdr try) (rtx-make 'xop xop))
+ (append! op-list (list try))
+ (cadr try)))))
+)
+
+; Subroutine of semantic-compile:process-expr!, to simplify it.
+;
+; ??? There are various optimizations (both space usage in ARGBUF and time
+; spent in semantic code) that can be done on code that uses index-of
+; (see i960's movq insn). Later.
+
+(define (-build-index-of-operand! expr tstate op-list)
+ (if (not (and (rtx? (rtx-index-of-value expr))
+ (rtx-kind? 'operand (rtx-index-of-value expr))))
+ (parse-error "FIXME" "only `(index-of operand)' is currently supported"
+ expr))
+
+ (let ((op (rtx-operand-obj (rtx-index-of-value expr))))
+ (let ((indx (op:index op)))
+ (if (not (eq? (hw-index:type indx) 'ifield))
+ (parse-error "FIXME" "only ifield indices are currently supported"
+ expr))
+ (let* ((f (hw-index:value indx))
+ (f-name (obj:name f)))
+ ; The rest of this is identical to -build-ifield-operand!.
+ (let* ((mode (obj:name (ifld-mode f)))
+ (try (list '-op- #f mode f-name #f))
+ (existing-op (-rtx-find-op try op-list)))
+
+ ; If already present, return the object, otherwise add it.
+ (if existing-op
+
+ (cadr existing-op)
+
+ (let ((xop (make <operand> f-name f-name
+ (atlist-cons (bool-attr-make 'SEM-ONLY #t)
+ (obj-atlist f))
+ (obj:name (ifld-hw-type f))
+ mode
+ (make <hw-index> 'anonymous
+ 'ifield
+ (ifld-mode f)
+ ; (send (op:type op) 'get-index-mode)
+ f)
+ nil #f #f)))
+ (set-car! (cdr try) (rtx-make 'xop xop))
+ (append! op-list (list try))
+ (cadr try)))))))
+)
+
+; Build the tstate known value list for INSN.
+; This built from the ifield-assertion list.
+
+(define (-build-known-values insn)
+ (let ((expr (insn-ifield-assertion insn)))
+ (if expr
+ (case (rtx-name expr)
+ ((eq)
+ (if (and (rtx-kind? 'ifield (rtx-cmp-op-arg expr 0))
+ (rtx-constant? (rtx-cmp-op-arg expr 1)))
+ (list (cons (rtx-ifield-name (rtx-cmp-op-arg expr 0))
+ (rtx-cmp-op-arg expr 1)))
+ nil))
+ ((member)
+ (if (rtx-kind? 'ifield (rtx-member-value expr))
+ (list (cons (rtx-ifield-name (rtx-member-value expr))
+ (rtx-member-set expr)))
+ nil))
+ (else nil))
+ nil))
+)
+
+; Structure to record the result of semantic-compile.
+
+(define (csem-make compiled-code inputs outputs attributes)
+ (vector compiled-code inputs outputs attributes)
+)
+
+; Accessors.
+
+(define (csem-code csem) (vector-ref csem 0))
+(define (csem-inputs csem) (vector-ref csem 1))
+(define (csem-outputs csem) (vector-ref csem 2))
+(define (csem-attrs csem) (vector-ref csem 3))
+
+; Traverse each element in SEM-CODE-LIST, converting them to canonical form,
+; and computing the input and output operands.
+; The result is an object of four elements (built with csem-make).
+; The first is a list of the canonical form of each element in SEM-CODE-LIST:
+; operand and ifield elements specified without `operand' or `ifield' have it
+; prepended, and operand numbers are computed for each operand.
+; Operand numbers are needed when emitting "write" handlers for LIW cpus.
+; Having the operand numbers available is also useful for efficient
+; modeling: recording operand references can be done with a bitmask (one host
+; insn), and the code to do the modeling can be kept out of the code that
+; performs the insn.
+; The second is the list of input <operand> objects.
+; The third is the list of output <operand> objects.
+; The fourth is an <attr-list> object of attributes that can be computed from
+; the semantics.
+; The possibilities are: UNCOND-CTI, COND-CTI, SKIP-CTI, DELAY-SLOT.
+; ??? Combine *-CTI into an enum attribute.
+;
+; CONTEXT is a <context> object or #f if there is none.
+; INSN is the <insn> object.
+;
+; ??? Specifying operand ordinals in the source would simplify this and speed
+; it up. On the other hand that makes the source form more complex. Maybe the
+; complexity will prove necessary, but following the goal of "incremental
+; complication", we don't do this yet.
+; Another way to simplify this and speed it up would be to add lists of
+; input/output operands to the instruction description.
+;
+; ??? This calls rtx-simplify which calls rtx-traverse as it's simpler to
+; simplify EXPR first, and then compile it. On the other hand it's slower
+; (two calls to rtx-traverse!).
+
+(define (semantic-compile context insn sem-code-list)
+ (for-each (lambda (rtx) (assert (rtx? rtx)))
+ sem-code-list)
+
+ (let*
+ ; String for error messages.
+ ((errtxt "semantic compilation")
+
+ ; These record the result of traversing SEM-CODE-LIST.
+ ; They're lists of (type object mode name [args ...]).
+ ; TYPE is one of: -op- reg mem.
+ ; `-op-' is just something unique and is only used internally.
+ ; OBJECT is the constructed <operand> object.
+ ; The first element is just a dummy so that append! always works.
+ (in-ops (list (list #f)))
+ (out-ops (list (list #f)))
+
+ ; List of attributes computed from SEM-CODE-LIST.
+ ; The first element is just a dummy so that append! always works.
+ (sem-attrs (list #f))
+
+ ; Called for expressions encountered in SEM-CODE-LIST.
+ ; Don't waste cpu here, this is part of the slowest piece in CGEN.
+ (process-expr!
+ (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (case (car expr)
+
+ ; Registers.
+ ((reg) (let ((ref-type (-rtx-ref-type parent-expr op-pos))
+ ; ??? could verify reg is a scalar
+ (regno (or (rtx-reg-number expr) 0)))
+ ; The register number is either a number or an
+ ; expression.
+ ; ??? This is a departure from GCC RTL that might have
+ ; significant ramifications. On the other hand in cases
+ ; where it matters the expression could always be
+ ; required to reduce to a constant (or some such).
+ (cond ((number? regno) #t)
+ ((form? regno)
+ (rtx-traverse-operands rtx-obj expr tstate appstuff))
+ (else (parse-error errtxt
+ "invalid register number"
+ regno)))
+ (-build-reg-operand! expr tstate
+ (if (eq? ref-type 'use)
+ in-ops
+ out-ops))))
+
+ ; Memory.
+ ((mem) (let ((ref-type (-rtx-ref-type parent-expr op-pos)))
+ (rtx-traverse-operands rtx-obj expr tstate appstuff)
+ (-build-mem-operand! expr tstate
+ (if (eq? ref-type 'use)
+ in-ops
+ out-ops))))
+
+ ; Operands.
+ ((operand) (let ((op (rtx-operand-obj expr))
+ (ref-type (-rtx-ref-type parent-expr op-pos)))
+ (-build-operand! (obj:name op) op mode tstate ref-type
+ (if (eq? ref-type 'use)
+ in-ops
+ out-ops)
+ sem-attrs)))
+
+ ; Give operand new name.
+ ((name) (let ((result (-rtx-traverse (caddr expr) 'RTX mode
+ parent-expr op-pos tstate appstuff)))
+ (if (not (operand? result))
+ (error "name: invalid argument:" expr result))
+ (op:set-sem-name! result (cadr expr))
+ ; (op:set-num! result (caddr expr))
+ result))
+
+ ; Specify a reference to a local variable
+ ((local) expr) ; nothing to do
+
+ ; Instruction fields.
+ ((ifield) (let ((ref-type (-rtx-ref-type parent-expr op-pos)))
+ (if (not (eq? ref-type 'use))
+ (parse-error errtxt "can't set an `ifield'" expr))
+ (-build-ifield-operand! expr tstate in-ops)))
+
+ ; Hardware indices.
+ ; For registers this is the register number.
+ ; For memory this is the address.
+ ; For constants, this is the constant.
+ ((index-of) (let ((ref-type (-rtx-ref-type parent-expr op-pos)))
+ (if (not (eq? ref-type 'use))
+ (parse-error errtxt "can't set an `index-of'" expr))
+ (-build-index-of-operand! expr tstate in-ops)))
+
+ ; Machine generate the SKIP-CTI attribute.
+ ((skip) (append! sem-attrs (list 'SKIP-CTI)) #f)
+
+ ; Machine generate the DELAY-SLOT attribute.
+ ((delay) (append! sem-attrs (list 'DELAY-SLOT)) #f)
+
+ ; If this is a syntax expression, the operands won't have been
+ ; processed, so tell our caller we want it to by returning #f.
+ ; We do the same for non-syntax expressions to keep things
+ ; simple. This requires collaboration with the traversal
+ ; handlers which are defined to do what we want if we return #f.
+ (else #f))))
+
+ ; Whew. We're now ready to traverse the expression.
+ ; Traverse the expression recording the operands and building objects
+ ; for most elements in the source representation.
+ ; This also performs various simplifications.
+ ; In particular machine dependent code for non-selected machines
+ ; is discarded.
+ (compiled-exprs (map (lambda (expr)
+ (rtx-traverse
+ context
+ insn
+ (rtx-simplify context insn expr
+ (-build-known-values insn))
+ process-expr!
+ #f))
+ sem-code-list))
+ )
+
+ ;(display "in: ") (display in-ops) (newline)
+ ;(display "out: ") (display out-ops) (newline)
+ ;(force-output)
+
+ ; Now that we have the nub of all input and output operands,
+ ; we can assign operand numbers. Inputs and outputs are not defined
+ ; separately, output operand numbers follow inputs. This simplifies the
+ ; code which keeps track of such things: it can use one variable.
+ ; The assignment is defined to be arbitrary. If there comes a day
+ ; when we need to prespecify operand numbers, revisit.
+ ; The operand lists are sorted to avoid spurious differences in generated
+ ; code (for example unnecessary extra entries can be created in the
+ ; ARGBUF struct).
+
+ ; Drop dummy first arg and sort operand lists.
+ (let ((sorted-ins
+ (sort (map (lambda (op)
+ (rtx-xop-obj (cadr op)))
+ (cdr in-ops))
+ (lambda (a b) (string<? (obj:name a) (obj:name b)))))
+ (sorted-outs
+ (sort (map (lambda (op)
+ (rtx-xop-obj (cadr op)))
+ (cdr out-ops))
+ (lambda (a b) (string<? (obj:name a) (obj:name b)))))
+ (sem-attrs (cdr sem-attrs)))
+
+ (let ((in-op-nums (iota (length sorted-ins)))
+ (out-op-nums (iota (length sorted-ins) (length sorted-outs))))
+
+ (for-each (lambda (op num) (op:set-num! op num))
+ sorted-ins in-op-nums)
+ (for-each (lambda (op num) (op:set-num! op num))
+ sorted-outs out-op-nums)
+
+ (let ((dump (lambda (op)
+ (string-append " "
+ (obj:name op)
+ " "
+ (number->string (op:num op))
+ "\n"))))
+ (logit 4
+ "Input operands:\n"
+ (map dump sorted-ins)
+ "Output operands:\n"
+ (map dump sorted-outs)
+ "End of operands.\n"))
+
+ (csem-make compiled-exprs sorted-ins sorted-outs
+ (atlist-parse sem-attrs "" "semantic attributes")))))
+)
+
+; Traverse SEM-CODE-LIST, computing attributes derivable from it.
+; The result is an <attr-list> object of attributes that can be computed from
+; the semantics.
+; The possibilities are: UNCOND-CTI, COND-CTI, SKIP-CTI, DELAY-SLOT.
+; This computes the same values as semantic-compile, but for speed is
+; focused on attributes only.
+; ??? Combine *-CTI into an enum attribute.
+;
+; CONTEXT is a <context> object or #f if there is none.
+; INSN is the <insn> object.
+
+(define (semantic-attrs context insn sem-code-list)
+ (for-each (lambda (rtx) (assert (rtx? rtx)))
+ sem-code-list)
+
+ (let*
+ ; String for error messages.
+ ((errtxt "semantic attribute computation")
+
+ ; List of attributes computed from SEM-CODE-LIST.
+ ; The first element is just a dummy so that append! always works.
+ (sem-attrs (list #f))
+
+ ; Called for expressions encountered in SEM-CODE-LIST.
+ (process-expr!
+ (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (case (car expr)
+
+ ((operand) (if (and (eq? 'pc (obj:name (rtx-operand-obj expr)))
+ (memq (-rtx-ref-type parent-expr op-pos)
+ '(set set-quiet)))
+ (append! sem-attrs
+ (if (tstate-cond? tstate)
+ ; Don't change these to '(FOO), since
+ ; we use append!.
+ (list 'COND-CTI)
+ (list 'UNCOND-CTI)))))
+ ((skip) (append! sem-attrs (list 'SKIP-CTI)) #f)
+ ((delay) (append! sem-attrs (list 'DELAY-SLOT)) #f)
+
+ ; If this is a syntax expression, the operands won't have been
+ ; processed, so tell our caller we want it to by returning #f.
+ ; We do the same for non-syntax expressions to keep things
+ ; simple. This requires collaboration with the traversal
+ ; handlers which are defined to do what we want if we return #f.
+ (else #f))))
+
+ ; Traverse the expression recording the attributes.
+ (traversed-exprs (map (lambda (expr)
+ (rtx-traverse
+ context
+ insn
+ (rtx-simplify context insn expr
+ (-build-known-values insn))
+ process-expr!
+ #f))
+ sem-code-list))
+ )
+
+ (let
+ ; Drop dummy first arg.
+ ((sem-attrs (cdr sem-attrs)))
+ (atlist-parse sem-attrs "" "semantic attributes")))
+)
diff --git a/cgen/sim-arch.scm b/cgen/sim-arch.scm
new file mode 100644
index 00000000000..394f68cef6c
--- /dev/null
+++ b/cgen/sim-arch.scm
@@ -0,0 +1,181 @@
+; Simulator generator support routines.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Utilities of cgen-arch.h.
+
+; Return C macro definitions of the various supported cpus.
+
+(define (-gen-cpuall-defines)
+ "" ; nothing yet
+)
+
+; Return C declarations of misc. support stuff.
+; ??? Modes are now defined in sim/common/cgen-types.h but we will need
+; target specific modes.
+
+(define (-gen-support-decls)
+ (string-append
+; (gen-enum-decl 'mode_type "mode types"
+; "MODE_"
+; ; Aliases are not distinct from their real mode so ignore
+; ; them here.
+; (append (map list (map obj:name
+; (mode-list-non-alias-values)))
+; '((max))))
+; "#define MAX_MODES ((int) MODE_MAX)\n\n"
+ )
+)
+
+; Utilities of cgen-cpuall.h.
+
+; Subroutine of -gen-cpuall-includes.
+
+(define (-gen-cpu-header cpu prefix)
+ (string-append "#include \"" prefix (cpu-file-transform cpu) ".h\"\n")
+)
+
+; Return C code to include all the relevant headers for each cpu family,
+; conditioned on ifdef WANT_CPU_@CPU@.
+
+(define (-gen-cpuall-includes)
+ (string-list
+ "/* Include files for each cpu family. */\n\n"
+ (string-list-map (lambda (cpu)
+ (let* ((cpu-name (gen-sym cpu))
+ (CPU-NAME (string-upcase cpu-name)))
+ (string-list "#ifdef WANT_CPU_" CPU-NAME "\n"
+ (-gen-cpu-header cpu "eng")
+ "#include \"cgen-engine.h\"\n"
+ (-gen-cpu-header cpu "cpu")
+ ; FIXME: Shorten "decode" to "dec".
+ (-gen-cpu-header cpu "decode")
+ "#endif\n\n")))
+ (current-cpu-list))
+ )
+)
+
+; Subroutine of -gen-cpuall-decls to generate cpu-specific structure entries.
+; The result is "struct <cpu>_<type-name> <member-name>;".
+; INDENT is the amount to indent by.
+; CPU is the cpu object.
+
+(define (-gen-cpu-specific-decl indent cpu type-name member-name)
+ (let* ((cpu-name (gen-sym cpu))
+ (CPU-NAME (string-upcase cpu-name)))
+ (string-append
+ "#ifdef WANT_CPU_" CPU-NAME "\n"
+ (spaces indent)
+ "struct " cpu-name "_" type-name " " member-name ";\n"
+ "#endif\n"))
+)
+
+; Return C declarations of cpu-specific structs.
+; These are defined here to achieve a simple and moderately type-safe
+; inheritance. In the non-cpu-specific files, these structs consist of
+; just the baseclass. In cpu-specific files, the baseclass is augmented
+; with the cpu-specific data.
+
+(define (-gen-cpuall-decls)
+ (string-list
+ (gen-argbuf-type #f)
+ (gen-scache-type #f)
+ )
+)
+
+; Top level generators for non-cpu-specific files.
+
+; Generate arch.h
+; This file defines non cpu family specific data about the architecture
+; and also data structures that combine all variants (e.g. cpu struct).
+; It is intended to be included before sim-basics.h and sim-base.h.
+
+(define (cgen-arch.h)
+ (logit 1 "Generating arch.h ...\n")
+
+ (string-write
+ (gen-copyright "Simulator header for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "#ifndef @ARCH@_ARCH_H\n"
+ "#define @ARCH@_ARCH_H\n"
+ "\n"
+ "#define TARGET_BIG_ENDIAN 1\n\n" ; FIXME
+ ;(gen-mem-macros)
+ ;"/* FIXME: split into 32/64 parts */\n"
+ ;"#define WI SI\n"
+ ;"#define UWI USI\n"
+ ;"#define AI USI\n\n"
+ -gen-cpuall-defines
+ -gen-support-decls
+ -gen-arch-model-decls
+ "#endif /* @ARCH@_ARCH_H */\n"
+ )
+)
+
+; Generate arch.c
+; This file defines non cpu family specific data about the architecture.
+
+(define (cgen-arch.c)
+ (logit 1 "Generating arch.c ...\n")
+
+ (string-write
+ (gen-copyright "Simulator support for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#include \"sim-main.h\"
+#include \"bfd.h\"
+
+"
+ -gen-mach-data
+ )
+)
+
+; Generate cpuall.h
+; This file pulls together all of the cpu variants .h's.
+; It is intended to be included after sim-base.h/cgen-sim.h.
+
+(define (cgen-cpuall.h)
+ (logit 1 "Generating cpuall.h ...\n")
+
+ (string-write
+ (gen-copyright "Simulator CPU header for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "#ifndef @ARCH@_CPUALL_H\n"
+ "#define @ARCH@_CPUALL_H\n"
+ "\n"
+ -gen-cpuall-includes
+ -gen-mach-decls
+ -gen-cpuall-decls
+ "#endif /* @ARCH@_CPUALL_H */\n"
+ )
+)
+
+; Generate ops.c
+; No longer used.
+
+(define (cgen-ops.c)
+ (logit 1 "Generating ops.c ...\n")
+
+ (string-write
+ (gen-copyright "Simulator operational support for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#define MEMOPS_DEFINE_INLINE
+
+#include \"config.h\"
+#include <signal.h>
+#include \"ansidecl.h\"
+#include \"bfd.h\"
+#include \"tconfig.h\"
+#include \"cgen-sim.h\"
+#include \"memops.h\"
+
+/* FIXME: wip */
+int pow2masks[] = {
+ 0, 0, 1, -1, 3, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, 15
+};
+
+"
+ gen-mode-defs
+ )
+)
diff --git a/cgen/sim-cpu.scm b/cgen/sim-cpu.scm
new file mode 100644
index 00000000000..a8e50ba38b8
--- /dev/null
+++ b/cgen/sim-cpu.scm
@@ -0,0 +1,1231 @@
+; CPU family related simulator generator, excluding decoding and model support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Notes:
+; - Add support to generate copies of semantic code and perform constant
+; folding based on selected mach. This would collapse out untaken branches
+; of tests on (current-mach).
+
+; Utilities of cgen-cpu.h.
+
+; Print various parameters of the cpu family.
+; A "cpu family" here is a collection of variants of a particular architecture
+; that share sufficient commonality that they can be handled together.
+
+(define (-gen-cpu-defines)
+ (string-append
+ "\
+/* Maximum number of instructions that are fetched at a time.
+ This is for LIW type instructions sets (e.g. m32r). */
+#define MAX_LIW_INSNS " (number->string (state-liw-insns))
+ "\n\
+
+/* Maximum number of instructions that can be executed in parallel. */
+#define MAX_PARALLEL_INSNS " (number->string (state-parallel-insns))
+ "\n\n"
+; (gen-enum-decl '@cpu@_virtual
+; "@cpu@ virtual insns"
+; "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h
+; '((x-invalid 0)
+; (x-before -1) (x-after -2)
+; (x-begin -3) (x-chain -4) (x-cti-chain -5)))
+ )
+)
+
+; Return a boolean indicating if hardware element HW needs storage allocated
+; for it in the SIM_CPU struct.
+
+(define (hw-need-storage? hw)
+ (and (register? hw) (not (obj-has-attr? hw 'VIRTUAL)))
+)
+
+; Return C type declarations of all of the hardware elements.
+; The name of the type is prepended with the cpu family name.
+
+(define (-gen-hardware-types)
+ (string-list
+ "/* CPU state information. */\n"
+ "typedef struct {\n"
+ " /* Hardware elements. */\n"
+ " struct {\n"
+ (string-list-map (lambda (hw)
+ (string-list
+ (gen-decl hw)
+ (gen-obj-sanitize hw
+ (string-list
+ (send hw 'gen-get-macro)
+ (send hw 'gen-set-macro)))
+ ))
+ (find hw-need-storage? (current-hw-list)))
+ " } hardware;\n"
+ "#define CPU_CGEN_HW(cpu) (& (cpu)->cpu_data.hardware)\n"
+ ;" /* CPU profiling state information. */\n"
+ ;" struct {\n"
+ ;(string-list-map (lambda (hw) (send hw 'gen-profile-decl))
+ ; (find hw-profilable? (current-hw-list)))
+ ;" } profile;\n"
+ ;"#define CPU_CGEN_PROFILE(cpu) (& (cpu)->cpu_data.profile)\n"
+ "} @CPU@_CPU_DATA;\n\n"
+ ; If there are any virtual regs, output get/set macros for them.
+ (let ((virtual-regs (find (lambda (hw)
+ (and (register? hw)
+ (obj-has-attr? hw 'VIRTUAL)))
+ (current-hw-list)))
+ (orig-with-parallel? (with-parallel?))
+ (result ""))
+ (set-with-parallel?! #f)
+ (if (not (null? virtual-regs))
+ (set! result
+ (string-list
+ "/* Virtual regs. */\n\n"
+ (string-list-map (lambda (hw)
+ (logit 3 "Generating get/set for " (obj:name hw)
+ " ...\n")
+ (gen-obj-sanitize hw
+ (string-list
+ (send hw 'gen-get-macro)
+ (send hw 'gen-set-macro))))
+ virtual-regs)
+ "\n"
+ )))
+ (set-with-parallel?! orig-with-parallel?)
+ result)
+ )
+)
+
+; Return the declaration of register access functions.
+
+(define (-gen-cpu-reg-access-decls)
+ (string-list
+ "/* Cover fns for register access. */\n"
+ (string-list-map (lambda (hw)
+ (gen-reg-access-decl hw
+ "@cpu@"
+ (gen-type hw)
+ (hw-scalar? hw)))
+ (find register? (current-hw-list)))
+ "\n"
+ "/* These must be hand-written. */\n"
+ "extern CPUREG_FETCH_FN @cpu@_fetch_register;\n"
+ "extern CPUREG_STORE_FN @cpu@_store_register;\n"
+ "\n")
+)
+
+; Generate type of struct holding model state while executing.
+
+(define (-gen-model-decls)
+ (logit 2 "Generating model decls ...\n")
+ (string-list
+ (string-list-map
+ (lambda (model)
+ (string-list
+ "typedef struct {\n"
+ (if (null? (model:state model))
+ " int empty;\n" ; ensure struct isn't empty so it compiles
+ (string-map (lambda (var)
+ (string-append " "
+ (mode:c-type (mode:lookup (cadr var)))
+ " "
+ (gen-c-symbol (car var))
+ ";\n"))
+ (model:state model)))
+ "} MODEL_" (string-upcase (gen-sym model)) "_DATA;\n\n"
+ ))
+ (current-model-list))
+ )
+)
+
+; Utility of -gen-extract-macros to generate a macro to define the local
+; vars to contain extracted field values and the code to assign them
+; for <iformat> IFMT.
+
+(define (-gen-extract-ifmt-macro ifmt)
+ (logit 2 "Processing format " (obj:name ifmt) " ...\n")
+ (string-list
+ (gen-define-ifmt-ifields ifmt "" #t #f)
+ (gen-extract-ifmt-ifields ifmt "" #t #f)
+ ; We don't need an extra blank line here as gen-extract-ifields adds one.
+ )
+)
+
+; Generate macros to extract instruction fields.
+
+(define (-gen-extract-macros)
+ (logit 2 "Generating extraction macros ...\n")
+ (string-list
+ "\
+/* Macros to simplify extraction, reading and semantic code.
+ These define and assign the local vars that contain the insn's fields. */
+\n"
+ (string-list-map -gen-extract-ifmt-macro (current-ifmt-list))
+ )
+)
+
+; Utility of -gen-parallel-exec-type to generate the definition of one
+; structure in PAREXEC.
+; SFMT is an <sformat> object.
+
+(define (-gen-parallel-exec-elm sfmt)
+ (string-append
+ " struct { /* " (obj:comment sfmt) " */\n"
+ (let ((sem-ops
+ ((if (with-parallel-write?) sfmt-out-ops sfmt-in-ops) sfmt)))
+ (if (null? sem-ops)
+ " int empty;\n" ; ensure struct isn't empty so it compiles
+ (string-map
+ (lambda (op)
+ (logit 2 "Processing operand " (obj:name op) " of format "
+ (obj:name sfmt) " ...\n")
+ (if (with-parallel-write?)
+ (let ((index-type (and (op-save-index? op)
+ (gen-index-type op sfmt))))
+ (string-append " " (gen-type op)
+ " " (gen-sym op) ";\n"
+ (if index-type
+ (string-append " " index-type
+ " " (gen-sym op) "_idx;\n")
+ "")))
+ (string-append " "
+ (gen-type op)
+ " "
+ (gen-sym op)
+ ";\n")))
+ sem-ops)))
+ " } " (gen-sym sfmt) ";\n"
+ )
+)
+
+; Generate the definition of the structure that holds register values, etc.
+; for use during parallel execution. When instructions are executed parallelly
+; either
+; - their inputs are read before their outputs are written. Thus we have to
+; fetch the input values of several instructions before executing any of them.
+; - or their outputs are queued here first and then written out after all insns
+; have executed.
+; The fetched/queued values are stored in an array of PAREXEC structs, one
+; element per instruction.
+
+(define (-gen-parallel-exec-type)
+ (logit 2 "Generating PAREXEC type ...\n")
+ (string-append
+ (if (with-parallel-write?)
+ "/* Queued output values of an instruction. */\n"
+ "/* Fetched input values of an instruction. */\n")
+ "\
+
+struct parexec {
+ union {\n"
+ (string-map -gen-parallel-exec-elm (current-sfmt-list))
+ "\
+ } operands;
+ /* For conditionally written operands, bitmask of which ones were. */
+ int written;
+};\n\n"
+ )
+)
+
+; Generate the TRACE_RECORD struct definition.
+; This struct will hold all necessary data for doing tracing and profiling
+; (e.g. register numbers). The goal is to remove all tracing code from the
+; semantic code. Then the fast/full distinction needn't use conditionals to
+; discard/include the tracing/profiling code.
+
+(define (-gen-trace-record-type)
+ (string-list
+ "\
+/* Collection of various things for the trace handler to use. */
+
+typedef struct trace_record {
+ IADDR pc;
+ /* FIXME:wip */
+} TRACE_RECORD;
+\n"
+ )
+)
+
+; Utilities of cgen-cpu.c
+
+; Get/set fns for every register.
+
+(define (-gen-cpu-reg-access-defns)
+ (string-list-map
+ (lambda (hw)
+ (let ((scalar? (hw-scalar? hw))
+ (name (obj:name hw))
+ (getter (hw-getter hw))
+ (setter (hw-setter hw)))
+ (gen-reg-access-defn hw
+ "@cpu@"
+ (gen-type hw)
+ scalar?
+ (if getter
+ (string-append
+ " return GET_"
+ (string-upcase (gen-c-symbol name))
+ " ("
+ (if scalar? "" "regno")
+ ");\n")
+ (string-append
+ " return CPU ("
+ (gen-c-symbol name)
+ (if scalar? "" "[regno]")
+ ");\n"))
+ (if setter
+ (string-append
+ " SET_"
+ (string-upcase (gen-c-symbol name))
+ " ("
+ (if scalar? "" "regno, ")
+ "newval);\n")
+ (string-append
+ " CPU ("
+ (gen-c-symbol name)
+ (if scalar? "" "[regno]")
+ ") = newval;\n")))))
+ (find (lambda (hw) (register? hw))
+ (current-hw-list)))
+)
+
+; Generate a function to record trace results in a trace record.
+
+(define (-gen-cpu-record-results)
+ (string-list
+ "\
+/* Record trace results for INSN. */
+
+void
+@cpu@_record_trace_results (SIM_CPU *current_cpu, CGEN_INSN *insn,
+ int *indices, TRACE_RECORD *tr)
+{\n"
+ "}\n"
+ )
+)
+
+; Utilities of cgen-read.c.
+; Parallel-read support is not currently used by any port and this code
+; has been left to bitrot. Don't delete it just yet.
+
+; Return C code to fetch and save all input operands to instructions with
+; <sformat> SFMT.
+
+(define (-gen-read-args sfmt)
+ (string-map (lambda (op) (op:read op sfmt))
+ (sfmt-in-ops sfmt))
+)
+
+; Utility of -gen-read-switch to generate a switch case for <sformat> SFMT.
+
+(define (-gen-read-case sfmt)
+ (logit 2 "Processing read switch case for \"" (obj:name sfmt) "\" ...\n")
+ (string-list
+ " CASE (read, READ_" (string-upcase (gen-sym sfmt)) ") : "
+ "/* " (obj:comment sfmt) " */\n"
+ " {\n"
+ (if (with-scache?)
+ (gen-define-field-macro sfmt)
+ "")
+ (gen-define-parallel-operand-macro sfmt)
+ (gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f)
+ (gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f)
+ (-gen-read-args sfmt)
+ (gen-undef-parallel-operand-macro sfmt)
+ (if (with-scache?)
+ (gen-undef-field-macro sfmt)
+ "")
+ " }\n"
+ " BREAK (read);\n\n"
+ )
+)
+
+; Generate the guts of a C switch statement to read insn operands.
+; The switch is based on instruction formats.
+
+(define (-gen-read-switch)
+ (logit 2 "Processing readers ...\n")
+ (string-write-map -gen-read-case (current-sfmt-list))
+)
+
+; Utilities of cgen-write.c.
+
+; This is the other way of implementing parallel execution support.
+; Instead of fetching all the input operands first, write all the output
+; operands and their addresses to holding variables, and then run a
+; post-processing pass to update the cpu state.
+;
+; There are separate implementations for semantics as functions and semantics
+; as one big switch. For the function case we create a function that is a
+; switch on each semantic format and loops writing each insn's results back.
+; For the switch case we add cases to the switch to handle the write back,
+; and it is up to the pbb compiler to include them in the generated "code".
+
+; Return C code to fetch and save all output operands to instructions with
+; <sformat> SFMT.
+
+(define (-gen-write-args sfmt)
+ (string-map (lambda (op) (op:write op sfmt))
+ (sfmt-out-ops sfmt))
+)
+
+; Utility of gen-write-switch to generate a switch case for <sformat> SFMT.
+; If INSN is non-#f, it is the <insn> object of the insn in which case
+; the case is named after the insn not the format. This is done because
+; current sem-switch support emits one handler per insn instead of per sfmt.
+
+(define (-gen-write-case sfmt insn)
+ (logit 2 "Processing write switch case for \"" (obj:name sfmt) "\" ...\n")
+ (string-list
+ (if insn
+ (string-list /indent
+ "CASE (sem, INSN_WRITE_"
+ (string-upcase (gen-sym insn)) ") : ")
+ (string-list /indent
+ "case @CPU@_"
+ (string-upcase (gen-sym sfmt)) " : "))
+ "/* "
+ (if insn
+ (string-list (insn-syntax insn))
+ (obj:comment sfmt))
+ " */\n"
+ /indent " {\n"
+ (if insn
+ (string-list
+ /indent
+ " SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);\n"
+ /indent
+ " const ARGBUF *abuf = SEM_ARGBUF (sem_arg)->fields.write.abuf;\n")
+ "")
+ (if (with-scache?)
+ (gen-define-field-macro sfmt)
+ "")
+ (gen-define-parallel-operand-macro sfmt)
+ /indent
+ " int UNUSED written = abuf->written;\n"
+ ;(gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f) - used by cgen-read.c
+ ;(gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f) - used by cgen-read.c
+ (if insn
+ (string-list /indent " IADDR UNUSED pc = abuf->addr;\n")
+ "")
+ (if (and insn (insn-cti? insn))
+ (string-list /indent
+ " SEM_BRANCH_INIT\n") ; no trailing `;' on purpose
+ "")
+ (if insn
+ (string-list /indent " vpc = SEM_NEXT_VPC (sem_arg, pc, 0);\n")
+ "")
+ "\n"
+ (/indent-add 4)
+ (-gen-write-args sfmt)
+ (/indent-add -4)
+ "\n"
+ (if (and insn (insn-cti? insn))
+ (string-list /indent " SEM_BRANCH_FINI (vpc);\n")
+ "")
+ (gen-undef-parallel-operand-macro sfmt)
+ (if (with-scache?)
+ (gen-undef-field-macro sfmt)
+ "")
+ /indent " }\n"
+ (if insn
+ (string-list /indent " NEXT (vpc);\n")
+ (string-list /indent " break;\n"))
+ "\n"
+ )
+)
+
+; Generate the guts of a C switch statement to write insn operands.
+; The switch is based on instruction formats.
+; ??? This will generate cases for formats that don't need it.
+; E.g. on the m32r all 32 bit insns can't be executed in parallel.
+; It's easier to generate the code anyway so we do.
+
+(define (-gen-write-switch)
+ (logit 2 "Processing writers ...\n")
+ (string-write-map (lambda (sfmt)
+ (-gen-write-case sfmt #f))
+ (current-sfmt-list))
+)
+
+; Utilities of cgen-semantics.c.
+
+; Return name of semantic fn for INSN.
+
+(define (-gen-sem-fn-name insn)
+ ;(string-append "sem_" (gen-sym insn))
+ (gen-sym insn)
+)
+
+; Return semantic fn table entry for INSN.
+
+(define (-gen-sem-fn-table-entry insn)
+ (string-list
+ " { "
+ "@CPU@_INSN_"
+ (string-upcase (gen-sym insn))
+ ", "
+ "SEM_FN_NAME (@cpu@," (-gen-sem-fn-name insn) ")"
+ " },\n"
+ )
+)
+
+; Return C code to define a table of all semantic fns and a function to
+; add the info to the insn descriptor table.
+
+(define (-gen-semantic-fn-table)
+ (string-write
+ "\
+/* Table of all semantic fns. */
+
+static const struct sem_fn_desc sem_fns[] = {\n"
+
+ (lambda ()
+ (string-write-map -gen-sem-fn-table-entry
+ (non-alias-insns (current-insn-list))))
+
+ "\
+ { 0, 0 }
+};
+
+/* Add the semantic fns to IDESC_TABLE. */
+
+void
+SEM_FN_NAME (@cpu@,init_idesc_table) (SIM_CPU *current_cpu)
+{
+ IDESC *idesc_table = CPU_IDESC (current_cpu);
+ const struct sem_fn_desc *sf;
+ int mach_num = MACH_NUM (CPU_MACH (current_cpu));
+
+ for (sf = &sem_fns[0]; sf->fn != 0; ++sf)
+ {
+ const CGEN_INSN *insn = idesc_table[sf->index].idata;
+ int valid_p = (CGEN_INSN_VIRTUAL_P (insn)
+ || CGEN_INSN_MACH_HAS_P (insn, mach_num));
+#if FAST_P
+ if (valid_p)
+ idesc_table[sf->index].sem_fast = sf->fn;
+ else
+ idesc_table[sf->index].sem_fast = SEM_FN_NAME (@cpu@,x_invalid);
+#else
+ if (valid_p)
+ idesc_table[sf->index].sem_full = sf->fn;
+ else
+ idesc_table[sf->index].sem_full = SEM_FN_NAME (@cpu@,x_invalid);
+#endif
+ }
+}
+\n"
+ )
+)
+
+; Return C code to perform the semantics of INSN.
+
+(define (gen-semantic-code insn)
+ ; Indicate generating code for INSN.
+ ; Use the compiled form if available.
+ ; The case when they're not available is for virtual insns.
+ (let ((sem (insn-compiled-semantics insn)))
+ (if sem
+ (rtl-c-parsed VOID sem nil
+ #:rtl-cover-fns? #t #:owner insn)
+ (rtl-c VOID (insn-semantics insn) nil
+ #:rtl-cover-fns? #t #:owner insn)))
+)
+
+; Return definition of C function to perform INSN.
+; This version handles the with-scache case.
+
+(define (-gen-scache-semantic-fn insn)
+ (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
+ (set! -with-profile? -with-profile-fn?)
+ (let ((profile? (and (with-profile?)
+ (not (obj-has-attr? insn 'VIRTUAL))))
+ (parallel? (with-parallel?))
+ (cti? (insn-cti? insn))
+ (insn-len (insn-length-bytes insn)))
+ (string-list
+ "/* " (obj:name insn) ": " (insn-syntax insn) " */\n\n"
+ "static SEM_PC\n"
+ "SEM_FN_NAME (@cpu@," (gen-sym insn) ")"
+ (if (and parallel? (not (with-generic-write?)))
+ " (SIM_CPU *current_cpu, SEM_ARG sem_arg, PAREXEC *par_exec)\n"
+ " (SIM_CPU *current_cpu, SEM_ARG sem_arg)\n")
+ "{\n"
+ (gen-define-field-macro (insn-sfmt insn))
+ (if (and parallel? (not (with-generic-write?)))
+ (gen-define-parallel-operand-macro (insn-sfmt insn))
+ "")
+ " ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
+ ; Unconditionally written operands are not recorded here.
+ " int UNUSED written = 0;\n"
+ ; The address of this insn, needed by extraction and semantic code.
+ ; Note that the address recorded in the cpu state struct is not used.
+ ; For faster engines that copy will be out of date.
+ " IADDR UNUSED pc = abuf->addr;\n"
+ (if (and cti? (not parallel?))
+ " SEM_BRANCH_INIT\n" ; no trailing `;' on purpose
+ "")
+ (string-list " SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, "
+ (number->string insn-len)
+ ");\n")
+ "\n"
+ (gen-semantic-code insn) "\n"
+ ; Only update what's been written if some are conditionally written.
+ ; Otherwise we know they're all written so there's no point in
+ ; keeping track.
+ (if (-any-cond-written? (insn-sfmt insn))
+ " abuf->written = written;\n"
+ "")
+ (if (and cti? (not parallel?))
+ " SEM_BRANCH_FINI (vpc);\n"
+ "")
+ " return vpc;\n"
+ (if (and parallel? (not (with-generic-write?)))
+ (gen-undef-parallel-operand-macro (insn-sfmt insn))
+ "")
+ (gen-undef-field-macro (insn-sfmt insn))
+ "}\n\n"
+ ))
+)
+
+; Return definition of C function to perform INSN.
+; This version handles the without-scache case.
+; ??? TODO: multiword insns.
+
+(define (-gen-no-scache-semantic-fn insn)
+ (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
+ (set! -with-profile? -with-profile-fn?)
+ (let ((profile? (and (with-profile?)
+ (not (obj-has-attr? insn 'VIRTUAL))))
+ (parallel? (with-parallel?))
+ (cti? (insn-cti? insn))
+ (insn-len (insn-length-bytes insn)))
+ (string-list
+ "/* " (obj:name insn) ": " (insn-syntax insn) " */\n\n"
+ "static SEM_STATUS\n"
+ "SEM_FN_NAME (@cpu@," (gen-sym insn) ")"
+ (if (and parallel? (not (with-generic-write?)))
+ " (SIM_CPU *current_cpu, SEM_ARG sem_arg, PAREXEC *par_exec, CGEN_INSN_INT insn)\n"
+ " (SIM_CPU *current_cpu, SEM_ARG sem_arg, CGEN_INSN_INT insn)\n")
+ "{\n"
+ (if (and parallel? (not (with-generic-write?)))
+ (gen-define-parallel-operand-macro (insn-sfmt insn))
+ "")
+ " SEM_STATUS status = 0;\n" ; ??? wip
+ " ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
+ ; Unconditionally written operands are not recorded here.
+ " int UNUSED written = 0;\n"
+ " IADDR UNUSED pc = GET_H_PC ();\n"
+ (if (and cti? (not parallel?))
+ " SEM_BRANCH_INIT\n" ; no trailing `;' on purpose
+ "")
+ (string-list " SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, "
+ (number->string insn-len)
+ ");\n")
+ (string-list (gen-define-ifmt-ifields (insn-ifmt insn) " " #f #t)
+ (gen-sfmt-op-argbuf-defns (insn-sfmt insn))
+ (gen-extract-ifmt-ifields (insn-ifmt insn) " " #f #t)
+ (gen-sfmt-op-argbuf-assigns (insn-sfmt insn)))
+ "\n"
+ (gen-semantic-code insn) "\n"
+ ; Only update what's been written if some are conditionally written.
+ ; Otherwise we know they're all written so there's no point in
+ ; keeping track.
+ (if (-any-cond-written? (insn-sfmt insn))
+ " abuf->written = written;\n"
+ "")
+ ; SEM_{,N}BRANCH_FINI are user-supplied macros.
+ (if (not parallel?)
+ (string-list
+ (if cti?
+ " SEM_BRANCH_FINI (vpc, "
+ " SEM_NBRANCH_FINI (vpc, ")
+ (gen-bool-attrs (obj-atlist insn) gen-attr-mask)
+ ");\n")
+ "")
+ " return status;\n"
+ (if (and parallel? (not (with-generic-write?)))
+ (gen-undef-parallel-operand-macro (insn-sfmt insn))
+ "")
+ "}\n\n"
+ ))
+)
+
+(define (-gen-all-semantic-fns)
+ (logit 2 "Processing semantics ...\n")
+ (let ((insns (non-alias-insns (current-insn-list))))
+ (if (with-scache?)
+ (string-write-map -gen-scache-semantic-fn insns)
+ (string-write-map -gen-no-scache-semantic-fn insns)))
+)
+
+; Utility of -gen-sem-case to return the mask of operands always written
+; to in <sformat> SFMT.
+; ??? Not currently used.
+
+(define (-uncond-written-mask sfmt)
+ (apply + (map (lambda (op)
+ (if (op:cond? op)
+ 0
+ (logsll 1 (op:num op))))
+ (sfmt-out-ops sfmt)))
+)
+
+; Utility of -gen-sem-case to return #t if any operand in <sformat> SFMT is
+; conditionally written to.
+
+(define (-any-cond-written? sfmt)
+ (any-true? (map op:cond? (sfmt-out-ops sfmt)))
+)
+
+; Generate a switch case to perform INSN.
+
+(define (-gen-sem-case insn parallel?)
+ (logit 2 "Processing "
+ (if parallel? "parallel " "")
+ "semantic switch case for \"" (insn-syntax insn) "\" ...\n")
+ (set! -with-profile? -with-profile-sw?)
+ (let ((cti? (insn-cti? insn))
+ (insn-len (insn-length-bytes insn)))
+ (string-list
+ ; INSN_ is prepended here and not elsewhere to avoid name collisions
+ ; with symbols like AND, etc.
+ " CASE (sem, "
+ "INSN_"
+ (if parallel? "PAR_" "")
+ (string-upcase (gen-sym insn)) ") : "
+ "/* " (insn-syntax insn) " */\n"
+ "{\n"
+ " SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);\n"
+ " ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
+ (if (with-scache?)
+ (gen-define-field-macro (insn-sfmt insn))
+ "")
+ (if (and parallel? (not (with-generic-write?)))
+ (gen-define-parallel-operand-macro (insn-sfmt insn))
+ "")
+ ; Unconditionally written operands are not recorded here.
+ " int UNUSED written = 0;\n"
+ ; The address of this insn, needed by extraction and semantic code.
+ ; Note that the address recorded in the cpu state struct is not used.
+ " IADDR UNUSED pc = abuf->addr;\n"
+ (if (and cti? (not parallel?))
+ " SEM_BRANCH_INIT\n" ; no trailing `;' on purpose
+ "")
+ (if (with-scache?)
+ ""
+ (string-list (gen-define-ifmt-ifields (insn-ifmt insn) " " #f #t)
+ (gen-extract-ifmt-ifields (insn-ifmt insn) " " #f #t)
+ "\n"))
+ (string-list " vpc = SEM_NEXT_VPC (sem_arg, pc, "
+ (number->string insn-len)
+ ");\n")
+ "\n"
+ (gen-semantic-code insn) "\n"
+ ; Only update what's been written if some are conditionally written.
+ ; Otherwise we know they're all written so there's no point in
+ ; keeping track.
+ (if (-any-cond-written? (insn-sfmt insn))
+ " abuf->written = written;\n"
+ "")
+ (if (and cti? (not parallel?))
+ " SEM_BRANCH_FINI (vpc);\n"
+ "")
+ (if (and parallel? (not (with-generic-write?)))
+ (gen-undef-parallel-operand-macro (insn-sfmt insn))
+ "")
+ (if (with-scache?)
+ (gen-undef-field-macro (insn-sfmt insn))
+ "")
+ "}\n"
+ " NEXT (vpc);\n\n"
+ ))
+)
+
+(define (-gen-sem-switch)
+ (logit 2 "Processing semantic switch ...\n")
+ ; Turn parallel execution support off.
+ (let ((orig-with-parallel? (with-parallel?)))
+ (set-with-parallel?! #f)
+ (let ((result
+ (string-write-map (lambda (insn) (-gen-sem-case insn #f))
+ (non-alias-insns (current-insn-list)))))
+ (set-with-parallel?! orig-with-parallel?)
+ result))
+)
+
+; Generate the guts of a C switch statement to execute parallel instructions.
+; This switch is included after the non-parallel instructions in the semantic
+; switch.
+;
+; ??? We duplicate the writeback case for each insn, even though we only need
+; one case per insn format. The former keeps the code for each insn
+; together and might improve cache usage. On the other hand the latter
+; reduces the amount of code, though it is believed that in this particular
+; instance the win isn't big enough.
+
+(define (-gen-parallel-sem-switch)
+ (logit 2 "Processing parallel insn semantic switch ...\n")
+ ; Turn parallel execution support on.
+ (let ((orig-with-parallel? (with-parallel?)))
+ (set-with-parallel?! #t)
+ (let ((result
+ (string-write-map (lambda (insn)
+ (string-list (-gen-sem-case insn #t)
+ (-gen-write-case (insn-sfmt insn) insn)))
+ (parallel-insns (current-insn-list)))))
+ (set-with-parallel?! orig-with-parallel?)
+ result))
+)
+
+; Top level file generators.
+
+; Generate cpu-<cpu>.h
+
+(define (cgen-cpu.h)
+ (logit 1 "Generating " (gen-cpu-name) " cpu.h ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support on if cpu needs it.
+ (set-with-parallel?! (state-parallel-exec?))
+
+ ; Tell the rtl->c translator we're not the simulator.
+ ; ??? Minimizes changes in generated code until this is changed.
+ ; RTL->C happens for field decoding.
+ (rtl-c-config! #:rtl-cover-fns? #f)
+
+ (string-write
+ (gen-copyright "CPU family header for @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#ifndef CPU_@CPU@_H
+#define CPU_@CPU@_H
+
+"
+ -gen-cpu-defines
+ -gen-hardware-types
+ -gen-cpu-reg-access-decls
+ -gen-model-decls
+ (lambda () (gen-argbuf-type #t))
+ (lambda () (gen-scache-type #t))
+ -gen-extract-macros
+ (if (and (with-parallel?) (not (with-generic-write?)))
+ -gen-parallel-exec-type
+ "")
+ -gen-trace-record-type
+ "#endif /* CPU_@CPU@_H */\n"
+ )
+)
+
+; Generate cpu-<cpu>.c
+
+(define (cgen-cpu.c)
+ (logit 1 "Generating " (gen-cpu-name) " cpu.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support on if cpu needs it.
+ (set-with-parallel?! (state-parallel-exec?))
+
+ ; Initialize rtl generation.
+ (rtl-c-config! #:rtl-cover-fns? #t)
+
+ (string-write
+ (gen-copyright "Misc. support for CPU family @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#define WANT_CPU @cpu@
+#define WANT_CPU_@CPU@
+
+#include \"sim-main.h\"
+#include \"cgen-ops.h\"
+
+"
+ -gen-cpu-reg-access-defns
+ -gen-cpu-record-results
+ )
+)
+
+; Generate read.c
+
+(define (cgen-read.c)
+ (logit 1 "Generating " (gen-cpu-name) " read.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support off.
+ (set-with-parallel?! #f)
+
+ ; Tell the rtx->c translator we are the simulator.
+ (rtl-c-config! #:rtl-cover-fns? #t)
+
+ (string-write
+ (gen-copyright (string-append "Simulator instruction operand reader for "
+ (current-arch-name) ".")
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#ifdef DEFINE_LABELS
+
+ /* The labels have the case they have because the enum of insn types
+ is all uppercase and in the non-stdc case the fmt symbol is built
+ into the enum name. */
+
+ static struct {
+ int index;
+ void *label;
+ } labels[] = {\n"
+
+ (lambda ()
+ (string-write-map (lambda (insn)
+ (string-append " { "
+ "@CPU@_INSN_"
+ (string-upcase (gen-sym insn))
+ ", && case_read_READ_"
+ (string-upcase (gen-sym (insn-sfmt insn)))
+ " },\n"))
+ (non-alias-insns (current-insn-list))))
+
+ " { 0, 0 }
+ };
+ int i;
+
+ for (i = 0; labels[i].label != 0; ++i)
+ CPU_IDESC (current_cpu) [labels[i].index].read = labels[i].label;
+
+#undef DEFINE_LABELS
+#endif /* DEFINE_LABELS */
+
+#ifdef DEFINE_SWITCH
+
+{\n"
+ (if (with-scache?)
+ "\
+ SEM_ARG sem_arg = sc;
+ ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+
+ SWITCH (read, sem_arg->read)\n"
+ "\
+ SWITCH (read, decode->read)\n")
+ "\
+ {
+
+"
+
+ -gen-read-switch
+
+ "\
+ }
+ ENDSWITCH (read) /* End of read switch. */
+}
+
+#undef DEFINE_SWITCH
+#endif /* DEFINE_SWITCH */
+"
+ )
+)
+
+; Generate write.c
+
+(define (cgen-write.c)
+ (logit 1 "Generating " (gen-cpu-name) " write.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support off.
+ (set-with-parallel?! #f)
+
+ ; Tell the rtx->c translator we are the simulator.
+ (rtl-c-config! #:rtl-cover-fns? #t)
+
+ (string-write
+ (gen-copyright (string-append "Simulator instruction operand writer for "
+ (current-arch-name) ".")
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+/* Write cached results of 1 or more insns executed in parallel. */
+
+void
+@cpu@_parallel_write (SIM_CPU *cpu, SCACHE *sbufs, PAREXEC *pbufs, int ninsns)
+{\n"
+ (if (with-scache?)
+ "\
+ SEM_ARG sem_arg = sc;
+ ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
+ "")
+ "\
+
+ do
+ {
+ ARGBUF *abuf = SEM_ARGBUF (sbufs);
+
+ switch (abuf->idesc->write)
+ {
+\n"
+
+ ;(/indent-add 8)
+ -gen-write-switch
+ ;(/indent-add -8)
+
+ "\
+ }
+ }
+ while (--ninsns > 0);
+}
+"
+ )
+)
+
+; Generate semantics.c
+; Each instruction is implemented in its own function.
+
+(define (cgen-semantics.c)
+ (logit 1 "Generating " (gen-cpu-name) " semantics.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support on if cpu needs it.
+ (set-with-parallel?! (state-parallel-exec?))
+
+ ; Tell the rtx->c translator we are the simulator.
+ (rtl-c-config! #:rtl-cover-fns? #t)
+
+ (string-write
+ (gen-copyright "Simulator instruction semantics for @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#define WANT_CPU @cpu@
+#define WANT_CPU_@CPU@
+
+#include \"sim-main.h\"
+#include \"cgen-mem.h\"
+#include \"cgen-ops.h\"
+
+#undef GET_ATTR
+#define GET_ATTR(cpu, num, attr) \
+CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_##attr)
+
+/* This is used so that we can compile two copies of the semantic code,
+ one with full feature support and one without that runs fast(er).
+ FAST_P, when desired, is defined on the command line, -DFAST_P=1. */
+#if FAST_P
+#define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn)
+#undef TRACE_RESULT
+#define TRACE_RESULT(cpu, abuf, name, type, val)
+#else
+#define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn)
+#endif
+\n"
+
+ -gen-all-semantic-fns
+ ; Put the table at the end so we don't have to declare all the sem fns.
+ -gen-semantic-fn-table
+ )
+)
+
+; Generate sem-switch.c.
+; Each instruction is a case in a switch().
+; This file consists of just the switch(). It is included by mainloop.c.
+
+(define (cgen-sem-switch.c)
+ (logit 1 "Generating " (gen-cpu-name) " sem-switch.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support off.
+ ; It is later turned on/off when generating the actual semantic code.
+ (set-with-parallel?! #f)
+
+ ; Tell the rtx->c translator we are the simulator.
+ (rtl-c-config! #:rtl-cover-fns? #t)
+
+ (string-write
+ (gen-copyright "Simulator instruction semantics for @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+
+ "\
+#ifdef DEFINE_LABELS
+
+ /* The labels have the case they have because the enum of insn types
+ is all uppercase and in the non-stdc case the insn symbol is built
+ into the enum name. */
+
+ static struct {
+ int index;
+ void *label;
+ } labels[] = {\n"
+
+ (lambda ()
+ (string-write-map (lambda (insn)
+ (string-append " { "
+ "@CPU@_INSN_"
+ (string-upcase (gen-sym insn))
+ ", && case_sem_INSN_"
+ (string-upcase (gen-sym insn))
+ " },\n"))
+ (non-alias-insns (current-insn-list))))
+
+ (if (state-parallel-exec?)
+ (lambda ()
+ (string-write-map (lambda (insn)
+ (string-append " { "
+ "@CPU@_INSN_PAR_"
+ (string-upcase (gen-sym insn))
+ ", && case_sem_INSN_PAR_"
+ (string-upcase (gen-sym insn))
+ " },\n"
+ " { "
+ "@CPU@_INSN_WRITE_"
+ (string-upcase (gen-sym insn))
+ ", && case_sem_INSN_WRITE_"
+ (string-upcase (gen-sym insn))
+ " },\n"))
+ (parallel-insns (current-insn-list))))
+ "")
+
+ " { 0, 0 }
+ };
+ int i;
+
+ for (i = 0; labels[i].label != 0; ++i)
+ {
+#if FAST_P
+ CPU_IDESC (current_cpu) [labels[i].index].sem_fast_lab = labels[i].label;
+#else
+ CPU_IDESC (current_cpu) [labels[i].index].sem_full_lab = labels[i].label;
+#endif
+ }
+
+#undef DEFINE_LABELS
+#endif /* DEFINE_LABELS */
+
+#ifdef DEFINE_SWITCH
+
+/* If hyper-fast [well not unnecessarily slow] execution is selected, turn
+ off frills like tracing and profiling. */
+/* FIXME: A better way would be to have TRACE_RESULT check for something
+ that can cause it to be optimized out. Another way would be to emit
+ special handlers into the instruction \"stream\". */
+
+#if FAST_P
+#undef TRACE_RESULT
+#define TRACE_RESULT(cpu, abuf, name, type, val)
+#endif
+
+#undef GET_ATTR
+#define GET_ATTR(cpu, num, attr) \
+CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_##attr)
+
+{
+
+#if WITH_SCACHE_PBB
+
+/* Branch to next handler without going around main loop. */
+#define NEXT(vpc) goto * SEM_ARGBUF (vpc) -> semantic.sem_case
+SWITCH (sem, SEM_ARGBUF (vpc) -> semantic.sem_case)
+
+#else /* ! WITH_SCACHE_PBB */
+
+#define NEXT(vpc) BREAK (sem)
+#ifdef __GNUC__
+#if FAST_P
+ SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_fast_lab)
+#else
+ SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_full_lab)
+#endif
+#else
+ SWITCH (sem, SEM_ARGBUF (sc) -> idesc->num)
+#endif
+
+#endif /* ! WITH_SCACHE_PBB */
+
+ {
+
+"
+
+ -gen-sem-switch
+
+ (if (state-parallel-exec?)
+ -gen-parallel-sem-switch
+ "")
+
+ "
+ }
+ ENDSWITCH (sem) /* End of semantic switch. */
+
+ /* At this point `vpc' contains the next insn to execute. */
+}
+
+#undef DEFINE_SWITCH
+#endif /* DEFINE_SWITCH */
+"
+ )
+)
+
+; Generate mainloop.in.
+; ??? Not currently used.
+
+(define (cgen-mainloop.in)
+ (logit 1 "Generating mainloop.in ...\n")
+
+ (string-write
+ "cat <<EOF >/dev/null\n"
+ (gen-copyright "Simulator main loop for @arch@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "EOF\n"
+ "\
+
+# Syntax:
+# /bin/sh mainloop.in init|support|{full,fast}-{extract,exec}-{scache,nocache}
+
+# ??? There's lots of conditional compilation here.
+# After a few more ports are done, revisit.
+
+case \"x$1\" in
+
+xsupport)
+
+cat <<EOF
+/*xsupport*/
+EOF
+
+;;
+
+xinit)
+
+cat <<EOF
+/*xinit*/
+EOF
+
+;;
+
+xfull-extract-* | xfast-extract-*)
+
+cat <<EOF
+{
+"
+ (rtl-c VOID insn-extract nil #:rtl-cover-fns? #t)
+"}
+EOF
+
+;;
+
+xfull-exec-* | xfast-exec-*)
+
+cat <<EOF
+{
+"
+ (rtl-c VOID insn-execute nil #:rtl-cover-fns? #t)
+"}
+EOF
+
+;;
+
+*)
+ echo \"Invalid argument to mainloop.in: $1\" >&2
+ exit 1
+ ;;
+
+esac
+"
+ )
+)
diff --git a/cgen/sim-decode.scm b/cgen/sim-decode.scm
new file mode 100644
index 00000000000..2285c2825e7
--- /dev/null
+++ b/cgen/sim-decode.scm
@@ -0,0 +1,592 @@
+; Decoder generation.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Names of various global vars.
+
+; Name of insn descriptor table var.
+(define IDESC-TABLE-VAR "@cpu@_insn_data")
+
+; Return decode entries for each insn.
+; ??? At one point we generated one variable per instruction rather than one
+; big array. It doesn't matter too much (yet). Generating one big array is
+; simpler.
+
+(define (-gen-decode-insn-globals insn-list)
+ ; Print the higher detailed stuff at higher verbosity.
+ (logit 2 "Processing decode insn globals ...\n")
+
+ (string-write
+
+ (if (and (with-parallel?) (not (with-parallel-only?)))
+ "\
+/* Insn can't be executed in parallel.
+ Or is that \"do NOt Pass to Air defense Radar\"? :-) */
+#define NOPAR (-1)
+\n"
+ "")
+
+ "\
+/* The instruction descriptor array.
+ This is computed at runtime. Space for it is not malloc'd to save a
+ teensy bit of cpu in the decoder. Moving it to malloc space is trivial
+ but won't be done until necessary (we don't currently support the runtime
+ addition of instructions nor an SMP machine with different cpus). */
+static IDESC " IDESC-TABLE-VAR "[@CPU@_INSN_MAX];
+
+/* Commas between elements are contained in the macros.
+ Some of these are conditionally compiled out. */
+
+static const struct insn_sem @cpu@_insn_sem[] =
+{\n"
+
+ (string-list-map
+ (lambda (insn)
+ (let ((name (gen-sym insn))
+ (pbb? (obj-has-attr? insn 'PBB))
+ (virtual? (insn-virtual? insn)))
+ (string-list
+ " { "
+ (if virtual?
+ (string-append "VIRTUAL_INSN_" (string-upcase name) ", ")
+ (string-append "@ARCH@_INSN_" (string-upcase name) ", "))
+ "@CPU@_INSN_" (string-upcase name) ", "
+ "@CPU@_" (-gen-fmt-enum (insn-sfmt insn))
+ (if (and (with-parallel?) (not (with-parallel-only?)))
+ (string-list
+ (if (insn-parallel? insn)
+ (string-append ", @CPU@_INSN_PAR_"
+ (string-upcase name)
+ ", "
+ (if (with-parallel-read?)
+ "@CPU@_INSN_READ_"
+ "@CPU@_INSN_WRITE_")
+ (string-upcase name))
+ ", NOPAR, NOPAR "))
+ "")
+ " },\n")))
+ insn-list)
+
+ "\
+};
+
+static const struct insn_sem @cpu@_insn_sem_invalid = {
+ VIRTUAL_INSN_X_INVALID, @CPU@_INSN_X_INVALID, @CPU@_SFMT_EMPTY"
+ (if (and (with-parallel?) (not (with-parallel-only?)))
+ ", NOPAR, NOPAR"
+ "")
+ "
+};
+\n"
+ )
+)
+
+; Return enum name of format FMT.
+
+(define (-gen-fmt-enum fmt)
+ (string-upcase (gen-sym fmt))
+)
+
+; Generate decls for the insn descriptor table type IDESC.
+
+(define (-gen-idesc-decls)
+ (string-append "\
+extern const IDESC *@cpu@_decode (SIM_CPU *, IADDR,
+ CGEN_INSN_INT,"
+ (if (adata-integral-insn? CURRENT-ARCH)
+ " CGEN_INSN_INT,\n"
+ "\n")
+ "\
+ ARGBUF *);
+extern void @cpu@_init_idesc_table (SIM_CPU *);
+extern void @cpu@_sem_init_idesc_table (SIM_CPU *);
+extern void @cpu@_semf_init_idesc_table (SIM_CPU *);
+\n")
+)
+
+; Return definition of C function to initialize the IDESC table.
+; @cpu@_init_idesc_table is defined here as it depends on with-parallel?
+; and thus can't be defined in sim/common.
+
+(define (-gen-idesc-init-fn)
+ (string-append "\
+/* Initialize an IDESC from the compile-time computable parts. */
+
+static INLINE void
+init_idesc (SIM_CPU *cpu, IDESC *id, const struct insn_sem *t)
+{
+ const CGEN_INSN *insn_table = CGEN_CPU_INSN_TABLE (CPU_CPU_DESC (cpu))->init_entries;
+
+ id->num = t->index;
+ id->sfmt = t->sfmt;
+ if ((int) t->type <= 0)
+ id->idata = & cgen_virtual_insn_table[- (int) t->type];
+ else
+ id->idata = & insn_table[t->type];
+ id->attrs = CGEN_INSN_ATTRS (id->idata);
+ /* Oh my god, a magic number. */
+ id->length = CGEN_INSN_BITSIZE (id->idata) / 8;
+
+#if WITH_PROFILE_MODEL_P
+ id->timing = & MODEL_TIMING (CPU_MODEL (cpu)) [t->index];
+ {
+ SIM_DESC sd = CPU_STATE (cpu);
+ SIM_ASSERT (t->index == id->timing->num);
+ }
+#endif
+
+ /* Semantic pointers are initialized elsewhere. */
+}
+
+/* Initialize the instruction descriptor table. */
+
+void
+@cpu@_init_idesc_table (SIM_CPU *cpu)
+{
+ IDESC *id,*tabend;
+ const struct insn_sem *t,*tend;
+ int tabsize = @CPU@_INSN_MAX;
+ IDESC *table = " IDESC-TABLE-VAR ";
+
+ memset (table, 0, tabsize * sizeof (IDESC));
+
+ /* First set all entries to the `invalid insn'. */
+ t = & @cpu@_insn_sem_invalid;
+ for (id = table, tabend = table + tabsize; id < tabend; ++id)
+ init_idesc (cpu, id, t);
+
+ /* Now fill in the values for the chosen cpu. */
+ for (t = @cpu@_insn_sem, tend = t + sizeof (@cpu@_insn_sem) / sizeof (*t);
+ t != tend; ++t)
+ {
+ init_idesc (cpu, & table[t->index], t);\n"
+
+ (if (and (with-parallel?) (not (with-parallel-only?)))
+ "\
+ if (t->par_index != NOPAR)
+ {
+ init_idesc (cpu, &table[t->par_index], t);
+ table[t->index].par_idesc = &table[t->par_index];
+ }\n"
+ "")
+
+ (if (and (with-parallel-write?) (not (with-parallel-only?)))
+ "\
+ if (t->par_index != NOPAR)
+ {
+ init_idesc (cpu, &table[t->write_index], t);
+ table[t->par_index].par_idesc = &table[t->write_index];
+ }\n"
+ "")
+
+ "\
+ }
+
+ /* Link the IDESC table into the cpu. */
+ CPU_IDESC (cpu) = table;
+}
+
+")
+)
+
+; Instruction field extraction support.
+; Two implementations are provided, one for !with-scache and one for
+; with-scache.
+;
+; Extracting ifields is a three phase process. First the ifields are
+; extracted and stored in local variables. Then any ifields requiring
+; additional processing for operands are handled. Then in the with-scache
+; case the results are stored in a struct for later retrieval by the semantic
+; code.
+;
+; The !with-scache case does this processing in the semantic function,
+; except it doesn't need the last step (it doesn't need to store the results
+; in a struct for later use).
+;
+; The with-scache case extracts the ifields in the decode function.
+; Furthermore, we use <sformat-argbuf> to reduce the quantity of structures
+; created (this helps semantic-fragment pbb engines).
+
+; Return C code to record <ifield> F for the semantic handler
+; in a local variable rather than an ARGBUF struct.
+
+(define (-gen-record-argbuf-ifld f sfmt)
+ (string-append " " (gen-ifld-argbuf-ref f)
+ " = " (gen-extracted-ifld-value f) ";\n")
+)
+
+; Return three of arguments to TRACE:
+; string argument to fprintf, character indicating type of third arg, value.
+; The type is one of: x.
+
+(define (-gen-trace-argbuf-ifld f sfmt)
+ (string-append
+ ; FIXME: Add method to return fprintf format string.
+ ", \"" (gen-sym f) " 0x%x\""
+ ", 'x'"
+ ", " (gen-extracted-ifld-value f))
+)
+
+; Instruction field extraction support cont'd.
+; Hardware support.
+
+; gen-extract method.
+; For the default case we use the ifield as is, which is output elsewhere.
+
+(method-make!
+ <hardware-base> 'gen-extract
+ (lambda (self op sfmt local?)
+ "")
+)
+
+; gen-trace-extract method.
+; Return appropriate arguments for TRACE_EXTRACT.
+
+(method-make!
+ <hardware-base> 'gen-trace-extract
+ (lambda (self op sfmt)
+ "")
+)
+
+; Extract the necessary fields into ARGBUF.
+
+(method-make!
+ <hw-register> 'gen-extract
+ (lambda (self op sfmt local?)
+ (if (hw-cache-addr? self)
+ (string-append " "
+ (if local?
+ (gen-hw-index-argbuf-name (op:index op))
+ (gen-hw-index-argbuf-ref (op:index op)))
+ " = & "
+ (gen-cpu-ref (gen-sym (op:type op)))
+ (gen-array-ref (gen-extracted-ifld-value (op-ifield op)))
+ ";\n")
+ ""))
+)
+
+; Return appropriate arguments for TRACE_EXTRACT.
+
+(method-make!
+ <hw-register> 'gen-trace-extract
+ (lambda (self op sfmt)
+ (if (hw-cache-addr? self)
+ (string-append
+ ; FIXME: Add method to return fprintf format string.
+ ", \"" (gen-sym op) " 0x%x\""
+ ", 'x'"
+ ", " (gen-extracted-ifld-value (op-ifield op)))
+ ""))
+)
+
+; Extract the necessary fields into ARGBUF.
+
+(method-make!
+ <hw-address> 'gen-extract
+ (lambda (self op sfmt local?)
+ (string-append " "
+ (if local?
+ (gen-hw-index-argbuf-name (op:index op))
+ (gen-hw-index-argbuf-ref (op:index op)))
+ " = "
+ (gen-extracted-ifld-value (op-ifield op))
+ ";\n"))
+)
+
+; Return appropriate arguments for TRACE_EXTRACT.
+
+(method-make!
+ <hw-address> 'gen-trace-extract
+ (lambda (self op sfmt)
+ (string-append
+ ; FIXME: Add method to return fprintf format string.
+ ", \"" (gen-sym op) " 0x%x\""
+ ", 'x'"
+ ", " (gen-extracted-ifld-value (op-ifield op))))
+)
+
+; Instruction field extraction support cont'd.
+; Operand support.
+
+; Return C code to record the field for the semantic handler.
+; In the case of a register, this is usually the address of the register's
+; value (if CACHE-ADDR).
+; LOCAL? indicates whether to record the value in a local variable or in
+; the ARGBUF struct.
+; ??? Later allow target to provide an `extract' expression.
+
+(define (-gen-op-extract op sfmt local?)
+ (send (op:type op) 'gen-extract op sfmt local?)
+)
+
+; Return three of arguments to TRACE_EXTRACT:
+; string argument to fprintf, character indicating type of third arg, value.
+; The type is one of: x.
+
+(define (-gen-op-trace-extract op sfmt)
+ (send (op:type op) 'gen-trace-extract op sfmt)
+)
+
+; Return C code to define local vars to hold processed ifield data for
+; <sformat> SFMT.
+; This is used when !with-scache.
+; Definitions of the extracted ifields is handled elsewhere.
+
+(define (gen-sfmt-op-argbuf-defns sfmt)
+ (let ((operands (sfmt-extracted-operands sfmt)))
+ (string-list-map (lambda (op)
+ (let ((var-spec (sfmt-op-sbuf-elm op sfmt)))
+ (if var-spec
+ (string-append " "
+ (cadr var-spec)
+ " "
+ (car var-spec)
+ ";\n")
+ "")))
+ operands))
+)
+
+; Return C code to assign values to the local vars that hold processed ifield
+; data for <sformat> SFMT.
+; This is used when !with-scache.
+; Assignment of the extracted ifields is handled elsewhere.
+
+(define (gen-sfmt-op-argbuf-assigns sfmt)
+ (let ((operands (sfmt-extracted-operands sfmt)))
+ (string-list-map (lambda (op)
+ (-gen-op-extract op sfmt #t))
+ operands))
+)
+
+; Instruction field extraction support cont'd.
+; Emit extraction section of decode function.
+
+; Return C code to record insn field data for <sformat> SFMT.
+; This is used when with-scache.
+
+(define (-gen-record-args sfmt)
+ (let ((operands (sfmt-extracted-operands sfmt))
+ (iflds (sfmt-needed-iflds sfmt)))
+ (string-list
+ " /* Record the fields for the semantic handler. */\n"
+ (string-list-map (lambda (f) (-gen-record-argbuf-ifld f sfmt))
+ iflds)
+ (string-list-map (lambda (op) (-gen-op-extract op sfmt #f))
+ operands)
+ " TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "
+ "\"" (gen-sym sfmt) "\""
+ (string-list-map (lambda (f) (-gen-trace-argbuf-ifld f sfmt))
+ iflds)
+ (string-list-map (lambda (op) (-gen-op-trace-extract op sfmt))
+ operands)
+ ", (char *) 0));\n"
+ ))
+)
+
+; Return C code to record insn field data for profiling.
+; Also recorded are operands not mentioned in the fields but mentioned
+; in the semantic code.
+;
+; FIXME: Register usage may need to be tracked as an array of longs.
+; If there are more than 32 regs, we can't know which until build time.
+; ??? For now we only handle reg sets of 32 or less.
+;
+; ??? The other way to obtain register numbers is to defer computing them
+; until they're actually needed. It will speed up execution when not doing
+; profiling, though the speed up is only for the extraction phase.
+; On the other hand the current way has one memory reference per register
+; number in the profiling routines. For RISC this can be a lose, though for
+; more complicated instruction sets it could be a win as all the computation
+; is kept to the extraction phase. If someone wants to put forth some real
+; data, this might then be changed (or at least noted).
+
+(define (-gen-record-profile-args sfmt)
+ (let ((in-ops (find op-profilable? (sfmt-in-ops sfmt)))
+ (out-ops (find op-profilable? (sfmt-out-ops sfmt)))
+ )
+ (if (and (null? in-ops) (null? out-ops))
+ ""
+ (string-list
+ "#if WITH_PROFILE_MODEL_P\n"
+ " /* Record the fields for profiling. */\n"
+ " if (PROFILE_MODEL_P (current_cpu))\n"
+ " {\n"
+ (string-list-map (lambda (op) (op:record-profile op sfmt #f))
+ in-ops)
+ (string-list-map (lambda (op) (op:record-profile op sfmt #t))
+ out-ops)
+ " }\n"
+ "#endif\n"
+ )))
+)
+
+; Return C code that extracts the fields of <sformat> SFMT.
+;
+; Extraction is based on formats to reduce the amount of code generated.
+; However, we also need to emit code which records the hardware elements used
+; by the semantic code. This is currently done by recording this information
+; with the format.
+
+(define (-gen-extract-case sfmt)
+ (logit 2 "Processing extractor for \"" (sfmt-key sfmt) "\" ...\n")
+ (string-list
+ " extract_" (gen-sym sfmt) ":\n"
+ " {\n"
+ " const IDESC *idesc = &" IDESC-TABLE-VAR "[itype];\n"
+ " CGEN_INSN_INT insn = "
+ (if (adata-integral-insn? CURRENT-ARCH)
+ "entire_insn;\n"
+ "base_insn;\n")
+ (gen-define-field-macro sfmt)
+ (gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f)
+ "\n"
+ (gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f)
+ "\n"
+ (-gen-record-args sfmt)
+ "\n"
+ (-gen-record-profile-args sfmt)
+ (gen-undef-field-macro sfmt)
+ " return idesc;\n"
+ " }\n\n"
+ )
+)
+
+; For each format, return its extraction function.
+
+(define (-gen-all-extractors)
+ (logit 2 "Processing extractors ...\n")
+ (string-list-map -gen-extract-case (current-sfmt-list))
+)
+
+; Generate top level decoder.
+; INITIAL-BITNUMS is a target supplied list of bit numbers to use to
+; build the first decode table. If nil, we compute 8 bits of it (FIXME)
+; ourselves.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; FIXME: Need to be perfect for every subtable, or allow target more control.
+; Leave for later (and don't give target more control until oodles of effort
+; have been spent trying to be perfect! ... or close enough).
+
+(define (-gen-decode-fn insn-list initial-bitnums lsb0?)
+
+ ; Compute the initial DECODE-BITSIZE as the minimum of all insn lengths.
+ ; The caller of @cpu@_decode must fetch and pass exactly this number of bits
+ ; of the instruction.
+ ; ??? Make this a parameter later but only if necessary.
+
+ (let ((decode-bitsize (apply min (map insn-base-mask-length insn-list))))
+
+ ; Compute INITIAL-BITNUMS if not supplied.
+ ; 0 is passed for the start bit (it is independent of lsb0?)
+ (if (null? initial-bitnums)
+ (set! initial-bitnums (decode-get-best-bits insn-list nil
+ 0 ; startbit
+ 8 ; max
+ decode-bitsize
+ lsb0?)))
+
+ ; All set. gen-decoder does the hard part, we just print out the result.
+ (let ((decode-code (gen-decoder insn-list initial-bitnums
+ decode-bitsize
+ " " lsb0?
+ (current-insn-lookup 'x-invalid))))
+
+ (string-write
+ "\
+/* Given an instruction, return a pointer to its IDESC entry. */
+
+const IDESC *
+@cpu@_decode (SIM_CPU *current_cpu, IADDR pc,
+ CGEN_INSN_INT base_insn,"
+ (if (adata-integral-insn? CURRENT-ARCH)
+ " CGEN_INSN_INT entire_insn,\n"
+ "\n")
+ "\
+ ARGBUF *abuf)
+{
+ /* Result of decoder. */
+ @CPU@_INSN_TYPE itype;
+
+ {
+ CGEN_INSN_INT insn = base_insn;
+\n"
+
+ decode-code
+
+ "\
+ }
+\n"
+
+ (if (with-scache?)
+ (string-list "\
+ /* The instruction has been decoded, now extract the fields. */\n\n"
+ -gen-all-extractors)
+ ; Without the scache, extraction is defered until the semantic code.
+ (string-list "\
+ /* Extraction is defered until the semantic code. */
+
+ done:
+ return &" IDESC-TABLE-VAR "[itype];\n"))
+
+ "\
+}\n"
+ )))
+)
+
+; Entry point. Generate decode.h.
+
+(define (cgen-decode.h)
+ (logit 1 "Generating " (gen-cpu-name) " decode.h ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support on if cpu needs it.
+ (set-with-parallel?! (state-parallel-exec?))
+
+ (string-write
+ (gen-copyright "Decode header for @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#ifndef @CPU@_DECODE_H
+#define @CPU@_DECODE_H
+
+"
+ -gen-idesc-decls
+ (lambda () (gen-cpu-insn-enum-decl (current-cpu)
+ (non-multi-insns (non-alias-insns (current-insn-list)))))
+ (lambda () (gen-sfmt-enum-decl (current-sfmt-list)))
+ gen-model-fn-decls
+ "#endif /* @CPU@_DECODE_H */\n"
+ )
+)
+
+; Entry point. Generate decode.c.
+
+(define (cgen-decode.c)
+ (logit 1 "Generating " (gen-cpu-name) " decode.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support on if cpu needs it.
+ (set-with-parallel?! (state-parallel-exec?))
+
+ ; Tell the rtx->c translator we are the simulator.
+ (rtl-c-config! #:rtl-cover-fns? #t)
+
+ (string-write
+ (gen-copyright "Simulator instruction decoder for @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#define WANT_CPU @cpu@
+#define WANT_CPU_@CPU@
+
+#include \"sim-main.h\"
+#include \"sim-assert.h\"\n\n"
+
+ (lambda () (-gen-decode-insn-globals (non-multi-insns (non-alias-insns (current-insn-list)))))
+ -gen-idesc-init-fn
+ (lambda () (-gen-decode-fn (non-multi-insns (real-insns (current-insn-list)))
+ (state-decode-assist)
+ (current-arch-insn-lsb0?)))
+ )
+)
diff --git a/cgen/sim-model.scm b/cgen/sim-model.scm
new file mode 100644
index 00000000000..eb42c93af23
--- /dev/null
+++ b/cgen/sim-model.scm
@@ -0,0 +1,394 @@
+; Simulator model support, plus misc. things associated with a cpu family.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; Return C code to define cpu implementation properties.
+
+(define (-gen-cpu-imp-properties)
+ (string-list
+ "\
+/* The properties of this cpu's implementation. */
+
+static const MACH_IMP_PROPERTIES @cpu@_imp_properties =
+{
+ sizeof (SIM_CPU),
+#if WITH_SCACHE
+ sizeof (SCACHE)
+#else
+ 0
+#endif
+};\n\n"
+ )
+)
+
+; Insn modeling support.
+
+; Generate code to profile hardware elements.
+; ??? Not currently used.
+
+(define (-gen-hw-profile-code)
+ ; Fetch profilable input and output operands of the semantic code.
+ (let ((in-ops (find op-profilable? (sfmt-in-ops (insn-sfmt insn))))
+ (out-ops (find op-profilable? (sfmt-out-ops (insn-sfmt insn)))))
+ (string-list
+ ; For each operand, record its being get/set.
+ (string-list-map (lambda (op) (send op 'gen-profile-code insn #f))
+ in-ops)
+ (string-list-map (lambda (op) (send op 'gen-profile-code insn #t))
+ out-ops)
+ ))
+)
+
+; Return decls of hardware element profilers.
+; ??? Not currently used.
+
+(define (-gen-hw-profile-decls)
+ (string-list
+ "/* Hardware profiling handlers. */\n\n"
+ (string-list-map (lambda (hw)
+ (string-append "extern void @cpu@_model_mark_get_"
+ (gen-sym hw) " (SIM_CPU *"
+ (if (hw-scalar? hw)
+ ""
+ ", int") ; FIXME: get index type
+ ");\n"
+ "extern void @cpu@_model_mark_set_"
+ (gen-sym hw) " (SIM_CPU *"
+ (if (hw-scalar? hw)
+ ""
+ ", int") ; FIXME: get index type
+ ");\n"))
+ (find hw-profilable? (current-hw-list)))
+ "\n"
+ )
+)
+
+; Return name of profiling handler for MODEL, UNIT.
+; Also called by sim.scm.
+
+(define (gen-model-unit-fn-name model unit)
+ (string-append "@cpu@_model_" (gen-sym model) "_" (gen-sym unit))
+)
+
+; Return decls of all insn model handlers.
+; This is called from sim-decode.scm.
+
+(define (gen-model-fn-decls)
+ (let ((gen-args (lambda (args)
+ (gen-c-args (map (lambda (arg)
+ (string-append
+ (mode:c-type (mode:lookup (cadr arg)))
+ " /*" (car arg) "*/"))
+ (find (lambda (arg)
+ ; Indices of scalars not passed.
+ (not (null? (cdr arg))))
+ args)))))
+ )
+
+ (string-list
+ ; -gen-hw-profile-decls
+ "/* Function unit handlers (user written). */\n\n"
+ (string-list-map
+ (lambda (model)
+ (string-list-map (lambda (unit)
+ (string-append
+ "extern int "
+ (gen-model-unit-fn-name model unit)
+ " (SIM_CPU *, const IDESC *,"
+ " int /*unit_num*/, int /*referenced*/"
+ (gen-args (unit:inputs unit))
+ (gen-args (unit:outputs unit))
+ ");\n"))
+ (model:units model)))
+ (current-model-list))
+ "\n"
+ "/* Profiling before/after handlers (user written) */\n\n"
+ "extern void @cpu@_model_insn_before (SIM_CPU *, int /*first_p*/);\n"
+ "extern void @cpu@_model_insn_after (SIM_CPU *, int /*last_p*/, int /*cycles*/);\n"
+ "\n"
+ ))
+)
+
+; Return name of profile handler for INSN, MODEL.
+
+(define (-gen-model-insn-fn-name model insn)
+ (string-append "model_" (gen-sym model) "_" (gen-sym insn))
+)
+
+; Return function to model INSN.
+
+(define (-gen-model-insn-fn model insn)
+ (logit 2 "Processing modeling for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
+ (string-list
+ "static int\n"
+ (-gen-model-insn-fn-name model insn)
+ ; sem_arg is a void * to keep cgen specific stuff out of sim-model.h
+ " (SIM_CPU *current_cpu, void *sem_arg)\n"
+ "{\n"
+ (if (with-scache?)
+ (gen-define-field-macro (insn-sfmt insn))
+ "")
+ " const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);\n"
+ " const IDESC * UNUSED idesc = abuf->idesc;\n"
+ ; or: idesc = & CPU_IDESC (current_cpu) ["
+ ; (gen-cpu-insn-enum (mach-cpu (model:mach model)) insn)
+ ; "];\n"
+ " int cycles = 0;\n"
+ (send insn 'gen-profile-locals model)
+ (if (with-scache?)
+ ""
+ (string-list
+ " IADDR UNUSED pc = GET_H_PC ();\n"
+ " CGEN_INSN_INT insn = abuf->insn;\n"
+ (gen-define-ifmt-ifields (insn-ifmt insn) " " #f #t)
+ (gen-sfmt-op-argbuf-defns (insn-sfmt insn))
+ (gen-extract-ifmt-ifields (insn-ifmt insn) " " #f #t)
+ (gen-sfmt-op-argbuf-assigns (insn-sfmt insn))))
+ ; Emit code to model the insn. Function units are handled here.
+ (send insn 'gen-profile-code model "cycles")
+ " return cycles;\n"
+ (if (with-scache?)
+ (gen-undef-field-macro (insn-sfmt insn))
+ "")
+ "}\n\n")
+)
+
+; Return insn modeling handlers.
+; ??? Might wish to reduce the amount of output by combining identical cases.
+; ??? Modelling of insns could be table driven, but that puts constraints on
+; generality.
+
+(define (-gen-model-insn-fns)
+ (string-write
+ "/* Model handlers for each insn. */\n\n"
+ (lambda () (string-write-map
+ (lambda (model)
+ (string-write-map
+ (lambda (insn) (-gen-model-insn-fn model insn))
+ (real-insns (current-insn-list))))
+ (current-model-list)))
+ )
+)
+
+; Generate timing table entry for function unit U while executing INSN.
+; U is a <unit> object.
+; ARGS is a list of overriding arguments from INSN.
+
+(define (-gen-insn-unit-timing model insn u args)
+ (string-append
+ "{ "
+ "(int) " (unit:enum u) ", "
+ (number->string (unit:issue u)) ", "
+ (let ((cycles (assq-ref args 'cycles)))
+ (if cycles
+ (number->string (car cycles))
+ (number->string (unit:done u))))
+ " }, "
+ )
+)
+
+; Generate timing table entry for MODEL for INSN.
+
+(define (-gen-insn-timing model insn)
+ ; Instruction timing is stored as an associative list based on the model.
+ (let ((timing (assq (obj:name model) (insn-timing insn))))
+ ;(display timing) (newline)
+ (string-list
+ " { "
+ (gen-cpu-insn-enum (mach-cpu (model:mach model)) insn)
+ ", "
+ (if (obj-has-attr? insn 'VIRTUAL)
+ "0"
+ (-gen-model-insn-fn-name model insn))
+ ", { "
+ (string-drop
+ -2
+ (if (not timing)
+ (-gen-insn-unit-timing model insn (model-default-unit model) nil)
+ (let ((units (timing:units (cdr timing))))
+ (string-map (lambda (iunit)
+ (-gen-insn-unit-timing model insn
+ (iunit:unit iunit)
+ (iunit:args iunit)))
+ units))))
+ " } },\n"
+ ))
+)
+
+; Generate model timing table for MODEL.
+
+(define (-gen-model-timing-table model)
+ (string-write
+ "/* Model timing data for `" (obj:name model) "'. */\n\n"
+ "static const INSN_TIMING " (gen-sym model) "_timing[] = {\n"
+ (lambda () (string-write-map (lambda (insn) (-gen-insn-timing model insn))
+ (non-alias-insns (current-insn-list))))
+ "};\n\n"
+ )
+)
+
+; Return C code to define model profiling support stuff.
+
+(define (-gen-model-profile-data)
+ (string-write
+ "/* We assume UNIT_NONE == 0 because the tables don't always terminate\n"
+ " entries with it. */\n\n"
+ (lambda () (string-write-map -gen-model-timing-table (current-model-list)))
+ )
+)
+
+; Return C code to define the model table for MACH.
+
+(define (-gen-mach-model-table mach)
+ (string-list
+ "\
+static const MODEL " (gen-sym mach) "_models[] =\n{\n"
+ (string-list-map (lambda (model)
+ (string-list " { "
+ "\"" (obj:name model) "\", "
+ "& " (gen-sym (model:mach model)) "_mach, "
+ (model:enum model) ", "
+ "TIMING_DATA (& "
+ (gen-sym model)
+ "_timing[0]), "
+ (gen-sym model) "_model_init"
+ " },\n"))
+ (find (lambda (model) (eq? (obj:name mach)
+ (obj:name (model:mach model))))
+ (current-model-list)))
+ " { 0 }\n"
+ "};\n\n"
+ )
+)
+
+; Return C code to define model init fn.
+
+(define (-gen-model-init-fn model)
+ (string-list "\
+static void\n"
+(gen-sym model) "_model_init (SIM_CPU *cpu)
+{
+ CPU_MODEL_DATA (cpu) = (void *) zalloc (sizeof (MODEL_"
+ (string-upcase (gen-sym model))
+ "_DATA));
+}\n\n"
+ )
+)
+
+; Return C code to define model data and support fns.
+
+(define (-gen-model-defns)
+ (string-write
+ (lambda () (string-write-map -gen-model-init-fn (current-model-list)))
+ "#if WITH_PROFILE_MODEL_P
+#define TIMING_DATA(td) td
+#else
+#define TIMING_DATA(td) 0
+#endif\n\n"
+ (lambda () (string-write-map -gen-mach-model-table (current-mach-list)))
+ )
+)
+
+; Return C definitions for this cpu family variant.
+
+(define (-gen-cpu-defns)
+ (string-list "\
+
+static void
+@cpu@_prepare_run (SIM_CPU *cpu)
+{
+ if (CPU_IDESC (cpu) == NULL)
+ @cpu@_init_idesc_table (cpu);
+}
+
+static const CGEN_INSN *
+@cpu@_get_idata (SIM_CPU *cpu, int inum)
+{
+ return CPU_IDESC (cpu) [inum].idata;
+}
+
+")
+)
+
+; Return C code to define the machine data.
+
+(define (-gen-mach-defns)
+ (string-list-map
+ (lambda (mach)
+ (gen-obj-sanitize
+ mach
+ (string-list "\
+static void\n"
+(gen-sym mach) "_init_cpu (SIM_CPU *cpu)
+{
+ CPU_REG_FETCH (cpu) = " (gen-sym (mach-cpu mach)) "_fetch_register;
+ CPU_REG_STORE (cpu) = " (gen-sym (mach-cpu mach)) "_store_register;
+ CPU_PC_FETCH (cpu) = " (gen-sym (mach-cpu mach)) "_h_pc_get;
+ CPU_PC_STORE (cpu) = " (gen-sym (mach-cpu mach)) "_h_pc_set;
+ CPU_GET_IDATA (cpu) = @cpu@_get_idata;
+ CPU_MAX_INSNS (cpu) = @CPU@_INSN_MAX;
+ CPU_INSN_NAME (cpu) = cgen_insn_name;
+ CPU_FULL_ENGINE_FN (cpu) = @cpu@_engine_run_full;
+#if WITH_FAST
+ CPU_FAST_ENGINE_FN (cpu) = @cpu@_engine_run_fast;
+#else
+ CPU_FAST_ENGINE_FN (cpu) = @cpu@_engine_run_full;
+#endif
+}
+
+const MACH " (gen-sym mach) "_mach =
+{
+ \"" (obj:name mach) "\", "
+ "\"" (mach-bfd-name mach) "\", "
+ (mach-enum mach) ",\n"
+ " " (number->string (cpu-word-bitsize (mach-cpu mach))) ", "
+ ; FIXME: addr-bitsize: delete
+ (number->string (cpu-word-bitsize (mach-cpu mach))) ", "
+ "& " (gen-sym mach) "_models[0], "
+ "& " (gen-sym (mach-cpu mach)) "_imp_properties,
+ " (gen-sym mach) "_init_cpu,
+ @cpu@_prepare_run
+};
+
+")))
+
+ (current-mach-list))
+)
+
+; Top level file generators.
+
+; Generate model.c
+
+(define (cgen-model.c)
+ (logit 1 "Generating " (gen-cpu-name) " model.c ...\n")
+
+ (sim-analyze-insns!)
+
+ ; Turn parallel execution support on if cpu needs it.
+ (set-with-parallel?! (state-parallel-exec?))
+
+ (string-write
+ (gen-copyright "Simulator model support for @cpu@."
+ CURRENT-COPYRIGHT CURRENT-PACKAGE)
+ "\
+#define WANT_CPU @cpu@
+#define WANT_CPU_@CPU@
+
+#include \"sim-main.h\"
+
+/* The profiling data is recorded here, but is accessed via the profiling
+ mechanism. After all, this is information for profiling. */
+
+#if WITH_PROFILE_MODEL_P
+
+"
+ -gen-model-insn-fns
+ -gen-model-profile-data
+"#endif /* WITH_PROFILE_MODEL_P */\n\n"
+
+ -gen-model-defns
+ -gen-cpu-imp-properties
+ -gen-cpu-defns
+ -gen-mach-defns
+ )
+)
diff --git a/cgen/sim-test.scm b/cgen/sim-test.scm
new file mode 100644
index 00000000000..42cf2fa32e9
--- /dev/null
+++ b/cgen/sim-test.scm
@@ -0,0 +1,244 @@
+; CPU description file generator for the simulator testsuite.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; This is invoked to build allinsn.exp and a script to run to
+; generate allinsn.s and allinsn.d.
+
+; Specify which application.
+(set! APPLICATION 'SIM-TEST)
+
+; Called before/after the .cpu file has been read.
+
+(define (sim-test-init!) (opcodes-init!))
+(define (sim-test-finish!) (opcodes-finish!))
+
+; Called after .cpu file has been read and global error checks are done.
+; We use the `tmp' member to record the syntax split up into its components.
+
+(define (sim-test-analyze!)
+ (opcodes-analyze!)
+ (map (lambda
+ (insn) (elm-xset! insn 'tmp (syntax-break-out (insn-syntax insn))))
+ (current-insn-list))
+ *UNSPECIFIED*
+)
+
+; Methods to compute test data.
+; The result is a list of strings to be inserted in the assembler
+; in the operand's position.
+
+(method-make!
+ <hw-asm> 'test-data
+ (lambda (self n)
+ ; FIXME: floating point support
+ (let ((signed (list 0 1 -1 2 -2))
+ (unsigned (list 0 1 2 3 4))
+ (mode (elm-get self 'mode)))
+ (map number->string
+ (list-take n
+ (if (eq? (mode:class mode) 'UINT)
+ unsigned
+ signed)))))
+)
+
+(method-make!
+ <keyword> 'test-data
+ (lambda (self n)
+ (let* ((values (elm-get self 'values))
+ (n (min n (length values))))
+ ; FIXME: Need to handle mach variants.
+ (map car (list-take n values))))
+)
+
+(method-make!
+ <hw-address> 'test-data
+ (lambda (self n)
+ (let ((test-data '("foodata" "4" "footext" "-4")))
+ (list-take n test-data)))
+)
+
+(method-make!
+ <hw-iaddress> 'test-data
+ (lambda (self n)
+ (let ((test-data '("footext" "4" "foodata" "-4")))
+ (list-take n test-data)))
+)
+
+(method-make-forward! <hw-register> 'indices '(test-data))
+(method-make-forward! <hw-immediate> 'values '(test-data))
+
+; This can't use method-make-forward! as we need to call op:type to
+; resolve the hardware reference.
+
+(method-make!
+ <operand> 'test-data
+ (lambda (self n)
+ (send (op:type self) 'test-data n))
+)
+
+; Given an operand, return a set of N test data.
+; e.g. For a keyword operand, return a random subset.
+; For a number, return N numbers.
+
+(define (operand-test-data op n)
+ (send op 'test-data n)
+)
+
+; Given the broken out assembler syntax string, return the list of operand
+; objects.
+
+(define (extract-operands syntax-list)
+ (let loop ((result nil) (l syntax-list))
+ (cond ((null? l) (reverse result))
+ ((object? (car l)) (loop (cons (car l) result) (cdr l)))
+ (else (loop result (cdr l)))))
+)
+
+; Given a list of operands for an instruction, return the test set
+; (all possible combinations).
+; N is the number of testcases for each operand.
+; The result has N to-the-power (length OP-LIST) elements.
+
+(define (build-test-set op-list n)
+ (let ((test-data (map (lambda (op) (operand-test-data op n)) op-list))
+ (len (length op-list)))
+ ; FIXME: Make slicker later.
+ (cond ((=? len 0) (list (list)))
+ ((=? len 1) test-data)
+ (else (list (map car test-data)))))
+)
+
+; Given an assembler expression and a set of operands build a testcase.
+; SYNTAX-LIST is a list of syntax elements (characters) and <operand> objects.
+; TEST-DATA is a list of strings, one element per operand.
+; FIXME: wip
+
+(define (build-sim-testcase syntax-list test-data)
+ (logit 3 "Building a testcase for: "
+ (map (lambda (sl)
+ (string-append " "
+ (cond ((string? sl)
+ sl)
+ ((operand? sl)
+ (obj:name sl))
+ (else
+ (with-output-to-string
+ (lambda () (display sl)))))))
+ syntax-list)
+ ", test data: "
+ (map (lambda (td) (list " " td))
+ test-data)
+ "\n")
+ (let loop ((result nil) (sl syntax-list) (td test-data))
+ ;(display (list result sl td "\n"))
+ (cond ((null? sl)
+ (string-append "\t"
+ (apply string-append (reverse result))
+ "\n"))
+ ((string? (car sl))
+ (loop (cons (car sl) result) (cdr sl) td))
+ (else (loop (cons (car td) result) (cdr sl) (cdr td)))))
+)
+
+; Generate a set of testcases for INSN.
+; FIXME: wip
+
+(define (gen-sim-test insn)
+ (logit 2 "Generating sim test set for " (obj:name insn) " ...\n")
+ (string-append
+ "\t.global " (gen-sym insn) "\n"
+ (gen-sym insn) ":\n"
+ (let* ((syntax-list (insn-tmp insn))
+ (op-list (extract-operands syntax-list))
+ (test-set (build-test-set op-list 2)))
+ (string-map (lambda (test-data)
+ (build-sim-testcase syntax-list test-data))
+ test-set))
+ )
+)
+
+; Generate the shell script that builds the .cgs files.
+; .cgs are .s files except that there may be other .s files in the directory
+; and we want the .exp driver script to easily find the files.
+;
+; Eventually it would be nice to generate as much of the testcase as possible.
+; For now we just generate the template and leave the programmer to fill in
+; the guts of the test (i.e. set up various registers, execute the insn to be
+; tested, and then verify the results).
+; Clearly some hand generated testcases will also be needed, but this
+; provides a good start for each instruction.
+
+(define (cgen-build.sh)
+ (logit 1 "Generating sim-build.sh ...\n")
+ (string-append
+ "\
+#/bin/sh
+# Generate test result data for " (current-arch-name) " simulator testing.
+# This script is machine generated.
+# It is intended to be run in the testsuite source directory.
+#
+# Syntax: /bin/sh sim-build.sh
+
+# Put results here, so we preserve the existing set for comparison.
+rm -rf tmpdir
+mkdir tmpdir
+cd tmpdir
+\n"
+
+ (string-map (lambda (insn)
+ (string-append
+ "cat <<EOF > " (gen-file-name (obj:name insn)) ".cgs\n"
+ ; FIXME: Need to record assembler line comment char in .cpu.
+ "# " (current-arch-name) " testcase for " (backslash "$" (insn-syntax insn)) "\n"
+ "# mach: "
+ (let ((machs (insn-machs insn)))
+ (if (null? machs)
+ "all"
+ (string-drop1 (string-map (lambda (mach)
+ (string-append "," mach))
+ machs))))
+ "\n\n"
+ "\t.include \"testutils.inc\"\n\n"
+ "\tstart\n\n"
+ (gen-sim-test insn)
+ "\n\tpass\n"
+ "EOF\n\n"))
+ (non-alias-insns (current-insn-list)))
+ )
+)
+
+; Generate the dejagnu allinsn.exp file that drives the tests.
+
+(define (cgen-allinsn.exp)
+ (logit 1 "Generating sim-allinsn.exp ...\n")
+ (string-append
+ "\
+# " (string-upcase (current-arch-name)) " simulator testsuite.
+
+if [istarget " (current-arch-name) "*-*-*] {
+ # load support procs (none yet)
+ # load_lib cgen.exp
+
+ # all machines
+ set all_machs \""
+ (string-drop1 (string-map (lambda (m)
+ (string-append " "
+ (gen-sym m)))
+ (current-mach-list)))
+ "\"
+
+ # The .cgs suffix is for \"cgen .s\".
+ foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.cgs]] {
+ # If we're only testing specific files and this isn't one of them,
+ # skip it.
+ if ![runtest_file_p $runtests $src] {
+ continue
+ }
+
+ run_sim_test $src $all_machs
+ }
+}\n"
+ )
+)
diff --git a/cgen/sim.scm b/cgen/sim.scm
new file mode 100644
index 00000000000..7f2b6b0a92f
--- /dev/null
+++ b/cgen/sim.scm
@@ -0,0 +1,2019 @@
+; Simulator generator support routines.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+
+; One goal of this file is to provide cover functions for all methods.
+; i.e. this file fills in the missing pieces of the interface between
+; the application independent part of CGEN (i.e. the code loaded by read.scm)
+; and the application dependent part (i.e. sim-*.scm).
+; `send' is not intended to appear in sim-*.scm.
+; [It still does but that's to be fixed.]
+
+; Specify which application.
+(set! APPLICATION 'SIMULATOR)
+
+; Cover functions for various methods.
+
+; Return the C type of something. This isn't always a mode.
+
+(define (gen-type self) (send self 'gen-type))
+
+; Return the C type of an index's value or #f if not needed (scalar).
+
+(define (gen-index-type op sfmt)
+ (let ((index-mode (send op 'get-index-mode)))
+ (if index-mode
+ (mode:c-type index-mode)
+ #f))
+)
+
+; Misc. state info.
+
+; Currently supported options:
+; with-scache
+; generate code to use the scache
+; This is an all or nothing option, either scache is used or it's not.
+; with-profile fn|sw
+; generate code to do profiling in the semantic function
+; code (fn) or in the semantic switch (sw)
+; with-generic-write
+; For architectures that have parallel execution.
+; Execute the semantics by recording the results in a generic buffer,
+; and doing a post-semantics writeback pass.
+; with-parallel-only
+; Only generate parallel versions of each insn.
+; copyright fsf|cygnus
+; emit an FSF or Cygnus copyright (temporary, pending decision)
+; package gnusim|cygsim
+; indicate the software package
+
+; #t if the scache is being used
+(define -with-scache? #f)
+(define (with-scache?) -with-scache?)
+
+; #t if we're generating profiling code
+; Each of the function and switch semantic code can have profiling.
+; The options as passed are stored in -with-profile-{fn,sw}?, and
+; -with-profile? is set at code generation time.
+(define -with-profile-fn? #f)
+(define -with-profile-sw? #f)
+(define -with-profile? #f)
+(define (with-profile?) -with-profile?)
+(define (with-any-profile?) (or -with-profile-fn? -with-profile-sw?))
+
+; Handle parallel execution with generic writeback pass.
+(define -with-generic-write? #f)
+(define (with-generic-write?) -with-generic-write?)
+
+; Only generate parallel versions of each insn.
+(define -with-parallel-only? #f)
+(define (with-parallel-only?) -with-parallel-only?)
+
+; String containing copyright text.
+(define CURRENT-COPYRIGHT #f)
+
+; String containing text defining the package we're generating code for.
+(define CURRENT-PACKAGE #f)
+
+; Initialize the options.
+
+(define (option-init!)
+ (set! -with-scache? #f)
+ (set! -with-profile-fn? #f)
+ (set! -with-profile-sw? #f)
+ (set! -with-generic-write? #f)
+ (set! -with-parallel-only? #f)
+ (set! CURRENT-COPYRIGHT copyright-fsf)
+ (set! CURRENT-PACKAGE package-gnu-simulators)
+ *UNSPECIFIED*
+)
+
+; Handle an option passed in from the command line.
+
+(define (option-set! name value)
+ (case name
+ ((with-scache) (set! -with-scache? #t))
+ ((with-profile) (cond ((equal? value '("fn"))
+ (set! -with-profile-fn? #t))
+ ((equal? value '("sw"))
+ (set! -with-profile-sw? #t))
+ (else (error "invalid with-profile value" value))))
+ ((with-generic-write) (set! -with-generic-write? #t))
+ ((with-parallel-only) (set! -with-parallel-only? #t))
+ ((copyright) (cond ((equal? value '("fsf"))
+ (set! CURRENT-COPYRIGHT copyright-fsf))
+ ((equal? value '("cygnus"))
+ (set! CURRENT-COPYRIGHT copyright-cygnus))
+ (else (error "invalid copyright value" value))))
+ ((package) (cond ((equal? value '("gnusim"))
+ (set! CURRENT-PACKAGE package-gnu-simulators))
+ ((equal? value '("cygsim"))
+ (set! CURRENT-PACKAGE package-cygnus-simulators))
+ (else (error "invalid package value" value))))
+ (else (error "unknown option" name))
+ )
+ *UNSPECIFIED*
+)
+
+; #t if the cpu can execute insns parallely.
+; This one isn't passed on the command line, but we follow the convention
+; of prefixing these things with `with-'.
+; While processing operand reading (or writing), parallel execution support
+; needs to be turned off, so it is up to the appropriate cgen-foo.c proc to
+; set-with-parallel?! appropriately.
+(define -with-parallel? #f)
+(define (with-parallel?) -with-parallel?)
+(define (set-with-parallel?! flag) (set! -with-parallel? flag))
+
+; Kind of parallel support.
+; If 'read, read pre-processing is done.
+; If 'write, write post-processing is done.
+; ??? At present we always use write post-processing, though the previous
+; version used read pre-processing. Not sure supporting both is useful
+; in the long run.
+(define -with-parallel-kind 'write)
+; #t if parallel support is provided by read pre-processing.
+(define (with-parallel-read?)
+ (and -with-parallel? (eq? -with-parallel-kind 'read))
+)
+; #t if parallel support is provided by write post-processing.
+(define (with-parallel-write?)
+ (and -with-parallel? (eq? -with-parallel-kind 'write))
+)
+
+; Misc. utilities.
+
+; All machine generated cpu elements are accessed through a cover macro
+; to hide the details of the underlying implementation.
+
+(define c-cpu-macro "CPU")
+
+(define (gen-cpu-ref sym)
+ (string-append c-cpu-macro " (" sym ")")
+)
+
+; Instruction field support code.
+
+; Return a <c-expr> object of the value of an ifield.
+
+(define (-cxmake-ifld-val mode f)
+ (if (with-scache?)
+ ; ??? Perhaps a better way would be to defer evaluating the src of a
+ ; set until the method processing the dest.
+ (cx:make-with-atlist mode (gen-ifld-argbuf-ref f)
+ (atlist-make "" (bool-attr-make 'CACHED #t)))
+ (cx:make mode (gen-extracted-ifld-value f)))
+)
+
+; Type system.
+
+; Methods:
+; gen-type - return C code representing the type
+; gen-sym-decl - generate decl using the provided symbol
+; gen-sym-get-macro - generate GET macro for accessing CPU elements
+; gen-sym-set-macro - generate SET macro for accessing CPU elements
+
+; Scalar type
+
+(method-make!
+ <scalar> 'gen-type
+ (lambda (self) (mode:c-type (elm-get self 'mode)))
+)
+
+(method-make!
+ <scalar> 'gen-sym-decl
+ (lambda (self sym comment)
+ (string-append
+ " /* " comment " */\n"
+ " " (send self 'gen-type) " "
+ (gen-c-symbol sym) ";\n"))
+)
+
+(method-make!
+ <scalar> 'gen-sym-get-macro
+ (lambda (self sym comment)
+ (let ((sym (gen-c-symbol sym)))
+ (gen-get-macro sym "" (gen-cpu-ref sym))))
+)
+
+(method-make!
+ <scalar> 'gen-sym-set-macro
+ (lambda (self sym comment)
+ (let ((sym (gen-c-symbol sym)))
+ (gen-set-macro sym "" (gen-cpu-ref sym))))
+)
+
+(method-make! <scalar> 'gen-ref (lambda (self sym index estate) sym))
+
+; Array type
+
+(method-make!
+ <array> 'gen-type
+ (lambda (self) (mode:c-type (elm-get self 'mode)))
+)
+
+(method-make!
+ <array> 'gen-sym-decl
+ (lambda (self sym comment)
+ (string-append
+ " /* " comment " */\n"
+ " " (send self 'gen-type) " "
+ (gen-c-symbol sym)
+ (gen-array-ref (elm-get self 'dimensions))
+ ";\n")
+ )
+)
+
+(method-make!
+ <array> 'gen-sym-get-macro
+ (lambda (self sym comment)
+ (let ((sym (gen-c-symbol sym))
+ (rank (length (elm-get self 'dimensions))))
+ (string-append
+ "#define GET_" (string-upcase sym)
+ "(" (string-drop 2 (gen-macro-args rank)) ") "
+ (gen-cpu-ref sym) (gen-array-ref (macro-args rank)) "\n"
+ )))
+)
+
+(method-make!
+ <array> 'gen-sym-set-macro
+ (lambda (self sym comment)
+ (let ((sym (gen-c-symbol sym))
+ (rank (length (elm-get self 'dimensions))))
+ (string-append
+ "#define SET_" (string-upcase sym)
+ "(" (string-drop 2 (gen-macro-args rank)) ", x) "
+ "(" (gen-cpu-ref sym) (gen-array-ref (macro-args rank))
+ " = (x))\n"
+ )))
+)
+
+; Return a reference to the array.
+; SYM is the name of the array.
+; INDEX is either a single index object or a (possibly empty) list of objects,
+; one object per dimension.
+
+(method-make!
+ <array> 'gen-ref
+ (lambda (self sym index estate)
+ (let ((gen-index1 (lambda (idx)
+ (string-append "["
+ (-gen-hw-index idx estate)
+ "]"))))
+ (string-append sym
+ (cond ((list? index) (string-map gen-index1 index))
+ (else (gen-index1 index))))))
+)
+
+; Integers
+;
+;(method-make!
+; <integer> 'gen-type
+; (lambda (self)
+; (mode:c-type (mode-find (elm-get self 'bits)
+; (if (has-attr? self 'UNSIGNED)
+; 'UINT 'INT)))
+; )
+;)
+;
+;(method-make! <integer> 'gen-sym-decl (lambda (self sym comment) ""))
+;(method-make! <integer> 'gen-sym-get-macro (lambda (self sym comment) ""))
+;(method-make! <integer> 'gen-sym-set-macro (lambda (self sym comment) ""))
+
+; Hardware descriptions support code.
+;
+; Various operations are required for each h/w object to support the various
+; things the simulator will want to do with it.
+;
+; Methods:
+; gen-decl
+; gen-get-macro - Generate definition of the GET access macro.
+; gen-set-macro - Generate definition of the SET access macro.
+; gen-write - Same as gen-read except done on output operands
+; cxmake-get - Return a <c-expr> object to fetch the value.
+; gen-set-quiet - Set the value.
+; ??? Could just call this gen-set as there is no gen-set-trace
+; but for consistency with the messages passed to operands
+; we use this same.
+; gen-type - C type to use to record value.
+; ??? Delete and just use get-mode?
+; save-index? - return #t if an index needs to be saved for parallel
+; execution post-write processing
+; gen-profile-decl
+; gen-record-profile
+; get-mode
+; gen-profile-locals
+; gen-sym-decl - Return a C declaration using the provided symbol.
+; gen-sym-get-macro - Generate default GET access macro.
+; gen-sym-set-macro - Generate default SET access macro.
+; gen-ref - Return a C reference to the object.
+
+; Generate CPU state struct entries.
+
+(method-make!
+ <hardware-base> 'gen-decl
+ (lambda (self)
+ (send self 'gen-sym-decl (obj:name self) (obj:comment self)))
+)
+
+(method-make-virtual! <hardware-base> 'gen-sym-decl (lambda (self sym comment) ""))
+
+; Return a C reference to a hardware object.
+
+(method-make! <hardware-base> 'gen-ref (lambda (self sym index estate) sym))
+
+; Each hardware type must provide its own gen-write method.
+
+(method-make!
+ <hardware-base> 'gen-write
+ (lambda (self estate index mode sfmt op access-macro)
+ (error "gen-write method not overridden:" self))
+)
+
+; gen-type handler, must be overridden
+
+(method-make-virtual!
+ <hardware-base> 'gen-type
+ (lambda (self) (error "gen-type not overridden:" self))
+)
+
+(method-make! <hardware-base> 'gen-profile-decl (lambda (self) ""))
+
+; Default gen-record-profile method.
+
+(method-make!
+ <hardware-base> 'gen-record-profile
+ (lambda (self index sfmt estate)
+ "") ; nothing to do
+)
+
+; Default cxmake-get method.
+; Return a <c-expr> object of the value of SELF.
+; ESTATE is the current rtl evaluator state.
+; INDEX is a <hw-index> object. It must be an ifield.
+; SELECTOR is a hardware selector RTX.
+
+(method-make!
+ <hardware-base> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (if (not (eq? 'ifield (hw-index:type index)))
+ (error "not an ifield hw-index" index))
+ (-cxmake-ifld-val mode (hw-index:value index)))
+)
+
+; Handle gen-get-macro/gen-set-macro.
+
+(method-make!
+ <hardware-base> 'gen-get-macro
+ (lambda (self)
+ "")
+)
+
+(method-make!
+ <hardware-base> 'gen-set-macro
+ (lambda (self)
+ "")
+)
+
+; PC support
+
+; 'gen-set-quiet helper for PC values.
+; NEWVAL is a <c-expr> object of the value to be assigned.
+; If OPTIONS contains #:direct, set the PC directly, bypassing semantic
+; code considerations.
+; ??? OPTIONS support wip. Probably want a new form (or extend existing form)
+; of rtx: that takes a variable number of named arguments.
+; ??? Another way to get #:direct might be (raw-reg h-pc).
+
+(define (-hw-gen-set-quiet-pc self estate mode index selector newval . options)
+ (if (not (send self 'pc?)) (error "Not a PC:" self))
+ (cond ((memq #:direct options)
+ (-hw-gen-set-quiet self estate mode index selector newval))
+ ((has-attr? newval 'CACHED)
+ (string-append "SEM_BRANCH_VIA_CACHE (current_cpu, sem_arg, "
+ (cx:c newval)
+ ", vpc);\n"))
+ (else
+ (string-append "SEM_BRANCH_VIA_ADDR (current_cpu, sem_arg, "
+ (cx:c newval)
+ ", vpc);\n")))
+)
+
+(method-make! <hw-pc> 'gen-set-quiet -hw-gen-set-quiet-pc)
+
+; Handle updates of the pc during parallel execution.
+; This is done in a post-processing pass after semantic evaluation.
+; SFMT is the <sformat>.
+; OP is the operand.
+; ACCESS-MACRO is the runtime C macro to use to fetch indices computed
+; during semantic evaluation.
+;
+; ??? This wouldn't be necessary if gen-set-quiet were a virtual method.
+; At this point I'm reluctant to willy nilly make methods virtual.
+
+(method-make!
+ <hw-pc> 'gen-write
+ (lambda (self estate index mode sfmt op access-macro)
+ (string-append " "
+ (send self 'gen-set-quiet estate VOID index hw-selector-default
+ (cx:make DFLT (string-append access-macro
+ " (" (gen-sym op) ")")))))
+)
+
+(method-make!
+ <hw-pc> 'cxmake-skip
+ (lambda (self estate yes?)
+ (cx:make VOID
+ (string-append "if ("
+ yes?
+ ")\n"
+ " SEM_SKIP_INSN (current_cpu, sem_arg, vpc);\n")))
+)
+
+; Registers.
+
+; Forward these methods onto TYPE.
+(method-make-virtual-forward! <hw-register> 'type '(gen-type gen-sym-decl))
+(method-make-forward! <hw-register> 'type '(gen-ref
+ gen-sym-get-macro
+ gen-sym-set-macro))
+
+; For parallel instructions supported by queueing outputs for later update,
+; return a boolean indicating if an index needs to be recorded.
+; An example of when the index isn't needed is if the index can be determined
+; during extraction.
+
+(method-make!
+ <hw-register> 'save-index?
+ (lambda (self op)
+ ; FIXME: Later handle case where register number is determined at runtime.
+ #f)
+)
+
+; Handle updates of registers during parallel execution.
+; This is done in a post-processing pass after semantic evaluation.
+; SFMT is the <sformat>.
+; OP is the <operand>.
+; ACCESS-MACRO is the runtime C macro to use to fetch indices computed
+; during semantic evaluation.
+; FIXME: May need mode of OP.
+
+(method-make!
+ <hw-register> 'gen-write
+ (lambda (self estate index mode sfmt op access-macro)
+ ; First get a hw-index object to use during indexing.
+ ; Some indices, e.g. memory addresses, are computed during semantic
+ ; evaluation. Others are computed during the extraction phase.
+ (let ((index (send index 'get-write-index self sfmt op access-macro)))
+ (string-append " "
+ (send self 'gen-set-quiet estate mode index hw-selector-default
+ (cx:make DFLT (string-append access-macro
+ " (" (gen-sym op) ")"))))))
+)
+
+(method-make!
+ <hw-register> 'gen-profile-decl
+ (lambda (self)
+ (string-append
+ " /* " (obj:comment self) " */\n"
+ " unsigned long " (gen-c-symbol (obj:name self)) ";\n"))
+)
+
+(method-make!
+ <hw-register> 'gen-record-profile
+ (lambda (self index sfmt estate)
+ ; FIXME: Need to handle scalars.
+ (-gen-hw-index-raw index estate))
+)
+
+(method-make!
+ <hw-register> 'gen-get-macro
+ (lambda (self)
+ (let ((getter (elm-get self 'get))
+ (mode (send self 'get-mode)))
+ (if getter
+ (let ((args (car getter))
+ (expr (cadr getter)))
+ (gen-get-macro (gen-sym self)
+ (if (hw-scalar? self) "" "index")
+ (rtl-c mode expr
+ (if (hw-scalar? self)
+ nil
+ (list (list (car args) 'UINT "index")))
+ #:rtl-cover-fns? #t)))
+ (send self 'gen-sym-get-macro
+ (obj:name self) (obj:comment self)))))
+)
+
+(method-make!
+ <hw-register> 'gen-set-macro
+ (lambda (self)
+ (let ((setter (elm-get self 'set))
+ (mode (send self 'get-mode)))
+ (if setter
+ (let ((args (car setter))
+ (expr (cadr setter)))
+ (gen-set-macro2 (gen-sym self)
+ (if (hw-scalar? self)
+ ""
+ "index")
+ "x"
+ (rtl-c VOID ; not `mode', sets have mode VOID
+ expr
+ (if (hw-scalar? self)
+ (list (list (car args) (hw-mode self) "(x)"))
+ (list (list (car args) 'UINT "(index)")
+ (list (cadr args) (hw-mode self) "(x)")))
+ #:rtl-cover-fns? #t #:macro? #t)))
+ (send self 'gen-sym-set-macro
+ (obj:name self) (obj:comment self)))))
+)
+
+; Utility to build a <c-expr> object to fetch the value of a register.
+
+(define (-hw-cxmake-get hw estate mode index selector)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (send hw 'get-mode)
+ mode))
+ (getter (hw-getter hw)))
+ ; If the register is accessed via a cover function/macro, do it.
+ ; Otherwise fetch the value from the cached address or from the CPU struct.
+ (cx:make mode
+ (cond (getter
+ (let ((scalar? (hw-scalar? hw))
+ (c-index (-gen-hw-index index estate)))
+ (string-append "GET_"
+ (string-upcase (gen-sym hw))
+ " ("
+ (if scalar? "" c-index)
+ ")")))
+ ((and (hw-cache-addr? hw) ; FIXME: redo test
+ (eq? 'ifield (hw-index:type index)))
+ (string-append
+ "* "
+ (if (with-scache?)
+ (gen-hw-index-argbuf-ref index)
+ (gen-hw-index-argbuf-name index))))
+ (else (gen-cpu-ref (send hw 'gen-ref
+ (gen-sym hw) index estate))))))
+)
+
+(method-make! <hw-register> 'cxmake-get -hw-cxmake-get)
+
+; raw-reg: support
+; ??? raw-reg: support is wip
+
+(method-make!
+ <hw-register> 'cxmake-get-raw
+ (lambda (self estate mode index selector)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (send self 'get-mode)
+ mode)))
+ (cx:make mode (gen-cpu-ref (send self 'gen-ref
+ (gen-sym self) index estate)))))
+)
+
+; Utilities to generate C code to assign a variable to a register.
+
+(define (-hw-gen-set-quiet hw estate mode index selector newval)
+ (let ((setter (hw-setter hw)))
+ (cond (setter
+ (let ((scalar? (hw-scalar? hw))
+ (c-index (-gen-hw-index index estate)))
+ (string-append "SET_"
+ (string-upcase (gen-sym hw))
+ " ("
+ (if scalar? "" (string-append c-index ", "))
+ (cx:c newval)
+ ");\n")))
+ ((and (hw-cache-addr? hw) ; FIXME: redo test
+ (eq? 'ifield (hw-index:type index)))
+ (string-append "* "
+ (if (with-scache?)
+ (gen-hw-index-argbuf-ref index)
+ (gen-hw-index-argbuf-name index))
+ " = " (cx:c newval) ";\n"))
+ (else (string-append (gen-cpu-ref (send hw 'gen-ref
+ (gen-sym hw) index estate))
+ " = " (cx:c newval) ";\n"))))
+)
+
+(method-make! <hw-register> 'gen-set-quiet -hw-gen-set-quiet)
+
+; raw-reg: support
+; ??? wip
+
+(method-make!
+ <hw-register> 'gen-set-quiet-raw
+ (lambda (self estate mode index selector newval)
+ (string-append (gen-cpu-ref (send self 'gen-ref
+ (gen-sym self) index estate))
+ " = " (cx:c newval) ";\n"))
+)
+
+; Return name of C access function for getting/setting a register.
+
+(define (gen-reg-getter-fn hw prefix)
+ (string-append prefix "_" (gen-sym hw) "_get")
+)
+
+(define (gen-reg-setter-fn hw prefix)
+ (string-append prefix "_" (gen-sym hw) "_set")
+)
+
+; Generate decls for access fns of register HW, beginning with
+; PREFIX, using C type TYPE.
+; SCALAR? is #t if the register is a scalar. Otherwise it is #f and the
+; register is a bank of registers.
+
+(define (gen-reg-access-decl hw prefix type scalar?)
+ (string-append
+ type " "
+ (gen-reg-getter-fn hw prefix)
+ " (SIM_CPU *"
+ (if scalar? "" ", UINT")
+ ");\n"
+ "void "
+ (gen-reg-setter-fn hw prefix)
+ " (SIM_CPU *, "
+ (if scalar? "" "UINT, ")
+ type ");\n"
+ )
+)
+
+; Generate defns of access fns of register HW, beginning with
+; PREFIX, using C type TYPE.
+; SCALAR? is #t if the register is a scalar. Otherwise it is #f and the
+; register is a bank of registers.
+; GET/SET-CODE are C fragments to get/set the value.
+; ??? Inlining left for later.
+
+(define (gen-reg-access-defn hw prefix type scalar? get-code set-code)
+ (string-append
+ "/* Get the value of " (obj:name hw) ". */\n\n"
+ type "\n"
+ (gen-reg-getter-fn hw prefix)
+ " (SIM_CPU *current_cpu"
+ (if scalar? "" ", UINT regno")
+ ")\n{\n"
+ get-code
+ "}\n\n"
+ "/* Set a value for " (obj:name hw) ". */\n\n"
+ "void\n"
+ (gen-reg-setter-fn hw prefix)
+ " (SIM_CPU *current_cpu, "
+ (if scalar? "" "UINT regno, ")
+ type " newval)\n"
+ "{\n"
+ set-code
+ "}\n\n")
+)
+
+; Memory support.
+
+(method-make!
+ <hw-memory> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (hw-mode self)
+ mode))
+ (default-selector? (hw-selector-default? selector)))
+ (cx:make mode
+ (string-append "GETMEM" (obj:name mode)
+ (if default-selector? "" "ASI")
+ " ("
+ "current_cpu, pc, "
+ (-gen-hw-index index estate)
+ (if default-selector?
+ ""
+ (string-append ", "
+ (-gen-hw-selector selector)))
+ ")"))))
+)
+
+(method-make!
+ <hw-memory> 'gen-set-quiet
+ (lambda (self estate mode index selector newval)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (hw-mode self)
+ mode))
+ (default-selector? (hw-selector-default? selector)))
+ (string-append "SETMEM" (obj:name mode)
+ (if default-selector? "" "ASI")
+ " ("
+ "current_cpu, pc, "
+ (-gen-hw-index index estate)
+ (if default-selector?
+ ""
+ (string-append ", "
+ (-gen-hw-selector selector)))
+ ", " (cx:c newval) ");\n")))
+)
+
+(method-make-virtual-forward! <hw-memory> 'type '(gen-type))
+(method-make-virtual! <hw-memory> 'gen-sym-decl (lambda (self sym comment) ""))
+(method-make! <hw-memory> 'gen-sym-get-macro (lambda (self sym comment) ""))
+(method-make! <hw-memory> 'gen-sym-set-macro (lambda (self sym comment) ""))
+
+; For parallel instructions supported by queueing outputs for later update,
+; return the type of the index or #f if not needed.
+
+(method-make!
+ <hw-memory> 'save-index?
+ (lambda (self op)
+ ; In the case of the complete memory address being an immediate
+ ; argument, we can return #f (later).
+ AI)
+)
+
+(method-make!
+ <hw-memory> 'gen-write
+ (lambda (self estate index mode sfmt op access-macro)
+ (let ((index (send index 'get-write-index self sfmt op access-macro)))
+ (string-append " "
+ (send self 'gen-set-quiet estate mode index
+ hw-selector-default
+ (cx:make DFLT (string-append access-macro " ("
+ (gen-sym op)
+ ")"))))))
+)
+
+; Immediates, addresses.
+
+; Forward these methods onto TYPE.
+(method-make-virtual-forward! <hw-immediate> 'type '(gen-type gen-sym-decl))
+(method-make-forward! <hw-immediate> 'type '(gen-sym-get-macro
+ gen-sym-set-macro))
+
+(method-make!
+ <hw-immediate> 'gen-write
+ (lambda (self estate index mode sfmt op access-macro)
+ (error "gen-write of <hw-immediate> shouldn't happen"))
+)
+
+; FIXME.
+(method-make-virtual! <hw-address> 'gen-type (lambda (self) "ADDR"))
+(method-make-virtual! <hw-address> 'gen-sym-decl (lambda (self sym comment) ""))
+(method-make! <hw-address> 'gen-sym-get-macro (lambda (self sym comment) ""))
+(method-make! <hw-address> 'gen-sym-set-macro (lambda (self sym comment) ""))
+
+; Return a <c-expr> object of the value of SELF.
+; ESTATE is the current rtl evaluator state.
+; INDEX is a hw-index object. It must be an ifield.
+; Needed because we record our own copy of the ifield in ARGBUF.
+; SELECTOR is a hardware selector RTX.
+
+(method-make!
+ <hw-address> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (if (not (eq? 'ifield (hw-index:type index)))
+ (error "not an ifield hw-index" index))
+ (if (with-scache?)
+ (cx:make mode (gen-hw-index-argbuf-ref index))
+ (cx:make mode (gen-hw-index-argbuf-name index))))
+)
+
+(method-make!
+ <hw-address> 'gen-write
+ (lambda (self estate index mode sfmt op access-macro)
+ (error "gen-write of <hw-address> shouldn't happen"))
+)
+
+; FIXME: revisit.
+(method-make-virtual! <hw-iaddress> 'gen-type (lambda (self) "IADDR"))
+
+; Return a <c-expr> object of the value of SELF.
+; ESTATE is the current rtl evaluator state.
+; INDEX is a <hw-index> object. It must be an ifield.
+; Needed because we record our own copy of the ifield in ARGBUF,
+; *and* because we want to record in the result the 'CACHED attribute
+; since instruction addresses based on ifields are fixed [and thus cacheable].
+; SELECTOR is a hardware selector RTX.
+
+(method-make!
+ <hw-iaddress> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (if (not (eq? 'ifield (hw-index:type index)))
+ (error "not an ifield hw-index" index))
+ (if (with-scache?)
+ ; ??? Perhaps a better way would be to defer evaluating the src of a
+ ; set until the method processing the dest.
+ (cx:make-with-atlist mode (gen-hw-index-argbuf-ref index)
+ (atlist-make "" (bool-attr-make 'CACHED #t)))
+ (cx:make mode (gen-hw-index-argbuf-name index))))
+)
+
+; Hardware index support code.
+
+; Return the index to use by the gen-write method.
+; In the cases where this is needed (the index isn't known until insn
+; execution time), the index is computed along with the value to be stored,
+; so this is easy.
+
+(method-make!
+ <hw-index> 'get-write-index
+ (lambda (self hw sfmt op access-macro)
+ (if (memq (hw-index:type self) '(scalar constant str-expr ifield))
+ self
+ (let ((index-mode (send hw 'get-index-mode)))
+ (if index-mode
+ (make <hw-index> 'anonymous 'str-expr index-mode
+ (string-append access-macro " (" (-op-index-name op) ")"))
+ (hw-index-scalar)))))
+)
+
+; Return the name of the PAREXEC structure member holding a hardware index
+; for operand OP.
+
+(define (-op-index-name op)
+ (string-append (gen-sym op) "_idx")
+)
+
+; Cover fn to hardware indices to generate the actual C code.
+; INDEX is the hw-index object (i.e. op:index).
+; The result is a string of C code.
+; FIXME:wip
+
+(define (-gen-hw-index-raw index estate)
+ (let ((type (hw-index:type index))
+ (mode (hw-index:mode index))
+ (value (hw-index:value index)))
+ (case type
+ ((scalar) "")
+ ; special case UINT to cut down on unnecessary verbosity.
+ ; ??? May wish to handle more similarily.
+ ((constant) (if (mode:eq? 'UINT mode)
+ (number->string value)
+ (string-append "((" (mode:c-type mode) ") "
+ (number->string value)
+ ")")))
+ ((str-expr) value)
+ ((rtx) (rtl-c-with-estate estate mode value))
+ ((ifield) (if (= (ifld-length value) 0)
+ ""
+ (gen-extracted-ifld-value value)))
+ ((operand) (cx:c (send value 'cxmake-get estate mode (op:index value)
+ (op:selector value) #f)))
+ (else (error "-gen-hw-index-raw: invalid index:" index))))
+)
+
+; Same as -gen-hw-index-raw except used where speedups are possible.
+; e.g. doing array index calcs at extraction time.
+
+(define (-gen-hw-index index estate)
+ (let ((type (hw-index:type index))
+ (mode (hw-index:mode index))
+ (value (hw-index:value index)))
+ (case type
+ ((scalar) "")
+ ((constant) (string-append "((" (mode:c-type mode) ") "
+ (number->string value)
+ ")"))
+ ((str-expr) value)
+ ((rtx) (rtl-c-with-estate estate mode value))
+ ((ifield) (if (= (ifld-length value) 0)
+ ""
+ (cx:c (-cxmake-ifld-val mode value))))
+ ((operand) (cx:c (send value 'cxmake-get estate mode (op:index value)
+ (op:selector value))))
+ (else (error "-gen-hw-index: invalid index:" index))))
+)
+
+; Return address where HW is stored.
+
+(define (-gen-hw-addr hw estate index)
+ (let ((setter (hw-setter hw)))
+ (cond ((and (hw-cache-addr? hw) ; FIXME: redo test
+ (eq? 'ifield (hw-index:type index)))
+ (if (with-scache?)
+ (gen-hw-index-argbuf-ref index)
+ (gen-hw-index-argbuf-name index)))
+ (else
+ (string-append "& "
+ (gen-cpu-ref (send hw 'gen-ref
+ (gen-sym hw) index estate))))))
+)
+
+; Return a <c-expr> object of the value of a hardware index.
+
+(method-make!
+ <hw-index> 'cxmake-get
+ (lambda (self estate mode)
+ (let ((mode (if (mode:eq? 'DFLT mode) (elm-get self 'mode) mode)))
+ ; If MODE is VOID, abort.
+ (if (mode:eq? 'VOID mode)
+ (error "hw-index:cxmake-get: result needs a mode" self))
+ (cx:make (if (mode:host? mode)
+ ; FIXME: Temporary hack to generate same code as before.
+ (let ((xmode (object-copy-top mode)))
+ (obj-cons-attr! xmode (bool-attr-make 'FORCE-C #t))
+ xmode)
+ mode)
+ (-gen-hw-index self estate))))
+)
+
+; Hardware selector support code.
+
+; Generate C code for SEL.
+
+(define (-gen-hw-selector sel)
+ (rtl-c 'INT sel nil)
+)
+
+; Instruction operand support code.
+
+; Methods:
+; gen-type - Return C type to use to hold operand's value.
+; gen-read - Record an operand's value prior to parallely executing
+; several instructions. Not used if gen-write used.
+; gen-write - Write back an operand's value after parallely executing
+; several instructions. Not used if gen-read used.
+; cxmake-get - Return C code to fetch the value of an operand.
+; gen-set-quiet - Return C code to set the value of an operand.
+; gen-set-trace - Return C code to set the value of an operand, and print
+; a result trace message. ??? Ideally this will go away when
+; trace record support is complete.
+
+; Return the C type of an operand.
+; Generally we forward things on to TYPE, but for the actual type we need to
+; use the get-mode method.
+
+;(method-make-forward! <operand> 'type '(gen-type))
+(method-make!
+ <operand> 'gen-type
+ (lambda (self)
+ ; First get the mode.
+ (let ((mode (send self 'get-mode)))
+ ; If it's VOID use the type's type.
+ (if (mode:eq? 'DFLT mode)
+ (send (op:type self) 'gen-type)
+ (mode:c-type mode))))
+)
+
+; Extra pc operand methods.
+
+(method-make!
+ <pc> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (send self 'get-mode)
+ mode)))
+ ; The enclosing function must set `pc' to the correct value.
+ (cx:make mode "pc")))
+)
+
+(method-make!
+ <pc> 'cxmake-skip
+ (lambda (self estate yes?)
+ (send (op:type self) 'cxmake-skip estate
+ (rtl-c INT yes? nil #:rtl-cover-fns? #t)))
+)
+
+; For parallel write post-processing, we don't want to defer setting the pc.
+; ??? Not sure anymore.
+;(method-make!
+; <pc> 'gen-set-quiet
+; (lambda (self estate mode index selector newval)
+; (-op-gen-set-quiet self estate mode index selector newval)))
+;(method-make!
+; <pc> 'gen-set-trace
+; (lambda (self estate mode index selector newval)
+; (-op-gen-set-trace self estate mode index selector newval)))
+
+; Name of C macro to access parallel execution operand support.
+
+(define -par-operand-macro "OPRND")
+
+; Return C code to fetch an operand's value and save it away for the
+; semantic handler. This is used to handle parallel execution of several
+; instructions where all inputs of all insns are read before any outputs are
+; written.
+; For operands, the word `read' is only used in this context.
+
+(define (op:read op sfmt)
+ (let ((estate (estate-make-for-normal-rtl-c nil nil)))
+ (send op 'gen-read estate sfmt -par-operand-macro))
+)
+
+; Return C code to write an operand's value.
+; This is used to handle parallel execution of several instructions where all
+; outputs are written to temporary spots first, and then a final
+; post-processing pass is run to update cpu state.
+; For operands, the word `write' is only used in this context.
+
+(define (op:write op sfmt)
+ (let ((estate (estate-make-for-normal-rtl-c nil nil)))
+ (send op 'gen-write estate sfmt -par-operand-macro))
+)
+
+; Default gen-read method.
+; This is used to help support targets with parallel insns.
+; Either this or gen-write (but not both) is used.
+
+(method-make!
+ <operand> 'gen-read
+ (lambda (self estate sfmt access-macro)
+ (string-append " "
+ access-macro " ("
+ (gen-sym self)
+ ") = "
+ ; Pass #f for the index -> use the operand's builtin index.
+ ; Ditto for the selector.
+ (cx:c (send self 'cxmake-get estate DFLT #f #f))
+ ";\n"))
+)
+
+; Forward gen-write onto the <hardware> object.
+
+(method-make!
+ <operand> 'gen-write
+ (lambda (self estate sfmt access-macro)
+ (let ((write-back-code (send (op:type self) 'gen-write estate
+ (op:index self) (op:mode self)
+ sfmt self access-macro)))
+ ; If operand is conditionally written, we have to check that first.
+ ; ??? If two (or more) operands are written based on the same condition,
+ ; all the tests can be collapsed together. Not sure that's a big
+ ; enough win yet.
+ (if (op:cond? self)
+ (string-append " if (written & (1 << "
+ (number->string (op:num self))
+ "))\n"
+ " {\n"
+ " " write-back-code
+ " }\n")
+ write-back-code)))
+)
+
+; Return <c-expr> object to get the value of an operand.
+; ESTATE is the current rtl evaluator state.
+; If INDEX is non-#f use it, otherwise use (op:index self).
+; This special handling of #f for INDEX is *only* supported for operands
+; in cxmake-get, gen-set-quiet, and gen-set-trace.
+; Ditto for SELECTOR.
+
+(method-make!
+ <operand> 'cxmake-get
+ (lambda (self estate mode index selector)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (send self 'get-mode)
+ mode))
+ (index (if index index (op:index self)))
+ (selector (if selector selector (op:selector self))))
+ ; If the instruction could be parallely executed with others and we're
+ ; doing read pre-processing, the operand has already been fetched, we
+ ; just have to grab the cached value.
+ ; ??? reg-raw: support wip
+ (cond ((obj-has-attr? self 'RAW)
+ (send (op:type self) 'cxmake-get-raw estate mode index selector))
+ ((with-parallel-read?)
+ (cx:make-with-atlist mode
+ (string-append -par-operand-macro
+ " (" (gen-sym self) ")")
+ nil)) ; FIXME: want CACHED attr if present
+ ((op:getter self)
+ (let ((args (car (op:getter self)))
+ (expr (cadr (op:getter self))))
+ (rtl-c mode expr
+ (if (= (length args) 0)
+ nil
+ (list (list (car args) 'UINT index)))
+ #:rtl-cover-fns? #t)))
+ (else
+ (send (op:type self) 'cxmake-get estate mode index selector)))))
+)
+
+; Utilities to implement gen-set-quiet/gen-set-trace.
+
+(define (-op-gen-set-quiet op estate mode index selector newval)
+ (send (op:type op) 'gen-set-quiet estate mode index selector newval)
+)
+
+; Return C code to call the appropriate queued-write handler.
+; ??? wip
+
+(define (-op-gen-queued-write op estate mode index selector newval)
+ (let* ((hw (op:type op))
+ (setter (hw-setter hw))
+ (sem-mode (mode:sem-mode mode)))
+ (string-append
+ " "
+ "sim_queue_"
+ ; FIXME: clean up (pc? op) vs (memory? hw)
+ ; FIXME: (send 'pc?) is a temporary hack, (pc? op) didn't work
+ (cond ((send hw 'pc?)
+ (string-append
+ (if setter
+ "fn_"
+ "")
+ "pc"))
+ (else
+ (string-append
+ (cond ((memory? hw)
+ "mem_")
+ ((hw-scalar? hw)
+ "scalar_")
+ (else ""))
+ (if setter
+ "fn_"
+ "")
+ (string-downcase (if sem-mode
+ (mode-real-name sem-mode)
+ (mode-real-name mode))))))
+ "_write (current_cpu"
+ ; ??? May need to include h/w id some day.
+ (if setter
+ (string-append ", " (gen-reg-setter-fn hw "@cpu@"))
+ "")
+ (cond ((hw-scalar? hw)
+ "")
+ (setter
+ (string-append ", " (-gen-hw-index index estate)))
+ ((memory? hw)
+ (string-append ", " (-gen-hw-index index estate)))
+ (else
+ (string-append ", " (-gen-hw-addr (op:type op) estate index))))
+ ", "
+ newval
+ ");\n"))
+)
+
+(define (-op-gen-set-quiet-parallel op estate mode index selector newval)
+ (if (with-generic-write?)
+ (-op-gen-queued-write op estate mode index selector (cx:c newval))
+ (string-append
+ (if (op-save-index? op)
+ (string-append " "
+ -par-operand-macro " (" (-op-index-name op) ")"
+ " = " (-gen-hw-index index estate) ";\n")
+ "")
+ " "
+ -par-operand-macro " (" (gen-sym op) ")"
+ " = " (cx:c newval) ";\n"))
+)
+
+(define (-op-gen-set-trace op estate mode index selector newval)
+ (string-append
+ " {\n"
+ " " (mode:c-type mode) " opval = " (cx:c newval) ";\n"
+ " " (send (op:type op) 'gen-set-quiet estate mode index selector
+ (cx:make-with-atlist mode "opval" (cx:atlist newval)))
+ (if (op:cond? op)
+ (string-append " written |= (1 << "
+ (number->string (op:num op))
+ ");\n")
+ "")
+; TRACE_RESULT_<MODE> (cpu, abuf, hwnum, opnum, value);
+; For each insn record array of operand numbers [or indices into
+; operand instance table].
+; Could just scan the operand table for the operand or hardware number,
+; assuming the operand number is stored in `op'.
+ " TRACE_RESULT (current_cpu, abuf"
+ ", " (send op 'gen-pretty-name mode)
+ ", " (mode:printf-type mode)
+ ", opval);\n"
+ " }\n")
+)
+
+(define (-op-gen-set-trace-parallel op estate mode index selector newval)
+ (string-append
+ " {\n"
+ " " (mode:c-type mode) " opval = " (cx:c newval) ";\n"
+ (if (with-generic-write?)
+ (-op-gen-queued-write op estate mode index selector "opval")
+ (string-append
+ (if (op-save-index? op)
+ (string-append " "
+ -par-operand-macro " (" (-op-index-name op) ")"
+ " = " (-gen-hw-index index estate) ";\n")
+ "")
+ " " -par-operand-macro " (" (gen-sym op) ")"
+ " = opval;\n"))
+ (if (op:cond? op)
+ (string-append " written |= (1 << "
+ (number->string (op:num op))
+ ");\n")
+ "")
+; TRACE_RESULT_<MODE> (cpu, abuf, hwnum, opnum, value);
+; For each insn record array of operand numbers [or indices into
+; operand instance table].
+; Could just scan the operand table for the operand or hardware number,
+; assuming the operand number is stored in `op'.
+ " TRACE_RESULT (current_cpu, abuf"
+ ", " (send op 'gen-pretty-name mode)
+ ", " (mode:printf-type mode)
+ ", opval);\n"
+ " }\n")
+)
+
+; Return C code to set the value of an operand.
+; NEWVAL is a <c-expr> object of the value to store.
+; If INDEX is non-#f use it, otherwise use (op:index self).
+; This special handling of #f for INDEX is *only* supported for operands
+; in cxmake-get, gen-set-quiet, and gen-set-trace.
+; Ditto for SELECTOR.
+
+(method-make!
+ <operand> 'gen-set-quiet
+ (lambda (self estate mode index selector newval)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (send self 'get-mode)
+ mode))
+ (index (if index index (op:index self)))
+ (selector (if selector selector (op:selector self))))
+ ; ??? raw-reg: support wip
+ (cond ((obj-has-attr? self 'RAW)
+ (send (op:type self) 'gen-set-quiet-raw estate mode index selector newval))
+ ((with-parallel-write?)
+ (-op-gen-set-quiet-parallel self estate mode index selector newval))
+ (else
+ (-op-gen-set-quiet self estate mode index selector newval)))))
+)
+
+; Return C code to set the value of an operand and print TRACE_RESULT message.
+; NEWVAL is a <c-expr> object of the value to store.
+; If INDEX is non-#f use it, otherwise use (op:index self).
+; This special handling of #f for INDEX is *only* supported for operands
+; in cxmake-get, gen-set-quiet, and gen-set-trace.
+; Ditto for SELECTOR.
+
+(method-make!
+ <operand> 'gen-set-trace
+ (lambda (self estate mode index selector newval)
+ (let ((mode (if (mode:eq? 'DFLT mode)
+ (send self 'get-mode)
+ mode))
+ (index (if index index (op:index self)))
+ (selector (if selector selector (op:selector self))))
+ ; ??? raw-reg: support wip
+ (cond ((obj-has-attr? self 'RAW)
+ (send (op:type self) 'gen-set-quiet-raw estate mode index selector newval))
+ ((with-parallel-write?)
+ (-op-gen-set-trace-parallel self estate mode index selector newval))
+ (else
+ (-op-gen-set-trace self estate mode index selector newval)))))
+)
+
+; Define and undefine C macros to tuck away details of instruction format used
+; in the parallel execution functions. See gen-define-field-macro for a
+; similar thing done for extraction/semantic functions.
+
+(define (gen-define-parallel-operand-macro sfmt)
+ (string-append "#define " -par-operand-macro "(f) "
+ "par_exec->operands."
+ (gen-sym sfmt)
+ ".f\n")
+)
+
+(define (gen-undef-parallel-operand-macro sfmt)
+ (string-append "#undef " -par-operand-macro "\n")
+)
+
+; Operand profiling and parallel execution support.
+
+(method-make!
+ <operand> 'save-index?
+ (lambda (self) (send (op:type self) 'save-index? self))
+)
+
+; Return boolean indicating if operand OP needs its index saved
+; (for parallel write post-processing support).
+
+(define (op-save-index? op)
+ (send op 'save-index?)
+)
+
+; Return C code to record profile data for modeling use.
+; In the case of a register, this is usually the register's number.
+; This shouldn't be called in the case of a scalar, the code should be
+; smart enough to know there is no need.
+
+(define (op:record-profile op sfmt out?)
+ (let ((estate (estate-make-for-normal-rtl-c nil nil)))
+ (send op 'gen-record-profile sfmt out? estate))
+)
+
+; Return C code to record the data needed for profiling operand SELF.
+; This is done during extraction.
+
+(method-make!
+ <operand> 'gen-record-profile
+ (lambda (self sfmt out? estate)
+ (if (hw-scalar? (op:type self))
+ ""
+ (string-append " "
+ (gen-argbuf-ref (string-append (if out? "out_" "in_")
+ (gen-sym self)))
+ " = "
+ (send (op:type self) 'gen-record-profile
+ (op:index self) sfmt estate)
+ ";\n")))
+)
+
+; Return C code to track profiling of operand SELF.
+; This is usually called by the x-after handler.
+
+(method-make!
+ <operand> 'gen-profile-code
+ (lambda (self insn out?)
+ (string-append " "
+ "@cpu@_model_mark_"
+ (if out? "set_" "get_")
+ (gen-sym (op:type self))
+ " (current_cpu"
+ (if (hw-scalar? (op:type self))
+ ""
+ (string-append ", "
+ (gen-argbuf-ref
+ (string-append (if out? "out_" "in_")
+ (gen-sym self)))))
+ ");\n"))
+)
+
+; CPU, mach, model support.
+
+; Return the declaration of the cpu/insn enum.
+
+(define (gen-cpu-insn-enum-decl cpu insn-list)
+ (gen-enum-decl "@cpu@_insn_type"
+ "instructions in cpu family @cpu@"
+ "@CPU@_INSN_"
+ (append! (map (lambda (i)
+ (cons (obj:name i)
+ (cons '-
+ (atlist-attrs (obj-atlist i)))))
+ insn-list)
+ (if (with-parallel?)
+ (apply append!
+ (map (lambda (i)
+ (list
+ (cons (symbol-append 'par- (obj:name i))
+ (cons '-
+ (atlist-attrs (obj-atlist i))))
+ (cons (symbol-append 'write- (obj:name i))
+ (cons '-
+ (atlist-attrs (obj-atlist i))))))
+ (parallel-insns insn-list)))
+ nil)
+ (list '(max))))
+)
+
+; Return the enum of INSN in cpu family CPU.
+; In addition to CGEN_INSN_TYPE, an enum is created for each insn in each
+; cpu family. This collapses the insn enum space for each cpu to increase
+; cache efficiently (since the IDESC table is similarily collapsed).
+
+(define (gen-cpu-insn-enum cpu insn)
+ (string-upcase (string-append "@CPU@_INSN_" (gen-sym insn)))
+)
+
+; Return C code to declare the machine data.
+
+(define (-gen-mach-decls)
+ (string-append
+ (string-map (lambda (mach)
+ (gen-obj-sanitize mach
+ (string-append "extern const MACH "
+ (gen-sym mach)
+ "_mach;\n")))
+ (current-mach-list))
+ "\n")
+)
+
+; Return C code to define the machine data.
+
+(define (-gen-mach-data)
+ (string-append
+ "const MACH *sim_machs[] =\n{\n"
+ (string-map (lambda (mach)
+ (gen-obj-sanitize
+ mach
+ (string-append "#ifdef " (gen-have-cpu (mach-cpu mach)) "\n"
+ " & " (gen-sym mach) "_mach,\n"
+ "#endif\n")))
+ (current-mach-list))
+ " 0\n"
+ "};\n\n"
+ )
+)
+
+; Return C declarations of cpu model support stuff.
+; ??? This goes in arch.h but a better place is each cpu.h.
+
+(define (-gen-arch-model-decls)
+ (string-append
+ (gen-enum-decl 'model_type "model types"
+ "MODEL_"
+ (append (map (lambda (model)
+ (cons (obj:name model)
+ (cons '-
+ (atlist-attrs (obj-atlist model)))))
+ (current-model-list))
+ '((max))))
+ "#define MAX_MODELS ((int) MODEL_MAX)\n\n"
+ (gen-enum-decl 'unit_type "unit types"
+ "UNIT_"
+ (cons '(none)
+ (append
+ ; "apply append" squeezes out nils.
+ (apply append
+ ; create <model_name>-<unit-name> for each unit
+ (map (lambda (model)
+ (let ((units (model:units model)))
+ (if (null? units)
+ nil
+ (map (lambda (unit)
+ (cons (symbol-append (obj:name model) '-
+ (obj:name unit))
+ (cons '- (atlist-attrs (obj-atlist model)))))
+ units))))
+ (current-model-list)))
+ '((max)))))
+ ; FIXME: revisit MAX_UNITS
+ "#define MAX_UNITS ("
+ (number->string
+ (apply max
+ (map (lambda (lengths) (apply max lengths))
+ (map (lambda (insn)
+ (let ((timing (insn-timing insn)))
+ (if (null? timing)
+ '(1)
+ (map (lambda (insn-timing)
+ (length (timing:units (cdr insn-timing))))
+ timing))))
+ (current-insn-list)))))
+ ")\n\n"
+ )
+)
+
+; Function units.
+
+(method-make! <unit> 'gen-decl (lambda (self) ""))
+
+; Lookup operand named OP-NAME in INSN.
+; Returns #f if OP-NAME is not an operand of INSN.
+; IN-OUT is 'in to request an input operand, 'out to request an output operand,
+; and 'in-out to request either (though if an operand is used for input and
+; output then the input version is returned).
+; FIXME: Move elsewhere.
+
+(define (insn-op-lookup op-name insn in-out)
+ (letrec ((lookup (lambda (op-list)
+ (cond ((null? op-list) #f)
+ ((eq? op-name (op:sem-name (car op-list))) (car op-list))
+ (else (lookup (cdr op-list)))))))
+ (case in-out
+ ((in) (lookup (sfmt-in-ops (insn-sfmt insn))))
+ ((out) (lookup (sfmt-out-ops (insn-sfmt insn))))
+ ((in-out) (or (lookup (sfmt-in-ops (insn-sfmt insn)))
+ (lookup (sfmt-out-ops (insn-sfmt insn)))))
+ (else (error "insn-op-lookup: bad arg:" in-out))))
+)
+
+; Return C code to profile a unit's usage.
+; UNIT-NUM is number of the unit in INSN.
+; OVERRIDES is a list of (name value) pairs, where
+; - NAME is a spec name, one of cycles, pred, in, out.
+; The only ones we're concerned with are in,out. They map operand names
+; as they appear in the semantic code to operand names as they appear in
+; the function unit spec.
+; - VALUE is the operand to NAME. For in,out it is (NAME VALUE) where
+; - NAME is the name of an input/output arg of the unit.
+; - VALUE is the name of the operand as it appears in semantic code.
+;
+; ??? This is a big sucker, though half of it is just the definitions
+; of utility fns.
+
+(method-make!
+ <unit> 'gen-profile-code
+ (lambda (self unit-num insn overrides cycles-var-name)
+ (let (
+ (inputs (unit:inputs self))
+ (outputs (unit:outputs self))
+
+ ; Return C code to initialize UNIT-REFERENCED-VAR to be a bit mask
+ ; of operands of UNIT that were read/written by INSN.
+ ; INSN-REFERENCED-VAR is a bitmask of operands read/written by INSN.
+ ; All we have to do is map INSN-REFERENCED-VAR to
+ ; UNIT-REFERENCED-VAR.
+ ; ??? For now we assume all input operands are read.
+ (gen-ref-arg (lambda (arg num in-out)
+ (let* ((op-name (assq-ref overrides (car arg)))
+ (op (insn-op-lookup (if op-name
+ (car op-name)
+ (car arg))
+ insn in-out))
+ (insn-referenced-var "insn_referenced")
+ (unit-referenced-var "referenced"))
+ (if op
+ (if (op:cond? op)
+ (string-append " "
+ "if ("
+ insn-referenced-var
+ " & (1 << "
+ (number->string (op:num op))
+ ")) "
+ unit-referenced-var
+ " |= 1 << "
+ (number->string num)
+ ";\n")
+ (string-append " "
+ unit-referenced-var
+ " |= 1 << "
+ (number->string num)
+ ";\n"))
+ ""))))
+
+ ; Initialize unit argument ARG.
+ ; OUT? is #f for input args, #t for output args.
+ (gen-arg-init (lambda (arg out?)
+ (if (or
+ ; Ignore scalars.
+ (null? (cdr arg))
+ ; Ignore remapped arg, handled elsewhere.
+ (assq (car arg) overrides)
+ ; Ignore operands not in INSN.
+ (not (insn-op-lookup (car arg) insn
+ (if out? 'out 'in))))
+ ""
+ (string-append " "
+ (if out? "out_" "in_")
+ (gen-c-symbol (car arg))
+ " = "
+ (gen-argbuf-ref
+ (string-append (if out? "out_" "in_")
+ (gen-c-symbol (car arg))))
+ ";\n"))))
+
+ ; Return C code to declare variable to hold unit argument ARG.
+ ; OUT? is #f for input args, #t for output args.
+ (gen-arg-decl (lambda (arg out?)
+ (if (null? (cdr arg)) ; ignore scalars
+ ""
+ (string-append " "
+ (mode:c-type (mode:lookup (cadr arg)))
+ " "
+ (if out? "out_" "in_")
+ (gen-c-symbol (car arg))
+ " = "
+ (if (null? (cddr arg))
+ "0"
+ (number->string (caddr arg)))
+ ";\n"))))
+
+ ; Return C code to pass unit argument ARG to the handler.
+ ; OUT? is #f for input args, #t for output args.
+ (gen-arg-arg (lambda (arg out?)
+ (if (null? (cdr arg)) ; ignore scalars
+ ""
+ (string-append ", "
+ (if out? "out_" "in_")
+ (gen-c-symbol (car arg))))))
+ )
+
+ (string-list
+ " {\n"
+ " int referenced = 0;\n"
+ " int UNUSED insn_referenced = abuf->written;\n"
+ ; Declare variables to hold unit arguments.
+ (string-map (lambda (arg) (gen-arg-decl arg #f))
+ inputs)
+ (string-map (lambda (arg) (gen-arg-decl arg #t))
+ outputs)
+ ; Initialize 'em, being careful not to initialize an operand that
+ ; has an override.
+ (let (; Make a list of names of in/out overrides.
+ (in-overrides (find-apply cadr
+ (lambda (elm) (eq? (car elm) 'in))
+ overrides))
+ (out-overrides (find-apply cadr
+ (lambda (elm) (eq? (car elm) 'out))
+ overrides)))
+ (string-list
+ (string-map (lambda (arg)
+ (if (memq (car arg) in-overrides)
+ ""
+ (gen-arg-init arg #f)))
+ inputs)
+ (string-map (lambda (arg)
+ (if (memq (car arg) out-overrides)
+ ""
+ (gen-arg-init arg #t)))
+ outputs)))
+ (string-map (lambda (arg)
+ (case (car arg)
+ ((pred) "")
+ ((cycles) "")
+ ((in)
+ (if (caddr arg)
+ (string-append " in_"
+ (gen-c-symbol (cadr arg))
+ " = "
+ (gen-argbuf-ref
+ (string-append
+ "in_"
+ (gen-c-symbol (caddr arg))))
+ ";\n")
+ ""))
+ ((out)
+ (if (caddr arg)
+ (string-append " out_"
+ (gen-c-symbol (cadr arg))
+ " = "
+ (gen-argbuf-ref
+ (string-append
+ "out_"
+ (gen-c-symbol (caddr arg))))
+ ";\n")
+ ""))
+ (else
+ (parse-error "insn function unit spec"
+ "invalid spec" arg))))
+ overrides)
+ ; Create bitmask indicating which args were referenced.
+ (string-map (lambda (arg num) (gen-ref-arg arg num 'in))
+ inputs
+ (iota (length inputs)))
+ (string-map (lambda (arg num) (gen-ref-arg arg num 'out))
+ outputs
+ (iota (length inputs)
+ (length outputs)))
+ ; Emit the call to the handler.
+ " " cycles-var-name " += "
+ (gen-model-unit-fn-name (unit:model self) self)
+ " (current_cpu, idesc"
+ ", " (number->string unit-num)
+ ", referenced"
+ (string-map (lambda (arg) (gen-arg-arg arg #f))
+ inputs)
+ (string-map (lambda (arg) (gen-arg-arg arg #t))
+ outputs)
+ ");\n"
+ " }\n"
+ )))
+)
+
+; Return C code to profile an insn-specific unit's usage.
+; UNIT-NUM is number of the unit in INSN.
+
+(method-make!
+ <iunit> 'gen-profile-code
+ (lambda (self unit-num insn cycles-var-name)
+ (let ((args (iunit:args self))
+ (unit (iunit:unit self)))
+ (send unit 'gen-profile-code unit-num insn args cycles-var-name)))
+)
+
+; ARGBUF generation.
+; ARGBUF support is put in cpuall.h, which doesn't depend on sim-cpu.scm,
+; so this support is here.
+
+; Utility of -gen-argbuf-fields-union to generate the definition for
+; <sformat-abuf> SBUF.
+
+(define (-gen-argbuf-elm sbuf)
+ (logit 2 "Processing sbuf format " (obj:name sbuf) " ...\n")
+ (string-list
+ " struct { /* " (obj:comment sbuf) " */\n"
+ (let ((elms (sbuf-elms sbuf)))
+ (if (null? elms)
+ " int empty;\n"
+ (string-list-map (lambda (elm)
+ (string-append " "
+ (cadr elm)
+ " "
+ (car elm)
+ ";\n"))
+ (sbuf-elms sbuf))))
+ " } " (gen-sym sbuf) ";\n")
+)
+
+; Utility of gen-argbuf-type to generate the union of extracted ifields.
+
+(define (-gen-argbuf-fields-union)
+ (string-list
+ "\
+/* Instruction argument buffer. */
+
+union sem_fields {\n"
+ (string-list-map -gen-argbuf-elm (current-sbuf-list))
+ "\
+#if WITH_SCACHE_PBB
+ /* Writeback handler. */
+ struct {
+ /* Pointer to argbuf entry for insn whose results need writing back. */
+ const struct argbuf *abuf;
+ } write;
+ /* x-before handler */
+ struct {
+ /*const SCACHE *insns[MAX_PARALLEL_INSNS];*/
+ int first_p;
+ } before;
+ /* x-after handler */
+ struct {
+ int empty;
+ } after;
+ /* This entry is used to terminate each pbb. */
+ struct {
+ /* Number of insns in pbb. */
+ int insn_count;
+ /* Next pbb to execute. */
+ SCACHE *next;
+ SCACHE *branch_target;
+ } chain;
+#endif
+};\n\n"
+ )
+)
+
+; Generate the definition of the structure that records arguments.
+; This is a union of structures with one structure for each insn format.
+; It also includes hardware profiling information and miscellaneous
+; administrivia.
+; CPU-DATA? is #t if data for the currently selected cpu is to be included.
+
+(define (gen-argbuf-type cpu-data?)
+ (logit 2 "Generating ARGBUF type ...\n")
+ (string-list
+ (if (and cpu-data? (with-scache?))
+ (-gen-argbuf-fields-union)
+ "")
+ (if cpu-data? "" "#ifndef WANT_CPU\n")
+ "\
+/* The ARGBUF struct. */
+struct argbuf {
+ /* These are the baseclass definitions. */
+ IADDR addr;
+ const IDESC *idesc;
+ char trace_p;
+ char profile_p;
+ /* ??? Temporary hack for skip insns. */
+ char skip_count;
+ char unused;
+ /* cpu specific data follows */\n"
+ (if cpu-data?
+ (if (with-scache?)
+ "\
+ union sem semantic;
+ int written;
+ union sem_fields fields;\n"
+ "\
+ CGEN_INSN_INT insn;
+ int written;\n")
+ "")
+ "};\n"
+ (if cpu-data? "" "#endif\n")
+ "\n"
+ )
+)
+
+; Generate the definition of the structure that records a cached insn.
+; This is cpu family specific (member `argbuf' is) so it is machine generated.
+; CPU-DATA? is #t if data for the currently selected cpu is to be included.
+
+(define (gen-scache-type cpu-data?)
+ (logit 2 "Generating SCACHE type ...\n")
+ (string-append
+ (if cpu-data? "" "#ifndef WANT_CPU\n")
+ "\
+/* A cached insn.
+
+ ??? SCACHE used to contain more than just argbuf. We could delete the
+ type entirely and always just use ARGBUF, but for future concerns and as
+ a level of abstraction it is left in. */
+
+struct scache {
+ struct argbuf argbuf;\n"
+ (if (with-generic-write?) "\
+ int first_insn_p;
+ int last_insn_p;\n" "")
+ "};\n"
+ (if cpu-data? "" "#endif\n")
+ "\n"
+ )
+)
+
+; Mode support.
+
+; Generate a table of mode data.
+; For now all we need is the names.
+
+(define (gen-mode-defs)
+ (string-append
+ "const char *mode_names[] = {\n"
+ (string-map (lambda (m)
+ (string-append " \"" (string-upcase (obj:name m)) "\",\n"))
+ ; We don't treat aliases as being different from the real
+ ; mode here, so ignore them.
+ (mode-list-non-alias-values))
+ "};\n\n"
+ )
+)
+
+; Insn profiling support.
+
+; Generate declarations for local variables needed for modelling code.
+
+(method-make!
+ <insn> 'gen-profile-locals
+ (lambda (self model)
+; (let ((cti? (or (has-attr? self 'UNCOND-CTI)
+; (has-attr? self 'COND-CTI))))
+; (string-append
+; (if cti? " int UNUSED taken_p = 0;\n" "")
+; ))
+ "")
+)
+
+; Generate C code to profile INSN.
+
+(method-make!
+ <insn> 'gen-profile-code
+ (lambda (self model cycles-var-name)
+ (string-list
+ (let ((timing (assq-ref (insn-timing self) (obj:name model))))
+ (if timing
+ (string-list-map (lambda (iunit unit-num)
+ (send iunit 'gen-profile-code unit-num self cycles-var-name))
+ (timing:units timing)
+ (iota (length (timing:units timing))))
+ (send (model-default-unit model) 'gen-profile-code 0 self nil cycles-var-name)))
+ ))
+)
+
+; .cpu file loading support
+
+; Only run sim-analyze-insns! once.
+(define -sim-insns-analyzed? #f)
+
+; List of computed sformat argument buffers.
+(define -sim-sformat-abuf-list #f)
+(define (current-sbuf-list) -sim-sformat-abuf-list)
+
+; Called before/after the .cpu file has been read in.
+
+(define (sim-init!)
+ (set! -sim-insns-analyzed? #f)
+ (set! -sim-sformat-abuf-list #f)
+ *UNSPECIFIED*
+)
+
+(define (sim-finish!)
+ ; Add begin,chain,before,after,invalid handlers if not provided.
+ ; The code generators should first look for x-foo-@cpu@, then for x-foo.
+ ; ??? This is good enough for the first pass. Will eventually need to use
+ ; less C and more RTL.
+
+ (let ((all (stringize (current-arch-isa-name-list) ",")))
+
+ (define-full-insn 'x-begin "pbb begin handler"
+ `(VIRTUAL PBB (ISA ,all))
+ "--begin--" () () '(c-code VOID "\
+ {
+#if WITH_SCACHE_PBB_@CPU@
+#ifdef DEFINE_SWITCH
+ /* In the switch case FAST_P is a constant, allowing several optimizations
+ in any called inline functions. */
+ vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
+#else
+ vpc = @cpu@_pbb_begin (current_cpu, STATE_RUN_FAST_P (CPU_STATE (current_cpu)));
+#endif
+#endif
+ }
+") nil)
+
+ (define-full-insn 'x-chain "pbb chain handler"
+ `(VIRTUAL PBB (ISA ,all))
+ "--chain--" () () '(c-code VOID "\
+ {
+#if WITH_SCACHE_PBB_@CPU@
+ vpc = @cpu@_pbb_chain (current_cpu, sem_arg);
+#ifdef DEFINE_SWITCH
+ BREAK (sem);
+#endif
+#endif
+ }
+") nil)
+
+ (define-full-insn 'x-cti-chain "pbb cti-chain handler"
+ `(VIRTUAL PBB (ISA ,all))
+ "--cti-chain--" () () '(c-code VOID "\
+ {
+#if WITH_SCACHE_PBB_@CPU@
+#ifdef DEFINE_SWITCH
+ vpc = @cpu@_pbb_cti_chain (current_cpu, sem_arg,
+ pbb_br_type, pbb_br_npc);
+ BREAK (sem);
+#else
+ /* FIXME: Allow provision of explicit ifmt spec in insn spec. */
+ vpc = @cpu@_pbb_cti_chain (current_cpu, sem_arg,
+ CPU_PBB_BR_TYPE (current_cpu),
+ CPU_PBB_BR_NPC (current_cpu));
+#endif
+#endif
+ }
+") nil)
+
+ (define-full-insn 'x-before "pbb begin handler"
+ `(VIRTUAL PBB (ISA ,all))
+ "--before--" () () '(c-code VOID "\
+ {
+#if WITH_SCACHE_PBB_@CPU@
+ @cpu@_pbb_before (current_cpu, sem_arg);
+#endif
+ }
+") nil)
+
+ (define-full-insn 'x-after "pbb after handler"
+ `(VIRTUAL PBB (ISA ,all))
+ "--after--" () () '(c-code VOID "\
+ {
+#if WITH_SCACHE_PBB_@CPU@
+ @cpu@_pbb_after (current_cpu, sem_arg);
+#endif
+ }
+") nil)
+
+ (define-full-insn 'x-invalid "invalid insn handler"
+ `(VIRTUAL (ISA ,all))
+ "--invalid--" () () (list 'c-code 'VOID (string-append "\
+ {
+ /* Update the recorded pc in the cpu state struct.
+ Only necessary for WITH_SCACHE case, but to avoid the
+ conditional compilation .... */
+ SET_H_PC (pc);
+ /* Virtual insns have zero size. Overwrite vpc with address of next insn
+ using the default-insn-bitsize spec. When executing insns in parallel
+ we may want to queue the fault and continue execution. */
+ vpc = SEM_NEXT_VPC (sem_arg, pc, " (number->string (bits->bytes (state-default-insn-bitsize))) ");
+ vpc = sim_engine_invalid_insn (current_cpu, pc, vpc);
+ }
+")) nil))
+
+ *UNSPECIFIED*
+)
+
+; Called after file is read in and global error checks are done
+; to initialize tables.
+
+(define (sim-analyze!)
+ *UNSPECIFIED*
+)
+
+; Scan insns, analyzing semantics and computing instruction formats.
+; 'twould be nice to do this in sim-analyze! but it doesn't know whether this
+; needs to be done or not (which is determined by what files are being
+; generated). Since this is an expensive operation, we defer doing this
+; to the files that need it.
+
+(define (sim-analyze-insns!)
+ ; This can only be done if one isa and one cpu family is being kept.
+ (assert-keep-one)
+
+ (if (not -sim-insns-analyzed?)
+
+ (begin
+ (arch-analyze-insns! CURRENT-ARCH
+ #f ; don't include aliases
+ #t) ; do analyze the semantics
+
+ ; Compute the set of sformat argument buffers.
+ (set! -sim-sformat-abuf-list (compute-sformat-argbufs! (current-sfmt-list)))
+
+ (set! -sim-insns-analyzed? #t)))
+
+ ; Do our own error checking.
+ (assert (current-insn-lookup 'x-invalid))
+
+ *UNSPECIFIED*
+)
+
+; For debugging.
+
+(define (cgen-all-arch)
+ (string-write
+ cgen-arch.h
+ cgen-arch.c
+ cgen-cpuall.h
+ ;cgen-mem-ops.h
+ ;cgen-sem-ops.h
+ ;cgen-ops.c
+ )
+)
+
+(define (cgen-all-cpu)
+ (string-write
+ cgen-cpu.h
+ cgen-cpu.c
+ cgen-decode.h
+ cgen-decode.c
+ ;cgen-extract.c
+ cgen-read.c
+ cgen-write.c
+ cgen-semantics.c
+ cgen-sem-switch.c
+ cgen-model.c
+ ;cgen-mainloop.in
+ )
+)
diff --git a/cgen/simplify.inc b/cgen/simplify.inc
new file mode 100644
index 00000000000..7ccd6fd2d38
--- /dev/null
+++ b/cgen/simplify.inc
@@ -0,0 +1,198 @@
+; Collection of macros to simplify .cpu file writing. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Enums.
+
+; Define a normal enum without using name/value pairs.
+; This is currently the same as define-full-enum but it needn't remain
+; that way (it's define-full-enum that would change).
+
+(define-pmacro (define-normal-enum name comment attrs prefix vals)
+ "\
+Define a normal enum, fixed number of arguments.
+"
+ (define-full-enum name comment attrs prefix vals)
+)
+
+; Define a normal insn enum.
+
+(define-pmacro (define-normal-insn-enum name comment attrs prefix fld vals)
+ "\
+Define a normal instruction opcode enum.
+"
+ (define-full-insn-enum name comment attrs prefix fld vals)
+)
+
+; Instruction fields.
+
+; Normally, fields are unsigned have no encode/decode needs.
+
+(define-pmacro (define-normal-ifield name comment attrs start length)
+ "Define a normal instruction field.\n"
+ (define-full-ifield name comment attrs start length UINT #f #f)
+)
+
+; For those who don't like typing.
+
+(define-pmacro df
+ "Shorthand form of define-full-ifield.\n"
+ define-full-ifield
+)
+(define-pmacro dnf
+ "Shorthand form of define-normal-ifield.\n"
+ define-normal-ifield
+)
+
+; Define a normal multi-ifield.
+; FIXME: The define-normal version for ifields doesn't include the mode.
+
+(define-pmacro (define-normal-multi-ifield name comment attrs
+ mode subflds insert extract)
+ "Define a normal multi-part instruction field.\n"
+ (define-full-multi-ifield name comment attrs mode subflds insert extract)
+)
+
+; For those who don't like typing.
+
+(define-pmacro dnmf
+ "Shorthand form of define-normal-multi-ifield.\n"
+ define-normal-multi-ifield
+)
+
+; Simple multi-ifields: mode is UINT, default insert/extract support.
+
+(define-pmacro (dsmf name comment attrs subflds)
+ "Define a simple multi-part instruction field.\n"
+ (define-full-multi-ifield name comment attrs UINT subflds #f #f)
+)
+
+; Hardware.
+
+; Simpler version for most hardware elements.
+; Allow special assembler support specification but no semantic-name or
+; get/set specs.
+
+(define-pmacro (define-normal-hardware name comment attrs type
+ indices values handlers)
+ "\
+Define a normal hardware element.
+"
+ (define-full-hardware name comment attrs name type
+ indices values handlers () () ())
+)
+
+; For those who don't like typing.
+
+(define-pmacro dnh
+ "Shorthand form of define-normal-hardware.\n"
+ define-normal-hardware
+)
+
+; Simpler version of dnh that leaves out the indices, values, handlers,
+; get, set, and layout specs.
+; This is useful for 1 bit registers.
+; ??? While dsh and dnh aren't that distinguishable when perusing a .cpu file,
+; they both take a fixed number of positional arguments, and dsh is a proper
+; subset of dnh with all arguments in the same positions, so methinks things
+; are ok.
+
+(define-pmacro (define-simple-hardware name comment attrs type)
+ "\
+Define a simple hardware element (usually a scalar register).
+"
+ (define-full-hardware name comment attrs name type () () () () () ())
+)
+
+(define-pmacro dsh
+ "Shorthand form of define-simple-hardware.\n"
+ define-simple-hardware
+)
+
+; Operands.
+
+(define-pmacro (define-normal-operand name comment attrs type index)
+ "Define a normal operand.\n"
+ (define-full-operand name comment attrs type DFLT index () () ())
+)
+
+; For those who don't like typing.
+; FIXME: dno?
+
+(define-pmacro dnop
+ "Shorthand form of define-normal-operand.\n"
+ define-normal-operand
+)
+
+(define-pmacro (dndo x-name x-mode x-args
+ x-syntax x-base-ifield x-encoding x-ifield-assertion
+ x-getter x-setter)
+ "Define a normal derived operand."
+ (define-derived-operand
+ (name x-name)
+ (mode x-mode)
+ (args x-args)
+ (syntax x-syntax)
+ (base-ifield x-base-ifield)
+ (encoding x-encoding)
+ (ifield-assertion x-ifield-assertion)
+ (getter x-getter)
+ (setter x-setter)
+ )
+)
+
+; Instructions.
+
+; Define an instruction object, normal version.
+; At present all fields must be specified.
+; Fields ifield-assertion is absent.
+
+(define-pmacro (define-normal-insn name comment attrs syntax fmt semantics timing)
+ "Define a normal instruction.\n"
+ (define-full-insn name comment attrs syntax fmt () semantics timing)
+)
+
+; To reduce the amount of typing.
+; Note that this is the same name as the D'ni in MYST. Oooohhhh.....
+; this must be the right way to go. :-)
+
+(define-pmacro dni
+ "Shorthand form of define-normal-insn.\n"
+ define-normal-insn
+)
+
+; Macro instructions.
+
+; Define a macro-insn object, normal version.
+; This only supports expanding to one real insn.
+
+(define-pmacro (define-normal-macro-insn name comment attrs syntax expansion)
+ "Define a normal macro instruction.\n"
+ (define-full-minsn name comment attrs syntax expansion)
+)
+
+; To reduce the amount of typing.
+
+(define-pmacro dnmi
+ "Shorthand form of define-normal-macro-insn.\n"
+ define-normal-macro-insn
+)
+
+; Modes.
+; ??? Not currently available for use.
+;
+; Define Normal Mode
+;
+;(define-pmacro (define-normal-mode name comment attrs bits bytes
+; non-mode-c-type printf-type sem-mode ptr-to host?)
+; "Define a normal mode.\n"
+; (define-full-mode name comment attrs bits bytes
+; non-mode-c-type printf-type sem-mode ptr-to host?)
+;)
+;
+; For those who don't like typing.
+;(define-pmacro dnm
+; "Shorthand form of define-normal-mode.\n"
+; define-normal-mode
+;)
diff --git a/cgen/slib/genwrite.scm b/cgen/slib/genwrite.scm
new file mode 100644
index 00000000000..f57d773daf2
--- /dev/null
+++ b/cgen/slib/genwrite.scm
@@ -0,0 +1,270 @@
+;;"genwrite.scm" generic write used by pretty-print and truncated-print.
+;; Copyright (c) 1991, Marc Feeley
+;; Author: Marc Feeley (feeley@iro.umontreal.ca)
+;; Distribution restrictions: none
+
+(define (generic-write obj display? width output)
+
+ (define (read-macro? l)
+ (define (length1? l) (and (pair? l) (null? (cdr l))))
+ (let ((head (car l)) (tail (cdr l)))
+ (case head
+ ((QUOTE QUASIQUOTE UNQUOTE UNQUOTE-SPLICING) (length1? tail))
+ (else #f))))
+
+ (define (read-macro-body l)
+ (cadr l))
+
+ (define (read-macro-prefix l)
+ (let ((head (car l)) (tail (cdr l)))
+ (case head
+ ((QUOTE) "'")
+ ((QUASIQUOTE) "`")
+ ((UNQUOTE) ",")
+ ((UNQUOTE-SPLICING) ",@"))))
+
+ (define (out str col)
+ (and col (output str) (+ col (string-length str))))
+
+ (define (wr obj col)
+
+ (define (wr-expr expr col)
+ (if (read-macro? expr)
+ (wr (read-macro-body expr) (out (read-macro-prefix expr) col))
+ (wr-lst expr col)))
+
+ (define (wr-lst l col)
+ (if (pair? l)
+ (let loop ((l (cdr l))
+ (col (and col (wr (car l) (out "(" col)))))
+ (cond ((not col) col)
+ ((pair? l)
+ (loop (cdr l) (wr (car l) (out " " col))))
+ ((null? l) (out ")" col))
+ (else (out ")" (wr l (out " . " col))))))
+ (out "()" col)))
+
+ (cond ((pair? obj) (wr-expr obj col))
+ ((null? obj) (wr-lst obj col))
+ ((vector? obj) (wr-lst (vector->list obj) (out "#" col)))
+ ((boolean? obj) (out (if obj "#t" "#f") col))
+ ((number? obj) (out (number->string obj) col))
+ ((symbol? obj) (out (symbol->string obj) col))
+ ((procedure? obj) (out "#[procedure]" col))
+ ((string? obj) (if display?
+ (out obj col)
+ (let loop ((i 0) (j 0) (col (out "\"" col)))
+ (if (and col (< j (string-length obj)))
+ (let ((c (string-ref obj j)))
+ (if (or (char=? c #\\)
+ (char=? c #\"))
+ (loop j
+ (+ j 1)
+ (out "\\"
+ (out (substring obj i j)
+ col)))
+ (loop i (+ j 1) col)))
+ (out "\""
+ (out (substring obj i j) col))))))
+ ((char? obj) (if display?
+ (out (make-string 1 obj) col)
+ (out (case obj
+ ((#\space) "space")
+ ((#\newline) "newline")
+ (else (make-string 1 obj)))
+ (out "#\\" col))))
+ ((input-port? obj) (out "#[input-port]" col))
+ ((output-port? obj) (out "#[output-port]" col))
+ ((eof-object? obj) (out "#[eof-object]" col))
+ ((keyword? obj) (let* ((o (symbol->string
+ (keyword-dash-symbol obj)))
+ (oo (list->string
+ (append (list #\# #\:)
+ (cdr (string->list o))))))
+ (out oo col)))
+ (else (out "#[unknown]" col))))
+
+ (define (pp obj col)
+
+ (define (spaces n col)
+ (if (> n 0)
+ (if (> n 7)
+ (spaces (- n 8) (out " " col))
+ (out (substring " " 0 n) col))
+ col))
+
+ (define (indent to col)
+ (and col
+ (if (< to col)
+ (and (out (make-string 1 #\newline) col) (spaces to 0))
+ (spaces (- to col) col))))
+
+ (define (pr obj col extra pp-pair)
+ (if (or (pair? obj) (vector? obj)) ; may have to split on multiple lines
+ (let ((result '())
+ (left (min (+ (- (- width col) extra) 1) max-expr-width)))
+ (generic-write obj display? #f
+ (lambda (str)
+ (set! result (cons str result))
+ (set! left (- left (string-length str)))
+ (> left 0)))
+ (if (> left 0) ; all can be printed on one line
+ (out (reverse-string-append result) col)
+ (if (pair? obj)
+ (pp-pair obj col extra)
+ (pp-list (vector->list obj) (out "#" col) extra pp-expr))))
+ (wr obj col)))
+
+ (define (pp-expr expr col extra)
+ (if (read-macro? expr)
+ (pr (read-macro-body expr)
+ (out (read-macro-prefix expr) col)
+ extra
+ pp-expr)
+ (let ((head (car expr)))
+ (if (symbol? head)
+ (let ((proc (style head)))
+ (if proc
+ (proc expr col extra)
+ (if (> (string-length (symbol->string head))
+ max-call-head-width)
+ (pp-general expr col extra #f #f #f pp-expr)
+ (pp-call expr col extra pp-expr))))
+ (pp-list expr col extra pp-expr)))))
+
+ ; (head item1
+ ; item2
+ ; item3)
+ (define (pp-call expr col extra pp-item)
+ (let ((col* (wr (car expr) (out "(" col))))
+ (and col
+ (pp-down (cdr expr) col* (+ col* 1) extra pp-item))))
+
+ ; (item1
+ ; item2
+ ; item3)
+ (define (pp-list l col extra pp-item)
+ (let ((col (out "(" col)))
+ (pp-down l col col extra pp-item)))
+
+ (define (pp-down l col1 col2 extra pp-item)
+ (let loop ((l l) (col col1))
+ (and col
+ (cond ((pair? l)
+ (let ((rest (cdr l)))
+ (let ((extra (if (null? rest) (+ extra 1) 0)))
+ (loop rest
+ (pr (car l) (indent col2 col) extra pp-item)))))
+ ((null? l)
+ (out ")" col))
+ (else
+ (out ")"
+ (pr l
+ (indent col2 (out "." (indent col2 col)))
+ (+ extra 1)
+ pp-item)))))))
+
+ (define (pp-general expr col extra named? pp-1 pp-2 pp-3)
+
+ (define (tail1 rest col1 col2 col3)
+ (if (and pp-1 (pair? rest))
+ (let* ((val1 (car rest))
+ (rest (cdr rest))
+ (extra (if (null? rest) (+ extra 1) 0)))
+ (tail2 rest col1 (pr val1 (indent col3 col2) extra pp-1) col3))
+ (tail2 rest col1 col2 col3)))
+
+ (define (tail2 rest col1 col2 col3)
+ (if (and pp-2 (pair? rest))
+ (let* ((val1 (car rest))
+ (rest (cdr rest))
+ (extra (if (null? rest) (+ extra 1) 0)))
+ (tail3 rest col1 (pr val1 (indent col3 col2) extra pp-2)))
+ (tail3 rest col1 col2)))
+
+ (define (tail3 rest col1 col2)
+ (pp-down rest col2 col1 extra pp-3))
+
+ (let* ((head (car expr))
+ (rest (cdr expr))
+ (col* (wr head (out "(" col))))
+ (if (and named? (pair? rest))
+ (let* ((name (car rest))
+ (rest (cdr rest))
+ (col** (wr name (out " " col*))))
+ (tail1 rest (+ col indent-general) col** (+ col** 1)))
+ (tail1 rest (+ col indent-general) col* (+ col* 1)))))
+
+ (define (pp-expr-list l col extra)
+ (pp-list l col extra pp-expr))
+
+ (define (pp-LAMBDA expr col extra)
+ (pp-general expr col extra #f pp-expr-list #f pp-expr))
+
+ (define (pp-IF expr col extra)
+ (pp-general expr col extra #f pp-expr #f pp-expr))
+
+ (define (pp-COND expr col extra)
+ (pp-call expr col extra pp-expr-list))
+
+ (define (pp-CASE expr col extra)
+ (pp-general expr col extra #f pp-expr #f pp-expr-list))
+
+ (define (pp-AND expr col extra)
+ (pp-call expr col extra pp-expr))
+
+ (define (pp-LET expr col extra)
+ (let* ((rest (cdr expr))
+ (named? (and (pair? rest) (symbol? (car rest)))))
+ (pp-general expr col extra named? pp-expr-list #f pp-expr)))
+
+ (define (pp-BEGIN expr col extra)
+ (pp-general expr col extra #f #f #f pp-expr))
+
+ (define (pp-DO expr col extra)
+ (pp-general expr col extra #f pp-expr-list pp-expr-list pp-expr))
+
+ ; define formatting style (change these to suit your style)
+
+ (define indent-general 2)
+
+ (define max-call-head-width 5)
+
+ (define max-expr-width 50)
+
+ (define (style head)
+ (case head
+ ((LAMBDA LET* LETREC DEFINE) pp-LAMBDA)
+ ((IF SET!) pp-IF)
+ ((COND) pp-COND)
+ ((CASE) pp-CASE)
+ ((AND OR) pp-AND)
+ ((LET) pp-LET)
+ ((BEGIN) pp-BEGIN)
+ ((DO) pp-DO)
+ (else #f)))
+
+ (pr obj col 0 pp-expr))
+
+ (if width
+ (out (make-string 1 #\newline) (pp obj 0))
+ (wr obj 0)))
+
+; (reverse-string-append l) = (apply string-append (reverse l))
+
+(define (reverse-string-append l)
+
+ (define (rev-string-append l i)
+ (if (pair? l)
+ (let* ((str (car l))
+ (len (string-length str))
+ (result (rev-string-append (cdr l) (+ i len))))
+ (let loop ((j 0) (k (- (- (string-length result) i) len)))
+ (if (< j len)
+ (begin
+ (string-set! result k (string-ref str j))
+ (loop (+ j 1) (+ k 1)))
+ result)))
+ (make-string i)))
+
+ (rev-string-append l 0))
diff --git a/cgen/slib/pp.scm b/cgen/slib/pp.scm
new file mode 100644
index 00000000000..4b245a36325
--- /dev/null
+++ b/cgen/slib/pp.scm
@@ -0,0 +1,10 @@
+;"pp.scm" Pretty-print
+
+; (pretty-print obj port) pretty prints 'obj' on 'port'. The current
+; output port is used if 'port' is not specified.
+
+(define (pp:pretty-print obj . opt)
+ (let ((port (if (pair? opt) (car opt) (current-output-port))))
+ (generic-write obj #f 79 (lambda (s) (display s port) #t))))
+
+(define pretty-print pp:pretty-print)
diff --git a/cgen/slib/sort.scm b/cgen/slib/sort.scm
new file mode 100644
index 00000000000..782f075b77a
--- /dev/null
+++ b/cgen/slib/sort.scm
@@ -0,0 +1,151 @@
+;;; "sort.scm" Defines: sorted?, merge, merge!, sort, sort!
+;;; Author : Richard A. O'Keefe (based on Prolog code by D.H.D.Warren)
+
+;;; Updated: 11 June 1991
+;;; Modified for scheme library: Aubrey Jaffer 19 Sept. 1991
+
+;;; (sorted? sequence less?)
+;;; is true when sequence is a list (x0 x1 ... xm) or a vector #(x0 ... xm)
+;;; such that for all 1 <= i <= m,
+;;; (not (less? (list-ref list i) (list-ref list (- i 1)))).
+
+(define (sort:sorted? seq less?)
+ (cond
+ ((null? seq)
+ #t)
+ ((vector? seq)
+ (let ((n (vector-length seq)))
+ (if (<= n 1)
+ #t
+ (do ((i 1 (+ i 1)))
+ ((or (= i n)
+ (less? (vector-ref seq (- i 1))
+ (vector-ref seq i)))
+ (= i n)) )) ))
+ (else
+ (let loop ((last (car seq)) (next (cdr seq)))
+ (or (null? next)
+ (and (not (less? (car next) last))
+ (loop (car next) (cdr next)) )) )) ))
+
+
+;;; (merge a b less?)
+;;; takes two lists a and b such that (sorted? a less?) and (sorted? b less?)
+;;; and returns a new list in which the elements of a and b have been stably
+;;; interleaved so that (sorted? (merge a b less?) less?).
+;;; Note: this does _not_ accept vectors. See below.
+
+(define (sort:merge a b less?)
+ (cond
+ ((null? a) b)
+ ((null? b) a)
+ (else (let loop ((x (car a)) (a (cdr a)) (y (car b)) (b (cdr b)))
+ ;; The loop handles the merging of non-empty lists. It has
+ ;; been written this way to save testing and car/cdring.
+ (if (less? y x)
+ (if (null? b)
+ (cons y (cons x a))
+ (cons y (loop x a (car b) (cdr b)) ))
+ ;; x <= y
+ (if (null? a)
+ (cons x (cons y b))
+ (cons x (loop (car a) (cdr a) y b)) )) )) ))
+
+
+;;; (merge! a b less?)
+;;; takes two sorted lists a and b and smashes their cdr fields to form a
+;;; single sorted list including the elements of both.
+;;; Note: this does _not_ accept vectors.
+
+(define (sort:merge! a b less?)
+ (define (loop r a b)
+ (if (less? (car b) (car a))
+ (begin
+ (set-cdr! r b)
+ (if (null? (cdr b))
+ (set-cdr! b a)
+ (loop b a (cdr b)) ))
+ ;; (car a) <= (car b)
+ (begin
+ (set-cdr! r a)
+ (if (null? (cdr a))
+ (set-cdr! a b)
+ (loop a (cdr a) b)) )) )
+ (cond
+ ((null? a) b)
+ ((null? b) a)
+ ((less? (car b) (car a))
+ (if (null? (cdr b))
+ (set-cdr! b a)
+ (loop b a (cdr b)))
+ b)
+ (else ; (car a) <= (car b)
+ (if (null? (cdr a))
+ (set-cdr! a b)
+ (loop a (cdr a) b))
+ a)))
+
+
+
+;;; (sort! sequence less?)
+;;; sorts the list or vector sequence destructively. It uses a version
+;;; of merge-sort invented, to the best of my knowledge, by David H. D.
+;;; Warren, and first used in the DEC-10 Prolog system. R. A. O'Keefe
+;;; adapted it to work destructively in Scheme.
+
+(define (sort:sort! seq less?)
+ (define (step n)
+ (cond
+ ((> n 2)
+ (let* ((j (quotient n 2))
+ (a (step j))
+ (k (- n j))
+ (b (step k)))
+ (sort:merge! a b less?)))
+ ((= n 2)
+ (let ((x (car seq))
+ (y (cadr seq))
+ (p seq))
+ (set! seq (cddr seq))
+ (if (less? y x) (begin
+ (set-car! p y)
+ (set-car! (cdr p) x)))
+ (set-cdr! (cdr p) '())
+ p))
+ ((= n 1)
+ (let ((p seq))
+ (set! seq (cdr seq))
+ (set-cdr! p '())
+ p))
+ (else
+ '()) ))
+ (if (vector? seq)
+ (let ((n (vector-length seq))
+ (vec seq))
+ (set! seq (vector->list seq))
+ (do ((p (step n) (cdr p))
+ (i 0 (+ i 1)))
+ ((null? p) vec)
+ (vector-set! vec i (car p)) ))
+ ;; otherwise, assume it is a list
+ (step (length seq)) ))
+
+;;; (sort sequence less?)
+;;; sorts a vector or list non-destructively. It does this by sorting a
+;;; copy of the sequence. My understanding is that the Standard says
+;;; that the result of append is always "newly allocated" except for
+;;; sharing structure with "the last argument", so (append x '()) ought
+;;; to be a standard way of copying a list x.
+
+(define (sort:sort seq less?)
+ (if (vector? seq)
+ (list->vector (sort:sort! (vector->list seq) less?))
+ (sort:sort! (append seq '()) less?)))
+
+;;; eof
+
+(define sorted? sort:sorted?)
+(define merge sort:merge)
+(define merge! sort:merge!)
+(define sort sort:sort)
+(define sort! sort:sort!)
diff --git a/cgen/sparc.cpu b/cgen/sparc.cpu
new file mode 100644
index 00000000000..e60f9d9348d
--- /dev/null
+++ b/cgen/sparc.cpu
@@ -0,0 +1,612 @@
+; SPARC CPU description. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Notes:
+; - sparc64 support wip
+; - fp support todo
+; - source file layout wip
+; - cpu family layout wip
+; - page numbers refered to here are to the sparc architecture reference
+; manuals (v8,v9).
+
+(include "simplify.inc")
+
+(define-arch
+ (name sparc)
+ (comment "Sun SPARC architecture")
+ (insn-lsb0? #t)
+ ; This list isn't currently intended to be identical to BFD's sparc mach
+ ; list. In time if and when there's a need.
+ ; While following the goal of incremental complication, v6,v7,sparclet don't
+ ; appear here either.
+ (machs sparc-v8 sparclite sparc-v9 sparc-v9a)
+ ;(default-mach sparc-v8)
+ (isas sparc)
+)
+
+; Macros to simplify MACH attribute specification.
+(define-pmacro (MACH32) (MACH sparc-v8,sparclite))
+(define-pmacro (MACH64) (MACH sparc-v9,sparc-v9a))
+
+; Attribute to simplify machine specific RTL.
+(define-attr
+ (type boolean)
+ (name ARCH64)
+ (comment "`true' for sparc64 machs")
+)
+
+(define-isa
+ (name sparc)
+ (base-insn-bitsize 32) ; number of bits that can be initially fetched
+ ; Initial bitnumbers to decode insns by.
+ (decode-assist (31 30 24 23 22 21 20 19)) ; 0 1 7 8 9 10 11 12
+)
+
+; The instruction fetch/execute cycle.
+; This is split into two parts as sometimes more than one instruction is
+; decoded at once.
+; The `const 0' argument to decode/execute is used to distinguish
+; multiple instructions processed at the same time (e.g. m32r).
+;
+; ??? This is wip, and not currently used.
+; ??? To be moved into define-arch and define-cpu.
+; ??? It might simplify things to separate the execute process from the
+; one that updates the PC.
+
+; This is how to fetch and extract the fields of an instruction.
+
+;(define-extract
+; (sequence ((USI insn))
+; (set-quiet insn (ifetch: USI pc))
+; (decode pc insn (const 0))
+; )
+;)
+
+; This is how to execute an extracted instruction.
+
+;(define-execute
+; (sequence ((AI new_pc))
+; (set-quiet new_pc (execute AI (const 0)))
+; ; QI mode means just do an assignment, not a jump.
+; ; FIXME: VOID also means something special. Perhaps there's a way
+; ; to use a mode other than QI (WI?) and have something cleaner?
+; (if (attr: HOSTINT insn (const 0) DELAY-SLOT)
+; (if (andif (attr: BI insn (const 0) ANNUL) h-annul-p)
+; (c-call "do_annul")
+; (sequence () ; in delay slot
+; (set-quiet QI pc h-npc)
+; (set-quiet AI h-npc new_pc)))
+; (sequence () ; not in delay slot
+; (set-quiet QI pc h-npc)
+; (set-quiet AI h-npc (add new_pc (const 4))))
+; ))
+;)
+
+; Instruction fields.
+
+(dnf f-op "op" () 31 2)
+(dnf f-op2 "op2" () 24 3)
+(dnf f-op3 "op3" () 24 6)
+(dnf f-rs1 "rs1" () 18 5)
+(dnf f-rs2 "rs2" () 4 5)
+(dnf f-rd "rd" () 29 5)
+(dnf f-rd-res "rd" (RESERVED) 29 5)
+(dnf f-i "i" () 13 1)
+(df f-simm13 "simm13" () 12 13 INT #f #f)
+(dnf f-imm22 "imm22" () 21 22)
+(define-ifield (name f-hi22) (comment "hi22") (attrs)
+ (start 21) (length 22)
+ ; shifting done elsewhere
+ ;(encode (value pc) (srl WI value (const 10)))
+ ;(decode (value pc) (sll WI value (const 10)))
+)
+(dnf f-a "a" () 29 1)
+(dnf f-fmt2-cond "fmt2 cond" () 28 4)
+(df f-disp22 "disp22" (PCREL-ADDR) 21 22 INT
+ ((value pc) (sra WI (sub WI value pc) (const WI 2)))
+ ((value pc) (add WI (sll WI value (const WI 2)) pc)))
+(df f-disp30 "disp30" (PCREL-ADDR) 29 30 INT
+ ((value pc) (sra WI (sub WI value pc) (const WI 2)))
+ ((value pc) (add WI (sll WI value (const WI 2)) pc)))
+(dnf f-opf "opf" () 13 9)
+(dnf f-res-12-8 "reserved bits of simm13 field when i=0" (RESERVED) 12 8)
+(dnf f-simm10 "simm10" () 9 10)
+(dnf f-fmt2-cc "cc" () 21 2)
+(dnf f-fmt3-cc "fmt3 cc" () 26 2)
+(dnf f-x "x" () 12 1)
+(dnf f-shcnt32 "shcnt32" () 4 5)
+(dnf f-fcn "fcn" () 29 5)
+(dnf f-imm-asi "asi" () 12 8)
+(dnf f-asi "asi" () 12 8)
+(dnf f-res-asi "reserved bits in asi position" (RESERVED) 12 8)
+(dnf f-fmt4-cc "fmt4 cc" () 12 2)
+(dnf f-soft-trap "soft trap" () 6 7)
+(dnf f-opf-low5 "opf low5" () 9 5)
+(dnf f-opf-low6 "opf low6" () 10 6)
+(dnf f-opf-cc "cc" () 13 3)
+
+; Enums of opcodes, special insn values, etc.
+; ??? Some of this to be moved and/or split up into sparc{32,64}.cpu.
+
+(define-normal-insn-enum insn-op
+ "main insn opcode field, v8 page ???, v9 page 267"
+ () OP_ f-op
+ ; order is important, the numbers here are actually part of symbols
+ ; (e.g. OP_0, OP_1, OP_2, OP_3) so they must be strings.
+ ("0" "1" "2" "3")
+)
+
+(define-normal-insn-enum insn-op2
+ "op2 insn type, v8 page ???, v9 page 267"
+ () OP2_ f-op2
+ ; order is important
+ ; ??? some of these are for v9 only (ok?)
+ (UNIMP BPCC BICC BPR SETHI FBPFCC FBFCC RESERVED)
+)
+
+(define-normal-insn-enum insn-fmt2
+ "op=2 op3 values, v8 page ??, v9 page 268"
+ () OP3_ f-op3
+ (
+ (ADD 0) (ADDCC 16) ; v9 page 135
+ (ADDX 8) (ADDXCC 24) ; v8 page ??
+ (ADDC 8 ARCH64) (ADDCCC 24 ARCH64) ; v9 page 135
+ (SUB 4) (SUBCC 20) ; v9 page 230
+ (SUBX 12) (SUBXCC 28) ; v8 page ??
+ (SUBC 12 ARCH64) (SUBCCC 28 ARCH64) ; v9 page 230
+ (AND 1) (ANDCC 17) (ANDN 5) (ANDNCC 21)
+ (OR 2) (ORCC 18) (ORN 6) (ORNCC 22)
+ (XOR 3) (XORCC 19) (XNOR 7) (XNORCC 23)
+ (SLL #x25) (SRL #x26) (SRA #x27)
+ (MULSCC #x24 !ARCH64) ; v8 page 112
+ (UMUL #xa) (SMUL #xb) (UMULCC #x1a) (SMULCC #x1b) ; v8 page 113
+ (UDIV #xe) (SDIV #xf) (UDIVCC #x1e) (SDIVCC #x1f)
+
+ (FPOPS1 #x34) (FPOPS2 #x35)
+
+ (SAVE #x3c) (RESTORE #x3d) ; v8 page 117
+ (RETT #x39) ; v8 page 127
+ (JMPL #x38) ; v8 page 126
+
+ (RDY #x28) (RDASR #x28) ; v8 page 131
+ (WRY #x30) (WRASR #x30) ; v8 page 133
+
+ ; v8 page 131
+ (RDPSR #x29 !ARCH64) (RDWIM #x2a !ARCH64) (RDTBR #x2b !ARCH64)
+ ; v8 page 133
+ (WRPSR #x31 !ARCH64) (WRWIM #x32 !ARCH64) (WRTBR #x33 !ARCH64)
+
+ ; v9 page 155
+ (DONE_RETRY #x3e ARCH64)
+ ; v9 page 165
+ (FLUSH #x3b ARCH64)
+ ; v9 page 167
+ (FLUSHW #x2b ARCH64)
+ ; v9 page 169
+ (IMPDEP1 #x36 ARCH64) (IMPDEP2 #x37 ARCH64)
+ ; v9 page 183
+ (MEMBAR #x28 ARCH64)
+ ; v9 page 191
+ (MOVCC #x2c ARCH64)
+ )
+)
+
+(define-normal-insn-enum insn-fmt3
+ "op=3 op3 values, v8 page ???, v9 page 269"
+ () OP3_ f-op3
+ (; order is important
+ LDUW LDUB LDUH LDD
+ STW STB STH STD
+ (LDSW - ARCH64) LDSB LDSH (LDX - ARCH64)
+ RES12 LDSTUB (STX - ARCH64) SWAP
+
+ LDUWA LDUBA LDUHA LDDA
+ STWA STBA STHA STDA
+ (LDSWA - ARCH64) LDSBA LDSHA (LDXA - ARCH64)
+ RES28 LDSTUBA (STXA - ARCH64) SWAPA
+
+ LDF (LDFSR #x21) (LDXFSR #x21) LDQF LDDF
+ STF (STFSR #x25) (STXFSR #x25) STQF STDF
+ RES40 RES41 RES42 RES43
+ RES44 PREFETCH RES46 RES47
+
+ LDFA RES49 LDQFA LDDFA
+ STFA RES53 STQFA STDFA
+ RES56 RES57 RES58 RES59
+ (CASA - ARCH64) (PREFETCHA - ARCH64) (CASXA - ARCH64) RES63
+ )
+)
+
+(define-normal-insn-enum rd-insn
+ "rd insn type"
+ () RD_ f-rd
+ (; order is important
+ Y RES1 CCR ASI TICK PC FPRS ASR7
+ ASR8 ASR9 ASR10 ASR11 ASR12 ASR13 ASR14 MEMBAR_STBAR
+ )
+)
+
+(define-normal-insn-enum wr-insn
+ "wr insn type"
+ () WR_ f-rd
+ (; order is important
+ Y RES1 CCR ASI ASR4 ASR5 FPRS ASR7
+ ASR8 ASR9 ASR10 ASR11 ASR12 ASR13 ASR14 SIGM
+ )
+)
+
+; The standard condition code tests.
+
+(define-normal-insn-enum cc-tests
+ "condition code tests, v8 page ???, v9 page 144"
+ () "" f-fmt2-cond
+ (
+ (CC_A 8) ; always
+ (CC_N 0) ; never
+ (CC_NE 9) ; not equal
+ (CC_NZ 9) ; not zero
+ (CC_E 1) ; equal
+ (CC_Z 1) ; zero
+ (CC_G 10) ; greater
+ (CC_LE 2) ; less or equal
+ (CC_GE 11) ; greater or equal
+ (CC_L 3) ; less
+ (CC_GU 12) ; unsigned greater
+ (CC_LEU 4) ; unsigned less or equal
+ (CC_CC 13) ; carry clear
+ (CC_GEU 13) ; unsigned greater or equal
+ (CC_CS 5) ; carry set
+ (CC_LU 5) ; unsigned less than
+ (CC_POS 14) ; positive
+ (CC_NEG 6) ; negative
+ (CC_VC 15) ; overflow clear
+ (CC_VS 7) ; overflow set
+ )
+)
+
+; Floating point condition code tests.
+
+(define-normal-insn-enum fcc-tests
+ "condition code tests, v8 page ???, v9 page 138"
+ () "FCOND_" f-fmt2-cond
+ (
+ (A 8) ; always
+ (N 0) ; never
+ (U 7) ; unordered
+ (G 6) ; greater
+ (UG 5) ; unordered or greater
+ (L 4) ; less
+ (UL 3) ; unordered or less
+ (LG 2) ; less or greater
+ (NE 1) ; less or greater or unordered (not equal)
+ (E 9) ; equal
+ (UE 10) ; unordered or equal
+ (GE 11) ; greater or equal
+ (UGE 12) ; unordered or greater or equal
+ (LE 13) ; less or equal
+ (ULE 14) ; unordered or less or equal
+ (O 15) ; equal or less or greater (ordered)
+ )
+)
+
+(define-normal-insn-enum fcc-value "fcc value" () FCC_ f-fmt2-cc
+ (EQ LT GT UN)
+)
+
+(define-normal-insn-enum fpop1
+ "fp op 1, v8 page ???, v9 page 270"
+ () FPOPS1_ f-opf
+ (
+ (FMOVS 1) (FMOVD 2) (FMOVQ 3)
+ (FNEGS 5) (FNEGD 6) (FNEGQ 7)
+ (FABSS 9) (FABSD 10) (FABSQ 11)
+ (FSQRTS #x29) (FSQRTD #x2a) (FSQRTQ #x2b)
+ (FADDS #x41) (FADDD #x42) (FADDQ #x43)
+ (FSUBS #x45) (FSUBD #x46) (FSUBQ #x47)
+ (FMULS #x49) (FMULD #x4a) (FMULQ #x4b)
+ (FDIVS #x4d) (FDIVD #x4e) (FDIVQ #x4f)
+ (FSMULD #x69) (FDMULQ #x6e)
+ (FSTOX #x81) (FDTOX #x82) (FQTOX #x83)
+ (FXTOS #x84) (FXTOD #x88) (FXTOQ #x8c)
+ (FITOS #xc4) (FDTOS #xc6) (FQTOS #xc7)
+ (FITOD #xc8) (FSTOD #xc9) (FQTOD #xcb)
+ (FITOQ #xcc) (FSTOQ #xcd) (FDTOQ #xce)
+ (FSTOI #xd1) (FDTOI #xd2) (FQTOI #xd3)
+ (MAX 511)
+ )
+)
+
+; ??? check MACH64, are all v9 only?
+
+(define-normal-insn-enum fpop2
+ "fp op 2, v9 page 271"
+ (ARCH64) FPOPS2_ f-opf
+ (
+ (FCMPS #x51) (FCMPD #x52) (FCMPQ #x53)
+ (FCMPSE #x55) (FCMPDE #x56) (FCMPQE #x57)
+ (FMOVSFCC0 #x01) (FMOVDFCC0 #x02) (FMOVQFCC0 #x03)
+ (FMOVSFCC1 #x41) (FMOVDFCC1 #x42) (FMOVQFCC1 #x43)
+ (FMOVSFCC2 #x81) (FMOVDFCC2 #x82) (FMOVQFCC2 #x83)
+ (FMOVSFCC3 #xc1) (FMOVDFCC3 #xc2) (FMOVQFCC3 #xc3)
+ (FMOVSICC #x101) (FMOVDICC #x102) (FMOVQICC #x103)
+ (FMOVSXCC #x181) (FMOVDXCC #x182) (FMOVQXCC #x183)
+ (FMOVRZS #x25) (FMOVRZD #x26) (FMOVRZQ #x27)
+ (FMOVRLEZS #x45) (FMOVRLEZD #x46) (FMOVRLEZQ #x47)
+ (FMOVRLZS #x65) (FMOVRLZD #x66) (FMOVRLZQ #x67)
+ (FMOVRNZS #xa5) (FMOVRNZD #xa6) (FMOVRNZQ #xa7)
+ (FMOVRGZS #xc5) (FMOVRGZD #xc6) (FMOVRGZQ #xc7)
+ (FMOVRGEZS #xe5) (FMOVRGEZD #xe6) (FMOVRGEZQ #xe7)
+ (MAX 511)
+ )
+)
+
+; Hardware pieces.
+; These are common to all (or most all) machs.
+
+(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())
+
+(define-hardware
+ (name h-npc)
+ (comment "next pc")
+ (attrs PC)
+ (type register WI)
+)
+
+(define-keyword
+ (name gr-names)
+ (print-name h-gr)
+ (prefix "%")
+ (values (fp 30) (sp 14)
+ (g0 0) (g1 1) (g2 2) (g3 3) (g4 4) (g5 5) (g6 6) (g7 7)
+ (o0 8) (o1 9) (o2 10) (o3 11) (o4 12) (o5 13) (o6 14) (o7 15)
+ (l0 16) (l1 17) (l2 18) (l3 19) (l4 20) (l5 21) (l6 22) (l7 23)
+ (i0 24) (i1 25) (i2 26) (i3 27) (i4 28) (i5 29) (i6 30) (i7 31)
+ )
+)
+
+; The general registers are accessed via a level of indirection to handle
+; the register windows. h-gr provides the top level entry point which is
+; indirected through various means depending upon the register window
+; implementation of the day. To be solidified in time.
+;
+; ??? Separation of h-gr for sparc32/64 is currently an experiment.
+
+(define-hardware
+ (name h-gr) ; h-gr32
+ ;(semantic-name h-gr)
+ (comment "sparc32 general registers")
+ (attrs PROFILE VIRTUAL (MACH32))
+ (type register SI (32))
+ (indices extern-keyword gr-names) ; keyword "%" (h-gr-indices))
+ (get (index) (c-call SI "GET_H_GR_RAW" index))
+ (set (index newval) (c-call VOID "SET_H_GR_RAW" index newval))
+)
+
+(define-hardware
+ (name h-gr) ; h-gr64
+ ;(semantic-name h-gr)
+ (comment "sparc64 general registers")
+ (attrs PROFILE VIRTUAL (MACH64))
+ (type register DI (32))
+ (indices extern-keyword gr-names) ; keyword "%" (h-gr-indices))
+ (get (index) (c-call SI "GET_H_GR_RAW" index))
+ (set (index newval) (c-call VOID "SET_H_GR_RAW" index newval))
+)
+
+(define-hardware
+ (name h-a)
+ (comment "annul bit")
+ (type immediate (UINT 1))
+ (values keyword "" (("" 0) (",a" 1)))
+)
+
+; The condition code bits.
+(dsh h-icc-c "icc carry bit" () (register BI))
+(dsh h-icc-n "icc negative bit" () (register BI))
+(dsh h-icc-v "icc overflow bit" () (register BI))
+(dsh h-icc-z "icc zero bit" () (register BI))
+
+; The extended condition code bits of v9.
+(dsh h-xcc-c "xcc carry bit" (ARCH64) (register BI))
+(dsh h-xcc-n "xcc negative bit" (ARCH64) (register BI))
+(dsh h-xcc-v "xcc overflow bit" (ARCH64) (register BI))
+(dsh h-xcc-z "xcc zero bit" (ARCH64) (register BI))
+
+; Misc. regs.
+
+; h-y is virtual because the real value is kept in the asr array.
+; ??? wip is get/set fields
+(define-hardware
+ (name h-y)
+ (comment "y register")
+ (attrs VIRTUAL)
+ (type register WI)
+ (get () (reg WI h-asr 0))
+ (set (newval) (set (reg WI h-asr 0) newval))
+)
+
+(dnh h-asr "ancilliary state registers" ()
+ (register WI (32))
+ (keyword "%"
+ (
+ (y 0)
+ (asr0 0) (asr1 1) (asr2 2) (asr3 3)
+ (asr4 4) (asr5 5) (asr6 6) (asr7 7)
+ (asr8 8) (asr9 9) (asr10 10) (asr11 11)
+ (asr12 12) (asr13 13) (asr14 14) (asr15 15)
+ (asr16 16) (asr17 17) (asr18 18) (asr19 19)
+ (asr20 20) (asr21 21) (asr22 22) (asr23 23)
+ (asr24 24) (asr25 25) (asr26 26) (asr27 27)
+ (asr28 28) (asr29 29) (asr30 30) (asr31 31)
+ ))
+ ()
+ ()
+) ; FIXME:wip
+
+; This assists the simulator engine, not part of the architecture.
+; ??? There should be an attribute for these critters.
+(dsh h-annul-p "annul next insn? - assists execution" () (register BI))
+
+; %lo,%hi,etc.
+
+(dnh h-lo10 "signed low 10 bits" ()
+ (immediate (UINT 10)) ; integer (UNSIGNED) 10))
+ () () ()
+)
+
+(dnh h-lo13 "signed low 13 bits" ()
+ (immediate (INT 13)) ; integer (SIGNED) 13))
+ () () ()
+)
+
+(dnh h-hi22 "unsigned high 22 bits" ()
+ (immediate (UINT 22)) ; integer (UNSIGNED) 22))
+ () () ()
+)
+
+; Instruction Operands.
+
+(dnop rs1 "source register 1" () h-gr f-rs1)
+(dnop rs2 "source register 2" () h-gr f-rs2)
+(dnop rd "destination register" () h-gr f-rd)
+
+; double-reg args to ldd,std
+
+(define-operand
+ (name rdd)
+ (comment "rd as two registers")
+ (type h-gr)
+ (index f-rd)
+; (get (args self index)
+; (mode (DI)
+; (eq (and index (const 1)) (const 0)) ; predicate, even regs only
+; (make: DI SI
+; (reg h-gr index)
+; (reg h-gr (add index (const 1)))))
+; )
+; (set (args self index newval)
+; (mode (DI)
+; (eq (and index (const 1)) (const 0)) ; predicate, even regs only
+; (sequence ()
+; (set (reg h-gr index)
+; (slice: SI DI newval (const 0)))
+; (set (reg h-gr (add index (const 1)))
+; (slice: SI DI newval (const 1)))))
+; )
+; (asm (parse "rdd"))
+)
+
+(dnop simm13 "13 bit signed immediate" () h-lo13 f-simm13)
+(dnop imm22 "22 bit unsigned immediate" () h-uint f-imm22)
+
+(dnop a "annul bit" () h-a f-a)
+
+(dnop icc-c "carry flag" (SEM-ONLY) h-icc-c f-nil)
+(dnop icc-v "overflow flag" (SEM-ONLY) h-icc-v f-nil)
+(dnop icc-n "negative flag" (SEM-ONLY) h-icc-n f-nil)
+(dnop icc-z "zero flag" (SEM-ONLY) h-icc-z f-nil)
+
+(dnop xcc-c "extended carry flag" (SEM-ONLY) h-xcc-c f-nil)
+(dnop xcc-v "extended overflow flag" (SEM-ONLY) h-xcc-v f-nil)
+(dnop xcc-n "extended negative flag" (SEM-ONLY) h-xcc-n f-nil)
+(dnop xcc-z "extended zero flag" (SEM-ONLY) h-xcc-z f-nil)
+
+; These two map h-asr to f-rs1 and f-rd so we have something to use in
+; the assembler spec, insn format, and semantic fields.
+; FIXME: 'twould be nice if we could do this mapping on the fly in the
+; define-insn (i.e. the old (%0,%1 stuff)).
+(dnop rdasr "read asr operand" () h-asr f-rs1)
+(dnop wrasr "write asr operand" () h-asr f-rd)
+
+(dnop asi "asi field" () h-uint f-asi)
+
+(dnop disp22 "22 bit displacement" () h-iaddr f-disp22)
+(dnop disp30 "30 bit displacement" () h-iaddr f-disp30)
+
+(define-operand
+ (name lo10)
+ (comment "10 bit signed immediate, for %lo()")
+ (type h-lo10)
+ (index f-simm10)
+ (handlers (parse "lo10"))
+)
+(define-operand
+ (name lo13)
+ (comment "13 bit signed immediate, for %lo()")
+ (type h-lo13)
+ (index f-simm13)
+ (handlers (parse "lo13"))
+)
+(define-operand
+ (name hi22)
+ (comment "22 bit unsigned immediate, for %hi()")
+ (type h-hi22)
+ (index f-hi22)
+ (handlers (parse "hi22") (print "hi22"))
+)
+
+; SPARC specific instruction attributes used:
+
+(define-attr
+ (for insn)
+ (type boolean)
+ (name TRAP)
+ (comment "insn is a trap insn")
+)
+
+(define-attr
+ (for insn)
+ (type boolean)
+ (name V9-DEPRECATED)
+ (comment "insn is deprecated in v9")
+)
+
+; Globally useful macros.
+
+; CC is one of icc,xcc.
+; ??? Might want canonical forms of these.
+; ??? Maybe move this to a library.
+; ??? bitfields still on todo list
+(define-pmacro (test-always cc) (const 1))
+(define-pmacro (test-never cc) (const 0))
+(define-pmacro (test-ne cc) (not (.sym cc -z)))
+(define-pmacro (test-eq cc) (.sym cc -z))
+(define-pmacro (test-gt cc) (not (or (.sym cc -z) (xor (.sym cc -n) (.sym cc -v)))))
+(define-pmacro (test-le cc) (or (.sym cc -z) (xor (.sym cc -n) (.sym cc -v))))
+(define-pmacro (test-ge cc) (not (xor (.sym cc -n) (.sym cc -v))))
+(define-pmacro (test-lt cc) (xor (.sym cc -n) (.sym cc -v)))
+(define-pmacro (test-gtu cc) (not (or (.sym cc -c) (.sym cc -z))))
+(define-pmacro (test-leu cc) (or (.sym cc -c) (.sym cc -z)))
+(define-pmacro (test-geu cc) (not (.sym cc -c)))
+(define-pmacro (test-ltu cc) (.sym cc -c))
+(define-pmacro (test-pos cc) (not (.sym cc -n)))
+(define-pmacro (test-neg cc) (.sym cc -n))
+(define-pmacro (test-vc cc) (not (.sym cc -v)))
+(define-pmacro (test-vs cc) (.sym cc -v))
+
+(define-pmacro (uncond-br-sem test cc)
+ (delay (const 1)
+ (sequence ()
+ (if (test cc)
+ (set pc disp22))
+ (annul a)))
+)
+(define-pmacro (cond-br-sem test cc)
+ (delay (const 1)
+ (if (test cc)
+ (set pc disp22)
+ (annul a)))
+)
+
+; The rest is broken out into various files.
+
+(if (keep-mach? (sparc-v8 sparclite))
+ (include "sparc32.cpu"))
+
+(if (keep-mach? (sparc-v9 sparc-v9a))
+ (include "sparc64.cpu"))
+
+(include "sparccom.cpu")
+(include "sparcfpu.cpu")
diff --git a/cgen/sparc.opc b/cgen/sparc.opc
new file mode 100644
index 00000000000..cbc025b2916
--- /dev/null
+++ b/cgen/sparc.opc
@@ -0,0 +1,180 @@
+/* SPARC opcode support. -*- C -*-
+ Copyright (C) 2000 Red Hat, Inc.
+ This file is part of CGEN.
+ This file is copyrighted with the GNU General Public License.
+ See file COPYING for details. */
+
+/* This file is an addendum to sparc.cpu. Heavy use of C code isn't
+ appropriate in .cpu files, so it resides here. This especially applies
+ to assembly/disassembly where parsing/printing can be quite involved.
+ Such things aren't really part of the specification of the cpu, per se,
+ so .cpu files provide the general framework and .opc files handle the
+ nitty-gritty details as necessary.
+
+ Each section is delimited with start and end markers.
+
+ <cpu>-opc.h additions use: "-- opc.h"
+ <cpu>-opc.c additions use: "-- opc.c"
+ <cpu>-asm.c additions use: "-- asm.c"
+ <cpu>-dis.c additions use: "-- dis.c"
+*/
+
+/* -- opc.h */
+
+#undef CGEN_DIS_HASH_SIZE
+#define CGEN_DIS_HASH_SIZE 256
+#undef CGEN_DIS_HASH
+extern const unsigned int sparc_cgen_opcode_bits[];
+#define CGEN_DIS_HASH(buffer, insn) \
+((((insn) >> 24) & 0xc0) \
+ | (((insn) & sparc_cgen_opcode_bits[((insn) >> 30) & 3]) >> 19))
+
+/* -- */
+
+/* -- asm.c */
+
+/* It is important that we only look at insn code bits as that is how the
+ opcode table is hashed. OPCODE_BITS is a table of valid bits for each
+ of the main types (0,1,2,3). */
+const unsigned int sparc_cgen_opcode_bits[4] = {
+ 0x01c00000, 0x0, 0x01f80000, 0x01f80000
+};
+
+/* Handle %lo(). */
+
+static const char *
+parse_lo10 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (strncasecmp (*strp, "%lo(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (od, strp, opindex, BFD_RELOC_LO10,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ value &= 0x3ff;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (od, strp, opindex, valuep);
+}
+
+static const char *
+parse_lo13 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (strncasecmp (*strp, "%lo(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (od, strp, opindex, BFD_RELOC_LO10,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ value &= 0x3ff;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (od, strp, opindex, valuep);
+}
+
+/* Handle %hi(). */
+
+static const char *
+parse_hi22 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (strncasecmp (*strp, "%hi(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (od, strp, opindex, BFD_RELOC_HI22,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value >>= 10;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (od, strp, opindex, valuep);
+}
+
+/* -- */
+
+/* -- dis.c */
+
+/* Include "%hi(foo)" in sethi output. */
+
+static void
+print_hi22 (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ disassemble_info *info = (disassemble_info *) dis_info;
+ (*info->fprintf_func) (info->stream, "%%hi(0x%lx)", value << 10);
+}
+
+#undef CGEN_PRINT_INSN
+#define CGEN_PRINT_INSN my_print_insn
+
+static int
+my_print_insn (cd, pc, info)
+ CGEN_CPU_DESC cd;
+ bfd_vma pc;
+ disassemble_info *info;
+{
+ char buffer[CGEN_MAX_INSN_SIZE];
+ char *buf = buffer;
+ int status;
+ unsigned long insn_value;
+ int len;
+
+ /* Read the base part of the insn. */
+
+ status = (*info->read_memory_func) (pc, buf, 4, info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, pc, info);
+ return -1;
+ }
+
+ len = print_insn (od, pc, info, buf, 4);
+ if (len != 0)
+ return len;
+
+ /* CGEN doesn't handle this insn yet. Fall back on old way. */
+ return old_print_insn_sparc (pc, info);
+}
+
+/* -- */
diff --git a/cgen/sparc32.cpu b/cgen/sparc32.cpu
new file mode 100644
index 00000000000..7634223d407
--- /dev/null
+++ b/cgen/sparc32.cpu
@@ -0,0 +1,170 @@
+; SPARC32 CPU description. -*- Scheme -*-
+; This file contains elements specific to sparc32.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Notes:
+; - sparc64 support wip
+; - fp support todo
+; - source file layout wip
+; - cpu family layout wip
+
+; ??? For the nonce there is one cpu family to cover all 32 bit sparcs.
+; It's not clear this will work, but following the goal of incremental
+; complication ....
+
+(define-cpu
+ (name sparc32)
+ (comment "SPARC 32 bit architecture")
+ (endian big)
+ (word-bitsize 32)
+ ; Generated files have a "32" suffix.
+ (file-transform "32")
+)
+
+(define-mach
+ (name sparc-v8)
+ (comment "sparc v8")
+ (cpu sparc32)
+ (bfd-name "sparc")
+)
+
+(define-mach
+ (name sparclite)
+ (comment "Fujitsu sparclite")
+ (cpu sparc32)
+ (bfd-name "sparc_sparclite")
+)
+
+; sparc32 models
+
+(define-model
+ (name sparc32-def)
+ (comment "sparc32 default")
+ (attrs)
+ (mach sparc-v8)
+ ; wip
+ (pipeline p-foo "" () ((fetch) (decode) (execute) (memory) (writeback)))
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () () () ())
+)
+
+; sparc32 enums of opcodes, special insn values, etc.
+
+; sparc32 hardware pieces.
+
+; ??? impl,ver are left as part of h-psr (change maybe later)
+(define-hardware
+ (name h-psr)
+ (comment "psr register")
+ (type register USI)
+ (get () (c-call USI "@cpu@_get_h_psr_handler"))
+ (set (newval) (c-call VOID "@cpu@_set_h_psr_handler" newval))
+)
+
+(dsh h-s "supervisor bit" () (register BI))
+(dsh h-ps "previous supervisor bit" () (register BI))
+
+(dsh h-pil "processor interrupt level" () (register UQI))
+
+(dsh h-et "enable traps bit" () (register BI))
+
+(define-hardware
+ (name h-tbr)
+ (comment "trap base register")
+ (type register WI)
+ ;CPU (h_tbr) = (CPU (h_tbr) & 0xff0) | ((newval) & 0xfffff000);
+ (set (newval) (set (raw-reg WI h-tbr)
+ (or WI (and WI (raw-reg WI h-tbr) (const #xff0))
+ (and WI newval (const #xfffff000)))))
+)
+
+(define-hardware
+ (name h-cwp)
+ (comment "current window pointer")
+ (type register UQI)
+ (set (newval) (c-call VOID "@cpu@_set_h_cwp_handler" newval))
+)
+
+(define-hardware
+ (name h-wim)
+ (comment "window invalid mask")
+ (type register USI)
+ ; ??? These just put ideas down so I can play with them. Ignore.
+ ;(get (value index) (and SI value (c-code SI "((1 << NWINDOWS) - 1)")))
+ ;(get (self mode index insn)
+ ; (c-code USI "(CPU (h_wim) & ((1 << NWINDOWS) - 1))"))
+ ;(set (self mode index insn newval)
+ ; (s-eval `(set SI ,self (and SI ,newval (const #xff)))))
+ (get () (and (raw-reg USI h-wim)
+ (sub (sll (const 1) (c-raw-call SI "GET_NWINDOWS")) (const 1))))
+)
+
+(dsh h-ag "alternate global indicator" () (register QI))
+
+; Coprocessor support.
+
+(dsh h-ec "enable coprocessor bit" () (register BI))
+
+; Floating point support.
+; wip.
+; - currently evaluating the various possibilities
+
+(dsh h-ef "enable fpu bit" () (register BI))
+
+(dsh h-fsr "floating point status register" () (register USI))
+
+; sparc32 instruction definitions.
+
+; Special register move operations.
+
+; %y is handled by the asr insns
+
+(dni rd-asr "read asr" ()
+ "rd $rdasr,$rd" ; note: `rdasr' is for ReaD asr, `rd' is for Reg Dest.
+ (+ OP_2 OP3_RDASR rd rdasr (f-i 0) (f-simm13 0))
+ (set rd rdasr)
+ ())
+(dni wr-asr "write asr" ()
+ "wr $rs1,$rs2,$wrasr"
+ (+ OP_2 OP3_WRASR wrasr rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set wrasr (xor rs1 rs2))
+ ())
+(dni wr-asr-imm "write-imm asr" ()
+ "wr $rs1,$simm13,$wrasr"
+ (+ OP_2 OP3_WRASR wrasr rs1 (f-i 1) simm13)
+ (set wrasr (xor rs1 simm13))
+ ())
+
+(define-pmacro (rdwr-op name op3 asm-name reg-name)
+ (begin
+ (dni (.sym rd- name) (.str "read " name) ()
+ (.str "rd " asm-name ",$rd")
+ (+ OP_2 (.sym OP3_RD op3) rd (f-rs1 0) (f-i 0) (f-simm13 0))
+ (set rd (reg WI reg-name))
+ ())
+ (dni (.sym wr- name) (.str "write " name) ()
+ (.str "wr $rs1,$rs2," asm-name)
+ (+ OP_2 (.sym OP3_WR op3) (f-rd 0) rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set (reg WI reg-name) (xor rs1 rs2))
+ ())
+ (dni (.sym wr- name -imm) (.str "write-imm " name) ()
+ (.str "wr $rs1,$simm13," asm-name)
+ (+ OP_2 (.sym OP3_WR op3) (f-rd 0) rs1 (f-i 1) simm13)
+ (set (reg WI reg-name) (xor rs1 simm13))
+ ())
+ )
+)
+
+(rdwr-op psr PSR "%psr" h-psr)
+(rdwr-op wim WIM "%wim" h-wim)
+(rdwr-op tbr TBR "%tbr" h-tbr)
+
+; TODO:
+; - rdy,wry
+; - stbar
+; - flush
+; - ldc, lddc, ldcsr, stc, stdc, stcsr, stdcq
+; - cbccc, cpop
diff --git a/cgen/sparc64.cpu b/cgen/sparc64.cpu
new file mode 100644
index 00000000000..1c4301b5532
--- /dev/null
+++ b/cgen/sparc64.cpu
@@ -0,0 +1,422 @@
+; SPARC64 CPU description. -*- Scheme -*-
+; This file contains elements specific to sparc64.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Notes:
+; - sparc64 support wip
+; - fp support todo
+; - source file layout wip
+; - cpu family layout wip
+
+; ??? For the nonce there is one cpu family to cover all 64 bit sparcs.
+; It's not clear this will work, but following the goal of incremental
+; complication ....
+
+(define-cpu
+ (name sparc64)
+ (comment "SPARC 64 bit architecture")
+ (endian big) ; ??? big insn, either data
+ (word-bitsize 64)
+ ; Generated files have a "64" suffix.
+ (file-transform "64")
+)
+
+(define-mach
+ (name sparc-v9)
+ (comment "sparc v9")
+ ;(attrs S64-P)
+ (cpu sparc64)
+ (bfd-name "sparc_v9")
+)
+
+(define-mach
+ (name sparc-v9a)
+ (comment "sparc v9a (sparc-v9 + vis)")
+ ;(attrs S64-P)
+ (cpu sparc64)
+ (bfd-name "sparc_v9a")
+)
+
+; sparc64 models
+
+(define-model
+ (name sparc64-def)
+ (comment "sparc64 default")
+ (attrs)
+ (mach sparc-v9)
+ ; wip (Meaning, yes I know this is inaccurate, duh ...
+ ; When I have time I'll finish this up right.
+ ; Support for some of this isn't even implemented yet and support for the
+ ; rest will be rewritten.)
+ (pipeline p-foo "" () ((fetch) (decode) (execute) (memory) (writeback)))
+ (unit u-exec "Execution Unit" ()
+ 1 1 ; issue done
+ () () () ())
+)
+
+; sparc64 instruction fields
+
+(dnf f-fmt2-cc1 "cc" ((MACH64)) 21 1)
+(dnf f-fmt2-cc0 "cc" ((MACH64)) 20 1)
+(dnf f-p "p" ((MACH64)) 19 1)
+(dnf f-fmt2-rcond "fmt2 rcond" ((MACH64)) 27 3)
+(df f-disp19 "disp19" (PCREL-ADDR (MACH64)) 13 19 INT #f #f)
+(dnf f-fmt3-rcond "fmt3 rcond" ((MACH64)) 19 3)
+(dnf f-shcnt64 "shcnt64" ((MACH64)) 5 6)
+(dnf f-fmt4-cond "cond" ((MACH64)) 14 4)
+(dnf f-fmt4-ccx-hi "ccx hi" ((MACH64)) 13 1)
+(dnf f-fmt4-ccx-lo "ccx lo" ((MACH64)) 19 2)
+(dnf f-fmt4-rcond "fmt4 rcond" ((MACH64)) 19 3)
+(dnf f-fmt4-cc2 "fmt4 cc2" ((MACH64)) 18 1)
+(dnf f-fmt4-cc1-0 "fmt4 cc1,cc0" ((MACH64)) 12 2)
+(dnf f-fmt4-res10-6 "reserved bits in movcc insns" (RESERVED (MACH64)) 10 6)
+
+; The disp16 field requires a bit of special handling as it is split in two.
+(df f-disp16-hi "disp16 hi" ((MACH64)) 10 2 INT #f #f)
+(dnf f-disp16-lo "disp16 lo" ((MACH64)) 18 14)
+(dnmf f-disp16 "disp16" (PCREL-ADDR (MACH64)) INT
+ (f-disp16-hi f-disp16-lo)
+ (sequence () ; insert
+ (set (ifield f-disp16-hi) (srl (ifield f-disp16) (const 14)))
+ (set (ifield f-disp16-lo) (and (ifield f-disp16) (const #x3fff)))
+ )
+ (sequence () ; extract
+ ; ??? where will pc be added?
+ (set (ifield f-disp16) (or (sll (ifield f-disp16-hi) (const 14))
+ (ifield f-disp16-low)))
+ )
+)
+
+(dnf f-res-18-19 "reserved bits in done/retry" (RESERVED (MACH64)) 18 19)
+
+; sparc64 enums of opcodes, special insn values, etc.
+
+(define-normal-insn-enum insn-rcond "rcond op values" () RCOND_ f-fmt2-rcond
+ (
+ (BRZ 1)
+ (BRLEZ 2)
+ (BRLZ 3)
+ (BRNZ 5)
+ (BRGZ 6)
+ (BRGEZ 7)
+ )
+)
+
+; sparc64 hardware pieces.
+
+(dsh h-ver "version" ((MACH64)) (register UDI))
+
+(dsh h-pstate "processor state" ((MACH64)) (register UDI))
+
+(dsh h-tba "trap base address" ((MACH64)) (register UDI))
+
+; FIXME: These are a stack of values.
+(dsh h-tt "trap type" ((MACH64)) (register UDI))
+(dsh h-tpc "trap pc" ((MACH64)) (register UDI))
+(dsh h-tnpc "trap npc" ((MACH64)) (register UDI))
+(dsh h-tstate "trap state" ((MACH64)) (register UDI))
+
+(dsh h-tl "trap level" ((MACH64)) (register UQI))
+
+(dsh h-asi "address space identifier" ((MACH64)) (register UQI))
+
+(dsh h-tick "tick counter" ((MACH64)) (register UDI))
+
+(dsh h-cansave "savable window registers" ((MACH64)) (register UDI))
+(dsh h-canrestore "restorable window registers" ((MACH64)) (register UDI))
+(dsh h-otherwin "other window registers" ((MACH64)) (register UDI))
+(dsh h-cleanwin "clean window registers" ((MACH64)) (register UDI))
+
+(dsh h-wstate "window state" ((MACH64)) (register UDI))
+
+(define-hardware
+ (name h-ixcc)
+ (comment "condition code selector")
+ (attrs (MACH64))
+ (type immediate (UINT 1))
+ (values keyword "%" (("icc" 0) ("xcc" 1)))
+)
+
+(define-hardware
+ (name h-p)
+ (comment "prediction bit")
+ (attrs (MACH64))
+ (type immediate (UINT 1))
+ (values keyword "" (("" 0) (",pf" 0) (",pt" 1)))
+)
+
+; sparc64 operands
+
+(dnop ixcc "%icc,%xcc arg to bpcc insns" ((MACH64)) h-ixcc f-fmt2-cc1)
+
+(dnop p "prediction bit" ((MACH64)) h-p f-p)
+
+(dnop disp16 "16 bit displacement" ((MACH64)) h-iaddr f-disp16)
+(dnop disp19 "19 bit displacement" ((MACH64)) h-iaddr f-disp19)
+
+; sparc64 branches
+
+(dnf f-bpr-res28-1 "reserved bit 28 in bpr insn" (RESERVED (MACH64)) 28 1)
+
+(define-pmacro (bpr-cbranch name comment rcond-op comp-op)
+ (dni name (.str comment ", v9 page 136")
+ ((MACH64))
+ (.str name "$a$p $rs1,$disp16")
+ (+ OP_0 a (f-bpr-res28-1 0) (.sym RCOND_ rcond-op)
+ OP2_BPR p rs1 disp16)
+ (delay (const 1)
+ (if (comp-op rs1 (const 0))
+ (set pc disp16)
+ (annul a)))
+ ())
+)
+(bpr-cbranch beqz "beqz" BRZ eq)
+(bpr-cbranch bgez "bgez" BRGEZ ge)
+(bpr-cbranch bgtz "bgtz" BRGZ gt)
+(bpr-cbranch blez "blez" BRLEZ le)
+(bpr-cbranch bltz "bltz" BRLZ lt)
+(bpr-cbranch bnez "bnez" BRNZ ne)
+
+(define-pmacro (bpcc-branch bname comment cond test br-sem)
+ (dni (.sym bpcc- bname)
+ (.str "branch with prediction %icc " comment ", v9 page 146")
+ ((MACH64))
+ (.str bname "$a$p %icc,$disp19")
+ (+ OP_0 a cond OP2_BPCC (f-fmt2-cc1 0) (f-fmt2-cc0 0) p disp19)
+ (br-sem test icc)
+ ())
+ (dni (.sym bpcc- bname)
+ (.str "branch with prediction %xcc " comment ", v9 page 146")
+ ((MACH64))
+ (.str bname "$a$p %xcc,$disp19")
+ (+ OP_0 a cond OP2_BPCC (f-fmt2-cc1 1) (f-fmt2-cc0 0) p disp19)
+ (br-sem test xcc)
+ ())
+)
+; test-*,uncond-br-sem,cond-br-sem are defined in sparc.cpu.
+(bpcc-branch ba "always" CC_A test-always uncond-br-sem)
+(bpcc-branch bn "never" CC_N test-never uncond-br-sem)
+(bpcc-branch bne "ne" CC_NE test-ne cond-br-sem)
+(bpcc-branch be "eq" CC_E test-eq cond-br-sem)
+(bpcc-branch bg "gt" CC_G test-gt cond-br-sem)
+(bpcc-branch ble "le" CC_LE test-le cond-br-sem)
+(bpcc-branch bge "ge" CC_GE test-ge cond-br-sem)
+(bpcc-branch bl "lt" CC_L test-lt cond-br-sem)
+(bpcc-branch bgu "gtu" CC_GU test-gtu cond-br-sem)
+(bpcc-branch bleu "leu" CC_LEU test-leu cond-br-sem)
+(bpcc-branch bcc "geu" CC_CC test-geu cond-br-sem)
+(bpcc-branch bcs "ltu" CC_CS test-ltu cond-br-sem)
+(bpcc-branch bpos "pos" CC_POS test-pos cond-br-sem)
+(bpcc-branch bneg "neg" CC_NEG test-neg cond-br-sem)
+(bpcc-branch bvc "vc" CC_VC test-vc cond-br-sem)
+(bpcc-branch bvs "vs" CC_VS test-vs cond-br-sem)
+
+; Misc.
+
+(dni done "done, v9 page 155" ((MACH64))
+ "done"
+ (+ OP_2 (f-fcn 0) OP3_DONE_RETRY (f-res-18-19 0))
+ (c-call "@cpu@_done" pc)
+ ()
+)
+(dni retry "retry, v9 page 155" ((MACH64))
+ "done"
+ (+ OP_2 (f-fcn 1) OP3_DONE_RETRY (f-res-18-19 0))
+ (c-call "@cpu@_retry" pc)
+ ()
+)
+
+(dni flush "flush instruction memory rs1+rs2, v9 page 165" ((MACH64))
+ "flush"
+ (+ OP_2 (f-rd 0) OP3_FLUSH rs1 (f-i 0) (f-res-asi 0) rs2)
+ (c-call "@cpu@_flush" pc (add rs1 rs2))
+ ()
+)
+(dni flush-imm "flush instruction memory rs1+simm13, v9 page 165" ((MACH64))
+ "flush"
+ (+ OP_2 (f-rd 0) OP3_FLUSH rs1 (f-i 1) simm13)
+ (c-call "@cpu@_flush" pc (add rs1 simm13))
+ ()
+)
+
+(dni flushw "flush register windows, v9 page 167" ((MACH64))
+ "flushw"
+ (+ OP_2 (f-rd 0) OP3_FLUSHW (f-rs1 0) (f-i 0) (f-simm13 0))
+ (c-call "@cpu@_flushw" pc)
+ ()
+)
+
+; On sparc64 unimp is called illtrap.
+
+(dnmi illtrap "illegal instruction trap, v9 page 168" ((MACH64))
+ "illtrap $imm22"
+ (emit unimp imm22)
+)
+
+; Impdep insns
+
+(dnf f-impdep5 "5 bit field in impdep insns" ((MACH64)) 29 5)
+(dnf f-impdep19 "19 bit field in impdep insns" ((MACH64)) 18 19)
+
+(dnop impdep5 "5 bit arg in impdep insns" ((MACH64)) h-uint f-impdep5)
+(dnop impdep19 "19 bit arg in impdep insns" ((MACH64)) h-uint f-impdep19)
+
+(dni impdep1 "implementation dependent instruction 1, v9 page 169"
+ ((MACH64))
+ "impdep1 $impdep5,$impdep19"
+ (+ OP_2 impdep5 OP3_IMPDEP1 impdep19)
+ (c-call "@cpu@_impdep1" pc impdep5 impdep19)
+ ()
+)
+(dni impdep2 "implementation dependent instruction 1, v9 page 169"
+ ((MACH64))
+ "impdep2 $impdep5,$impdep19"
+ (+ OP_2 impdep5 OP3_IMPDEP2 impdep19)
+ (c-call "@cpu@_impdep2" pc impdep5 impdep19)
+ ()
+)
+
+; Memory barrier insn
+
+(dnf f-membar-res12-6 "reserved bits 12-7 in membar insn"
+ (RESERVED (MACH64)) 12 6)
+(dnf f-cmask "cmask field in membar insn" ((MACH64)) 6 3)
+(dnf f-mmask "mmask field in membar insn" ((MACH64)) 3 4)
+(dnf f-membarmask "cmask+mmask field in membar insn" ((MACH64)) 6 7)
+
+(define-hardware
+ (name h-membarmask)
+ (comment "membar mask")
+ (attrs (MACH64))
+ (type immediate (UINT 7))
+ (values keyword "" (
+ ("#StoreStore" #x8)
+ ("#LoadStore" #x4)
+ ("#StoreLoad" #x2)
+ ("#LoadLoad" #x1)
+ ("#Sync" #x40)
+ ("#MemIssue" #x20)
+ ("#Lookaside" #x10)
+ ))
+)
+
+(define-operand
+ (name membarmask)
+ (comment "cmask+mmask arg in membar insn")
+ (attrs (MACH64))
+ (type h-membarmask)
+ (index f-membarmask)
+ (handlers (parse "membar_mask")
+ (print "membar_mask"))
+)
+
+(dni membar "memory barrier, v9 page 183"
+ ((MACH64))
+ "member $membarmask" ; ${membar-mask}
+ (+ OP_2 (f-rd 0) OP3_MEMBAR (f-rs1 15) (f-i 1) (f-membar-res12-6 0)
+ membarmask)
+ (c-call "@cpu@_membar" pc membarmask)
+ ()
+)
+
+; Conditional move insns
+
+(df f-simm11 "11 bit signed immediate field" ((MACH64)) 10 11 INT #f #f)
+
+(dnop simm11 "11 bit signed immediate arg to condition move insns"
+ ((MACH64)) h-sint f-simm11)
+
+(define-pmacro (cond-move-1 name comment mnemonic cc-prefix cc-name cc-opcode
+ src-name src-opcode cond test)
+ (dni name
+ (.str "move %" cc-name " " comment ", v9 page 191")
+ ((MACH64))
+ (.str mnemonic " " cc-prefix cc-name ",$" src-name ",$rd")
+ (.splice + OP_2 rd OP3_MOVCC cond
+ (.unsplice cc-opcode) (.unsplice src-opcode))
+ (if (test cc-name)
+ (set rd src-name))
+ ())
+)
+
+(define-pmacro (cond-move name comment cond test)
+ (begin
+ (cond-move-1 (.sym name -icc) comment
+ name "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
+ rs2 ((f-i 0) (f-fmt4-res10-6 0) rs2)
+ cond test)
+ (cond-move-1 (.sym name -imm-icc) comment
+ name "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
+ simm11 ((f-i 1) simm11)
+ cond test)
+ (cond-move-1 (.sym name -xcc) comment
+ name "%" xcc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 2))
+ rs2 ((f-i 0) (f-fmt4-res10-6 0) rs2)
+ cond test)
+ (cond-move-1 (.sym name -imm-xcc) comment
+ name "%" xcc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 2))
+ simm11 ((f-i 1) simm11)
+ cond test)
+ )
+)
+; test-* are defined in sparc.cpu.
+(cond-move mova "always" CC_A test-always)
+(cond-move movn "never" CC_N test-never)
+(cond-move movne "ne" CC_NE test-ne)
+(cond-move move "eq" CC_E test-eq)
+(cond-move movg "gt" CC_G test-gt)
+(cond-move movle "le" CC_LE test-le)
+(cond-move movge "ge" CC_GE test-ge)
+(cond-move movl "lt" CC_L test-lt)
+(cond-move movgu "gtu" CC_GU test-gtu)
+(cond-move movleu "leu" CC_LEU test-leu)
+(cond-move movcc "geu" CC_CC test-geu)
+(cond-move movcs "ltu" CC_CS test-ltu)
+(cond-move movpos "pos" CC_POS test-pos)
+(cond-move movneg "neg" CC_NEG test-neg)
+(cond-move movvc "vc" CC_VC test-vc)
+(cond-move movvs "vs" CC_VS test-vs)
+
+; Arithmetic binary ops
+
+(define-pmacro (v8-addx-rename old new)
+ (begin
+ (dnmi new
+ (.str old " in v8 is " new " in v9, v9 page 135") ()
+ (.str new " $rs1,$rs2,$rd")
+ (emit old rs1 rs2 rd))
+ (dnmi (.sym new -imm)
+ (.str old " in v8 is " new " in v9, v9 page 135") ()
+ (.str new " $rs1,$simm13,$rd")
+ (emit old rs1 simm13 rd))
+ )
+)
+(v8-addx-rename addx addc)
+(v8-addx-rename addxcc addccc)
+
+; Binary boolean ops
+
+(define-pmacro (s64-set-bool-flags x)
+ (sequence ()
+ (set icc-z (zflag (trunc SI x)))
+ (set icc-n (nflag (trunc SI x)))
+ (set icc-c (const 0))
+ (set icc-v (const 0))
+ (set xcc-z (zflag x))
+ (set xcc-n (nflag x))
+ (set xcc-c (const 0))
+ (set xcc-v (const 0))
+ )
+)
+
+; Multiply/Divide
+
+; FIXME: flags handling incomplete
+; FIXME: div-binop is in sparccom.cpu which is included later.
+;(div-binop s64-sdiv "sdiv" MACH64 SDIV div ext: (s64-set-bool-flags rd))
+;(div-binop s64-udiv "udiv" MACH64 UDIV div zext: (s64-set-bool-flags rd))
+
+; TODO
+; - casa, casxa
diff --git a/cgen/sparccom.cpu b/cgen/sparccom.cpu
new file mode 100644
index 00000000000..2c8e7fc89ed
--- /dev/null
+++ b/cgen/sparccom.cpu
@@ -0,0 +1,766 @@
+; SPARC 32/64 CPU description. -*- Scheme -*-
+; This file contains instructions common to both sparc32/sparc64.
+; It also contains sparc32/64 specific insns, but only when they are a variant
+; of a collection of common ones.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Notes:
+; - sparc64 support wip
+; - fp support todo
+; - source file layout wip
+; - cpu family layout wip
+
+; Lots of sparc insns have either reg/reg or reg/simm13 cases. */
+
+(define-pmacro (op3-reg-fmt op3-code)
+ (+ OP_2 op3-code rd rs1 rs2 (f-i 0) (f-res-asi 0))
+)
+(define-pmacro (op3-imm-fmt op3-code)
+ (+ OP_2 op3-code rd rs1 (f-i 1) simm13)
+)
+
+; Load/Store ops
+
+(define-pmacro (ld-op name comment attrs op3 mode dest)
+ (begin
+ (dnmi (.sym name "-reg+g0") comment attrs
+ (.str name " [$rs1],$" dest)
+ (emit (.sym name -reg+reg) rs1 (rs2 0) dest))
+ (dnmi (.sym name "-reg+0") comment attrs
+ (.str name " [$rs1],$" dest)
+ (emit (.sym name -reg+imm) rs1 (simm13 0) dest))
+ (dni (.sym name "-reg+reg") comment attrs
+ (.str name " [$rs1+$rs2],$" dest)
+ (+ OP_3 op3 dest rs1 (f-i 0) (f-res-asi 0) rs2)
+ (set mode dest (mem mode (add WI rs1 rs2)))
+ ())
+ (dni (.sym name "-reg+imm") comment attrs
+ (.str name " [$rs1+$simm13],$" dest)
+ (+ OP_3 op3 dest rs1 (f-i 1) simm13)
+ (set mode dest (mem mode (add WI rs1 simm13)))
+ ())
+ (dnmi (.sym name "-reg/asi") comment attrs
+ (.str name " [$rs1]$asi,$" dest)
+ (emit (.sym name -reg+reg/asi) rs1 (rs2 0) asi dest))
+ (dni (.sym name "-reg+reg/asi") comment attrs
+ (.str name " [$rs1+$rs2]$asi,$" dest)
+ (+ OP_3 (.sym op3 A) dest rs1 (f-i 0) asi rs2)
+ (set mode dest (mem mode (add WI rs1 rs2)))
+ ())
+ )
+)
+(ld-op ldsb "load signed byte" () OP3_LDSB QI rd)
+(ld-op ldub "load unsigned byte" () OP3_LDUB UQI rd)
+(ld-op ldsh "load signed halfword" () OP3_LDSH HI rd)
+(ld-op lduh "load unsigned halfword" () OP3_LDUH UHI rd)
+(ld-op ldsw "load signed word" () OP3_LDSW SI rd)
+(ld-op lduw "load unsigned word" () OP3_LDUW USI rd)
+(ld-op ldx "load extended word" ((MACH64)) OP3_LDX DI rd)
+
+; Aliases are treated as such (ALIAS attribute) so we can use ld-op.
+; ??? Perhaps lduw should be the alias. Let's leave it like this for now.
+(ld-op ld "load word" (ALIAS) OP3_LDUW SI rd)
+
+; ??? This would work with special operand get/set support but
+; it's not clear this case justifies implementing that yet.
+;(ld-op ldd "load double reg" () OP3_LDD DI rdd)
+
+(dnmi ldd-reg+g0 "load double reg, reg+g0" ()
+ "ldd [$rs1],$rdd"
+ (emit ldd-reg+reg rs1 (rs2 0) rdd)
+)
+(dnmi ldd-reg+0 "load double reg, reg+0" ()
+ "ldd [$rs1],$rdd"
+ (emit ldd-reg+imm rs1 (simm13 0) rdd)
+)
+(dni ldd-reg+reg "load double reg, reg+reg" ()
+ "ldd [$rs1+$rs2],$rdd"
+ (+ OP_3 OP3_LDD rdd rs1 (f-i 0) (f-res-asi 0) rs2)
+ (sequence ((DI temp))
+ (set temp (mem DI (add WI rs1 rs2)))
+ (set rdd (subword SI temp (const 0)))
+ (set (reg h-gr (add (regno rdd) (const 1)))
+ (subword SI temp (const 1))))
+ ()
+)
+(dni ldd-reg+imm "load double reg, reg+imm" ()
+ "ldd [$rs1+$simm13],$rdd"
+ (+ OP_3 OP3_LDD rdd rs1 (f-i 1) simm13)
+ (sequence ()
+ (set rdd (mem SI (add WI rs1 simm13)))
+ (set (reg h-gr (add (regno rdd) (const 1)))
+ (mem SI (add rs1 (add simm13 (const 4))))))
+ ()
+)
+(dnmi ldd-reg/asi "load double reg, reg+g0/asi" ()
+ "ldd [$rs1]$asi,$rdd"
+ (emit ldd-reg+reg/asi rs1 (rs2 0) asi rdd)
+)
+(dni ldd-reg+reg/asi "load double reg, reg+reg/asi" ()
+ "ldd [$rs1+$rs2]$asi,$rdd"
+ (+ OP_3 OP3_LDDA rdd rs1 (f-i 0) asi rs2)
+ (sequence ()
+ (set rdd (mem SI (add WI rs1 rs2)))
+ (set (reg h-gr (add (regno rdd) (const 1)))
+ (mem SI (add rs1 (add rs2 (const 4))))))
+ ()
+)
+
+(define-pmacro (st-op name comment attrs op3 mode src)
+ (begin
+ (dnmi (.sym name "-reg+g0") comment attrs
+ (.str name " $" src ",[$rs1]")
+ (emit (.sym name -reg+reg) src rs1 (rs2 0)))
+ (dnmi (.sym name "-reg+0") comment attrs
+ (.str name " $" src ",[$rs1]")
+ (emit (.sym name -reg+imm) src rs1 (simm13 0)))
+ (dni (.sym name "-reg+reg") comment attrs
+ (.str name " $" src ",[$rs1+$rs2]")
+ (+ OP_3 op3 src rs1 (f-i 0) (f-res-asi 0) rs2)
+ (set mode (mem mode (add WI rs1 rs2)) src)
+ ())
+ (dni (.sym name "-reg+imm") comment attrs
+ (.str name " $" src ",[$rs1+$simm13]")
+ (+ OP_3 op3 src rs1 (f-i 1) simm13)
+ (set mode (mem mode (add WI rs1 simm13)) src)
+ ())
+ (dnmi (.sym name "-reg/asi") comment attrs
+ (.str name " $" src ",[$rs1]$asi")
+ (emit (.sym name -reg+reg/asi) src rs1 (rs2 0) asi))
+ (dni (.sym name "-reg+reg/asi") comment attrs
+ (.str name " $" src ",[$rs1+$rs2]$asi")
+ (+ OP_3 (.sym op3 A) src rs1 (f-i 0) asi rs2)
+ (set mode (mem mode (add WI rs1 rs2)) src)
+ ())
+ )
+)
+(st-op stb "store byte" () OP3_STB QI rd)
+(st-op sth "store halfword" () OP3_STH HI rd)
+(st-op st "store word" () OP3_STW SI rd)
+(st-op stx "store extended word" ((MACH64)) OP3_STX DI rd)
+
+; ??? This would work with special operand get/set support but
+; it's not clear this case justifies implementing that yet.
+;(st-op std "store double reg" () OP3_STD DI rdd)
+
+(dnmi std-reg+g0 "store double reg, reg+g0" ()
+ "std $rdd,[$rs1]"
+ (emit std-reg+reg rdd rs1 (rs2 0))
+)
+(dnmi std-reg+0 "store double reg, reg+0" ()
+ "std $rdd,[$rs1]"
+ (emit std-reg+imm rdd rs1 (simm13 0))
+)
+(dni std-reg+reg "store double reg, reg+reg" ()
+ "std $rdd,[$rs1+$rs2]"
+ (+ OP_3 OP3_STD rdd rs1 (f-i 0) (f-res-asi 0) rs2)
+ (sequence ()
+ (set (mem SI (add rs1 rs2)) rdd)
+ (set (mem SI (add rs1 (add rs2 (const 4))))
+ (reg h-gr (add (regno rdd) (const 1)))))
+ ()
+)
+(dni std-reg+imm "store double reg, reg+imm" ()
+ "std $rdd,[$rs1+$simm13]"
+ (+ OP_3 OP3_STD rdd rs1 (f-i 1) simm13)
+ (sequence ()
+ (set (mem SI (add rs1 simm13)) rdd)
+ (set (mem SI (add rs1 (add simm13 (const 4))))
+ (reg h-gr (add (regno rdd) (const 1)))))
+ ()
+)
+(dnmi std-reg/asi "store double reg, reg+g0/asi" ()
+ "std $rdd,[$rs1]$asi"
+ (emit std-reg+reg/asi rdd rs1 (rs2 0) asi)
+)
+(dni std-reg+reg/asi "store double reg, reg+reg/asi" ()
+ "std $rdd,[$rs1+$rs2]$asi"
+ (+ OP_3 OP3_STDA rdd rs1 (f-i 0) asi rs2)
+ (sequence ()
+ (set (mem SI (add rs1 rs2)) rdd)
+ (set (mem SI (add rs1 (add rs2 (const 4))))
+ (reg h-gr (add (regno rdd) (const 1)))))
+ ()
+)
+
+; nop
+; A nop is defined to be a sethi of %g0.
+; This needn't be a macro-insn, but making it one greatly simplifies decode.c
+; as code needn't be generated to confirm hi22 == 0.
+; On the other hand spending a little time in the decoder is often worth it.
+
+(dnmi nop "nop"
+ ()
+ "nop"
+ (emit sethi (rd 0) (hi22 0))
+)
+
+; sethi
+
+(dni sethi "sethi" ()
+ "sethi $hi22,$rd"
+ (+ OP_0 rd OP2_SETHI hi22)
+ (set rd (sll USI hi22 (const 10))) ; (set SI rd hi22)
+ ()
+)
+
+; Add/Subtract
+
+(define-pmacro (s32-set-addc-flags a b carry)
+ (sequence ((SI x))
+ (set x (addc a b carry))
+ (set icc-c (add-cflag a b carry))
+ (set icc-v (add-oflag a b carry))
+ (set icc-n (nflag x))
+ (set icc-z (zflag x)))
+)
+(define-pmacro (s32-set-subc-flags a b carry)
+ (sequence ((SI x))
+ (set x (subc a b carry))
+ (set icc-c (sub-cflag a b carry))
+ (set icc-v (sub-oflag a b carry))
+ (set icc-n (nflag x))
+ (set icc-z (zflag x)))
+)
+
+(define-pmacro (s64-set-addc-flags a b carry)
+ (sequence ((SI x32) (DI x))
+ (set x (addc a b carry))
+ (set x32 x)
+ (set icc-c (add-cflag SI a b carry))
+ (set icc-v (add-oflag SI a b carry))
+ (set icc-n (nflag x32))
+ (set icc-z (zflag x32))
+ (set xcc-c (add-cflag a b carry))
+ (set xcc-v (add-oflag a b carry))
+ (set xcc-n (nflag x))
+ (set xcc-z (zflag x)))
+)
+(define-pmacro (s64-set-subc-flags a b carry)
+ (sequence ((SI x32) (DI x))
+ (set x (subc a b carry))
+ (set x32 x)
+ (set icc-c (sub-cflag SI a b carry))
+ (set icc-v (sub-oflag SI a b carry))
+ (set icc-n (nflag x32))
+ (set icc-z (zflag x32))
+ (set xcc-c (sub-cflag a b carry))
+ (set xcc-v (sub-oflag a b carry))
+ (set xcc-n (nflag x))
+ (set xcc-z (zflag x)))
+)
+
+(define-pmacro (arith-binop name comment page attrs op3 sem-op)
+ (begin
+ (dni name
+ (.str comment ", " page)
+ attrs
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set rd (sem-op rs1 rs2))
+ ())
+ (dni (.sym name -imm)
+ (.str comment " immediate, " page)
+ attrs
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (set rd (sem-op rs1 simm13))
+ ())
+ )
+)
+(define-pmacro (arith-cc-binop name comment page attrs op3 sem-op
+ s32-set-flags s64-set-flags)
+ (begin
+ (dni name
+ (.str comment ", setting cc, " page)
+ attrs
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ()
+ (if (eq-attr (current-mach) ARCH64 TRUE)
+ (s64-set-flags rs1 rs2 (const 0))
+ (s32-set-flags rs1 rs2 (const 0)))
+ (set rd (sem-op rs1 rs2))
+ )
+ ())
+ (dni (.sym name -imm)
+ (.str comment " immediate, setting cc, " page)
+ attrs
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (sequence ()
+ (if (eq-attr (current-mach) ARCH64 TRUE)
+ (s64-set-flags rs1 simm13 (const 0))
+ (s32-set-flags rs1 simm13 (const 0)))
+ (set rd (sem-op rs1 simm13))
+ )
+ ())
+ )
+)
+(arith-binop add "add" "v8 page ??, v9 page 135" () OP3_ADD add)
+(arith-binop sub "subtract" "v8 page ??, v9 page 230" () OP3_SUB sub)
+(arith-cc-binop addcc "add" "v8 page ??, v9 page 135" () OP3_ADDCC add
+ s32-set-addc-flags s64-set-addc-flags)
+(arith-cc-binop subcc "subtract" "v8 page ??, v9 page 230" () OP3_SUBCC sub
+ s32-set-subc-flags s64-set-subc-flags)
+
+; Same except include carry bit.
+
+(define-pmacro (arith-carry-binop name comment page attrs op3 sem-op)
+ (begin
+ (dni name
+ (.str comment " with carry, " page)
+ attrs
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set rd (sem-op rs1 rs2 icc-c))
+ ())
+ (dni (.sym name -imm)
+ (.str comment " immediate with carry, " page)
+ attrs
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (set rd (sem-op rs1 simm13 icc-c))
+ ())
+ )
+)
+(define-pmacro (arith-carry-cc-binop name comment page attrs op3 sem-op set-flags)
+ (begin
+ (dni name
+ (.str comment " with carry, setting cc, " page)
+ attrs
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ()
+ (set-flags rs1 rs2 icc-c)
+ (set rd (sem-op rs1 rs2 icc-c))
+ )
+ ())
+ (dni (.sym name -imm)
+ (.str comment " immediate with carry, setting cc, " page)
+ attrs
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (sequence ()
+ (set-flags rs1 simm13 icc-c)
+ (set rd (sem-op rs1 simm13 icc-c))
+ )
+ ())
+ )
+)
+; mach32 versions
+(arith-carry-binop addx "add" "v8 page ??" ((MACH32)) OP3_ADDX addc)
+(arith-carry-binop subx "subtract" "v8 page ??" ((MACH32)) OP3_SUBX subc)
+(arith-carry-cc-binop addxcc "add" "v8 page ??" ((MACH32)) OP3_ADDXCC addc
+ s32-set-addc-flags)
+(arith-carry-cc-binop subxcc "subtract" "v8 page ??" ((MACH32)) OP3_SUBXCC subc
+ s32-set-subc-flags)
+; mach64 versions
+; same as mach32 except mnemonic is different
+(arith-carry-binop addc "add" "v9 page 135" ((MACH64)) OP3_ADDC addc)
+(arith-carry-binop subc "subtract" "v9 page 230" ((MACH64)) OP3_SUBC subc)
+(arith-carry-cc-binop addccc "add" "v9 page 135" ((MACH64)) OP3_ADDCCC addc
+ s64-set-addc-flags)
+(arith-carry-cc-binop subccc "subtract" "v9 page 230" ((MACH64)) OP3_SUBCCC subc
+ s64-set-subc-flags)
+
+; Binary boolean ops
+
+(define-pmacro (s32-set-bool-flags x)
+ (sequence ()
+ (set icc-z (zflag x))
+ (set icc-n (nflag x))
+ (set icc-c (const 0))
+ (set icc-v (const 0))
+ )
+)
+(define-pmacro (s64-set-bool-flags x)
+ (sequence ()
+ (set icc-z (zflag (trunc SI x)))
+ (set icc-n (nflag (trunc SI x)))
+ (set icc-c (const 0))
+ (set icc-v (const 0))
+ (set xcc-z (zflag x))
+ (set xcc-n (nflag x))
+ (set xcc-c (const 0))
+ (set xcc-v (const 0))
+ )
+)
+
+(define-pmacro (bool-binop name page op3 sem-op)
+ (begin
+ (dni name (.str name ", " page) ()
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set rd (sem-op rs1 rs2))
+ ())
+ (dni (.sym name -imm) (.str name " immediate, " page) ()
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (set rd (sem-op rs1 simm13))
+ ())
+ (dni (.sym name cc) (.str name ", setting cc, " page) ()
+ (.str name "cc $rs1,$rs2,$rd")
+ (+ OP_2 (.sym op3 CC) rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ()
+ (if (eq-attr (current-mach) ARCH64 TRUE)
+ (s64-set-bool-flags (sem-op rs1 rs2))
+ (s32-set-bool-flags (sem-op rs1 rs2)))
+ (set rd (sem-op rs1 rs2))
+ )
+ ())
+ (dni (.sym name cc-imm) (.str name " immediate, setting cc, " page) ()
+ (.str name "cc $rs1,$simm13,$rd")
+ (+ OP_2 (.sym op3 CC) rd rs1 (f-i 1) simm13)
+ (sequence ()
+ (if (eq-attr (current-mach) ARCH64 TRUE)
+ (s64-set-bool-flags (sem-op rs1 simm13))
+ (s32-set-bool-flags (sem-op rs1 simm13)))
+ (set rd (sem-op rs1 simm13))
+ )
+ ())
+ )
+)
+(bool-binop and "v9 page 181" OP3_AND and)
+(bool-binop or "v9 page 181" OP3_OR or)
+(bool-binop xor "v9 page 181" OP3_XOR xor)
+
+; Early experiments.
+;(dsmn (andn a b) (list 'and a (list 'inv b)))
+;(dsmn (orn a b) (list 'or a (list 'inv b)))
+;(dsmn (xorn a b) (list 'xor a (list 'inv b)))
+
+(define-pmacro (sem-andn a b) (and a (inv b)))
+(define-pmacro (sem-orn a b) (or a (inv b)))
+(define-pmacro (sem-xorn a b) (xor a (inv b)))
+
+(bool-binop andn "v9 page 181" OP3_ANDN sem-andn)
+(bool-binop orn "v9 page 181" OP3_ORN sem-orn)
+(bool-binop xnor "v9 page 181" OP3_XNOR sem-xorn)
+
+; Shifts
+
+(define-pmacro (shift-binop name comment op3 sem-op)
+ (begin
+ (dni name comment ()
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set rd (sem-op rs1 (and rs2 (const 31))))
+ ())
+ (dni (.sym name -imm) (.str comment -imm) ()
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ ; ??? v9 uses only the low bits. v8?
+ (set rd (sem-op rs1 (and simm13 (const 31))))
+ ())
+ )
+)
+(shift-binop sll "shift left logical" OP3_SLL sll)
+(shift-binop srl "shift right logical" OP3_SRL srl)
+(shift-binop sra "shift right arithmetic" OP3_SRA sra)
+
+; Multiply/Divide
+
+(define-pmacro (mult-binop name comment op3 sem-op ext-op)
+ (begin
+ (dni name comment ()
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ((DI res))
+ (set res (sem-op (ext-op DI rs1) (ext-op DI rs2)))
+ (set (reg WI h-y) (trunc SI (srl res (const 32))))
+ (set rd (trunc SI res))
+ )
+ ())
+ (dni (.sym name -imm) (.str comment -imm) ()
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (sequence ((DI res))
+ (set res (sem-op (ext-op DI rs1) (ext-op DI simm13)))
+ (set (reg WI h-y) (trunc SI (srl res (const 32))))
+ (set rd (trunc SI res))
+ )
+ ())
+ (dni (.sym name -cc) (.str comment -cc) ()
+ (.str name "cc $rs1,$rs2,$rd")
+ (+ OP_2 (.sym op3 CC) rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ((DI res))
+ (set res (sem-op (ext-op DI rs1) (ext-op DI rs2)))
+ (set (reg WI h-y) (trunc SI (srl res (const 32))))
+ (set rd (trunc SI res))
+ ; We use bool-flags here 'cus it works (FIXME:revisit).
+ ; We can't use rd here 'cus it might be %g0.
+ (s32-set-bool-flags (trunc SI res))
+ )
+ ())
+ (dni (.sym name -cc-imm) (.str comment -cc-imm) ()
+ (.str name "cc $rs1,$simm13,$rd")
+ (+ OP_2 (.sym op3 CC) rd rs1 (f-i 1) simm13)
+ (sequence ((DI res))
+ (set res (sem-op (ext-op DI rs1) (ext-op DI simm13)))
+ (set (reg WI h-y) (trunc SI (srl res (const 32))))
+ (set rd (trunc SI res))
+ ; We use bool-flags here 'cus it works (FIXME:revisit).
+ ; We can't use rd here 'cus it might be %g0.
+ (s32-set-bool-flags (trunc SI res))
+ )
+ ())
+ )
+)
+(mult-binop smul "smul" OP3_SMUL mul ext)
+(mult-binop umul "umul" OP3_UMUL mul zext)
+
+(define-pmacro (div-binop name comment mach-attrs op3 sem-op ext-op set-flags)
+ (begin
+ (dni name (.str comment ", v9 page 152") ((mach-attrs))
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ((DI dividend))
+ (set dividend (join DI SI (reg SI h-y) rs1))
+ (set rd (trunc SI (sem-op dividend (ext-op DI rs2))))
+ ; FIXME: Overflow,etc. handling.
+ )
+ ())
+ (dni (.sym name -imm) (.str comment -imm ", v9 page 152") ((mach-attrs))
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (sequence ((DI dividend))
+ (set dividend (join DI SI (reg SI h-y) rs1))
+ (set rd (trunc SI (sem-op dividend (ext-op DI simm13))))
+ ; FIXME: Overflow,etc. handling.
+ )
+ ())
+ (dni (.sym name -cc) (.str comment -cc ", v9 page 152") ((mach-attrs))
+ (.str name "cc $rs1,$rs2,$rd")
+ (+ OP_2 (.sym op3 CC) rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ((DI dividend))
+ (set dividend (join DI SI (reg SI h-y) rs1))
+ (set rd (trunc SI (sem-op dividend (ext-op DI rs2))))
+ ; FIXME: Overflow,etc. handling.
+ set-flags
+ )
+ ())
+ (dni (.sym name -cc-imm) (.str comment -cc-imm ", v9 page 152") ((mach-attrs))
+ (.str name "cc $rs1,$simm13,$rd")
+ (+ OP_2 (.sym op3 CC) rd rs1 (f-i 1) simm13)
+ (sequence ((DI dividend))
+ (set dividend (join DI SI (reg SI h-y) rs1))
+ (set rd (trunc SI (sem-op dividend (ext-op DI simm13))))
+ ; FIXME: Overflow,etc. handling.
+ set-flags
+ )
+ ())
+ )
+)
+(div-binop sdiv "sdiv" MACH32 OP3_SDIV div ext (s32-set-bool-flags rd))
+(div-binop udiv "udiv" MACH32 OP3_UDIV div zext (s32-set-bool-flags rd))
+
+; Multiply/Step
+
+(dni mulscc "multiply step" ()
+ "mulscc $rs1,$rs2,$rd"
+ (+ OP_2 OP3_MULSCC rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (sequence ((SI tmp) (SI add-tmp) (SI rd-tmp))
+ ; v8 page 112, step 2
+ (set tmp (srl SI rs1 (const 1)))
+ (if (ne (xor BI (reg BI h-icc-n) (reg BI h-icc-v))
+ (const 0))
+ (set tmp (or SI tmp (const SI #x80000000))))
+ ; step 3
+ (if (ne (and SI (reg SI h-y) (const 1)) (const 0))
+ (set add-tmp rs2)
+ (set add-tmp (const 0)))
+ ; step 4
+ (set rd-tmp (add tmp add-tmp))
+ ; step 5
+ (s32-set-addc-flags tmp add-tmp (const 0))
+ ;(set (reg UQI h-cc) (addc-cc tmp add-tmp (const 0)))
+ ; step 6
+ (set (reg SI h-y) (srl SI (reg SI h-y) (const 1)))
+ (if (ne (and SI rs1 (const 1)) (const 0))
+ (set (reg SI h-y) (or SI (reg SI h-y) (const SI #x80000000))))
+ ; rd first created in rd-tmp so step 6 gets right value for rs1
+ (set SI rd rd-tmp)
+ )
+ ()
+)
+
+; Window ops
+; V8 page 117
+
+(define-pmacro (window-binop name comment op3 handler)
+ (begin
+ (dni name comment ()
+ (.str name " $rs1,$rs2,$rd")
+ (+ OP_2 op3 rd rs1 rs2 (f-i 0) (f-res-asi 0))
+ (set rd (c-call WI handler pc rs1 rs2))
+ ())
+ (dni (.sym name -imm) (.str comment -imm) ()
+ (.str name " $rs1,$simm13,$rd")
+ (+ OP_2 op3 rd rs1 (f-i 1) simm13)
+ (set rd (c-call WI handler pc rs1 simm13))
+ ())
+ )
+)
+(window-binop save "save caller's window" OP3_SAVE "@cpu@_do_save")
+(window-binop restore "restore caller's window" OP3_RESTORE "@cpu@_do_restore")
+
+; Trap stuff
+
+(dni rett "return from trap" ()
+ "rett $rs1,$rs2"
+ (+ OP_2 OP3_RETT (f-rd 0) rs1 rs2 (f-i 0) (f-res-asi 0))
+ (delay (const 1)
+ (set pc (c-call WI "@cpu@_do_rett" pc rs1 rs2)))
+ ()
+)
+(dni rett-imm "return from trap, immediate" ()
+ "rett $rs1,$simm13"
+ (+ OP_2 OP3_RETT (f-rd 0) rs1 (f-i 1) simm13)
+ (delay (const 1)
+ (set pc (c-call WI "@cpu@_do_rett" pc rs1 simm13)))
+ ()
+)
+
+; Misc.
+
+(dni unimp "unimplemented" ()
+ "unimp $imm22"
+ (+ OP_0 (f-rd-res 0) OP2_UNIMP imm22)
+ (c-call VOID "@arch@_do_unimp" pc imm22)
+ ()
+)
+
+; Subroutine calls, returns.
+
+(dnmi call-reg,0 "call reg,0" ()
+ "call $rs1,0" ; FIXME: what's the ,0 suffix for?
+ (emit jmpl rs1 (rd 15) (rs2 0))
+)
+
+(dnmi call-reg "call reg" ()
+ "call $rs1"
+ (emit jmpl rs1 (rd 15) (rs2 0))
+)
+
+(dnmi call,0 "call,0" ()
+ "call $disp30,0" ; FIXME: what's the ,0 suffix for?
+ (emit call disp30)
+)
+
+(dni call "call" (DELAY-SLOT)
+ "call $disp30"
+ (+ OP_1 disp30)
+ (sequence ()
+ (set (reg h-gr 15) pc)
+ (delay (const 1)
+ (set pc disp30)))
+ ()
+)
+
+(dni jmpl "jmpl" (DELAY-SLOT)
+ "jmpl $rs1+$rs2,$rd"
+ (op3-reg-fmt OP3_JMPL)
+ (sequence ()
+ (set rd pc)
+ (delay (const 1)
+ (set pc (add WI rs1 rs2))))
+ ()
+)
+
+(dni jmpl-imm "jmpl" (DELAY-SLOT)
+ "jmpl $rs1+$simm13,$rd"
+ (op3-imm-fmt OP3_JMPL)
+ (sequence ()
+ (set rd pc)
+ (delay (const 1)
+ (set pc (add WI rs1 simm13))))
+ ()
+)
+
+;(dsn (icc-op op) (cx:make BI (string-append "icc (" op ")")))
+;(dsn (icc-op op) (list 'c-call: 'BI "icc" (reg UQI h-cc) (.str op)))
+;(dsmn (icc-op op) (list 'c-call: 'BI "icc" '(reg UQI h-cc) (.str op)))
+;(define-pmacro (icc-op op) (c-call BI "icc" (reg UQI h-cc) (.str op)))
+
+; Branches
+
+(define-pmacro (bicc-branch bname tname comment cond test br-sem)
+ (begin
+ (dni bname (.str "branch " comment) (V9-DEPRECATED)
+ (.str bname "$a $disp22")
+ (+ OP_0 a cond OP2_BICC disp22)
+ (br-sem test icc)
+ ())
+ (dni tname (.str "trap " comment) (TRAP)
+ (.str tname " $rs1,$rs2")
+ (+ OP_2 (f-a 0) cond (f-op3 #x3a) rs1 (f-i 0) (f-res-asi 0) rs2)
+ (if (test icc)
+ (set pc (c-call IAI "@cpu@_sw_trap" pc rs1 rs2)))
+ ())
+ (dni (.sym tname -imm) (.str "trap-imm " comment) (TRAP)
+ (.str tname " $rs1,$simm13")
+ (+ OP_2 (f-a 0) cond (f-op3 #x3a) rs1 (f-i 1) simm13)
+ (if (test icc)
+ (set pc (c-call IAI "@cpu@_sw_trap" pc rs1 simm13)))
+ ())
+ )
+)
+; test-*,uncond-br-sem,cond-br-sem are defined in sparc.cpu.
+(bicc-branch ba ta "always" CC_A test-always uncond-br-sem)
+(bicc-branch bn tn "never" CC_N test-never uncond-br-sem)
+(bicc-branch bne tne "ne" CC_NE test-ne cond-br-sem)
+(bicc-branch be te "eq" CC_E test-eq cond-br-sem)
+(bicc-branch bg tg "gt" CC_G test-gt cond-br-sem)
+(bicc-branch ble tle "le" CC_LE test-le cond-br-sem)
+(bicc-branch bge tge "ge" CC_GE test-ge cond-br-sem)
+(bicc-branch bl tl "lt" CC_L test-lt cond-br-sem)
+(bicc-branch bgu tgu "gtu" CC_GU test-gtu cond-br-sem)
+(bicc-branch bleu tleu "leu" CC_LEU test-leu cond-br-sem)
+(bicc-branch bcc tcc "geu" CC_CC test-geu cond-br-sem)
+(bicc-branch bcs tcs "ltu" CC_CS test-ltu cond-br-sem)
+(bicc-branch bpos tpos "pos" CC_POS test-pos cond-br-sem)
+(bicc-branch bneg tneg "neg" CC_NEG test-neg cond-br-sem)
+(bicc-branch bvc tvc "vc" CC_VC test-vc cond-br-sem)
+(bicc-branch bvs tvs "vs" CC_VS test-vs cond-br-sem)
+
+; Atomic load/stores.
+
+(define-pmacro (atomic-op name comment attrs op3 do_fn)
+ (begin
+ (dnmi (.sym name "-reg") comment attrs
+ (.str name " [$rs1],$rd")
+ (emit (.sym name -reg+reg) rs1 (rs2 0) rd))
+ (dnmi (.sym name "-reg+0") comment attrs
+ (.str name " [$rs1],$rd")
+ (emit (.sym name -reg+imm) rs1 (simm13 0) rd))
+ (dni (.sym name "-reg+reg") comment attrs
+ (.str name " [$rs1+$rs2],$rd")
+ (+ OP_3 op3 rd rs1 (f-i 0) (f-res-asi 0) rs2)
+ (c-call do_fn pc (regno rd) rs1 rs2 (const -1))
+ ())
+ (dni (.sym name "-reg+imm") comment attrs
+ (.str name " [$rs1+$simm13],$rd")
+ (+ OP_3 op3 rd rs1 (f-i 1) simm13)
+ (c-call do_fn pc (regno rd) rs1 simm13 (const -1))
+ ())
+ (dnmi (.sym name "-reg/asi") comment attrs
+ (.str name " [$rs1]$asi,$rd")
+ (emit (.sym name "-reg+reg/asi") rs1 (rs2 0) asi rd))
+ (dni (.sym name "-reg+reg/asi") comment attrs
+ (.str name " [$rs1+$rs2]$asi,$rd")
+ (+ OP_3 (.sym op3 A) rd rs1 (f-i 0) asi rs2)
+ (c-call do_fn pc (regno rd) rs1 rs2 asi)
+ ())
+ )
+)
+(atomic-op ldstub "atomic load-store unsigned byte, v9 page 179" ()
+ OP3_LDSTUB "@cpu@_do_ldstub")
+(atomic-op swap "atomic swap reg with mem" (V9-DEPRECATED)
+ OP3_SWAP "@cpu@_do_swap")
+
+; TODO:
+; - tagged add/sub
+; - synthetic insns
diff --git a/cgen/sparcfpu.cpu b/cgen/sparcfpu.cpu
new file mode 100644
index 00000000000..dbbd10ea3f5
--- /dev/null
+++ b/cgen/sparcfpu.cpu
@@ -0,0 +1,527 @@
+; SPARC 32/64 FPU description. -*- Scheme -*-
+; This file contains fpu instructions common to both sparc32/sparc64.
+; It also contains sparc32/64 specific insns, but only when they are a variant
+; of a collection of common ones (at least that's the current theory).
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; FP support is defined even for cpu's without an fpu as the instructions
+; still have to be assembled and the simulator still has to recognize them
+; so that the appropriate trap can be generated.
+;
+; The physical registers are stored as an array of SI values: here `SI'
+; denotes "set of 32 bits" rather than "32 bit signed integer".
+;
+; wip: currently evaluating the various possibilities
+
+; Floating point hardware.
+
+; The description needs to know whether the fpu is present.
+; Creating a utility register for this purposes seems reasonable.
+; Might want an attribute to denote it as such.
+
+(dsh h-fpu? "h/w fpu present?" () (register BI))
+(dnop fpu? "h/w fpu present?" () h-fpu? f-nil)
+
+(define-pmacro (build-freg-name n) ((.sym f n) n))
+
+(define-hardware
+ (name h-fr32)
+ (semantic-name h-fr)
+ (comment "sparc32 floating point regs")
+ (attrs (MACH32))
+ (type register SI (32))
+ (indices keyword "%" (.map build-freg-name (.iota 32)))
+)
+(define-hardware
+ (name h-fr64)
+ (semantic-name h-fr)
+ (comment "sparc64 floating point regs")
+ (attrs (MACH64))
+ (type register SI (64))
+ (indices keyword "%" (.map build-freg-name (.iota 64)))
+)
+
+(define-hardware
+ (name h-frd32)
+ (semantic-name h-frd)
+ (comment "sparc32 double precision floating point regs")
+ (attrs VIRTUAL (MACH32))
+ (type register DI (16))
+ ; ??? This works, but multiple copies of all the register names might be
+ ; unpalatable. Another way is to specify a register table plus a constraint.
+ ;(indices keyword "%" (.map build-freg-name (.iota 16 0 2)))
+ (get (index) (join DI SI
+ (reg h-fr index)
+ (reg h-fr (add index 1))))
+ (set (index newval)
+ (sequence ()
+ (set (reg h-fr index) (subword SI newval 0))
+ (set (reg h-fr (add index 1)) (subword SI newval 1))))
+)
+
+(define-hardware
+ (name h-frq32)
+ (semantic-name h-frq)
+ (comment "sparc32 quad precision floating point regs")
+ (attrs VIRTUAL (MACH32))
+ (type register TF (8))
+ (indices keyword "%" (.map build-freg-name (.iota 8 0 4)))
+ (get (index) (join TF SI
+ (reg h-fr index)
+ (reg h-fr (add index (const 1)))
+ (reg h-fr (add index (const 2)))
+ (reg h-fr (add index (const 3)))))
+ (set (index newval)
+ (sequence ()
+ (set (reg h-fr index) (subword SI newval 0))
+ (set (reg h-fr (add index (const 1))) (subword SI newval 1))
+ (set (reg h-fr (add index (const 2))) (subword SI newval 2))
+ (set (reg h-fr (add index (const 3))) (subword SI newval 3))))
+)
+
+(define-hardware
+ (name h-frd64)
+ (semantic-name h-frd)
+ (comment "sparc64 double precision floating point regs")
+ (attrs VIRTUAL (MACH64))
+ (type register DF (32))
+ (indices keyword "%" (.map build-freg-name (.iota 32 0 2)))
+ (get (index) (join DF SI
+ (reg h-fr index)
+ (reg h-fr (add index (const 1)))))
+ (set (index newval)
+ (sequence ()
+ (set (reg h-fr index) (subword SI newval 0))
+ (set (reg h-fr (add index (const 1))) (subword SI newval 1))))
+)
+
+(define-hardware
+ (name h-frq64)
+ (semantic-name h-frq)
+ (comment "sparc64 quad precision floating point regs")
+ (attrs VIRTUAL (MACH64))
+ (type register TF (16))
+ (indices keyword "%" (.map build-freg-name (.iota 16 0 4)))
+ (get (index) (join TF SI
+ (reg h-fr index)
+ (reg h-fr (add index (const 1)))
+ (reg h-fr (add index (const 2)))
+ (reg h-fr (add index (const 3)))))
+ (set (index newval)
+ (sequence ()
+ (set (reg h-fr index) (subword SI newval 0))
+ (set (reg h-fr (add index (const 1))) (subword SI newval 1))
+ (set (reg h-fr (add index (const 2))) (subword SI newval 2))
+ (set (reg h-fr (add index (const 3))) (subword SI newval 3))))
+)
+
+; fp condition codes
+
+(dsh h-fcc0 "%fcc0" () (register (UINT 2)))
+(dsh h-fcc1 "%fcc1" ((MACH64)) (register (UINT 2)))
+(dsh h-fcc2 "%fcc2" ((MACH64)) (register (UINT 2)))
+(dsh h-fcc3 "%fcc3" ((MACH64)) (register (UINT 2)))
+
+; sparc64 fpu control regs
+
+(dsh h-fsr-rd "fsr rounding direction" ((MACH64)) (register UQI))
+(dsh h-fsr-tem "fsr trap enable mask" ((MACH64)) (register UQI))
+(dsh h-fsr-ns "fsr nonstandard fp" ((MACH64)) (register BI))
+(dsh h-fsr-ver "fsr version" ((MACH64)) (register UQI))
+(dsh h-fsr-ftt "fsr fp trap type" ((MACH64)) (register UQI))
+(dsh h-fsr-qne "fsr queue not empty" ((MACH64)) (register BI))
+(dsh h-fsr-aexc "fsr accrued exception" ((MACH64)) (register UQI))
+(dsh h-fsr-cexc "fsr current exception" ((MACH64)) (register UQI))
+;(dsh h-fsr "floating point state" ((MACH64)) (register UDI))
+
+(dsh h-fpsr-fef "fpsr enable fp" ((MACH64)) (register BI))
+(dsh h-fpsr-du "fpsr dirty upper" ((MACH64)) (register BI))
+(dsh h-fpsr-dl "fpsr dirty lower" ((MACH64)) (register BI))
+
+(define-hardware
+ (name h-fpsr)
+ (comment "fp regs state")
+ (attrs VIRTUAL (MACH64))
+ (type register UQI)
+ (get () (const 0)) ; FIXME
+ (set (newval) (set (raw-reg UQI h-fpsr) (const 0))) ; FIXME
+)
+
+; Floating point operands.
+
+(define-operand
+ (name frs1s)
+ (comment "single precision floating point source register 1")
+ (type h-fr)
+ (index f-rs1)
+ (mode SF)
+)
+(define-operand
+ (name frs2s)
+ (comment "single precision floating point source register 2")
+ (type h-fr)
+ (index f-rs2)
+ (mode SF)
+)
+(define-operand
+ (name frds)
+ (comment "single precision floating point dest'n register")
+ (type h-fr)
+ (index f-rd)
+ (mode SF)
+)
+
+(define-operand
+ (name frs1d)
+ (comment "double precision floating point source register 1")
+ (attrs (MACH32))
+ (type h-frd)
+ (index f-rs1)
+ (mode DF)
+)
+(define-operand
+ (name frs2d)
+ (comment "double precision floating point source register 2")
+ (attrs (MACH32))
+ (type h-frd)
+ (index f-rs2)
+ (mode DF)
+)
+(define-operand
+ (name frdd)
+ (comment "double precision floating point dest'n register")
+ (attrs (MACH32))
+ (type h-frd)
+ (index f-rd)
+ (mode DF)
+)
+
+(dnop frs1q "quad precision floating point source register 1" ((MACH32))
+ h-frq f-rs1)
+(dnop frs2q "quad precision floating point source register 2" ((MACH32))
+ h-frq f-rs2)
+(dnop frdq "quad precision floating point dest'n register" ((MACH32))
+ h-frq f-rd)
+
+; Encoding/decoding of field for sparc64 requires extra effort.
+; See v9 page 40: 5.1.4.1 Floating-Point Register Number Encoding.
+(df f-frs1d-64 "rs1 field for sparc64 DF regs" ((MACH64)) 18 5 UINT
+ ((value pc) (or INT (srl value (const 5)) (and value (const #x1e))))
+ ((value pc) (or INT (sll (and value (const 1)) (const 5))
+ (and value (const #x1e))))
+)
+(df f-frs2d-64 "rs2 field for sparc64 DF regs" ((MACH64)) 4 5 UINT
+ ((value pc) (or INT (srl value (const 5)) (and value (const #x1e))))
+ ((value pc) (or INT (sll (and value (const 1)) (const 5))
+ (and value (const #x1e))))
+)
+(df f-frdd-64 "rd field for sparc64 DF regs" ((MACH64)) 29 5 UINT
+ ((value pc) (or INT (srl value (const 5)) (and value (const #x1e))))
+ ((value pc) (or INT (sll (and value (const 1)) (const 5))
+ (and value (const #x1e))))
+)
+(dnop frs1d "double precision floating point source register 1" ((MACH64))
+ h-frd f-frs1d-64)
+(dnop frs2d "double precision floating point source register 2" ((MACH64))
+ h-frd f-frs2d-64)
+(dnop frdd "double precision floating point dest'n register" ((MACH64))
+ h-frd f-frdd-64)
+
+; Encoding/decoding of field for sparc64 requires extra effort.
+; See v9 page 40: 5.1.4.1 Floating-Point Register Number Encoding.
+(df f-frs1q-64 "rs1 field for sparc64 TF regs" ((MACH64)) 18 5 UINT
+ ((value pc) (or INT (srl value (const 5)) (and value (const #x1e))))
+ ((value pc) (or INT (sll (and value (const 1)) (const 5))
+ (and value (const #x1e))))
+)
+(df f-frs2q-64 "rs2 field for sparc64 TF regs" ((MACH64)) 4 5 UINT
+ ((value pc) (or INT (srl value (const 5)) (and value (const #x1e))))
+ ((value pc) (or INT (sll (and value (const 1)) (const 5))
+ (and value (const #x1e))))
+)
+(df f-frdq-64 "rd field for sparc64 TF regs" ((MACH64)) 29 5 UINT
+ ((value pc) (or INT (srl value (const 5)) (and value (const #x1e))))
+ ((value pc) (or INT (sll (and value (const 1)) (const 5))
+ (and value (const #x1e))))
+)
+(dnop frs1q "quad precision floating point source register 1" ((MACH64))
+ h-frq f-frs1q-64)
+(dnop frs2q "quad precision floating point source register 2" ((MACH64))
+ h-frq f-frs2q-64)
+(dnop frdq "quad precision floating point dest'n register" ((MACH64))
+ h-frq f-frdq-64)
+
+(dnop fcc0 "%fcc0" () h-fcc0 f-nil)
+
+; Misc. support macros.
+; FIXME: TRAP32 wip
+; FIXME: sparc32/sparc64 differences
+; FIXME: trap handling in general (c-call's used until more thought invested)
+
+; Check if fpu is present and enabled.
+
+(define-pmacro (check-fp-enabled)
+ ; FIXME: more things to check
+ (if (not fpu?)
+ (c-call VOID "@cpu@_hw_trap" pc (c-code INT "TRAP32_FP_DIS")))
+)
+
+; Return pointer to FPU.
+; ??? wip. maybe move `snan?' to language proper?
+
+(define-pmacro (current-fpu) (c-call PTR "CGEN_CPU_FPU"))
+
+; Issue appropriate trap if x is an snan.
+
+(define-pmacro (check-sf-snan x)
+ (if (c-raw-call BI "cgen_sf_snan_p" (current-fpu) x)
+ (c-call VOID "@cpu@_hw_trap" pc (c-code INT "TRAP32_FP_DIS"))) ; FIXME
+)
+
+(define-pmacro (check-df-snan x)
+ (if (c-raw-call BI "cgen_df_snan_p" (current-fpu) x)
+ (c-call VOID "@cpu@_hw_trap" pc (c-code INT "TRAP32_FP_DIS"))) ; FIXME
+)
+
+; Floating point memory ops.
+
+; Note: the startup code uses a load to %f0 to see if an fpu is present.
+; Other startup code tries to set the EF bit in the PSR.
+
+(define-pmacro (fp-ld-op name comment op3 mode dest)
+ (begin
+ (dnmi (.sym name "f-reg") comment ()
+ (.str name " [$rs1],$" dest)
+ (emit (.sym name f-reg+reg) rs1 (rs2 0) dest))
+ (dnmi (.sym name "f-reg+0") comment ()
+ (.str name " [$rs1],$" dest)
+ (emit (.sym name f-reg+imm) rs1 (simm13 0) dest))
+ (dni (.sym name "f-reg+reg") comment ()
+ (.str name " [$rs1+$rs2],$" dest)
+ (+ OP_3 op3 dest rs1 (f-i 0) (f-res-asi 0) rs2)
+ (sequence ()
+ (check-fp-enabled)
+ (set dest (mem mode (add WI rs1 rs2))))
+ ())
+ (dni (.sym name "f-reg+imm") comment ()
+ (.str name " [$rs1+$simm13],$" dest)
+ (+ OP_3 op3 dest rs1 (f-i 1) simm13)
+ (sequence ()
+ (check-fp-enabled)
+ (set dest (mem mode (add WI rs1 simm13))))
+ ())
+ (dnmi (.sym name "f-reg/asi") comment ()
+ (.str name " [$rs1]$asi,$" dest)
+ (emit (.sym name f-reg+reg/asi) rs1 (rs2 0) asi dest))
+ (dni (.sym name "f-reg+reg/asi") comment ()
+ (.str name " [$rs1+$rs2]$asi,$" dest)
+ (+ OP_3 (.sym op3 A) dest rs1 (f-i 0) asi rs2)
+ (sequence ()
+ (check-fp-enabled)
+ (set dest (mem mode (add WI rs1 rs2))))
+ ())
+ )
+)
+(fp-ld-op ld "fp SF load" OP3_LDF SF frds)
+(fp-ld-op ldd "fp DF load" OP3_LDDF DF frdd)
+
+(define-pmacro (fp-st-op name comment op3 mode src)
+ (begin
+ (dnmi (.sym name "f-reg") comment ()
+ (.str name " $" src ",[$rs1]")
+ (emit (.sym name f-reg+reg) rs1 (rs2 0) src))
+ (dnmi (.sym name "f-reg+0") comment ()
+ (.str name " $" src ",[$rs1]")
+ (emit (.sym name f-reg+imm) rs1 (simm13 0) src))
+ (dni (.sym name "f-reg+reg") comment ()
+ (.str name " $" src ",[$rs1+$rs2]")
+ (+ OP_3 op3 src rs1 (f-i 0) (f-res-asi 0) rs2)
+ (sequence ()
+ (check-fp-enabled)
+ (set (mem mode (add WI rs1 rs2)) src))
+ ())
+ (dni (.sym name "f-reg+imm") comment ()
+ (.str name " $" src ",[$rs1+$simm13]")
+ (+ OP_3 op3 src rs1 (f-i 1) simm13)
+ (sequence ()
+ (check-fp-enabled)
+ (set (mem mode (add WI rs1 simm13)) src))
+ ())
+ (dnmi (.sym name "f-reg/asi") comment ()
+ (.str name " $" src ",[$rs1]$asi")
+ (emit (.sym name -reg+reg/asi) rs1 (rs2 0) asi src))
+ (dni (.sym name "f-reg+reg/asi") comment ()
+ (.str name " $" src ",[$rs1+$rs2]$asi")
+ (+ OP_3 (.sym op3 A) src rs1 (f-i 0) asi rs2)
+ (sequence ()
+ (check-fp-enabled)
+ (set (mem mode (add WI rs1 rs2)) src))
+ ())
+ )
+)
+(fp-st-op st "fp SF store" OP3_STF SF frds)
+(fp-st-op std "fp DF store" OP3_STDF DF frdd)
+
+; SF mode arithmetic ops.
+
+(define-pmacro (sf-unary-op name comment op3 fpop1 fn)
+ (begin
+ (dni name comment ()
+ (.str name " $frs1s,$frds")
+ (+ OP_2 op3 fpop1 frds frs1s (f-rs2 0))
+ (sequence ()
+ (check-fp-enabled)
+ (set frds (fn frs1s))
+ ; ??? dest is modified if snan, assign to tmp first?
+ ; [grep for all check-*-snan's]
+ (check-sf-snan frds))
+ ())
+ )
+)
+
+(define-pmacro (sf-binary-op name comment op3 fpop1 fn)
+ (begin
+ (dni name comment ()
+ (.str name " $frs1s,$frs2s,$frds")
+ (+ OP_2 op3 fpop1 frds frs1s frs2s)
+ (sequence ()
+ (check-fp-enabled)
+ (set frds (fn frs1s frs2s))
+ (check-sf-snan frds))
+ ())
+ )
+)
+
+(sf-unary-op fnegs "32 bit fp neg" OP3_FPOPS1 FPOPS1_FNEGS neg)
+(sf-unary-op fabss "32 bit fp abs" OP3_FPOPS1 FPOPS1_FABSS abs)
+
+(sf-binary-op fadds "32 bit fp add" OP3_FPOPS1 FPOPS1_FADDS add)
+(sf-binary-op fsubs "32 bit fp sub" OP3_FPOPS1 FPOPS1_FSUBS sub)
+(sf-binary-op fmuls "32 bit fp mul" OP3_FPOPS1 FPOPS1_FMULS mul)
+(sf-binary-op fdivs "32 bit fp div" OP3_FPOPS1 FPOPS1_FDIVS div)
+
+; ??? floating point compares are wip
+
+(dni fp-fcmps "32 bit compare" ()
+ "fcmps $frs1s,$frs2s"
+ (+ OP_2 OP3_FPOPS2 FPOPS2_FCMPS (f-rd 0) frs1s frs2s)
+ (sequence ()
+ (check-fp-enabled)
+ (set fcc0 (c-call UINT "SFCMP" frs1s frs2s)))
+ ()
+)
+
+(dni fp-fcmpse "32 bit compare, signal if any nans" ()
+ "fcmpse $frs1s,$frs2s"
+ (+ OP_2 OP3_FPOPS2 FPOPS2_FCMPSE (f-rd 0) frs1s frs2s)
+ (sequence ()
+ (check-fp-enabled)
+ (check-sf-snan frs1s)
+ (check-sf-snan frs2s)
+ (set fcc0 (c-call UINT "SFCMP" frs1s frs2s)))
+ ()
+)
+
+; DF mode arithmetic ops.
+
+(define-pmacro (df-unary-op name comment op3 fpop1 fn)
+ (begin
+ (dni name comment ()
+ (.str name " $frs1d,$frdd")
+ (+ OP_2 op3 fpop1 frdd frs1d (f-rs2 0))
+ (sequence ()
+ (check-fp-enabled)
+ (set frdd (fn frs1d))
+ (check-df-snan frdd))
+ ())
+ )
+)
+
+(define-pmacro (df-binary-op name comment op3 fpop1 fn)
+ (begin
+ (dni name comment ()
+ (.str name " $frs1d,$frs2d,$frdd")
+ (+ OP_2 op3 fpop1 frdd frs1d frs2d)
+ (sequence ()
+ (check-fp-enabled)
+ (set frdd (fn frs1d frs2d))
+ (check-df-snan frdd))
+ ())
+ )
+)
+
+(df-unary-op fnegd "64 bit fp neg" OP3_FPOPS1 FPOPS1_FNEGD neg)
+(df-unary-op fabsd "64 bit fp abs" OP3_FPOPS1 FPOPS1_FABSD abs)
+
+(df-binary-op faddd "64 bit fp add" OP3_FPOPS1 FPOPS1_FADDD add)
+(df-binary-op fsubd "64 bit fp sub" OP3_FPOPS1 FPOPS1_FSUBD sub)
+(df-binary-op fmuld "64 bit fp mul" OP3_FPOPS1 FPOPS1_FMULD mul)
+(df-binary-op fdivd "64 bit fp div" OP3_FPOPS1 FPOPS1_FDIVD div)
+
+; ??? floating point compares are wip
+
+(dni fp-fcmpd "64 bit compare" ()
+ "fcmpd $frs1d,$frs2d"
+ (+ OP_2 OP3_FPOPS2 FPOPS2_FCMPD (f-rd 0) frs1d frs2d)
+ (sequence ()
+ (check-fp-enabled)
+ (set fcc0 (c-call UINT "DFCMP" frs1d frs2d)))
+ ()
+)
+
+(dni fp-fcmpde "64 bit compare, signal if any nans" ()
+ "fcmpde $frs1d,$frs2d"
+ (+ OP_2 OP3_FPOPS2 FPOPS2_FCMPDE (f-rd 0) frs1d frs2d)
+ (sequence ()
+ (check-fp-enabled)
+ (check-df-snan frs1d)
+ (check-df-snan frs2d)
+ (set fcc0 (c-call UINT "DFCMP" frs1d frs2d)))
+ ()
+)
+
+; Branches
+
+; CC is one of fcc0,fcc
+(define-pmacro (ftest-u cc) (eq cc FCC_UN))
+(define-pmacro (ftest-g cc) (eq cc FCC_GT))
+(define-pmacro (ftest-ug cc) (orif (eq cc FCC_UN) (eq cc FCC_GT)))
+(define-pmacro (ftest-l cc) (eq cc FCC_LT))
+(define-pmacro (ftest-ul cc) (orif (eq cc FCC_UN) (eq cc FCC_LT)))
+(define-pmacro (ftest-lg cc) (orif (eq cc FCC_LT) (eq cc FCC_GT)))
+(define-pmacro (ftest-ne cc) (ne cc FCC_EQ))
+(define-pmacro (ftest-e cc) (eq cc FCC_EQ))
+(define-pmacro (ftest-ue cc) (orif (eq cc FCC_UN) (eq cc FCC_EQ)))
+(define-pmacro (ftest-ge cc) (orif (eq cc FCC_GT) (eq cc FCC_EQ)))
+(define-pmacro (ftest-uge cc) (ne cc FCC_LT))
+(define-pmacro (ftest-le cc) (orif (eq cc FCC_LT) (eq cc FCC_EQ)))
+(define-pmacro (ftest-ule cc) (ne cc FCC_GT))
+(define-pmacro (ftest-o cc) (ne cc FCC_UN))
+
+(define-pmacro (fbfcc-branch bname comment cond test br-sem)
+ (begin
+ (dni bname (.str "fp branch " comment) (V9-DEPRECATED)
+ (.str bname "$a $disp22")
+ (+ OP_0 a cond OP2_FBFCC disp22)
+ (br-sem test fcc0)
+ ())
+ )
+)
+(fbfcc-branch fba "always" FCOND_A test-always uncond-br-sem)
+(fbfcc-branch fbn "never" FCOND_N test-never uncond-br-sem)
+(fbfcc-branch fbu "unordered" FCOND_U ftest-u cond-br-sem)
+(fbfcc-branch fbg "greater" FCOND_G ftest-g cond-br-sem)
+(fbfcc-branch fbug "unordered or greater" FCOND_UG ftest-ug cond-br-sem)
+(fbfcc-branch fbl "less" FCOND_L ftest-l cond-br-sem)
+(fbfcc-branch fbul "unordered or less" FCOND_UL ftest-ul cond-br-sem)
+(fbfcc-branch fblg "less or greater" FCOND_LG ftest-lg cond-br-sem)
+(fbfcc-branch fbne "not equal" FCOND_NE ftest-ne cond-br-sem)
+(fbfcc-branch fbe "equal" FCOND_E ftest-e cond-br-sem)
+(fbfcc-branch fbue "unordered or equal" FCOND_UE ftest-ue cond-br-sem)
+(fbfcc-branch fbge "greater or equal" FCOND_GE ftest-ge cond-br-sem)
+(fbfcc-branch fbuge "unordered or greater or equal" FCOND_UGE ftest-uge cond-br-sem)
+(fbfcc-branch fble "less or equal" FCOND_LE ftest-le cond-br-sem)
+(fbfcc-branch fbule "unordered or less or equal" FCOND_ULE ftest-ule cond-br-sem)
+(fbfcc-branch fbo "ordered" FCOND_O ftest-o cond-br-sem)
diff --git a/cgen/stamp-h.in b/cgen/stamp-h.in
new file mode 100644
index 00000000000..9788f70238c
--- /dev/null
+++ b/cgen/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/cgen/thumb.cpu b/cgen/thumb.cpu
new file mode 100644
index 00000000000..343a9cad03b
--- /dev/null
+++ b/cgen/thumb.cpu
@@ -0,0 +1,842 @@
+; ARM/Thumb instructions. -*- Scheme -*-
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+;
+; This file is included by arm.cpu.
+
+; Hardware elements.
+
+(define-hardware
+ (name h-gr-t)
+ (comment "Thumb's general purpose registers")
+ (attrs (ISA thumb) VIRTUAL) ; ??? CACHE-ADDR should be doable
+ (type register WI (8))
+ (indices keyword ""
+ ((r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)))
+ (get (regno) (reg h-gr regno))
+ (set (regno newval) (set (reg h-gr regno) newval))
+)
+
+(define-hardware
+ (name h-lr-t)
+ (comment "Thumb's access to the LR register")
+ (attrs (ISA thumb) VIRTUAL)
+ (type register WI)
+ (get () (reg h-gr 14))
+ (set (newval) (set (reg h-gr 14) newval))
+)
+
+(define-hardware
+ (name h-sp-t)
+ (comment "Thumb's access to the SP register")
+ (attrs (ISA thumb) VIRTUAL)
+ (type register WI)
+ (get () (reg h-gr 13))
+ (set (newval) (set (reg h-gr 13) newval))
+)
+
+; Instruction fields.
+
+; define-normal-thumb-field
+(define-pmacro (dntf name comment attrs start length)
+ (dnf name comment (.splice (.unsplice attrs) (ISA thumb)) start length)
+)
+
+; Main opcode fields.
+(dntf f-op3 "First 3 bits of opcode" () 15 3)
+(dntf f-op4 "First 4 bits of opcode" () 15 4)
+(dntf f-op5 "First 5 bits of opcode" () 15 5)
+(dntf f-op6 "First 6 bits of opcode" () 15 6)
+(dntf f-op8 "First 8 bits of opcode" () 15 8)
+
+; Other opcode like fields with special names.
+(dntf f-h1 "h1 field in hireg insns" () 7 1)
+(dntf f-h2 "h2 field in hireg insns" () 6 1)
+(dntf f-l "load/store indicator" () 11 1)
+(dntf f-b "byte/word indicator" () 10 1)
+(dntf f-h "byte/halfword indicator" () 11 1)
+
+; Misc. remaining opcode fields (constant values but unnamed).
+(dntf f-bit9 "bit 9" () 9 1)
+
+; Data fields.
+(dntf f-offset5 "5 bit unsigned immediate" () 10 5)
+(dntf f-rs "Rs (source reg)" () 5 3)
+(dntf f-rd "Rd (dest reg)" () 2 3)
+(dntf f-rn "Rn (2nd source reg in add/sub insns" () 8 3)
+(dntf f-offset3 "3 bit unsigned immediate in add/sub insns" () 8 3)
+(dntf f-bit10-rd "Rd (dest reg) at bit 10" () 10 3)
+(dntf f-offset8 "8 bit unsigned immediate" () 7 8)
+(dntf f-ro "Ro (offset register)" () 8 3)
+(dntf f-rb "Rb (base register)" () 5 3)
+
+; Instruction operands.
+
+; define-normal-thumb-operand
+(define-pmacro (dntop name comment attrs hw indx)
+ (dnop name comment (.splice (.unsplice attrs) (ISA thumb)) hw indx)
+)
+
+(dntop sp "stack pointer" () h-sp-t f-nil)
+(dntop lr "link register" () h-lr-t f-nil)
+
+(dntop rd "destination register" () h-gr-t f-rd)
+(dntop rs "source register" () h-gr-t f-rs)
+(dntop offset5 "5 bit unsigned immediate" () h-uint f-offset5)
+(dntop rn "2nd source register" () h-gr-t f-rn)
+(dntop offset3 "3 bit unsigned immediate" () h-uint f-offset3)
+(dntop offset8 "8 bit unsigned immediate" () h-uint f-offset8)
+
+(dntop bit10-rd "rd in bits 10,9,8" () h-gr-t f-bit10-rd)
+
+(dntop ro "offset register" () h-gr-t f-ro)
+(dntop rb "base register" () h-gr-t f-rb)
+
+; Instruction definitions.
+
+; Cover macro to dni to indicate these are all Thumb insns.
+; dnti: define-normal-thumb-insn
+
+(define-pmacro (dnti xname xcomment xattrs xsyntax xformat xsemantics)
+ (define-insn
+ (name xname)
+ (comment xcomment)
+ (.splice attrs (.unsplice xattrs) (ISA thumb))
+ (syntax xsyntax)
+ (format xformat)
+ (semantics xsemantics)
+ )
+)
+
+; Move shifted register insns.
+
+(dntf f-shift-op "Move shifted register opcode" () 12 2)
+
+(dnti lsl "logical shift left"
+ ()
+ "lsl $rd,$rs,#$offset5"
+ (+ (f-op3 0) (f-shift-op 0) offset5 rs rd)
+ (sequence ((BI carry-out))
+ (set carry-out
+ (c-call BI "compute_carry_out_immshift" rs
+ SHIFT-TYPE-lsl offset5 cbit))
+ (set rd (sll rs offset5))
+ (set-logical-cc rd carry-out))
+)
+(dnti lsr "logical shift right"
+ ()
+ "lsr $rd,$rs,#$offset5"
+ (+ (f-op3 0) (f-shift-op 1) offset5 rs rd)
+ (sequence ((BI carry-out))
+ (set carry-out
+ (c-call BI "compute_carry_out_immshift" rs
+ SHIFT-TYPE-lsr offset5 cbit))
+ (set rd (srl rs offset5))
+ (set-logical-cc rd carry-out))
+)
+(dnti asr "arithmetic shift right"
+ ()
+ "asr $rd,$rs,#$offset5"
+ (+ (f-op3 0) (f-shift-op 2) offset5 rs rd)
+ (sequence ((BI carry-out))
+ (set carry-out
+ (c-call BI "compute_carry_out_immshift" rs
+ SHIFT-TYPE-asr offset5 cbit))
+ (set rd (sra rs offset5))
+ (set-logical-cc rd carry-out))
+)
+
+; Add/subtract insns.
+
+(dntf f-i "immediate indicator in add/sub insns" () 10 1)
+
+(dntf f-addsub-op "Add/subtract opcode" () 9 1)
+
+(dnti add "add reg+reg"
+ ()
+ "add $rd,$rs,$rn"
+ (+ (f-op5 3) (f-i 0) (f-addsub-op 0) rn rs rd)
+ (sequence ()
+ (set-add-flags rs rn 0)
+ (set rd (add rs rn)))
+)
+(dnti addi "add reg+imm"
+ ()
+ "add $rd,$rs,#$offset3"
+ (+ (f-op5 3) (f-i 1) (f-addsub-op 0) offset3 rs rd)
+ (sequence ()
+ (set-add-flags rs offset3 0)
+ (set rd (add rs offset3)))
+)
+(dnti sub "sub reg+reg"
+ ()
+ "sub $rd,$rs,$rn"
+ (+ (f-op5 3) (f-i 0) (f-addsub-op 1) rn rs rd)
+ (sequence ()
+ (set-sub-flags rs rn 1)
+ (set rd (sub rs rn)))
+)
+(dnti subi "sub reg+imm"
+ ()
+ "sub $rd,$rs,#$offset3"
+ (+ (f-op5 3) (f-i 1) (f-addsub-op 1) offset3 rs rd)
+ (sequence ()
+ (set-sub-flags rs offset3 1)
+ (set rd (sub rs offset3)))
+)
+
+; Move/compare/add/subtract immediate insns.
+
+(dntf f-mcasi-op "Move/compare/add/subtract immediate opcode" () 12 2)
+
+(dnti mov "move imm->reg"
+ ()
+ "mov ${bit10-rd},#$offset8"
+ (+ (f-op3 1) (f-mcasi-op 0) bit10-rd offset8)
+ (sequence ()
+ (set bit10-rd offset8)
+ (set-zn-flags bit10-rd))
+)
+(dnti cmp "cmp reg,imm"
+ ()
+ "cmp ${bit10-rd},#$offset8"
+ (+ (f-op3 1) (f-mcasi-op 1) bit10-rd offset8)
+ (set-sub-flags bit10-rd offset8 1)
+)
+(dnti addi8 "add 8 bit immediate"
+ ()
+ "add ${bit10-rd},#$offset8"
+ (+ (f-op3 1) (f-mcasi-op 2) bit10-rd offset8)
+ (sequence ()
+ (set-add-flags bit10-rd offset8 0)
+ (set bit10-rd (add bit10-rd offset8)))
+)
+(dnti subi8 "sub 8 bit immediate"
+ ()
+ "sub ${bit10-rd},#$offset8"
+ (+ (f-op3 1) (f-mcasi-op 3) bit10-rd offset8)
+ (sequence ()
+ (set-sub-flags bit10-rd offset8 1)
+ (set bit10-rd (sub bit10-rd offset8)))
+)
+
+; ALU operations.
+
+(dntf f-alu-op "ALU opcode" () 9 4)
+
+(define-pmacro (alu-logical-op mnemonic comment alu-opcode sem-fn)
+ (dnti (.sym alu- mnemonic) comment
+ ()
+ (.str mnemonic " $rd,$rs")
+ (+ (f-op6 #x10) (f-alu-op alu-opcode) rs rd)
+ (sequence ()
+ (set rd (sem-fn rd rs))
+ (set-zn-flags rd))
+ )
+)
+
+(define-pmacro (alu-arith-op mnemonic comment alu-opcode sem-fn set-flags)
+ (dnti (.sym alu- mnemonic) comment
+ ()
+ (.str mnemonic " $rd,$rs")
+ (+ (f-op6 #x10) (f-alu-op alu-opcode) rs rd)
+ (sequence ((SI result))
+ (set result (sem-fn rd rs cbit))
+ (set-flags rd rs cbit)
+ (set rd result))
+ )
+)
+
+(define-pmacro (alu-shift-op mnemonic comment alu-opcode sem-fn shift-type)
+ (dnti (.sym alu- mnemonic) comment
+ ()
+ (.str mnemonic " $rd,$rs")
+ (+ (f-op6 #x10) (f-alu-op alu-opcode) rs rd)
+ (sequence ((BI carry-out) (SI result))
+ (set carry-out
+ (c-call BI "compute_carry_out_regshift"
+ rd shift-type rs cbit))
+ (set result (sem-fn rd rs))
+ (set rd result)
+ (set-logical-cc result carry-out))
+ )
+)
+
+(alu-logical-op and "and" 0 and)
+(alu-logical-op eor "xor" 1 xor)
+
+(alu-shift-op lsl "logical shift left" 2 sll SHIFT-TYPE-lsl)
+(alu-shift-op lsr "logical shift right" 3 srl SHIFT-TYPE-lsr)
+(alu-shift-op asr "arithmetic shift right" 4 sra SHIFT-TYPE-asr)
+(alu-shift-op ror "rotate right" 7 ror SHIFT-TYPE-ror)
+
+(alu-arith-op adc "add with carry" 5
+ (.pmacro (rd rs cbit) (addc rd rs cbit))
+ (.pmacro (rd rs cbit) (set-add-flags rd rs cbit)))
+(alu-arith-op sbc "subtract with carry (borrow)" 6
+ (.pmacro (rd rs cbit) (subc rd rs (not cbit)))
+ (.pmacro (rd rs cbit) (set-sub-flags rd rs cbit)))
+
+(dnti alu-tst "test"
+ ()
+ "tst $rd,$rs"
+ (+ (f-op6 #x10) (f-alu-op 8) rs rd)
+ (sequence ((SI x))
+ (set x (and rd rs))
+ (set-zn-flags x))
+)
+
+(alu-arith-op neg "negate" 9
+ (.pmacro (rd rs cbit) (neg rs))
+ (.pmacro (rd rs cbit) (set-sub-flags 0 rs 1)))
+
+(dnti alu-cmp "compare"
+ ()
+ "cmp $rd,$rs"
+ (+ (f-op6 #x10) (f-alu-op 10) rs rd)
+ (set-sub-flags rd rs 1)
+)
+(dnti alu-cmn "compare negative"
+ ()
+ "cmn $rd,$rs"
+ (+ (f-op6 #x10) (f-alu-op 11) rs rd)
+ (set-add-flags rd rs 0)
+)
+
+(alu-logical-op orr "or" 12 or)
+
+; use alu-logical-op 'cus it sets the condition codes the way we want
+(alu-logical-op mul "multiply" 13 mul)
+
+(alu-logical-op bic "bit clear" 14 (.pmacro (rd rs) (and rd (inv rs))))
+
+(alu-logical-op mvn "invert" 15 (.pmacro (rd rs) (inv rs)))
+
+; Hi register operations.
+;
+; R15 and PC are treated as two distinct registers. It is assumed that the
+; execution environment ensures R15 = PC+4. All reads are taken from R15.
+; All writes are written to PC.
+
+(define-hardware
+ (name h-hiregs)
+ (comment "High registers (R8-R15)")
+ (attrs (ISA thumb) VIRTUAL)
+ (type register WI (8))
+ (indices keyword ""
+ ((r8 0) (r9 1) (r10 2) (r11 3) (r12 4) (r13 5) (r14 6) (r15 7)))
+ ; ??? Accesses won't be as efficient as possible as +8 calculation will
+ ; get done at exec time (could be defered to extract phase), but that's an
+ ; optimization that can be generally useful in the extract phase.
+ (get (regno) (reg h-gr (add regno (const 8))))
+ (set (regno newval) (set (reg h-gr (add regno (const 8))) newval))
+)
+
+
+(dntf f-hireg-op "Hi register opcode" () 9 2)
+
+(dntop hs "high source register" () h-hiregs f-rs)
+(dntop hd "high destination register" () h-hiregs f-rd)
+
+(define-pmacro (hireg-op mnemonic
+ lo-op-hi-comment
+ hi-op-lo-comment
+ hi1-op-hi2-comment
+ opcode
+ lo-dest-sem-fn
+ hi-dest-sem-fn)
+ (begin
+ (dnti (.sym mnemonic -rd-hs)
+ lo-op-hi-comment
+ ()
+ (.str mnemonic " $rd,$hs")
+ (+ (f-op6 #x11) (f-hireg-op opcode) (f-h1 0) (f-h2 1) hs rd)
+ (lo-dest-sem-fn rd hs)
+ )
+ (dnti (.sym mnemonic -hd-rs)
+ hi-op-lo-comment
+ ()
+ (.str mnemonic " $hd,$rs")
+ (+ (f-op6 #x11) (f-hireg-op opcode) (f-h1 1) (f-h2 0) hd rs)
+ (hi-dest-sem-fn hd rs)
+ )
+ (dnti (.sym mnemonic -hd-hs)
+ hi1-op-hi2-comment
+ ()
+ (.str mnemonic " $hd,$hs")
+ (+ (f-op6 #x11) (f-hireg-op opcode) (f-h1 1) (f-h2 1) hd hs)
+ (hi-dest-sem-fn hd hs)
+ )
+ )
+)
+
+(hireg-op add "lo = lo + hi" "hi = hi + lo" "hi = hi + hi2" 0
+ (.pmacro (src1-dest src2) (set src1-dest (add src1-dest src2)))
+ (.pmacro (src1-dest src2)
+ (if (eq (regno src1-dest) 7)
+ (set pc (add src1-dest src2))
+ (set src1-dest (add src1-dest src2))))
+)
+
+(hireg-op cmp "compare lo,hi" "compare hi,lo" "compare hi1,hi2" 1
+ (.pmacro (src1 src2) (set-sub-flags src1 src2 1))
+ (.pmacro (src1 src2) (set-sub-flags src1 src2 1))
+)
+
+(hireg-op mov "lo = hi" "hi = lo" "hi1 = hi2" 2
+ (.pmacro (dest src) (set dest src))
+ (.pmacro (dest src)
+ (if (eq (regno dest) 7)
+ (set pc src)
+ (set dest src)))
+)
+
+(dnti bx-rs "bx on lo reg"
+ ()
+ "bx $rs"
+ (+ (f-op6 #x11) (f-hireg-op 3) (f-h1 0) (f-h2 0) (f-rd 0) rs)
+ (sequence ()
+ (set pc rs)
+ (if (not (and rs 1))
+ (set (reg h-tbit) 0)))
+)
+(dnti bx-hs "bx on hi reg"
+ ()
+ "bx $hs"
+ (+ (f-op6 #x11) (f-hireg-op 3) (f-h1 0) (f-h2 1) (f-rd 0) hs)
+ (sequence ()
+ (set pc hs)
+ (if (not (and hs 1))
+ (set (reg h-tbit) 0)))
+)
+
+; PC relative load.
+
+(df f-word8 "10 bit unsigned offset, right shifted by 2"
+ ((ISA thumb))
+ 7 8 UINT
+ ((value pc) (srl WI value (const 2)))
+ ((value pc) (sll WI value (const 2)))
+)
+
+(dntop word8 "10 bit unsigned immediate" () h-uint f-word8)
+
+(dnti ldr-pc "pc relative load"
+ ()
+ "ldr ${bit10-rd},[pc,#$word8]"
+ (+ (f-op5 9) bit10-rd word8)
+ (set bit10-rd
+ (mem WI (add (and (add pc (const 4)) (const WI -4)) word8)))
+)
+
+; Load/store with register offset.
+
+(dnti str "store word"
+ ()
+ "str $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-l 0) (f-b 0) (f-bit9 0) ro rb rd)
+ (set (mem WI (add rb ro)) rd)
+)
+(dnti strb "store byte"
+ ()
+ "strb $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-l 0) (f-b 1) (f-bit9 0) ro rb rd)
+ (set (mem QI (add rb ro)) rd)
+)
+(dnti ldr "load word"
+ ()
+ "ldr $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-l 1) (f-b 0) (f-bit9 0) ro rb rd)
+ (set rd (mem WI (add rb ro)))
+)
+(dnti ldrb "load zero extended byte"
+ ()
+ "ldrb $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-l 1) (f-b 1) (f-bit9 0) ro rb rd)
+ (set rd (zext SI (mem QI (add rb ro))))
+)
+
+; Load/store sign-extended byte/halfword.
+
+(dntf f-s "signed/unsigned indicator" () 10 1)
+
+(dnti strh "store halfword"
+ ()
+ "strh $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-h 0) (f-s 0) (f-bit9 1) ro rb rd)
+ (set (mem HI (add rb ro)) rd)
+)
+(dnti ldrh "load zero extended halfword"
+ ()
+ "ldrh $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-h 1) (f-s 0) (f-bit9 1) ro rb rd)
+ (set rd (zext SI (mem HI (add rb ro))))
+)
+(dnti ldsb "load sign extended byte"
+ ()
+ "ldsb $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-h 0) (f-s 1) (f-bit9 1) ro rb rd)
+ (set rd (ext SI (mem QI (add rb ro))))
+)
+(dnti ldsh "load sign extended halfword"
+ ()
+ "ldsh $rd,[$rb,$ro]"
+ (+ (f-op4 5) (f-h 1) (f-s 1) (f-bit9 1) ro rb rd)
+ (set rd (ext SI (mem HI (add rb ro))))
+)
+
+; Load/store with immediate offset.
+
+(dntf f-b-imm "byte/word indicator in load/store with immediate offset insns" () 12 1)
+
+(df f-offset5-7 "offset5 field as 7 bit unsigned immediate"
+ ((ISA thumb))
+ 10 5 UINT
+ ((value pc) (srl WI value (const 2)))
+ ((value pc) (sll WI value (const 2)))
+)
+
+(dntop offset5-7 "offset5 as 7 bit unsigned immediate" () h-uint f-offset5-7)
+
+(dnti str-imm "store word with immediate offset"
+ ()
+ "str $rd,[$rb,#${offset5-7}]"
+ (+ (f-op3 3) (f-b-imm 0) (f-l 0) offset5-7 rb rd)
+ (set (mem WI (add rb offset5-7)) rd)
+)
+(dnti ldr-imm "load word with immediate offset"
+ ()
+ "ldr $rd,[$rb,#${offset5-7}]"
+ (+ (f-op3 3) (f-b-imm 0) (f-l 1) offset5-7 rb rd)
+ (set rd (mem WI (add rb offset5-7)))
+)
+(dnti strb-imm "store byte with immediate offset"
+ ()
+ "strb $rd,[$rb,#$offset5]"
+ (+ (f-op3 3) (f-b-imm 1) (f-l 0) offset5 rb rd)
+ (set (mem QI (add rb offset5)) rd)
+)
+(dnti ldrb-imm "load zero extended byte with immediate offset"
+ ()
+ "ldrb $rd,[$rb,#$offset5]"
+ (+ (f-op3 3) (f-b-imm 1) (f-l 1) offset5 rb rd)
+ (set rd (zext SI (mem QI (add rb offset5))))
+)
+
+; Load/store halfword with immediate offset.
+
+(df f-offset5-6 "offset5 field as 6 bit unsigned immediate"
+ ((ISA thumb))
+ 10 5 UINT
+ ((value pc) (srl WI value (const 1)))
+ ((value pc) (sll WI value (const 1)))
+)
+
+(dntop offset5-6 "offset5 as 7 bit unsigned immediate" () h-uint f-offset5-6)
+
+(dnti strh-imm "store halfword with immediate offset"
+ ()
+ "strh $rd,[$rb,#${offset5-6}]"
+ (+ (f-op4 8) (f-l 0) offset5-6 rb rd)
+ (set (mem HI (add rb offset5-6)) rd)
+)
+(dnti ldrh-imm "load zero extended halfword with immediate offset"
+ ()
+ "ldrh $rd,[$rb,#${offset5-6}]"
+ (+ (f-op4 8) (f-l 1) offset5-6 rb rd)
+ (set rd (zext WI (mem HI (add rb offset5-6))))
+)
+
+; SP-relative load/store
+
+(dnti str-sprel "store word, sp-relative"
+ ()
+ "str ${bit10-rd},[sp,#$word8]"
+ (+ (f-op4 9) (f-l 0) bit10-rd word8)
+ (set (mem WI (add sp word8)) bit10-rd)
+)
+(dnti ldr-sprel "load word, sp-relative"
+ ()
+ "ldr ${bit10-rd},[sp,#$word8]"
+ (+ (f-op4 9) (f-l 1) bit10-rd word8)
+ (set bit10-rd (mem WI (add sp word8)))
+)
+
+; Load address
+
+(dntf f-sp "sp/pc indicator" () 11 1)
+
+(dnti lda-pc "load address from pc"
+ ()
+ "add ${bit10-rd},pc,$word8"
+ (+ (f-op4 10) (f-sp 0) bit10-rd word8)
+ (set bit10-rd (add (and (add pc (const 4)) (const WI -4)) word8))
+)
+(dnti lda-sp "load address from sp"
+ ()
+ "add ${bit10-rd},sp,$word8"
+ (+ (f-op4 10) (f-sp 1) bit10-rd word8)
+ (set bit10-rd (add sp word8))
+)
+
+; Add offset to stack pointer.
+; FIXME: Handling of sign+magnitude needs revisiting.
+; If expressions are allowed here we can't assume "-" follows "#".
+
+(dntf f-addoff-s "s bit in add offset to sp insns" () 7 1)
+
+(df f-sword7 "7 bit magnitude, accompanies sign bit"
+ ((ISA thumb))
+ 6 7 UINT
+ ((value pc) (srl WI value (const 2)))
+ ((value pc) (sll WI value (const 2)))
+)
+
+(dntop sword7 "7 bit magnitude, accompanies sign bit" () h-uint f-sword7)
+
+(dnti add-sp "add offset to sp"
+ ()
+ "add sp,#$sword7"
+ (+ (f-op8 #xb0) (f-addoff-s 0) sword7)
+ (set sp (add sp sword7))
+)
+(dnti sub-sp "subtract offset from sp"
+ ()
+ "add sp,#-$sword7"
+ (+ (f-op8 #xb0) (f-addoff-s 1) sword7)
+ (set sp (sub sp sword7))
+)
+
+; Push/pop registers.
+
+; FIXME: Might be better to use sequence temp as address reg.
+
+(define-pmacro (push-reg regno)
+ (if (and rlist (sll 1 regno))
+ (sequence ()
+ (set sp (sub sp 4))
+ (set (mem WI sp) (reg WI h-gr-t regno))
+ ))
+)
+(define-pmacro (pop-reg regno)
+ (if (and rlist (sll 1 regno))
+ (sequence ()
+ (set (reg WI h-gr-t regno) (mem WI sp))
+ (set sp (add sp 4))
+ ))
+)
+
+(dntf f-pushpop-op "opcode bits 10,9 in push/pop insns" () 10 2)
+
+(dntf f-r "register indicator in push/pop insns" () 8 1)
+
+(dntf f-rlist "register list" () 7 8)
+
+; ??? Print/parse handler specs missing. Later.
+(dntop rlist "register list" () h-uint f-rlist)
+(dntop rlist-lr "register list with lr" () h-uint f-rlist)
+(dntop rlist-pc "register list with pc" () h-uint f-rlist)
+
+(dnti push "push registers"
+ ()
+ "push {$rlist}"
+ (+ (f-op4 11) (f-l 0) (f-pushpop-op 2) (f-r 0) rlist)
+ (.splice sequence () (.unsplice (.map push-reg (.iota 8 7 -1))))
+)
+(dnti push-lr "push registers and lr"
+ ()
+ "push {${rlist-lr}}"
+ (+ (f-op4 11) (f-l 0) (f-pushpop-op 2) (f-r 1) rlist)
+ (.splice sequence ()
+ (set sp (sub sp 4))
+ (set (mem WI sp) lr)
+ (.unsplice (.map push-reg (.iota 8 7 -1)))
+ )
+)
+
+(dnti pop "pop registers"
+ ()
+ "pop {$rlist}"
+ (+ (f-op4 11) (f-l 1) (f-pushpop-op 2) (f-r 0) rlist)
+ (.splice sequence () (.unsplice (.map pop-reg (.iota 8))))
+)
+(dnti pop-pc "pop registers and pc"
+ ()
+ "pop {${rlist-pc}}"
+ (+ (f-op4 11) (f-l 1) (f-pushpop-op 2) (f-r 1) rlist)
+ (.splice sequence ()
+ (.unsplice (.map pop-reg (.iota 8)))
+ (set pc (mem WI sp))
+ (set sp (add sp 4))
+ )
+)
+
+; Multiple load/store.
+
+; FIXME: Might be better to use sequence temp as address reg.
+
+(dntf f-bit10-rb "Rb at bit 10" () 10 3)
+
+(dntop bit10-rb "base reg at bit 10" () h-gr-t f-bit10-rb)
+
+(define-pmacro (save-reg-inc regno)
+ (if (and rlist (sll 1 regno))
+ (sequence ()
+ (set (mem WI bit10-rb) (reg WI h-gr-t regno))
+ (set bit10-rb (add bit10-rb 4))
+ ))
+)
+(define-pmacro (load-reg-inc regno)
+ (if (and rlist (sll 1 regno))
+ (sequence ()
+ (set (reg WI h-gr-t regno) (mem WI bit10-rb))
+ (set bit10-rb (add bit10-rb 4))
+ ))
+)
+
+(dnti stmia "store multiple"
+ ()
+ "stmia $rb!,{$rlist}"
+ (+ (f-op4 12) (f-l 0) bit10-rb rlist)
+ (.splice sequence () (.unsplice (.map save-reg-inc (.iota 8))))
+)
+(dnti ldmia "load multiple"
+ ()
+ "ldmia $rb!,{$rlist}"
+ (+ (f-op4 12) (f-l 1) bit10-rb rlist)
+ (.splice sequence () (.unsplice (.map load-reg-inc (.iota 8))))
+)
+
+; Conditional branches.
+
+(dntf f-cond "condition code spec" () 11 4)
+
+; The standard condition code tests.
+
+(define-normal-insn-enum cc-tests
+ "condition code tests"
+ () "" f-cond
+ (
+ (CC_EQ 0) ; equal
+ (CC_NE 1) ; not equal
+ (CC_CS 2) ; carry set (unsigned greater or equal)
+ (CC_CC 3) ; carry clear (unsigned less than)
+ (CC_MI 4) ; minus (negative)
+ (CC_PL 5) ; positive or zero
+ (CC_VS 6) ; overflow set
+ (CC_VC 7) ; overflow clear
+ (CC_HI 8) ; higher (unsigned greater)
+ (CC_LS 9) ; less or same (unsigned less or equal)
+ (CC_GE 10) ; greater or equal
+ (CC_LT 11) ; less
+ (CC_GT 12) ; greater
+ (CC_LE 13) ; less or equal
+ )
+)
+
+(df f-soffset8 "8 bit pc relative branch address"
+ (PCREL-ADDR (ISA thumb))
+ 7 8 INT
+ ((value pc) (sra WI (sub WI value (add WI pc (const 4))) (const 1)))
+ ((value pc) (add WI (sll WI value (const 1)) (add WI pc (const 4))))
+)
+
+(dntop soffset8 "8 bit pc relative branch address" () h-iaddr f-soffset8)
+
+(define-pmacro (cbranch bname comment cond test)
+ (dnti bname (.str "branch if " comment)
+ ()
+ (.str bname " $soffset8")
+ (+ (f-op4 13) cond soffset8)
+ (if (test)
+ (set pc soffset8))
+ )
+)
+(cbranch beq "eq" CC_EQ test-eq)
+(cbranch bne "ne" CC_NE test-ne)
+(cbranch bcs "cs (ltu)" CC_CS test-cs)
+(cbranch bcc "cc (geu)" CC_CC test-cc)
+(cbranch bmi "mi (negative)" CC_MI test-mi)
+(cbranch bpl "pl (positive or zero)" CC_PL test-pl)
+(cbranch bvs "vs (overflow set)" CC_VS test-vs)
+(cbranch bvc "vc (overflow clear)" CC_VC test-vc)
+(cbranch bhi "hi (gtu)" CC_HI test-hi)
+(cbranch bls "ls (leu)" CC_LS test-ls)
+(cbranch bge "ge" CC_GE test-ge)
+(cbranch blt "lt" CC_LT test-lt)
+(cbranch bgt "gt" CC_GT test-gt)
+(cbranch ble "le" CC_LE test-le)
+
+; Software interrupt.
+
+(dntf f-value8 "8 bit value for swi" () 7 8)
+
+(dntop value8 "8 bit value for swi" () h-uint f-value8)
+
+(dnti swi "software interrupt"
+ ()
+ "swi $value8"
+ (+ (f-op8 #xdf) value8)
+ ; FIXME: for now
+ (set pc (c-call WI "thumb_swi" pc value8))
+)
+
+; Unconditional branch.
+
+(df f-offset11 "11 bit pc relative branch address"
+ (PCREL-ADDR (ISA thumb))
+ 10 11 INT
+ ((value pc) (sra WI (sub value (add pc (const 4))) (const 1)))
+ ((value pc) (add WI (sll value (const 1)) (add pc (const 4))))
+)
+
+(dntop offset11 "11 bit pc relative branch address" () h-iaddr f-offset11)
+
+(dnti b "unconditional branch"
+ ()
+ "b $offset11"
+ (+ (f-op5 #x1c) offset11)
+ (set pc offset11)
+)
+
+; Long branch with link.
+; Two instructions that make up a subroutine call.
+; FIXME: Assembler access is via one insn - macro-insn?
+; Left for later, as is all assembly considerations.
+
+(dntf f-lbwl-h "long branch with link `h' field" () 11 1)
+
+; This one is signed.
+(define-ifield
+ (name f-lbwl-hi)
+ (comment "long branch with link offset, high part")
+ (attrs (ISA thumb))
+ (mode INT)
+ (start 10)
+ (length 11)
+)
+(dntop lbwl-hi "long branch with link offset, high part" ()
+ h-sint f-lbwl-hi)
+
+; This one is unsigned.
+(dntf f-lbwl-lo "long branch with link offset, low part" () 10 11)
+(dntop lbwl-lo "long branch with link offset, low part" ()
+ h-uint f-lbwl-lo)
+
+(dnti bl-hi "branch link, high offset"
+ ()
+ "bl-hi ${lbwl-hi}"
+ (+ (f-op4 15) (f-lbwl-h 0) lbwl-hi)
+ (set lr (add (add pc 4) (sll lbwl-hi 12)))
+)
+
+(dnti bl-lo "branch link, low offset"
+ ()
+ "bl-lo ${lbwl-lo}"
+ (+ (f-op4 15) (f-lbwl-h 1) lbwl-lo)
+ (sequence ((WI cur-pc))
+ (set cur-pc pc)
+ (set pc (add lr (sll lbwl-lo 1)))
+ (set lr (or (add cur-pc 2) 1)))
+)
diff --git a/cgen/types.scm b/cgen/types.scm
new file mode 100644
index 00000000000..dec4142e5af
--- /dev/null
+++ b/cgen/types.scm
@@ -0,0 +1,278 @@
+; Type system.
+; This provides the low level classes for describing data, except for
+; the actual type (confusingly enough) which is described in mode.scm.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Array type.
+; DIMENSIONS has a suitable initial value so (new <scalar>) to works.
+
+(define <array> (class-make '<array> nil '(mode (dimensions . ())) nil))
+
+; Return number of elements in array.
+
+(method-make!
+ <array> 'get-num-elms
+ (lambda (self)
+ (apply * (elm-get self 'dimensions)))
+)
+
+; Return mode of the array.
+
+(method-make! <array> 'get-mode (lambda (self) (elm-get self 'mode)))
+
+; Return the rank of the array (number of dimensions).
+
+(method-make! <array> 'get-rank (lambda (self) (length (elm-get self 'dimensions)))
+)
+
+; Return shape of array
+
+(method-make! <array> 'get-shape (lambda (self) (elm-get self 'dimensions))
+)
+
+; Return #t if X is an array.
+
+(define (array? x) (class-instance? <array> x))
+
+; Scalar type.
+
+(define <scalar> (class-make '<scalar> '(<array>) nil nil))
+
+(method-make-make! <scalar> '(mode))
+
+; Return #t if X is a scalar.
+
+(define (scalar? x) (and (array? x) (= (send x 'get-rank) 0)))
+
+; Return number of bits in an element of TYPE.
+
+(define (type-bits type)
+ (mode:bits (send type 'get-mode))
+)
+
+; Integers.
+; These are like scalars but are specified in bits.
+; BITS is the size in bits.
+; ATTRS contains !UNSIGNED [or nothing] or UNSIGNED.
+;
+; A mode is needed so we know how big a field is needed to record the value.
+; It might be more appropriate to use a host mode though.
+;
+; FIXME: Need to separate rank from type. scalar/array are not types.
+;
+;(define <integer> (class-make '<integer> nil '(attrs bits) nil))
+;
+;(method-make! <integer> 'get-atlist (lambda (self) (elm-get self 'attrs)))
+;
+;(method-make!
+; <integer> 'get-mode
+; (lambda (self)
+; (mode-find (elm-get self 'bits)
+; (if (has-attr? self 'UNSIGNED) 'UINT 'INT))
+; )
+;)
+;
+; FIXME: Quick hack. Revisit.
+;
+;(method-make! <integer> 'get-rank (lambda (self) 0))
+
+; Structures.
+; FIXME: Unfinished.
+
+(define <struct> (class-make '<struct> nil '(members) nil))
+
+; Parse a type spec.
+; TYPE-SPEC is: (mode [(dimensions ...)])
+; or: ((mode bits) [(dimensions ...)])
+
+(define (parse-type errtxt type-spec)
+ ; Preliminary error checking.
+ (if (and (list? (car type-spec))
+ (not (= (length (car type-spec)) 2)))
+ (parse-error errtxt "invalid type spec" type-spec))
+
+ ; Pick out the arguments.
+ (let ((mode (if (list? (car type-spec)) (caar type-spec) (car type-spec)))
+ (bits (if (list? (car type-spec)) (cadar type-spec) #f))
+ (dims (if (> (length type-spec) 1) (cadr type-spec) nil)))
+
+ ; FIXME: Need more error checking here.
+ ; Validate the mode and bits.
+ (let ((mode-obj
+ (case mode
+ ((INT)
+ (if (integer? bits)
+ (mode-make-int bits)
+ (parse-error errtxt "invalid number of bits" bits)))
+ ((UINT)
+ (if (integer? bits)
+ (mode-make-uint bits)
+ (parse-error errtxt "invalid number of bits" bits)))
+ ((BI QI HI SI DI WI UQI UHI USI UDI UWI SF DF XF TF)
+ (let ((x (parse-mode-name mode errtxt)))
+ (if (and bits (not (= bits (mode:bits x))))
+ (parse-error errtxt "wrong number of bits for mode" bits))
+ x))
+ (else (parse-error errtxt "unknown/unsupported mode" mode)))))
+
+ ; Validate the dimension spec.
+ (if (or (not (list? dims))
+ (not (all-true? (map integer? dims))))
+ (parse-error errtxt "invalid dimension spec" dims))
+
+ ; All done, create the <array> object.
+ ; ??? Special casing scalars is a concession for apps that think
+ ; scalars aren't arrays. Not sure it should stay.
+ (if (null? dims)
+ (make <scalar> mode-obj)
+ (make <array> mode-obj dims))))
+)
+
+; Bit ranges.
+; ??? Perhaps this should live in a different source file, but for now
+; it's here.
+;
+; Endianness is not recorded with the bitrange.
+; Values are operated on a "word" at a time.
+; This is to handle bi-endian systems: we don't want two copies of
+; every bitrange.
+;
+; Instruction word sizes are based on the "base insn length" which is the
+; number of bytes the cpu first looks at to decode an insn. In cases where
+; the total length is longer than the base insn length, the word length
+; for the rest of the insn is the base insn length replicated as many times
+; as necessary. The trailing part [last few bytes] of the insn may not fill
+; the entire word, in which case the numbering is adjusted for it.
+; ??? Might need to have an insn-base-length and an insn-word-length.
+;
+; Instructions that have words of one endianness and sub-words of a different
+; endianness are handled at a higher level.
+;
+; Bit numbering examples:
+; [each byte is represented MSB to LSB, low address to high address]
+;
+; lsb0? = #f
+; insn-word-length = 2
+; endian = little
+; | 8 ... 15 | 0 ... 7 | 24 ... 31 | 16 ... 23 | 40 ... 47 | 32 ... 39 |
+;
+; lsb0? = #t
+; insn-word-length = 2
+; endian = little
+; [note that this is the little endian canonical form
+; - word length is irrelevant]
+; | 7 ... 0 | 15 ... 8 | 23 ... 16 | 31 ... 24 | 39 ... 32 | 47 ... 40 |
+;
+; lsb0? = #f
+; insn-word-length = 2
+; endian = big
+; [note that this is the big endian canonical form
+; - word length is irrelevant]
+; | 0 ... 7 | 8 ... 15 | 16 ... 23 | 24 ... 31 | 32 ... 39 | 40 ... 47 |
+;
+; lsb0? = #t
+; insn-word-length = 2
+; endian = big
+; | 15 ... 8 | 7 ... 0 | 31 ... 24 | 23 ... 16 | 47 ... 40 | 39 ... 32 |
+;
+; While there are no current examples, the intent is to not preclude
+; situations where each "word" in an insn isn't the same size. For example a
+; 48 bit insn with a 16 bit opcode and a 32 bit immediate value might [but not
+; necessarily] consist of one 16 bit "word" and one 32 bit "word".
+; Bitranges support this situation, however none of the rest of the code does.
+;
+; Examples:
+;
+; lsb0? = #f
+; insn-word-length = 2, 4
+; endian = little
+; | 8 ... 15 | 0 ... 7 | 40 ... 47 | 32 ... 39 | 24 ... 31 | 16 ... 23 |
+;
+; lsb0? = #t
+; insn-word-length = 2, 4
+; endian = little
+; | 7 ... 0 | 15 ... 8 | 23 ... 16 | 31 ... 24 | 39 ... 32 | 47 ... 40 |
+;
+; lsb0? = #f
+; insn-word-length = 2, 4
+; endian = big
+; | 0 ... 7 | 8 ... 15 | 16 ... 23 | 24 ... 31 | 32 ... 39 | 40 ... 47 |
+;
+; lsb0? = #t
+; insn-word-length = 2, 4
+; endian = big
+; | 15 ... 8 | 7 ... 0 | 47 ... 40 | 39 ... 32 | 31 ... 24 | 23 ... 16 |
+
+(define <bitrange>
+ (class-make '<bitrange>
+ nil
+ '(
+ ; offset in bits from the start of the insn of the word
+ ; in which the value resides [must be divisible by 8]
+ ; [this allows the bitrange to be independent of the lengths
+ ; of words preceding this one]
+ word-offset
+ ; starting bit number within the word
+ ; [externally, = word-offset + start]
+ start
+ ; number of bits in the value
+ length
+ ; length of word in which the value resides
+ word-length
+ ; lsb = bit number 0?
+ lsb0?
+ )
+ nil)
+)
+
+; Accessor fns.
+
+(define-getters <bitrange> bitrange
+ (word-offset start length word-length lsb0?)
+)
+
+(define-setters <bitrange> bitrange
+ ; lsb0? left out on purpose: not sure changing it should be allowed
+ (word-offset start length word-length)
+)
+
+; Return a boolean indicating if two bitranges overlap.
+
+(define (bitrange-overlap? start1 length1 start2 length2 lsb0?)
+ ; ??? lsb0?
+ (let ((end1 (+ start1 length1))
+ (end2 (+ start2 length2)))
+ (not (or (<= end1 start2)
+ (>= start1 end2))))
+)
+
+; Return a boolean indicating if BITPOS is beyond bitrange START,LEN.
+; ??? This needs more thought.
+
+(define (bitpos-beyond? bitpos start length word-length lsb0?)
+ (>= bitpos (+ start length))
+)
+
+; Return the offset of the word after <bitrange> br.
+
+(define (bitrange-next-word br)
+ (let ((word-offset (bitrange-word-offset br))
+ (start (bitrange-start br))
+ (length (bitrange-length br))
+ (word-length (bitrange-word-length br))
+ (lsb0? (bitrange-lsb0? br)))
+ ; ??? revisit
+ (+ word-offset word-length))
+)
+
+; Initialize/finalize support.
+
+(define (types-init!)
+ *UNSPECIFIED*
+)
+
+(define (types-finish!)
+ *UNSPECIFIED*
+)
diff --git a/cgen/utils-cgen.scm b/cgen/utils-cgen.scm
new file mode 100644
index 00000000000..5d3f24cb76d
--- /dev/null
+++ b/cgen/utils-cgen.scm
@@ -0,0 +1,654 @@
+; CGEN Utilities.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+;
+; This file contains utilities specific to cgen.
+; Generic utilities should go in utils.scm.
+
+; True if text of sanitize markers are to be emitted.
+; This is a debugging tool only, though it could have use in sanitized trees.
+(define include-sanitize-marker? #t)
+
+; Utility to display command line invocation for debugging purposes.
+
+(define (display-argv argv)
+ (let ((cep (current-error-port)))
+ (display "cgen -s " cep)
+ (for-each (lambda (arg)
+ ; Output double-quotes if string has a space for better
+ ; correspondence to how to specify string to shell.
+ (if (string-index arg #\space)
+ (write arg cep)
+ (display arg cep))
+ (display " " cep))
+ argv)
+ (newline cep))
+)
+
+; COS utilities.
+; Perhaps these should be provided with cos (cgen-object-system), but for
+; now they live here.
+
+; Define the getter for a list of elements of a class.
+
+(defmacro define-getters (class class-prefix elm-names)
+ (cons 'begin
+ (map (lambda (elm-name)
+ (if (pair? elm-name)
+ `(define ,(symbol-append class-prefix '- (cdr elm-name))
+ (elm-make-getter ,class (quote ,(car elm-name))))
+ `(define ,(symbol-append class-prefix '- elm-name)
+ (elm-make-getter ,class (quote ,elm-name)))))
+ elm-names))
+)
+
+; Define the setter for a list of elements of a class.
+
+(defmacro define-setters (class class-prefix elm-names)
+ (cons 'begin
+ (map (lambda (elm-name)
+ (if (pair? elm-name)
+ `(define ,(symbol-append class-prefix '-set- (cdr elm-name) '!)
+ (elm-make-setter ,class (quote ,(car elm-name))))
+ `(define ,(symbol-append class-prefix '-set- elm-name '!)
+ (elm-make-setter ,class (quote ,elm-name)))))
+ elm-names))
+)
+
+; Make an object, specifying values for particular elements.
+; ??? Eventually move to cos.scm/cos.c.
+
+(define (vmake class . args)
+ (let ((obj (new class)))
+ (let ((unrecognized (send obj 'vmake! args)))
+ (if (null? unrecognized)
+ obj
+ (error "vmake: unknown options:" unrecognized))))
+)
+
+; Each named entry in the description file typically has these three members:
+; name, comment attrs.
+
+(define <ident> (class-make '<ident> () '(name comment attrs) ()))
+
+(method-make! <ident> 'get-name (lambda (self) (elm-get self 'name)))
+(method-make! <ident> 'get-comment (lambda (self) (elm-get self 'comment)))
+(method-make! <ident> 'get-atlist (lambda (self) (elm-get self 'attrs)))
+
+(method-make! <ident> 'set-name!
+ (lambda (self newval) (elm-set! self 'name newval)))
+(method-make! <ident> 'set-comment!
+ (lambda (self newval) (elm-set! self 'comment newval)))
+(method-make! <ident> 'set-atlist!
+ (lambda (self newval) (elm-set! self 'attrs newval)))
+
+; All objects defined in the .cpu file have these elements.
+; Where in the class hierarchy they're recorded depends on the object.
+; Additionally most objects have `name', `comment' and `attrs' elements.
+
+(define (obj:name obj) (send obj 'get-name))
+(define (obj-set-name! obj name) (send obj 'set-name! name))
+(define (obj:comment obj) (send obj 'get-comment))
+
+; Utility to add standard access methods for name, comment, attrs.
+; ??? Old. Using <ident> baseclass now.
+
+(define (add-ident-methods! class)
+ (method-make! class 'get-name (lambda (self) (elm-get self 'name)))
+ (method-make! class 'set-name! (lambda (self name) (elm-set! self 'name name)))
+
+ (method-make! class 'get-comment (lambda (self) (elm-get self 'comment)))
+ (method-make! class 'set-comment! (lambda (self comment) (elm-set! self 'comment comment)))
+
+ (method-make! class 'get-atlist (lambda (self) (elm-get self 'attrs)))
+ (method-make! class 'set-atlist! (lambda (self attrs) (elm-set! self 'attrs attrs)))
+
+ *UNSPECIFIED*
+)
+
+; Parsing utilities
+
+; Parsing context, used to give better error messages.
+
+(define <context>
+ (class-make '<context> nil
+ '(
+ ; Name of file containing object being processed.
+ (file . #f)
+ ; Line number in the file.
+ (lineno . #f)
+ ; Error message prefix
+ (prefix . "")
+ )
+ nil)
+)
+
+; Accessors.
+
+(define-getters <context> context (file lineno prefix))
+
+; Create a <context> object that is just a prefix.
+
+(define (context-make-prefix prefix)
+ (make <context> #f #f prefix)
+)
+
+; Create a <context> object for the reader.
+; This sets file,lineno from (current-input-port).
+
+(define (context-make-reader prefix)
+ (make <context>
+ (or (port-filename (current-input-port))
+ "<input>")
+ (port-line (current-input-port))
+ prefix)
+)
+
+; Call this to issue an error message.
+; CONTEXT is a <context> object or #f if there is none.
+; ARG is the value that had the error if there is one.
+
+(define (context-error context errmsg . arg)
+ (cond ((and context (context-file context))
+ (let ((msg (string-append
+ (context-file context) ":"
+ (number->string (context-lineno context)) ": "
+ (context-prefix context) ": "
+ errmsg ": ")))
+ (apply error (cons msg arg))))
+ (context (let ((msg (string-append (context-prefix context) ": "
+ errmsg ": ")))
+ (apply error (cons msg arg))))
+ (else (apply error (cons (string-append errmsg ": ") arg))))
+)
+
+; Parse an object name.
+; NAME is either a symbol or a list of symbols which are concatenated
+; together. Each element can in turn be a list of symbols, and so on.
+; This supports symbol concatenation in the description file without having
+; to using string-append or some such.
+; FIXME: Isn't the plan to move ERRTXT to the 1st arg?
+
+(define (parse-name name errtxt)
+ (cond ((list? name)
+ (string->symbol (string-map (lambda (elm) (parse-name elm errtxt)) name)))
+ ((symbol? name) name)
+ ((string? name) (string->symbol name))
+ (else (parse-error errtxt "improper name" name)))
+)
+
+; Parse an object comment.
+; COMMENT is either a string or a list of strings, each element of which may
+; in turn be a list of strings.
+; FIXME: Isn't the plan to move ERRTXT to the 1st arg?
+
+(define (parse-comment comment errtxt)
+ (cond ((list? comment)
+ (string-map (lambda (elm) (parse-comment elm errtxt)) comment))
+ ((or (string? comment) (symbol? comment))
+ comment)
+ (else (parse-error errtxt "improper comment" comment)))
+)
+
+; Parse a symbol.
+
+(define (parse-symbol context value)
+ (if (and (not (symbol? value)) (not (string? value)))
+ (parse-error context "not a symbol" value))
+ value
+)
+
+; Parse a string.
+
+(define (parse-string context value)
+ (if (and (not (symbol? value)) (not (string? value)))
+ (parse-error context "not a string" value))
+ value
+)
+
+; Parse a number.
+; VALID-VALUES is a list of numbers and (min . max) pairs.
+
+(define (parse-number errtxt value . valid-values)
+ (if (not (number? value))
+ (parse-error errtxt "not a number" value))
+ (if (any-true? (map (lambda (test)
+ (if (pair? test)
+ (and (>= value (car test))
+ (<= value (cdr test)))
+ (= value test)))
+ valid-values))
+ value
+ (parse-error errtxt "invalid number" value valid-values))
+)
+
+; Parse a boolean value
+
+(define (parse-boolean context value)
+ (if (boolean? value)
+ value
+ (parse-error context "not a boolean (#f/#t)" value))
+)
+
+; Parse a list of handlers.
+; Each entry is (symbol "string").
+; These map function to a handler for it.
+; The meaning is up to the application but generally the handler is a
+; C/C++ function name.
+; ALLOWED is a list valid values for the symbol or #f if anything is allowed.
+; The result is handlers unchanged.
+
+(define (parse-handlers context allowed handlers)
+ (if (not (list? handlers))
+ (parse-error context "bad handler spec" handlers))
+ (for-each (lambda (arg)
+ (if (not (list-elements-ok? arg (list symbol? string?)))
+ (parse-error context "bad handler spec" arg))
+ (if (and allowed (not (memq (car arg) allowed)))
+ (parse-error context "unknown handler type" (car arg))))
+ handlers)
+ handlers
+)
+
+; Return a boolean indicating if X is a keyword.
+; This also handles symbols named :foo because Guile doesn't stablely support
+; :keywords (how does one enable :keywords? read-options doesn't appear to
+; work).
+
+(define (keyword-list? x)
+ (and (list? x)
+ (not (null? x))
+ (or (keyword? (car x))
+ (and (symbol? (car x))
+ (char=? (string-ref (car x) 0) #\:))))
+)
+
+; Convert a list like (#:key1 val1 #:key2 val2 ...) to
+; ((#:key1 val1) (#:key2 val2) ...).
+; Missing values are specified with an empty list.
+; This also supports (:sym1 val1 ...) because Guile doesn't stablely support
+; :keywords (#:keywords work, but #:foo shouldn't appear in the description
+; language).
+
+(define (keyword-list->arg-list kl)
+ ; Scan KL backwards, building up each element as we go.
+ (let loop ((result nil) (current nil) (rkl (reverse kl)))
+ (cond ((null? rkl)
+ result)
+ ((keyword? (car rkl))
+ (loop (acons (keyword->symbol (car rkl)) current result)
+ nil
+ (cdr rkl)))
+ ((and (symbol? (car rkl))
+ (char=? (string-ref (car rkl) 0) #\:))
+ (loop (acons (string->symbol
+ (substring (car rkl) 1 (string-length (car rkl))))
+ current result)
+ nil
+ (cdr rkl)))
+ (else
+ (loop result
+ (cons (car rkl) current)
+ (cdr rkl)))))
+)
+
+; Signal an error if the argument name is not a symbol.
+; This is done by each of the argument validation routines so the caller
+; doesn't need to make two calls.
+
+(define (arg-list-validate-name errtxt arg-spec)
+ (if (null? arg-spec)
+ (parse-error errtxt "empty argument spec"))
+ (if (not (symbol? (car arg-spec)))
+ (parse-error errtxt "argument name not a symbol" arg-spec))
+ *UNSPECIFIED*
+)
+
+; Signal a parse error if an argument was specified with a value.
+; ARG-SPEC is (name value).
+
+(define (arg-list-check-no-args errtxt arg-spec)
+ (arg-list-validate-name errtxt arg-spec)
+ (if (not (null? (cdr arg-spec)))
+ (parse-error errtxt (string-append (car arg-spec)
+ " takes zero arguments")))
+ *UNSPECIFIED*
+)
+
+; Validate and return a symbol argument.
+; ARG-SPEC is (name value).
+
+(define (arg-list-symbol-arg errtxt arg-spec)
+ (arg-list-validate-name errtxt arg-spec)
+ (if (or (!= (length (cdr arg-spec)) 1)
+ (not (symbol? (cadr arg-spec))))
+ (parse-error errtxt (string-append (car arg-spec)
+ ": argument not a symbol")))
+ (cadr arg-spec)
+)
+
+; Sanitization
+
+; Sanitization is handled via attributes. Anything that must be sanitized
+; has a `sanitize' attribute with the value being the keyword to sanitize on.
+; Ideally most, if not all, of the guts of the generated sanitization is here.
+
+; Utility to simplify expression in .cpu file.
+; Usage: (sanitize keyword entry-type entry-name1 [entry-name2 ...])
+; Enum attribute `(sanitize keyword)' is added to the entry.
+; It's written this way so Hobbit can handle it.
+
+(define (sanitize keyword entry-type . entry-names)
+ (for-each (lambda (entry-name)
+ (let ((entry #f))
+ (case entry-type
+ ((attr) (set! entry (current-attr-lookup entry-name)))
+ ((enum) (set! entry (current-enum-lookup entry-name)))
+ ((isa) (set! entry (current-isa-lookup entry-name)))
+ ((cpu) (set! entry (current-cpu-lookup entry-name)))
+ ((mach) (set! entry (current-mach-lookup entry-name)))
+ ((model) (set! entry (current-model-lookup entry-name)))
+ ((ifield) (set! entry (current-ifld-lookup entry-name)))
+ ((hardware) (set! entry (current-hw-lookup entry-name)))
+ ((operand) (set! entry (current-op-lookup entry-name)))
+ ((insn) (set! entry (current-insn-lookup entry-name)))
+ ((macro-insn) (set! entry (current-minsn-lookup entry-name)))
+ (else (parse-error "sanitize" "unknown entry type" entry-type)))
+
+ ; ENTRY is #f in the case where the element was discarded
+ ; because its mach wasn't selected. But in the case where
+ ; we're keeping everything, ensure ENTRY is not #f to
+ ; catch spelling errors.
+
+ (if entry
+
+ (begin
+ (obj-cons-attr! entry (enum-attr-make 'sanitize keyword))
+ ; Propagate the sanitize attribute to class members
+ ; as necessary.
+ (case entry-type
+ ((hardware)
+ (if (hw-indices entry)
+ (obj-cons-attr! (hw-indices entry)
+ (enum-attr-make 'sanitize
+ keyword)))
+ (if (hw-values entry)
+ (obj-cons-attr! (hw-values entry)
+ (enum-attr-make 'sanitize
+ keyword))))
+ ))
+
+ (if (and (eq? APPLICATION 'OPCODES) (keep-all?))
+ (parse-error "sanitize"
+ (string-append "unknown " entry-type)
+ entry-name)))))
+ entry-names)
+
+ #f ; caller eval's our result, so return a no-op
+)
+
+; Return TEXT sanitized with KEYWORD.
+; TEXT must exist on a line (or lines) by itself.
+; i.e. it is assumed that it begins at column 1 and ends with a newline.
+; If KEYWORD is #f, no sanitization is generated.
+
+(define (gen-sanitize keyword text)
+ (cond ((null? text) "")
+ ((pair? text) ; pair? -> cheap list?
+ (if (and keyword include-sanitize-marker?)
+ (string-list
+ ; split string to avoid removal
+ "/* start-"
+ "sanitize-" keyword " */\n"
+ text
+ "/* end-"
+ "sanitize-" keyword " */\n")
+ text))
+ (else
+ (if (= (string-length text) 0)
+ ""
+ (if (and keyword include-sanitize-marker?)
+ (string-append
+ ; split string to avoid removal
+ "/* start-"
+ "sanitize-" keyword " */\n"
+ text
+ "/* end-"
+ "sanitize-" keyword " */\n")
+ text))))
+)
+
+; Return TEXT sanitized with OBJ's sanitization, if it has any.
+; OBJ may be #f.
+
+(define (gen-obj-sanitize obj text)
+ (if obj
+ (let ((san (obj-attr-value obj 'sanitize)))
+ (gen-sanitize (if (or (not san) (eq? san 'none)) #f san)
+ text))
+ (gen-sanitize #f text))
+)
+
+; Cover procs to handle generation of object declarations and definitions.
+; All object output should be routed through gen-decl and gen-defn.
+
+; Send the gen-decl message to OBJ, and sanitize the output if necessary.
+
+(define (gen-decl obj)
+ (logit 3 "Generating decl for "
+ (cond ((method-present? obj 'get-name) (send obj 'get-name))
+ ((elm-present? obj 'name) (elm-get obj 'name))
+ (else "unknown"))
+ " ...\n")
+ (cond ((and (method-present? obj 'gen-decl) (not (has-attr? obj 'META)))
+ (gen-obj-sanitize obj (send obj 'gen-decl)))
+ (else ""))
+)
+
+; Send the gen-defn message to OBJ, and sanitize the output if necessary.
+
+(define (gen-defn obj)
+ (logit 3 "Generating defn for "
+ (cond ((method-present? obj 'get-name) (send obj 'get-name))
+ ((elm-present? obj 'name) (elm-xget obj 'name))
+ (else "unknown"))
+ " ...\n")
+ (cond ((and (method-present? obj 'gen-defn) (not (has-attr? obj 'META)))
+ (gen-obj-sanitize obj (send obj 'gen-defn)))
+ (else ""))
+)
+
+; Attributes
+
+; Return C code to declare an enum of attributes ATTRS.
+; PREFIX is one of "cgen_ifld", "cgen_hw", "cgen_operand", "cgen_insn".
+; ATTRS is an alist of attribute values. The value is unimportant except that
+; it is used to determine bool/non-bool.
+; Non-bools need to be separated from bools as they're each recorded
+; differently. Non-bools are recorded in an int for each. All bools are
+; combined into one int to save space.
+; ??? We assume there is at least one bool.
+
+(define (gen-attr-enum-decl prefix attrs)
+ (string-append
+ (gen-enum-decl (string-append prefix "_attr")
+ (string-append prefix " attrs")
+ (string-append prefix "_")
+ (attr-list-enum-list attrs))
+ "/* Number of non-boolean elements in " prefix "_attr. */\n"
+ "#define " (string-upcase prefix) "_NBOOL_ATTRS "
+ "(" (string-upcase prefix) "_END_NBOOLS - "
+ (string-upcase prefix) "_START_NBOOLS - 1)\n"
+ "\n")
+)
+
+; Return name of symbol ATTR-NAME.
+; PREFIX is the prefix arg to gen-attr-enum-decl.
+
+(define (gen-attr-name prefix attr-name)
+ (string-upcase (gen-c-symbol (string-append prefix "_" attr-name)))
+)
+
+; Normal gen-mask argument to gen-bool-attrs.
+; Returns "(1<< PREFIX_NAME)" where PREFIX is from atlist-prefix and
+; NAME is the name of the attribute.
+; ??? This used to return PREFIX_NAME-CGEN_ATTR_BOOL_OFFSET.
+; The tradeoff is simplicity vs perceived maximum number of boolean attributes
+; needed. In the end the maximum number needn't be fixed, and the simplicity
+; of the current way is good.
+
+(define (gen-attr-mask prefix name)
+ (string-append "(1<<" (gen-attr-name prefix name) ")")
+)
+
+; Return C expression of bitmasks of boolean attributes in ATTRS.
+; ATTRS is an <attr-list> object, it need not be pre-sorted.
+; GEN-MASK is a procedure that returns the C code of the mask.
+
+(define (gen-bool-attrs attrs gen-mask)
+ (let loop ((result "0")
+ (alist (attr-remove-meta-attrs-alist
+ (attr-nub (atlist-attrs attrs)))))
+ (cond ((null? alist) result)
+ ((and (boolean? (cdar alist)) (cdar alist))
+ (loop (string-append result
+ ; `|' is used here instead of `+' so we don't
+ ; have to care about duplicates.
+ "|" (gen-mask (atlist-prefix attrs)
+ (caar alist)))
+ (cdr alist)))
+ (else (loop result (cdr alist)))))
+)
+
+; Return the C definition of OBJ's attributes.
+; TYPE is one of 'ifld, 'hw, 'operand, 'insn.
+; [Other objects have attributes but these are the only ones we currently
+; emit definitions for.]
+; OBJ is any object that supports the 'get-atlist message.
+; ALL-ATTRS is an ordered alist of all attributes.
+; "ordered" means all the non-boolean attributes are at the front and
+; duplicate entries have been removed.
+; GEN-MASK is the gen-mask arg to gen-bool-attrs.
+
+(define (gen-obj-attr-defn type obj all-attrs num-non-bools gen-mask)
+ (let* ((attrs (obj-atlist obj))
+ (non-bools (attr-non-bool-attrs (atlist-attrs attrs)))
+ (all-non-bools (list-take num-non-bools all-attrs)))
+ (string-append
+ "{ "
+ (gen-bool-attrs attrs gen-mask)
+ ", {"
+ ; For the boolean case, we can (currently) get away with only specifying
+ ; the attributes that are used since they all fit in one int and the
+ ; default is currently always #f (and won't be changed without good
+ ; reason). In the non-boolean case order is important since each value
+ ; has a specific spot in an array, all of them must be specified.
+ (if (null? all-non-bools)
+ " 0"
+ (string-drop1 ; drop the leading ","
+ (string-map (lambda (attr)
+ (let ((val (or (assq-ref non-bools (obj:name attr))
+ (attr-default attr))))
+ ; FIXME: Are we missing attr-prefix here?
+ (string-append ", "
+ (send attr 'gen-value-for-defn val))))
+ all-non-bools)))
+ " } }"
+ ))
+)
+
+; Return a boolean indicating if ATLIST indicates a CTI insn.
+
+(define (atlist-cti? atlist)
+ (or (atlist-has-attr? atlist 'UNCOND-CTI)
+ (atlist-has-attr? atlist 'COND-CTI))
+)
+
+; Misc. gen-* procs
+
+; Return name of obj as a C symbol.
+
+(define (gen-sym obj) (gen-c-symbol (obj:name obj)))
+
+; Return the name of the selected cpu family.
+; An error is signalled if more than one has been selected.
+
+(define (gen-cpu-name)
+ ; FIXME: error checking
+ (gen-sym (current-cpu))
+)
+
+; Return HAVE_CPU_<CPU>.
+
+(define (gen-have-cpu cpu)
+ (string-append "HAVE_CPU_"
+ (string-upcase (gen-sym cpu)))
+)
+
+; Return the bfd mach name for MACH.
+
+(define (gen-mach-bfd-name mach)
+ (string-append "bfd_mach_" (gen-c-symbol (mach-bfd-name mach)))
+)
+
+; Return definition of C macro to get the value of SYM.
+
+(define (gen-get-macro sym index-args expr)
+ (string-append
+ "#define GET_" (string-upcase sym) "(" index-args ") " expr "\n")
+)
+
+; Return definition of C macro to set the value of SYM.
+
+(define (gen-set-macro sym index-args lvalue)
+ (string-append
+ "#define SET_" (string-upcase sym)
+ "(" index-args
+ (if (equal? index-args "") "" ", ")
+ "x) (" lvalue " = (x))\n")
+)
+
+; Return definition of C macro to set the value of SYM, version 2.
+; EXPR is one or more C statements *without* proper \newline handling,
+; we prepend \ to each line.
+
+(define (gen-set-macro2 sym index-args newval-arg expr)
+ (string-append
+ "#define SET_" (string-upcase sym)
+ "(" index-args
+ (if (equal? index-args "") "" ", ")
+ newval-arg ") \\\n"
+ "do { \\\n"
+ (backslash "\n" expr)
+ ";} while (0)\n")
+)
+
+; Return C code to fetch a value from instruction memory.
+; PC-VAR is the C expression containing the address of the start of the
+; instruction.
+; ??? Aligned/unaligned support?
+
+(define (gen-ifetch pc-var bitoffset bitsize)
+ (string-append "GETIMEM"
+ (case bitsize
+ ((8) "UQI")
+ ((16) "UHI")
+ ((32) "USI")
+ (else (error "bad bitsize argument to gen-ifetch" bitsize)))
+ " (current_cpu, "
+ pc-var " + " (number->string (quotient bitoffset 8))
+ ")")
+)
+
+; Called before loading the .cpu file to initialize.
+
+(define (utils-init!)
+ (reader-add-command! 'sanitize
+ "\
+Mark an entry as being sanitized.
+"
+ nil '(keyword entry-type . entry-names) sanitize)
+
+ *UNSPECIFIED*
+)
diff --git a/cgen/utils-gen.scm b/cgen/utils-gen.scm
new file mode 100644
index 00000000000..b96c0efe959
--- /dev/null
+++ b/cgen/utils-gen.scm
@@ -0,0 +1,506 @@
+; Application independent utilities for C/C++ code generation.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; Attributes.
+
+(define (attr-bool-gen-decl attr) "")
+
+(define (attr-bool-gen-defn attr) "")
+
+(define (attr-int-gen-decl attr) "")
+
+(define (attr-int-gen-defn attr) "")
+
+(define (attr-gen-decl attr)
+ (gen-enum-decl (symbol-append (obj:name attr) '-attr)
+ (obj:comment attr)
+ (string-append (obj:name attr) "_")
+ (attr-values attr))
+)
+
+(define (attr-gen-defn attr)
+ (string-append
+ "static const CGEN_ATTR_ENTRY "
+ (gen-sym attr) "_attr"
+ "[] =\n{\n"
+ (string-map (lambda (elm)
+ (let* ((san (and (pair? elm) (pair? (cdr elm))
+ (attr-value (cddr elm) 'sanitize #f))))
+ (gen-sanitize
+ (if (and san (not (eq? san 'none)))
+ san
+ #f)
+ (string-append " { "
+ "\""
+ (gen-c-symbol (car elm))
+ "\", "
+ (string-upcase (gen-sym attr))
+ "_"
+ (string-upcase (gen-c-symbol (car elm)))
+ " },\n"))))
+ (attr-values attr))
+ " { 0, 0 }\n"
+ "};\n\n")
+)
+
+(method-make! <boolean-attribute> 'gen-decl attr-bool-gen-decl)
+(method-make! <bitset-attribute> 'gen-decl attr-gen-decl)
+(method-make! <integer-attribute> 'gen-decl attr-int-gen-decl)
+(method-make! <enum-attribute> 'gen-decl attr-gen-decl)
+
+(method-make! <boolean-attribute> 'gen-defn attr-bool-gen-defn)
+(method-make! <bitset-attribute> 'gen-defn attr-gen-defn)
+(method-make! <integer-attribute> 'gen-defn attr-int-gen-defn)
+(method-make! <enum-attribute> 'gen-defn attr-gen-defn)
+
+; Ifield extraction utilities.
+
+; Return the C data type to use to hold an extracted and decoded
+; <ifield> from an insn. Usually this is just an int, but for register
+; numbers or large unsigned immediates, an unsigned int may be preferable.
+; Then there's floats (??? which aren't handled yet).
+
+(define (gen-ifld-type f)
+ (mode:c-type (ifld-decode-mode f))
+)
+
+; Return C declaration of variable(s) to hold <ifield> F.
+; MACRO? is #t if the result is part of a macro.
+
+(define (gen-ifld-extract-decl f indent macro?)
+ (string-append indent (gen-ifld-type f) " " (gen-sym f) ";"
+ (if macro? " \\\n" "\n"))
+)
+
+; Return C code to extract a field from the base part of an insn.
+;
+; TOTAL-LENGTH is the total length of the value in VAL.
+; BASE-VALUE is a C expression (string) containing the base part of the insn.
+
+(define (-gen-ifld-extract-base f total-length base-value)
+ (let ((extraction
+ (string-append "EXTRACT_"
+ (if (current-arch-insn-lsb0?) "LSB0_" "MSB0_")
+ (case (mode:class (ifld-mode f))
+ ((INT) "INT")
+ ((UINT) "UINT")
+ (else (error "unsupported mode class"
+ (mode:class (ifld-mode f)))))
+ " ("
+ base-value ", "
+ (number->string total-length) ", "
+ ; ??? Is passing total-length right here?
+ (number->string (ifld-start f total-length)) ", "
+ (number->string (ifld-length f))
+ ")"))
+ (decode (ifld-decode f)))
+ ; If the field doesn't have a special decode expression,
+ ; just return the raw extracted value. Otherwise, emit
+ ; the expression.
+ (if (not decode)
+ extraction
+ ; cadr: fetches expression to be evaluated
+ ; caar: fetches symbol in arglist
+ ; cadar: fetches `pc' symbol in arglist
+ (rtl-c VOID (cadr decode)
+ (list (list (caar decode) 'UINT extraction)
+ (list (cadar decode) 'IAI "pc"))
+ #:rtl-cover-fns? #f #:ifield-var? #t)))
+)
+
+; Subroutine of -gen-ifld-extract-beyond to extract the relevant value
+; from WORD-NAME and move it into place.
+
+(define (-gen-extract-word word-name word-start word-length start length
+ unsigned? lsb0?)
+ ; ??? lsb0?
+ (let ((word-end (+ word-start word-length))
+ (end (+ start length)))
+ (string-append "("
+ "EXTRACT_"
+ (if (current-arch-insn-lsb0?) "LSB0" "MSB0")
+ (if (and (not unsigned?)
+ ; Only want sign extension for word with sign bit.
+ (bitrange-overlap? start 1 word-start word-length
+ lsb0?))
+ "_INT ("
+ "_UINT (")
+ word-name
+ ", "
+ (number->string word-length)
+ ", "
+ (number->string (if (< start word-start)
+ 0
+ (- start word-start)))
+ ", "
+ (number->string (if (< end word-end)
+ (- word-end end)
+ word-length))
+ ") << "
+ (number->string (if (> end word-end)
+ (- end word-end)
+ 0))
+ ")"))
+)
+
+; Return C code to extract a field that extends beyond the base insn.
+;
+; Things get tricky in the non-integral-insn case (no kidding).
+; This case includes every architecture with at least one insn larger
+; than 32 bits, and all architectures where insns smaller than 32 bits
+; can't be interpreted as an int.
+; ??? And maybe other architectures not considered yet.
+; We want to handle these reasonably fast as this includes architectures like
+; the ARC and I960 where 99% of the insns are 32 bits, with a few insns that
+; take a 32 bit immediate. It would be a real shame to unnecessarily slow down
+; handling of 99% of the instruction set just for a few insns. Fortunately
+; for these chips base-insn includes these insns, so things fall out naturally.
+;
+; BASE-LENGTH is base-insn-bitsize.
+; TOTAL-LENGTH is the total length of the insn.
+; VAR-LIST is a list of variables containing the insn.
+; Each element in VAR-LIST is (name start length).
+; The contents of the insn are in several variables: insn, word_[123...],
+; where `insn' contains the "base insn" and `word_N' is a set of variables
+; recording the rest of the insn, 32 bits at a time (with the last one
+; containing whatever is left over).
+
+(define (-gen-ifld-extract-beyond f base-length total-length var-list)
+ ; First compute the list of variables that contains pieces of the
+ ; desired value.
+ (let ((start (+ (ifld-start f total-length) (ifld-word-offset f)))
+ (length (ifld-length f))
+ ;(word-start (ifld-word-offset f))
+ ;(word-length (ifld-word-length f))
+ ; extraction code
+ (extraction #f)
+ ; extra processing to perform on extracted value
+ (decode (ifld-decode f))
+ (lsb0? (current-arch-insn-lsb0?)))
+ ; Find which vars are needed and move the value into place.
+ (let loop ((var-list var-list) (result (list ")")))
+ (if (null? var-list)
+ (set! extraction (apply string-append (cons "(0" result)))
+ (let ((var-name (caar var-list))
+ (var-start (cadar var-list))
+ (var-length (caddar var-list)))
+ (if (bitrange-overlap? start length
+ var-start var-length
+ lsb0?)
+ (loop (cdr var-list)
+ (cons "|"
+ (cons (-gen-extract-word var-name
+ var-start
+ var-length
+ start length
+ (eq? (mode:class (ifld-mode f))
+ 'UINT)
+ lsb0?)
+ result)))
+ (loop (cdr var-list) result)))))
+ ; If the field doesn't have a special decode expression, just return the
+ ; raw extracted value. Otherwise, emit the expression.
+ (if (not decode)
+ extraction
+ ; cadr: fetches expression to be evaluated
+ ; caar: fetches symbol in arglist
+ ; cadar: fetches `pc' symbol in arglist
+ (rtl-c VOID (cadr decode)
+ (list (list (caar decode) 'UINT extraction)
+ (list (cadar decode) 'IAI "pc"))
+ #:rtl-cover-fns? #f #:ifield-var? #t)))
+)
+
+; Return C code to extract <ifield> F.
+
+(define (gen-ifld-extract f indent base-length total-length base-value var-list macro?)
+ (string-append
+ indent
+ (gen-sym f)
+ " = "
+ (if (ifld-beyond-base? f base-length total-length)
+ (-gen-ifld-extract-beyond f base-length total-length var-list)
+ (-gen-ifld-extract-base f (min base-length total-length) base-value))
+ ";"
+ (if macro? " \\\n" "\n")
+ )
+)
+
+; Return C code to extract a <multi-ifield> from an insn.
+; This must have the same signature as gen-ifld-extract as both can be
+; made methods in application code.
+
+(define (gen-multi-ifld-extract f indent base-length total-length base-value var-list macro?)
+ ; The subfields must have already been extracted.
+ (let* ((extract (rtl-c VOID (multi-ifld-extract f) nil
+ #:rtl-cover-fns? #f #:ifield-var? #t))
+ (decode-proc (ifld-decode f))
+ (decode (if decode-proc
+ (rtl-c VOID (cadr decode-proc)
+ (list (list (caar decode-proc) 'UINT extract)
+ (list (cadar decode-proc) 'IAI "pc"))
+ #:rtl-cover-fns? #f #:ifield-var? #t)
+ extract)))
+ (if macro?
+ (backslash "\n" decode)
+ decode))
+)
+
+; Return C symbol of variable containing the extracted field value
+; in the extraction code. E.g. f_rd = EXTRACT_UINT (insn, ...).
+
+(define (gen-extracted-ifld-value f)
+ (gen-sym f)
+)
+
+; Subroutine of gen-extract-ifields to compute arguments for -extract-chunk
+; to extract values beyond the base insn.
+; This is also used by gen-define-ifields to know how many vars are needed.
+;
+; The result is a list of (offset . length) pairs.
+;
+; ??? Here's a case where explicitly defined instruction formats can
+; help - without them we can only use heuristics (which must evolve).
+; At least all the details are tucked away here.
+
+(define (-extract-chunk-specs base-length total-length alignment)
+ (let ((chunk-length
+ (case alignment
+ ; For the aligned and forced case split the insn up into base-insn
+ ; sized chunks. For the unaligned case, use a chunk-length of 32.
+ ; 32 was chosen because the values are extracted into portable ints.
+ ((aligned forced) (min base-length 32))
+ ((unaligned) 32)
+ (else (error "unknown alignment" alignment)))))
+ (let loop ((start base-length)
+ (remaining (- total-length base-length))
+ (result nil))
+ (if (<= remaining 0)
+ (reverse! result)
+ (loop (+ start chunk-length)
+ (- remaining chunk-length)
+ (cons (cons start (min chunk-length remaining))
+ result)))))
+)
+
+; Subroutine of gen-define-ifmt-ifields and gen-extract-ifmt-ifields to
+; insert the subfields of any multi-ifields present into IFLDS.
+; Subfields are inserted before their corresponding multi-ifield as they
+; are initialized in order.
+
+(define (-extract-insert-subfields iflds)
+ (let loop ((result nil) (iflds iflds))
+ (cond ((null? iflds)
+ (reverse! result))
+ ((multi-ifield? (car iflds))
+ (loop (cons (car iflds)
+ ; There's no real need to reverse the subfields here
+ ; other than to keep them in order.
+ (append (reverse (multi-ifld-subfields (car iflds)))
+ result))
+ (cdr iflds)))
+ (else
+ (loop (cons (car iflds) result) (cdr iflds)))))
+)
+
+; Return C code to define local vars to contain IFIELDS.
+; All insns using the result have the same TOTAL-LENGTH (in bits).
+; INDENT is a string prepended to each line.
+; MACRO? is #t if the code is part of a macro (and thus '\\' must be appended
+; to each line).
+
+(define (gen-define-ifields ifields total-length indent macro?)
+ (let* ((base-length (state-base-insn-bitsize))
+ (chunk-specs (-extract-chunk-specs base-length total-length
+ (current-arch-default-alignment))))
+ (string-list
+ (string-list-map (lambda (f)
+ (gen-ifld-extract-decl f indent macro?))
+ ifields)
+ ; Define enough ints to hold the trailing part of the insn,
+ ; N bits at a time.
+ ; ??? This could be more intelligent of course. Later.
+ ; ??? Making these global to us would allow filling them during
+ ; decoding.
+ (if (> total-length base-length)
+ (string-list
+ indent
+ "/* Contents of trailing part of insn. */"
+ (if macro? " \\\n" "\n")
+ (string-list-map (lambda (chunk-num)
+ (string-list indent
+ "UINT word_"
+ (number->string chunk-num)
+ (if macro? "; \\\n" ";\n")))
+ (iota 1 (length chunk-specs))))
+ "")))
+)
+
+; Return C code to define local vars to contain IFIELDS of <iformat> IFMT.
+; INDENT is a string prepended to each line.
+; MACRO? is #t if the code is part of a macro (and thus '\\' must be appended
+; to each line).
+; USE-MACRO? is #t if instead of generating the fields, we return the macro
+; that does that.
+
+(define (gen-define-ifmt-ifields ifmt indent macro? use-macro?)
+ (let ((macro-name (string-append
+ "EXTRACT_" (string-upcase (gen-sym ifmt))
+ "_VARS"))
+ (ifields (-extract-insert-subfields (ifmt-ifields ifmt))))
+ (if use-macro?
+ (string-list indent macro-name
+ " /*"
+ (string-list-map (lambda (fld)
+ (string-append " " (obj:name fld)))
+ ifields)
+ " */\n")
+ (let ((indent (if macro? (string-append indent " ") indent)))
+ (string-list
+ (if macro?
+ (string-list "#define " macro-name " \\\n")
+ (string-list indent "/* Instruction fields. */\n"))
+ (gen-define-ifields ifields (ifmt-length ifmt) indent macro?)
+ indent "unsigned int length;"
+ ; The last line doesn't have a trailing '\\'.
+ "\n"
+ ))))
+)
+
+; Subroutine of gen-extract-ifields to fetch one value into VAR-NAME.
+
+(define (-extract-chunk offset bits var-name macro?)
+ (string-append
+ " "
+ var-name
+ " = "
+ (gen-ifetch "pc" offset bits)
+ ";"
+ (if macro? " \\\n" "\n"))
+)
+
+; Subroutine of gen-extract-ifields to compute the var-list arg to
+; gen-ifld-extract-beyond.
+; The result is a list of `(name start length)' elements describing the
+; variables holding the parts of the insn.
+; CHUNK-SPECS is a list of (offset . length) pairs.
+
+(define (-gen-extract-beyond-var-list base-length var-prefix chunk-specs lsb0?)
+ ; ??? lsb0? support ok?
+ (cons (list "insn" 0 base-length)
+ (map (lambda (chunk-num chunk-spec)
+ (list (string-append var-prefix (number->string chunk-num))
+ (car chunk-spec)
+ (cdr chunk-spec)))
+ (iota 1 (length chunk-specs))
+ chunk-specs))
+)
+
+; Return C code to extract IFIELDS.
+; All insns using the result have the same TOTAL-LENGTH (in bits).
+; MACRO? is #t if the code is part of a macro (and thus '\\' must be appended
+; to each line).
+;
+; Here is where we handle integral-insn vs non-integeral-insn architectures.
+;
+; Examples of architectures that can be handled as integral-insns are:
+; sparc, m32r, mips, etc.
+;
+; Examples of architectures that can't be handled as integral insns are:
+; arc, i960, fr30, i386, m68k.
+; [i386,m68k are only mentioned for completeness. cgen ports of these
+; would be great, but more thought is needed first]
+;
+; C variable `insn' is assumed to contain the base part of the insn
+; (max base-insn-bitsize insn-bitsize). In the m32r case insn-bitsize
+; can be less than base-insn-bitsize.
+;
+; ??? Need to see how well gcc optimizes this.
+;
+; ??? Another way to do this is to put this code in an inline function that
+; gets passed pointers to each ifield variable. GCC is smart enough to
+; produce optimal code for this, but other compilers may not have inlining
+; or the indirection removal. I think the slowdown for a non-scache simulator
+; would be phenomenal and while one can say "too bad, use gcc", I'm defering
+; doing this for now.
+
+(define (gen-extract-ifields ifields total-length indent macro?)
+ (let* ((base-length (state-base-insn-bitsize))
+ (chunk-specs (-extract-chunk-specs base-length total-length
+ (current-arch-default-alignment))))
+ (string-list
+ ; If the insn has a trailing part, fetch it.
+ ; ??? Could have more intelligence here. Later.
+ (if (> total-length base-length)
+ (let ()
+ (string-list-map (lambda (chunk-spec chunk-num)
+ (-extract-chunk (car chunk-spec)
+ (cdr chunk-spec)
+ (string-append
+ "word_"
+ (number->string chunk-num))
+ macro?))
+ chunk-specs
+ (iota 1 (length chunk-specs))))
+ "")
+ (string-list-map
+ (lambda (f)
+ ; Dispatching on a method works better, as would a generic fn.
+ ; ??? Written this way to pass through Hobbit, doesn't handle
+ ; ((if foo a b) (arg1 arg2)).
+ (if (multi-ifield? f)
+ (gen-multi-ifld-extract
+ f indent base-length total-length "insn"
+ (-gen-extract-beyond-var-list base-length "word_"
+ chunk-specs
+ (current-arch-insn-lsb0?))
+ macro?)
+ (gen-ifld-extract
+ f indent base-length total-length "insn"
+ (-gen-extract-beyond-var-list base-length "word_"
+ chunk-specs
+ (current-arch-insn-lsb0?))
+ macro?)))
+ ifields)
+ ))
+)
+
+; Return C code to extract the fields of <iformat> IFMT.
+; MACRO? is #t if the code is part of a macro (and thus '\\' must be appended
+; to each line).
+; USE-MACRO? is #t if instead of generating the fields, we return the macro
+; that does that.
+
+(define (gen-extract-ifmt-ifields ifmt indent macro? use-macro?)
+ (let ((macro-name (string-append
+ "EXTRACT_" (string-upcase (gen-sym ifmt))
+ "_CODE"))
+ (ifields (-extract-insert-subfields (ifmt-ifields ifmt))))
+ (if use-macro?
+ (string-list indent macro-name "\n")
+ (let ((indent (if macro? (string-append indent " ") indent)))
+ (string-list
+ (if macro?
+ (string-list "#define " macro-name " \\\n")
+ "")
+ indent "length = "
+ (number->string (bits->bytes (ifmt-length ifmt)))
+ ";"
+ (if macro? " \\\n" "\n")
+ (gen-extract-ifields ifields (ifmt-length ifmt) indent macro?)
+ ; The last line doesn't have a trailing '\\'.
+ "\n"
+ ))))
+)
+
+; Instruction format utilities.
+
+(define (gen-sfmt-enum-decl sfmt-list)
+ (gen-enum-decl "@cpu@_sfmt_type"
+ "semantic formats in cpu family @cpu@"
+ "@CPU@_"
+ (map (lambda (sfmt) (cons (obj:name sfmt) nil))
+ sfmt-list))
+)
diff --git a/cgen/utils-sim.scm b/cgen/utils-sim.scm
new file mode 100644
index 00000000000..e0951adb07a
--- /dev/null
+++ b/cgen/utils-sim.scm
@@ -0,0 +1,955 @@
+; Generic simulator application utilities.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; The cache-addr? method.
+; Return #t if the hardware element's address is stored in the scache buffer.
+; This saves doing the index calculation during semantic processing.
+
+(method-make!
+ <hardware-base> 'cache-addr?
+ (lambda (self)
+ (and (with-scache?)
+ (has-attr? self 'CACHE-ADDR)))
+)
+
+(define (hw-cache-addr? hw) (send hw 'cache-addr?))
+
+; The needed-iflds method.
+; Return list of ifields needed during semantic execution by hardware element
+; SELF referenced by <operand> OP in <sformat> SFMT.
+
+(method-make!
+ <hardware-base> 'needed-iflds
+ (lambda (self op sfmt)
+ (list (op-ifield op)))
+)
+
+(method-make!
+ <hw-register> 'needed-iflds
+ (lambda (self op sfmt)
+ (list (op-ifield op)))
+; Instead of the following, we now arrange to store the ifield in the
+; argbuf, even for CACHE-ADDR operands. This way, the ifield values
+; (register numbers, etc.) remain available during semantics tracing.
+; (if (hw-cache-addr? self)
+; nil
+; (list (op-ifield op))))
+)
+
+; For addresses this is none because we make our own copy of the ifield
+; [because we want to use a special type].
+
+(method-make!
+ <hw-address> 'needed-iflds
+ (lambda (self op sfmt)
+ nil)
+)
+
+(define (hw-needed-iflds hw op sfmt) (send hw 'needed-iflds op sfmt))
+
+; Return a list of ifields of <operand> OP that must be recorded in ARGBUF
+; for <sformat> SFMT.
+; ??? At the moment there can only be at most one, but callers must not
+; assume this.
+
+(define (op-needed-iflds op sfmt)
+ (let ((indx (op:index op)))
+ (if (and (eq? (hw-index:type indx) 'ifield)
+ (not (= (ifld-length (hw-index:value indx)) 0)))
+ (hw-needed-iflds (op:type op) op sfmt)
+ nil))
+)
+
+; Operand extraction (ARGBUF) support code.
+;
+; Any operand that uses a non-empty ifield needs extraction support.
+; Normally we just record the ifield's value. However, in cases where
+; hardware elements have CACHE-ADDR specified or where the mode of the
+; hardware index isn't compatible with the mode of the decoded ifield
+; (this can happen for pc-relative instruction address), we need to record
+; something else.
+
+; Return a boolean indicating if <operand> OP needs any extraction processing.
+
+(define (op-extract? op)
+ (let* ((indx (op:index op))
+ (extract?
+ (if (derived-operand? op)
+ (any-true? (map op-extract? (derived-args op)))
+ (and (eq? (hw-index:type indx) 'ifield)
+ (not (= (ifld-length (hw-index:value indx)) 0))))))
+ (logit 4 "op-extract? op=" (obj:name op) " =>" extract? "\n")
+ extract?)
+)
+
+; Return a list of operands that need special extraction processing.
+; SFMT is an <sformat> object.
+
+(define (sfmt-extracted-operands sfmt)
+ (let ((in-ops (sfmt-in-ops sfmt))
+ (out-ops (sfmt-out-ops sfmt)))
+ (let ((ops (append (find op-extract? in-ops)
+ (find op-extract? out-ops))))
+ (nub ops obj:name)))
+)
+
+; Return a list of ifields that are needed by the semantic code.
+; SFMT is an <sformat> object.
+; ??? This redoes a lot of the calculation that sfmt-extracted-operands does.
+
+(define (sfmt-needed-iflds sfmt)
+ (let ((in-ops (sfmt-in-ops sfmt))
+ (out-ops (sfmt-out-ops sfmt)))
+ (let ((ops (append (find op-extract? in-ops)
+ (find op-extract? out-ops))))
+ (nub (apply append (map (lambda (op)
+ (op-needed-iflds op sfmt))
+ ops))
+ obj:name)))
+)
+
+; Sformat argument buffer.
+;
+; This contains the details needed to create an argument buffer `fields' union
+; entry for the containing sformats.
+
+(define <sformat-argbuf>
+ (class-make '<sformat-argbuf>
+ '(<ident>)
+ ; From <ident>:
+ ; - NAME is derived from one of the containing sformats.
+ '(
+ ; List of structure elements.
+ ; Each element is ("var name" "C type" bitsize).
+ ; The list is sorted by decreasing size, then C type,
+ ; then var name.
+ elms
+ )
+ nil)
+)
+
+(define-getters <sformat-argbuf> sbuf (sfmts elms))
+
+; Subroutine of -sfmt-contents to return an ifield element.
+; The result is ("var-name" "C-type" bitsize).
+
+(define (-sfmt-ifld-elm f sfmt)
+ (let ((real-mode (mode-real-mode (ifld-decode-mode f))))
+ (list (gen-sym f)
+ (mode:c-type real-mode)
+ (mode:bits real-mode)))
+)
+
+; sbuf-elm method.
+; The result is ("var-name" "C-type" approx-bitsize) or #f if unneeded.
+; For the default case we use the ifield as is, which is computed elsewhere.
+
+(method-make!
+ <hardware-base> 'sbuf-elm
+ (lambda (self op ifmt)
+ #f)
+)
+
+(method-make!
+ <hw-register> 'sbuf-elm
+ (lambda (self op ifmt)
+ (if (hw-cache-addr? self)
+ (list (gen-sym (op:index op))
+ (string-append (gen-type self) "*")
+ ; Use 64 bits for size. Doesn't really matter, just put them
+ ; near the front.
+ 64)
+ #f))
+)
+
+; We want to use ADDR/IADDR in ARGBUF for addresses
+
+(method-make!
+ <hw-address> 'sbuf-elm
+ (lambda (self op ifmt)
+ (list (gen-sym (op:index op))
+ "ADDR"
+ ; Use 64 bits for size. Doesn't really matter, just put them
+ ; near the front.
+ 64))
+)
+
+(method-make!
+ <hw-iaddress> 'sbuf-elm
+ (lambda (self op ifmt)
+ (list (gen-sym (op:index op))
+ "IADDR"
+ ; Use 64 bits for size. Doesn't really matter, just put them
+ ; near the front.
+ 64))
+)
+
+; Subroutine of -sfmt-contents to return an operand element.
+; These are in addition (or instead of) the actual ifields.
+; This is also used to compute definitions of local vars needed in the
+; !with-scache case.
+; The result is ("var-name" "C-type" approx-bitsize) or #f if unneeded.
+
+(define (sfmt-op-sbuf-elm op sfmt)
+ (send (op:type op) 'sbuf-elm op sfmt)
+)
+
+; Subroutine of compute-sformat-bufs! to compute list of structure elements
+; needed by <sformat> SFMT.
+; The result is
+; (SFMT ("var-name1" "C-type1" size1) ("var-name2" "C-type2" size2) ...)
+; and is sorted by decreasing size, then C type, then variable name
+; (as <sformat-argbuf> wants it).
+
+(define (-sfmt-contents sfmt)
+ (let ((needed-iflds (sfmt-needed-iflds sfmt))
+ (extracted-ops (sfmt-extracted-operands sfmt))
+ (in-ops (sfmt-in-ops sfmt))
+ (out-ops (sfmt-out-ops sfmt))
+ (sort-elms (lambda (a b)
+ ; Sort by descending size, then ascending C type, then
+ ; ascending name.
+ (cond ((> (caddr a) (caddr b))
+ #t)
+ ((= (caddr a) (caddr b))
+ (cond ((string<? (cadr a) (cadr b))
+ #t)
+ ((string=? (cadr a) (cadr b))
+ (string<? (car a) (car b)))
+ (else
+ #f)))
+ (else
+ #f))))
+ )
+ (cons sfmt
+ (sort
+ ; Compute list of all things we need to record at extraction time.
+ (find (lambda (x)
+ ; Discard #f entries, they indicate "unneeded".
+ x)
+ (append
+ (map (lambda (f)
+ (-sfmt-ifld-elm f sfmt))
+ needed-iflds)
+ (map (lambda (op)
+ (sfmt-op-sbuf-elm op sfmt))
+ extracted-ops)
+ (cond ((with-any-profile?)
+ (append
+ ; Profiling support. ??? This stuff is in flux.
+ (map (lambda (op)
+ (sfmt-op-profile-elm op sfmt #f))
+ (find op-profilable? in-ops))
+ (map (lambda (op)
+ (sfmt-op-profile-elm op sfmt #t))
+ (find op-profilable? out-ops))))
+ (else
+ (append)))))
+ sort-elms)))
+)
+
+; Return #t if ELM-LIST is a subset of SBUF.
+; SBUF is an <sformat-argbuf> object.
+
+(define (-sbuf-subset? elm-list sbuf)
+ ; We take advantage of the fact that elements in each are already sorted.
+ ; FIXME: Can speed up.
+ (let loop ((elm-list elm-list) (sbuf-elm-list (sbuf-elms sbuf)))
+ (cond ((null? elm-list)
+ #t)
+ ((null? sbuf-elm-list)
+ #f)
+ ((equal? (car elm-list) (car sbuf-elm-list))
+ (loop (cdr elm-list) (cdr sbuf-elm-list)))
+ (else
+ (loop elm-list (cdr sbuf-elm-list)))))
+)
+
+; Subroutine of compute-sformat-bufs!.
+; Lookup ELM-LIST in SBUF-LIST. A match is found if ELM-LIST
+; is a subset of one in SBUF-LIST.
+; Return the containing <sformat-argbuf> object if found, otherwise return #f.
+; SBUF-LIST is a list of <sformat-argbuf> objects.
+; ELM-LIST is (elm1 elm2 ...).
+
+(define (-sbuf-lookup elm-list sbuf-list)
+ (let loop ((sbuf-list sbuf-list))
+ (cond ((null? sbuf-list)
+ #f)
+ ((-sbuf-subset? elm-list (car sbuf-list))
+ (car sbuf-list))
+ (else
+ (loop (cdr sbuf-list)))))
+)
+
+; Compute and record the set of <sformat-argbuf> objects needed for SFMT-LIST,
+; a list of all sformats.
+; The result is the computed list of <sformat-argbuf> objects.
+;
+; This is used to further reduce the number of entries in the argument buffer's
+; `fields' union. Some sformats have structs with the same contents or one is
+; a subset of another's, thus there is no need to distinguish them as far as
+; the struct is concerned (there may be other reasons to distinguish them of
+; course).
+; The consequence of this is fewer semantic fragments created in with-sem-frags
+; pbb engines.
+
+(define (compute-sformat-argbufs! sfmt-list)
+ (logit 1 "Computing sformat argument buffers ...\n")
+
+ (let ((sfmt-contents
+ ; Sort by descending length. This helps building the result: while
+ ; iterating over each element, its sbuf is either a subset of a
+ ; previous entry or requires a new entry.
+ (sort (map -sfmt-contents sfmt-list)
+ (lambda (a b)
+ (> (length a) (length b)))))
+ ; Build an <sformat-argbuf> object.
+ (build-sbuf (lambda (sfmt-data)
+ (make <sformat-argbuf>
+ (obj:name (car sfmt-data))
+ ""
+ atlist-empty
+ (cdr sfmt-data))))
+ )
+ ; Start off with the first sfmt.
+ ; Also build an empty sbuf. Which sbuf to use for an empty argument list
+ ; is rather arbitrary. Rather than pick one, keep the empty sbuf unto
+ ; itself.
+ (let ((nub-sbufs (list (build-sbuf (car sfmt-contents))))
+ (empty-sbuf (make <sformat-argbuf>
+ 'fmt-empty "no operands" atlist-empty
+ nil))
+ )
+ (sfmt-set-sbuf! (caar sfmt-contents) (car nub-sbufs))
+
+ ; Now loop over the remaining sfmts.
+ (let loop ((sfmt-contents (cdr sfmt-contents)))
+ (if (not (null? sfmt-contents))
+ (let ((sfmt-data (car sfmt-contents)))
+ (if (null? (cdr sfmt-data))
+ (sfmt-set-sbuf! (car sfmt-data) empty-sbuf)
+ (let ((sbuf (-sbuf-lookup (cdr sfmt-data) nub-sbufs)))
+ (if (not sbuf)
+ (begin
+ (set! sbuf (build-sbuf sfmt-data))
+ (set! nub-sbufs (cons sbuf nub-sbufs))))
+ (sfmt-set-sbuf! (car sfmt-data) sbuf)))
+ (loop (cdr sfmt-contents)))))
+
+ ; Done.
+ ; Note that the result will be sorted by ascending number of elements
+ ; (because the search list was sorted by descending length and the result
+ ; is built up in reverse order of that).
+ ; Not that it matters, but that's kinda nice.
+ (cons empty-sbuf nub-sbufs)))
+)
+
+; Profiling support.
+
+; By default hardware elements are not profilable.
+
+(method-make! <hardware-base> 'profilable? (lambda (self) #f))
+
+(method-make!
+ <hw-register> 'profilable?
+ (lambda (self) (has-attr? self 'PROFILE))
+)
+
+; Return boolean indicating if HW is profilable.
+
+(define (hw-profilable? hw) (send hw 'profilable?))
+
+; Return a boolean indicating if OP is profilable.
+
+(define (op-profilable? op)
+ (hw-profilable? (op:type op))
+)
+
+; sbuf-profile-data method.
+; Return a list of C type and size to use in an sformat's argument buffer.
+
+(method-make!
+ <hardware-base> 'sbuf-profile-data
+ (lambda (self)
+ (error "sbuf-profile-elm not supported for this hw type"))
+)
+
+(method-make!
+ <hw-register> 'sbuf-profile-data
+ (lambda (self)
+ ; Don't unnecessarily bloat size of argument buffer.
+ (if (<= (hw-num-elms self) 255)
+ (list "unsigned char" 8)
+ (list "unsigned short" 16)))
+)
+
+; sbuf-profile-elm method.
+; Return the ARGBUF member needed for profiling SELF in <sformat> SFMT.
+; The result is (var-name "C-type" approx-bitsize) or #f if unneeded.
+
+(method-make!
+ <operand> 'sbuf-profile-elm
+ (lambda (self sfmt out?)
+ (if (hw-scalar? (op:type self))
+ #f
+ (cons (string-append (if out? "out_" "in_")
+ (gen-sym self))
+ (send (op:type self) 'sbuf-profile-data))))
+)
+
+; Subroutine of -sfmt-contents to return an operand's profile element.
+; The result is (var-name "C-type" approx-bitsize) or #f if unneeded.
+
+(define (sfmt-op-profile-elm op sfmt out?)
+ (send op 'sbuf-profile-elm sfmt out?)
+)
+
+; ARGBUF accessor support.
+
+; Define and undefine C macros to tuck away details of instruction format used
+; in the extraction and semantic code. Instruction format names can
+; change frequently and this can result in unnecessarily large diffs from one
+; generated version of the file to the next. Secondly, tucking away details of
+; the extracted argument structure from the extraction code is a good thing.
+
+; Name of macro to access fields in ARGBUF.
+(define c-argbuf-macro "FLD")
+
+(define (gen-define-argbuf-macro sfmt)
+ (string-append "#define " c-argbuf-macro "(f) "
+ "abuf->fields."
+ (gen-sym (sfmt-sbuf sfmt))
+ ".f\n")
+)
+
+(define (gen-undef-argbuf-macro sfmt)
+ (string-append "#undef " c-argbuf-macro "\n")
+)
+
+; For old code. Delete in time.
+(define gen-define-field-macro gen-define-argbuf-macro)
+(define gen-undef-field-macro gen-undef-argbuf-macro)
+
+; Return a C reference to an ARGBUF field value.
+
+(define (gen-argbuf-ref name)
+ (string-append c-argbuf-macro " (" name ")")
+)
+
+; Return name of ARGBUF member for extracted <field> F.
+
+(define (gen-ifld-argbuf-name f)
+ (gen-sym f)
+)
+
+; Return the C reference to a cached ifield.
+
+(define (gen-ifld-argbuf-ref f)
+ (gen-argbuf-ref (gen-ifld-argbuf-name f))
+)
+
+; Return name of ARGBUF member holding processed from of extracted
+; ifield value for <hw-index> index.
+
+(define (gen-hw-index-argbuf-name index)
+ (gen-sym index)
+)
+
+; Return C reference to a processed <hw-index> in ARGBUF.
+
+(define (gen-hw-index-argbuf-ref index)
+ (gen-argbuf-ref (gen-hw-index-argbuf-name index))
+)
+
+; Decode support.
+
+; Main procedure call tree:
+; cgen-decode.{c,cxx}
+; -gen-decode-fn
+; gen-decoder [our entry point]
+; decode-build-table
+; -gen-decoder-switch
+; -gen-decoder-switch
+;
+; decode-build-table is called to construct a tree of "table-guts" elements
+; (??? Need better name obviously),
+; and then gen-decoder is recursively called on each of these elements.
+
+; Return C/C++ code that fetches the desired decode bits from C value VAL.
+; SIZE is the size in bits of val (the MSB is 1 << (size - 1)) which we
+; treat as bitnum 0.
+; BITNUMS must be monotonically increasing.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; FIXME: START may not be handled right in words beyond first.
+;
+; e.g. (-gen-decode-bits '(0 1 2 3 8 9 10 11) 0 16 "insn" #f)
+; --> "(((insn >> 8) & 0xf0) | ((insn >> 4) & 0xf))"
+; FIXME: The generated code has some inefficiencies in edge cases. Later.
+
+(define (-gen-decode-bits bitnums start size val lsb0?)
+
+ ; Compute a list of lists of three numbers:
+ ; (first bitnum in group, position in result (0=LSB), bits in result)
+
+ (let ((groups
+ ; POS = starting bit position of current group.
+ ; COUNT = number of bits in group.
+ ; Work from least to most significant bit so reverse bitnums.
+ (let loop ((result nil) (pos 0) (count 0) (bitnums (reverse bitnums)))
+ ;(display (list result pos count bitnums)) (newline)
+ (if (null? bitnums)
+ result
+ (if (or (= (length bitnums) 1)
+ ; Are numbers not next to each other?
+ (not (= (- (car bitnums) (if lsb0? -1 1))
+ (cadr bitnums))))
+ (loop (cons (list (car bitnums) pos (+ 1 count))
+ result)
+ (+ pos count 1) 0
+ (cdr bitnums))
+ (loop result
+ pos (+ 1 count)
+ (cdr bitnums)))))))
+ (string-append
+ "("
+ (string-drop 3
+ (string-map
+ (lambda (group)
+ (let* ((first (car group))
+ (pos (cadr group))
+ (bits (caddr group))
+ ; Difference between where value is and where
+ ; it needs to be.
+ ; FIXME: Need to handle left (-ve) shift.
+ (shift (- (if lsb0?
+ (- first bits -1)
+ (- (+ start size) (+ first bits)))
+ pos)))
+ (string-append
+ " | ((" val " >> " (number->string shift)
+ ") & ("
+ (number->string (- (integer-expt 2 bits) 1))
+ " << " (number->string pos) "))")))
+ groups))
+ ")"))
+)
+
+; Convert decoder table into C code.
+
+; Return code for one insn entry.
+; REST is the remaining entries.
+
+(define (-gen-decode-insn-entry entry rest indent)
+ (assert (eq? 'insn (dtable-entry-type entry)))
+ (logit 3 "Generating decode insn entry for " (obj:name (dtable-entry-value entry)) " ...\n")
+
+ (let ((insn (dtable-entry-value entry)))
+
+ (cond
+
+ ; Leave invalids to the default case.
+ ((eq? (obj:name insn) 'x-invalid)
+ "")
+
+ ; If same contents as next case, fall through.
+ ; FIXME: Can reduce more by sorting cases. Much later.
+ ((and (not (null? rest))
+ ; Ensure both insns.
+ (eq? 'insn (dtable-entry-type (car rest)))
+ ; Ensure same insn.
+ (eq? (obj:name insn)
+ (obj:name (dtable-entry-value (car rest)))))
+ (string-append indent " case "
+ (number->string (dtable-entry-index entry))
+ " : /* fall through */\n"))
+
+ (else
+ (string-append indent " case "
+ (number->string (dtable-entry-index entry))
+ " : itype = "
+ (gen-cpu-insn-enum (current-cpu) insn)
+ "; "
+ (if (with-scache?)
+ (string-append "goto "
+ "extract_"
+ (gen-sym (insn-sfmt insn))
+ ";\n")
+ "goto done;\n")))))
+)
+
+; Subroutine of -decode-expr-ifield-tracking.
+; Return a list of all possible values for ifield IFLD-NAME.
+; FIXME: Quick-n-dirty implementation. Should use bit arrays.
+
+(define (-decode-expr-ifield-values ifld-name)
+ (let* ((ifld (current-ifld-lookup ifld-name))
+ (bits (ifld-length ifld)))
+ (if (mode-unsigned? (ifld-mode ifld))
+ (iota (logsll 1 bits))
+ (iota (- (logsll 1 (- bits 1))) (logsll 1 bits))))
+)
+
+; Subroutine of -decode-expr-ifield-tracking,-decode-expr-ifield-mark-used.
+; Create the search key for tracking table lookup.
+
+(define (-decode-expr-ifield-tracking-key insn ifld-name)
+ (symbol-append (obj:name (insn-ifmt insn)) '-x- ifld-name)
+)
+
+; Subroutine of -gen-decode-expr-entry.
+; Return a table to track used ifield values.
+; The table is an associative list of (key . value-list).
+; KEY is "iformat-name-x-ifield-name".
+; VALUE-LIST is a list of the unused values.
+
+(define (-decode-expr-ifield-tracking expr-list)
+ (let ((table1
+ (apply append
+ (map (lambda (entry)
+ (map (lambda (ifld-name)
+ (cons (exprtable-entry-insn entry)
+ (cons ifld-name
+ (-decode-expr-ifield-values ifld-name))))
+ (exprtable-entry-iflds entry)))
+ expr-list))))
+ ; TABLE1 is a list of (insn ifld-name value1 value2 ...).
+ (nub (map (lambda (elm)
+ (cons
+ (-decode-expr-ifield-tracking-key (car elm) (cadr elm))
+ (cddr elm)))
+ table1)
+ car))
+)
+
+; Subroutine of -decode-expr-ifield-mark-used!.
+; Return list of values completely used for ifield IFLD-NAME in EXPR.
+; "completely used" here means the value won't appear elsewhere.
+; e.g. in (andif (eq f-rd 15) (eq f-rx 14)) we don't know what happens
+; for the (ne f-rx 14) case.
+
+(define (-decode-expr-ifield-values-used ifld-name expr)
+ (case (rtx-name expr)
+ ((eq)
+ (if (and (rtx-kind? 'ifield (rtx-cmp-op-arg expr 0))
+ (rtx-constant? (rtx-cmp-op-arg expr 1)))
+ (list (rtx-constant-value (rtx-cmp-op-arg expr 1)))
+ nil))
+ ((member)
+ (if (rtx-kind? 'ifield (rtx-member-value expr))
+ (rtx-member-set expr)
+ nil))
+ ; FIXME: more needed
+ (else nil))
+)
+
+; Subroutine of -gen-decode-expr-entry.
+; Mark ifield values used by EXPR-ENTRY in TRACKING-TABLE.
+
+(define (-decode-expr-ifield-mark-used! tracking-table expr-entry)
+ (let ((insn (exprtable-entry-insn expr-entry))
+ (expr (exprtable-entry-expr expr-entry))
+ (ifld-names (exprtable-entry-iflds expr-entry)))
+ (for-each (lambda (ifld-name)
+ (let ((table-entry
+ (assq (-decode-expr-ifield-tracking-key insn ifld-name)
+ tracking-table))
+ (used (-decode-expr-ifield-values-used ifld-name expr)))
+ (for-each (lambda (value)
+ (delq! value table-entry))
+ used)
+ ))
+ ifld-names))
+ *UNSPECIFIED*
+)
+
+; Subroutine of -gen-decode-expr-entry.
+; Return code to set `itype' and branch to the extraction phase.
+
+(define (-gen-decode-expr-set-itype indent insn-enum fmt-name)
+ (string-append
+ indent
+ "{ itype = "
+ insn-enum
+ "; "
+ (if (with-scache?)
+ (string-append "goto "
+ "extract_"
+ fmt-name
+ ";")
+ "goto done;")
+ " }\n"
+ )
+)
+
+; Generate code to decode the expression table in ENTRY.
+; INVALID-INSN is the <insn> object of the pseudo insn to handle invalid ones.
+
+(define (-gen-decode-expr-entry entry indent invalid-insn)
+ (assert (eq? 'expr (dtable-entry-type entry)))
+ (logit 3 "Generating decode expr entry for " (exprtable-name (dtable-entry-value entry)) " ...\n")
+
+ (let ((expr-list (exprtable-insns (dtable-entry-value entry))))
+ (string-list
+ indent " case "
+ (number->string (dtable-entry-index entry))
+ " :\n"
+
+ (let ((iflds-tracking (-decode-expr-ifield-tracking expr-list))
+ (indent (string-append indent " ")))
+
+ (let loop ((expr-list expr-list) (code nil))
+
+ (if (null? expr-list)
+
+ ; All done. If we used up all field values we don't need to
+ ; "fall through" and select the invalid insn marker.
+
+ (if (all-true? (map null? (map cdr iflds-tracking)))
+ code
+ (append! code
+ (list
+ (-gen-decode-expr-set-itype
+ indent
+ (gen-cpu-insn-enum (current-cpu) invalid-insn)
+ "sfmt_empty"))))
+
+ ; Not all done, process next expr.
+
+ (let ((insn (exprtable-entry-insn (car expr-list)))
+ (expr (exprtable-entry-expr (car expr-list)))
+ (ifld-names (exprtable-entry-iflds (car expr-list))))
+
+ ; Mark of those ifield values we use first.
+ ; If there are none left afterwards, we can unconditionally
+ ; choose this insn.
+ (-decode-expr-ifield-mark-used! iflds-tracking (car expr-list))
+
+ (let ((next-code
+ ; If this is the last expression, and it uses up all
+ ; remaining ifield values, there's no need to perform any
+ ; test.
+ (if (and (null? (cdr expr-list))
+ (all-true? (map null? (map cdr iflds-tracking))))
+
+ ; Need this in a list for a later append!.
+ (string-list
+ (-gen-decode-expr-set-itype
+ indent
+ (gen-cpu-insn-enum (current-cpu) insn)
+ (gen-sym (insn-sfmt insn))))
+
+ ; We don't use up all ifield values, so emit a test.
+ (let ((iflds (map current-ifld-lookup ifld-names)))
+ (string-list
+ indent "{\n"
+ (gen-define-ifields iflds
+ (insn-length insn)
+ (string-append indent " ")
+ #f)
+ (gen-extract-ifields iflds
+ (insn-length insn)
+ (string-append indent " ")
+ #f)
+ indent " if ("
+ (rtl-c 'BI expr nil #:ifield-var? #t)
+ ")\n"
+ (-gen-decode-expr-set-itype
+ (string-append indent " ")
+ (gen-cpu-insn-enum (current-cpu) insn)
+ (gen-sym (insn-sfmt insn)))
+ indent "}\n")))))
+
+ (loop (cdr expr-list)
+ (append! code next-code)))))))
+ ))
+)
+
+; Generate code to decode TABLE.
+; REST is the remaining entries.
+; SWITCH-NUM, STARTBIT, DECODE-BITSIZE, INDENT, LSB0?, INVALID-INSN are same
+; as for -gen-decoder-switch.
+
+(define (-gen-decode-table-entry table rest switch-num startbit decode-bitsize indent lsb0? invalid-insn)
+ (assert (eq? 'table (dtable-entry-type table)))
+ (logit 3 "Generating decode table entry for case " (dtable-entry-index table) " ...\n")
+
+ (string-list
+ indent " case "
+ (number->string (dtable-entry-index table))
+ " :"
+ ; If table is same as next, just emit a "fall through" to cut down on
+ ; generated code.
+ (if (and (not (null? rest))
+ ; Ensure both tables.
+ (eq? 'table (dtable-entry-type (car rest)))
+ ; Ensure same table.
+ (eqv? (subdtable-key (dtable-entry-value table))
+ (subdtable-key (dtable-entry-value (car rest)))))
+ " /* fall through */\n"
+ (string-list
+ "\n"
+ (-gen-decoder-switch switch-num
+ startbit
+ decode-bitsize
+ (subdtable-table (dtable-entry-value table))
+ (string-append indent " ")
+ lsb0?
+ invalid-insn))))
+)
+
+; Subroutine of -decode-sort-entries.
+; Return a boolean indicating if A,B are equivalent entries.
+
+(define (-decode-equiv-entries? a b)
+ (let ((a-type (dtable-entry-type a))
+ (b-type (dtable-entry-type b)))
+ (if (eq? a-type b-type)
+ (case a-type
+ ((insn)
+ (let ((a-name (obj:name (dtable-entry-value a)))
+ (b-name (obj:name (dtable-entry-value b))))
+ (eq? a-name b-name)))
+ ((expr)
+ ; Ignore expr entries for now.
+ #f)
+ ((table)
+ (let ((a-name (subdtable-key (dtable-entry-value a)))
+ (b-name (subdtable-key (dtable-entry-value b))))
+ (eq? a-name b-name))))
+ ; A and B are not the same type.
+ #f))
+)
+
+; Subroutine of -gen-decoder-switch, sort ENTRIES according to desired
+; print order (maximizes amount of fall-throughs, but maintains numerical
+; order as much as possible).
+; ??? This is an O(n^2) algorithm. An O(n Log(n)) algorithm can be done
+; but it seemed more complicated than necessary for now.
+
+(define (-decode-sort-entries entries)
+ (let ((find-equiv!
+ ; Return list of entries in non-empty list L that have the same decode
+ ; entry as the first entry. Entries found are marked with #f so
+ ; they're not processed again.
+ (lambda (l)
+ ; Start off the result with the first entry, then see if the
+ ; remaining ones match it.
+ (let ((first (car l)))
+ (let loop ((l (cdr l)) (result (cons first nil)))
+ (if (null? l)
+ (reverse! result)
+ (if (and (car l) (-decode-equiv-entries? first (car l)))
+ (let ((lval (car l)))
+ (set-car! l #f)
+ (loop (cdr l) (cons lval result)))
+ (loop (cdr l) result)))))))
+ )
+ (let loop ((entries (list-copy entries)) (result nil))
+ (if (null? entries)
+ (apply append (reverse! result))
+ (if (car entries)
+ (loop (cdr entries)
+ (cons (find-equiv! entries)
+ result))
+ (loop (cdr entries) result)))))
+)
+
+; Generate switch statement to decode TABLE-GUTS.
+; SWITCH-NUM is for compatibility with the computed goto decoder and
+; isn't used.
+; STARTBIT is the bit offset of the instruction value that C variable `insn'
+; holds (note that this is independent of LSB0?).
+; DECODE-BITSIZE is the number of bits of the insn that `insn' holds.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; INVALID-INSN is the <insn> object of the pseudo insn to handle invalid ones.
+
+(define (-gen-decoder-switch switch-num startbit decode-bitsize table-guts indent lsb0? invalid-insn)
+ ; For entries that are a single insn, we're done, otherwise recurse.
+
+ (string-list
+ indent "{\n"
+ ; Are we at the next word?
+ (if (not (= startbit (dtable-guts-startbit table-guts)))
+ (begin
+ (set! startbit (dtable-guts-startbit table-guts))
+ (set! decode-bitsize (dtable-guts-bitsize table-guts))
+ ; FIXME: Bits may get fetched again during extraction.
+ (string-append indent " unsigned int val;\n"
+ indent " /* Must fetch more bits. */\n"
+ indent " insn = "
+ (gen-ifetch "pc" startbit decode-bitsize)
+ ";\n"
+ indent " val = "))
+ (string-append indent " unsigned int val = "))
+ (-gen-decode-bits (dtable-guts-bitnums table-guts)
+ (dtable-guts-startbit table-guts)
+ (dtable-guts-bitsize table-guts) "insn" lsb0?)
+ ";\n"
+ indent " switch (val)\n"
+ indent " {\n"
+
+ ; The code is more readable, and icache use is improved, if we collapse
+ ; common code into one case and use "fall throughs" for all but the last of
+ ; a set of common cases.
+ ; FIXME: We currently rely on -gen-decode-foo-entry to recognize the fall
+ ; through. We should take care of it ourselves.
+
+ (let loop ((entries (-decode-sort-entries (dtable-guts-entries table-guts)))
+ (result nil))
+ (if (null? entries)
+ (reverse! result)
+ (loop
+ (cdr entries)
+ (cons (case (dtable-entry-type (car entries))
+ ((insn)
+ (-gen-decode-insn-entry (car entries) (cdr entries) indent))
+ ((expr)
+ (-gen-decode-expr-entry (car entries) indent invalid-insn))
+ ((table)
+ (-gen-decode-table-entry (car entries) (cdr entries)
+ switch-num startbit decode-bitsize
+ indent lsb0? invalid-insn))
+ )
+ result))))
+
+ ; ??? Can delete if all cases are present.
+ indent " default : itype = "
+ (gen-cpu-insn-enum (current-cpu) invalid-insn)
+ ";"
+ (if (with-scache?)
+ " goto extract_sfmt_empty;\n"
+ " goto done;\n")
+ indent " }\n"
+ indent "}\n"
+ )
+)
+
+; Decoder generation entry point.
+; Generate code to decode INSN-LIST.
+; BITNUMS is the set of bits to initially key off of.
+; DECODE-BITSIZE is the number of bits of the instruction that `insn' holds.
+; LSB0? is non-#f if bit number 0 is the least significant bit.
+; INVALID-INSN is the <insn> object of the pseudo insn to handle invalid ones.
+
+(define (gen-decoder insn-list bitnums decode-bitsize indent lsb0? invalid-insn)
+ (logit 3 "Building decode tree.\n"
+ "bitnums = " (stringize bitnums " ") "\n"
+ "decode-bitsize = " (number->string decode-bitsize) "\n"
+ "lsb0? = " (if lsb0? "#t" "#f") "\n"
+ )
+
+ ; First build a table that decodes the instruction set.
+
+ (let ((table-guts (decode-build-table insn-list bitnums
+ decode-bitsize lsb0?
+ invalid-insn)))
+
+ ; Now print it out.
+
+ (-gen-decoder-switch "0" 0 decode-bitsize table-guts indent lsb0?
+ invalid-insn)
+ )
+)
diff --git a/cgen/utils.scm b/cgen/utils.scm
new file mode 100644
index 00000000000..84e871e6e05
--- /dev/null
+++ b/cgen/utils.scm
@@ -0,0 +1,1268 @@
+; Generic Utilities.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; These utilities are neither object nor cgen centric.
+; They're generic, non application-specific utilities.
+; There are a few exceptions, keep them to a minimum.
+;
+; Conventions:
+; - the prefix "gen-" comes from cgen's convention that procs that return C
+; code, and only those procs, are prefixed with "gen-"
+
+(define nil '())
+
+; Hobbit support code; for when not using hobbit.
+; FIXME: eliminate this stuff ASAP.
+
+(defmacro /fastcall-make (proc) proc)
+
+(defmacro fastcall4 (proc arg1 arg2 arg3 arg4)
+ (list proc arg1 arg2 arg3 arg4)
+)
+
+(defmacro fastcall5 (proc arg1 arg2 arg3 arg4 arg5)
+ (list proc arg1 arg2 arg3 arg4 arg5)
+)
+
+(defmacro fastcall6 (proc arg1 arg2 arg3 arg4 arg5 arg6)
+ (list proc arg1 arg2 arg3 arg4 arg5 arg6)
+)
+
+(defmacro fastcall7 (proc arg1 arg2 arg3 arg4 arg5 arg6 arg7)
+ (list proc arg1 arg2 arg3 arg4 arg5 arg6 arg7)
+)
+
+; ??? value doesn't matter too much here, just check if portable
+; Name was `UNSPECIFIED' but that conflicts with hobbit.
+(define *UNSPECIFIED* (if #f 1))
+
+; Define as global to avoid multiple copies in hobbit generated code.
+(define assert-fail-msg "assertion failure:")
+
+(defmacro assert (expr)
+ `(if (not ,expr)
+ (error assert-fail-msg ',expr))
+)
+
+(define verbose-level 0)
+
+(define (verbose-inc!)
+ (set! verbose-level (+ verbose-level 1))
+)
+
+(define (verbose? level) (>= verbose-level level))
+
+; Print to stderr, takes an arbitrary number of strings, possibly nested.
+
+(define message
+ (lambda args
+ (for-each (lambda (str)
+ (if (pair? str)
+ (apply message str)
+ (display str (current-error-port))))
+ args))
+)
+
+; Print a message if the verbosity level calls for it.
+; This is a macro as a bit of cpu may be spent computing args,
+; and we only want to spend it if the result will be printed.
+; Macro's can't be used in hobbit-compiled code, so instead there use:
+; (if (verbose? level) (message ...)).
+
+(defmacro logit (level . args)
+ `(if (>= verbose-level ,level) (message ,@args))
+)
+
+; Return a string of N spaces.
+
+(define (spaces n) (make-string n #\space))
+
+; Write N spaces to PORT, or the current output port if elided.
+
+(define (write-spaces n . port)
+ (let ((port (if (null? port) (current-output-port) (car port))))
+ (write (spaces n) port))
+)
+
+; Often used idiom.
+
+(define (string-map fn . args) (apply string-append (apply map (cons fn args))))
+
+; Collect a flat list of returned sublists from the lambda fn applied over args.
+
+(define (collect fn . args) (apply append (apply map (cons fn args))))
+
+
+; Map over value entries in an alist.
+; 'twould be nice if this were a primitive.
+
+(define (amap fn args)
+ (map fn (map cdr args))
+)
+
+; Like map but accept a proper or improper list.
+; An improper list is (a b c . d).
+; FN must be a proc of one argument.
+
+(define (map1-improper fn l)
+ (let ((result nil))
+ (let loop ((last #f) (l l))
+ (cond ((null? l)
+ result)
+ ((pair? l)
+ (if last
+ (begin
+ (set-cdr! last (cons (fn (car l)) nil))
+ (loop (cdr last) (cdr l)))
+ (begin
+ (set! result (cons (fn (car l)) nil))
+ (loop result (cdr l)))))
+ (else
+ (if last
+ (begin
+ (set-cdr! last (fn l))
+ result)
+ (fn l))))))
+)
+
+; Turn STR into a proper C symbol.
+; We assume STR has no leading digits.
+; All invalid characters are turned into '_'.
+; FIXME: Turn trailing "?" into "_p".
+
+(define (gen-c-symbol str)
+ (if (not (or (string? str) (symbol? str)))
+ (error "gen-c-symbol: not symbol or string:" str))
+ (map-over-string (lambda (c) (if (id-char? c) c #\_)) str)
+)
+
+; Turn STR into a proper file name, which is defined to be the same
+; as gen-c-symbol except use -'s instead of _'s.
+
+(define (gen-file-name str)
+ (if (not (or (string? str) (symbol? str)))
+ (error "gen-file-name: not symbol or string:" str))
+ (map-over-string (lambda (c) (if (id-char? c) c #\-)) str)
+)
+
+; Turn STR into lowercase.
+
+(define (string-downcase str)
+ (map-over-string (lambda (c) (char-downcase c)) str)
+)
+
+; Turn STR into uppercase.
+
+(define (string-upcase str)
+ (map-over-string (lambda (c) (char-upcase c)) str)
+)
+
+; Drop N chars from string S.
+; If N is negative, drop chars from the end.
+; It is ok to drop more characters than are in the string, the result is "".
+
+(define (string-drop n s)
+ (cond ((>= n (string-length s)) "")
+ ((< n 0) (substring s 0 (+ (string-length s) n)))
+ (else (substring s n (string-length s))))
+)
+
+; Drop the leading char from string S (assumed to have at least 1 char).
+
+(define (string-drop1 s)
+ (string-drop 1 s)
+)
+
+; Return the leading N chars from string STR.
+; This has APL semantics:
+; N > length: FILLER chars are appended
+; N < 0: take from the end of the string and prepend FILLER if necessary
+
+(define (string-take-with-filler n str filler)
+ (let ((len (string-length str)))
+ (if (< n 0)
+ (let ((n (- n)))
+ (string-append (if (> n len)
+ (make-string (- n len) filler)
+ "")
+ (substring str (max 0 (- len n)) len)))
+ (string-append (substring str 0 (min len n))
+ (if (> n len)
+ (make-string (- n len) filler)
+ ""))))
+)
+
+(define (string-take n str)
+ (string-take-with-filler n str #\space)
+)
+
+; Return the leading char from string S (assumed to have at least 1 char).
+
+(define (string-take1 s)
+ (substring s 0 1)
+)
+
+; Return the index of char C in string S or #f if not found.
+
+(define (string-index s c)
+ (let loop ((i 0))
+ (cond ((= i (string-length s)) #f)
+ ((char=? c (string-ref s i)) i)
+ (else (loop (1+ i)))))
+)
+
+; Cut string S into a list of strings using delimiter DELIM (a character).
+
+(define (string-cut s delim)
+ (let loop ((start 0)
+ (end 0)
+ (length (string-length s))
+ (result nil))
+ (cond ((= end length)
+ (if (> end start)
+ (reverse! (cons (substring s start end) result))
+ (reverse! result)))
+ ((char=? (string-ref s end) delim)
+ (loop (1+ end) (1+ end) length (cons (substring s start end) result)))
+ (else (loop start (1+ end) length result))))
+)
+
+; Convert a list of elements to a string, inserting DELIM (a string)
+; between elements.
+; L can also be a string or a number.
+
+(define (stringize l delim)
+ (cond ((string? l) l)
+ ((number? l) (number->string l))
+ ((symbol? l) (symbol->string l))
+ ((list? l)
+ (string-drop
+ (string-length delim)
+ (string-map (lambda (elm)
+ (string-append delim
+ (stringize elm delim)))
+ l)))
+ (else (error "stringize: can't handle:" l)))
+)
+
+; Output routines.
+
+; Extension to the current-output-port.
+; Only valid inside string-write.
+
+(define -current-print-state #f)
+
+; Create a print-state object.
+; This is written in portable Scheme so we don't use COS objects, etc.
+
+(define (make-print-state)
+ (vector 'print-state 0)
+)
+
+; print-state accessors.
+
+(define (pstate-indent pstate) (vector-ref pstate 1))
+(define (pstate-set-indent! pstate indent) (vector-set! pstate 1 indent))
+
+; Special print commands (embedded in args).
+
+(define (pstate-cmd? x) (and (vector? x) (eq? (vector-ref x 0) 'pstate)))
+
+;(define /endl (vector 'pstate '/endl)) ; ??? needed?
+(define /indent (vector 'pstate '/indent))
+(define (/indent-set n) (vector 'pstate '/indent-set n))
+(define (/indent-add n) (vector 'pstate '/indent-add n))
+
+; Process a pstate command.
+
+(define (pstate-cmd-do pstate cmd)
+ (assert (pstate-cmd? cmd))
+ (case (vector-ref cmd 1)
+ ((/endl)
+ "\n")
+ ((/indent)
+ (let ((indent (pstate-indent pstate)))
+ (string-append (make-string (quotient indent 8) #\tab)
+ (make-string (remainder indent 8) #\space))))
+ ((/indent-set)
+ (pstate-set-indent! pstate (vector-ref cmd 2))
+ "")
+ ((/indent-add)
+ (pstate-set-indent! pstate (+ (pstate-indent pstate)
+ (vector-ref cmd 2)))
+ "")
+ (else
+ (error "unknown pstate command" (vector-ref cmd 1))))
+)
+
+; Write STRINGS to current-output-port.
+; STRINGS is a list of things to write. Supported types are strings, symbols,
+; lists, procedures. Lists are printed by applying string-write recursively.
+; Procedures are thunks that return the string to write.
+;
+; The result is the empty string. This is for debugging where this
+; procedure is modified to return its args, rather than write them out.
+
+(define string-write
+ (lambda strings
+ (let ((pstate (make-print-state)))
+ (set! -current-print-state pstate)
+ (for-each (lambda (elm) (-string-write pstate elm))
+ strings)
+ (set! -current-print-state #f)
+ ""))
+)
+
+; Subroutine of string-write and string-write-map.
+
+(define (-string-write pstate expr)
+ (cond ((string? expr) (display expr)) ; not write, we want raw text
+ ((symbol? expr) (display expr))
+ ((procedure? expr) (-string-write pstate (expr)))
+ ((pstate-cmd? expr) (display (pstate-cmd-do pstate expr)))
+ ((list? expr) (for-each (lambda (x) (-string-write pstate x)) expr))
+ (else (error "string-write: bad arg:" expr)))
+ *UNSPECIFIED*
+)
+
+; Combination of string-map and string-write.
+
+(define (string-write-map proc arglist)
+ (let ((pstate -current-print-state))
+ (for-each (lambda (arg) (-string-write pstate (proc arg)))
+ arglist))
+ ""
+)
+
+; Build up an argument for string-write.
+
+(define string-list list)
+(define string-list-map map)
+
+; Subroutine of string-list->string. Does same thing -string-write does.
+
+(define (-string-list-flatten pstate strlist)
+ (cond ((string? strlist) strlist)
+ ((symbol? strlist) strlist)
+ ((procedure? strlist) (-string-list-flatten pstate (strlist)))
+ ((pstate-cmd? strlist) (pstate-cmd-do pstate strlist))
+ ((list? strlist) (apply string-append
+ (map (lambda (str)
+ (-string-list-flatten pstate str))
+ strlist)))
+ (else (error "string-list->string: bad arg:" strlist)))
+)
+
+; Flatten out a string list.
+
+(define (string-list->string strlist)
+ (-string-list-flatten (make-print-state) strlist)
+)
+
+; Prefix CHARS, a string of characters, with backslash in STR.
+; STR is either a string or list of strings (to any depth).
+; ??? Quick-n-dirty implementation.
+
+(define (backslash chars str)
+ (if (string? str)
+ ; quick check for any work to do
+ (if (any-true? (map (lambda (c)
+ (string-index str c))
+ (string->list chars)))
+ (let loop ((result "") (str str))
+ (if (= (string-length str) 0)
+ result
+ (loop (string-append result
+ (if (string-index chars (string-ref str 0))
+ "\\"
+ "")
+ (substring str 0 1))
+ (substring str 1 (string-length str)))))
+ str)
+ ; must be a list
+ (if (null? str)
+ nil
+ (cons (backslash chars (car str))
+ (backslash chars (cdr str)))))
+)
+
+; Return a boolean indicating if S is bound to a value.
+;(define old-symbol-bound? symbol-bound?)
+;(define (symbol-bound? s) (old-symbol-bound? #f s))
+
+; Return a boolean indicating if S is a symbol and is bound to a value.
+
+(define (bound-symbol? s)
+ (and (symbol? s)
+ (or (symbol-bound? #f s)
+ ;(module-bound? cgen-module s)
+ ))
+)
+
+; Return X.
+
+(define (identity x) x)
+
+; Test whether X is a `form' (non-empty list).
+; ??? Is `form' the right word to use here?
+; One can argue we should also test for a valid car. If so, it's the
+; name that's wrong not the code (because the code is what I want).
+
+(define (form? x) (and (not (null? x)) (list? x)))
+
+; Return the number of arguments to ARG-SPEC, a valid argument list
+; of `lambda'.
+; The result is a pair: number of fixed arguments, varargs indicator (#f/#t).
+
+(define (num-args arg-spec)
+ (if (symbol? arg-spec)
+ '(0 . #t)
+ (let loop ((count 0) (arg-spec arg-spec))
+ (cond ((null? arg-spec) (cons count #f))
+ ((null? (cdr arg-spec)) (cons (+ count 1) #f))
+ ((pair? (cdr arg-spec)) (loop (+ count 1) (cdr arg-spec)))
+ (else (cons (+ count 1) #t)))))
+)
+
+; Return a boolean indicating if N args is ok to pass to a proc with
+; an argument specification of ARG-SPEC (a valid argument list of `lambda').
+
+(define (num-args-ok? n arg-spec)
+ (let ((processed-spec (num-args arg-spec)))
+ (and
+ ; Ensure enough fixed arguments.
+ (>= n (car processed-spec))
+ ; If more args than fixed args, ensure varargs.
+ (or (= n (car processed-spec))
+ (cdr processed-spec))))
+)
+
+; Take N elements from list L.
+; If N is negative, take elements from the end.
+; If N is larger than the length, the extra elements are NIL.
+; FIXME: incomplete
+; FIXME: list-tail has args reversed (we should conform)
+
+(define (list-take n l)
+ (let ((len (length l)))
+ (if (< n 0)
+ (list-tail l (+ len n))
+ (let loop ((result nil) (l l) (i 0))
+ (if (= i n)
+ (reverse! result)
+ (loop (cons (car l) result) (cdr l) (+ i 1))))))
+)
+
+; Drop N elements from list L.
+; FIXME: list-tail has args reversed (we should conform)
+
+(define (list-drop n l)
+ (let loop ((n n) (l l))
+ (if (> n 0)
+ (loop (- n 1) (cdr l))
+ l))
+)
+
+; Drop N elements from the end of L.
+; FIXME: list-tail has args reversed (we should conform)
+
+(define (list-tail-drop n l)
+ (reverse! (list-drop n (reverse l)))
+)
+
+; APL's +\ operation on a vector of numbers.
+
+(define (plus-scan l)
+ (letrec ((-plus-scan (lambda (l result)
+ (if (null? l)
+ result
+ (-plus-scan (cdr l)
+ (cons (if (null? result)
+ (car l)
+ (+ (car l) (car result)))
+ result))))))
+ (reverse! (-plus-scan l nil)))
+)
+
+; Remove duplicate elements from sorted list L.
+; Currently supported elements are symbols (a b c) and lists ((a) (b) (c)).
+
+(define (remove-duplicates l)
+ (let loop ((l l) (result nil))
+ (cond ((null? l) (reverse! result))
+ ((null? result) (loop (cdr l) (cons (car l) result)))
+ ((equal? (car l) (car result)) (loop (cdr l) result))
+ (else (loop (cdr l) (cons (car l) result)))
+ )
+ )
+)
+
+; Return a boolean indicating if each element of list satisfies its
+; corresponding predicates. The length of L must be equal to the length
+; of PREDS.
+
+(define (list-elements-ok? l preds)
+ (and (list? l)
+ (= (length l) (length preds))
+ (all-true? (map (lambda (pred elm) (pred elm)) preds l)))
+)
+
+; Remove duplicates from unsorted list L.
+; KEY-GENERATOR is a lambda that takes a list element as input and returns
+; an equal? key to use to determine duplicates.
+; The first instance in a set of duplicates is always used.
+; This is not intended to be applied to large lists with an expected large
+; result (where sorting the list first would be faster), though one could
+; add such support later.
+
+(define (nub l key-generator)
+ (let loop ((l l) (keys (map key-generator l)) (result nil))
+ (if (null? l)
+ (reverse! (map cdr result))
+ (if (assv (car keys) result)
+ (loop (cdr l) (cdr keys) result)
+ (loop (cdr l) (cdr keys) (acons (car keys) (car l)
+ result)))))
+)
+
+; Return a boolean indicating if list L1 is a subset of L2.
+; Uses memq.
+
+(define (subset? l1 l2)
+ (let loop ((l1 l1))
+ (if (null? l1)
+ #t
+ (if (memq (car l1) l2)
+ (loop (cdr l1))
+ #f)))
+)
+
+; Return intersection of two lists.
+
+(define (intersection l1 l2)
+ (cond ((null? l1) l1)
+ ((null? l2) l2)
+ ((memq (car l1) l2) (cons (car l1) (intersection (cdr l1) l2)))
+ (else (intersection (cdr l1) l2)))
+)
+
+; Return a count of the number of elements of list L1 that are in list L2.
+; Uses memq.
+
+(define (count-common l1 l2)
+ (let loop ((result 0) (l1 l1))
+ (if (null? l1)
+ result
+ (if (memq (car l1) l2)
+ (loop (+ result 1) (cdr l1))
+ (loop result (cdr l1)))))
+)
+
+; Remove duplicate elements from sorted alist L.
+; L must be sorted by name.
+
+(define (alist-nub l)
+ (let loop ((l l) (result nil))
+ (cond ((null? l) (reverse! result))
+ ((null? result) (loop (cdr l) (cons (car l) result)))
+ ((eq? (caar l) (caar result)) (loop (cdr l) result))
+ (else (loop (cdr l) (cons (car l) result)))
+ )
+ )
+)
+
+; Return a copy of alist L.
+
+(define (alist-copy l)
+ ; (map cons (map car l) (map cdr l)) ; simple way
+ ; presumably more efficient way (less cons cells created)
+ (map (lambda (elm)
+ (cons (car elm) (cdr elm)))
+ l)
+)
+
+; Return the order in which to select elements of L sorted by SORT-FN.
+; The result is origin 0.
+
+(define (sort-grade l sort-fn)
+ (let ((sorted (sort (map cons (iota (length l)) l)
+ (lambda (a b) (sort-fn (cdr a) (cdr b))))))
+ (map car sorted))
+)
+
+; Return ALIST sorted on the name in ascending order.
+
+(define (alist-sort alist)
+ (sort alist
+ (lambda (a b)
+ (string<? (symbol->string (car a))
+ (symbol->string (car b)))))
+)
+
+; Return a boolean indicating if C is a leading id char.
+; '@' is treated as an id-char as it's used to delimit something that
+; sed will alter.
+
+(define (leading-id-char? c)
+ (or (char-alphabetic? c)
+ (char=? c #\_)
+ (char=? c #\@))
+)
+
+; Return a boolean indicating if C is an id char.
+; '@' is treated as an id-char as it's used to delimit something that
+; sed will alter.
+
+(define (id-char? c)
+ (or (leading-id-char? c)
+ (char-numeric? c))
+)
+
+; Return the length of the identifier that begins S.
+; Identifiers are any of letter, digit, _, @.
+; The first character must not be a digit.
+; ??? The convention is to use "-" between cgen symbols, not "_".
+; Try to handle "-" here as well.
+
+(define (id-len s)
+ (if (leading-id-char? (string-ref s 0))
+ (let ((len (string-length s)))
+ (let loop ((n 0))
+ (if (and (< n len)
+ (id-char? (string-ref s n)))
+ (loop (1+ n))
+ n)))
+ 0)
+)
+
+; Return number of characters in STRING until DELIMITER.
+; Returns #f if DELIMITER not present.
+; FIXME: Doesn't yet support \-prefixed delimiter (doesn't terminate scan).
+
+(define (chars-until-delimiter string delimiter)
+ (let loop ((str string) (result 0))
+ (cond ((= (string-length str) 0)
+ #f)
+ ((char=? (string-ref str 0) delimiter)
+ result)
+ (else (loop (string-drop1 str) (1+ result)))))
+)
+
+; Apply FN to each char of STR.
+
+(define (map-over-string fn str)
+ (do ((tmp (string-copy (if (symbol? str) (symbol->string str) str)))
+ (i (- (string-length str) 1) (- i 1)))
+ ((< i 0) tmp)
+ (string-set! tmp i (fn (string-ref tmp i)))
+ )
+)
+
+; Return a range.
+; It must be distinguishable from a list of numbers.
+
+(define (minmax min max) (cons min max))
+
+; Move VALUE of LENGTH bits to position START in a word of SIZE bits.
+; LSB0? is non-#f if bit numbering goes LSB->MSB.
+; Otherwise it goes MSB->LSB.
+; START-LSB? is non-#f if START denotes the least significant bit.
+; Otherwise START denotes the most significant bit.
+; N is assumed to fit in the field.
+
+(define (word-value start length size lsb0? start-lsb? value)
+ (if lsb0?
+ (if start-lsb?
+ (logsll value start)
+ (logsll value (+ (- start length) 1)))
+ (if start-lsb?
+ (logsll value (- size start 1))
+ (logsll value (- size (+ start length)))))
+)
+
+; Return a bit mask of LENGTH bits in a word of SIZE bits starting at START.
+; LSB0? is non-#f if bit numbering goes LSB->MSB.
+; Otherwise it goes MSB->LSB.
+; START-LSB? is non-#f if START denotes the least significant bit.
+; Otherwise START denotes the most significant bit.
+
+(define (word-mask start length size lsb0? start-lsb?)
+ (if lsb0?
+ (if start-lsb?
+ (logsll (mask length) start)
+ (logsll (mask length) (+ (- start length) 1)))
+ (if start-lsb?
+ (logsll (mask length) (- size start 1))
+ (logsll (mask length) (- size (+ start length)))))
+)
+
+; Extract LENGTH bits at bit number START in a word of SIZE bits from VALUE.
+; LSB0? is non-#f if bit numbering goes LSB->MSB.
+; Otherwise it goes MSB->LSB.
+; START-LSB? is non-#f if START denotes the least significant bit.
+; Otherwise START denotes the most significant bit.
+;
+; ??? bit-extract takes a big-number argument but still uses logand
+; which doesn't so we don't use it
+
+(define (word-extract start length size lsb0? start-lsb? value)
+ (if lsb0?
+ (if start-lsb?
+ (remainder (logslr value start) (integer-expt 2 length))
+ (remainder (logslr value (+ (- start length) 1)) (integer-expt 2 length)))
+ (if start-lsb?
+ (remainder (logslr value (- size start 1)) (integer-expt 2 length))
+ (remainder (logslr value (- size (+ start length))) (integer-expt 2 length))))
+)
+
+; Return a bit mask of size SIZE beginning at the LSB.
+
+(define (mask size)
+ (- (logsll 1 size) 1)
+)
+
+; Split VAL into pieces of bit size LENGTHS.
+; e.g. (split-bits '(8 2) 997) -> (229 3)
+; There are as many elements in the result as there are in LENGTHS.
+; Note that this can result in a loss of information.
+
+(define (split-bits lengths val)
+ (letrec ((split1
+ (lambda (lengths val result)
+ (if (null? lengths)
+ result
+ (split1 (cdr lengths)
+ (quotient val (integer-expt 2 (car lengths)))
+ (cons (remainder val (integer-expt 2 (car lengths)))
+ result))))))
+ (reverse! (split1 lengths val nil)))
+)
+
+; Generalized version of split-bits.
+; e.g. (split-value '(10 10 10) 1234) -> (4 3 2 1) ; ??? -> (1 2 3 4) ?
+; (split-value '(10 10) 1234) -> (4 3)
+; There are as many elements in the result as there are in BASES.
+; Note that this can result in a loss of information.
+
+(define (split-value bases val)
+ (letrec ((split1
+ (lambda (bases val result)
+ (if (null? bases)
+ result
+ (split1 (cdr bases)
+ (quotient val (car bases))
+ (cons (remainder val (car bases))
+ result))))))
+ (reverse! (split1 bases val nil)))
+)
+
+; Convert bits to bytes.
+
+(define (bits->bytes bits) (quotient (+ 7 bits) 8))
+
+; Convert bytes to bits.
+
+(define (bytes->bits bytes) (* bytes 8))
+
+; Return a list of integers.
+; ARGS is either a list of one integer (N) meaning return a list from 0 to N-1,
+; or a list of two integers (START N) meaning return a list from START to
+; START+N-1.
+; FIXME: change to (iota n . start).
+
+(define (iota . args)
+ (case (length args)
+ ((1) (let loop ((n (car args)) (z nil))
+ (if (<= n 0) z (loop (1- n) (cons (1- n) z)))))
+ ((2) (let ((start (car args)))
+ (let loop ((n (cadr args)) (z nil))
+ (if (<= n 0) z (loop (1- n) (cons (+ start (1- n)) z))))))
+ (else (error "iota: wrong number of arguments:" args)))
+)
+
+; Return a list of the first N powers of 2.
+
+(define (powers-of-2 n)
+ (cond ((= n 0) nil)
+ (else (cons (integer-expt 2 (1- n)) (powers-of-2 (1- n))))
+ )
+ ; Another way: (map (lambda (n) (ash 1 n)) (iota n))
+)
+
+; I'm tired of writing (not (= foo bar)).
+
+(define (!= a b) (not (= a b)))
+
+; Return #t if BIT-NUM (which is starting from LSB), is set in the binary
+; representation of non-negative integer N.
+
+(define (bit-set? n bit-num)
+ ; ??? Quick hack to work around missing bignum support.
+ ;(= 1 (cg-logand (logslr n bit-num) 1))
+ (if (>= n #x20000000)
+ (if (>= bit-num 16)
+ (logbit? (- bit-num 16) (logslr n 16))
+ (logbit? bit-num (remainder n 65536)))
+ (logbit? bit-num n))
+)
+
+; Return #t if each element of bools is #t. Since Scheme considers any
+; non-#f value as #t we do too.
+; (all-true? ()) is #t since that is the identity element.
+
+(define (all-true? bools)
+ (cond ((null? bools) #t)
+ ((car bools) (all-true? (cdr bools)))
+ (else #f))
+)
+
+; Return #t if any element of BOOLS is #t.
+; If BOOLS is empty, return #f.
+
+(define (any-true? bools)
+ (cond ((null? bools) #f)
+ ((car bools) #t)
+ (else (any-true? (cdr bools))))
+)
+
+; Return count of true values.
+
+(define (count-true flags)
+ (let loop ((result 0) (flags flags))
+ (if (null? flags)
+ result
+ (loop (+ result (if (car flags) 1 0))
+ (cdr flags))))
+)
+
+; Return count of all ones in BITS.
+
+(define (count-bits bits)
+ (let loop ((result 0) (bits bits))
+ (if (= bits 0)
+ result
+ (loop (+ result (remainder bits 2)) (quotient bits 2))))
+)
+
+; Convert bits in N #f/#t.
+; LENGTH is the length of N in bits.
+
+(define (bits->bools n length)
+ (do ((result (make-list length #f))
+ (i 0 (+ i 1)))
+ ((= i length) (reverse! result))
+ (list-set! result i (if (bit-set? n i) #t #f))
+ )
+)
+
+; Print a C integer.
+
+(define (gen-integer val)
+ (cond ((and (<= #x-80000000 val) (> #x80000000 val))
+ (number->string val))
+ ((and (<= #x80000000 val) (>= #xffffffff val))
+ ; ??? GCC complains if not affixed with "U" but that's not k&r.
+ ;(string-append (number->string val) "U"))
+ (string-append "0x" (number->string val 16)))
+ (else (error "Number too large for gen-integer:" val)))
+)
+
+; Return higher/lower part of double word integer.
+
+(define (high-part val)
+ (logslr val 32)
+)
+(define (low-part val)
+ (remainder val #x100000000)
+)
+
+; Logical operations.
+
+(define (logslr val shift) (ash val (- shift)))
+(define logsll ash) ; (logsll val shift) (ash val shift))
+; logand, logior, logxor defined by guile so we don't need to
+; (define (logand a b) ...)
+; (define (logxor a b) ...)
+; (define (logior a b) ...)
+;
+; On the other hand they didn't support bignums, so the cgen-binary
+; defines cg-log* that does. These are just a quick hack that only
+; handle what currently needs handling.
+
+(define (cg-logand a b)
+ (if (or (>= a #x20000000)
+ (>= b #x20000000))
+ (+ (logsll (logand (logslr a 16) (logslr b 16)) 16)
+ (logand (remainder a 65536) (remainder b 65536)))
+ (logand a b))
+)
+
+(define (cg-logxor a b)
+ (if (or (>= a #x20000000)
+ (>= b #x20000000))
+ (+ (logsll (logxor (logslr a 16) (logslr b 16)) 16)
+ (logxor (remainder a 65536) (remainder b 65536)))
+ (logxor a b))
+)
+
+; Return list of bit values for the 1's in X.
+
+(define (bit-vals x)
+ (let loop ((result nil) (mask 65536))
+ (cond ((= mask 0) result)
+ ((> (logand x mask) 0) (loop (cons mask result) (logslr mask 1)))
+ (else (loop result (logslr mask 1)))))
+)
+
+; Return bit representation of N in LEN bits.
+; e.g. (bit-rep 6 3) -> (1 1 0)
+
+(define (bit-rep n len)
+ (cond ((= len 0) nil)
+ ((> (logand n (logsll 1 (- len 1))) 0)
+ (cons 1 (bit-rep n (- len 1))))
+ (else (cons 0 (bit-rep n (- len 1))))))
+
+; Return list of all bit values from 0 to N.
+; e.g. (bit-patterns 3) -> ((0 0 0) (0 0 1) (0 1 0) ... (1 1 1))
+
+(define (bit-patterns len)
+ (map (lambda (x) (bit-rep x len)) (iota (logsll 1 len)))
+)
+
+; Compute the list of all indices from bits missing in MASK.
+; e.g. (missing-bit-indices #xff00 #xffff) -> (0 1 2 3 ... 255)
+;
+; Hobbit emits two functions named `missing_bit_indices_fn31' for this.
+;(define (missing-bit-indices mask full-mask)
+; (let* ((bitvals (bit-vals (logxor mask full-mask)))
+; (selectors (bit-patterns (length bitvals))))
+; (map (lambda (sel) (apply + (map * sel bitvals))) selectors))
+;)
+; So it's rewritten to this ...
+
+(define (missing-bit-indices mask full-mask)
+ (let* ((bitvals (bit-vals (logxor mask full-mask)))
+ (selectors (bit-patterns (length bitvals)))
+ (map-star (lambda (sel) (map * sel bitvals)))
+ (compute-indices (lambda (sel) (apply + (map-star sel)))))
+ (map compute-indices selectors))
+)
+
+; Convert a list of numbers to a string, separated by SEP.
+; The result is prefixed by SEP too.
+
+(define (numbers->string nums sep)
+ (string-map (lambda (elm) (string-append sep (number->string elm))) nums)
+)
+
+; Convert a number to a hex string.
+
+(define (number->hex num)
+ (number->string num 16)
+)
+
+; Given a list of numbers NUMS, generate text to pass them as arguments to a
+; C function. We assume they're not the first argument and thus have a
+; leading comma.
+
+(define (gen-int-args nums)
+ (numbers->string nums ", ")
+)
+
+; Given a C expression or a list of C expressions, return a comma separated
+; list of them.
+; In the case of more than 0 elements the leading ", " is present so that
+; there is no edge case in the case of 0 elements when the caller is appending
+; the result to an initial set of arguments (the number of commas equals the
+; number of elements). The caller is responsible for dropping the leading
+; ", " if necessary. Note that `string-drop' can handle the case where more
+; characters are dropped than are present.
+
+(define (gen-c-args exprs)
+ (cond ((null? exprs) "")
+ ((pair? exprs) (string-map (lambda (elm) (string-append ", " elm))
+ exprs))
+ ((equal? exprs "") "")
+ (else (string-append ", " exprs)))
+)
+
+; Return a list of N macro argument names.
+
+(define (macro-args n)
+ (map (lambda (i) (string-append "a" (number->string i)))
+ (map 1+ (iota n)))
+)
+
+; Return C code for N macro argument names.
+; (gen-macro-args 4) -> ", a1, a2, a3, a4"
+
+(define (gen-macro-args n)
+ (gen-c-args (macro-args n))
+)
+
+; Return a string to reference an array.
+; INDICES is either a (possibly empty) list of indices or a single index.
+; The values can either be numbers or strings (/symbols).
+
+(define (gen-array-ref indices)
+ (let ((gen-index (lambda (idx)
+ (string-append "["
+ (cond ((number? idx) (number->string idx))
+ (else idx))
+ "]"))))
+ (cond ((null? indices) "")
+ ((pair? indices) ; list of indices?
+ (string-map gen-index indices))
+ (else (gen-index indices))))
+)
+
+; Return list element N or #f if list L is too short.
+
+(define (list-maybe-ref l n)
+ (if (> (length l) n)
+ (list-ref l n)
+ #f)
+)
+
+; Return list of index numbers of elements in list L that satisfy PRED.
+; I is usually 0.
+
+(define (find-index i pred l)
+ (define (find1 i pred l result)
+ (cond ((null? l) result)
+ ((pred (car l)) (find1 (+ 1 i) pred (cdr l) (cons i result)))
+ (else (find1 (+ 1 i) pred (cdr l) result))))
+ (reverse! (find1 i pred l nil))
+)
+
+; Return list of elements of L that satisfy PRED.
+
+(define (find pred l)
+ (define (find1 pred l result)
+ (cond ((null? l) result)
+ ((pred (car l)) (find1 pred (cdr l) (cons (car l) result)))
+ (else (find1 pred (cdr l) result))))
+ (reverse! (find1 pred l nil))
+)
+
+; Return first element of L that satisfies PRED or #f if there is none.
+
+(define (find-first pred l)
+ (cond ((null? l) #f)
+ ((pred (car l)) (car l))
+ (else (find-first pred (cdr l))))
+)
+
+; Return list of FN applied to elements of L that satisfy PRED.
+
+(define (find-apply fn pred l)
+ (cond ((null? l) nil)
+ ((pred (car l)) (cons (fn (car l)) (find-apply fn pred (cdr l))))
+ (else (find-apply fn pred (cdr l))))
+)
+
+; Given a list of lists L such that the first element in each list names the
+; entry, look up symbol S in that and return its index. If not found,
+; return #f.
+; Eg: (lookup 'element2 '((element1 1) (element2 2)))
+; Granted, linear searching isn't efficient. If it ever becomes a problem we
+; can do something about it then.
+; I is added to the result.
+
+(define (lookup-index s l i)
+ (cond ((null? l) #f)
+ ((eqv? s (caar l)) i)
+ (else (lookup-index s (cdr l) (1+ i))))
+)
+
+; Return the index of element ELM in list L or #f if not found.
+; If found, I is added to the result.
+; (Yes, in one sense I is present to simplify the implementation. Sue me.)
+
+(define (element-lookup-index elm l i)
+ (cond ((null? l) #f)
+ ((equal? elm (car l)) i)
+ (else (element-lookup-index elm (cdr l) (1+ i))))
+)
+
+; Return #t if ELM is in ELM-LIST.
+
+(define (element? elm elm-list)
+ (->bool (member elm elm-list))
+)
+
+; Return the set of all possible combinations of elements in list L
+; according to the following rules:
+; - each element of L is either an atom (non-list) or a list
+; - each list element is (recursively) interpreted as a set of choices
+; - the result is a list of all possible combinations of elements
+;
+; Example: (list-expand '(a b (1 2 (3 4)) c (5 6)))
+; --> ((a b 1 c d 5)
+; (a b 1 c d 6)
+; (a b 2 c d 5)
+; (a b 2 c d 6)
+; (a b 3 c d 5)
+; (a b 3 c d 6)
+; (a b 4 c d 5)
+; (a b 4 c d 6))
+
+(define (list-expand l)
+ #f ; ??? wip
+)
+
+; Given X, a number or symbol, reduce it to a constant if possible.
+; Numbers always reduce to themselves.
+; Symbols are reduced to a number if they're defined as such,
+; or to an enum constant if one exists; otherwise X is returned unchanged.
+; Requires: symbol-bound? enum-lookup-val
+
+(define (reduce x)
+ (if (number? x)
+ x
+ ; A symbol bound to a number?
+ (if (and (symbol? x) (symbol-bound? #f x) (number? (eval x)))
+ (eval x)
+ ; An enum value that has a known numeric value?
+ (let ((e (enum-lookup-val x)))
+ (if (number? (car e))
+ (car e)
+ ; Otherwise return X unchanged.
+ x))))
+)
+
+; If OBJ has a dump method call it, otherwise return OBJ untouched.
+
+(define (dump obj)
+ (if (method-present? obj 'dump)
+ (send obj 'dump)
+ obj)
+)
+
+; Copyright messages.
+
+; Pair of header,trailer parts of copyright.
+
+(define copyright-fsf
+ (cons "\
+THIS FILE IS MACHINE GENERATED WITH CGEN.
+
+Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+"
+ "\
+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, 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.
+"
+))
+
+; Pair of header,trailer parts of copyright.
+
+(define copyright-cygnus
+ (cons "\
+THIS FILE IS MACHINE GENERATED WITH CGEN.
+
+Copyright (C) 2000 Red Hat, Inc.
+"
+ "\
+"))
+
+; Set this to one of copyright-fsf, copyright-cygnus.
+
+(define CURRENT-COPYRIGHT copyright-fsf)
+
+; Packages.
+
+(define package-gnu-binutils-gdb "\
+This file is part of the GNU Binutils and/or GDB, the GNU debugger.
+")
+
+(define package-gnu-simulators "\
+This file is part of the GNU Simulators.
+")
+
+(define package-cygnus-simulators "\
+This file is part of the Cygnus Simulators.
+")
+
+; Return COPYRIGHT, with FILE-DESC as the first line
+; and PACKAGE as the name of the package which the file belongs in.
+; COPYRIGHT is a pair of (header . trailer).
+
+(define (gen-copyright file-desc copyright package)
+ (string-append "/* " file-desc "\n\n"
+ (car copyright)
+ "\n" package "\n"
+ (cdr copyright)
+ "\n*/\n\n")
+)
+
+; File operations.
+
+; Delete FILE, handling the case where it doesn't exist.
+
+(define (delete-file-noerr file)
+ ; This could also use file-exists?, but it's nice to have a few examples
+ ; of how to use `catch' lying around.
+ (catch 'system-error (lambda () (delete-file file))
+ (lambda args #f))
+)
+
+; Create FILE, point current-output-port to it, and call WRITE-FN.
+; FILE is always overwritten.
+; GEN-FN either writes output to stdout or returns the text to write,
+; the last thing we do is write the text returned by WRITE-FN to FILE.
+
+(define (file-write file write-fn)
+ (delete-file-noerr file)
+ (let ((left-over-text (with-output-to-file file write-fn)))
+ (let ((port (open-file file "a")))
+ (display left-over-text port)
+ (close-port port))
+ #t)
+)
+
+; Return the size in bytes of FILE.
+
+(define (file-size file)
+ (let ((stat (%stat file)))
+ (if stat
+ (vector-ref (%stat file) 7)
+ -1))
+)
+
+; Time operations.
+
+; Return the current time.
+; The result is a black box understood only by time-elapsed.
+
+(define (time-current) (gettimeofday))
+
+; Return the elapsed time in milliseconds since START.
+
+(define (time-elapsed start)
+ (let ((now (gettimeofday)))
+ (+ (* (- (car now) (car start)) 1000)
+ (quotient (- (cdr now) (cdr start)) 1000)))
+)
+
+; Run PROC and return the number of milliseconds it took to execute it N times.
+
+(define (time-proc n proc)
+ (let ((now (time-current)))
+ (do ((i 0 (+ i 1))) ((= i n) (time-elapsed now))
+ (proc)))
+)