aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-s12z.c
diff options
context:
space:
mode:
authorJohn Darrington <john@darrington.wattle.id.au>2018-05-18 15:26:18 +0100
committerNick Clifton <nickc@redhat.com>2018-05-18 15:26:18 +0100
commit7b4ae824289504c173a597e86a00ceab452095b7 (patch)
tree98efc51666beecffead172a6c29c4c1f75b14174 /gas/config/tc-s12z.c
parent011b32fd4270fb7111ee1f63695ccd44562ee7df (diff)
downloadgdb-7b4ae824289504c173a597e86a00ceab452095b7.zip
gdb-7b4ae824289504c173a597e86a00ceab452095b7.tar.gz
gdb-7b4ae824289504c173a597e86a00ceab452095b7.tar.bz2
Add support for the Freescale s12z processor.
bfd * Makefile.am: Add s12z files. * Makefile.in: Regenerate. * archures.c: Add bfd_s12z_arch. * bfd-in.h: Add exports of bfd_putb24 and bfd_putl24. * bfd-in2.h: Regenerate. * config.bfd: Add s12z target. * configure.ac: Add s12z target. * configure: Regenerate. * cpu-s12z.c: New file. * elf32-s12z.c: New file. * libbfd.c (bfd_putb24): New function. (bfd_putl24): New function. * libbfd.h: Regenerate. * reloc.c: Add s12z relocations. (bfd_get_reloc_size): Handle size 5 relocs. * targets.c: Add s12z_elf32_vec. opcodes * Makefile.am: Add support for s12z architecture. * configure.ac: Likewise. * disassemble.c: Likewise. * disassemble.h: Likewise. * Makefile.in: Regenerate. * configure: Regenerate. * s12z-dis.c: New file. * s12z.h: New file. include * elf/s12z.h: New header. ld * Makefile.am: Add support for s12z architecture. * configure.tgt: Likewise. * Makefile.in: Regenerate. * emulparams/m9s12zelf.sh: New file. * scripttempl/elfm9s12z.sc: New file. * testsuite/ld-discard/static.d: Expect to fail for the s12z target. * testsuite/ld-elf/endsym.d: Likewise. * testsuite/ld-elf/merge.d: Likewise. * testsuite/ld-elf/pr14926.d: Skip for the s12z target. * testsuite/ld-elf/sec64k.exp: Likewise. * testsuite/ld-s12z: New directory. * testsuite/ld-s12z/opr-linking.d: New file. * testsuite/ld-s12z/opr-linking.s: New file. * testsuite/ld-s12z/relative-linking.d: New file. * testsuite/ld-s12z/relative-linking.s: New file. * testsuite/ld-s12z/z12s.exp: New file. gas * Makefile.am: Add support for s12z target. * Makefile.in: Regenerate. * NEWS: Mention the new support. * config/tc-s12z.c: New file. * config/tc-s12z.h: New file. * configure.tgt: Add s12z support. * doc/Makefile.am: Likewise. * doc/Makefile.in: Regenerate. * doc/all.texi: Add s12z documentation. * doc/as.textinfo: Likewise. * doc/c-s12z.texi: New file. * testsuite/gas/s12z: New directory. * testsuite/gas/s12z/abs.d: New file. * testsuite/gas/s12z/abs.s: New file. * testsuite/gas/s12z/adc-imm.d: New file. * testsuite/gas/s12z/adc-imm.s: New file. * testsuite/gas/s12z/adc-opr.d: New file. * testsuite/gas/s12z/adc-opr.s: New file. * testsuite/gas/s12z/add-imm.d: New file. * testsuite/gas/s12z/add-imm.s: New file. * testsuite/gas/s12z/add-opr.d: New file. * testsuite/gas/s12z/add-opr.s: New file. * testsuite/gas/s12z/and-imm.d: New file. * testsuite/gas/s12z/and-imm.s: New file. * testsuite/gas/s12z/and-opr.d: New file. * testsuite/gas/s12z/and-opr.s: New file. * testsuite/gas/s12z/and-or-cc.d: New file. * testsuite/gas/s12z/and-or-cc.s: New file. * testsuite/gas/s12z/bfext-special.d: New file. * testsuite/gas/s12z/bfext-special.s: New file. * testsuite/gas/s12z/bfext.d: New file. * testsuite/gas/s12z/bfext.s: New file. * testsuite/gas/s12z/bit-manip.d: New file. * testsuite/gas/s12z/bit-manip.s: New file. * testsuite/gas/s12z/bit.d: New file. * testsuite/gas/s12z/bit.s: New file. * testsuite/gas/s12z/bra-expression-defined.d: New file. * testsuite/gas/s12z/bra-expression-defined.s: New file. * testsuite/gas/s12z/bra-expression-undef.d: New file. * testsuite/gas/s12z/bra-expression-undef.s: New file. * testsuite/gas/s12z/bra.d: New file. * testsuite/gas/s12z/bra.s: New file. * testsuite/gas/s12z/brclr-symbols.d: New file. * testsuite/gas/s12z/brclr-symbols.s: New file. * testsuite/gas/s12z/brset-clr-opr-imm-rel.d: New file. * testsuite/gas/s12z/brset-clr-opr-imm-rel.s: New file. * testsuite/gas/s12z/brset-clr-opr-reg-rel.d: New file. * testsuite/gas/s12z/brset-clr-opr-reg-rel.s: New file. * testsuite/gas/s12z/brset-clr-reg-imm-rel.d: New file. * testsuite/gas/s12z/brset-clr-reg-imm-rel.s: New file. * testsuite/gas/s12z/brset-clr-reg-reg-rel.d: New file. * testsuite/gas/s12z/brset-clr-reg-reg-rel.s: New file. * testsuite/gas/s12z/clb.d: New file. * testsuite/gas/s12z/clb.s: New file. * testsuite/gas/s12z/clr-opr.d: New file. * testsuite/gas/s12z/clr-opr.s: New file. * testsuite/gas/s12z/clr.d: New file. * testsuite/gas/s12z/clr.s: New file. * testsuite/gas/s12z/cmp-imm.d: New file. * testsuite/gas/s12z/cmp-imm.s: New file. * testsuite/gas/s12z/cmp-opr-inc.d: New file. * testsuite/gas/s12z/cmp-opr-inc.s: New file. * testsuite/gas/s12z/cmp-opr-rdirect.d: New file. * testsuite/gas/s12z/cmp-opr-rdirect.s: New file. * testsuite/gas/s12z/cmp-opr-reg.d: New file. * testsuite/gas/s12z/cmp-opr-reg.s: New file. * testsuite/gas/s12z/cmp-opr-rindirect.d: New file. * testsuite/gas/s12z/cmp-opr-rindirect.s: New file. * testsuite/gas/s12z/cmp-opr-sxe4.d: New file. * testsuite/gas/s12z/cmp-opr-sxe4.s: New file. * testsuite/gas/s12z/cmp-opr-xys.d: New file. * testsuite/gas/s12z/cmp-opr-xys.s: New file. * testsuite/gas/s12z/cmp-s-imm.d: New file. * testsuite/gas/s12z/cmp-s-imm.s: New file. * testsuite/gas/s12z/cmp-s-opr.d: New file. * testsuite/gas/s12z/cmp-s-opr.s: New file. * testsuite/gas/s12z/cmp-xy.d: New file. * testsuite/gas/s12z/cmp-xy.s: New file. * testsuite/gas/s12z/com-opr.d: New file. * testsuite/gas/s12z/com-opr.s: New file. * testsuite/gas/s12z/complex-shifts.d: New file. * testsuite/gas/s12z/complex-shifts.s: New file. * testsuite/gas/s12z/db-tb-cc-opr.d: New file. * testsuite/gas/s12z/db-tb-cc-opr.s: New file. * testsuite/gas/s12z/db-tb-cc-reg.d: New file. * testsuite/gas/s12z/db-tb-cc-reg.s: New file. * testsuite/gas/s12z/dbCC.d: New file. * testsuite/gas/s12z/dbCC.s: New file. * testsuite/gas/s12z/dec-opr.d: New file. * testsuite/gas/s12z/dec-opr.s: New file. * testsuite/gas/s12z/dec.d: New file. * testsuite/gas/s12z/dec.s: New file. * testsuite/gas/s12z/div.d: New file. * testsuite/gas/s12z/div.s: New file. * testsuite/gas/s12z/eor.d: New file. * testsuite/gas/s12z/eor.s: New file. * testsuite/gas/s12z/exg.d: New file. * testsuite/gas/s12z/exg.s: New file. * testsuite/gas/s12z/ext24-ld-xy.d: New file. * testsuite/gas/s12z/ext24-ld-xy.s: New file. * testsuite/gas/s12z/inc-opr.d: New file. * testsuite/gas/s12z/inc-opr.s: New file. * testsuite/gas/s12z/inc.d: New file. * testsuite/gas/s12z/inc.s: New file. * testsuite/gas/s12z/inh.d: New file. * testsuite/gas/s12z/inh.s: New file. * testsuite/gas/s12z/jmp.d: New file. * testsuite/gas/s12z/jmp.s: New file. * testsuite/gas/s12z/jsr.d: New file. * testsuite/gas/s12z/jsr.s: New file. * testsuite/gas/s12z/ld-imm-page2.d: New file. * testsuite/gas/s12z/ld-imm-page2.s: New file. * testsuite/gas/s12z/ld-imm.d: New file. * testsuite/gas/s12z/ld-imm.s: New file. * testsuite/gas/s12z/ld-immu18.d: New file. * testsuite/gas/s12z/ld-immu18.s: New file. * testsuite/gas/s12z/ld-large-direct.d: New file. * testsuite/gas/s12z/ld-large-direct.s: New file. * testsuite/gas/s12z/ld-opr.d: New file. * testsuite/gas/s12z/ld-opr.s: New file. * testsuite/gas/s12z/ld-s-opr.d: New file. * testsuite/gas/s12z/ld-s-opr.s: New file. * testsuite/gas/s12z/ld-small-direct.d: New file. * testsuite/gas/s12z/ld-small-direct.s: New file. * testsuite/gas/s12z/lea-immu18.d: New file. * testsuite/gas/s12z/lea-immu18.s: New file. * testsuite/gas/s12z/lea.d: New file. * testsuite/gas/s12z/lea.s: New file. * testsuite/gas/s12z/mac.d: New file. * testsuite/gas/s12z/mac.s: New file. * testsuite/gas/s12z/min-max.d: New file. * testsuite/gas/s12z/min-max.s: New file. * testsuite/gas/s12z/mod.d: New file. * testsuite/gas/s12z/mod.s: New file. * testsuite/gas/s12z/mov.d: New file. * testsuite/gas/s12z/mov.s: New file. * testsuite/gas/s12z/mul-imm.d: New file. * testsuite/gas/s12z/mul-imm.s: New file. * testsuite/gas/s12z/mul-opr-opr.d: New file. * testsuite/gas/s12z/mul-opr-opr.s: New file. * testsuite/gas/s12z/mul-opr.d: New file. * testsuite/gas/s12z/mul-opr.s: New file. * testsuite/gas/s12z/mul-reg.d: New file. * testsuite/gas/s12z/mul-reg.s: New file. * testsuite/gas/s12z/mul.d: New file. * testsuite/gas/s12z/mul.s: New file. * testsuite/gas/s12z/neg-opr.d: New file. * testsuite/gas/s12z/neg-opr.s: New file. * testsuite/gas/s12z/not-so-simple-shifts.d: New file. * testsuite/gas/s12z/not-so-simple-shifts.s: New file. * testsuite/gas/s12z/opr-18u.d: New file. * testsuite/gas/s12z/opr-18u.s: New file. * testsuite/gas/s12z/opr-expr.d: New file. * testsuite/gas/s12z/opr-expr.s: New file. * testsuite/gas/s12z/opr-ext-18.d: New file. * testsuite/gas/s12z/opr-ext-18.s: New file. * testsuite/gas/s12z/opr-idx-24-reg.d: New file. * testsuite/gas/s12z/opr-idx-24-reg.s: New file. * testsuite/gas/s12z/opr-idx3-reg.d: New file. * testsuite/gas/s12z/opr-idx3-reg.s: New file. * testsuite/gas/s12z/opr-idx3-xysp-24.d: New file. * testsuite/gas/s12z/opr-idx3-xysp-24.s: New file. * testsuite/gas/s12z/opr-indirect-expr.d: New file. * testsuite/gas/s12z/opr-indirect-expr.s: New file. * testsuite/gas/s12z/opr-symbol.d: New file. * testsuite/gas/s12z/opr-symbol.s: New file. * testsuite/gas/s12z/or-imm.d: New file. * testsuite/gas/s12z/or-imm.s: New file. * testsuite/gas/s12z/or-opr.d: New file. * testsuite/gas/s12z/or-opr.s: New file. * testsuite/gas/s12z/p2-mul.d: New file. * testsuite/gas/s12z/p2-mul.s: New file. * testsuite/gas/s12z/page2-inh.d: New file. * testsuite/gas/s12z/page2-inh.s: New file. * testsuite/gas/s12z/psh-pul.d: New file. * testsuite/gas/s12z/psh-pul.s: New file. * testsuite/gas/s12z/qmul.d: New file. * testsuite/gas/s12z/qmul.s: New file. * testsuite/gas/s12z/rotate.d: New file. * testsuite/gas/s12z/rotate.s: New file. * testsuite/gas/s12z/s12z.exp: New file. * testsuite/gas/s12z/sat.d: New file. * testsuite/gas/s12z/sat.s: New file. * testsuite/gas/s12z/sbc-imm.d: New file. * testsuite/gas/s12z/sbc-imm.s: New file. * testsuite/gas/s12z/sbc-opr.d: New file. * testsuite/gas/s12z/sbc-opr.s: New file. * testsuite/gas/s12z/shift.d: New file. * testsuite/gas/s12z/shift.s: New file. * testsuite/gas/s12z/simple-shift.d: New file. * testsuite/gas/s12z/simple-shift.s: New file. * testsuite/gas/s12z/single-ops.d: New file. * testsuite/gas/s12z/single-ops.s: New file. * testsuite/gas/s12z/specd6.d: New file. * testsuite/gas/s12z/specd6.s: New file. * testsuite/gas/s12z/st-large-direct.d: New file. * testsuite/gas/s12z/st-large-direct.s: New file. * testsuite/gas/s12z/st-opr.d: New file. * testsuite/gas/s12z/st-opr.s: New file. * testsuite/gas/s12z/st-s-opr.d: New file. * testsuite/gas/s12z/st-s-opr.s: New file. * testsuite/gas/s12z/st-small-direct.d: New file. * testsuite/gas/s12z/st-small-direct.s: New file. * testsuite/gas/s12z/st-xy.d: New file. * testsuite/gas/s12z/st-xy.s: New file. * testsuite/gas/s12z/sub-imm.d: New file. * testsuite/gas/s12z/sub-imm.s: New file. * testsuite/gas/s12z/sub-opr.d: New file. * testsuite/gas/s12z/sub-opr.s: New file. * testsuite/gas/s12z/tfr.d: New file. * testsuite/gas/s12z/tfr.s: New file. * testsuite/gas/s12z/trap.d: New file. * testsuite/gas/s12z/trap.s: New file. binutils* readelf.c: Add support for s12z architecture. * testsuite/lib/binutils-common.exp (is_elf_format): Excluse s12z targets.
Diffstat (limited to 'gas/config/tc-s12z.c')
-rw-r--r--gas/config/tc-s12z.c3840
1 files changed, 3840 insertions, 0 deletions
diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
new file mode 100644
index 0000000..e024e72
--- /dev/null
+++ b/gas/config/tc-s12z.c
@@ -0,0 +1,3840 @@
+/* tc-s12z.c -- Assembler code for the Freescale S12Z
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS 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 3, or (at your option)
+ any later version.
+
+ GAS 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 GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "dwarf2dbg.h"
+#include "opcodes/s12z.h"
+#include <stdint.h>
+#include <limits.h>
+#include <stdbool.h>
+
+const char comment_chars[] = ";";
+
+const char line_comment_chars[] = "#*";
+const char line_separator_chars[] = "";
+
+const char EXP_CHARS[] = "eE";
+const char FLT_CHARS[] = "dD";
+
+static char *fail_line_pointer;
+
+
+/* Options and initialization. */
+
+const char *md_shortopts = "Sm:";
+
+struct option md_longopts[] =
+ {
+ };
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+
+relax_typeS md_relax_table[] =
+ {
+
+ };
+
+/* This table describes all the machine specific pseudo-ops the assembler
+ has to support. The fields are:
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function. */
+const pseudo_typeS md_pseudo_table[] =
+ {
+ {0, 0, 0}
+ };
+
+
+/* Get the target cpu for the assembler. */
+const char *
+s12z_arch_format (void)
+{
+ return "elf32-s12z";
+}
+
+enum bfd_architecture
+s12z_arch (void)
+{
+ return bfd_arch_s12z;
+}
+
+int
+s12z_mach (void)
+{
+ return 0;
+}
+
+/* Listing header selected according to cpu. */
+const char *
+s12z_listing_header (void)
+{
+ return "S12Z GAS ";
+}
+
+void
+md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
+{
+}
+
+void
+s12z_print_statistics (FILE *file ATTRIBUTE_UNUSED)
+{
+}
+
+int
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+const char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ return ieee_md_atof (type, litP, sizeP, TRUE);
+}
+
+valueT
+md_section_align (asection *seg, valueT addr)
+{
+ int align = bfd_get_section_alignment (stdoutput, seg);
+ return ((addr + (1 << align) - 1) & -(1 << align));
+}
+
+void
+md_begin (void)
+{
+}
+
+void
+s12z_init_after_args (void)
+{
+}
+
+/* Builtin help. */
+
+
+static char *
+skip_whites (char *p)
+{
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ return p;
+}
+
+
+
+/* Start a new insn that contains at least 'size' bytes. Record the
+ line information of that insn in the dwarf2 debug sections. */
+static char *
+s12z_new_insn (int size)
+{
+ char *f = frag_more (size);
+
+ dwarf2_emit_insn (size);
+
+ return f;
+}
+
+
+
+static int lex_reg_name (uint16_t which, int *reg);
+
+static int
+lex_constant (long *v)
+{
+ char *end = NULL;
+ char *p = input_line_pointer;
+
+ /* A constant may not have the same value as a register
+ eg: "d6" */
+ int dummy;
+ if (lex_reg_name (~0, &dummy))
+ {
+ input_line_pointer = p;
+ return 0;
+ }
+
+ errno = 0;
+ *v = strtol (p, &end, 0);
+ if (errno == 0 && end != p)
+ {
+ input_line_pointer = end;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+lex_match (char x)
+{
+ char *p = input_line_pointer;
+ if (*p != x)
+ return 0;
+
+ input_line_pointer++;
+ return 1;
+}
+
+
+static int
+lex_expression (expressionS *exp)
+{
+ char *ilp = input_line_pointer;
+ int dummy;
+ exp->X_op = O_absent;
+
+ if (lex_match ('#'))
+ goto fail;
+
+ if (lex_reg_name (~0, &dummy))
+ goto fail;
+
+ expression (exp);
+ if (exp->X_op != O_absent)
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+/* immediate operand */
+static int
+lex_imm (long *v)
+{
+ char *ilp = input_line_pointer;
+
+ if (*input_line_pointer != '#')
+ goto fail;
+
+ input_line_pointer++;
+ expressionS exp;
+ if (!lex_expression (&exp))
+ goto fail;
+
+ if (exp.X_op != O_constant)
+ goto fail;
+
+ *v = exp.X_add_number;
+ return 1;
+
+fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+/* Short mmediate operand */
+static int
+lex_imm_e4 (long *val)
+{
+ char *ilp = input_line_pointer;
+ if ((lex_imm (val)))
+ {
+ if ((*val == -1) || (*val > 0 && *val <= 15))
+ {
+ return 1;
+ }
+ }
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+lex_match_string (const char *s)
+{
+ char *p = input_line_pointer;
+ while (p != 0 && *p != '\t' && *p != ' ' && *p != '\0')
+ {
+ p++;
+ }
+
+ size_t len = p - input_line_pointer;
+ if (len != strlen (s))
+ return 0;
+
+ if (0 == strncasecmp (s, input_line_pointer, len))
+ {
+ input_line_pointer = p;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Parse a register name.
+ WHICH is a ORwise combination of the registers which are accepted.
+ ~0 accepts all.
+ On success, REG will be filled with the index of the register which
+ was successfully scanned.
+*/
+static int
+lex_reg_name (uint16_t which, int *reg)
+{
+ char *p = input_line_pointer;
+ while (p != 0 &&
+ ((*p >= 'a' && *p <='z') || (*p >= '0' && *p <= '9') || (*p >= 'A' && *p <='Z')))
+ {
+ p++;
+ }
+
+ int len = p - input_line_pointer;
+
+ if (len <= 0)
+ return 0;
+
+ int i;
+ for (i = 0; i < S12Z_N_REGISTERS; ++i)
+ {
+ gas_assert (registers[i].name);
+
+ if (0 == strncasecmp (registers[i].name, input_line_pointer, len))
+ {
+ if ((0x1U << i) & which)
+ {
+ input_line_pointer = p;
+ *reg = i;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+lex_force_match (char x)
+{
+ char *p = input_line_pointer;
+ if (*p != x)
+ {
+ as_bad (_("Expecting '%c'"), x);
+ return 0;
+ }
+
+ input_line_pointer++;
+ return 1;
+}
+
+static int
+lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp)
+{
+ char *ilp = input_line_pointer;
+ uint8_t *xb = buffer;
+ int reg;
+ long imm;
+ exp->X_op = O_absent;
+ *n_bytes = 0;
+ *xb = 0;
+ if (lex_imm_e4 (&imm))
+ {
+ if (imm > 0)
+ *xb = imm;
+ else
+ *xb = 0;
+ *xb |= 0x70;
+ *n_bytes = 1;
+ return 1;
+ }
+ else if (lex_reg_name (REG_BIT_Dn, &reg))
+ {
+ *xb = reg;
+ *xb |= 0xb8;
+ *n_bytes = 1;
+ return 1;
+ }
+ else if (lex_match ('['))
+ {
+ if (lex_expression (exp))
+ {
+ long c = exp->X_add_number;
+ if (lex_match (','))
+ {
+ if (lex_reg_name (REG_BIT_XYSP, &reg))
+ {
+ int i;
+ if (c <= 255 && c >= -256)
+ {
+ *n_bytes = 2;
+ *xb |= 0xc4;
+ }
+ else
+ {
+ *n_bytes = 4;
+ *xb |= 0xc6;
+ }
+ *xb |= (reg - REG_X) << 4;
+
+ if (c < 0)
+ *xb |= 0x01;
+ for (i = 1; i < *n_bytes ; ++i)
+ {
+ buffer[i] = c >> (8 * (*n_bytes - i - 1));
+ }
+ }
+ else
+ {
+ as_bad (_("Bad operand for constant offset"));
+ goto fail;
+ }
+ }
+ else
+ {
+ *xb = 0xfe;
+ *n_bytes = 4;
+ buffer[1] = c >> 16;
+ buffer[2] = c >> 8;
+ buffer[3] = c;
+ }
+ }
+ else if (lex_reg_name (REG_BIT_Dn, &reg))
+ {
+ if (!lex_force_match (','))
+ goto fail;
+
+ int reg2;
+ if (lex_reg_name (REG_BIT_XY, &reg2))
+ {
+ *n_bytes = 1;
+ *xb = reg;
+ *xb |= (reg2 - REG_X) << 4;
+ *xb |= 0xc8;
+ }
+ else
+ {
+ as_bad (_("Invalid operand for register offset"));
+ goto fail;
+ }
+ }
+ else
+ {
+ goto fail;
+ }
+ if (!lex_force_match (']'))
+ goto fail;
+ return 1;
+ }
+ else if (lex_match ('('))
+ {
+ long c;
+ if (lex_constant (&c))
+ {
+ if (!lex_force_match (','))
+ goto fail;
+ int reg2;
+ if (lex_reg_name (REG_BIT_XYSP, &reg2))
+ {
+ if (reg2 != REG_P && c >= 0 && c <= 15)
+ {
+ *n_bytes = 1;
+ *xb = 0x40;
+ *xb |= (reg2 - REG_X) << 4;
+ *xb |= c;
+ }
+ else if (c >= -256 && c <= 255)
+ {
+ *n_bytes = 2;
+ *xb = 0xc0;
+ *xb |= (reg2 - REG_X) << 4;
+ if (c < 0)
+ *xb |= 0x01;
+ buffer[1] = c;
+ }
+ else
+ {
+ *n_bytes = 4;
+ *xb = 0xc2;
+ *xb |= (reg2 - REG_X) << 4;
+ buffer[1] = c >> 16;
+ buffer[2] = c >> 8;
+ buffer[3] = c;
+ }
+ }
+ else if (lex_reg_name (REG_BIT_Dn, &reg2))
+ {
+ if (c >= -1 * (long) (0x1u << 17)
+ &&
+ c < (long) (0x1u << 17) - 1)
+ {
+ *n_bytes = 3;
+ *xb = 0x80;
+ *xb |= reg2;
+ *xb |= ((c >> 16) & 0x03) << 4;
+ buffer[1] = c >> 8;
+ buffer[2] = c;
+ }
+ else
+ {
+ *n_bytes = 4;
+ *xb = 0xe8;
+ *xb |= reg2;
+ buffer[1] = c >> 16;
+ buffer[2] = c >> 8;
+ buffer[3] = c;
+ }
+ }
+ else
+ {
+ as_bad (_("Bad operand for constant offset"));
+ goto fail;
+ }
+ }
+ else if (lex_reg_name (REG_BIT_Dn, &reg))
+ {
+ if (lex_match (','))
+ {
+ int reg2;
+ if (lex_reg_name (REG_BIT_XYS, &reg2))
+ {
+ *n_bytes = 1;
+ *xb = 0x88;
+ *xb |= (reg2 - REG_X) << 4;
+ *xb |= reg;
+ }
+ else
+ {
+ as_bad (_("Invalid operand for register offset"));
+ goto fail;
+ }
+ }
+ else
+ {
+ goto fail;
+ }
+ }
+ else if (lex_reg_name (REG_BIT_XYS, &reg))
+ {
+ if (lex_match ('-'))
+ {
+ if (reg == REG_S)
+ {
+ as_bad (_("Invalid register for postdecrement operation"));
+ goto fail;
+ }
+ *n_bytes = 1;
+ if (reg == REG_X)
+ *xb = 0xc7;
+ else if (reg == REG_Y)
+ *xb = 0xd7;
+ }
+ else if (lex_match ('+'))
+ {
+ *n_bytes = 1;
+ if (reg == REG_X)
+ *xb = 0xe7;
+ else if (reg == REG_Y)
+ *xb = 0xf7;
+ else if (reg == REG_S)
+ *xb = 0xff;
+ }
+ else
+ {
+ goto fail;
+ }
+ }
+ else if (lex_match ('+'))
+ {
+ if (lex_reg_name (REG_BIT_XY, &reg))
+ {
+ *n_bytes = 1;
+ if (reg == REG_X)
+ *xb = 0xe3;
+ else if (reg == REG_Y)
+ *xb = 0xf3;
+ }
+ else
+ {
+ as_bad (_("Invalid register for preincrement operation"));
+ goto fail;
+ }
+ }
+ else if (lex_match ('-'))
+ {
+ if (lex_reg_name (REG_BIT_XYS, &reg))
+ {
+ *n_bytes = 1;
+ if (reg == REG_X)
+ *xb = 0xc3;
+ else if (reg == REG_Y)
+ *xb = 0xd3;
+ else if (reg == REG_S)
+ *xb = 0xfb;
+ }
+ else
+ {
+ as_bad (_("Invalid register for predecrement operation"));
+ goto fail;
+ }
+ }
+ else
+ {
+ goto fail;
+ }
+
+ if (! lex_match (')'))
+ goto fail;
+ return 1;
+ }
+ else if (lex_expression (exp))
+ {
+ *xb = 0xfa;
+ *n_bytes = 4;
+ buffer[1] = 0;
+ buffer[2] = 0;
+ buffer[3] = 0;
+ if (exp->X_op == O_constant)
+ {
+ if (exp->X_add_number < (0x1U << 14))
+ {
+ *xb = 0x00;
+ *n_bytes = 2;
+ *xb |= exp->X_add_number >> 8;
+ buffer[1] = exp->X_add_number;
+ }
+ else if (exp->X_add_number < (0x1U << 19))
+ {
+ *xb = 0xf8;
+ if (exp->X_add_number & (0x1U << 17))
+ *xb |= 0x04;
+ if (exp->X_add_number & (0x1U << 16))
+ *xb |= 0x01;
+ *n_bytes = 3;
+ buffer[1] = exp->X_add_number >> 8;
+ buffer[2] = exp->X_add_number;
+ }
+ else
+ {
+ *xb = 0xfa;
+ *n_bytes = 4;
+ buffer[1] = exp->X_add_number >> 16;
+ buffer[2] = exp->X_add_number >> 8;
+ buffer[3] = exp->X_add_number;
+ }
+ }
+ return 1;
+ }
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+lex_offset (long *val)
+{
+ char *end = NULL;
+ char *p = input_line_pointer;
+
+ if (*p++ != '*')
+ return 0;
+
+ if (*p != '+' && *p != '-')
+ return 0;
+
+ bool negative = (*p == '-');
+ p++;
+
+ errno = 0;
+ *val = strtol (p, &end, 0);
+ if (errno == 0)
+ {
+ if (negative)
+ *val *= -1;
+ input_line_pointer = end;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+struct instruction;
+
+typedef int (*parse_operand_func) (const struct instruction *);
+
+struct instruction
+{
+ const char *name;
+
+ /* The "page" to which the instruction belongs.
+ This is also only a hint. Some instructions might have modes in both
+ pages... */
+ char page;
+
+ /* This is a hint - and only a hint - about the opcode of the instruction.
+ The parse_operand_func is free to ignore it.
+ */
+ uint8_t opc;
+
+ parse_operand_func parse_operands;
+
+ /* Some instructions can be encoded with a different opcode */
+ uint8_t alt_opc;
+};
+
+static int
+no_operands (const struct instruction *insn)
+{
+ if (*input_line_pointer != '\0')
+ {
+ as_bad (_("Garbage at end of instruction"));
+ return 0;
+ }
+
+ char *f = s12z_new_insn (insn->page);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc, 1);
+
+ return 1;
+}
+
+/* Emit the code for an OPR address mode operand */
+static char *
+emit_opr (char *f, const uint8_t *buffer, int n_bytes, expressionS *exp)
+{
+ int i;
+ number_to_chars_bigendian (f++, buffer[0], 1);
+ if (exp->X_op != O_absent && exp->X_op != O_constant)
+ {
+ fix_new_exp (frag_now,
+ f - frag_now->fr_literal,
+ 3,
+ exp,
+ FALSE,
+ BFD_RELOC_24);
+ }
+ for (i = 1; i < n_bytes; ++i)
+ number_to_chars_bigendian (f++, buffer[i], 1);
+
+ return f;
+}
+
+/* Emit the code for a 24 bit direct address operand */
+static char *
+emit_ext24 (char *f, long v)
+{
+ number_to_chars_bigendian (f, v, 3);
+
+ return f + 3;
+}
+
+static int
+opr (const struct instruction *insn)
+{
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (lex_opr (buffer, &n_bytes, &exp))
+ {
+ /* Large constant direct values are more efficiently encoded as ext24 mode.
+ Otherwise a decision has to be deferred to a relax. */
+ if (exp.X_op == O_constant
+ && buffer[0] == 0xFA
+ && insn->alt_opc != 0)
+ {
+ char *f = s12z_new_insn (4);
+
+ /* I don't think there are any instances of page 2 opcodes in this case */
+ gas_assert (insn->page == 1);
+
+ number_to_chars_bigendian (f++, insn->alt_opc, 1);
+
+ emit_ext24 (f, exp.X_add_number);
+ }
+ else
+ {
+ char *f = s12z_new_insn (n_bytes + 1);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Parse a 15 bit offset, as an expression.
+ LONG_DISPLACEMENT will be set to true if the offset is wider than 7 bits.
+ */
+static int
+lex_15_bit_offset (bool *long_displacement, expressionS *exp)
+{
+ char *ilp = input_line_pointer;
+
+ long val;
+ if (lex_offset (&val))
+ {
+ exp->X_op = O_absent;
+ exp->X_add_number = val;
+ }
+ else if (lex_expression (exp))
+ {
+ if (exp->X_op == O_constant)
+ {
+ val = exp->X_add_number;
+ }
+ else
+ {
+ /* If a symbol was parsed we don't know the displacement.
+ We have to assume it is long, and relax it later if possible. */
+ *long_displacement = true;
+ return 1;
+ }
+ }
+ else
+ {
+ exp->X_op = O_absent;
+ goto fail;
+ }
+
+ if (val > 0x3FFF || val < -0x4000)
+ {
+ as_fatal (_("Offset is outside of 15 bit range"));
+ return 0;
+ }
+
+ *long_displacement = (val > 63 || val < -64);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static void
+emit_15_bit_offset (char *f, int where, expressionS *exp)
+{
+ gas_assert (exp);
+ if (exp->X_op != O_absent && exp->X_op != O_constant)
+ {
+ exp->X_add_number += where;
+ fixS *fix = fix_new_exp (frag_now,
+ f - frag_now->fr_literal,
+ 2,
+ exp,
+ TRUE,
+ BFD_RELOC_16_PCREL);
+ fix->fx_addnumber = where - 2;
+ }
+ else
+ {
+ long val = exp->X_add_number;
+ bool long_displacement = (val > 63 || val < -64);
+ if (long_displacement)
+ val |= 0x8000;
+ else
+ val &= 0x7F;
+
+ number_to_chars_bigendian (f++, val, long_displacement ? 2 : 1);
+ }
+}
+
+static int
+rel (const struct instruction *insn)
+{
+ bool long_displacement;
+
+ expressionS exp;
+ if (! lex_15_bit_offset (&long_displacement, &exp))
+ return 0;
+
+ char *f = s12z_new_insn (long_displacement ? 3 : 2);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ emit_15_bit_offset (f, 3, &exp);
+ return 1;
+}
+
+static int
+reg_inh (const struct instruction *insn)
+{
+ int reg;
+ if (lex_reg_name (REG_BIT_Dn, &reg))
+ {
+ char *f = s12z_new_insn (insn->page);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + reg, 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Special case for CLR X and CLR Y */
+static int
+clr_xy (const struct instruction *insn ATTRIBUTE_UNUSED)
+{
+ int reg;
+ if (lex_reg_name (REG_BIT_XY, &reg))
+ {
+ char *f = s12z_new_insn (1);
+ number_to_chars_bigendian (f, 0x9a + reg - REG_X, 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Some instructions have a suffix like ".l", ".b", ".w" etc
+ which indicates the size of the operands. */
+static int
+size_from_suffix (const struct instruction *insn, int idx)
+{
+ const char *dot = strchr (insn->name, '.');
+
+ if (dot == NULL)
+ return -3;
+
+ int size = -2;
+ switch (dot[1 + idx])
+ {
+ case 'b':
+ size = 1;
+ break;
+ case 'w':
+ size = 2;
+ break;
+ case 'p':
+ size = 3;
+ break;
+ case 'l':
+ size = 4;
+ break;
+ default:
+ as_fatal (_("Bad size"));
+ };
+
+ return size;
+}
+
+static int
+mul_reg_reg_reg (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int Dd;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dj;
+ if (!lex_reg_name (REG_BIT_Dn, &Dj))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dk;
+ if (!lex_reg_name (REG_BIT_Dn, &Dk))
+ goto fail;
+
+ char *f = s12z_new_insn (insn->page + 1);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + Dd, 1);
+ const char *dot = strchrnul (insn->name, '.');
+ uint8_t mb ;
+ switch (dot[-1])
+ {
+ case 's':
+ mb = 0x80;
+ break;
+ case 'u':
+ mb = 0x00;
+ break;
+ default:
+ as_fatal (_("BAD MUL"));
+ break;
+ }
+
+ mb |= Dj << 3;
+ mb |= Dk;
+
+ number_to_chars_bigendian (f++, mb, 1);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+mul_reg_reg_imm (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int Dd;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dj;
+ if (!lex_reg_name (REG_BIT_Dn, &Dj))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long imm;
+ if (!lex_imm (&imm))
+ goto fail;
+
+
+ int size = size_from_suffix (insn, 0);
+
+ char *f = s12z_new_insn (insn->page + 1 + size);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + Dd, 1);
+ uint8_t mb = 0x44;
+ const char *dot = strchrnul (insn->name, '.');
+ switch (dot[-1])
+ {
+ case 's':
+ mb |= 0x80;
+ break;
+ case 'u':
+ mb |= 0x00;
+ break;
+ default:
+ as_fatal (_("BAD MUL"));
+ break;
+ }
+
+ mb |= Dj << 3;
+ mb |= size - 1;
+
+ number_to_chars_bigendian (f++, mb, 1);
+ number_to_chars_bigendian (f++, imm, size);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+mul_reg_reg_opr (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int Dd;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dj;
+ if (!lex_reg_name (REG_BIT_Dn, &Dj))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ int size = size_from_suffix (insn, 0);
+
+ char *f = s12z_new_insn (insn->page + 1 + n_bytes);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + Dd, 1);
+ uint8_t mb = 0x40;
+ const char *dot = strchrnul (insn->name, '.');
+ switch (dot[-1])
+ {
+ case 's':
+ mb |= 0x80;
+ break;
+ case 'u':
+ mb |= 0x00;
+ break;
+ default:
+ as_fatal (_("BAD MUL"));
+ break;
+ }
+
+ mb |= Dj << 3;
+ mb |= size - 1;
+
+ number_to_chars_bigendian (f++, mb, 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+mul_reg_opr_opr (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int Dd;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer1[4];
+ int n_bytes1;
+ expressionS exp1;
+ if (!lex_opr (buffer1, &n_bytes1, &exp1))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer2[4];
+ int n_bytes2;
+ expressionS exp2;
+ if (!lex_opr (buffer2, &n_bytes2, &exp2))
+ goto fail;
+
+ int size1 = size_from_suffix (insn, 0);
+ int size2 = size_from_suffix (insn, 1);
+
+ char *f = s12z_new_insn (insn->page + 1 + n_bytes1 + n_bytes2);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + Dd, 1);
+ uint8_t mb = 0x42;
+ const char *dot = strchrnul (insn->name, '.');
+ switch (dot[-1])
+ {
+ case 's':
+ mb |= 0x80;
+ break;
+ case 'u':
+ mb |= 0x00;
+ break;
+ default:
+ as_fatal (_("BAD MUL"));
+ break;
+ }
+
+ mb |= (size1 - 1) << 4;
+ mb |= (size2 - 1) << 2;
+ number_to_chars_bigendian (f++, mb, 1);
+
+ f = emit_opr (f, buffer1, n_bytes1, &exp1);
+ f = emit_opr (f, buffer2, n_bytes2, &exp2);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+#define REG_BIT_GRP0 \
+ ((0x1U << REG_D2) | \
+ (0x1U << REG_D3) | \
+ (0x1U << REG_CCH) | \
+ (0x1U << REG_CCL) | \
+ (0x1U << REG_D0) | \
+ (0x1U << REG_D1))
+
+#define REG_BIT_GRP1 \
+ ((0x1U << REG_D4) | \
+ (0x1U << REG_D5) | \
+ (0x1U << REG_D6) | \
+ (0x1U << REG_D7) | \
+ (0x1U << REG_X) | \
+ (0x1U << REG_Y))
+
+static const uint8_t reg_map [] =
+ {
+ 0x02, // D2
+ 0x01, // D3
+ 0x20,
+ 0x10, // D5
+ 0x08, // D0
+ 0x04, // D1
+ 0x08, // D6
+ 0x04, // D7
+ 0x02,
+ 0x01, // Y
+ 0x00,
+ 0x00,
+ 0x20, // CCH
+ 0x10, // CCL
+ 0x00
+ };
+
+static int
+lex_reg_list (uint16_t grp, uint16_t *reg_bits)
+{
+ if (lex_match (','))
+ {
+ int reg;
+ if (!lex_reg_name (grp, &reg))
+ return 0;
+ *reg_bits |= 0x1u << reg;
+ lex_reg_list (grp, reg_bits);
+ }
+
+ /* Empty list */
+ return 1;
+}
+
+static int
+psh_pull (const struct instruction *insn)
+{
+ uint8_t pb =
+ (0 == strcmp ("pul", insn->name)) ? 0x80: 0x00;
+
+ if (lex_match_string ("all16b"))
+ {
+ pb |= 0x40;
+ }
+ else if (lex_match_string ("all"))
+ {
+ /* Nothing to do */
+ }
+ else
+ {
+ int reg1;
+ if (!lex_reg_name (REG_BIT_GRP1 | REG_BIT_GRP0, &reg1))
+ goto fail;
+ uint16_t admitted_group = 0;
+
+ if ((0x1U << reg1) & REG_BIT_GRP1)
+ admitted_group = REG_BIT_GRP1;
+ else if ((0x1U << reg1) & REG_BIT_GRP0)
+ admitted_group = REG_BIT_GRP0;
+
+ uint16_t reg_bits = 0x1 << reg1;
+ if (!lex_reg_list (admitted_group, &reg_bits))
+ goto fail;
+
+ if (reg_bits & REG_BIT_GRP1)
+ pb |= 0x40;
+
+ int i;
+ for (i = 0; i < 16; ++i)
+ {
+ if (reg_bits & (0x1u << i))
+ pb |= reg_map[i];
+ }
+ }
+
+ char *f = s12z_new_insn (2);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, pb, 1);
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ return 0;
+}
+
+
+static int
+tfr (const struct instruction *insn)
+{
+ int reg1;
+ if (!lex_reg_name (~0, &reg1))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int reg2;
+ if (!lex_reg_name (~0, &reg2))
+ goto fail;
+
+ if ((0 == strcasecmp ("sex", insn->name))
+ || (0 == strcasecmp ("zex", insn->name)))
+ {
+ if (registers[reg1].bytes >= registers[reg2].bytes)
+ {
+ as_bad (_("Source register for %s must be smaller that the destination register"),
+ insn->name);
+ goto fail;
+ }
+ }
+
+ char *f = s12z_new_insn (1 + insn->page);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, reg1 << 4 | reg2, 1);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ return 0;
+}
+
+static int
+imm8 (const struct instruction *insn)
+{
+ long imm;
+ if (! lex_imm (&imm))
+ return 0;
+ if (imm > 127 || imm < -128)
+ {
+ as_bad (_("Immediate value %ld is out of range for instruction %s"),
+ imm, insn->name);
+ }
+
+ char *f = s12z_new_insn (2);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, imm, 1);
+
+ return 1;
+}
+
+static int
+reg_imm (const struct instruction *insn, int allowed_reg)
+{
+ char *ilp = input_line_pointer;
+ int reg;
+ if (lex_reg_name (allowed_reg, &reg))
+ {
+ if (!lex_force_match (','))
+ goto fail;
+ long imm;
+ if (! lex_imm (&imm))
+ goto fail;
+
+ short size = registers[reg].bytes;
+ char *f = s12z_new_insn (insn->page + size);
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + reg, 1);
+ number_to_chars_bigendian (f++, imm, size);
+ return 1;
+ }
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+regd_imm (const struct instruction *insn)
+{
+ return reg_imm (insn, REG_BIT_Dn);
+}
+
+static int
+regdxy_imm (const struct instruction *insn)
+{
+ return reg_imm (insn, REG_BIT_Dn | REG_BIT_XY);
+}
+
+
+static int
+regs_imm (const struct instruction *insn)
+{
+ return reg_imm (insn, 0x1U << REG_S);
+}
+
+static int
+trap_imm (const struct instruction *insn ATTRIBUTE_UNUSED)
+{
+ long imm = -1;
+ if (! lex_imm (&imm))
+ goto fail;
+
+ if (imm < 0x92 || imm > 0xFF ||
+ (imm >= 0xA0 && imm <= 0xA7) ||
+ (imm >= 0xB0 && imm <= 0xB7))
+ {
+ as_bad (_("trap value %ld is not valid"), imm);
+ return 0;
+ }
+ else
+ {
+ char *f = s12z_new_insn (2);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, imm & 0xFF, 1);
+ return 1;
+ }
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ return 0;
+}
+
+
+
+/* Special one byte instruction CMP X, Y */
+static int
+regx_regy (const struct instruction *insn)
+{
+ int reg;
+ if (lex_reg_name (0x1U << REG_X, &reg))
+ {
+ if (lex_force_match (','))
+ {
+ if (lex_reg_name (0x1U << REG_Y, &reg))
+ {
+ char *f = s12z_new_insn (1);
+ number_to_chars_bigendian (f, insn->opc, 1);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Special one byte instruction SUB D6, X, Y */
+static int
+regd6_regx_regy (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+ int reg;
+ if (!lex_reg_name (0x1U << REG_D6, &reg))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ if (!lex_reg_name (0x1U << REG_X, &reg))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ if (!lex_reg_name (0x1U << REG_Y, &reg))
+ goto fail;
+
+ char *f = s12z_new_insn (1);
+ number_to_chars_bigendian (f, insn->opc, 1);
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+/* Special one byte instruction SUB D6, Y, X */
+static int
+regd6_regy_regx (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+ int reg;
+ if (!lex_reg_name (0x1U << REG_D6, &reg))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ if (!lex_reg_name (0x1U << REG_Y, &reg))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ if (!lex_reg_name (0x1U << REG_X, &reg))
+ goto fail;
+
+ char *f = s12z_new_insn (1);
+ number_to_chars_bigendian (f, insn->opc, 1);
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+reg_opr (const struct instruction *insn, int allowed_regs)
+{
+ char *ilp = input_line_pointer;
+ int reg;
+ if (lex_reg_name (allowed_regs, &reg))
+ {
+ if (!lex_force_match (','))
+ goto fail;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (lex_opr (buffer, &n_bytes, &exp))
+ {
+ /* Large constant direct values are more efficiently encoded as ext24 mode.
+ Otherwise a decision has to be deferred to a relax. */
+ if (exp.X_op == O_constant
+ && buffer[0] == 0xFA
+ && insn->alt_opc != 0)
+ {
+ char *f = s12z_new_insn (4);
+
+ /* I don't think there are any instances of page 2 opcodes in this case */
+ gas_assert (insn->page == 1);
+
+ number_to_chars_bigendian (f++, insn->alt_opc + reg, 1);
+
+ emit_ext24 (f, exp.X_add_number);
+ }
+ else
+ {
+ char *f = s12z_new_insn (n_bytes + insn->page);
+
+ if (insn->page == 2)
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+
+ number_to_chars_bigendian (f++, insn->opc + reg, 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+ }
+
+ return 1;
+ }
+ }
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+regdxy_opr (const struct instruction *insn)
+{
+ return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY);
+}
+
+static int
+regd_opr (const struct instruction *insn)
+{
+ return reg_opr (insn, REG_BIT_Dn);
+}
+
+
+static int
+regs_opr (const struct instruction *insn)
+{
+ return reg_opr (insn, 0x1U << REG_S);
+}
+
+static int
+imm_opr (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+ long imm;
+ if (!lex_imm (&imm))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ int size = size_from_suffix (insn, 0);
+ char *f = s12z_new_insn (1 + n_bytes + size);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+
+ int i;
+ for (i = 0; i < size; ++i)
+ number_to_chars_bigendian (f++, imm >> (CHAR_BIT * (size - i - 1)), 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+opr_opr (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer1[4];
+ int n_bytes1;
+ expressionS exp1;
+ if (!lex_opr (buffer1, &n_bytes1, &exp1))
+ goto fail;
+
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer2[4];
+ int n_bytes2;
+ expressionS exp2;
+ if (!lex_opr (buffer2, &n_bytes2, &exp2))
+ goto fail;
+
+ char *f = s12z_new_insn (1 + n_bytes1 + n_bytes2);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+
+ f = emit_opr (f, buffer1, n_bytes1, &exp1);
+ f = emit_opr (f, buffer2, n_bytes2, &exp2);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+reg67sxy_opr (const struct instruction *insn)
+{
+ int reg;
+ if (!lex_reg_name (REG_BIT_XYS | (0x1U << REG_D6) | (0x1U << REG_D7), &reg))
+ return 0;
+
+ if (!lex_match (','))
+ return 0;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ return 0;
+
+ char *f = s12z_new_insn (1 + n_bytes);
+ number_to_chars_bigendian (f++, insn->opc + reg - REG_D6, 1);
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+}
+
+static int
+rotate (const struct instruction *insn, short dir)
+{
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (lex_opr (buffer, &n_bytes, &exp))
+ {
+ char *f = s12z_new_insn (n_bytes + 2);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ int size = size_from_suffix (insn, 0);
+ if (size < 0)
+ size = 1;
+ uint8_t sb = 0x24;
+ sb |= size - 1;
+ if (dir)
+ sb |= 0x40;
+ number_to_chars_bigendian (f++, sb, 1);
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+rol (const struct instruction *insn)
+{
+ return rotate (insn, 1);
+}
+
+static int
+ror (const struct instruction *insn)
+{
+ return rotate (insn, 0);
+}
+
+
+/* Shift instruction with a register operand and an immediate #1 or #2
+ left = 1; right = 0;
+ logical = 0; arithmetic = 1;
+*/
+static int
+lex_shift_reg_imm1 (const struct instruction *insn, short type, short dir)
+{
+ /*
+ This function is highly unusual and a bit wierd!
+ It first matches the input against a register {d0, d1, ... d7} followed by an immediate
+ {#1, #2}.
+ Then, it rewinds the input and parses it again as a OPR.
+ */
+ char *ilp = input_line_pointer;
+
+ int Dd;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ {
+ goto fail;
+ }
+
+ if (!lex_match (','))
+ goto fail;
+
+ long imm = -1;
+ if (!lex_imm (&imm))
+ goto fail;
+
+ if (imm != 1 && imm != 2)
+ goto fail;
+ input_line_pointer = ilp;
+
+ /* Now parse the first operand again */
+
+ uint8_t buffer[4];
+ int n_bytes;
+
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ gas_assert (n_bytes == 1);
+
+ uint8_t sb = 0x34;
+ sb |= dir << 6;
+ sb |= type << 7;
+ if (imm == 2)
+ sb |= 0x08;
+
+ char *f = s12z_new_insn (3);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, sb, 1);
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+/* Shift instruction with a register operand.
+ left = 1; right = 0;
+ logical = 0; arithmetic = 1; */
+static int
+lex_shift_reg (const struct instruction *insn, short type, short dir)
+{
+ int Dd, Ds, Dn;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ {
+ goto fail;
+ }
+
+ if (!lex_match (','))
+ goto fail;
+
+ if (!lex_reg_name (REG_BIT_Dn, &Ds))
+ {
+ goto fail;
+ }
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t sb = 0x10;
+ sb |= Ds;
+ sb |= dir << 6;
+ sb |= type << 7;
+ long imm;
+ if (lex_reg_name (REG_BIT_Dn, &Dn))
+ {
+ char *f = s12z_new_insn (3);
+ number_to_chars_bigendian (f++, insn->opc | Dd, 1);
+ number_to_chars_bigendian (f++, sb, 1);
+ uint8_t xb = 0xb8;
+ xb |= Dn;
+ number_to_chars_bigendian (f++, xb, 1);
+
+ return 1;
+ }
+ else if (lex_imm (&imm))
+ {
+ if (imm < 0 || imm > 31)
+ {
+ as_bad (_("Shift value should be in the range [0,31]"));
+ goto fail;
+ }
+
+ int n_bytes = 3;
+ if (imm == 1 || imm == 2)
+ {
+ n_bytes = 2;
+ sb &= ~0x10;
+ }
+ else
+ {
+ sb |= (imm & 0x01) << 3;
+ }
+
+ char *f = s12z_new_insn (n_bytes);
+ number_to_chars_bigendian (f++, insn->opc | Dd, 1);
+ number_to_chars_bigendian (f++, sb, 1);
+ if (n_bytes > 2)
+ {
+ uint8_t xb = 0x70;
+ xb |= imm >> 1;
+ number_to_chars_bigendian (f++, xb, 1);
+ }
+
+ return 1;
+ }
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ return 0;
+}
+
+static void
+impute_shift_dir_and_type (const struct instruction *insn, short *type, short *dir)
+{
+ *dir = -1;
+ *type = -1;
+ switch (insn->name[0])
+ {
+ case 'l':
+ *type = 0;
+ break;
+ case 'a':
+ *type = 1;
+ break;
+ default:
+ as_fatal (_("Bad shift mode"));
+ break;
+ }
+
+ switch (insn->name[2])
+ {
+ case 'l':
+ *dir = 1;
+ break;
+ case 'r':
+ *dir = 0;
+ break;
+ default:
+ as_fatal (_("Bad shift *direction"));
+ break;
+ }
+}
+
+/* Shift instruction with a OPR operand */
+static int
+shift_two_operand (const struct instruction *insn)
+{
+ uint8_t sb = 0x34;
+ char *ilp = input_line_pointer;
+
+ short dir = -1;
+ short type = -1;
+ impute_shift_dir_and_type (insn, &type, &dir);
+ sb |= dir << 6;
+ sb |= type << 7;
+
+ int size = size_from_suffix (insn, 0);
+ sb |= size - 1;
+
+ uint8_t buffer[4];
+ int n_opr_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long imm = -1;
+ if (!lex_imm (&imm))
+ goto fail;
+
+ if (imm != 1 && imm != 2)
+ goto fail;
+
+ if (imm == 2)
+ sb |= 0x08;
+
+ char *f = s12z_new_insn (2 + n_opr_bytes);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, sb, 1);
+ emit_opr (f, buffer, n_opr_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+/* Shift instruction with a OPR operand */
+static int
+shift_opr_imm (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ short dir = -1;
+ short type = -1;
+ impute_shift_dir_and_type (insn, &type, &dir);
+
+ int Dd = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int n_bytes = 2;
+
+ uint8_t buffer1[4];
+ int n_opr_bytes1;
+
+ expressionS exp1;
+ if (!lex_opr (buffer1, &n_opr_bytes1, &exp1))
+ goto fail;
+
+ n_bytes += n_opr_bytes1;
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer2[4];
+ int n_opr_bytes2 = 0;
+ expressionS exp2;
+ long imm;
+ bool immediate = false;
+ if (lex_imm (&imm))
+ {
+ immediate = true;
+ }
+ else if (!lex_opr (buffer2, &n_opr_bytes2, &exp2))
+ goto fail;
+
+ uint8_t sb = 0x20;
+
+ int size = size_from_suffix (insn, 0);
+
+ if (size != -1)
+ sb |= size - 1;
+
+ sb |= dir << 6;
+ sb |= type << 7;
+
+ if (immediate)
+ {
+ if (imm == 2 || imm == 1)
+ {
+ if (imm == 2)
+ sb |= 0x08;
+ }
+ else
+ {
+ n_bytes++;
+ sb |= 0x10;
+ if (imm % 2)
+ sb |= 0x08;
+ }
+ }
+ else
+ {
+ n_bytes += n_opr_bytes2;
+ sb |= 0x10;
+ }
+
+ char *f = s12z_new_insn (n_bytes);
+ number_to_chars_bigendian (f++, insn->opc | Dd, 1);
+ number_to_chars_bigendian (f++, sb, 1);
+ f = emit_opr (f, buffer1, n_opr_bytes1, &exp1);
+ if (immediate)
+ {
+ if (imm != 1 && imm != 2)
+ {
+ number_to_chars_bigendian (f++, 0x70 | (imm >> 1), 1);
+ }
+ }
+ else
+ {
+ f = emit_opr (f, buffer2, n_opr_bytes2, &exp2);
+ }
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+/* Shift instruction with a register operand */
+static int
+shift_reg (const struct instruction *insn)
+{
+ short dir = -1;
+ short type = -1;
+ impute_shift_dir_and_type (insn, &type, &dir);
+
+ if (lex_shift_reg_imm1 (insn, type, dir))
+ return 1;
+
+ return lex_shift_reg (insn, type, dir);
+}
+
+static int
+bm_regd_imm (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+ int Di = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Di))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long imm;
+ if (!lex_imm (&imm))
+ goto fail;
+
+
+ uint8_t bm = imm << 3;
+ bm |= Di;
+
+ char *f = s12z_new_insn (2);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+bm_opr_reg (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer[4];
+ int n_opr_bytes;
+
+ expressionS exp;
+ if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dn = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dn))
+ goto fail;
+
+ uint8_t bm = Dn << 4;
+ int size = size_from_suffix (insn, 0);
+ bm |= (size - 1) << 2;
+ bm |= 0x81;
+
+ char *f = s12z_new_insn (2 + n_opr_bytes);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+
+ emit_opr (f, buffer, n_opr_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+bm_opr_imm (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer[4];
+ int n_opr_bytes;
+
+ expressionS exp;
+ if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+
+ long imm;
+ if (!lex_imm (&imm))
+ goto fail;
+
+ int size = size_from_suffix (insn, 0);
+
+ if (imm < 0 || imm >= size * 8)
+ {
+ as_bad (_("Immediate operand %ld is inappropriate for size of instruction"), imm);
+ goto fail;
+ }
+
+ uint8_t bm = 0x80;
+ if (size == 2)
+ bm |= 0x02;
+ else if (size == 4)
+ bm |= 0x08;
+ bm |= (imm & 0x07) << 4;
+ bm |= (imm >> 3);
+
+
+ char *f = s12z_new_insn (2 + n_opr_bytes);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+ emit_opr (f, buffer, n_opr_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+bm_regd_reg (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+ int Di = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Di))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dn = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dn))
+ goto fail;
+
+ uint8_t bm = Dn << 4;
+ bm |= 0x81;
+
+ uint8_t xb = Di | 0xb8;
+
+ char *f = s12z_new_insn (3);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+ number_to_chars_bigendian (f++, xb, 1);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+
+
+
+static int
+bf_reg_opr_imm (const struct instruction *insn, short ie)
+{
+ char *ilp = input_line_pointer;
+ int Dd = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t buffer[4];
+ int n_bytes;
+
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long width;
+ if (!lex_imm (&width))
+ goto fail;
+
+ if (width < 0 || width > 31)
+ {
+ as_bad (_("Invalid width value for %s"), insn->name);
+ goto fail;
+ }
+
+ if (!lex_match (':'))
+ goto fail;
+
+ long offset;
+ if (!lex_constant (&offset))
+ goto fail;
+
+ if (offset < 0 || offset > 31)
+ {
+ as_bad (_("Invalid offset value for %s"), insn->name);
+ goto fail;
+ }
+
+ uint8_t i1 = width << 5;
+ i1 |= offset;
+
+ int size = size_from_suffix (insn, 0);
+ uint8_t bb = ie ? 0x80 : 0x00;
+ bb |= 0x60;
+ bb |= (size - 1) << 2;
+ bb |= width >> 3;
+
+ char *f = s12z_new_insn (4 + n_bytes);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, 0x08 | Dd, 1);
+ number_to_chars_bigendian (f++, bb, 1);
+ number_to_chars_bigendian (f++, i1, 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+bf_opr_reg_imm (const struct instruction *insn, short ie)
+{
+ char *ilp = input_line_pointer;
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Ds = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Ds))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long width;
+ if (!lex_imm (&width))
+ goto fail;
+
+ if (width < 0 || width > 31)
+ {
+ as_bad (_("Invalid width value for %s"), insn->name);
+ goto fail;
+ }
+
+ if (!lex_match (':'))
+ goto fail;
+
+ long offset;
+ if (!lex_constant (&offset))
+ goto fail;
+
+ if (offset < 0 || offset > 31)
+ {
+ as_bad (_("Invalid offset value for %s"), insn->name);
+ goto fail;
+ }
+
+ uint8_t i1 = width << 5;
+ i1 |= offset;
+
+ int size = size_from_suffix (insn, 0);
+ uint8_t bb = ie ? 0x80 : 0x00;
+ bb |= 0x70;
+ bb |= (size - 1) << 2;
+ bb |= width >> 3;
+
+ char *f = s12z_new_insn (4 + n_bytes);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, 0x08 | Ds, 1);
+ number_to_chars_bigendian (f++, bb, 1);
+ number_to_chars_bigendian (f++, i1, 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+
+static int
+bf_reg_reg_imm (const struct instruction *insn, short ie)
+{
+ char *ilp = input_line_pointer;
+ int Dd = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Ds = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Ds))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long width;
+ if (!lex_imm (&width))
+ goto fail;
+
+ if (width < 0 || width > 31)
+ {
+ as_bad (_("Invalid width value for %s"), insn->name);
+ goto fail;
+ }
+
+ if (!lex_match (':'))
+ goto fail;
+
+ long offset;
+ if (!lex_constant (&offset))
+ goto fail;
+
+ if (offset < 0 || offset > 31)
+ {
+ as_bad (_("Invalid offset value for %s"), insn->name);
+ goto fail;
+ }
+
+ uint8_t bb = ie ? 0x80 : 0x00;
+ bb |= 0x20;
+ bb |= Ds << 2;
+ bb |= width >> 3;
+
+ uint8_t i1 = width << 5;
+ i1 |= offset;
+
+ char *f = s12z_new_insn (4);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, 0x08 | Dd, 1);
+ number_to_chars_bigendian (f++, bb, 1);
+ number_to_chars_bigendian (f++, i1, 1);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+bf_reg_reg_reg (const struct instruction *insn ATTRIBUTE_UNUSED, short ie)
+{
+ char *ilp = input_line_pointer;
+ int Dd = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Ds = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Ds))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dp = 0;
+ if (!lex_reg_name ((0x01u << REG_D2) |
+ (0x01u << REG_D3) |
+ (0x01u << REG_D4) |
+ (0x01u << REG_D5),
+ &Dp))
+ goto fail;
+
+ uint8_t bb = ie ? 0x80 : 0x00;
+ bb |= Ds << 2;
+ bb |= Dp;
+
+ char *f = s12z_new_insn (3);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, 0x08 | Dd, 1);
+ number_to_chars_bigendian (f++, bb , 1);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+bf_opr_reg_reg (const struct instruction *insn, short ie)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+
+ int Ds = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Ds))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+
+ int Dp = 0;
+ if (!lex_reg_name ((0x01u << REG_D2) |
+ (0x01u << REG_D3) |
+ (0x01u << REG_D4) |
+ (0x01u << REG_D5),
+ &Dp))
+ goto fail;
+
+ int size = size_from_suffix (insn, 0);
+ uint8_t bb = ie ? 0x80 : 0x00;
+ bb |= 0x50;
+ bb |= Dp;
+ bb |= (size - 1) << 2;
+
+ char *f = s12z_new_insn (3 + n_bytes);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, 0x08 | Ds, 1);
+ number_to_chars_bigendian (f++, bb , 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+bf_reg_opr_reg (const struct instruction *insn, short ie)
+{
+ char *ilp = input_line_pointer;
+ int Dd = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dd))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dp = 0;
+ if (!lex_reg_name ((0x01u << REG_D2) |
+ (0x01u << REG_D3) |
+ (0x01u << REG_D4) |
+ (0x01u << REG_D5),
+ &Dp))
+ goto fail;
+
+ int size = size_from_suffix (insn, 0);
+ uint8_t bb = ie ? 0x80 : 0x00;
+ bb |= 0x40;
+ bb |= Dp;
+ bb |= (size - 1) << 2;
+
+ char *f = s12z_new_insn (3 + n_bytes);
+ number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
+ number_to_chars_bigendian (f++, 0x08 | Dd, 1);
+ number_to_chars_bigendian (f++, bb , 1);
+
+ emit_opr (f, buffer, n_bytes, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+
+static int
+bfe_reg_reg_reg (const struct instruction *insn)
+{
+ return bf_reg_reg_reg (insn, 0);
+}
+
+static int
+bfi_reg_reg_reg (const struct instruction *insn)
+{
+ return bf_reg_reg_reg (insn, 1);
+}
+
+static int
+bfe_reg_reg_imm (const struct instruction *insn)
+{
+ return bf_reg_reg_imm (insn, 0);
+}
+
+static int
+bfi_reg_reg_imm (const struct instruction *insn)
+{
+ return bf_reg_reg_imm (insn, 1);
+}
+
+
+static int
+bfe_reg_opr_reg (const struct instruction *insn)
+{
+ return bf_reg_opr_reg (insn, 0);
+}
+
+static int
+bfi_reg_opr_reg (const struct instruction *insn)
+{
+ return bf_reg_opr_reg (insn, 1);
+}
+
+
+static int
+bfe_opr_reg_reg (const struct instruction *insn)
+{
+ return bf_opr_reg_reg (insn, 0);
+}
+
+static int
+bfi_opr_reg_reg (const struct instruction *insn)
+{
+ return bf_opr_reg_reg (insn, 1);
+}
+
+static int
+bfe_reg_opr_imm (const struct instruction *insn)
+{
+ return bf_reg_opr_imm (insn, 0);
+}
+
+static int
+bfi_reg_opr_imm (const struct instruction *insn)
+{
+ return bf_reg_opr_imm (insn, 1);
+}
+
+static int
+bfe_opr_reg_imm (const struct instruction *insn)
+{
+ return bf_opr_reg_imm (insn, 0);
+}
+
+static int
+bfi_opr_reg_imm (const struct instruction *insn)
+{
+ return bf_opr_reg_imm (insn, 1);
+}
+
+
+
+
+static int
+tb_reg_rel (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int reg;
+ if (!lex_reg_name (REG_BIT_Dn | REG_BIT_XY, &reg))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ bool long_displacement;
+ expressionS exp;
+ if (! lex_15_bit_offset (&long_displacement, &exp))
+ goto fail;
+
+ uint8_t lb = 0x00;
+ if (reg == REG_X || reg == REG_Y)
+ {
+ lb |= 0x08;
+ }
+ else
+ {
+ lb |= reg;
+ }
+ if (reg == REG_Y)
+ lb |= 0x01;
+
+ if (0 == strncmp (insn->name + 2, "ne", 2))
+ lb |= 0x00 << 4;
+ else if (0 == strncmp (insn->name + 2, "eq", 2))
+ lb |= 0x01 << 4;
+ else if (0 == strncmp (insn->name + 2, "pl", 2))
+ lb |= 0x02 << 4;
+ else if (0 == strncmp (insn->name + 2, "mi", 2))
+ lb |= 0x03 << 4;
+ else if (0 == strncmp (insn->name + 2, "gt", 2))
+ lb |= 0x04 << 4;
+ else if (0 == strncmp (insn->name + 2, "le", 2))
+ lb |= 0x05 << 4;
+
+ switch (insn->name[0])
+ {
+ case 'd':
+ lb |= 0x80;
+ break;
+ case 't':
+ break;
+ default:
+ gas_assert (0);
+ break;
+ };
+
+ char *f = s12z_new_insn (long_displacement ? 4 : 3);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, lb, 1);
+
+ emit_15_bit_offset (f, 4, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+tb_opr_rel (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ bool long_displacement;
+ expressionS exp2;
+ if (! lex_15_bit_offset (&long_displacement, &exp2))
+ goto fail;
+
+ uint8_t lb = 0x0C;
+
+ if (0 == strncmp (insn->name + 2, "ne", 2))
+ lb |= 0x00 << 4;
+ else if (0 == strncmp (insn->name + 2, "eq", 2))
+ lb |= 0x01 << 4;
+ else if (0 == strncmp (insn->name + 2, "pl", 2))
+ lb |= 0x02 << 4;
+ else if (0 == strncmp (insn->name + 2, "mi", 2))
+ lb |= 0x03 << 4;
+ else if (0 == strncmp (insn->name + 2, "gt", 2))
+ lb |= 0x04 << 4;
+ else if (0 == strncmp (insn->name + 2, "le", 2))
+ lb |= 0x05 << 4;
+
+ switch (insn->name[0])
+ {
+ case 'd':
+ lb |= 0x80;
+ break;
+ case 't':
+ break;
+ default:
+ gas_assert (0);
+ break;
+ };
+
+ int size = size_from_suffix (insn, 0);
+
+ lb |= size -1;
+
+ char *f = s12z_new_insn (n_bytes + (long_displacement ? 4 : 3));
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, lb, 1);
+ f = emit_opr (f, buffer, n_bytes, &exp);
+
+ emit_15_bit_offset (f, n_bytes + 4, &exp2);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+
+
+static int
+test_br_reg_reg_rel (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int Di = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Di))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+
+ int Dn = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dn))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+
+ bool long_displacement;
+ expressionS exp;
+ if (! lex_15_bit_offset (&long_displacement, &exp))
+ goto fail;
+
+ uint8_t bm = 0x81;
+ uint8_t xb = 0xb8;
+
+ bm |= Dn << 4;
+ xb |= Di;
+
+ char *f = s12z_new_insn (long_displacement ? 5 : 4);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+ number_to_chars_bigendian (f++, xb, 1);
+
+ emit_15_bit_offset (f, 5, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+static int
+test_br_opr_reg_rel (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ int Dn = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Dn))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ uint8_t bm = 0x81;
+ bm |= Dn << 4;
+ int size = size_from_suffix (insn, 0);
+ bm |= (size -1) << 2;
+
+ bool long_displacement;
+
+ expressionS exp2;
+ if (! lex_15_bit_offset (&long_displacement, &exp2))
+ goto fail;
+
+ int n = n_bytes + (long_displacement ? 4 : 3);
+ char *f = s12z_new_insn (n);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+ f = emit_opr (f, buffer, n_bytes, &exp);
+
+ emit_15_bit_offset (f, n, &exp2);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+test_br_opr_imm_rel (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ uint8_t buffer[4];
+ int n_bytes;
+ expressionS exp;
+ if (!lex_opr (buffer, &n_bytes, &exp))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long imm;
+ if (!lex_imm (&imm))
+ goto fail;
+
+ if (imm < 0 || imm > 31)
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ bool long_displacement;
+ expressionS exp2;
+ if (! lex_15_bit_offset (&long_displacement, &exp2))
+ goto fail;
+
+ int size = size_from_suffix (insn, 0);
+
+ uint8_t bm = 0x80;
+ bm |= (imm & 0x07) << 4;
+ bm |= (imm >> 3) & 0x03;
+ if (size == 4)
+ bm |= 0x08;
+ else if (size == 2)
+ bm |= 0x02;
+
+ char *f = s12z_new_insn (n_bytes + (long_displacement ? 4 : 3));
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+ f = emit_opr (f, buffer, n_bytes, &exp);
+
+ emit_15_bit_offset (f, n_bytes + 4, &exp2);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+static int
+test_br_reg_imm_rel (const struct instruction *insn)
+{
+ char *ilp = input_line_pointer;
+
+ int Di = 0;
+ if (!lex_reg_name (REG_BIT_Dn, &Di))
+ goto fail;
+
+ if (!lex_match (','))
+ goto fail;
+
+ long imm;
+ if (!lex_imm (&imm))
+ goto fail;
+
+ if (imm < 0 || imm > 31)
+ goto fail;
+
+
+ if (!lex_match (','))
+ goto fail;
+
+ bool long_displacement;
+ expressionS exp;
+ if (! lex_15_bit_offset (&long_displacement, &exp))
+ goto fail;
+
+ uint8_t bm = Di;
+ bm |= imm << 3;
+
+ char *f = s12z_new_insn (long_displacement ? 4 : 3);
+ number_to_chars_bigendian (f++, insn->opc, 1);
+ number_to_chars_bigendian (f++, bm, 1);
+
+ emit_15_bit_offset (f, 4, &exp);
+
+ return 1;
+
+ fail:
+ fail_line_pointer = input_line_pointer;
+ input_line_pointer = ilp;
+ return 0;
+}
+
+
+
+
+static const struct instruction opcodes[] = {
+ {"bgnd", 1, 0x00, no_operands, 0},
+ {"nop", 1, 0x01, no_operands, 0},
+
+ {"brclr", 1, 0x02, test_br_reg_reg_rel, 0},
+ {"brset", 1, 0x03, test_br_reg_reg_rel, 0},
+
+ {"brclr", 1, 0x02, test_br_reg_imm_rel, 0},
+ {"brset", 1, 0x03, test_br_reg_imm_rel, 0},
+
+ {"brclr.b", 1, 0x02, test_br_opr_reg_rel, 0},
+ {"brclr.w", 1, 0x02, test_br_opr_reg_rel, 0},
+ {"brclr.l", 1, 0x02, test_br_opr_reg_rel, 0},
+
+ {"brset.b", 1, 0x03, test_br_opr_reg_rel, 0},
+ {"brset.w", 1, 0x03, test_br_opr_reg_rel, 0},
+ {"brset.l", 1, 0x03, test_br_opr_reg_rel, 0},
+
+ {"brclr.b", 1, 0x02, test_br_opr_imm_rel, 0},
+ {"brclr.w", 1, 0x02, test_br_opr_imm_rel, 0},
+ {"brclr.l", 1, 0x02, test_br_opr_imm_rel, 0},
+
+ {"brset.b", 1, 0x03, test_br_opr_imm_rel, 0},
+ {"brset.w", 1, 0x03, test_br_opr_imm_rel, 0},
+ {"brset.l", 1, 0x03, test_br_opr_imm_rel, 0},
+
+ {"psh", 1, 0x04, psh_pull, 0},
+ {"pul", 1, 0x04, psh_pull, 0},
+
+ {"rts", 1, 0x05, no_operands, 0},
+ {"lea", 1, 0x06, reg67sxy_opr, 0},
+
+ {"dbne", 1, 0x0b, tb_reg_rel, 0},
+ {"dbeq", 1, 0x0b, tb_reg_rel, 0},
+ {"dbpl", 1, 0x0b, tb_reg_rel, 0},
+ {"dbmi", 1, 0x0b, tb_reg_rel, 0},
+ {"dbgt", 1, 0x0b, tb_reg_rel, 0},
+ {"dble", 1, 0x0b, tb_reg_rel, 0},
+
+ {"dbne.b", 1, 0x0b, tb_opr_rel, 0},
+ {"dbeq.b", 1, 0x0b, tb_opr_rel, 0},
+ {"dbpl.b", 1, 0x0b, tb_opr_rel, 0},
+ {"dbmi.b", 1, 0x0b, tb_opr_rel, 0},
+ {"dbgt.b", 1, 0x0b, tb_opr_rel, 0},
+ {"dble.b", 1, 0x0b, tb_opr_rel, 0},
+
+ {"dbne.w", 1, 0x0b, tb_opr_rel, 0},
+ {"dbeq.w", 1, 0x0b, tb_opr_rel, 0},
+ {"dbpl.w", 1, 0x0b, tb_opr_rel, 0},
+ {"dbmi.w", 1, 0x0b, tb_opr_rel, 0},
+ {"dbgt.w", 1, 0x0b, tb_opr_rel, 0},
+ {"dble.w", 1, 0x0b, tb_opr_rel, 0},
+
+ {"dbne.p", 1, 0x0b, tb_opr_rel, 0},
+ {"dbeq.p", 1, 0x0b, tb_opr_rel, 0},
+ {"dbpl.p", 1, 0x0b, tb_opr_rel, 0},
+ {"dbmi.p", 1, 0x0b, tb_opr_rel, 0},
+ {"dbgt.p", 1, 0x0b, tb_opr_rel, 0},
+ {"dble.p", 1, 0x0b, tb_opr_rel, 0},
+
+ {"dbne.l", 1, 0x0b, tb_opr_rel, 0},
+ {"dbeq.l", 1, 0x0b, tb_opr_rel, 0},
+ {"dbpl.l", 1, 0x0b, tb_opr_rel, 0},
+ {"dbmi.l", 1, 0x0b, tb_opr_rel, 0},
+ {"dbgt.l", 1, 0x0b, tb_opr_rel, 0},
+ {"dble.l", 1, 0x0b, tb_opr_rel, 0},
+
+ {"tbne", 1, 0x0b, tb_reg_rel, 0},
+ {"tbeq", 1, 0x0b, tb_reg_rel, 0},
+ {"tbpl", 1, 0x0b, tb_reg_rel, 0},
+ {"tbmi", 1, 0x0b, tb_reg_rel, 0},
+ {"tbgt", 1, 0x0b, tb_reg_rel, 0},
+ {"tble", 1, 0x0b, tb_reg_rel, 0},
+
+ {"tbne.b", 1, 0x0b, tb_opr_rel, 0},
+ {"tbeq.b", 1, 0x0b, tb_opr_rel, 0},
+ {"tbpl.b", 1, 0x0b, tb_opr_rel, 0},
+ {"tbmi.b", 1, 0x0b, tb_opr_rel, 0},
+ {"tbgt.b", 1, 0x0b, tb_opr_rel, 0},
+ {"tble.b", 1, 0x0b, tb_opr_rel, 0},
+
+ {"tbne.w", 1, 0x0b, tb_opr_rel, 0},
+ {"tbeq.w", 1, 0x0b, tb_opr_rel, 0},
+ {"tbpl.w", 1, 0x0b, tb_opr_rel, 0},
+ {"tbmi.w", 1, 0x0b, tb_opr_rel, 0},
+ {"tbgt.w", 1, 0x0b, tb_opr_rel, 0},
+ {"tble.w", 1, 0x0b, tb_opr_rel, 0},
+
+ {"tbne.p", 1, 0x0b, tb_opr_rel, 0},
+ {"tbeq.p", 1, 0x0b, tb_opr_rel, 0},
+ {"tbpl.p", 1, 0x0b, tb_opr_rel, 0},
+ {"tbmi.p", 1, 0x0b, tb_opr_rel, 0},
+ {"tbgt.p", 1, 0x0b, tb_opr_rel, 0},
+ {"tble.p", 1, 0x0b, tb_opr_rel, 0},
+
+ {"tbne.l", 1, 0x0b, tb_opr_rel, 0},
+ {"tbeq.l", 1, 0x0b, tb_opr_rel, 0},
+ {"tbpl.l", 1, 0x0b, tb_opr_rel, 0},
+ {"tbmi.l", 1, 0x0b, tb_opr_rel, 0},
+ {"tbgt.l", 1, 0x0b, tb_opr_rel, 0},
+ {"tble.l", 1, 0x0b, tb_opr_rel, 0},
+
+ {"mov.b", 1, 0x0c, imm_opr, 0},
+ {"mov.w", 1, 0x0d, imm_opr, 0},
+ {"mov.p", 1, 0x0e, imm_opr, 0},
+ {"mov.l", 1, 0x0f, imm_opr, 0},
+
+ {"rol", 1, 0x10, rol, 0},
+ {"rol.b", 1, 0x10, rol, 0},
+ {"rol.w", 1, 0x10, rol, 0},
+ {"rol.p", 1, 0x10, rol, 0},
+ {"rol.l", 1, 0x10, rol, 0},
+
+ {"ror", 1, 0x10, ror, 0},
+ {"ror.b", 1, 0x10, ror, 0},
+ {"ror.w", 1, 0x10, ror, 0},
+ {"ror.p", 1, 0x10, ror, 0},
+ {"ror.l", 1, 0x10, ror, 0},
+
+ {"lsl", 1, 0x10, shift_reg, 0},
+ {"lsr", 1, 0x10, shift_reg, 0},
+ {"asl", 1, 0x10, shift_reg, 0},
+ {"asr", 1, 0x10, shift_reg, 0},
+
+ {"lsl.b", 1, 0x10, shift_two_operand, 0},
+ {"lsl.w", 1, 0x10, shift_two_operand, 0},
+ {"lsl.p", 1, 0x10, shift_two_operand, 0},
+ {"lsl.l", 1, 0x10, shift_two_operand, 0},
+ {"asl.b", 1, 0x10, shift_two_operand, 0},
+ {"asl.w", 1, 0x10, shift_two_operand, 0},
+ {"asl.p", 1, 0x10, shift_two_operand, 0},
+ {"asl.l", 1, 0x10, shift_two_operand, 0},
+
+ {"lsr.b", 1, 0x10, shift_two_operand, 0},
+ {"lsr.w", 1, 0x10, shift_two_operand, 0},
+ {"lsr.p", 1, 0x10, shift_two_operand, 0},
+ {"lsr.l", 1, 0x10, shift_two_operand, 0},
+ {"asr.b", 1, 0x10, shift_two_operand, 0},
+ {"asr.w", 1, 0x10, shift_two_operand, 0},
+ {"asr.p", 1, 0x10, shift_two_operand, 0},
+ {"asr.l", 1, 0x10, shift_two_operand, 0},
+
+ {"lsl.b", 1, 0x10, shift_opr_imm, 0},
+ {"lsl.w", 1, 0x10, shift_opr_imm, 0},
+ {"lsl.p", 1, 0x10, shift_opr_imm, 0},
+ {"lsl.l", 1, 0x10, shift_opr_imm, 0},
+ {"asl.b", 1, 0x10, shift_opr_imm, 0},
+ {"asl.w", 1, 0x10, shift_opr_imm, 0},
+ {"asl.p", 1, 0x10, shift_opr_imm, 0},
+ {"asl.l", 1, 0x10, shift_opr_imm, 0},
+
+ {"lsr.b", 1, 0x10, shift_opr_imm, 0},
+ {"lsr.w", 1, 0x10, shift_opr_imm, 0},
+ {"lsr.p", 1, 0x10, shift_opr_imm, 0},
+ {"lsr.l", 1, 0x10, shift_opr_imm, 0},
+ {"asr.b", 1, 0x10, shift_opr_imm, 0},
+ {"asr.w", 1, 0x10, shift_opr_imm, 0},
+ {"asr.p", 1, 0x10, shift_opr_imm, 0},
+ {"asr.l", 1, 0x10, shift_opr_imm, 0},
+
+ {"mov.b", 1, 0x1c, opr_opr, 0},
+ {"mov.w", 1, 0x1d, opr_opr, 0},
+ {"mov.p", 1, 0x1e, opr_opr, 0},
+ {"mov.l", 1, 0x1f, opr_opr, 0},
+
+ {"bra", 1, 0x20, rel, 0},
+ {"bsr", 1, 0x21, rel, 0},
+ {"bhi", 1, 0x22, rel, 0},
+ {"bls", 1, 0x23, rel, 0},
+ {"bcc", 1, 0x24, rel, 0},
+ {"bcs", 1, 0x25, rel, 0},
+ {"bne", 1, 0x26, rel, 0},
+ {"beq", 1, 0x27, rel, 0},
+ {"bvc", 1, 0x28, rel, 0},
+ {"bvs", 1, 0x29, rel, 0},
+ {"bpl", 1, 0x2a, rel, 0},
+ {"bmi", 1, 0x2b, rel, 0},
+ {"bge", 1, 0x2c, rel, 0},
+ {"blt", 1, 0x2d, rel, 0},
+ {"bgt", 1, 0x2e, rel, 0},
+ {"ble", 1, 0x2f, rel, 0},
+
+ {"inc", 1, 0x30, reg_inh, 0},
+ {"clr", 1, 0x38, reg_inh, 0},
+ {"dec", 1, 0x40, reg_inh, 0},
+
+ {"muls", 1, 0x48, mul_reg_reg_reg, 0},
+ {"mulu", 1, 0x48, mul_reg_reg_reg, 0},
+
+ {"muls.b", 1, 0x48, mul_reg_reg_opr, 0},
+ {"muls.w", 1, 0x48, mul_reg_reg_opr, 0},
+ {"muls.l", 1, 0x48, mul_reg_reg_opr, 0},
+
+ {"mulu.b", 1, 0x48, mul_reg_reg_opr, 0},
+ {"mulu.w", 1, 0x48, mul_reg_reg_opr, 0},
+ {"mulu.l", 1, 0x48, mul_reg_reg_opr, 0},
+
+ {"muls.b", 1, 0x48, mul_reg_reg_imm, 0},
+ {"muls.w", 1, 0x48, mul_reg_reg_imm, 0},
+ {"muls.l", 1, 0x48, mul_reg_reg_imm, 0},
+
+ {"mulu.b", 1, 0x48, mul_reg_reg_imm, 0},
+ {"mulu.w", 1, 0x48, mul_reg_reg_imm, 0},
+ {"mulu.l", 1, 0x48, mul_reg_reg_imm, 0},
+
+ {"muls.bb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.bw", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.bp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.bl", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"muls.wb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.ww", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.wp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.wl", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"muls.pb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.pw", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.pp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.pl", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"muls.lb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.lw", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.lp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"muls.ll", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"mulu.bb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.bw", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.bp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.bl", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"mulu.wb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.ww", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.wp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.wl", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"mulu.pb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.pw", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.pp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.pl", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"mulu.lb", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.lw", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.lp", 1, 0x48, mul_reg_opr_opr, 0},
+ {"mulu.ll", 1, 0x48, mul_reg_opr_opr, 0},
+
+ {"add", 1, 0x50, regd_imm, 0},
+ {"and", 1, 0x58, regd_imm, 0},
+
+ {"add", 1, 0x60, regd_opr, 0},
+ {"and", 1, 0x68, regd_opr, 0},
+
+ {"sub", 1, 0x70, regd_imm, 0},
+ {"or", 1, 0x78, regd_imm, 0},
+
+ {"sub", 1, 0x80, regd_opr, 0},
+ {"or", 1, 0x88, regd_opr, 0},
+
+ {"ld", 1, 0x90, regdxy_imm, 0},
+
+ {"clr", 1, 0x9a, clr_xy, 0},
+ {"tfr", 1, 0x9e, tfr, 0},
+ {"zex", 1, 0x9e, tfr, 0},
+
+ {"ld", 1, 0xa0, regdxy_opr, 0xb0},
+
+ {"jmp", 1, 0xaa, opr, 0xba},
+ {"jsr", 1, 0xab, opr, 0xbb},
+
+ {"exg", 1, 0xae, tfr, 0},
+ {"sex", 1, 0xae, tfr, 0},
+
+ {"st", 1, 0xc0, regdxy_opr, 0xd0},
+
+ {"andcc", 1, 0xce, imm8, 0},
+ {"orcc", 1, 0xde, imm8, 0},
+
+ {"inc.b", 1, 0x9c, opr, 0},
+ {"inc.w", 1, 0x9d, opr, 0},
+ {"inc.l", 1, 0x9f, opr, 0},
+
+ {"dec.b", 1, 0xac, opr, 0},
+ {"dec.w", 1, 0xad, opr, 0},
+ {"dec.l", 1, 0xaf, opr, 0},
+
+ {"clr.b", 1, 0xbc, opr, 0},
+ {"clr.w", 1, 0xbd, opr, 0},
+ {"clr.p", 1, 0xbe, opr, 0},
+ {"clr.l", 1, 0xbf, opr, 0},
+
+ {"com.b", 1, 0xcc, opr, 0},
+ {"com.w", 1, 0xcd, opr, 0},
+ {"com.l", 1, 0xcf, opr, 0},
+
+ {"neg.b", 1, 0xdc, opr, 0},
+ {"neg.w", 1, 0xdd, opr, 0},
+ {"neg.l", 1, 0xdf, opr, 0},
+
+ {"bclr", 1, 0xec, bm_regd_imm, 0},
+ {"bset", 1, 0xed, bm_regd_imm, 0},
+ {"btgl", 1, 0xee, bm_regd_imm, 0},
+
+ {"bclr", 1, 0xec, bm_regd_reg, 0},
+ {"bset", 1, 0xed, bm_regd_reg, 0},
+ {"btgl", 1, 0xee, bm_regd_reg, 0},
+
+ {"bclr.b", 1, 0xec, bm_opr_imm, 0},
+ {"bclr.w", 1, 0xec, bm_opr_imm, 0},
+ {"bclr.l", 1, 0xec, bm_opr_imm, 0},
+
+ {"bset.b", 1, 0xed, bm_opr_imm, 0},
+ {"bset.w", 1, 0xed, bm_opr_imm, 0},
+ {"bset.l", 1, 0xed, bm_opr_imm, 0},
+
+ {"btgl.b", 1, 0xee, bm_opr_imm, 0},
+ {"btgl.w", 1, 0xee, bm_opr_imm, 0},
+ {"btgl.l", 1, 0xee, bm_opr_imm, 0},
+
+ {"bclr.b", 1, 0xec, bm_opr_reg, 0},
+ {"bclr.w", 1, 0xec, bm_opr_reg, 0},
+ {"bclr.l", 1, 0xec, bm_opr_reg, 0},
+
+ {"bset.b", 1, 0xed, bm_opr_reg, 0},
+ {"bset.w", 1, 0xed, bm_opr_reg, 0},
+ {"bset.l", 1, 0xed, bm_opr_reg, 0},
+
+ {"btgl.b", 1, 0xee, bm_opr_reg, 0},
+ {"btgl.w", 1, 0xee, bm_opr_reg, 0},
+ {"btgl.l", 1, 0xee, bm_opr_reg, 0},
+
+ {"cmp", 1, 0xe0, regdxy_imm, 0},
+ {"cmp", 1, 0xf0, regdxy_opr, 0},
+
+ {"cmp", 1, 0xfc, regx_regy, 0},
+ {"sub", 1, 0xfd, regd6_regx_regy, 0},
+ {"sub", 1, 0xfe, regd6_regy_regx, 0},
+
+ {"swi", 1, 0xff, no_operands, 0},
+
+ /* Page 2 */
+
+ /* The -10 below is a kludge. The opcode is in fact 0x00 */
+ {"ld", 2, -10, regs_opr, 0},
+
+ /* The -9 below is a kludge. The opcode is in fact 0x01 */
+ {"st", 2, -9, regs_opr, 0},
+
+ /* The -8 below is a kludge. The opcode is in fact 0x02 */
+ {"cmp", 2, -8, regs_opr, 0},
+
+ /* The -7 below is a kludge. The opcode is in fact 0x03 */
+ {"ld", 2, -7, regs_imm, 0},
+
+ /* The -6 below is a kludge. The opcode is in fact 0x04 */
+ {"cmp", 2, -6, regs_imm, 0},
+
+ {"bfext", 2, 0x08, bfe_reg_reg_reg, 0},
+ {"bfext", 2, 0x08, bfe_reg_reg_imm, 0},
+ {"bfext.b", 2, 0x08, bfe_reg_opr_reg, 0},
+ {"bfext.w", 2, 0x08, bfe_reg_opr_reg, 0},
+ {"bfext.p", 2, 0x08, bfe_reg_opr_reg, 0},
+ {"bfext.l", 2, 0x08, bfe_reg_opr_reg, 0},
+ {"bfext.b", 2, 0x08, bfe_opr_reg_reg, 0},
+ {"bfext.w", 2, 0x08, bfe_opr_reg_reg, 0},
+ {"bfext.p", 2, 0x08, bfe_opr_reg_reg, 0},
+ {"bfext.l", 2, 0x08, bfe_opr_reg_reg, 0},
+ {"bfext.b", 2, 0x08, bfe_reg_opr_imm, 0},
+ {"bfext.w", 2, 0x08, bfe_reg_opr_imm, 0},
+ {"bfext.p", 2, 0x08, bfe_reg_opr_imm, 0},
+ {"bfext.l", 2, 0x08, bfe_reg_opr_imm, 0},
+ {"bfext.b", 2, 0x08, bfe_opr_reg_imm, 0},
+ {"bfext.w", 2, 0x08, bfe_opr_reg_imm, 0},
+ {"bfext.p", 2, 0x08, bfe_opr_reg_imm, 0},
+ {"bfext.l", 2, 0x08, bfe_opr_reg_imm, 0},
+
+
+ {"bfins", 2, 0x08, bfi_reg_reg_reg, 0},
+ {"bfins", 2, 0x08, bfi_reg_reg_imm, 0},
+ {"bfins.b", 2, 0x08, bfi_reg_opr_reg, 0},
+ {"bfins.w", 2, 0x08, bfi_reg_opr_reg, 0},
+ {"bfins.p", 2, 0x08, bfi_reg_opr_reg, 0},
+ {"bfins.l", 2, 0x08, bfi_reg_opr_reg, 0},
+ {"bfins.b", 2, 0x08, bfi_opr_reg_reg, 0},
+ {"bfins.w", 2, 0x08, bfi_opr_reg_reg, 0},
+ {"bfins.p", 2, 0x08, bfi_opr_reg_reg, 0},
+ {"bfins.l", 2, 0x08, bfi_opr_reg_reg, 0},
+ {"bfins.b", 2, 0x08, bfi_reg_opr_imm, 0},
+ {"bfins.w", 2, 0x08, bfi_reg_opr_imm, 0},
+ {"bfins.p", 2, 0x08, bfi_reg_opr_imm, 0},
+ {"bfins.l", 2, 0x08, bfi_reg_opr_imm, 0},
+ {"bfins.b", 2, 0x08, bfi_opr_reg_imm, 0},
+ {"bfins.w", 2, 0x08, bfi_opr_reg_imm, 0},
+ {"bfins.p", 2, 0x08, bfi_opr_reg_imm, 0},
+ {"bfins.l", 2, 0x08, bfi_opr_reg_imm, 0},
+
+
+ {"minu", 2, 0x10, regd_opr, 0},
+ {"maxu", 2, 0x18, regd_opr, 0},
+ {"mins", 2, 0x20, regd_opr, 0},
+ {"maxs", 2, 0x28, regd_opr, 0},
+
+ {"clb", 2, 0x91, tfr, 0},
+
+ {"trap", 2, 0x00, trap_imm, 0},
+ {"abs", 2, 0x40, reg_inh, 0},
+ {"sat", 2, 0xa0, reg_inh, 0},
+
+ {"rti", 2, 0x90, no_operands, 0},
+ {"stop", 2, 0x05, no_operands, 0},
+ {"wai", 2, 0x06, no_operands, 0},
+ {"sys", 2, 0x07, no_operands, 0},
+
+ {"bit", 2, 0x58, regd_imm, 0},
+ {"bit", 2, 0x68, regd_opr, 0},
+
+ {"adc", 2, 0x50, regd_imm, 0},
+ {"adc", 2, 0x60, regd_opr, 0},
+
+ {"sbc", 2, 0x70, regd_imm, 0},
+ {"eor", 2, 0x78, regd_imm, 0},
+
+ {"sbc", 2, 0x80, regd_opr, 0},
+ {"eor", 2, 0x88, regd_opr, 0},
+
+ {"divs", 2, 0x30, mul_reg_reg_reg, 0},
+ {"divu", 2, 0x30, mul_reg_reg_reg, 0},
+
+ {"divs.b", 2, 0x30, mul_reg_reg_opr, 0},
+ {"divs.w", 2, 0x30, mul_reg_reg_opr, 0},
+ {"divs.l", 2, 0x30, mul_reg_reg_opr, 0},
+
+ {"divu.b", 2, 0x30, mul_reg_reg_opr, 0},
+ {"divu.w", 2, 0x30, mul_reg_reg_opr, 0},
+ {"divu.l", 2, 0x30, mul_reg_reg_opr, 0},
+
+ {"divs.b", 2, 0x30, mul_reg_reg_imm, 0},
+ {"divs.w", 2, 0x30, mul_reg_reg_imm, 0},
+ {"divs.l", 2, 0x30, mul_reg_reg_imm, 0},
+
+ {"divu.b", 2, 0x30, mul_reg_reg_imm, 0},
+ {"divu.w", 2, 0x30, mul_reg_reg_imm, 0},
+ {"divu.l", 2, 0x30, mul_reg_reg_imm, 0},
+
+ {"divs.bb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.bw", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.bp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.bl", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divs.wb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.ww", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.wp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.wl", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divs.pb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.pw", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.pp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.pl", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divs.lb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.lw", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.lp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divs.ll", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divu.bb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.bw", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.bp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.bl", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divu.wb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.ww", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.wp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.wl", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divu.pb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.pw", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.pp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.pl", 2, 0x30, mul_reg_opr_opr, 0},
+
+ {"divu.lb", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.lw", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.lp", 2, 0x30, mul_reg_opr_opr, 0},
+ {"divu.ll", 2, 0x30, mul_reg_opr_opr, 0},
+
+ //
+
+ {"qmuls", 2, 0xb0, mul_reg_reg_reg, 0},
+ {"qmulu", 2, 0xb0, mul_reg_reg_reg, 0},
+
+ {"qmuls.b", 2, 0xb0, mul_reg_reg_opr, 0},
+ {"qmuls.w", 2, 0xb0, mul_reg_reg_opr, 0},
+ {"qmuls.l", 2, 0xb0, mul_reg_reg_opr, 0},
+
+ {"qmulu.b", 2, 0xb0, mul_reg_reg_opr, 0},
+ {"qmulu.w", 2, 0xb0, mul_reg_reg_opr, 0},
+ {"qmulu.l", 2, 0xb0, mul_reg_reg_opr, 0},
+
+ {"qmuls.b", 2, 0xb0, mul_reg_reg_imm, 0},
+ {"qmuls.w", 2, 0xb0, mul_reg_reg_imm, 0},
+ {"qmuls.l", 2, 0xb0, mul_reg_reg_imm, 0},
+
+ {"qmulu.b", 2, 0xb0, mul_reg_reg_imm, 0},
+ {"qmulu.w", 2, 0xb0, mul_reg_reg_imm, 0},
+ {"qmulu.l", 2, 0xb0, mul_reg_reg_imm, 0},
+
+ {"qmuls.bb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.bw", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.bp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.bl", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmuls.wb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.ww", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.wp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.wl", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmuls.pb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.pw", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.pp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.pl", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmuls.lb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.lw", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.lp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmuls.ll", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmulu.bb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.bw", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.bp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.bl", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmulu.wb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.ww", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.wp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.wl", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmulu.pb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.pw", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.pp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.pl", 2, 0xb0, mul_reg_opr_opr, 0},
+
+ {"qmulu.lb", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.lw", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.lp", 2, 0xb0, mul_reg_opr_opr, 0},
+ {"qmulu.ll", 2, 0xb0, mul_reg_opr_opr, 0},
+
+
+ //
+
+ {"macs", 2, 0x48, mul_reg_reg_reg, 0},
+ {"macu", 2, 0x48, mul_reg_reg_reg, 0},
+
+ {"macs.b", 2, 0x48, mul_reg_reg_opr, 0},
+ {"macs.w", 2, 0x48, mul_reg_reg_opr, 0},
+ {"macs.l", 2, 0x48, mul_reg_reg_opr, 0},
+
+ {"macu.b", 2, 0x48, mul_reg_reg_opr, 0},
+ {"macu.w", 2, 0x48, mul_reg_reg_opr, 0},
+ {"macu.l", 2, 0x48, mul_reg_reg_opr, 0},
+
+ {"macs.b", 2, 0x48, mul_reg_reg_imm, 0},
+ {"macs.w", 2, 0x48, mul_reg_reg_imm, 0},
+ {"macs.l", 2, 0x48, mul_reg_reg_imm, 0},
+
+ {"macu.b", 2, 0x48, mul_reg_reg_imm, 0},
+ {"macu.w", 2, 0x48, mul_reg_reg_imm, 0},
+ {"macu.l", 2, 0x48, mul_reg_reg_imm, 0},
+
+ {"macs.bb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.bw", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.bp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.bl", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macs.wb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.ww", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.wp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.wl", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macs.pb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.pw", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.pp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.pl", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macs.lb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.lw", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.lp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macs.ll", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macu.bb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.bw", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.bp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.bl", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macu.wb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.ww", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.wp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.wl", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macu.pb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.pw", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.pp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.pl", 2, 0x48, mul_reg_opr_opr, 0},
+
+ {"macu.lb", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.lw", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.lp", 2, 0x48, mul_reg_opr_opr, 0},
+ {"macu.ll", 2, 0x48, mul_reg_opr_opr, 0},
+
+
+ //
+
+ {"mods", 2, 0x38, mul_reg_reg_reg, 0},
+ {"modu", 2, 0x38, mul_reg_reg_reg, 0},
+
+ {"mods.b", 2, 0x38, mul_reg_reg_opr, 0},
+ {"mods.w", 2, 0x38, mul_reg_reg_opr, 0},
+ {"mods.l", 2, 0x38, mul_reg_reg_opr, 0},
+
+ {"modu.b", 2, 0x38, mul_reg_reg_opr, 0},
+ {"modu.w", 2, 0x38, mul_reg_reg_opr, 0},
+ {"modu.l", 2, 0x38, mul_reg_reg_opr, 0},
+
+ {"mods.b", 2, 0x38, mul_reg_reg_imm, 0},
+ {"mods.w", 2, 0x38, mul_reg_reg_imm, 0},
+ {"mods.l", 2, 0x38, mul_reg_reg_imm, 0},
+
+ {"modu.b", 2, 0x38, mul_reg_reg_imm, 0},
+ {"modu.w", 2, 0x38, mul_reg_reg_imm, 0},
+ {"modu.l", 2, 0x38, mul_reg_reg_imm, 0},
+
+ {"mods.bb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.bw", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.bp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.bl", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"mods.wb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.ww", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.wp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.wl", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"mods.pb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.pw", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.pp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.pl", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"mods.lb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.lw", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.lp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"mods.ll", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"modu.bb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.bw", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.bp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.bl", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"modu.wb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.ww", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.wp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.wl", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"modu.pb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.pw", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.pp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.pl", 2, 0x38, mul_reg_opr_opr, 0},
+
+ {"modu.lb", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.lw", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.lp", 2, 0x38, mul_reg_opr_opr, 0},
+ {"modu.ll", 2, 0x38, mul_reg_opr_opr, 0}
+};
+
+
+/* Gas line assembler entry point. */
+
+/* This is the main entry point for the machine-dependent assembler. str
+ points to a machine-dependent instruction. This function is supposed to
+ emit the frags/bytes it assembles to. */
+void
+md_assemble (char *str)
+{
+ char *op_start;
+ char *op_end;
+ char name[20];
+ size_t nlen = 0;
+
+ fail_line_pointer = NULL;
+
+ /* Find the opcode end and get the opcode in 'name'. The opcode is forced
+ lower case (the opcode table only has lower case op-codes). */
+ for (op_start = op_end = str;
+ *op_end && !is_end_of_line[(int)*op_end] && *op_end != ' ';
+ op_end++)
+ {
+ name[nlen] = TOLOWER (op_start[nlen]);
+ nlen++;
+ gas_assert (nlen < sizeof (name) - 1);
+ }
+ name[nlen] = 0;
+
+ if (nlen == 0)
+ {
+ as_bad (_("No instruction or missing opcode."));
+ return;
+ }
+
+ input_line_pointer = skip_whites (op_end);
+
+ size_t i;
+ for (i = 0; i < sizeof (opcodes) / sizeof (opcodes[0]); ++i)
+ {
+ const struct instruction *opc = opcodes + i;
+ if (0 == strcmp (name, opc->name))
+ {
+ if (opc->parse_operands (opc))
+ return;
+ continue;
+ }
+ }
+
+ as_bad (_("Invalid instruction: \"%s\""), str);
+ as_bad (_("First invalid token: \"%s\""), fail_line_pointer);
+ while (*input_line_pointer++)
+ ;
+}
+
+
+
+
+
+/* Relocation, relaxation and frag conversions. */
+
+/* PC-relative offsets are relative to the start of the
+ next instruction. That is, the address of the offset, plus its
+ size, since the offset is always the last part of the insn. */
+long
+md_pcrel_from (fixS *fixP)
+{
+ long ret = fixP->fx_size + fixP->fx_frag->fr_address;
+ if (fixP->fx_addsy && S_IS_DEFINED (fixP->fx_addsy))
+ ret += fixP->fx_where;
+
+ return ret;
+}
+
+
+/* We need a port-specific relaxation function to cope with sym2 - sym1
+ relative expressions with both symbols in the same segment (but not
+ necessarily in the same frag as this insn), for example:
+ ldab sym2-(sym1-2),pc
+ sym1:
+ The offset can be 5, 9 or 16 bits long. */
+
+long
+s12z_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS *fragP ATTRIBUTE_UNUSED,
+ long stretch ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+void
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec ATTRIBUTE_UNUSED,
+ fragS *fragP ATTRIBUTE_UNUSED)
+{
+}
+
+/* On an ELF system, we can't relax a weak symbol. The weak symbol
+ can be overridden at final link time by a non weak symbol. We can
+ relax externally visible symbol because there is no shared library
+ and such symbol can't be overridden (unless they are weak). */
+
+/* Force truly undefined symbols to their maximum size, and generally set up
+ the frag list to be relaxed. */
+int
+md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, asection *segment ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+
+/* If while processing a fixup, a reloc really needs to be created
+ then it is done here. */
+arelent *
+tc_gen_reloc (asection *section, fixS *fixp)
+{
+ arelent *reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+ if (reloc->howto == (reloc_howto_type *) NULL)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("Relocation %d is not supported by object file format."),
+ (int) fixp->fx_r_type);
+ return NULL;
+ }
+
+ if (0 == (section->flags & SEC_CODE))
+ reloc->addend = fixp->fx_offset;
+ else
+ reloc->addend = fixp->fx_addnumber;
+
+ return reloc;
+}
+
+/* See whether we need to force a relocation into the output file. */
+int
+tc_s12z_force_relocation (fixS *fixP)
+{
+ return generic_force_reloc (fixP);
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+ to the beginning of the section instead of the symbol. Basically
+ we need to make sure that the linker relaxation is done
+ correctly, so in some cases we force the original symbol to be
+ used. */
+int
+tc_s12z_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+ long value = *valP;
+
+ if (fixP->fx_addsy == (symbolS *) NULL)
+ fixP->fx_done = 1;
+
+ /* We don't actually support subtracting a symbol. */
+ if (fixP->fx_subsy != (symbolS *) NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
+
+ /*
+ Patch the instruction with the resolved operand. Elf relocation
+ info will also be generated to take care of linker/loader fixups.
+ */
+ char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_8:
+ ((bfd_byte *) where)[0] = (bfd_byte) value;
+ break;
+ case BFD_RELOC_24:
+ bfd_putb24 ((bfd_vma) value, (unsigned char *) where);
+ break;
+ case BFD_RELOC_32:
+ bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
+ break;
+ case BFD_RELOC_16_PCREL:
+ if (value < -0x8000 || value > 0x7FFF)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value out of 16-bit range."));
+
+ bfd_putb16 ((bfd_vma) value | 0x8000, (unsigned char *) where);
+ break;
+
+ default:
+ as_fatal (_("Line %d: unknown relocation type: 0x%x."),
+ fixP->fx_line, fixP->fx_r_type);
+ }
+}
+
+/* Set the ELF specific flags. */
+void
+s12z_elf_final_processing (void)
+{
+}