2004-02-20 Andrew Cagney <cagney@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Fri, 20 Feb 2004 16:26:45 +0000 (16:26 +0000)
committerAndrew Cagney <cagney@redhat.com>
Fri, 20 Feb 2004 16:26:45 +0000 (16:26 +0000)
* m32r.opc, m32r.cpu: New files.  Written by , Doug Evans, Nick
Clifton, Ben Elliston, Matthew Green, and Andrew Haley.

cpu/ChangeLog
cpu/m32r.cpu [new file with mode: 0644]
cpu/m32r.opc [new file with mode: 0644]

index f6ed0ba429217eaeaf83333ea647b9fb6c66a65c..9d0f3e2a15c8b0a980206c1de9f2670eaad445e5 100644 (file)
@@ -1,5 +1,8 @@
 2004-02-20  Andrew Cagney  <cagney@redhat.com>
 
+       * m32r.opc, m32r.cpu: New files.  Written by , Doug Evans, Nick
+       Clifton, Ben Elliston, Matthew Green, and Andrew Haley.
+
        * sh.cpu, sh.opc, sh64-compact.cpu, sh64-media.cpu: New files, all
        written by Ben Elliston.
 
diff --git a/cpu/m32r.cpu b/cpu/m32r.cpu
new file mode 100644 (file)
index 0000000..a2f94a8
--- /dev/null
@@ -0,0 +1,2127 @@
+; Mitsubishi M32R CPU description.  -*- Scheme -*-
+;
+; Copyright 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+;
+; Contributed by Red Hat Inc; developed under contract from Mitsubishi
+; Electric Corporation.
+;
+; This file is part of the GNU Binutils.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, write to the Free Software
+; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+(include "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))
+        )
+)
+\f
+; 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)
+)
+\f
+; 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)
+       )
+)
+\f
+; 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.
+\f
+; 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)))
+)
+\f
+; 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")
+)
+\f
+; 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))
+\f
+; 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)
+\f
+; 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")
+)
+
+; IDOC attribute for instruction documentation.
+
+(define-attr
+  (for insn)
+  (type enum)
+  (name IDOC)
+  (comment "insn kind for documentation")
+  (attrs META)
+  (values
+   (MEM - () "Memory")
+   (ALU - () "ALU")
+   (BR - () "Branch")
+   (ACCUM - () "Accumulator")
+   (MAC - () "Multiply/Accumulate")
+   (MISC - () "Miscellaneous")
+  )
+)
+
+(define-pmacro (bin-op mnemonic op2-op sem-op imm-prefix imm)
+  (begin
+     (dni mnemonic
+         (.str mnemonic " reg/reg")
+         ((PIPE OS) (IDOC ALU))
+         (.str mnemonic " $dr,$sr")
+         (+ OP1_0 op2-op dr sr)
+         (set dr (sem-op dr sr))
+         ()
+     )
+     (dni (.sym mnemonic "3")
+         (.str mnemonic " reg/" imm)
+         ((IDOC ALU))
+         (.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) (IDOC ALU))
+     ;#.(string-append "addi " "$dr,$simm8") ; #. experiment
+     "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) (IDOC ALU))
+     "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"
+     ((IDOC ALU))
+     "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) (IDOC ALU))
+     "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) (IDOC BR))
+     "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) (IDOC BR))
+     "bc $disp8"
+     (emit bc8 disp8)
+)
+
+(dni bc24 "bc with 24 bit displacement"
+     (COND-CTI (IDOC BR))
+     "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 RELAXED (IDOC BR))
+     "bc $disp24"
+     (emit bc24 disp24)
+)
+
+(dni beq "beq"
+     (COND-CTI (IDOC BR))
+     "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 (IDOC BR))
+       (.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) (IDOC BR))
+     "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) (IDOC BR))
+     "bl $disp8"
+     (emit bl8 disp8)
+)
+
+(dni bl24 "bl with 24 bit displacement"
+     (UNCOND-CTI (IDOC BR))
+     "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 RELAXED (IDOC BR))
+     "bl $disp24"
+     (emit bl24 disp24)
+)
+
+(dni bcl8 "bcl with 8 bit displacement"
+     (COND-CTI FILL-SLOT (MACH m32rx) (PIPE O) (IDOC BR))
+     "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 (IDOC BR))
+     "bcl $disp8"
+     (emit bcl8 disp8)
+)
+
+(dni bcl24 "bcl with 24 bit displacement"
+     (COND-CTI (MACH m32rx) (IDOC BR))
+     "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) RELAXED (IDOC BR))
+     "bcl $disp24"
+     (emit bcl24 disp24)
+)
+
+(dni bnc8 "bnc with 8 bit displacement"
+     (COND-CTI (PIPE O) (IDOC BR))
+     "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) (IDOC BR))
+     "bnc $disp8"
+     (emit bnc8 disp8)
+)
+
+(dni bnc24 "bnc with 24 bit displacement"
+     (COND-CTI (IDOC BR))
+     "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 RELAXED (IDOC BR))
+     "bnc $disp24"
+     (emit bnc24 disp24)
+)
+
+(dni bne "bne"
+     (COND-CTI (IDOC BR))
+     "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) (IDOC BR))
+     "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) (IDOC BR))
+     "bra $disp8"
+     (emit bra8 disp8)
+)
+
+(dni bra24 "bra with 24 displacement"
+     (UNCOND-CTI (IDOC BR))
+     "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 RELAXED (IDOC BR))
+     "bra $disp24"
+     (emit bra24 disp24)
+)
+
+(dni bncl8 "bncl with 8 bit displacement"
+     (COND-CTI FILL-SLOT (MACH m32rx) (PIPE O) (IDOC BR))
+     "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 (IDOC BR))
+     "bncl $disp8"
+     (emit bncl8 disp8)
+)
+
+(dni bncl24 "bncl with 24 bit displacement"
+     (COND-CTI (MACH m32rx) (IDOC BR))
+     "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) RELAXED (IDOC BR))
+     "bncl $disp24"
+     (emit bncl24 disp24)
+)
+
+(dni cmp "cmp"
+     ((PIPE OS) (IDOC ALU))
+     "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"
+     ((IDOC ALU))
+     "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) (IDOC ALU))
+     "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"
+     ((IDOC ALU))
+     "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) (IDOC ALU))
+     "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) (IDOC ALU))
+     "cmpz $src2"
+     (+ OP1_0 OP2_7 (f-r1 0) src2)
+     (set condbit (eq src2 (const 0)))
+     ((m32rx (unit u-cmp)))
+)
+
+(dni div "div"
+     ((IDOC ALU))
+     "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"
+     ((IDOC ALU))
+     "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"
+     ((IDOC ALU))
+     "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"
+     ((IDOC ALU))
+     "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) (IDOC ALU))
+     "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 (IDOC BR))
+     "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 (IDOC BR))
+     "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) (IDOC BR))
+     "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) (IDOC BR))
+     "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) (IDOC MEM))
+        (.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) (IDOC MEM))
+         (.str "ld" suffix " $dr,@($sr)")
+         (emit (.sym ld suffix) dr sr))
+    (dni (.sym ld suffix -d) (.str "ld" suffix "-d")
+        ((IDOC MEM))
+        (.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 (IDOC MEM))
+         (.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) (IDOC MEM))
+     "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"
+      ((IDOC MEM))
+      "pop $dr"
+      (emit ld-plus dr (sr 15)) ; "ld %0,@sp+"
+)
+
+(dni ld24 "ld24"
+     ((IDOC MEM))
+     "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) (IDOC ALU))
+     "ldi8 $dr,$simm8"
+     (+ OP1_6 dr simm8)
+     (set dr simm8)
+     ()
+)
+
+(dnmi ldi8a "ldi8 alias"
+     ((PIPE OS) (IDOC ALU))
+     "ldi $dr,$simm8"
+     (emit ldi8 dr simm8)
+)
+
+(dni ldi16 "ldi16"
+     ((IDOC ALU))
+     "ldi16 $dr,$hash$slo16"
+     (+ OP1_9 OP2_15 (f-r2 0) dr slo16)
+     (set dr slo16)
+     ()
+)
+
+(dnmi ldi16a "ldi16 alias"
+     ((IDOC ALU))
+     "ldi $dr,$hash$slo16"
+     (emit ldi16 dr slo16)
+)
+
+(dni lock "lock"
+     ((PIPE O) (IDOC MISC))
+     "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) (IDOC MAC)
+     )
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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 (IDOC MAC))
+     "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) (IDOC MAC))
+     "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 (IDOC MAC))
+     "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) (IDOC ALU))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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 (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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 (IDOC ACCUM))
+     "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) (IDOC ALU))
+     "mv $dr,$sr"
+     (+ OP1_1 OP2_8 dr sr)
+     (set dr sr)
+     ()
+)
+
+(dni mvfachi "mvfachi"
+     ((MACH m32r) (PIPE S) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC MISC))
+     "mvfc $dr,$scr"
+     (+ OP1_1 OP2_9 dr scr)
+     (set dr scr)
+     ()
+)
+
+(dni mvtachi "mvtachi"
+     ((MACH m32r) (PIPE S) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC ACCUM))
+     "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) (IDOC MISC))
+     "mvtc $sr,$dcr"
+     (+ OP1_1 OP2_10 dcr sr)
+     (set dcr sr)
+     ()
+)
+
+(dni neg "neg"
+     ((PIPE OS) (IDOC ALU))
+     "neg $dr,$sr"
+     (+ OP1_0 OP2_3 dr sr)
+     (set dr (neg sr))
+     ()
+)
+
+(dni nop "nop"
+     ((PIPE OS) (IDOC MISC))
+     "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) (IDOC ALU))
+     "not $dr,$sr"
+     (+ OP1_0 OP2_11 dr sr)
+     (set dr (inv sr))
+     ()
+)
+
+(dni rac "rac"
+     ((MACH m32r) (PIPE S) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "rac $accd"
+     (emit rac-dsi accd (f-accs 0) (f-imm1 0))
+)
+
+(dnmi rac-ds "rac-ds"
+     ((MACH m32rx) (PIPE S) (IDOC MAC))
+     "rac $accd,$accs"
+     (emit rac-dsi accd accs (f-imm1 0))
+)
+
+
+(dni rach "rach"
+     ((MACH m32r) (PIPE S) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "rach $accd"
+     (emit rach-dsi accd (f-accs 0) (f-imm1 0))
+)
+
+(dnmi rach-ds "rach-ds"
+     ((MACH m32rx) (PIPE S) (IDOC MAC))
+     "rach $accd,$accs"
+     (emit rach-dsi accd accs (f-imm1 0))
+)
+
+(dni rte "rte"
+     (UNCOND-CTI (PIPE O) (IDOC BR))
+     "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"
+     ((IDOC ALU))
+     "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) (IDOC ALU))
+         (.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 ((IDOC ALU))
+         (.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) (IDOC ALU))
+         (.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) (IDOC MEM))
+        (.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) (IDOC MEM))
+         (.str "st" suffix " $src1,@($src2)")
+         (emit (.sym st suffix) src1 src2))
+    (dni (.sym st suffix -d) (.str "st" suffix "-d")
+        ((IDOC MEM))
+        (.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 (IDOC MEM))
+         (.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) (IDOC MEM))
+     "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) (IDOC MEM))
+     "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" ((IDOC MEM))
+  "push $src1"
+  (emit st-minus src1 (src2 15)) ; "st %0,@-sp"
+)
+
+(dni sub "sub"
+     ((PIPE OS) (IDOC ALU))
+     "sub $dr,$sr"
+     (+ OP1_0 OP2_2 dr sr)
+     (set dr (sub dr sr))
+     ()
+)
+
+(dni subv "sub:rv"
+     ((PIPE OS) (IDOC ALU))
+     "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) (IDOC ALU))
+     "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) (IDOC MISC))
+     "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) (IDOC MISC))
+     "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) (IDOC ALU))
+     "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) (IDOC ALU))
+     "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 (IDOC ALU))
+     "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 (IDOC ALU))
+     "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) (IDOC ACCUM))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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) (IDOC MAC))
+     "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 (IDOC BR))
+     "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 (IDOC BR))
+     "snc"
+     (+ OP1_7 (f-r1 5) OP2_0 (f-r2 1))
+     (skip (zext INT (not condbit)))
+     ()
+)
diff --git a/cpu/m32r.opc b/cpu/m32r.opc
new file mode 100644 (file)
index 0000000..dbb6f1d
--- /dev/null
@@ -0,0 +1,302 @@
+/* M32R opcode support.  -*- C -*-
+
+   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+   Contributed by Red Hat Inc; developed under contract from
+   Mitsubishi Electric Corporation.
+
+   This file is part of the GNU Binutils.
+
+   Contributed by Red Hat Inc; developed under contract from Fujitsu.
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+
+/* 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"
+*/
+\f
+/* -- 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)))
+
+/* -- */
+\f
+/* -- asm.c */
+static const char * parse_hash
+  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
+static const char * parse_hi16
+  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
+static const char * parse_slo16
+  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
+static const char * parse_ulo16
+  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
+
+/* Handle '#' prefixes (i.e. skip over them).  */
+
+static const char *
+parse_hash (cd, strp, opindex, valuep)
+     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
+     const char **strp;
+     int opindex ATTRIBUTE_UNUSED;
+     unsigned long *valuep ATTRIBUTE_UNUSED;
+{
+  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);
+}
+
+/* -- */
+\f
+/* -- dis.c */
+static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
+static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
+
+/* 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 ATTRIBUTE_UNUSED;
+     PTR dis_info;
+     long value ATTRIBUTE_UNUSED;
+     unsigned int attrs ATTRIBUTE_UNUSED;
+     bfd_vma pc ATTRIBUTE_UNUSED;
+     int length ATTRIBUTE_UNUSED;
+{
+  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;
+}
+
+/* -- */