[binutils-gdb] Add support for the Freescale s12z processor.

Nick Clifton nickc@sourceware.org
Fri May 18 14:29:00 GMT 2018


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7b4ae824289504c173a597e86a00ceab452095b7

commit 7b4ae824289504c173a597e86a00ceab452095b7
Author: John Darrington <john@darrington.wattle.id.au>
Date:   Fri May 18 15:26:18 2018 +0100

    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.

Diff:
---
 bfd/ChangeLog                                   |   19 +
 bfd/Makefile.am                                 |    4 +
 bfd/Makefile.in                                 |    6 +
 bfd/archures.c                                  |    4 +
 bfd/bfd-in.h                                    |    2 +
 bfd/bfd-in2.h                                   |    9 +
 bfd/config.bfd                                  |    4 +
 bfd/configure                                   |    1 +
 bfd/configure.ac                                |    1 +
 bfd/cpu-s12z.c                                  |   41 +
 bfd/elf32-s12z.c                                |  270 ++
 bfd/libbfd.c                                    |   21 +
 bfd/libbfd.h                                    |    1 +
 bfd/reloc.c                                     |   17 +
 bfd/targets.c                                   |    3 +
 binutils/ChangeLog                              |    6 +
 binutils/readelf.c                              |    7 +
 binutils/testsuite/binutils-all/dw2-1.S         |    2 +
 binutils/testsuite/lib/binutils-common.exp      |    2 +-
 gas/ChangeLog                                   |  216 ++
 gas/Makefile.am                                 |    2 +
 gas/Makefile.in                                 |   17 +
 gas/NEWS                                        |    2 +
 gas/config/tc-s12z.c                            | 3840 +++++++++++++++++++++++
 gas/config/tc-s12z.h                            |  105 +
 gas/configure.tgt                               |    3 +
 gas/doc/Makefile.am                             |    1 +
 gas/doc/Makefile.in                             |    1 +
 gas/doc/all.texi                                |    1 +
 gas/doc/as.texinfo                              |    7 +
 gas/doc/c-s12z.texi                             |  212 ++
 gas/testsuite/gas/s12z/abs.d                    |   19 +
 gas/testsuite/gas/s12z/abs.s                    |    8 +
 gas/testsuite/gas/s12z/adc-imm.d                |   21 +
 gas/testsuite/gas/s12z/adc-imm.s                |    8 +
 gas/testsuite/gas/s12z/adc-opr.d                |   21 +
 gas/testsuite/gas/s12z/adc-opr.s                |    9 +
 gas/testsuite/gas/s12z/add-imm.d                |   21 +
 gas/testsuite/gas/s12z/add-imm.s                |    8 +
 gas/testsuite/gas/s12z/add-opr.d                |   21 +
 gas/testsuite/gas/s12z/add-opr.s                |    9 +
 gas/testsuite/gas/s12z/and-imm.d                |   21 +
 gas/testsuite/gas/s12z/and-imm.s                |    8 +
 gas/testsuite/gas/s12z/and-opr.d                |   22 +
 gas/testsuite/gas/s12z/and-opr.s                |    9 +
 gas/testsuite/gas/s12z/and-or-cc.d              |   13 +
 gas/testsuite/gas/s12z/and-or-cc.s              |    2 +
 gas/testsuite/gas/s12z/bfext-special.d          |   13 +
 gas/testsuite/gas/s12z/bfext-special.s          |    2 +
 gas/testsuite/gas/s12z/bfext.d                  |   47 +
 gas/testsuite/gas/s12z/bfext.s                  |   23 +
 gas/testsuite/gas/s12z/bit-manip.d              |   26 +
 gas/testsuite/gas/s12z/bit-manip.s              |   16 +
 gas/testsuite/gas/s12z/bit.d                    |   33 +
 gas/testsuite/gas/s12z/bit.s                    |   17 +
 gas/testsuite/gas/s12z/bra-expression-defined.d |   23 +
 gas/testsuite/gas/s12z/bra-expression-defined.s |   11 +
 gas/testsuite/gas/s12z/bra-expression-undef.d   |   24 +
 gas/testsuite/gas/s12z/bra-expression-undef.s   |    9 +
 gas/testsuite/gas/s12z/bra.d                    |   34 +
 gas/testsuite/gas/s12z/bra.s                    |   20 +
 gas/testsuite/gas/s12z/brclr-symbols.d          |   32 +
 gas/testsuite/gas/s12z/brclr-symbols.s          |    9 +
 gas/testsuite/gas/s12z/brset-clr-opr-imm-rel.d  |   23 +
 gas/testsuite/gas/s12z/brset-clr-opr-imm-rel.s  |    7 +
 gas/testsuite/gas/s12z/brset-clr-opr-reg-rel.d  |   21 +
 gas/testsuite/gas/s12z/brset-clr-opr-reg-rel.s  |    5 +
 gas/testsuite/gas/s12z/brset-clr-reg-imm-rel.d  |   24 +
 gas/testsuite/gas/s12z/brset-clr-reg-imm-rel.s  |   12 +
 gas/testsuite/gas/s12z/brset-clr-reg-reg-rel.d  |   19 +
 gas/testsuite/gas/s12z/brset-clr-reg-reg-rel.s  |    6 +
 gas/testsuite/gas/s12z/clb.d                    |   19 +
 gas/testsuite/gas/s12z/clb.s                    |    8 +
 gas/testsuite/gas/s12z/clr-opr.d                |   15 +
 gas/testsuite/gas/s12z/clr-opr.s                |    5 +
 gas/testsuite/gas/s12z/clr.d                    |   21 +
 gas/testsuite/gas/s12z/clr.s                    |   10 +
 gas/testsuite/gas/s12z/cmp-imm.d                |   23 +
 gas/testsuite/gas/s12z/cmp-imm.s                |   12 +
 gas/testsuite/gas/s12z/cmp-opr-inc.d            |   21 +
 gas/testsuite/gas/s12z/cmp-opr-inc.s            |   11 +
 gas/testsuite/gas/s12z/cmp-opr-rdirect.d        |   19 +
 gas/testsuite/gas/s12z/cmp-opr-rdirect.s        |    9 +
 gas/testsuite/gas/s12z/cmp-opr-reg.d            |   19 +
 gas/testsuite/gas/s12z/cmp-opr-reg.s            |    9 +
 gas/testsuite/gas/s12z/cmp-opr-rindirect.d      |   19 +
 gas/testsuite/gas/s12z/cmp-opr-rindirect.s      |    9 +
 gas/testsuite/gas/s12z/cmp-opr-sxe4.d           |   21 +
 gas/testsuite/gas/s12z/cmp-opr-sxe4.s           |   10 +
 gas/testsuite/gas/s12z/cmp-opr-xys.d            |   19 +
 gas/testsuite/gas/s12z/cmp-opr-xys.s            |    9 +
 gas/testsuite/gas/s12z/cmp-s-imm.d              |   27 +
 gas/testsuite/gas/s12z/cmp-s-imm.s              |   10 +
 gas/testsuite/gas/s12z/cmp-s-opr.d              |   25 +
 gas/testsuite/gas/s12z/cmp-s-opr.s              |   10 +
 gas/testsuite/gas/s12z/cmp-xy.d                 |   12 +
 gas/testsuite/gas/s12z/cmp-xy.s                 |    1 +
 gas/testsuite/gas/s12z/com-opr.d                |   15 +
 gas/testsuite/gas/s12z/com-opr.s                |    3 +
 gas/testsuite/gas/s12z/complex-shifts.d         |   18 +
 gas/testsuite/gas/s12z/complex-shifts.s         |    4 +
 gas/testsuite/gas/s12z/db-tb-cc-opr.d           |   30 +
 gas/testsuite/gas/s12z/db-tb-cc-opr.s           |   11 +
 gas/testsuite/gas/s12z/db-tb-cc-reg.d           |   31 +
 gas/testsuite/gas/s12z/db-tb-cc-reg.s           |   21 +
 gas/testsuite/gas/s12z/dbCC.d                   |   27 +
 gas/testsuite/gas/s12z/dbCC.s                   |    7 +
 gas/testsuite/gas/s12z/dec-opr.d                |   15 +
 gas/testsuite/gas/s12z/dec-opr.s                |    3 +
 gas/testsuite/gas/s12z/dec.d                    |   19 +
 gas/testsuite/gas/s12z/dec.s                    |    8 +
 gas/testsuite/gas/s12z/div.d                    |   23 +
 gas/testsuite/gas/s12z/div.s                    |    8 +
 gas/testsuite/gas/s12z/eor.d                    |   33 +
 gas/testsuite/gas/s12z/eor.s                    |   17 +
 gas/testsuite/gas/s12z/exg.d                    |   29 +
 gas/testsuite/gas/s12z/exg.s                    |   18 +
 gas/testsuite/gas/s12z/ext24-ld-xy.d            |   12 +
 gas/testsuite/gas/s12z/ext24-ld-xy.s            |    2 +
 gas/testsuite/gas/s12z/inc-opr.d                |   15 +
 gas/testsuite/gas/s12z/inc-opr.s                |    3 +
 gas/testsuite/gas/s12z/inc.d                    |   19 +
 gas/testsuite/gas/s12z/inc.s                    |    8 +
 gas/testsuite/gas/s12z/inh.d                    |   15 +
 gas/testsuite/gas/s12z/inh.s                    |    5 +
 gas/testsuite/gas/s12z/jmp.d                    |   33 +
 gas/testsuite/gas/s12z/jmp.s                    |   20 +
 gas/testsuite/gas/s12z/jsr.d                    |   33 +
 gas/testsuite/gas/s12z/jsr.s                    |   20 +
 gas/testsuite/gas/s12z/ld-imm-page2.d           |   15 +
 gas/testsuite/gas/s12z/ld-imm-page2.s           |    2 +
 gas/testsuite/gas/s12z/ld-imm.d                 |   25 +
 gas/testsuite/gas/s12z/ld-imm.s                 |   16 +
 gas/testsuite/gas/s12z/ld-immu18.d              |   28 +
 gas/testsuite/gas/s12z/ld-immu18.s              |   10 +
 gas/testsuite/gas/s12z/ld-large-direct.d        |   21 +
 gas/testsuite/gas/s12z/ld-large-direct.s        |   11 +
 gas/testsuite/gas/s12z/ld-opr.d                 |   22 +
 gas/testsuite/gas/s12z/ld-opr.s                 |   10 +
 gas/testsuite/gas/s12z/ld-s-opr.d               |   16 +
 gas/testsuite/gas/s12z/ld-s-opr.s               |    4 +
 gas/testsuite/gas/s12z/ld-small-direct.d        |   31 +
 gas/testsuite/gas/s12z/ld-small-direct.s        |   11 +
 gas/testsuite/gas/s12z/lea-immu18.d             |   14 +
 gas/testsuite/gas/s12z/lea-immu18.s             |    3 +
 gas/testsuite/gas/s12z/lea.d                    |   18 +
 gas/testsuite/gas/s12z/lea.s                    |    8 +
 gas/testsuite/gas/s12z/mac.d                    |   23 +
 gas/testsuite/gas/s12z/mac.s                    |    8 +
 gas/testsuite/gas/s12z/min-max.d                |   48 +
 gas/testsuite/gas/s12z/min-max.s                |   32 +
 gas/testsuite/gas/s12z/mod.d                    |   23 +
 gas/testsuite/gas/s12z/mod.s                    |    8 +
 gas/testsuite/gas/s12z/mov.d                    |   26 +
 gas/testsuite/gas/s12z/mov.s                    |    8 +
 gas/testsuite/gas/s12z/mul-imm.d                |   19 +
 gas/testsuite/gas/s12z/mul-imm.s                |    6 +
 gas/testsuite/gas/s12z/mul-opr-opr.d            |   19 +
 gas/testsuite/gas/s12z/mul-opr-opr.s            |    6 +
 gas/testsuite/gas/s12z/mul-opr.d                |   17 +
 gas/testsuite/gas/s12z/mul-opr.s                |    6 +
 gas/testsuite/gas/s12z/mul-reg.d                |   27 +
 gas/testsuite/gas/s12z/mul-reg.s                |   16 +
 gas/testsuite/gas/s12z/mul.d                    |   19 +
 gas/testsuite/gas/s12z/mul.s                    |    6 +
 gas/testsuite/gas/s12z/neg-opr.d                |   34 +
 gas/testsuite/gas/s12z/neg-opr.s                |   21 +
 gas/testsuite/gas/s12z/not-so-simple-shifts.d   |   17 +
 gas/testsuite/gas/s12z/not-so-simple-shifts.s   |    4 +
 gas/testsuite/gas/s12z/opr-18u.d                |   26 +
 gas/testsuite/gas/s12z/opr-18u.s                |   15 +
 gas/testsuite/gas/s12z/opr-expr.d               |   13 +
 gas/testsuite/gas/s12z/opr-expr.s               |    5 +
 gas/testsuite/gas/s12z/opr-ext-18.d             |   13 +
 gas/testsuite/gas/s12z/opr-ext-18.s             |    5 +
 gas/testsuite/gas/s12z/opr-idx-24-reg.d         |   13 +
 gas/testsuite/gas/s12z/opr-idx-24-reg.s         |    2 +
 gas/testsuite/gas/s12z/opr-idx3-reg.d           |   17 +
 gas/testsuite/gas/s12z/opr-idx3-reg.s           |    3 +
 gas/testsuite/gas/s12z/opr-idx3-xysp-24.d       |   15 +
 gas/testsuite/gas/s12z/opr-idx3-xysp-24.s       |    3 +
 gas/testsuite/gas/s12z/opr-indirect-expr.d      |   14 +
 gas/testsuite/gas/s12z/opr-indirect-expr.s      |    1 +
 gas/testsuite/gas/s12z/opr-symbol.d             |  170 +
 gas/testsuite/gas/s12z/opr-symbol.s             |  109 +
 gas/testsuite/gas/s12z/or-imm.d                 |   21 +
 gas/testsuite/gas/s12z/or-imm.s                 |    8 +
 gas/testsuite/gas/s12z/or-opr.d                 |   21 +
 gas/testsuite/gas/s12z/or-opr.s                 |    8 +
 gas/testsuite/gas/s12z/p2-mul.d                 |   17 +
 gas/testsuite/gas/s12z/p2-mul.s                 |    7 +
 gas/testsuite/gas/s12z/page2-inh.d              |   15 +
 gas/testsuite/gas/s12z/page2-inh.s              |    5 +
 gas/testsuite/gas/s12z/psh-pul.d                |   21 +
 gas/testsuite/gas/s12z/psh-pul.s                |    8 +
 gas/testsuite/gas/s12z/qmul.d                   |   23 +
 gas/testsuite/gas/s12z/qmul.s                   |    8 +
 gas/testsuite/gas/s12z/rotate.d                 |   22 +
 gas/testsuite/gas/s12z/rotate.s                 |   10 +
 gas/testsuite/gas/s12z/s12z.exp                 |  132 +
 gas/testsuite/gas/s12z/sat.d                    |   19 +
 gas/testsuite/gas/s12z/sat.s                    |    8 +
 gas/testsuite/gas/s12z/sbc-imm.d                |   21 +
 gas/testsuite/gas/s12z/sbc-imm.s                |    8 +
 gas/testsuite/gas/s12z/sbc-opr.d                |   23 +
 gas/testsuite/gas/s12z/sbc-opr.s                |    9 +
 gas/testsuite/gas/s12z/shift.d                  |   22 +
 gas/testsuite/gas/s12z/shift.s                  |   11 +
 gas/testsuite/gas/s12z/simple-shift.d           |   18 +
 gas/testsuite/gas/s12z/simple-shift.s           |    9 +
 gas/testsuite/gas/s12z/single-ops.d             |   15 +
 gas/testsuite/gas/s12z/single-ops.s             |    4 +
 gas/testsuite/gas/s12z/specd6.d                 |   14 +
 gas/testsuite/gas/s12z/specd6.s                 |    4 +
 gas/testsuite/gas/s12z/st-large-direct.d        |   21 +
 gas/testsuite/gas/s12z/st-large-direct.s        |   11 +
 gas/testsuite/gas/s12z/st-opr.d                 |   22 +
 gas/testsuite/gas/s12z/st-opr.s                 |   10 +
 gas/testsuite/gas/s12z/st-s-opr.d               |   16 +
 gas/testsuite/gas/s12z/st-s-opr.s               |    4 +
 gas/testsuite/gas/s12z/st-small-direct.d        |   34 +
 gas/testsuite/gas/s12z/st-small-direct.s        |   12 +
 gas/testsuite/gas/s12z/st-xy.d                  |   12 +
 gas/testsuite/gas/s12z/st-xy.s                  |    3 +
 gas/testsuite/gas/s12z/sub-imm.d                |   21 +
 gas/testsuite/gas/s12z/sub-imm.s                |    8 +
 gas/testsuite/gas/s12z/sub-opr.d                |   22 +
 gas/testsuite/gas/s12z/sub-opr.s                |    9 +
 gas/testsuite/gas/s12z/tfr.d                    |   20 +
 gas/testsuite/gas/s12z/tfr.s                    |    9 +
 gas/testsuite/gas/s12z/trap.d                   |  105 +
 gas/testsuite/gas/s12z/trap.s                   |   96 +
 include/ChangeLog                               |    4 +
 include/elf/s12z.h                              |   36 +
 ld/ChangeLog                                    |   20 +
 ld/Makefile.am                                  |    5 +
 ld/Makefile.in                                  |    6 +
 ld/configure.tgt                                |    2 +
 ld/emulparams/m9s12zelf.sh                      |   18 +
 ld/scripttempl/elfm9s12z.sc                     |  444 +++
 ld/testsuite/ld-discard/static.d                |    2 +-
 ld/testsuite/ld-elf/endsym.d                    |    2 +-
 ld/testsuite/ld-elf/merge.d                     |    2 +-
 ld/testsuite/ld-elf/pr14926.d                   |    2 +-
 ld/testsuite/ld-elf/sec64k.exp                  |    1 +
 ld/testsuite/ld-s12z/opr-linking.d              |   20 +
 ld/testsuite/ld-s12z/opr-linking.s              |    7 +
 ld/testsuite/ld-s12z/relative-linking.d         |   14 +
 ld/testsuite/ld-s12z/relative-linking.s         |    5 +
 ld/testsuite/ld-s12z/z12s.exp                   |   33 +
 opcodes/ChangeLog                               |   11 +
 opcodes/Makefile.am                             |    1 +
 opcodes/Makefile.in                             |    2 +
 opcodes/configure                               |    1 +
 opcodes/configure.ac                            |    1 +
 opcodes/disassemble.c                           |    5 +
 opcodes/disassemble.h                           |    1 +
 opcodes/s12z-dis.c                              | 2672 ++++++++++++++++
 opcodes/s12z.h                                  |   71 +
 259 files changed, 11812 insertions(+), 5 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index a9248e6..0319fa7 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,22 @@
+2018-05-18  John Darrington  <john@darrington.wattle.id.au>
+
+	* 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.
+
 2018-05-18  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/23189
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 8500a4f..8374bbd 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -123,6 +123,7 @@ ALL_MACHINES = \
 	cpu-m68hc11.lo \
 	cpu-m68hc12.lo \
 	cpu-m9s12x.lo \
+	cpu-s12z.lo \
 	cpu-m9s12xg.lo \
 	cpu-m68k.lo \
 	cpu-mcore.lo \
@@ -207,6 +208,7 @@ ALL_MACHINES_CFILES = \
 	cpu-m68hc11.c \
 	cpu-m68hc12.c \
 	cpu-m9s12x.c \
+	cpu-s12z.c \
 	cpu-m9s12xg.c \
 	cpu-m68k.c \
 	cpu-mcore.c \
@@ -322,6 +324,7 @@ BFD32_BACKENDS = \
 	elf32-m68hc12.lo \
 	elf32-m68hc1x.lo \
 	elf32-m68k.lo \
+	elf32-s12z.lo \
 	elf32-mcore.lo \
 	elf32-mep.lo \
 	elf32-metag.lo \
@@ -458,6 +461,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-m68hc12.c \
 	elf32-m68hc1x.c \
 	elf32-m68k.c \
+	elf32-s12z.c \
 	elf32-mcore.c \
 	elf32-mep.c \
 	elf32-metag.c \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index ccd9ce1..88b6b8e 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -456,6 +456,7 @@ ALL_MACHINES = \
 	cpu-m68hc11.lo \
 	cpu-m68hc12.lo \
 	cpu-m9s12x.lo \
+	cpu-s12z.lo \
 	cpu-m9s12xg.lo \
 	cpu-m68k.lo \
 	cpu-mcore.lo \
@@ -540,6 +541,7 @@ ALL_MACHINES_CFILES = \
 	cpu-m68hc11.c \
 	cpu-m68hc12.c \
 	cpu-m9s12x.c \
+	cpu-s12z.c \
 	cpu-m9s12xg.c \
 	cpu-m68k.c \
 	cpu-mcore.c \
@@ -656,6 +658,7 @@ BFD32_BACKENDS = \
 	elf32-m68hc12.lo \
 	elf32-m68hc1x.lo \
 	elf32-m68k.lo \
+	elf32-s12z.lo \
 	elf32-mcore.lo \
 	elf32-mep.lo \
 	elf32-metag.lo \
@@ -792,6 +795,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-m68hc12.c \
 	elf32-m68hc1x.c \
 	elf32-m68k.c \
+	elf32-s12z.c \
 	elf32-mcore.c \
 	elf32-mep.c \
 	elf32-metag.c \
@@ -1253,6 +1257,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m68k.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m9s12x.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m9s12xg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-s12z.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mcore.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-metag.Plo@am__quote@
@@ -1344,6 +1349,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68hc12.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68hc1x.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-s12z.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mcore.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-metag.Plo@am__quote@
diff --git a/bfd/archures.c b/bfd/archures.c
index 4c20664..3af7ddd 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -281,6 +281,8 @@ DESCRIPTION
 .#define bfd_mach_m6812s	2
 .  bfd_arch_m9s12x,    {* Freescale S12X.  *}
 .  bfd_arch_m9s12xg,   {* Freescale XGATE.  *}
+.  bfd_arch_s12z,    {* Freescale S12Z.  *}
+.#define bfd_mach_s12z_default 0
 .  bfd_arch_z8k,       {* Zilog Z8000.  *}
 .#define bfd_mach_z8001		1
 .#define bfd_mach_z8002		2
@@ -590,6 +592,7 @@ extern const bfd_arch_info_type bfd_m68hc11_arch;
 extern const bfd_arch_info_type bfd_m68hc12_arch;
 extern const bfd_arch_info_type bfd_m9s12x_arch;
 extern const bfd_arch_info_type bfd_m9s12xg_arch;
+extern const bfd_arch_info_type bfd_s12z_arch;
 extern const bfd_arch_info_type bfd_m68k_arch;
 extern const bfd_arch_info_type bfd_mcore_arch;
 extern const bfd_arch_info_type bfd_mep_arch;
@@ -679,6 +682,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] =
     &bfd_m68hc12_arch,
     &bfd_m9s12x_arch,
     &bfd_m9s12xg_arch,
+    &bfd_s12z_arch,
     &bfd_m68k_arch,
     &bfd_mcore_arch,
     &bfd_mep_arch,
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 50a8b52..481587e 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -581,6 +581,8 @@ void bfd_putb64 (bfd_uint64_t, void *);
 void bfd_putl64 (bfd_uint64_t, void *);
 void bfd_putb32 (bfd_vma, void *);
 void bfd_putl32 (bfd_vma, void *);
+void bfd_putb24 (bfd_vma, void *);
+void bfd_putl24 (bfd_vma, void *);
 void bfd_putb16 (bfd_vma, void *);
 void bfd_putl16 (bfd_vma, void *);
 
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 5f7ecd3..c64eee1 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -588,6 +588,8 @@ void bfd_putb64 (bfd_uint64_t, void *);
 void bfd_putl64 (bfd_uint64_t, void *);
 void bfd_putb32 (bfd_vma, void *);
 void bfd_putl32 (bfd_vma, void *);
+void bfd_putb24 (bfd_vma, void *);
+void bfd_putl24 (bfd_vma, void *);
 void bfd_putb16 (bfd_vma, void *);
 void bfd_putl16 (bfd_vma, void *);
 
@@ -2149,6 +2151,8 @@ enum bfd_architecture
 #define bfd_mach_m6812s        2
   bfd_arch_m9s12x,    /* Freescale S12X.  */
   bfd_arch_m9s12xg,   /* Freescale XGATE.  */
+  bfd_arch_s12z,    /* Freescale S12Z.  */
+#define bfd_mach_s12z_default 0
   bfd_arch_z8k,       /* Zilog Z8000.  */
 #define bfd_mach_z8001         1
 #define bfd_mach_z8002         2
@@ -5253,6 +5257,11 @@ This is the 8 bit high part of an absolute address and immediately follows
 a matching LO8XG part.  */
   BFD_RELOC_M68HC12_HI8XG,
 
+/* Freescale S12Z reloc.
+This is a 15 bit relative address.  If the most significant bits are all zero
+then it may be truncated to 8 bits.  */
+  BFD_RELOC_S12Z_15_PCREL,
+
 /* NS CR16C Relocations.  */
   BFD_RELOC_16C_NUM08,
   BFD_RELOC_16C_NUM08_C,
diff --git a/bfd/config.bfd b/bfd/config.bfd
index bbd4194..0db8ed4 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -179,6 +179,7 @@ lm32)	         targ_archs=bfd_lm32_arch ;;
 m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;;
 m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;;
 m68*)		 targ_archs=bfd_m68k_arch ;;
+s12z*)         targ_archs=bfd_s12z_arch ;;
 microblaze*)	 targ_archs=bfd_microblaze_arch ;;
 mips*)		 targ_archs=bfd_mips_arch ;;
 nds32*)		 targ_archs=bfd_nds32_arch ;;
@@ -814,6 +815,9 @@ case "${targ}" in
     targ_defvec=m68k_elf32_vec
     ;;
 
+  s12z-*-*)
+    targ_defvec=s12z_elf32_vec
+    ;;
   mcore-*-elf)
     targ_defvec=mcore_elf32_be_vec
     targ_selvecs="mcore_elf32_be_vec mcore_elf32_le_vec"
diff --git a/bfd/configure b/bfd/configure
index edc1de9..2f3dbe7 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -14465,6 +14465,7 @@ do
     m68hc11_elf32_vec)		 tb="$tb elf32-m68hc11.lo elf32-m68hc1x.lo elf32.lo $elf" ;;
     m68hc12_elf32_vec)		 tb="$tb elf32-m68hc12.lo elf32-m68hc1x.lo elf32.lo $elf" ;;
     m68k_elf32_vec)		 tb="$tb elf32-m68k.lo elf32.lo $elf" ;;
+    s12z_elf32_vec)		 tb="$tb elf32-s12z.lo elf32.lo $elf" ;;
     mach_o_be_vec)		 tb="$tb mach-o.lo dwarf2.lo" ;;
     mach_o_le_vec)		 tb="$tb mach-o.lo dwarf2.lo" ;;
     mach_o_fat_vec)		 tb="$tb mach-o.lo dwarf2.lo" ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 1297469..b320828 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -520,6 +520,7 @@ do
     m68hc11_elf32_vec)		 tb="$tb elf32-m68hc11.lo elf32-m68hc1x.lo elf32.lo $elf" ;;
     m68hc12_elf32_vec)		 tb="$tb elf32-m68hc12.lo elf32-m68hc1x.lo elf32.lo $elf" ;;
     m68k_elf32_vec)		 tb="$tb elf32-m68k.lo elf32.lo $elf" ;;
+    s12z_elf32_vec)		 tb="$tb elf32-s12z.lo elf32.lo $elf" ;;
     mach_o_be_vec)		 tb="$tb mach-o.lo dwarf2.lo" ;;
     mach_o_le_vec)		 tb="$tb mach-o.lo dwarf2.lo" ;;
     mach_o_fat_vec)		 tb="$tb mach-o.lo dwarf2.lo" ;;
diff --git a/bfd/cpu-s12z.c b/bfd/cpu-s12z.c
new file mode 100644
index 0000000..07bcb49
--- /dev/null
+++ b/bfd/cpu-s12z.c
@@ -0,0 +1,41 @@
+/* BFD support for the Freescale 9S12Z processor
+   Copyright (C) 2008-2018 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+
+const bfd_arch_info_type bfd_s12z_arch =
+{
+    16,	/* 16 bits in a word.  */
+    24,	/* 24 bits in an address.  */
+    8,	/* 8 bits in a byte.  */
+    bfd_arch_s12z,
+    0,
+    "s12z",
+    "s12z",
+    4, /* Section alignment power.  */
+    TRUE,
+    bfd_default_compatible,
+    bfd_default_scan,
+    bfd_arch_default_fill,
+    0,
+};
+
diff --git a/bfd/elf32-s12z.c b/bfd/elf32-s12z.c
new file mode 100644
index 0000000..4b638e6
--- /dev/null
+++ b/bfd/elf32-s12z.c
@@ -0,0 +1,270 @@
+/* Freescale S12Z-specific support for 32-bit ELF
+   Copyright (C) 1999-2018 Free Software Foundation, Inc.
+   (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com))
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+
+#include "elf/s12z.h"
+
+/* Relocation functions.  */
+static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
+  (bfd *, bfd_reloc_code_real_type);
+static bfd_boolean s12z_info_to_howto_rel
+  (bfd *, arelent *, Elf_Internal_Rela *);
+
+static bfd_reloc_status_type
+shift_addend_reloc (bfd *abfd, arelent *reloc_entry, struct bfd_symbol *symbol ATTRIBUTE_UNUSED,
+		    void *data ATTRIBUTE_UNUSED, asection *input_section ATTRIBUTE_UNUSED,
+		    bfd *output ATTRIBUTE_UNUSED, char **msg ATTRIBUTE_UNUSED)
+{
+  /* This is a really peculiar reloc, which is done for compatibility
+     with the Freescale toolchain.
+
+     That toolchain appears to (ab)use the lowest 15 bits of the addend for
+     the purpose of holding flags.  The purpose of these flags are unknown.
+     So in this function, when writing the bfd we left shift the addend by
+     15, and when reading we right shift it by 15 (discarding the lower bits).
+
+     This allows the linker to work with object files generated by Freescale,
+     as well as by Gas.  */
+
+  if (abfd->is_linker_input)
+    reloc_entry->addend >>= 15;
+  else
+    reloc_entry->addend <<= 15;
+
+  return bfd_reloc_continue;
+}
+
+#define USE_REL	0
+
+static reloc_howto_type elf_s12z_howto_table[] =
+{
+  /* This reloc does nothing.  */
+  HOWTO (R_S12Z_NONE,	/* type */
+	 0,			/* rightshift */
+	 3,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont,/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_S12Z_NONE",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* A 24 bit absolute relocation emitted by the OPR mode operands  */
+  HOWTO (R_S12Z_OPR,        /* type */
+	 0,			/* rightshift */
+	 5,			/* size (0 = byte, 1 = short, 2 = long) */
+	 24,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 shift_addend_reloc,
+	 "R_S12Z_OPR",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x00ffffff,            /* src_mask */
+	 0x00ffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* The purpose of this reloc is not known */
+  HOWTO (R_S12Z_UKNWN_2,	/* type */
+	 0,			/* rightshift */
+	 3,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont,/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_S12Z_UKNWN_2",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* A 15 bit PC-rel relocation */
+  HOWTO (R_S12Z_PCREL_7_15,	/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 15,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 shift_addend_reloc,
+	 "R_S12Z_PCREL_7_15",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x00,                  /* src_mask */
+	 0x007fff,		/* dst_mask */
+	 TRUE),		/* pcrel_offset */
+
+  /* A 24 bit absolute relocation emitted by EXT24 mode operands */
+  HOWTO (R_S12Z_EXT24,        /* type */
+	 0,			/* rightshift */
+	 5,			/* size (0 = byte, 1 = short, 2 = long) */
+	 24,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_S12Z_EXT24",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x00ffffff,            /* src_mask */
+	 0x00ffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* The purpose of this reloc is not known */
+  HOWTO (R_S12Z_UKNWN_3,	/* type */
+	 0,			/* rightshift */
+	 3,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont,/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_S12Z_UKNWN_3",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* A 32 bit absolute relocation  */
+  HOWTO (R_S12Z_EXT32,        /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_S12Z_EXT32",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffff,            /* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+};
+
+/* Map BFD reloc types to S12Z ELF reloc types.  */
+
+struct s12z_reloc_map
+{
+  bfd_reloc_code_real_type bfd_reloc_val;
+  unsigned char elf_reloc_val;
+};
+
+static const struct s12z_reloc_map s12z_reloc_map[] =
+{
+  /* bfd reloc val */ /* elf reloc val */
+  {BFD_RELOC_NONE, R_S12Z_NONE},
+  {BFD_RELOC_32, R_S12Z_EXT32},
+  {BFD_RELOC_24, R_S12Z_EXT24},
+  {BFD_RELOC_16_PCREL, R_S12Z_PCREL_7_15}
+};
+
+static reloc_howto_type *
+bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				 bfd_reloc_code_real_type code)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < sizeof (s12z_reloc_map) / sizeof (struct s12z_reloc_map);
+       i++)
+    {
+      if (s12z_reloc_map[i].bfd_reloc_val == code)
+	{
+	  return &elf_s12z_howto_table[s12z_reloc_map[i].elf_reloc_val];
+	}
+    }
+
+  printf ("%s:%d Not found type %d\n", __FILE__, __LINE__, code);
+
+  return NULL;
+}
+
+static reloc_howto_type *
+bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				 const char *r_name)
+{
+  unsigned int i;
+
+  printf ("%s:%d Looking up %s\n", __FILE__, __LINE__, r_name);
+
+  for (i = 0;
+       i < (sizeof (elf_s12z_howto_table)
+	    / sizeof (elf_s12z_howto_table[0]));
+       i++)
+    if (elf_s12z_howto_table[i].name != NULL
+	&& strcasecmp (elf_s12z_howto_table[i].name, r_name) == 0)
+      return &elf_s12z_howto_table[i];
+
+  return NULL;
+}
+
+/* Set the howto pointer for an S12Z ELF reloc.  */
+
+static bfd_boolean
+s12z_info_to_howto_rel (bfd *abfd,
+			  arelent *cache_ptr, Elf_Internal_Rela *dst)
+{
+  unsigned int  r_type = ELF32_R_TYPE (dst->r_info);
+
+  if (r_type >= (unsigned int) R_S12Z_max)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+			  abfd, r_type);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  cache_ptr->howto = &elf_s12z_howto_table[r_type];
+  return TRUE;
+}
+
+static bfd_boolean
+s12z_elf_set_mach_from_flags (bfd *abfd)
+{
+  bfd_default_set_arch_mach (abfd, bfd_arch_s12z, 0); // bfd_mach_s12z);
+
+  return TRUE;
+}
+
+#define ELF_ARCH		bfd_arch_s12z
+#define ELF_TARGET_ID		0
+#define ELF_MACHINE_CODE	EM_S12Z
+#define ELF_MAXPAGESIZE		0x1000
+
+#define TARGET_BIG_SYM		s12z_elf32_vec
+#define TARGET_BIG_NAME		"elf32-s12z"
+
+#define elf_info_to_howto			NULL
+#define elf_info_to_howto_rel			s12z_info_to_howto_rel
+#define elf_backend_object_p			s12z_elf_set_mach_from_flags
+#define elf_backend_final_write_processing	NULL
+#define elf_backend_can_gc_sections		1
+
+#include "elf32-target.h"
diff --git a/bfd/libbfd.c b/bfd/libbfd.c
index c581238..971be4f 100644
--- a/bfd/libbfd.c
+++ b/bfd/libbfd.c
@@ -613,6 +613,27 @@ bfd_putl16 (bfd_vma data, void *p)
   addr[1] = (data >> 8) & 0xff;
 }
 
+
+void
+bfd_putb24 (bfd_vma data, void *p)
+{
+  bfd_byte *addr = (bfd_byte *) p;
+  addr[0] = (data >> 16) & 0xff;
+  addr[1] = (data >> 8) & 0xff;
+  addr[2] = data & 0xff;
+}
+
+
+void
+bfd_putl24 (bfd_vma data, void *p)
+{
+  bfd_byte *addr = (bfd_byte *) p;
+  addr[0] = data & 0xff;
+  addr[1] = (data >> 8) & 0xff;
+  addr[2] = (data >> 16) & 0xff;
+}
+
+
 bfd_vma
 bfd_getb32 (const void *p)
 {
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index e8c0fd8..b810c40 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2513,6 +2513,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_M68HC12_10_PCREL",
   "BFD_RELOC_M68HC12_LO8XG",
   "BFD_RELOC_M68HC12_HI8XG",
+  "BFD_RELOC_S12Z_15_PCREL",
   "BFD_RELOC_16C_NUM08",
   "BFD_RELOC_16C_NUM08_C",
   "BFD_RELOC_16C_NUM16",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index f7e34a9..411f998 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -431,6 +431,7 @@ bfd_get_reloc_size (reloc_howto_type *howto)
 {
   switch (howto->size)
     {
+    case 5: return 3;
     case 0: return 1;
     case 1: return 2;
     case 2: return 4;
@@ -917,6 +918,16 @@ space consuming.  For each target:
 
   switch (howto->size)
     {
+    case 5:
+      {
+	long x = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+	x >>= 8;
+	DOIT (x);
+	bfd_put_16 (abfd, (bfd_vma) (x >> 8), (bfd_byte *) data + octets);
+	bfd_put_8 (abfd, (x & 0xFF), (unsigned char *) data + 2 + octets);
+      }
+      break;
+
     case 0:
       {
 	char x = bfd_get_8 (abfd, (char *) data + octets);
@@ -5949,6 +5960,12 @@ ENUMDOC
   This is the 8 bit high part of an absolute address and immediately follows
   a matching LO8XG part.
 ENUM
+  BFD_RELOC_S12Z_15_PCREL
+ENUMDOC
+  Freescale S12Z reloc.
+  This is a 15 bit relative address.  If the most significant bits are all zero
+  then it may be truncated to 8 bits.
+ENUM
   BFD_RELOC_16C_NUM08
 ENUMX
   BFD_RELOC_16C_NUM08_C
diff --git a/bfd/targets.c b/bfd/targets.c
index 5d78f57..5a2a684 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -684,6 +684,7 @@ extern const bfd_target m32r_elf32_linux_le_vec;
 extern const bfd_target m68hc11_elf32_vec;
 extern const bfd_target m68hc12_elf32_vec;
 extern const bfd_target m68k_elf32_vec;
+extern const bfd_target s12z_elf32_vec;
 extern const bfd_target mach_o_be_vec;
 extern const bfd_target mach_o_le_vec;
 extern const bfd_target mach_o_fat_vec;
@@ -1044,6 +1045,8 @@ static const bfd_target * const _bfd_target_vector[] =
 
 	&m68k_elf32_vec,
 
+	&s12z_elf32_vec,
+
 	&mach_o_be_vec,
 	&mach_o_le_vec,
 	&mach_o_fat_vec,
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 3d90103..fd77f44 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2018-05-18  John Darrington  <john@darrington.wattle.id.au>
+
+	* readelf.c: Add support for s12z architecture.
+	* testsuite/lib/binutils-common.exp (is_elf_format): Excluse s12z
+	targets.
+
 2018-05-15  Tamar Christina  <tamar.christina@arm.com>
 
 	PR binutils/21446
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 6a9c51d..6a9319f 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -119,6 +119,7 @@
 #include "elf/m32r.h"
 #include "elf/m68k.h"
 #include "elf/m68hc11.h"
+#include "elf/s12z.h"
 #include "elf/mcore.h"
 #include "elf/mep.h"
 #include "elf/metag.h"
@@ -1274,6 +1275,10 @@ dump_relocations (Filedata *          filedata,
 	  rtype = elf_m68hc11_reloc_type (type);
 	  break;
 
+	case EM_S12Z:
+	  rtype = elf_s12z_reloc_type (type);
+	  break;
+
 	case EM_68K:
 	  rtype = elf_m68k_reloc_type (type);
 	  break;
@@ -12309,6 +12314,8 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_68HC11:
     case EM_68HC12:
       return reloc_type == 6; /* R_M68HC11_32.  */
+    case EM_S12Z:
+      return reloc_type == 6; /* R_S12Z_EXT32.  */
     case EM_MCORE:
       return reloc_type == 1; /* R_MCORE_ADDR32.  */
     case EM_CYGNUS_MEP:
diff --git a/binutils/testsuite/binutils-all/dw2-1.S b/binutils/testsuite/binutils-all/dw2-1.S
index 06cb593..6342a0e 100644
--- a/binutils/testsuite/binutils-all/dw2-1.S
+++ b/binutils/testsuite/binutils-all/dw2-1.S
@@ -27,6 +27,8 @@ _start:
 func_cu1:
 .Lbegin_func_cu1:
 	.4byte 0
+	.global func_cu1_end
+func_cu1_end:	
 .Lend_func_cu1:
 	.size func_cu1, .-func_cu1
 .Lend_text1:
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index 9fc9a18..dcaab84 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -23,7 +23,7 @@ proc is_elf_format {} {
     # config.sub for these targets curiously transforms a target doublet
     # ending in -elf to -none.  eg. m68hc12-elf to m68hc12-unknown-none
     # They are always elf.
-    if { [istarget m68hc1*-*] || [istarget xgate-*] } {
+    if { [istarget m68hc1*-*] || [istarget s12z*-*] || [istarget xgate-*] } {
 	return 1;
     }
 # vxworks (and windiss) excluded due to number of ELF tests that need
diff --git a/gas/ChangeLog b/gas/ChangeLog
index c2a5659..39c51b2 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,219 @@
+2018-05-18  John Darrington  <john@darrington.wattle.id.au>
+
+	* 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.
+
 2018-05-16  Maciej W. Rozycki  <macro@mips.com>
 
 	* tc-nds32.c (md_assemble): Rename `expr' local variable to
diff --git a/gas/Makefile.am b/gas/Makefile.am
index 9523770..ff46b0d 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -156,6 +156,7 @@ TARGET_CPU_CFILES = \
 	config/tc-m32r.c \
 	config/tc-m68hc11.c \
 	config/tc-m68k.c \
+	config/tc-s12z.c \
 	config/tc-mcore.c \
 	config/tc-mep.c \
 	config/tc-metag.c \
@@ -229,6 +230,7 @@ TARGET_CPU_HFILES = \
 	config/tc-m32r.h \
 	config/tc-m68hc11.h \
 	config/tc-m68k.h \
+	config/tc-s12z.h \
 	config/tc-mcore.h \
 	config/tc-mep.h \
 	config/tc-metag.h \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index 4feabb3..c127d36 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -452,6 +452,7 @@ TARGET_CPU_CFILES = \
 	config/tc-m32r.c \
 	config/tc-m68hc11.c \
 	config/tc-m68k.c \
+	config/tc-s12z.c \
 	config/tc-mcore.c \
 	config/tc-mep.c \
 	config/tc-metag.c \
@@ -525,6 +526,7 @@ TARGET_CPU_HFILES = \
 	config/tc-m32r.h \
 	config/tc-m68hc11.h \
 	config/tc-m68k.h \
+	config/tc-s12z.h \
 	config/tc-mcore.h \
 	config/tc-mep.h \
 	config/tc-metag.h \
@@ -872,6 +874,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-m32r.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-m68hc11.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-m68k.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-s12z.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-mcore.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-mep.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-metag.Po@am__quote@
@@ -1318,6 +1321,20 @@ tc-m68k.obj: config/tc-m68k.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-m68k.obj `if test -f 'config/tc-m68k.c'; then $(CYGPATH_W) 'config/tc-m68k.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-m68k.c'; fi`
 
+tc-s12z.o: config/tc-s12z.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-s12z.o -MD -MP -MF $(DEPDIR)/tc-s12z.Tpo -c -o tc-s12z.o `test -f 'config/tc-s12z.c' || echo '$(srcdir)/'`config/tc-s12z.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-s12z.Tpo $(DEPDIR)/tc-s12z.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-s12z.c' object='tc-s12z.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-s12z.o `test -f 'config/tc-s12z.c' || echo '$(srcdir)/'`config/tc-s12z.c
+
+tc-s12z.obj: config/tc-s12z.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-s12z.obj -MD -MP -MF $(DEPDIR)/tc-s12z.Tpo -c -o tc-s12z.obj `if test -f 'config/tc-s12z.c'; then $(CYGPATH_W) 'config/tc-s12z.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-s12z.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-s12z.Tpo $(DEPDIR)/tc-s12z.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-s12z.c' object='tc-s12z.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-s12z.obj `if test -f 'config/tc-s12z.c'; then $(CYGPATH_W) 'config/tc-s12z.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-s12z.c'; fi`
+
 tc-mcore.o: config/tc-mcore.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-mcore.o -MD -MP -MF $(DEPDIR)/tc-mcore.Tpo -c -o tc-mcore.o `test -f 'config/tc-mcore.c' || echo '$(srcdir)/'`config/tc-mcore.c
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-mcore.Tpo $(DEPDIR)/tc-mcore.Po
diff --git a/gas/NEWS b/gas/NEWS
index ec1ba78..a05b703 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* Add support for the Freescale S12Z architecture.
+
 * Add --generate-missing-build-notes=[yes|no] option to create (or not) GNU
   Build Attribute notes if none are present in the input sources.  Add a
   --enable-generate-build-notes=[yes|no] configure time option to set the
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[...]

[diff truncated at 100000 bytes]



More information about the Binutils-cvs mailing list