From 22cbcafce0c08683209fe1bba2b7faef111764d4 Mon Sep 17 00:00:00 2001 From: Ake Rehnman Date: Fri, 24 Feb 2017 11:51:54 +0100 Subject: [PATCH 1/10] First commit for stm8-binutils-gdb # Conflicts: # bfd/archures.c # bfd/bfd-in2.h # bfd/libbfd.h # bfd/reloc.c # gas/configure.tgt # gdb/configure.tgt --- bfd/Makefile.am | 12 +- bfd/Makefile.in | 14 +- bfd/archures.c | 4 + bfd/bfd-in2.h | 5 + bfd/config.bfd | 6 + bfd/configure | 1 + bfd/configure.ac | 1 + bfd/cpu-stm8.c | 40 ++ bfd/cpu-stm8.h | 6 + bfd/elf32-stm8.c | 285 +++++++++++ bfd/elfcode.h | 22 +- bfd/libbfd.h | 1 + bfd/reloc.c | 5 + bfd/targets.c | 2 + config.sub | 6 +- gas/Makefile.am | 6 +- gas/Makefile.in | 21 +- gas/config/tc-stm8.c | 1026 ++++++++++++++++++++++++++++++++++++++++ gas/config/tc-stm8.h | 97 ++++ gas/configure.tgt | 4 +- gdb/configure.tgt | 5 + gdb/stm8-tdep.c | 1130 ++++++++++++++++++++++++++++++++++++++++++++ include/dis-asm.h | 1 + include/elf/stm8.h | 38 ++ include/opcode/stm8.h | 82 ++++ ld/Makefile.am | 7 +- ld/Makefile.in | 7 +- ld/configure.tgt | 2 + ld/emulparams/elf32stm8.sh | 14 + ld/scripttempl/elfstm8.sc | 232 +++++++++ opcodes/Makefile.am | 4 +- opcodes/Makefile.in | 6 +- opcodes/configure | 1 + opcodes/configure.ac | 1 + opcodes/disassemble.c | 6 + opcodes/stm8-dis.c | 412 ++++++++++++++++ opcodes/stm8-opc.c | 799 +++++++++++++++++++++++++++++++ 37 files changed, 4286 insertions(+), 25 deletions(-) create mode 100644 bfd/cpu-stm8.c create mode 100644 bfd/cpu-stm8.h create mode 100644 bfd/elf32-stm8.c create mode 100644 gas/config/tc-stm8.c create mode 100644 gas/config/tc-stm8.h create mode 100644 gdb/stm8-tdep.c create mode 100644 include/elf/stm8.h create mode 100644 include/opcode/stm8.h create mode 100644 ld/emulparams/elf32stm8.sh create mode 100644 ld/scripttempl/elfstm8.sc create mode 100644 opcodes/stm8-dis.c create mode 100644 opcodes/stm8-opc.c diff --git a/bfd/Makefile.am b/bfd/Makefile.am index f727ebeb28..83e090ac6d 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -176,7 +176,8 @@ ALL_MACHINES = \ cpu-xstormy16.lo \ cpu-xtensa.lo \ cpu-z80.lo \ - cpu-z8k.lo + cpu-z8k.lo \ + cpu-stm8.lo ALL_MACHINES_CFILES = \ cpu-aarch64.c \ @@ -266,7 +267,8 @@ ALL_MACHINES_CFILES = \ cpu-xstormy16.c \ cpu-xtensa.c \ cpu-z80.c \ - cpu-z8k.c + cpu-z8k.c \ + cpu-stm8.c # The .o files needed by all of the 32 bit vectors that are configured into # target_vector in targets.c if configured with --enable-targets=all. @@ -465,7 +467,8 @@ BFD32_BACKENDS = \ xcofflink.lo \ xsym.lo \ xtensa-isa.lo \ - xtensa-modules.lo + xtensa-modules.lo \ + elf32-stm8.lo BFD32_BACKENDS_CFILES = \ aout-adobe.c \ @@ -661,7 +664,8 @@ BFD32_BACKENDS_CFILES = \ xcofflink.c \ xsym.c \ xtensa-isa.c \ - xtensa-modules.c + xtensa-modules.c \ + elf32-stm8.c # The .o files needed by all of the 64 bit vectors that are configured into # target_vector in targets.c if configured with --enable-targets=all diff --git a/bfd/Makefile.in b/bfd/Makefile.in index 40608238b7..e26cfc58c5 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -509,7 +509,8 @@ ALL_MACHINES = \ cpu-xstormy16.lo \ cpu-xtensa.lo \ cpu-z80.lo \ - cpu-z8k.lo + cpu-z8k.lo \ + cpu-stm8.lo ALL_MACHINES_CFILES = \ cpu-aarch64.c \ @@ -599,7 +600,8 @@ ALL_MACHINES_CFILES = \ cpu-xstormy16.c \ cpu-xtensa.c \ cpu-z80.c \ - cpu-z8k.c + cpu-z8k.c \ + cpu-stm8.c # The .o files needed by all of the 32 bit vectors that are configured into @@ -799,7 +801,8 @@ BFD32_BACKENDS = \ xcofflink.lo \ xsym.lo \ xtensa-isa.lo \ - xtensa-modules.lo + xtensa-modules.lo \ + elf32-stm8.lo BFD32_BACKENDS_CFILES = \ aout-adobe.c \ @@ -995,7 +998,8 @@ BFD32_BACKENDS_CFILES = \ xcofflink.c \ xsym.c \ xtensa-isa.c \ - xtensa-modules.c + xtensa-modules.c \ + elf32-stm8.c # The .o files needed by all of the 64 bit vectors that are configured into @@ -1446,6 +1450,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-sh.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-sparc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-spu.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-stm8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic30.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic4x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic54x.Plo@am__quote@ @@ -1542,6 +1547,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-sh64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-sparc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-spu.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-stm8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-tic6x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-tilegx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-tilepro.Plo@am__quote@ diff --git a/bfd/archures.c b/bfd/archures.c index e83c57a2f3..d23bb2c77a 100644 --- a/bfd/archures.c +++ b/bfd/archures.c @@ -537,6 +537,8 @@ DESCRIPTION .#define bfd_mach_wasm32 1 . bfd_arch_pru, {* PRU. *} .#define bfd_mach_pru 0 +. bfd_arch_stm8, {* ST STM8 *} +.#define bfd_mach_stm8 1 . bfd_arch_last . }; */ @@ -670,6 +672,7 @@ extern const bfd_arch_info_type bfd_xc16x_arch; extern const bfd_arch_info_type bfd_xgate_arch; extern const bfd_arch_info_type bfd_z80_arch; extern const bfd_arch_info_type bfd_z8k_arch; +extern const bfd_arch_info_type bfd_stm8_arch; static const bfd_arch_info_type * const bfd_archures_list[] = { @@ -762,6 +765,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_xgate_arch, &bfd_z80_arch, &bfd_z8k_arch, + &bfd_stm8_arch, #endif 0 }; diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index f4b3720b4b..78221ddcc1 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2398,6 +2398,8 @@ enum bfd_architecture #define bfd_mach_wasm32 1 bfd_arch_pru, /* PRU. */ #define bfd_mach_pru 0 + bfd_arch_stm8, /* ST STM8 */ +#define bfd_mach_stm8 1 bfd_arch_last }; @@ -6512,6 +6514,9 @@ assembler and not (currently) written to any object files. */ BFD_RELOC_WASM32_CODE_POINTER, BFD_RELOC_WASM32_INDEX, BFD_RELOC_WASM32_PLT_SIG, + +/* STM8 bit field immediate for BTJx, BCPL, BSET, BRES instruction. */ + BFD_RELOC_STM8_BIT_FLD, BFD_RELOC_UNUSED }; typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; diff --git a/bfd/config.bfd b/bfd/config.bfd index f04a993f06..ec98fc050f 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -203,6 +203,7 @@ xtensa*) targ_archs=bfd_xtensa_arch ;; xgate) targ_archs=bfd_xgate_arch ;; z80|r800) targ_archs=bfd_z80_arch ;; z8k*) targ_archs=bfd_z8k_arch ;; +stm8*) targ_archs=bfd_stm8_arch ;; *) targ_archs=bfd_${targ_cpu}_arch ;; esac @@ -1850,6 +1851,11 @@ case "${targ}" in targ_underscore=yes ;; + stm8-*-elf*) + targ_defvec=stm8_elf32_vec + targ_underscore=yes + ;; + *-*-ieee*) targ_defvec=ieee_vec ;; diff --git a/bfd/configure b/bfd/configure index 32ee062e80..463d0bedb6 100755 --- a/bfd/configure +++ b/bfd/configure @@ -14641,6 +14641,7 @@ do xtensa_elf32_le_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;; z80_coff_vec) tb="$tb coff-z80.lo reloc16.lo $coffgen" ;; z8k_coff_vec) tb="$tb coff-z8k.lo reloc16.lo $coff" ;; + stm8_elf32_vec) tb="$tb elf32-stm8.lo elf32.lo $elf" ;; # These appear out of order in targets.c srec_vec) tb="$tb srec.lo" ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index 2342f3faea..d093fbe418 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -723,6 +723,7 @@ do xtensa_elf32_le_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;; z80_coff_vec) tb="$tb coff-z80.lo reloc16.lo $coffgen" ;; z8k_coff_vec) tb="$tb coff-z8k.lo reloc16.lo $coff" ;; + stm8_elf32_vec) tb="$tb elf32-stm8.lo elf32.lo $elf" ;; # These appear out of order in targets.c srec_vec) tb="$tb srec.lo" ;; diff --git a/bfd/cpu-stm8.c b/bfd/cpu-stm8.c new file mode 100644 index 0000000000..feb6cf805e --- /dev/null +++ b/bfd/cpu-stm8.c @@ -0,0 +1,40 @@ +/* BFD support for the STM8 processor. + Copyright (C) 2007-2016 Free Software Foundation, Inc. + Written by Åke Rehnman (at) gmail dot 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 "libbfd.h" + +const bfd_arch_info_type bfd_stm8_arch = +{ + 8, /* bits per word */ + 24, /* bits per address */ + 8, /* bits per byte */ + bfd_arch_stm8, /* architecture */ + bfd_mach_stm8, /* machine */ + "stm8", /* architecture name */ + "stm8", /* printable name */ + 4, /* section align power */ + TRUE, /* the default ? */ + bfd_default_compatible, /* architecture comparison fn */ + bfd_default_scan, /* string to architecture convert fn */ + bfd_arch_default_fill, + 0, +}; diff --git a/bfd/cpu-stm8.h b/bfd/cpu-stm8.h new file mode 100644 index 0000000000..665642ca3e --- /dev/null +++ b/bfd/cpu-stm8.h @@ -0,0 +1,6 @@ +#ifndef __CPU_STM8_H +#define __CPU_STM8_H + +extern bfd_stm8_arch; + +#endif diff --git a/bfd/elf32-stm8.c b/bfd/elf32-stm8.c new file mode 100644 index 0000000000..37995553c3 --- /dev/null +++ b/bfd/elf32-stm8.c @@ -0,0 +1,285 @@ +/* STM8-specific support for 32-bit ELF + Copyright (C) 2007-2016 Free Software Foundation, Inc. + Written by Åke Rehnman (at) gmail dot 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 "bfd_stdint.h" +#include "libiberty.h" +#include "libbfd.h" +#include "elf-bfd.h" + +#include "elf/stm8.h" +//#include "elf32-avr.h" +#include "bfd_stdint.h" + +bfd_reloc_status_type +bfd_elf_stm8_spec_reloc (bfd *abfd ATTRIBUTE_UNUSED, + arelent *reloc_entry, + asymbol *symbol, + void *data ATTRIBUTE_UNUSED, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED); + +static reloc_howto_type elf32_stm8_howto_table_1[] = +{ + HOWTO (R_STM8_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_STM8_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* 8 bit offset. */ + HOWTO (R_STM8_8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_STM8_8", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 16 bit absolute relocation. */ + HOWTO (R_STM8_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_STM8_16", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + +//use this with unpatched bfd_get_reloc_size + HOWTO (R_STM8_24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ //the relocation use bfd_get_32 so our relocation end up in the upper 24 bits and so relocation value has to be shifted 8 bits to the left + complain_overflow_unsigned, /* complain_on_overflow */ + //bfd_elf_stm8_spec_reloc, /* special_function */ + bfd_elf_generic_reloc, /* special_function */ + "R_STM8_24", /* name */ + FALSE, /* partial_inplace */ + 0xff000000, /* src_mask */ + 0x00ffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + +// HOWTO (R_STM8_24, /* type */ +// 0, /* rightshift */ +// 99, /* size (0 = byte, 1 = short, 2 = long, 99 = 24 bit) */ +// 24, /* bitsize */ +// FALSE, /* pc_relative */ +// 0, /* bitpos */ //the relocation use bfd_get_32 so our relocation end up in the upper 24 bits and so relocation value has to be shifted 8 bits to the left +// complain_overflow_unsigned, /* complain_on_overflow */ +// bfd_elf_generic_reloc, /* special_function */ +// "R_STM8_24", /* name */ +// FALSE, /* partial_inplace */ +// 0x00, /* src_mask */ +// 0xffffff, /* dst_mask */ +// FALSE), /* pcrel_offset */ + + HOWTO (R_STM8_32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_STM8_32", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 8 bit PC relative relocation. */ + HOWTO (R_STM8_8_PCREL, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_STM8_8_PCREL", /* name */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ +}; + +//stupid bfd_elf_generic_reloc cant handle 24-bit relocations +//so we have to write our own... +bfd_reloc_status_type +bfd_elf_stm8_spec_reloc (bfd *abfd ATTRIBUTE_UNUSED, + arelent *reloc_entry, + asymbol *symbol, + void *data ATTRIBUTE_UNUSED, + asection *input_section ATTRIBUTE_UNUSED, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + if (output_bfd != NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset+1; + return bfd_reloc_ok; + } + + if (output_bfd == NULL) + return bfd_reloc_continue; + reloc_entry->address += input_section->output_offset-1; + return bfd_reloc_continue; +} + +static reloc_howto_type * +elf32_stm8_howto_from_type (unsigned int r_type) +{ + if (r_type < ARRAY_SIZE (elf32_stm8_howto_table_1)) + return &elf32_stm8_howto_table_1[r_type]; + + return NULL; +} + +static void +elf32_stm8_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * bfd_reloc, + Elf_Internal_Rela * elf_reloc) +{ + unsigned int r_type; + + r_type = ELF32_R_TYPE (elf_reloc->r_info); + bfd_reloc->howto = elf32_stm8_howto_from_type (r_type); +} + +struct elf32_stm8_reloc_map + { + bfd_reloc_code_real_type bfd_reloc_val; + unsigned char elf_reloc_val; + }; + +/* All entries in this list must also be present in elf32_stm8_howto_table. */ +static const struct elf32_stm8_reloc_map elf32_stm8_reloc_map[] = +{ + { BFD_RELOC_NONE, R_STM8_NONE }, + { BFD_RELOC_8, R_STM8_8 }, + { BFD_RELOC_16, R_STM8_16 }, + { BFD_RELOC_24, R_STM8_24 }, + { BFD_RELOC_32, R_STM8_32 }, + { BFD_RELOC_8_PCREL, R_STM8_8_PCREL} +}; + +static reloc_howto_type * +elf32_stm8_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (elf32_stm8_reloc_map); i ++) + if (elf32_stm8_reloc_map[i].bfd_reloc_val == code) + return elf32_stm8_howto_from_type (elf32_stm8_reloc_map[i].elf_reloc_val); + + return NULL; +} + +static reloc_howto_type * +elf32_stm8_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (elf32_stm8_howto_table_1); i++) + if (elf32_stm8_howto_table_1[i].name != NULL + && strcasecmp (elf32_stm8_howto_table_1[i].name, r_name) == 0) + return &elf32_stm8_howto_table_1[i]; + + return NULL; +} + +static void +elf32_stm8_post_process_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); +// i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_STANDALONE; +// i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_ARM; +// i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; + i_ehdrp->e_ident[EI_ABIVERSION] = 0; +} + +static bfd_boolean +elf32_stm8_modify_segment_map (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + struct elf_segment_map *m; + return TRUE; + m = elf_seg_map (abfd); + while (m) + { + m->includes_filehdr = 0; + m->includes_phdrs = 0; + m = m->next; + } + return TRUE; +} + + +#define elf_backend_post_process_headers elf32_stm8_post_process_headers +#define elf_backend_modify_segment_map elf32_stm8_modify_segment_map + +#define bfd_elf32_bfd_reloc_type_lookup elf32_stm8_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup elf32_stm8_reloc_name_lookup + +#define ELF_ARCH bfd_arch_stm8 +//#define ELF_TARGET_ID AVR_ELF_DATA +#define ELF_TARGET_ID GENERIC_ELF_DATA +#define ELF_MACHINE_CODE EM_STM8 +//#define ELF_OSABI ELFOSABI_STANDALONE +//#define ELF_MACHINE_ALT1 EM_STM8_OLD +#define ELF_MAXPAGESIZE 1 +//#define TARGET_LITTLE_SYM stm8_elf32_vec +//#define TARGET_LITTLE_NAME "elf32-stm8" +#define TARGET_BIG_SYM stm8_elf32_vec +#define TARGET_BIG_NAME "elf32-stm8" + +#define elf_info_to_howto elf32_stm8_info_to_howto +#define elf_info_to_howto_rel NULL + +#include "elf32-target.h" diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 00a900124a..eec2588464 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -1468,12 +1468,22 @@ elf_slurp_reloc_table_from_section (bfd *abfd, relent->addend = rela.r_addend; - if ((entsize == sizeof (Elf_External_Rela) - && ebd->elf_info_to_howto != NULL) - || ebd->elf_info_to_howto_rel == NULL) - (*ebd->elf_info_to_howto) (abfd, relent, &rela); - else - (*ebd->elf_info_to_howto_rel) (abfd, relent, &rela); +// Ake Rehnman 2017-02-21 +// bug fixed, preventing call to elf_info_to_howto_rel +// if elf_info_to_howto is NULL +// if ((entsize == sizeof (Elf_External_Rela) +// && ebd->elf_info_to_howto != NULL) +// || ebd->elf_info_to_howto_rel == NULL) +// (*ebd->elf_info_to_howto) (abfd, relent, &rela); +// else +// (*ebd->elf_info_to_howto_rel) (abfd, relent, &rela); + if (entsize == sizeof (Elf_External_Rela)) + { + if (ebd->elf_info_to_howto) + (*ebd->elf_info_to_howto) (abfd, relent, &rela); + else if (ebd->elf_info_to_howto_rel) + (*ebd->elf_info_to_howto_rel) (abfd, relent, &rela); + } } if (allocated != NULL) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 2f5f16e776..fca8c19eed 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -3188,6 +3188,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_WASM32_CODE_POINTER", "BFD_RELOC_WASM32_INDEX", "BFD_RELOC_WASM32_PLT_SIG", + "BFD_RELOC_STM8_BIT_FLD", "@@overflow: BFD_RELOC_UNUSED@@", }; #endif diff --git a/bfd/reloc.c b/bfd/reloc.c index a1353a281b..c7b862aab5 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -7931,6 +7931,11 @@ ENUMX ENUMDOC WebAssembly relocations. +ENUM + BFD_RELOC_STM8_BIT_FLD +ENUMDOC + STM8 bit field immediate for BTJx, BCPL, BSET, BRES instruction. + ENDSENUM BFD_RELOC_UNUSED CODE_FRAGMENT diff --git a/bfd/targets.c b/bfd/targets.c index 43102d428b..0e6f7dae2e 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -930,6 +930,7 @@ extern const bfd_target xtensa_elf32_be_vec; extern const bfd_target xtensa_elf32_le_vec; extern const bfd_target z80_coff_vec; extern const bfd_target z8k_coff_vec; +extern const bfd_target stm8_elf32_vec; /* These are always included. */ extern const bfd_target srec_vec; @@ -1174,6 +1175,7 @@ static const bfd_target * const _bfd_target_vector[] = &m68hc11_elf32_vec, &m68hc12_elf32_vec, + &stm8_elf32_vec, #if 0 &m68k_aout_4knbsd_vec, diff --git a/config.sub b/config.sub index 40ea5dfe11..d4a68493c0 100755 --- a/config.sub +++ b/config.sub @@ -318,7 +318,8 @@ case $basic_machine in | wasm32 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) + | z8k | z80 \ + | stm8) basic_machine=$basic_machine-unknown ;; c54x) @@ -452,7 +453,8 @@ case $basic_machine in | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ - | z8k-* | z80-*) + | z8k-* | z80-* \ + | stm8-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) diff --git a/gas/Makefile.am b/gas/Makefile.am index 5aa68f3c6a..b6af0cf2ca 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -203,7 +203,8 @@ TARGET_CPU_CFILES = \ config/tc-xtensa.c \ config/tc-z80.c \ config/tc-z8k.c \ - config/xtensa-relax.c + config/xtensa-relax.c \ + config/tc-stm8.c TARGET_CPU_HFILES = \ config/tc-aarch64.h \ @@ -279,7 +280,8 @@ TARGET_CPU_HFILES = \ config/tc-xtensa.h \ config/tc-z80.h \ config/tc-z8k.h \ - config/xtensa-relax.h + config/xtensa-relax.h \ + config/tc-stm8.h # OBJ files in config diff --git a/gas/Makefile.in b/gas/Makefile.in index 51e96e52c1..b6d76c5348 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -499,7 +499,8 @@ TARGET_CPU_CFILES = \ config/tc-xtensa.c \ config/tc-z80.c \ config/tc-z8k.c \ - config/xtensa-relax.c + config/xtensa-relax.c \ + config/tc-stm8.c TARGET_CPU_HFILES = \ config/tc-aarch64.h \ @@ -575,7 +576,8 @@ TARGET_CPU_HFILES = \ config/tc-xtensa.h \ config/tc-z80.h \ config/tc-z8k.h \ - config/xtensa-relax.h + config/xtensa-relax.h \ + config/tc-stm8.h # OBJ files in config @@ -920,6 +922,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-sh64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-sparc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-spu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-stm8.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-tic30.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-tic4x.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-tic54x.Po@am__quote@ @@ -2011,6 +2014,20 @@ xtensa-relax.obj: config/xtensa-relax.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 xtensa-relax.obj `if test -f 'config/xtensa-relax.c'; then $(CYGPATH_W) 'config/xtensa-relax.c'; else $(CYGPATH_W) '$(srcdir)/config/xtensa-relax.c'; fi` +tc-stm8.o: config/tc-stm8.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-stm8.o -MD -MP -MF $(DEPDIR)/tc-stm8.Tpo -c -o tc-stm8.o `test -f 'config/tc-stm8.c' || echo '$(srcdir)/'`config/tc-stm8.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-stm8.Tpo $(DEPDIR)/tc-stm8.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-stm8.c' object='tc-stm8.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-stm8.o `test -f 'config/tc-stm8.c' || echo '$(srcdir)/'`config/tc-stm8.c + +tc-stm8.obj: config/tc-stm8.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-stm8.obj -MD -MP -MF $(DEPDIR)/tc-stm8.Tpo -c -o tc-stm8.obj `if test -f 'config/tc-stm8.c'; then $(CYGPATH_W) 'config/tc-stm8.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-stm8.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-stm8.Tpo $(DEPDIR)/tc-stm8.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-stm8.c' object='tc-stm8.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-stm8.obj `if test -f 'config/tc-stm8.c'; then $(CYGPATH_W) 'config/tc-stm8.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-stm8.c'; fi` + obj-aout.o: config/obj-aout.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-aout.o -MD -MP -MF $(DEPDIR)/obj-aout.Tpo -c -o obj-aout.o `test -f 'config/obj-aout.c' || echo '$(srcdir)/'`config/obj-aout.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/obj-aout.Tpo $(DEPDIR)/obj-aout.Po diff --git a/gas/config/tc-stm8.c b/gas/config/tc-stm8.c new file mode 100644 index 0000000000..84e667278e --- /dev/null +++ b/gas/config/tc-stm8.c @@ -0,0 +1,1026 @@ +/* tc-stm8.c -- Assembler for the STM8. + Written by Ake Rehnman 2017-02-21, + ake.rehnman (at) gmail dot com + + Copyright (C) 2007-2017 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 "as.h" +#include +#include +#include +#include +#include "opcode/stm8.h" + +typedef enum { + OP_ILLEGAL = 0, + OP_IMM, + OP_SHORTMEM, + OP_MEM, + OP_INDX, + OP_INDY, + OP_OFF_X, + OP_OFF_Y, + OP_OFF_SP, + OP_PTRW, + OP_PTRE, + OP_PTRW_X, + OP_PTRW_Y, + OP_PTRE_X, + OP_PTRE_Y, + OP_REGISTER +} stm8_operand_t; + +static struct hash_control *stm8_hash; + +const char comment_chars[] = ";"; +const char line_comment_chars[] = "#"; +const char line_separator_chars[] = "{"; + +int md_short_jump_size = 3; +int md_long_jump_size = 4; + +/* The target specific pseudo-ops which we support. */ +/* example: +const pseudo_typeS md_pseudo_table[] = +{ + {"arch", avr_set_arch, 0}, + { NULL, NULL, 0} +}; +*/ +const pseudo_typeS md_pseudo_table[] = +{ + { NULL, NULL, 0} +}; + +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant. + As in 0f12.456 + or 0d1.2345e12 */ +const char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* On the Z8000, a PC-relative offset is relative to the address of the + instruction plus its size. */ +long +md_pcrel_from (fixS *fixP) +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +const char * +md_atof (int type, char *litP, int *sizeP) +{ + return ieee_md_atof (type, litP, sizeP, TRUE); +} + +void +md_show_usage (FILE *stream) +{ + fprintf (stream, _("\ + STM8 options:\n\ + ")); +} + +const char *md_shortopts = ""; + +struct option md_longopts[] = + { + {NULL, no_argument, NULL, 0} + }; + +size_t md_longopts_size = sizeof (md_longopts); + +void +md_begin (void) +{ + const struct stm8_opcodes_s *opcode; + stm8_hash = hash_new (); + + /* Insert unique names into hash table. This hash table then provides a + quick index to the first opcode with a particular name in the opcode + table. */ + for (opcode = stm8_opcodes; opcode->name; opcode++) + hash_insert (stm8_hash, opcode->name, (char *) opcode); + + //add register names to symbol table + + symbol_table_insert (symbol_create ("A", reg_section, + ST8_REG_A, &zero_address_frag)); + + symbol_table_insert (symbol_create ("X", reg_section, + ST8_REG_X, &zero_address_frag)); + + symbol_table_insert (symbol_create ("Y", reg_section, + ST8_REG_Y, &zero_address_frag)); + + symbol_table_insert (symbol_create ("SP", reg_section, + ST8_REG_SP, &zero_address_frag)); + + symbol_table_insert (symbol_create ("CC", reg_section, + ST8_REG_CC, &zero_address_frag)); + + symbol_table_insert (symbol_create ("XL", reg_section, + ST8_REG_XL, &zero_address_frag)); + + symbol_table_insert (symbol_create ("XH", reg_section, + ST8_REG_XH, &zero_address_frag)); + + symbol_table_insert (symbol_create ("YL", reg_section, + ST8_REG_YL, &zero_address_frag)); + + symbol_table_insert (symbol_create ("YH", reg_section, + ST8_REG_YH, &zero_address_frag)); + + symbol_table_insert (symbol_create ("a", reg_section, + ST8_REG_A, &zero_address_frag)); + + symbol_table_insert (symbol_create ("x", reg_section, + ST8_REG_X, &zero_address_frag)); + + symbol_table_insert (symbol_create ("y", reg_section, + ST8_REG_Y, &zero_address_frag)); + + symbol_table_insert (symbol_create ("sp", reg_section, + ST8_REG_SP, &zero_address_frag)); + + symbol_table_insert (symbol_create ("cc", reg_section, + ST8_REG_CC, &zero_address_frag)); + + symbol_table_insert (symbol_create ("xl", reg_section, + ST8_REG_XL, &zero_address_frag)); + + symbol_table_insert (symbol_create ("xh", reg_section, + ST8_REG_XH, &zero_address_frag)); + + symbol_table_insert (symbol_create ("yl", reg_section, + ST8_REG_YL, &zero_address_frag)); + + symbol_table_insert (symbol_create ("yh", reg_section, + ST8_REG_YH, &zero_address_frag)); + +} + +static inline char * +skip_space (char *s) +{ + while (*s == ' ' || *s == '\t') + ++s; + return s; +} + +/* Extract one word from FROM and copy it to TO. */ + +static char * +extract_word (char *from, char *to, int limit) +{ + char *op_end; + int size = 0; + + /* Drop leading whitespace. */ + from = skip_space (from); + *to = 0; + + /* Find the op code end. */ + for (op_end = from; *op_end != 0 && is_part_of_name (*op_end);) + { + to[size++] = *op_end++; + if (size + 1 >= limit) + break; + } + + to[size] = 0; + return op_end; +} + +void +md_operand (expressionS * exp __attribute__((unused))) +{ + /* In case of a syntax error, escape back to try next syntax combo. */ + as_bad(_("stm8: call to md_operand")); +} + +void print_fixup (fixS *); + + + +/* Attempt to simplify or eliminate a fixup. To indicate that a fixup + has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL, + we will have to generate a reloc entry. */ +void +md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) +{ + long val = * (long *) valP; + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + print_fixup(fixP); + + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + if (fixP->fx_addsy) + { + fixP->fx_no_overflow = 1; + fixP->fx_done = 0; + } + else + *buf++ = val; + break; + + case BFD_RELOC_16: + if (fixP->fx_addsy) + { + fixP->fx_no_overflow = 1; + fixP->fx_done = 0; + } + else + { + *buf++ = (val >> 8); + *buf++ = val; + } + break; + + case BFD_RELOC_24: + if (fixP->fx_addsy) + { + fixP->fx_no_overflow = 1; + fixP->fx_done = 0; + fixP->fx_where--; + } + else + { + *buf++ = (val >> 16); + *buf++ = (val >> 8); + *buf++ = val; + } + break; + + case BFD_RELOC_32: + if (fixP->fx_addsy) + { + fixP->fx_no_overflow = 1; + fixP->fx_done = 0; + } + else + { + *buf++ = (val >> 24); + *buf++ = (val >> 16); + *buf++ = (val >> 8); + *buf++ = val; + } + break; + + case BFD_RELOC_8_PCREL: + if (fixP->fx_addsy) + { + fixP->fx_pcrel_adjust = -1; + fixP->fx_no_overflow = 1; + fixP->fx_done = 0; + } + else + { + if (val > 127 || val < -128) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("relative jump out of range")); + *buf++ = val; + fixP->fx_no_overflow = 1; + fixP->fx_done = 1; + } + break; + + case BFD_RELOC_STM8_BIT_FLD: + if (val > 7 || val < 0) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bitfield out of range %ld"),val); + *buf++ += val*2; + fixP->fx_no_overflow = 1; + fixP->fx_done = 1; + break; + + default: + printf(_("md_apply_fix: unknown r_type 0x%x\n"), fixP->fx_r_type); + abort (); + } + + if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) + fixP->fx_done = 1; +} + +/* Generate a machine dependent reloc from a fixup. */ + +arelent* +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, + fixS *fixp ATTRIBUTE_UNUSED) +{ + arelent *reloc; + + print_fixup(fixp); + + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = fixp->fx_offset; + if (fixp->fx_r_type == BFD_RELOC_8_PCREL) + reloc->addend = fixp->fx_offset+ fixp->fx_pcrel_adjust; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + + if (! reloc->howto) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("Cannot represent %s relocation in object file"), + bfd_get_reloc_code_name (fixp->fx_r_type)); + abort (); + } + return reloc; +} + +valueT +md_section_align (segT seg, valueT size) +{ + int align = bfd_get_section_alignment (stdoutput, seg); + valueT mask = ((valueT) 1 << align) - 1; + + return (size + mask) & ~mask; +} + +int +md_parse_option (int c __attribute__((unused)), const char *arg __attribute__((unused))) +{ + return 1; +} + +symbolS * +md_undefined_symbol (char *name) +{ + return 0; + //Hande the case where a symbol has .w or .e suffix attached. + //This is actually quite stupid because the operand length is the + //same independent of whether it is .w or .e + char *p; + symbolS *symbolP=NULL; + + if ((p=strstr(name,".w"))) + { + if (*(p+2) == 0) + { + *p = 0; + symbolP = symbol_find (name); + //*p = '.'; + } + } + if ((p=strstr(name,".l"))) + { + if (*(p+2) == 0) + { + *p = 0; + symbolP = symbol_find (name); + //*p = '.'; + } + } + if ((p=strstr(name,".e"))) + { + if (*(p+2) == 0) + { + *p = 0; + symbolP = symbol_find (name); + //*p = '.'; + } + } + return symbolP; +} + + +void +md_create_long_jump (char *ptr __attribute__((unused)), + addressT from_addr ATTRIBUTE_UNUSED, + addressT to_addr __attribute__((unused)), + fragS *frag __attribute__((unused)), + symbolS *to_symbol __attribute__((unused))) +{ + as_bad(_("long_jump")); +} + +void +md_create_short_jump (char *ptr __attribute__((unused)), + addressT from_addr __attribute__((unused)), + addressT to_addr ATTRIBUTE_UNUSED, + fragS *frag ATTRIBUTE_UNUSED, + symbolS *to_symbol ATTRIBUTE_UNUSED) +{ + as_bad(_("short_jump")); +} + +/* Put number into target byte order. */ + +void +md_number_to_chars (char *ptr, valueT use, int nbytes) +{ + number_to_chars_bigendian (ptr, use, nbytes); +} + +int +md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, + segT segment_type ATTRIBUTE_UNUSED) +{ + as_bad (_("call to md_estimate_size_before_relax\n")); + return 0; +} + +void +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, + segT sec ATTRIBUTE_UNUSED, + fragS *fragP ATTRIBUTE_UNUSED) +{ + as_bad (_("call to md_convert_frag\n")); +} + +static +char* match_parentheses(char* str) +{ + char *p; + int cnt=0; + + p = str; + while (*p != 0) + { + if (*p == '(') cnt++; + if (*p == ')') + { + if (--cnt == 0) + return p; + } + p++; + } + return 0; +} + +static +int split_words(char *str, char **chunks) +{ + int i; + char *p; + + p = str; + for (i=0;i<3;i++) + { + chunks[i] = str; + if (*str == 0) + break; + while(*p != 0) + { + if (*p=='(') + { + p = match_parentheses(str); + if (p == 0) return 0; + } + if (*p==',') + { + *p = 0; + p++; + break; + } + p++; + } + str = p; + } + return i; +} + +static +int read_arg_ptr(char *str, expressionS *exps) +{ + char *s; + char *p; + char c; + + if ((str[0]=='[') && (strstr(str,"]"))) + { + s = str; + s++; + input_line_pointer=s; + + /* first eat up .w and .e */ + if ((p = strstr(s,".w]"))) + { + c = *p; + *p = 0; + } + else + if ((p = strstr(s,".e]"))) + { + c = *p; + *p = 0; + } + + expression(exps); + print_expr(exps); + + /* restore c */ + if (p) + *p = c; + + //return default pointer len + if (*input_line_pointer == ']') + { + input_line_pointer+=1; + return 2; + } else + if ((*input_line_pointer == '.') && (*(input_line_pointer+1) == 'w')) + { + input_line_pointer+=2; + return 2; + } else + if ((*input_line_pointer == '.') && (*(input_line_pointer+1) == 'e')) + { + input_line_pointer+=2; + return 3; + } + else + { + as_bad("Expected ']' or '.e' or '.w' but found '%c'",*input_line_pointer); + return -1; + } + } + return 0; +} + + +char* toupperstr(char *str); + +char* toupperstr(char *str) +{ + for(int i = 0; str[i]; i++){ + str[i] = toupper(str[i]); + } + return str; +} + +//expressionS last_exp; +/* In: argument + Out: value + Modifies: type */ +static +int read_arg(char *str, expressionS *exps) +{ + int ret; + const char *name ATTRIBUTE_UNUSED; + /* There is a number of addressing modes in ST8 architecture. + We need to properly handle each of them in order to find a proper opcode. */ + if(!str) return(0); + + //Immidate + if(str[0]=='#') + { + str++; + exps->X_md = OP_IMM; + input_line_pointer = str; + expression(exps); + print_expr(exps); + return 1; + } + + char strx[256]; + strncpy(strx,str,sizeof(strx)); + toupperstr(strx); + + //decode ptr operand + if (str[0]=='[') + { + ret = read_arg_ptr(str, exps); + if (ret>0) + { + if (ret == 2) + { + exps->X_md=OP_PTRW; + return 1; + } + if (ret == 3) + { + exps->X_md=OP_PTRE; + return 1; + } + } + else + return 0; + } + //decode index operands + //index X + else if ((str[0]=='(') && (strstr(strx,"(X)"))) + { + exps->X_md=OP_INDX; + return 1; + } + //index Y + else if ((str[0]=='(') && (strstr(strx,"(Y)"))) + { + exps->X_md=OP_INDY; + return 1; + } + //offset,X + else if ((str[0]=='(') && (strstr(strx,",X)"))) + { + str++; + if (str[0]=='[') + { + ret = read_arg_ptr(str, exps); + if (ret==2) + { + exps->X_md=OP_PTRW_X; + return 1; + } + if (ret==3) + { + exps->X_md=OP_PTRE_X; + return 1; + } + return 0; + } + str=strtok(str,","); + input_line_pointer=str; + expression(exps); + print_expr(exps); + exps->X_md=OP_OFF_X; + return 1; + } + //offset,Y + else if ((str[0]=='(') && (strstr(strx,",Y)"))) + { + str++; + if (str[0]=='[') + { + ret = read_arg_ptr(str, exps); + if (ret==2) + { + exps->X_md=OP_PTRW_Y; + return 1; + } + if (ret==3) + { + exps->X_md=OP_PTRE_Y; + return 1; + } + return 0; + } + str=strtok(str,","); + input_line_pointer=str; + expression(exps); + print_expr(exps); + exps->X_md=OP_OFF_X; + return 1; + } + //offset,SP + else if ((str[0]=='(') && (strstr(strx,",SP)"))) + { + str++; + str=strtok(str,","); + input_line_pointer=str; + expression(exps); + print_expr(exps); + exps->X_md=OP_OFF_SP; + return 1; + } + + char *p; + char c; + if ((p = strstr(str,".short"))) + { + c = *p; + *p = 0; + exps->X_md = OP_SHORTMEM; + input_line_pointer = str; + expression(exps); + print_expr(exps); + *p = c; + input_line_pointer += 6; + return 1; + } + + input_line_pointer = str; + expression(exps); + print_expr(exps); + + if (exps->X_op == O_register) + { + exps->X_md = OP_REGISTER; + return 1; + } + + if (exps->X_op != O_illegal) + { + exps->X_md = OP_MEM; + return 1; + } + + /* Can't parse an expression, notifying caller about that. */ + return(0); +} + +static +int read_args(char *str, expressionS exps[]) +{ + char *chunks[3]; + int count = split_words(str, chunks); + int i; + for(i = 0; i < count; i++) + { + int ret = read_arg(chunks[i], &(exps[i])); + if(!ret) as_bad("Invalid operand: %s", chunks[i]); + } + return(count); +} + +static +void stm8_bfd_out(struct stm8_opcodes_s op, expressionS exp[], int count, char *frag) +{ + int i; + + for(i = 0; i < count; i++) + { + int where = frag - frag_now->fr_literal; + + if (exp[i].X_op != O_illegal) + { + switch(op.constraints[i]) + { + case ST8_EXTMEM: + case ST8_EXTOFF_X: + case ST8_EXTOFF_Y: + fix_new_exp(frag_now, where, 3, &exp[i], FALSE, BFD_RELOC_24); + bfd_put_bits(0xaaaaaaaa, frag, 24, true); + frag+=3; + break; + case ST8_LONGPTRW_Y: + case ST8_LONGPTRW_X: + case ST8_LONGPTRW: + case ST8_LONGPTRE: + case ST8_LONGOFF_Y: + case ST8_LONGOFF_X: + case ST8_WORD: + case ST8_LONGMEM: + fix_new_exp(frag_now, where, 2, &exp[i], FALSE, BFD_RELOC_16); + bfd_put_bits(0xaaaaaaaa, frag, 16, true); + frag+=2; + break; + case ST8_SHORTPTRW_Y: + case ST8_SHORTPTRW_X: + case ST8_SHORTPTRW: + case ST8_SHORTOFF_Y: + case ST8_SHORTOFF_X: + case ST8_SHORTOFF_SP: + case ST8_BYTE: + case ST8_SHORTMEM: + fix_new_exp(frag_now, where, 1, &exp[i], FALSE, BFD_RELOC_8); + bfd_put_bits(0xaaaaaaaa, frag, 8, true); + frag+=1; + break; + case ST8_PCREL: + fix_new_exp(frag_now, where, 1, &exp[i], TRUE, BFD_RELOC_8_PCREL); + bfd_put_bits(0xaaaaaaaa, frag, 8, true); + frag+=1; + break; + case ST8_BIT_0: + fix_new_exp(frag_now, where-3, 1, &exp[i], FALSE, BFD_RELOC_STM8_BIT_FLD); + break; + default: + break; + } + } + } +} + +static +int cmpspec(stm8_addr_mode_t addr_mode[], expressionS exps[], int count) +{ + int i, ret = 0; + unsigned int value; + stm8_operand_t operand; + + for(i = 0; i < count; i++) { + operand = exps[i].X_md; + if (!addr_mode || !operand) + continue; // End + if (exps[i].X_op == O_constant) + value = exps[i].X_add_number; + else + value = -1; + + switch (operand) + { + case OP_REGISTER: + if (addr_mode[i] == (stm8_addr_mode_t)exps[i].X_add_number) + continue; + break; + case OP_IMM: + if (addr_mode[i] == ST8_BYTE) + continue; + if (addr_mode[i] == ST8_WORD) + continue; + if (addr_mode[i] == ST8_BIT_0) + continue; + break; + case OP_INDX: + if (addr_mode[i] == ST8_INDX) + continue; + break; + case OP_INDY: + if (addr_mode[i] == ST8_INDY) + continue; + break; + case OP_OFF_X: + if (addr_mode[i] == ST8_SHORTOFF_X) + if (value < 0x100) + continue; + if (addr_mode[i] == ST8_LONGOFF_X) + continue; + if (addr_mode[i] == ST8_EXTOFF_X) + continue; + break; + case OP_OFF_Y: + if (addr_mode[i] == ST8_SHORTOFF_Y) + if (value < 0x100) + continue; + if (addr_mode[i] == ST8_LONGOFF_Y) + continue; + if (addr_mode[i] == ST8_EXTOFF_Y) + continue; + break; + case OP_OFF_SP: + if (addr_mode[i] == ST8_SHORTOFF_SP) + continue; + break; + case OP_PTRW: + if (addr_mode[i] == ST8_SHORTPTRW) + if (value < 0x100) + continue; + if (addr_mode[i] == ST8_LONGPTRW) + continue; + break; + case OP_PTRW_X: + if (addr_mode[i] == ST8_SHORTPTRW_X) + if (value < 0x100) + continue; + if (addr_mode[i] == ST8_LONGPTRW_X) + continue; + break; + case OP_PTRW_Y: + if (addr_mode[i] == ST8_SHORTPTRW_Y) + if (value < 0x100) + continue; + if (addr_mode[i] == ST8_LONGPTRW_Y) + continue; + break; + case OP_PTRE: + if (addr_mode[i] == ST8_LONGPTRE) + continue; + break; + case OP_PTRE_X: + if (addr_mode[i] == ST8_LONGPTRE_X) + continue; + break; + case OP_PTRE_Y: + if (addr_mode[i] == ST8_LONGPTRE_Y) + continue; + break; + case OP_MEM: + if (addr_mode[i] == ST8_PCREL) + continue; + if (addr_mode[i] == ST8_EXTMEM) + continue; + if (addr_mode[i] == ST8_LONGMEM) + continue; + break; + case OP_SHORTMEM: + if (addr_mode[i] == ST8_SHORTMEM) + continue; + break; + case OP_ILLEGAL: + as_fatal(_("BUG: OP_ILLEGAL")); + return 1; + } + +// if (operand == ST8_DIRECT) +// { +// if (addr_mode[i] == ST8_SHORTMEM) continue; +// } + + //not a match + ret++; + } + return(ret); +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. */ + +void +md_assemble (char *str) +{ + char op[11]; + char *t = input_line_pointer; + char *str_orig = strdup(str); + str = skip_space(extract_word(str, op, sizeof(op))); + //stm8_operand_t spec[3]; + expressionS exps[3]; + //memset(spec, 0, sizeof(stm8_operand_t) * 3); + memset(exps, 0, sizeof(expressionS) * 3); + + int count = read_args(str, exps); + struct stm8_opcodes_s *opcode = (struct stm8_opcodes_s *)hash_find(stm8_hash, op); + + if (opcode == NULL) { + as_bad (_("unknown opcode `%s'"), op); + return; + } + + int i; + for(i = 0; opcode[i].name != NULL; i++) + { + if (!strcmp(op, opcode[i].name)) + if(!cmpspec(opcode[i].constraints, exps, count)) + { + int insn_size = stm8_compute_insn_size(opcode[i]); + char *frag = frag_more(insn_size); + int opcode_length = stm8_opcode_size(opcode[i].bin_opcode); + bfd_put_bits(opcode[i].bin_opcode, frag, opcode_length * 8, true); + frag += opcode_length; + stm8_bfd_out(opcode[i], exps, count, frag); + break; + } + } + if(!opcode[i].name) + as_bad("Invalid instruction: %s", str_orig); + input_line_pointer = t; + free(str_orig); +} + + +/* If you define this macro, it should return the position from which + the PC relative adjustment for a PC relative fixup should be made. + On many processors, the base of a PC relative instruction is the + next instruction, so this macro would return the length of an + instruction, plus the address of the PC relative fixup. The latter + can be calculated as fixp->fx_where + + fixp->fx_frag->fr_address. */ + +long +md_pcrel_from_section (fixS *fixp, segT sec) +{ + if (fixp->fx_addsy != (symbolS *) NULL + && (!S_IS_DEFINED (fixp->fx_addsy) + || (S_GET_SEGMENT (fixp->fx_addsy) != sec))) + return 0; + + return fixp->fx_size + fixp->fx_where + fixp->fx_frag->fr_address; + //return fixp->fx_frag->fr_address+fixp->fx_frag->fr_fix; + return fixp->fx_frag->fr_address + fixp->fx_where; +} + +int stm8_need_index_operator() +{ + return 1; +} + +operatorT stm8_operator (const char *name ATTRIBUTE_UNUSED, unsigned int operands ATTRIBUTE_UNUSED, char *pc ATTRIBUTE_UNUSED) +{ + return O_absent; +} + +void stm8_check_label (symbolS *labelsym ATTRIBUTE_UNUSED) +{ +} + +extern void stm8_symbol_new_hook (symbolS * labelsym) +{ + char* name; + char* p; + int value; + + name = (char*)S_GET_NAME(labelsym); + if ((p=strstr(name,".b"))) + { + if (*(p+2)==0) + { + *p=0; + S_SET_NAME(labelsym,name); + value=1; + symbol_set_tc(labelsym, &value); + } + } +} diff --git a/gas/config/tc-stm8.h b/gas/config/tc-stm8.h new file mode 100644 index 0000000000..066e72ea43 --- /dev/null +++ b/gas/config/tc-stm8.h @@ -0,0 +1,97 @@ +/* This file is tc-stm8.h + Copyright (C) 1999-2016 Free Software Foundation, Inc. + + Written by Ake Rehnman 2017-02-21, + ake.rehnman (at) gmail dot com + + 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. */ + +/* By convention, you should define this macro in the `.h' file. For + example, `tc-m68k.h' defines `TC_M68K'. You might have to use this + if it is necessary to add CPU specific code to the object format + file. */ +#define TC_STM8 + +/* This macro is the BFD target name to use when creating the output + file. This will normally depend upon the `OBJ_FMT' macro. */ +#define TARGET_FORMAT "elf32-stm8" + +/* This macro is the BFD architecture to pass to `bfd_set_arch_mach'. */ +#define TARGET_ARCH bfd_arch_stm8 + +/* This macro is the BFD machine number to pass to + `bfd_set_arch_mach'. If it is not defined, GAS will use 0. */ +#define TARGET_MACH 0 + +/* You should define this macro to be non-zero if the target is big + endian, and zero if the target is little endian. */ +#define TARGET_BYTES_BIG_ENDIAN 0 + +/* If you define this macro, GAS will warn about the use of + nonstandard escape sequences in a string. */ +#define ONLY_STANDARD_ESCAPES + +#define DIFF_EXPR_OK /* .-foo gets turned into PC relative relocs */ + +/* If you define this macro, it should return the offset between the + address of a PC relative fixup and the position from which the PC + relative adjustment should be made. On many processors, the base + of a PC relative instruction is the next instruction, so this + macro would return the length of an instruction. */ +#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section (FIX, SEC) +extern long md_pcrel_from_section (struct fix *, segT); + +#define NEED_INDEX_OPERATOR +extern int stm8_need_index_operator (void); +//#define md_need_index_operator stm8_need_index_operator + +#define NUMBERS_WITH_SUFFIX 1 + +//#define UNDEFINED_DIFFERENCE_OK +//#define TC_VALIDATE_FIX_SUB(fix, seg) stm8_validate_fix_sub (fix) +//extern int stm8_validate_fix_sub (struct fix *); + +//#define STM8_FIXUP 128 + +extern operatorT stm8_operator (const char *name, unsigned int operands, char *); +#define md_operator stm8_operator + +extern void stm8_check_label (symbolS *labelsym); +//#define tc_check_label(ls) stm8_check_label (ls) + +#define tc_symbol_new_hook(sym) stm8_symbol_new_hook (sym) +extern void stm8_symbol_new_hook (symbolS * labelsym); + +#define TC_SYMFIELD_TYPE int + +#define md_register_arithmetic 0 + + +//int split_words(char *str, char **chunks); +//int getnumber(const char *str, int *out); +//int gethex(const char *str, int *out); +//int getnum(const char *str, int *out); +//int read_arg(char *str, expressionS *exps); +//int read_args(char *str, expressionS exps[]); +//unsigned int bytes_count(unsigned int number); +//int compute_insn_size(struct stm8_opcodes_s opcode); +//int cmpspec(stm8_addr_mode_t addr_mode[], expressionS exps[], int count); +//void stm8_bfd_out(struct stm8_opcodes_s op, expressionS exp[], int count, char *frag); +//char* match_parentheses(char* str); +//int read_arg_ptr(char *str, expressionS *exps); +//int is_ptr_w(stm8_addr_mode_t type); diff --git a/gas/configure.tgt b/gas/configure.tgt index afe4e0608c..81770e21ec 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -481,6 +481,8 @@ case ${generic_target} in z8k-*-coff | z8k-*-sim) fmt=coff ;; + stm8-*-elf*) fmt=elf ;; + *-*-aout | *-*-scout) fmt=aout ;; *-*-cloudabi*) fmt=elf ;; *-*-dragonfly*) fmt=elf em=dragonfly ;; @@ -497,7 +499,7 @@ case ${generic_target} in esac case ${cpu_type} in - aarch64 | alpha | arm | i386 | ia64 | microblaze | mips | ns32k | or1k | or1knd | pdp11 | ppc | riscv | sparc | z80 | z8k) + aarch64 | alpha | arm | i386 | ia64 | microblaze | mips | ns32k | or1k | or1knd | pdp11 | ppc | riscv | sparc | z80 | z8k | stm8) bfd_gas=yes ;; esac diff --git a/gdb/configure.tgt b/gdb/configure.tgt index fb8014a8e8..e128398891 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -744,6 +744,11 @@ xtensa*-*-linux*) gdb_target=linux gdb_target_obs="xtensa-linux-tdep.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; +stm8-*-*) + # Target: STM8 + gdb_target_obs="stm8-tdep.o" + #gdb_sim=../sim/stm8/libsim.a + ;; esac diff --git a/gdb/stm8-tdep.c b/gdb/stm8-tdep.c new file mode 100644 index 0000000000..30b345cfd7 --- /dev/null +++ b/gdb/stm8-tdep.c @@ -0,0 +1,1130 @@ +/* Target-dependent code for STM8, for GDB. + Written by Ake Rehnman 2017-02-21, + ake.rehnman (at) gmail dot com + + Copyright (C) 1996-2016 Free Software Foundation, Inc. + + This file is part of GDB. + + 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, see . */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "trad-frame.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "gdbtypes.h" +#include "inferior.h" +#include "symfile.h" +#include "arch-utils.h" +#include "regcache.h" +#include "dis-asm.h" +#include "objfiles.h" +#include "target-descriptions.h" +#include +#include "dwarf2-frame.h" + +enum stm8_regnum +{ + STM8_PC_REGNUM, + STM8_A_REGNUM, + STM8_X_REGNUM, + STM8_Y_REGNUM, + STM8_SP_REGNUM, + STM8_CC_REGNUM, + //pseudo register + STM8_FP_REGNUM +}; + +static const char *stm8_register_names[] = +{ + "pc", "a", "x", "y", "sp", "cc" +}; + +struct stm8_soft_reg +{ + const char *name; + CORE_ADDR addr; +}; + +unsigned int stm8_debug; + +#define STM8_NUM_REGS ARRAY_SIZE (stm8_register_names) + +struct gdbarch_tdep +{ + struct stm8_soft_reg fp_reg; +}; + +enum insn_return_kind { + RETURN_RET, + RETURN_RETF, + RETURN_IRET +}; + +static int +stm8_convert_register_p (struct gdbarch *gdbarch, int regnum, + struct type *type) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if ((regnum == STM8_FP_REGNUM) && (TYPE_LENGTH(type) > 2)) + { + return 1; + } + return 0; +} + +/* Read a value of type TYPE from register REGNUM in frame FRAME, and + return its contents in TO. */ + +static int +stm8_register_to_value (struct frame_info *frame, int regnum, + struct type *type, gdb_byte *to, + int *optimizedp, int *unavailablep) +{ + struct type *fpreg_type = register_type (get_frame_arch (frame), + STM8_FP_REGNUM); + + /* We only support ptr values. */ + if ((TYPE_CODE (type) != TYPE_CODE_PTR) && (regnum != STM8_FP_REGNUM) && (TYPE_LENGTH(type) >= TYPE_LENGTH(fpreg_type))) + { + warning (_("Conversion failure in stm8_register_to_value: regnum = %d "), regnum); + *optimizedp = *unavailablep = 0; + return 0; + } + + /* Convert to TYPE. */ + + memset(to,0,TYPE_LENGTH(type)); + + if (!get_frame_register_bytes (frame, regnum, 0, TYPE_LENGTH (fpreg_type), + to+TYPE_LENGTH(type)-TYPE_LENGTH(fpreg_type), optimizedp, unavailablep)) + return 0; + + *optimizedp = *unavailablep = 0; + return 1; +} + + +/* Look in the symbol table for the address of a pseudo register + in memory. If we don't find it, pretend the register is not used + and not available. */ +static void +stm8_get_register_info (struct stm8_soft_reg *reg, const char *name) +{ + struct bound_minimal_symbol msymbol; + + msymbol = lookup_minimal_symbol (name, NULL, NULL); + if (msymbol.minsym) + { + reg->addr = BMSYMBOL_VALUE_ADDRESS (msymbol); + reg->name = xstrdup (name); + } + else + { + reg->name = 0; + reg->addr = 0; + } +} + +static void +stm8_initialize_soft_register_info(struct gdbarch_tdep *tdep) +{ + stm8_get_register_info(&tdep->fp_reg, "_fp_"); + if ((tdep->fp_reg.name == 0) && (symfile_objfile)) + { + warning (_("No frame soft register found in the symbol table (_fp_).\n" + "Stack backtrace will not work.\n")); + } +} + +static const char * +stm8_register_name (struct gdbarch *gdbarch, int regnum) +{ + if (regnum >= 0 && regnum < STM8_NUM_REGS) + return stm8_register_names[regnum]; + if (regnum == STM8_FP_REGNUM) + return "fp"; + return NULL; +} + +static struct type * +stm8_register_type (struct gdbarch *gdbarch, int regnum) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + switch (regnum) + { + case STM8_PC_REGNUM: + return builtin_type (gdbarch)->builtin_uint32; + case STM8_SP_REGNUM: + return builtin_type (gdbarch)->builtin_uint16; + case STM8_X_REGNUM: + case STM8_Y_REGNUM: + return builtin_type (gdbarch)->builtin_uint16; + case STM8_FP_REGNUM: + return builtin_type (gdbarch)->builtin_uint16; + default: + return builtin_type (gdbarch)->builtin_uint8; + } +} + +static enum register_status +stm8_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, gdb_byte *buf) +{ + enum register_status status; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int regsize = 2; + + switch (regnum) + { + case STM8_FP_REGNUM: + /* Fetch a soft register: translate into a memory read. */ + memset (buf, 0, regsize); + if (tdep->fp_reg.name) + { + target_read_memory (tdep->fp_reg.addr, buf, 2); + } + return REG_VALID; + default: + internal_error (__FILE__, __LINE__, _("invalid regnum")); + return REG_UNAVAILABLE; + } +} + +static void +stm8_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, const gdb_byte *buf) +{ + enum register_status status; + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + const int regsize = 2; + + switch (regnum) + { + case STM8_FP_REGNUM: + /* Store a soft register: translate into a memory write. */ + if (tdep->fp_reg.name) + { + target_write_memory (tdep->fp_reg.addr, buf, 2); + } + return; + default: + internal_error (__FILE__, __LINE__, _("invalid regnum")); + return; + } +} + + +struct stm8_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + CORE_ADDR pc; + + /* Do we have a frame? */ + int frameless_p; + + /* Frame size. */ + int framesize; + + /* Frame size. */ + int stackadj; + + /* Frame register. */ + int fp_regnum; + + /* Return instruction */ + enum insn_return_kind return_kind; + + /* Offsets to saved registers. */ + int register_offsets[STM8_NUM_REGS]; + + /* Table of saved registers. */ + struct trad_frame_saved_reg *saved_regs; +}; + +static const unsigned char * +stm8_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, + int *lenptr) +{ + static gdb_byte stm8_breakpoint[] = { 0x8b }; + + *lenptr = sizeof (stm8_breakpoint); + return stm8_breakpoint; +} + +/* Implement the breakpoint_kind_from_pc gdbarch method. */ +#if 0 +static int +stm8_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) +{ + CORE_ADDR pc = *pcptr; + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_breakpoint_kind_from_pc called %8.8lx\n",pc); + + return 1; +} + +static const gdb_byte * +stm8_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) +{ + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_sw_breakpoint_from_kind called\n"); + + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); + + static gdb_byte stm8_breakpoint[] = { 0x8b }; + + *size = 1; + + return stm8_breakpoint; +} + +#endif + +static int dwarf2_to_reg_map[6] = +{ 0 /* r0 */, 1 /* r1 */, 2 /* r2 */, 3 /* r3 */, /* 0- 3 */ + 4 /* r4 */, 5 /* r5 */ +}; + +static int +stm8_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg) +{ + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_dwarf2_reg_to_regnum called\n"); + if (reg >= 0 && reg < sizeof (dwarf2_to_reg_map)) + return dwarf2_to_reg_map[reg]; + if (reg == 31) + return STM8_FP_REGNUM; + return -1; +} + +static void +stm8_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_write_pc called\n"); + regcache_cooked_write_unsigned (regcache, STM8_PC_REGNUM, pc); +} + +static CORE_ADDR +stm8_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + gdb_byte buf[4]; + CORE_ADDR pc; + + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + frame_unwind_register (next_frame, STM8_PC_REGNUM, buf); + pc = extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr); + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_unwind_pc called: pc=%8.8lx\n",pc); + return pc; +} + +static CORE_ADDR +stm8_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + ULONGEST sp; + + sp = frame_unwind_register_unsigned (next_frame, STM8_SP_REGNUM); + sp = gdbarch_addr_bits_remove (gdbarch, sp); + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_unwind_sp called: sp=%8.8llx\n",sp); + return sp; +} + +#if 0 +static struct value * +stm8_dwarf2_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + CORE_ADDR pc; + + switch (regnum) + { + case STM8_PC_REGNUM: + pc = frame_unwind_register_unsigned (this_frame, AARCH64_PC_REGNUM); + return frame_unwind_got_constant (this_frame, regnum, lr); + + default: + internal_error (__FILE__, __LINE__, + _("Unexpected register %d"), regnum); + } +} + +static void +stm8_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) +{ + switch (regnum) + { + case STM8_PC_REGNUM: + reg->how = DWARF2_FRAME_REG_FN; + reg->loc.fn = stm8_dwarf2_prev_register; + break; + case STM8_SP_REGNUM: + reg->how = DWARF2_FRAME_REG_CFA; + break; + } +} +#endif + +/* Assuming THIS_FRAME is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ + +static struct frame_id +stm8_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + fprintf_unfiltered (gdb_stdlog, "stm8_dummy_id called\n"); + + return frame_id_build + (get_frame_register_signed (this_frame, STM8_SP_REGNUM), + get_frame_pc (this_frame)); +} + + +/* Allocate and initialize a frame cache. */ + +static struct stm8_frame_cache * +stm8_alloc_frame_cache (void) +{ + struct stm8_frame_cache *cache; + + cache = FRAME_OBSTACK_ZALLOC (struct stm8_frame_cache); + + // /* Base address. */ + cache->base = 0; + cache->pc = 0; + + /* Frameless until proven otherwise. */ + cache->frameless_p = 1; + + return cache; +} + +/* Figure out what return type this function has. */ +static enum insn_return_kind +stm8_get_return_insn (CORE_ADDR pc) +{ + const char *name; + CORE_ADDR func_addr, func_end, stop; + + if (find_pc_partial_function (pc, &name, &func_addr, &func_end)) + { + gdb_byte buf[1]; + //func_end is pointing to last insn+1 ??? + if (!target_read_code (func_end-1, buf, sizeof (buf))) + { + switch (buf[0]) + { + case 0x81: + return RETURN_RET; + case 0x87: + return RETURN_RETF; + case 0x80: + return RETURN_IRET; + } + } + } + + //defaut to RET + if (stm8_debug) + fprintf_unfiltered(gdb_stdlog, "WARNING: stm8_get_return_insn: No return instruction found in function %s start_addr = %8.8lx end_addr = %8.8lx\n", name, func_addr, func_end); + return RETURN_RET; +} + +/* Find the start of this function. */ +static CORE_ADDR +stm8_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, + CORE_ADDR current_pc, + struct stm8_frame_cache *cache) +{ + const char *name; + CORE_ADDR func_addr, func_end, stop; + unsigned long insn; + int done; + gdb_byte buf[4]; + + if (stm8_debug) + fprintf_unfiltered(gdb_stdlog, "stm8_analyze_prologue called (pc=%8.8lx current_pc=%8.8lx)\n",pc,current_pc); + + /* Initialize info about frame. */ + cache->framesize = 0; + cache->fp_regnum = STM8_FP_REGNUM; + cache->frameless_p = 1; + cache->stackadj = 0; + + /* Find the start of this function. */ + find_pc_partial_function (pc, &name, &func_addr, &func_end); + if (func_addr < pc) + pc = func_addr; + + if (current_pc < pc) + return current_pc; + + /* Start decoding the prologue. We start by checking two special cases: + + 1. We're about to return + 2. We're at the first insn of the prologue. + + If we're about to return, our frame has already been deallocated. + If we are stopped at the first instruction of a prologue, + then our frame has not yet been set up. */ + + /* Get the first insn from memory. */ + if (target_read_code (pc, buf, sizeof (buf))) + return current_pc; + + //RET? + if (buf[0] == 0x81) + { + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_analyze_prologue: current_pc is RTS so we dont have a frame!\n"); + return pc; + } + + /* Start at beginning of function and analyze until we get to the + current pc, or the end of the function, whichever is first. */ + stop = (current_pc < func_end ? current_pc : func_end); + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_analyze_prologue: name=%s, func_addr=%s, stop=%s\n", + name, paddress (gdbarch, func_addr), + paddress (gdbarch, stop)); + + /* scan the prologue */ + pc = func_addr; + done = 0; + while ((pc < stop) && !done) + { + if (target_read_code (pc, buf, sizeof (buf))) + return current_pc; + + insn = buf[0]; + if (buf[0] == 0x90) + insn = (insn << 8) + buf[1]; + + switch (insn) + { + case 0x3b: + //PUSH extmem + cache->framesize += 1; + pc += 3; + break; + case 0x9096: + //LDW Y, SP + pc += 2; + break; + case 0x90cf: + //LDW extmem, Y + pc += 4; + cache->frameless_p = 0; + break; + case 0x52: + //SUB SP,#xx? + cache->framesize += buf[1]; + pc+=2; + break; + case 0x88: + //PUSH A? + cache->framesize += 1; + pc++; + break; + case 0x89: + //PUSH X? + cache->framesize += 2; + pc++; + break; + case 0x9089: + //PUSH Y? + cache->framesize += 2; + pc+=2; + break; + default: + done = 1; + } + + } + + if (stm8_debug) + if (cache->frameless_p) + fprintf_unfiltered (gdb_stdlog, "stm8_analyze_prologue: this function is frameless! No pc adjustment was done.\n"); + + return pc; +} + +/* Return PC of first real instruction of the function starting at + START_PC. */ + +static CORE_ADDR +stm8_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) +{ + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_skip_prologue called: start_pc=%8.8lx\n", start_pc); + + struct symtab_and_line sal; + CORE_ADDR func_start, func_end, ostart_pc; + struct stm8_frame_cache cache; + + /* This is the preferred method, find the end of the prologue by + using the debugging information. Debugging info does not always + give the right answer since parameters are stored on stack after this. + Always analyze the prologue. */ + if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end)) + { + sal = find_pc_line (func_start, 0); + + if (sal.end < func_end + && start_pc <= sal.end) + start_pc = sal.end; + } + + ostart_pc = stm8_analyze_prologue (gdbarch, func_start, 0xffffffffUL, + &cache); + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_skip_prologue: start_pc=%8.8lx ostart_pc=%8.8lx\n",start_pc,ostart_pc); + + if (ostart_pc > start_pc) + return ostart_pc; + return start_pc; +} + +/* Normal frames. + + The STM8 frame is typically: + + args + return lo addr + return hi addr + prev fp lo + prev fp hi + locals <- fp +sp-> empty + */ + +static struct stm8_frame_cache * +stm8_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_frame_cache called (next_frame=%p)\n",next_frame); + + struct stm8_frame_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (next_frame); + CORE_ADDR start_pc, current_pc, current_sp, fp; + int retsize; + + if (*this_cache) + return (struct stm8_frame_cache *) *this_cache; + + cache = stm8_alloc_frame_cache (); + *this_cache = cache; + + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + start_pc = get_frame_func (next_frame); + + cache->return_kind = stm8_get_return_insn (start_pc); + + current_pc = get_frame_pc (next_frame); + current_sp = get_frame_sp (next_frame); + + /* Analyze the function prologue. */ + if (start_pc != 0) + stm8_analyze_prologue (gdbarch, start_pc, current_pc, + (struct stm8_frame_cache *) *this_cache); + + /* get our fp by unwinding it from the next frame + * if we don't have a fp we use sp instead but if there + * are arguments on the stack unwinding will be + * unpredictable. + */ + //fp = frame_unwind_register_unsigned (next_frame, cache->fp_regnum); + fp = get_frame_register_unsigned (next_frame, cache->fp_regnum); + if (fp == 0) + { + cache->base = 0; + cache->frameless_p = 1; + //return (struct stm8_frame_cache *) (*this_cache); + } + + switch (cache->return_kind) + { + case RETURN_RET: + retsize = 2; + break; + case RETURN_RETF: + retsize = 3; + break; + case RETURN_IRET: + retsize = 9; + break; + } + + if (cache->frameless_p) + { + cache->base = current_sp + cache->framesize; + if (cache->return_kind == RETURN_IRET) + cache->saved_regs[STM8_PC_REGNUM].addr = cache->base + 1 + 6; + else + cache->saved_regs[STM8_PC_REGNUM].addr = cache->base + 1; + trad_frame_set_value (cache->saved_regs, + STM8_SP_REGNUM, + cache->base+retsize); + } + else + { + /* fp points to our base */ + cache->base = fp; + if (cache->return_kind == RETURN_IRET) + cache->saved_regs[STM8_PC_REGNUM].addr = cache->base + 1 + 2 + 6; + else + cache->saved_regs[STM8_PC_REGNUM].addr = cache->base + 1 + 2; + cache->saved_regs[STM8_FP_REGNUM].addr = fp + 1; + trad_frame_set_value (cache->saved_regs, + STM8_SP_REGNUM, + cache->base+retsize+2); + } + + + if (stm8_debug) + { + fprintf_unfiltered (gdb_stdlog, "stm8_frame_cache: (next_frame=%p) base=%4.4lx curr_pc=%4.4lx curr_sp=%4.4lx fp_regnum=%d fp=%4.4lx framesize=%4.4x stackadj=%4.4x retsize=%d\n", + next_frame, cache->base, current_pc, current_sp, cache->fp_regnum, fp, cache->framesize, cache->stackadj, retsize); + + CORE_ADDR frame_pc; + CORE_ADDR frame_sp; + CORE_ADDR frame_fp; + frame_pc = value_as_long(trad_frame_get_prev_register (next_frame, cache->saved_regs, STM8_PC_REGNUM)); + frame_sp = value_as_long(trad_frame_get_prev_register (next_frame, cache->saved_regs, STM8_SP_REGNUM)); + + // this is stupid, trad_frame_get_prev_register can't get a + // register value unless we have a valid frame id + // hopefully this will get resolved in the future :) + if (cache->saved_regs[STM8_FP_REGNUM].addr > 0) + frame_fp = value_as_long(trad_frame_get_prev_register (next_frame, cache->saved_regs, STM8_FP_REGNUM)); + else + frame_fp = fp; + + frame_pc = frame_pc >> 16; + fprintf_unfiltered (gdb_stdlog, "stm8_frame_cache: (next_frame=%p) pc=%8.8llx *pc=%8.8lx\n", next_frame, cache->saved_regs[STM8_PC_REGNUM].addr, frame_pc); + fprintf_unfiltered (gdb_stdlog, "stm8_frame_cache: (next_frame=%p) sp=%8.8llx *sp=%8.8lx\n", next_frame, cache->saved_regs[STM8_SP_REGNUM].addr, frame_sp); + fprintf_unfiltered (gdb_stdlog, "stm8_frame_cache: (next_frame=%p) fp=%8.8llx *fp=%8.8lx\n", next_frame, cache->saved_regs[STM8_FP_REGNUM].addr, frame_fp); + } + + return (struct stm8_frame_cache *) (*this_cache); +} + + +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ +static void +stm8_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct stm8_frame_cache *cache = + stm8_frame_cache (next_frame, this_cache); + CORE_ADDR func; + CORE_ADDR base; + + func = get_frame_func (next_frame); + base = cache->base; + + /* This marks the outermost frame. */ + if (base == 0) + return; + + (*this_id) = frame_id_build (base, func); + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_frame_this_id: base=%8.8lx pc=%8.8lx\n",base, func); +} + +static struct value * +stm8_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct value *value; + struct stm8_frame_cache *info = stm8_frame_cache (this_frame, + this_cache); + + value = trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); + + /* Take into account the STM8 specific call. + * Different lengths if it is CALL or CALLF */ + if (regnum == STM8_PC_REGNUM) + { + CORE_ADDR pc = value_as_long (value); + if (info->return_kind == RETURN_RET) + pc >>= 16; + else + pc >>= 8; + + release_value (value); + value_free (value); + + value = frame_unwind_got_constant (this_frame, regnum, pc); + } + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_frame_prev_register: regnum(%d)=%8.8llx\n", regnum, value_as_long(value)); + + return value; +} + +static void +stm8_store_return_value (struct type *type, struct regcache *regcache, + const gdb_byte *valbuf) +{ + int len; + + len = TYPE_LENGTH (type); + + if (len == 1) + regcache_raw_write_part (regcache, STM8_A_REGNUM, 0, 1, valbuf); + else if (len == 2) + regcache_raw_write_part (regcache, STM8_X_REGNUM, 0, 2, valbuf); + else if (len == 4) + { + regcache_raw_write_part (regcache, STM8_X_REGNUM, 0, 2, valbuf+2); + regcache_raw_write_part (regcache, STM8_Y_REGNUM, 0, 2, valbuf); + } + else + error (_("return of value > 4 is not supported.")); +} + +/* Given a return value in `regcache' with a type `type', + extract and copy its value into `valbuf'. */ + +static void +stm8_extract_return_value (struct type *type, struct regcache *regcache, + void *valbuf) +{ + gdb_byte buf[2]; + + switch (TYPE_LENGTH (type)) + { + case 1: + regcache_raw_read (regcache, STM8_A_REGNUM, buf); + memcpy (valbuf, buf, 1); + break; + + case 2: + regcache_raw_read (regcache, STM8_X_REGNUM, buf); + memcpy (valbuf, buf, 2); + break; + + case 4: + regcache_raw_read (regcache, STM8_X_REGNUM, buf); + memcpy ((char*) valbuf + 2, buf, 2); + regcache_raw_read (regcache, STM8_Y_REGNUM, buf); + memcpy (valbuf, buf, 2); + break; + + default: + error (_("bad size for return value")); + } +} + +static enum return_value_convention +stm8_return_value (struct gdbarch *gdbarch, struct value *function, + struct type *valtype, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT + || TYPE_CODE (valtype) == TYPE_CODE_UNION + || TYPE_CODE (valtype) == TYPE_CODE_ARRAY + || TYPE_LENGTH (valtype) > 4) + return RETURN_VALUE_STRUCT_CONVENTION; + else + { + if (readbuf != NULL) + stm8_extract_return_value (valtype, regcache, readbuf); + if (writebuf != NULL) + stm8_store_return_value (valtype, regcache, writebuf); + return RETURN_VALUE_REGISTER_CONVENTION; + } +} + +static const struct frame_unwind stm8_frame_unwind = { + NORMAL_FRAME, + default_frame_unwind_stop_reason, + stm8_frame_this_id, + stm8_frame_prev_register, + NULL, + default_frame_sniffer +}; + +static CORE_ADDR +stm8_frame_base_address (struct frame_info *next_frame, + void **this_cache) +{ + struct stm8_frame_cache *cache = + stm8_frame_cache (next_frame, this_cache); + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_frame_base_address: fb=%8.8lx\n", cache->base); + + return cache->base; +} + +static CORE_ADDR +stm8_frame_args_address (struct frame_info *this_frame, void **this_cache) +{ + CORE_ADDR addr; + struct stm8_frame_cache *info + = stm8_frame_cache (this_frame, this_cache); + + addr = info->base; + if (info->return_kind == RETURN_IRET) + addr += 12; //2 bytes fp + 9 bytes regs + 1 + else if (info->return_kind == RETURN_RETF) + addr += 6; //2 bytes fp + 3 bytes pc + 1 + else + addr += 5; //2 bytes fp + 2 bytes pc + 1 + + if (stm8_debug) + fprintf_unfiltered (gdb_stdlog, "stm8_frame_args_address: addr = %8.8lx\n",addr); + + return addr; +} + +static const struct frame_base stm8_frame_base = +{ + &stm8_frame_unwind, + stm8_frame_base_address, + stm8_frame_base_address, + stm8_frame_args_address +}; + +static const struct frame_base * +stm8_frame_base_sniffer (struct frame_info *this_frame) +{ + return &stm8_frame_base; +} + +struct target_desc *tdesc_stm8; +static void +initialize_tdesc_stm8 (void) +{ + struct target_desc *result = allocate_target_description (); + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.stm8.core"); + tdesc_create_reg (feature, "pc", 0, 1, "general", 32, "uint32"); + tdesc_create_reg (feature, "a", 1, 1, "general", 8, "uint8"); + tdesc_create_reg (feature, "x", 2, 1, "general", 16, "uint16"); + tdesc_create_reg (feature, "y", 3, 1, "general", 16, "uint16"); + tdesc_create_reg (feature, "sp", 4, 1, "general", 16, "uint16"); + tdesc_create_reg (feature, "cc", 5, 1, "general", 8, "uint16"); + + tdesc_stm8 = result; +} + + +/* Initialize the gdbarch structure for the STM8. */ + +static struct gdbarch * +stm8_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + struct gdbarch_list *best_arch; + struct tdesc_arch_data *tdesc_data = NULL; + const struct target_desc *tdesc = info.target_desc; + + /* If there is already a candidate, use it. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + { + tdep = gdbarch_tdep (arches->gdbarch); + stm8_initialize_soft_register_info(tdep); + return arches->gdbarch; + } + if (tdesc == NULL) + tdesc = tdesc_stm8; + + /* Check any target description for validity. */ + if (tdesc_has_registers (tdesc)) + { + const struct tdesc_feature *feature; + int valid_p; + int i; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.stm8.core"); + if (feature == NULL) + return NULL; + tdesc_data = tdesc_data_alloc (); + + valid_p = 1; + for (int i = 0; i < STM8_NUM_REGS; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + stm8_register_names[i]); + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + } + + /* None found, create a new architecture from the information provided. */ + tdep = XNEW (struct gdbarch_tdep); + gdbarch = gdbarch_alloc (&info, tdep); + + /* Initialize soft registers */ + stm8_initialize_soft_register_info(tdep); + + set_gdbarch_num_regs (gdbarch, STM8_NUM_REGS); + set_gdbarch_register_name (gdbarch, stm8_register_name); + set_gdbarch_register_type (gdbarch, stm8_register_type); + set_tdesc_pseudo_register_type (gdbarch, stm8_register_type); + set_tdesc_pseudo_register_name (gdbarch, stm8_register_name); + + set_gdbarch_num_pseudo_regs (gdbarch, 1); + set_gdbarch_pseudo_register_read (gdbarch, stm8_pseudo_register_read); + set_gdbarch_pseudo_register_write (gdbarch, stm8_pseudo_register_write); + + set_gdbarch_convert_register_p (gdbarch, stm8_convert_register_p); + set_gdbarch_register_to_value (gdbarch, stm8_register_to_value); + + /* Register numbers of various important registers. */ + set_gdbarch_sp_regnum (gdbarch, STM8_SP_REGNUM); + set_gdbarch_pc_regnum (gdbarch, STM8_PC_REGNUM); + set_gdbarch_ps_regnum (gdbarch, STM8_CC_REGNUM); + + //set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT); + //set_gdbarch_addr_bit (gdbarch, 3 * TARGET_CHAR_BIT); + + /* Map Dwarf2 registers to GDB registers. */ + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, stm8_dwarf2_reg_to_regnum); + + /* Call dummy code. */ + set_gdbarch_call_dummy_location (gdbarch, ON_STACK); + + set_gdbarch_return_value (gdbarch, stm8_return_value); + + set_gdbarch_skip_prologue (gdbarch, stm8_skip_prologue); + + /* Stack grows downward. */ + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + +#if 0 + set_gdbarch_breakpoint_kind_from_pc (gdbarch, stm8_breakpoint_kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, stm8_sw_breakpoint_from_kind); +#endif + set_gdbarch_breakpoint_from_pc (gdbarch, stm8_breakpoint_from_pc); + + //set_gdbarch_frame_args_skip (gdbarch, 8); + + set_gdbarch_print_insn (gdbarch, print_insn_stm8); + + set_gdbarch_write_pc (gdbarch, stm8_write_pc); + + set_gdbarch_unwind_pc (gdbarch, stm8_unwind_pc); + set_gdbarch_unwind_sp (gdbarch, stm8_unwind_sp); + set_gdbarch_dummy_id (gdbarch, stm8_dummy_id); + + frame_base_set_default (gdbarch, &stm8_frame_base); + + /* Hook in ABI-specific overrides, if they have been registered. */ + //gdbarch_init_osabi (info, gdbarch); + + //dwarf2 cfi unwinder + //dwarf2_frame_set_init_reg (gdbarch, stm8_dwarf2_frame_init_reg); + + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &stm8_frame_unwind); + frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer); + frame_base_append_sniffer (gdbarch, stm8_frame_base_sniffer); + +// /* Create a type for PC. We can't use builtin types here, as they may not +// be defined. */ +// tdep->void_type = arch_type (gdbarch, TYPE_CODE_VOID, 1, "void"); +// tdep->func_void_type = make_function_type (tdep->void_type, NULL); +// tdep->pc_type = arch_pointer_type (gdbarch, 4 * TARGET_CHAR_BIT, NULL, +// tdep->func_void_type); +// +// set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT); +// set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT); +// set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT); +// set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT); +// set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT); +// set_gdbarch_addr_bit (gdbarch, 32); +// +// set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT); +// set_gdbarch_double_bit (gdbarch, 4 * TARGET_CHAR_BIT); +// set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT); +// +// set_gdbarch_float_format (gdbarch, floatformats_ieee_single); +// set_gdbarch_double_format (gdbarch, floatformats_ieee_single); +// set_gdbarch_long_double_format (gdbarch, floatformats_ieee_single); +// +// +// set_gdbarch_push_dummy_call (gdbarch, stm8_push_dummy_call); +// +// set_gdbarch_dwarf2_reg_to_regnum (gdbarch, stm8_dwarf_reg_to_regnum); +// +// set_gdbarch_address_to_pointer (gdbarch, avr_address_to_pointer); +// set_gdbarch_pointer_to_address (gdbarch, avr_pointer_to_address); +// set_gdbarch_integer_to_address (gdbarch, avr_integer_to_address); +// +// frame_base_set_default (gdbarch, &stm8_frame_base); +// +// set_gdbarch_dummy_id (gdbarch, stm8_dummy_id); +// +// + + if (tdesc_data != NULL) + tdesc_use_registers (gdbarch, tdesc, tdesc_data); + + return gdbarch; +} + +static void +show_stm8_debug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("stm8 debugging is %s.\n"), value); +} + +extern initialize_file_ftype _initialize_stm8_tdep; /* -Wmissing-prototypes */ + +void +_initialize_stm8_tdep (void) +{ + stm8_debug = 0; + register_gdbarch_init (bfd_arch_stm8, stm8_gdbarch_init); + initialize_tdesc_stm8 (); + + add_setshow_zuinteger_cmd ("stm8", class_maintenance, &stm8_debug, _("\ +Set stm8 debugging."), _("\ +Show stm8 debugging."), _("\ +When non-zero, stm8 debugging is enabled."), +NULL, +show_stm8_debug, +&setdebuglist, &showdebuglist); + +} diff --git a/include/dis-asm.h b/include/dis-asm.h index eebdaf874f..234dfed263 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -248,6 +248,7 @@ extern int print_insn_rl78 (bfd_vma, disassemble_info *); extern int print_insn_rl78_g10 (bfd_vma, disassemble_info *); extern int print_insn_rl78_g13 (bfd_vma, disassemble_info *); extern int print_insn_rl78_g14 (bfd_vma, disassemble_info *); +extern int print_insn_stm8 (bfd_vma, disassemble_info *); extern disassembler_ftype arc_get_disassembler (bfd *); extern disassembler_ftype cris_get_disassembler (bfd *); diff --git a/include/elf/stm8.h b/include/elf/stm8.h new file mode 100644 index 0000000000..4f70335431 --- /dev/null +++ b/include/elf/stm8.h @@ -0,0 +1,38 @@ +/* STM8 ELF support for BFD. + Written by Ake Rehnman 2017-02-21, + ake.rehnman (at) gmail dot com + + Copyright (C) 1999-2016 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. */ + +#ifndef _ELF_STM8_H +#define _ELF_STM8_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_avr_reloc_type) + RELOC_NUMBER (R_STM8_NONE, 0) + RELOC_NUMBER (R_STM8_8, 1) + RELOC_NUMBER (R_STM8_16, 2) + RELOC_NUMBER (R_STM8_24, 3) + RELOC_NUMBER (R_STM8_32, 4) + RELOC_NUMBER (R_STM8_8_PCREL, 5) +END_RELOC_NUMBERS (R_STM8_max) + +#endif /* _ELF_STM_H */ diff --git a/include/opcode/stm8.h b/include/opcode/stm8.h new file mode 100644 index 0000000000..a40ff0aaaa --- /dev/null +++ b/include/opcode/stm8.h @@ -0,0 +1,82 @@ +/* include/opcode/stm8.h -- Assembler for the STM8. + Written by Ake Rehnman 2017-02-21, + ake.rehnman (at) gmail dot com + + Copyright (C) 2007-2016 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. */ + +#ifndef _STM8_H_ +#define _STM8_H_ + +typedef enum { + ST8_END = 0, + ST8_BIT_0, + ST8_BIT_1, + ST8_BIT_2, + ST8_BIT_3, + ST8_BIT_4, + ST8_BIT_5, + ST8_BIT_6, + ST8_BIT_7, + ST8_PCREL, + ST8_REG_CC, + ST8_REG_A, + ST8_REG_X, + ST8_REG_Y, + ST8_REG_SP, + ST8_REG_XL, + ST8_REG_XH, + ST8_REG_YL, + ST8_REG_YH, + ST8_BYTE, //IMM8 + ST8_WORD, //IMM16 + ST8_SHORTMEM, //DIR8 + ST8_LONGMEM, //DIR16 + ST8_EXTMEM, //DIR24 + ST8_INDX, + ST8_INDY, + ST8_SHORTOFF_X, + ST8_LONGOFF_X, + ST8_EXTOFF_X, + ST8_SHORTOFF_Y, + ST8_LONGOFF_Y, + ST8_EXTOFF_Y, + ST8_SHORTOFF_SP, + ST8_SHORTPTRW, + ST8_LONGPTRW, + ST8_SHORTPTRW_X, + ST8_LONGPTRW_X, + ST8_SHORTPTRW_Y, + ST8_LONGPTRW_Y, + ST8_LONGPTRE, + ST8_LONGPTRE_X, + ST8_LONGPTRE_Y +} stm8_addr_mode_t; + +struct stm8_opcodes_s +{ + const char * name; + stm8_addr_mode_t constraints[5]; + unsigned int bin_opcode; +}; + +extern const struct stm8_opcodes_s stm8_opcodes[]; + +extern int stm8_compute_insn_size(struct stm8_opcodes_s opcode); + +extern unsigned int stm8_opcode_size(unsigned int number); + +#endif /* _STM8_H_ */ diff --git a/ld/Makefile.am b/ld/Makefile.am index 6243c12528..edac1c77fc 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -516,7 +516,8 @@ ALL_64_EMULATION_SOURCES = \ eshelf64.c \ eshelf64_nbsd.c \ eshlelf64.c \ - eshlelf64_nbsd.c + eshlelf64_nbsd.c \ + eelf32stm8.c ALL_64_EMULATIONS = $(ALL_64_EMULATION_SOURCES:.c=.@OBJEXT@) @@ -2093,6 +2094,10 @@ eshlelf64_nbsd.c: $(srcdir)/emulparams/shlelf64_nbsd.sh \ $(srcdir)/emulparams/shelf64_nbsd.sh \ $(srcdir)/emulparams/shelf32_nbsd.sh $(srcdir)/emulparams/shelf32.sh \ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + +eelf32stm8.c: $(srcdir)/emulparams/elf32stm8.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elfstm8.sc ${GEN_DEPENDS} + # We need this for automake to use YLWRAP. diff --git a/ld/Makefile.in b/ld/Makefile.in index 760c037f9d..a73392c0d6 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -884,7 +884,8 @@ ALL_64_EMULATION_SOURCES = \ eshelf64.c \ eshelf64_nbsd.c \ eshlelf64.c \ - eshlelf64_nbsd.c + eshlelf64_nbsd.c \ + eelf32stm8.c ALL_64_EMULATIONS = $(ALL_64_EMULATION_SOURCES:.c=.@OBJEXT@) ALL_EMUL_EXTRA_OFILES = \ @@ -1282,6 +1283,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32ppcwindiss.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32rl78.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32rx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32stm8.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32tilegx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32tilegx_be.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32tilepro.Po@am__quote@ @@ -3658,6 +3660,9 @@ eshlelf64_nbsd.c: $(srcdir)/emulparams/shlelf64_nbsd.sh \ $(srcdir)/emulparams/shelf32_nbsd.sh $(srcdir)/emulparams/shelf32.sh \ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} +eelf32stm8.c: $(srcdir)/emulparams/elf32stm8.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elfstm8.sc ${GEN_DEPENDS} + check-DEJAGNU: site.exp srcroot=`cd $(srcdir) && pwd`; export srcroot; \ r=`pwd`; export r; \ diff --git a/ld/configure.tgt b/ld/configure.tgt index 6183a85b3d..3f6e0f28f4 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -877,6 +877,8 @@ z80-*-coff) targ_emul=z80 ;; z8k-*-coff) targ_emul=z8002; targ_extra_emuls=z8001 ;; +stm8-*-elf32) targ_emul=elf32stm8 + ;; *-*-ieee*) targ_emul=vanilla ;; *-tandem-none) targ_emul=st2000 diff --git a/ld/emulparams/elf32stm8.sh b/ld/emulparams/elf32stm8.sh new file mode 100644 index 0000000000..c37c9e51da --- /dev/null +++ b/ld/emulparams/elf32stm8.sh @@ -0,0 +1,14 @@ +ARCH=stm8 +MACHINE=stm8 +SCRIPT_NAME=elfstm8 +OUTPUT_FORMAT="elf32-stm8" +MAXPAGESIZE=1 +EMBEDDED=yes +TEMPLATE_NAME=elf32 + +TEXT_LENGTH=1024K +DATA_ORIGIN=0x802000 +DATA_LENGTH=0xffa0 + + + diff --git a/ld/scripttempl/elfstm8.sc b/ld/scripttempl/elfstm8.sc new file mode 100644 index 0000000000..0ce6b56741 --- /dev/null +++ b/ld/scripttempl/elfstm8.sc @@ -0,0 +1,232 @@ +# Adapted from mips.sc +# +# Copyright (C) 2014-2016 Free Software Foundation, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# +# These variables may be overridden by the emulation file. The +# defaults are appropriate for a DECstation running Ultrix. + +test -z "$ENTRY" && ENTRY=_start + +#test -z "$TEXT_START_ADDR" && TEXT_START_ADDR="0x0" + +CTOR=".ctors ${CONSTRUCTING-0} : + { + ${CONSTRUCTING+${CTOR_START}} + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + + KEEP (*crtbegin.o(.ctors)) + + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + ${CONSTRUCTING+${CTOR_END}} + }" + +DTOR=" .dtors ${CONSTRUCTING-0} : + { + ${CONSTRUCTING+${DTOR_START}} + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + ${CONSTRUCTING+${DTOR_END}} + }" + +cat < +#include "dis-asm.h" +#include "opintl.h" +#include "libiberty.h" + +#include "opcode/stm8.h" + +disassemble_info *dinfo; +bfd_vma daddr; +int instrlen; +bfd_vma lastlabeladdr; +unsigned char buffer[16]; + +int stm8_dis(bfd_vma addr, unsigned int op); +int stm8_operands(char *s, unsigned char buf[], stm8_addr_mode_t arg); +const char* find_symbol(unsigned int addr); +int find_symbol_x(bfd_vma addr); + + +static int +fetch_data (unsigned char *buf, bfd_vma addr, disassemble_info *info, int n) +{ + int r; + + r = info->read_memory_func (addr, buf, n, info); + return r; +} + +int find_symbol_x(bfd_vma addr) +{ + return dinfo->symbol_at_address_func(addr,dinfo); +} + +const char* find_symbol(unsigned int addr) +{ + int i; + + for (i=0;i<(dinfo->symtab_size);i++) + { + if ((dinfo->symtab[i]->value+dinfo->symtab[i]->section->vma) == addr) + return dinfo->symtab[i]->name; + } + lastlabeladdr = addr; + return 0; +} + +int stm8_operands(char *s, unsigned char buf[], stm8_addr_mode_t arg) +{ + unsigned int val; + const char *sym; + + switch(arg) + { + case ST8_REG_A: + sprintf(s,"A"); + break; + case ST8_REG_X: + sprintf(s,"X"); + break; + case ST8_REG_Y: + sprintf(s,"Y"); + break; + case ST8_REG_SP: + sprintf(s,"SP"); + break; + case ST8_REG_CC: + sprintf(s,"CC"); + break; + case ST8_REG_XL: + sprintf(s,"XL"); + break; + case ST8_REG_XH: + sprintf(s,"XH"); + break; + case ST8_REG_YL: + sprintf(s,"YL"); + break; + case ST8_REG_YH: + sprintf(s,"YH"); + break; + case ST8_BIT_0: + sprintf(s,"#0"); + break; + case ST8_BIT_1: + sprintf(s,"#1"); + break; + case ST8_BIT_2: + sprintf(s,"#2"); + break; + case ST8_BIT_3: + sprintf(s,"#3"); + break; + case ST8_BIT_4: + sprintf(s,"#4"); + break; + case ST8_BIT_5: + sprintf(s,"#5"); + break; + case ST8_BIT_6: + sprintf(s,"#6"); + break; + case ST8_BIT_7: + sprintf(s,"#7"); + break; + case ST8_BYTE: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"#%s",sym); + else + sprintf(s,"#0x%2.2x",val); + return 1; + break; + case ST8_WORD: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"#%s",sym); + else + sprintf(s,"#0x%4.4x",val); + return 2; + break; + case ST8_PCREL: + val = (char)buf[0]; + val += (daddr + instrlen); + sym = find_symbol(val); + if (sym) + sprintf(s,"%s",sym); + else + sprintf(s,"0x%4.4x",val); + return 1; + break; + case ST8_SHORTMEM: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"%s",sym); + else + sprintf(s,"0x%2.2x",val); + return 1; + break; + case ST8_INDX: + sprintf(s,"(X)"); + break; + case ST8_SHORTOFF_X: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,X)",sym); + else + sprintf(s,"(0x%2.2x,X)",val); + return 1; + break; + case ST8_INDY: + sprintf(s,"(Y)"); + break; + case ST8_SHORTOFF_Y: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,Y)",sym); + else + sprintf(s,"(0x%2.2x,Y)",val); + return 1; + break; + case ST8_SHORTOFF_SP: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,SP)",sym); + else + sprintf(s,"(0x%2.2x,SP)",val); + return 1; + break; + case ST8_SHORTPTRW: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"[%s.w]",sym); + else + sprintf(s,"[0x%2.2x.w]",val); + return 1; + break; + case ST8_SHORTPTRW_X: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"([%s.w],X)",sym); + else + sprintf(s,"([0x%2.2x.w],X)",val); + return 1; + break; + case ST8_SHORTPTRW_Y: + val = buf[0]; + sym = find_symbol(val); + if (sym) + sprintf(s,"([%s.w],Y)",sym); + else + sprintf(s,"([0x%2.2x.w],Y)",val); + return 1; + break; + case ST8_LONGMEM: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"%s",sym); + else + sprintf(s,"0x%4.4x",val); + return 2; + break; + case ST8_LONGOFF_X: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,X)",sym); + else + sprintf(s,"(0x%4.4x,X)",val); + return 2; + break; + case ST8_LONGOFF_Y: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,Y)",sym); + else + sprintf(s,"(0x%4.4x,Y)",val); + return 2; + break; + case ST8_LONGPTRW: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"[%s.w]",sym); + else + sprintf(s,"[0x%4.4x.w]",val); + return 2; + break; + case ST8_LONGPTRW_X: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"([%s.w],X)",sym); + else + sprintf(s,"([0x%4.4x.w],X)",val); + return 2; + break; + case ST8_LONGPTRW_Y: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"([%s.w],Y)",sym); + else + sprintf(s,"([0x%4.4x.w],Y)",val); + return 2; + break; + case ST8_LONGPTRE: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"[%s.e]",sym); + else + sprintf(s,"[0x%4.4x.e]",val); + return 2; + break; + case ST8_LONGPTRE_X: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"([%s.e],X)",sym); + else + sprintf(s,"([0x%4.4x.e],X)",val); + return 2; + break; + case ST8_LONGPTRE_Y: + val = (buf[0]<<8)+buf[1]; + sym = find_symbol(val); + if (sym) + sprintf(s,"([%s.e],Y)",sym); + else + sprintf(s,"([0x%4.4x.e],Y)",val); + return 2; + break; + case ST8_EXTMEM: + val = (buf[0]<<16)+(buf[1]<<8)+buf[2]; +// if (find_symbol_x(val)) +// dinfo->print_address_func(val,dinfo); + sym = find_symbol(val); + if (sym) + sprintf(s,"%s",sym); + else + sprintf(s,"0x%6.6x",val); + return 3; + break; + case ST8_EXTOFF_X: + val = (buf[0]<<16)+(buf[1]<<8)+buf[2]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,X)",sym); + else + sprintf(s,"(0x%6.6x,X)",val); + return 3; + break; + case ST8_EXTOFF_Y: + val = (buf[0]<<16)+(buf[1]<<8)+buf[2]; + sym = find_symbol(val); + if (sym) + sprintf(s,"(%s,Y)",sym); + else + sprintf(s,"(0x%6.6x,Y)",val); + return 3; + break; + case ST8_END: + break; + } + return 0; +} + +int stm8_dis(bfd_vma addr, unsigned int op) +{ + unsigned char buf[8]; + unsigned char *bufp; + char s[256]; + int i=0; + int j; + char c; + int operandlen; + + while (stm8_opcodes[i].name) + { + if (op == stm8_opcodes[i].bin_opcode) + { + bufp=buf; + s[0] = 0; + dinfo->fprintf_func(dinfo->stream, "%s",stm8_opcodes[i].name); + operandlen = stm8_compute_insn_size(stm8_opcodes[i])-stm8_opcode_size(op); + instrlen += operandlen; + if (fetch_data(buf,addr,dinfo,operandlen)) + return 0; + lastlabeladdr = 0; + for (j=0;j<5;j++) + { + s[0]=0; + bufp+=stm8_operands(s, bufp, stm8_opcodes[i].constraints[j]); + if (s[0]) + { + if (j==0) c=' '; else c=','; + dinfo->fprintf_func(dinfo->stream, "%c%s",c,s); + } + } + if (lastlabeladdr) + { + dinfo->fprintf_func(dinfo->stream, " ;"); + dinfo->print_address_func(lastlabeladdr, dinfo); + } + return operandlen; + } + i++; + } + return 0; +} + +#define PDY 0x90 +#define PIX 0x92 +#define PIY 0x91 +#define PWSP 0x72 + +int print_insn_stm8 (bfd_vma addr, disassemble_info *info) +{ + unsigned int op; + + instrlen = 0; + dinfo = info; + daddr = addr; + if (!fetch_data(buffer, addr, info, 1)) + { + op = buffer[0]; + instrlen++; + if ((buffer[0]==PDY) || (buffer[0]==PIX) || (buffer[0]==PIY) || (buffer[0]==PWSP)) + { + if (fetch_data(buffer, addr, info, 2)) + return -1; + instrlen++; + op = buffer[0]<<8; + op += buffer[1]; + } + stm8_dis(addr+instrlen, op); + } + return instrlen; +} diff --git a/opcodes/stm8-opc.c b/opcodes/stm8-opc.c new file mode 100644 index 0000000000..3a600d66d3 --- /dev/null +++ b/opcodes/stm8-opc.c @@ -0,0 +1,799 @@ +/* stm8-opc.c -- Table of opcodes for the STM8 processor. + Copyright (C) 2007-2016 Free Software Foundation, Inc. + Contributed by Ake Rehnman ake dot rehnman (at) gmail dot com + + This file is part of the GNU opcodes library. + + This library 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. + + It 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 +#include "libiberty.h" +#include "symcat.h" +#include "opcode/stm8.h" + +const struct stm8_opcodes_s stm8_opcodes[] = +{ +//nop +{"nop", {}, 0x9D}, +//adc +{"adc", {ST8_REG_A, ST8_BYTE}, 0xA9}, +{"adc", {ST8_REG_A, ST8_SHORTMEM}, 0xB9}, +{"adc", {ST8_REG_A, ST8_LONGMEM}, 0xC9}, +{"adc", {ST8_REG_A, ST8_INDX}, 0xF9}, +{"adc", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE9}, +{"adc", {ST8_REG_A, ST8_LONGOFF_X}, 0xD9}, +{"adc", {ST8_REG_A, ST8_INDY}, 0x90F9}, +{"adc", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E9}, +{"adc", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D9}, +{"adc", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x19}, +{"adc", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C9}, +{"adc", {ST8_REG_A, ST8_LONGPTRW}, 0x72C9}, +{"adc", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D9}, +{"adc", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D9}, +{"adc", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D9}, +//add +{"add", {ST8_REG_A, ST8_BYTE}, 0xAB}, +{"add", {ST8_REG_A, ST8_SHORTMEM}, 0xBB}, +{"add", {ST8_REG_A, ST8_LONGMEM}, 0xCB}, +{"add", {ST8_REG_A, ST8_INDX}, 0xFB}, +{"add", {ST8_REG_A, ST8_SHORTOFF_X}, 0xEB}, +{"add", {ST8_REG_A, ST8_LONGOFF_X}, 0xDB}, +{"add", {ST8_REG_A, ST8_INDY}, 0x90FB}, +{"add", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90EB}, +{"add", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90DB}, +{"add", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x1B}, +{"add", {ST8_REG_A, ST8_SHORTPTRW}, 0x92CB}, +{"add", {ST8_REG_A, ST8_LONGPTRW}, 0x72CB}, +{"add", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92DB}, +{"add", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72DB}, +{"add", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91DB}, +//addw +{"addw", {ST8_REG_X, ST8_WORD}, 0x1C}, +{"addw", {ST8_REG_X, ST8_LONGMEM}, 0x72BB}, +{"addw", {ST8_REG_X, ST8_SHORTOFF_SP}, 0x72FB}, +{"addw", {ST8_REG_Y, ST8_WORD}, 0x72A9}, +{"addw", {ST8_REG_Y, ST8_LONGMEM}, 0x72B9}, +{"addw", {ST8_REG_Y, ST8_SHORTOFF_SP}, 0x72F9}, +{"addw", {ST8_REG_SP, ST8_BYTE}, 0x5B}, +//and +{"and", {ST8_REG_A, ST8_BYTE}, 0xA4}, +{"and", {ST8_REG_A, ST8_SHORTMEM}, 0xB4}, +{"and", {ST8_REG_A, ST8_LONGMEM}, 0xC4}, +{"and", {ST8_REG_A, ST8_INDX}, 0xF4}, +{"and", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE4}, +{"and", {ST8_REG_A, ST8_LONGOFF_X}, 0xD4}, +{"and", {ST8_REG_A, ST8_INDY}, 0x90F4}, +{"and", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E4}, +{"and", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D4}, +{"and", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x14}, +{"and", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C4}, +{"and", {ST8_REG_A, ST8_LONGPTRW}, 0x72C4}, +{"and", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D4}, +{"and", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D4}, +{"and", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D4}, +//bccm +//{"bccm", {ST8_LONGMEM, ST8_BYTE}, 0x90xx}, +//bcp +{"bcp", {ST8_REG_A, ST8_BYTE}, 0xA5}, +{"bcp", {ST8_REG_A, ST8_SHORTMEM}, 0xB5}, +{"bcp", {ST8_REG_A, ST8_LONGMEM}, 0xC5}, +{"bcp", {ST8_REG_A, ST8_INDX}, 0xF5}, +{"bcp", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE5}, +{"bcp", {ST8_REG_A, ST8_LONGOFF_X}, 0xD5}, +{"bcp", {ST8_REG_A, ST8_INDY}, 0x90F5}, +{"bcp", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E5}, +{"bcp", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D5}, +{"bcp", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x15}, +{"bcp", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C5}, +{"bcp", {ST8_REG_A, ST8_LONGPTRW}, 0x72C5}, +{"bcp", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D5}, +{"bcp", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D5}, +{"bcp", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D5}, +//bcpl +{"bcpl", {ST8_LONGMEM, ST8_BIT_0}, 0x9010}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_1}, 0x9012}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_2}, 0x9014}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_3}, 0x9016}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_4}, 0x9018}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_5}, 0x901a}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_6}, 0x901c}, +{"bcpl", {ST8_LONGMEM, ST8_BIT_7}, 0x901e}, +//break +{"break", {}, 0x8B}, +//bres +{"bres", {ST8_LONGMEM, ST8_BIT_0}, 0x7211}, +{"bres", {ST8_LONGMEM, ST8_BIT_1}, 0x7213}, +{"bres", {ST8_LONGMEM, ST8_BIT_2}, 0x7215}, +{"bres", {ST8_LONGMEM, ST8_BIT_3}, 0x7217}, +{"bres", {ST8_LONGMEM, ST8_BIT_4}, 0x7219}, +{"bres", {ST8_LONGMEM, ST8_BIT_5}, 0x721b}, +{"bres", {ST8_LONGMEM, ST8_BIT_6}, 0x721d}, +{"bres", {ST8_LONGMEM, ST8_BIT_7}, 0x721f}, +//bset +{"bset", {ST8_LONGMEM, ST8_BIT_0}, 0x7210}, +{"bset", {ST8_LONGMEM, ST8_BIT_1}, 0x7212}, +{"bset", {ST8_LONGMEM, ST8_BIT_2}, 0x7214}, +{"bset", {ST8_LONGMEM, ST8_BIT_3}, 0x7216}, +{"bset", {ST8_LONGMEM, ST8_BIT_4}, 0x7218}, +{"bset", {ST8_LONGMEM, ST8_BIT_5}, 0x721a}, +{"bset", {ST8_LONGMEM, ST8_BIT_6}, 0x721c}, +{"bset", {ST8_LONGMEM, ST8_BIT_7}, 0x721e}, +//btjf +{"btjf", {ST8_LONGMEM, ST8_BIT_0, ST8_PCREL}, 0x7201}, +{"btjf", {ST8_LONGMEM, ST8_BIT_1, ST8_PCREL}, 0x7203}, +{"btjf", {ST8_LONGMEM, ST8_BIT_2, ST8_PCREL}, 0x7205}, +{"btjf", {ST8_LONGMEM, ST8_BIT_3, ST8_PCREL}, 0x7207}, +{"btjf", {ST8_LONGMEM, ST8_BIT_4, ST8_PCREL}, 0x7209}, +{"btjf", {ST8_LONGMEM, ST8_BIT_5, ST8_PCREL}, 0x720b}, +{"btjf", {ST8_LONGMEM, ST8_BIT_6, ST8_PCREL}, 0x720d}, +{"btjf", {ST8_LONGMEM, ST8_BIT_7, ST8_PCREL}, 0x720f}, +//btjt +{"btjt", {ST8_LONGMEM, ST8_BIT_0, ST8_PCREL}, 0x7200}, +{"btjt", {ST8_LONGMEM, ST8_BIT_1, ST8_PCREL}, 0x7202}, +{"btjt", {ST8_LONGMEM, ST8_BIT_2, ST8_PCREL}, 0x7204}, +{"btjt", {ST8_LONGMEM, ST8_BIT_3, ST8_PCREL}, 0x7206}, +{"btjt", {ST8_LONGMEM, ST8_BIT_4, ST8_PCREL}, 0x7208}, +{"btjt", {ST8_LONGMEM, ST8_BIT_5, ST8_PCREL}, 0x720a}, +{"btjt", {ST8_LONGMEM, ST8_BIT_6, ST8_PCREL}, 0x720c}, +{"btjt", {ST8_LONGMEM, ST8_BIT_7, ST8_PCREL}, 0x720e}, +//call +{"call", {ST8_LONGMEM}, 0xCD}, +{"call", {ST8_INDX}, 0xFD}, +{"call", {ST8_SHORTOFF_X}, 0xED}, +{"call", {ST8_LONGOFF_X}, 0xDD}, +{"call", {ST8_INDY}, 0x90FD}, +{"call", {ST8_SHORTOFF_Y}, 0x90ED}, +{"call", {ST8_LONGOFF_Y}, 0x90DD}, +{"call", {ST8_SHORTPTRW}, 0x92CD}, +{"call", {ST8_LONGPTRW}, 0x72CD}, +{"call", {ST8_SHORTPTRW_X}, 0x92DD}, +{"call", {ST8_LONGPTRW_X}, 0x72DD}, +{"call", {ST8_SHORTPTRW_Y}, 0x91DD}, +//callf +{"callf", {ST8_EXTMEM}, 0x8D}, +{"callf", {ST8_LONGPTRE}, 0x928D}, +//callr +{"callr", {ST8_PCREL}, 0xAD}, +//ccf +{"ccf", {}, 0x8C}, +//clr +{"clr", {ST8_REG_A}, 0x4F}, +{"clr", {ST8_SHORTMEM}, 0x3F}, +{"clr", {ST8_LONGMEM}, 0x725F}, +{"clr", {ST8_INDX}, 0x7F}, +{"clr", {ST8_SHORTOFF_X}, 0x6F}, +{"clr", {ST8_LONGOFF_X}, 0x724F}, +{"clr", {ST8_INDY}, 0x907F}, +{"clr", {ST8_SHORTOFF_Y}, 0x906F}, +{"clr", {ST8_LONGOFF_Y}, 0x904F}, +{"clr", {ST8_SHORTOFF_SP}, 0x0F}, +{"clr", {ST8_SHORTPTRW}, 0x923F}, +{"clr", {ST8_LONGPTRW}, 0x723F}, +{"clr", {ST8_SHORTPTRW_X}, 0x926F}, +{"clr", {ST8_LONGPTRW_X}, 0x726F}, +{"clr", {ST8_SHORTPTRW_Y}, 0x916F}, +//clrw +{"clrw", {ST8_REG_X}, 0x5F}, +{"clrw", {ST8_REG_Y}, 0x905F}, +//cp +{"cp", {ST8_REG_A, ST8_BYTE}, 0xA1}, +{"cp", {ST8_REG_A, ST8_SHORTMEM}, 0xB1}, +{"cp", {ST8_REG_A, ST8_LONGMEM}, 0xC1}, +{"cp", {ST8_REG_A, ST8_INDX}, 0xF1}, +{"cp", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE1}, +{"cp", {ST8_REG_A, ST8_LONGOFF_X}, 0xD1}, +{"cp", {ST8_REG_A, ST8_INDY}, 0x90F1}, +{"cp", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E1}, +{"cp", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D1}, +{"cp", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x11}, +{"cp", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C1}, +{"cp", {ST8_REG_A, ST8_LONGPTRW}, 0x72C1}, +{"cp", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D1}, +{"cp", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D1}, +{"cp", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D1}, +//cpw +{"cpw", {ST8_REG_X, ST8_WORD}, 0xA3}, +{"cpw", {ST8_REG_X, ST8_SHORTMEM}, 0xB3}, +{"cpw", {ST8_REG_X, ST8_LONGMEM}, 0xC3}, +{"cpw", {ST8_REG_X, ST8_INDY}, 0x90F3}, +{"cpw", {ST8_REG_X, ST8_SHORTOFF_Y}, 0x90E3}, +{"cpw", {ST8_REG_X, ST8_LONGOFF_Y}, 0x90D3}, +{"cpw", {ST8_REG_X, ST8_SHORTOFF_SP}, 0x13}, +{"cpw", {ST8_REG_X, ST8_SHORTPTRW}, 0x92C3}, +{"cpw", {ST8_REG_X, ST8_LONGPTRW}, 0x72C3}, +{"cpw", {ST8_REG_X, ST8_SHORTPTRW_Y}, 0x91D3}, +{"cpw", {ST8_REG_Y, ST8_WORD}, 0x90A3}, +{"cpw", {ST8_REG_Y, ST8_SHORTMEM}, 0x90B3}, +{"cpw", {ST8_REG_Y, ST8_LONGMEM}, 0x90C3}, +{"cpw", {ST8_REG_Y, ST8_INDX}, 0xF3}, +{"cpw", {ST8_REG_Y, ST8_SHORTOFF_X}, 0xE3}, +{"cpw", {ST8_REG_Y, ST8_LONGOFF_X}, 0xD3}, +{"cpw", {ST8_REG_Y, ST8_SHORTPTRW}, 0x91C3}, +{"cpw", {ST8_REG_Y, ST8_LONGPTRW}, 0x92D3}, +{"cpw", {ST8_REG_Y, ST8_SHORTPTRW_X}, 0x72D3}, +//cpl +{"cpl", {ST8_REG_A}, 0x43}, +{"cpl", {ST8_SHORTMEM}, 0x33}, +{"cpl", {ST8_LONGMEM}, 0x7253}, +{"cpl", {ST8_INDX}, 0x73}, +{"cpl", {ST8_SHORTOFF_X}, 0x63}, +{"cpl", {ST8_LONGOFF_X}, 0x7243}, +{"cpl", {ST8_INDY}, 0x9073}, +{"cpl", {ST8_SHORTOFF_Y}, 0x9063}, +{"cpl", {ST8_LONGOFF_Y}, 0x9043}, +{"cpl", {ST8_SHORTOFF_SP}, 0x03}, +{"cpl", {ST8_SHORTPTRW}, 0x9233}, +{"cpl", {ST8_LONGPTRW}, 0x7233}, +{"cpl", {ST8_SHORTPTRW_X}, 0x9263}, +{"cpl", {ST8_LONGPTRW_X}, 0x7263}, +{"cpl", {ST8_SHORTPTRW_Y}, 0x9163}, +//cplw +{"clrw", {ST8_REG_X}, 0x53}, +{"clrw", {ST8_REG_Y}, 0x9053}, +//dec +{"dec", {ST8_REG_A}, 0x4A}, +{"dec", {ST8_SHORTMEM}, 0x3A}, +{"dec", {ST8_LONGMEM}, 0x725A}, +{"dec", {ST8_INDX}, 0x7A}, +{"dec", {ST8_SHORTOFF_X}, 0x6A}, +{"dec", {ST8_LONGOFF_X}, 0x724A}, +{"dec", {ST8_INDY}, 0x907A}, +{"dec", {ST8_SHORTOFF_Y}, 0x906A}, +{"dec", {ST8_LONGOFF_Y}, 0x904A}, +{"dec", {ST8_SHORTOFF_SP}, 0x0A}, +{"dec", {ST8_SHORTPTRW}, 0x923A}, +{"dec", {ST8_LONGPTRW}, 0x723A}, +{"dec", {ST8_SHORTPTRW_X}, 0x926A}, +{"dec", {ST8_LONGPTRW_X}, 0x726A}, +{"dec", {ST8_SHORTPTRW_Y}, 0x916A}, +//decw +{"decw", {ST8_REG_X}, 0x5A}, +{"decw", {ST8_REG_Y}, 0x905A}, +//div +{"div", {ST8_REG_X, ST8_REG_A}, 0x62}, +{"div", {ST8_REG_Y, ST8_REG_A}, 0x9062}, +//divw +{"divw", {ST8_REG_X, ST8_REG_Y}, 0x65}, +//exg +{"exg", {ST8_REG_A, ST8_REG_XL}, 0x41}, +{"exg", {ST8_REG_A, ST8_REG_YL}, 0x61}, +{"exg", {ST8_REG_A, ST8_LONGMEM}, 0x31}, +//exgw +{"exgw", {ST8_REG_X, ST8_REG_Y}, 0x51}, +//halt +{"halt", {}, 0x8E}, +//inc +{"inc", {ST8_REG_A}, 0x4C}, +{"inc", {ST8_SHORTMEM}, 0x3C}, +{"inc", {ST8_LONGMEM}, 0x725C}, +{"inc", {ST8_INDX}, 0x7C}, +{"inc", {ST8_SHORTOFF_X}, 0x6C}, +{"inc", {ST8_LONGOFF_X}, 0x724C}, +{"inc", {ST8_INDY}, 0x907C}, +{"inc", {ST8_SHORTOFF_Y}, 0x906C}, +{"inc", {ST8_LONGOFF_Y}, 0x904C}, +{"inc", {ST8_SHORTOFF_SP}, 0x0C}, +{"inc", {ST8_SHORTPTRW}, 0x923C}, +{"inc", {ST8_LONGPTRW}, 0x723C}, +{"inc", {ST8_SHORTPTRW_X}, 0x926C}, +{"inc", {ST8_LONGPTRW_X}, 0x726C}, +{"inc", {ST8_SHORTPTRW_Y}, 0x916C}, +//incw +{"incw", {ST8_REG_X}, 0x5C}, +{"incw", {ST8_REG_Y}, 0x905C}, +//int +{"int", {ST8_EXTMEM}, 0x82}, +//iret +{"iret", {}, 0x80}, +//jp +{"jp", {ST8_LONGMEM}, 0xCC}, +{"jp", {ST8_INDX}, 0xFC}, +{"jp", {ST8_SHORTOFF_X}, 0xEC}, +{"jp", {ST8_LONGOFF_X}, 0xDC}, +{"jp", {ST8_INDY}, 0x90FC}, +{"jp", {ST8_SHORTOFF_Y}, 0x90EC}, +{"jp", {ST8_LONGOFF_Y}, 0x90DC}, +{"jp", {ST8_SHORTPTRW}, 0x92CC}, +{"jp", {ST8_LONGPTRW}, 0x72CC}, +{"jp", {ST8_SHORTPTRW_X}, 0x92DC}, +{"jp", {ST8_LONGPTRW_X}, 0x72DC}, +{"jp", {ST8_SHORTPTRW_Y}, 0x91DC}, +//jpf +{"jpf", {ST8_EXTMEM}, 0xAC}, +{"jpf", {ST8_LONGPTRE}, 0x92AC}, +//jrxx +{"jra", {ST8_PCREL}, 0x20}, +{"jrc", {ST8_PCREL}, 0x25}, +{"jreq", {ST8_PCREL}, 0x27}, +{"jrf", {ST8_PCREL}, 0x21}, +{"jrh", {ST8_PCREL}, 0x9029}, +{"jrih", {ST8_PCREL}, 0x902F}, +{"jril", {ST8_PCREL}, 0x902E}, +{"jrm", {ST8_PCREL}, 0x902D}, +{"jrmi", {ST8_PCREL}, 0x2B}, +{"jrnc", {ST8_PCREL}, 0x24}, +{"jrne", {ST8_PCREL}, 0x26}, +{"jrnh", {ST8_PCREL}, 0x9028}, +{"jrnm", {ST8_PCREL}, 0x902C}, +{"jrnv", {ST8_PCREL}, 0x28}, +{"jrpl", {ST8_PCREL}, 0x2A}, +{"jrsge", {ST8_PCREL}, 0x2E}, +{"jrsgt", {ST8_PCREL}, 0x2C}, +{"jrsle", {ST8_PCREL}, 0x2D}, +{"jrslt", {ST8_PCREL}, 0x2F}, +{"jrt", {ST8_PCREL}, 0x20}, +{"jruge", {ST8_PCREL}, 0x24}, +{"jrugt", {ST8_PCREL}, 0x22}, +{"jrule", {ST8_PCREL}, 0x23}, +{"jrult", {ST8_PCREL}, 0x25}, +{"jrv", {ST8_PCREL}, 0x29}, +//ld +{"ld", {ST8_REG_A, ST8_BYTE}, 0xA6}, +{"ld", {ST8_REG_A, ST8_SHORTMEM}, 0xB6}, +{"ld", {ST8_REG_A, ST8_LONGMEM}, 0xC6}, +{"ld", {ST8_REG_A, ST8_INDX}, 0xF6}, +{"ld", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE6}, +{"ld", {ST8_REG_A, ST8_LONGOFF_X}, 0xD6}, +{"ld", {ST8_REG_A, ST8_INDY}, 0x90F6}, +{"ld", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E6}, +{"ld", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D6}, +{"ld", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x7B}, +{"ld", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C6}, +{"ld", {ST8_REG_A, ST8_LONGPTRW}, 0x72C6}, +{"ld", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D6}, +{"ld", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D6}, +{"ld", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D6}, +{"ld", {ST8_SHORTMEM, ST8_REG_A}, 0xB7}, +{"ld", {ST8_LONGMEM, ST8_REG_A}, 0xC7}, +{"ld", {ST8_INDX, ST8_REG_A}, 0xF7}, +{"ld", {ST8_SHORTOFF_X, ST8_REG_A}, 0xE7}, +{"ld", {ST8_LONGOFF_X, ST8_REG_A}, 0xD7}, +{"ld", {ST8_INDY, ST8_REG_A}, 0x90F7}, +{"ld", {ST8_SHORTOFF_Y, ST8_REG_A}, 0x90E7}, +{"ld", {ST8_LONGOFF_Y, ST8_REG_A}, 0x90D7}, +{"ld", {ST8_SHORTOFF_SP, ST8_REG_A}, 0x6B}, +{"ld", {ST8_SHORTPTRW, ST8_REG_A}, 0x92C7}, +{"ld", {ST8_LONGPTRW, ST8_REG_A}, 0x72C7}, +{"ld", {ST8_SHORTPTRW_X, ST8_REG_A}, 0x92D7}, +{"ld", {ST8_LONGPTRW_X, ST8_REG_A}, 0x72D7}, +{"ld", {ST8_SHORTPTRW_Y, ST8_REG_A}, 0x91D7}, +{"ld", {ST8_REG_XL, ST8_REG_A}, 0x97}, +{"ld", {ST8_REG_A, ST8_REG_XL}, 0x9F}, +{"ld", {ST8_REG_YL, ST8_REG_A}, 0x9097}, +{"ld", {ST8_REG_A, ST8_REG_YL}, 0x909F}, +{"ld", {ST8_REG_XH, ST8_REG_A}, 0x95}, +{"ld", {ST8_REG_A, ST8_REG_XH}, 0x9E}, +{"ld", {ST8_REG_YH, ST8_REG_A}, 0x9095}, +{"ld", {ST8_REG_A, ST8_REG_YH}, 0x909E}, +//ldf +{"ldf", {ST8_REG_A, ST8_EXTMEM}, 0xBC}, +{"ldf", {ST8_REG_A, ST8_EXTOFF_X}, 0xAF}, +{"ldf", {ST8_REG_A, ST8_EXTOFF_Y}, 0x90AF}, +{"ldf", {ST8_REG_A, ST8_LONGPTRE_X}, 0x92AF}, +{"ldf", {ST8_REG_A, ST8_LONGPTRE_Y}, 0x91AF}, +{"ldf", {ST8_REG_A, ST8_LONGPTRE}, 0x92BC}, +{"ldf", {ST8_EXTMEM, ST8_REG_A}, 0xBD}, +{"ldf", {ST8_EXTOFF_X, ST8_REG_A}, 0xA7}, +{"ldf", {ST8_EXTOFF_Y, ST8_REG_A}, 0x90A7}, +{"ldf", {ST8_LONGPTRE_X, ST8_REG_A}, 0x92A7}, +{"ldf", {ST8_LONGPTRE_Y, ST8_REG_A}, 0x91A7}, +{"ldf", {ST8_LONGPTRE, ST8_REG_A}, 0x92BD}, +//ldw +{"ldw", {ST8_REG_X, ST8_WORD}, 0xAE}, +{"ldw", {ST8_REG_X, ST8_SHORTMEM}, 0xBE}, +{"ldw", {ST8_REG_X, ST8_LONGMEM}, 0xCE}, +{"ldw", {ST8_REG_X, ST8_INDX}, 0xFE}, +{"ldw", {ST8_REG_X, ST8_SHORTOFF_X}, 0xEE}, +{"ldw", {ST8_REG_X, ST8_LONGOFF_X}, 0xDE}, +{"ldw", {ST8_REG_X, ST8_SHORTOFF_SP}, 0x1E}, +{"ldw", {ST8_REG_X, ST8_SHORTPTRW}, 0x92CE}, +{"ldw", {ST8_REG_X, ST8_LONGPTRW}, 0x72CE}, +{"ldw", {ST8_REG_X, ST8_SHORTPTRW_X}, 0x92DE}, +{"ldw", {ST8_REG_X, ST8_LONGPTRW_X}, 0x72DE}, +{"ldw", {ST8_SHORTMEM, ST8_REG_X}, 0xBF}, +{"ldw", {ST8_LONGMEM, ST8_REG_X}, 0xCF}, +{"ldw", {ST8_INDX, ST8_REG_Y}, 0xFF}, +{"ldw", {ST8_SHORTOFF_X, ST8_REG_Y}, 0xEF}, +{"ldw", {ST8_LONGOFF_X, ST8_REG_Y}, 0xDF}, +{"ldw", {ST8_SHORTOFF_SP, ST8_REG_X}, 0x1F}, +{"ldw", {ST8_SHORTPTRW, ST8_REG_X}, 0x92CF}, +{"ldw", {ST8_LONGPTRW, ST8_REG_X}, 0x72CF}, +{"ldw", {ST8_SHORTPTRW_X, ST8_REG_Y}, 0x92DF}, +{"ldw", {ST8_LONGPTRW_X, ST8_REG_Y}, 0x72DF}, +{"ldw", {ST8_REG_Y, ST8_WORD}, 0x90AE}, +{"ldw", {ST8_REG_Y, ST8_SHORTMEM}, 0x90BE}, +{"ldw", {ST8_REG_Y, ST8_LONGMEM}, 0x90CE}, +{"ldw", {ST8_REG_Y, ST8_INDY}, 0x90FE}, +{"ldw", {ST8_REG_Y, ST8_SHORTOFF_Y}, 0x90EE}, +{"ldw", {ST8_REG_Y, ST8_LONGOFF_Y}, 0x90DE}, +{"ldw", {ST8_REG_Y, ST8_SHORTOFF_SP}, 0x16}, +{"ldw", {ST8_REG_Y, ST8_SHORTPTRW}, 0x91CE}, +{"ldw", {ST8_REG_Y, ST8_SHORTPTRW_Y}, 0x91DE}, +{"ldw", {ST8_SHORTMEM, ST8_REG_Y}, 0x90BF}, +{"ldw", {ST8_LONGMEM, ST8_REG_Y}, 0x90CF}, +{"ldw", {ST8_INDY, ST8_REG_X}, 0x90FF}, +{"ldw", {ST8_SHORTOFF_Y, ST8_REG_X}, 0x90EF}, +{"ldw", {ST8_LONGOFF_Y, ST8_REG_X}, 0x90DF}, +{"ldw", {ST8_SHORTOFF_SP, ST8_REG_Y}, 0x17}, +{"ldw", {ST8_SHORTPTRW, ST8_REG_Y}, 0x91CF}, +{"ldw", {ST8_SHORTPTRW_Y, ST8_REG_X}, 0x91DF}, +{"ldw", {ST8_REG_Y, ST8_REG_X}, 0x9093}, +{"ldw", {ST8_REG_X, ST8_REG_Y}, 0x93}, +{"ldw", {ST8_REG_X, ST8_REG_SP}, 0x96}, +{"ldw", {ST8_REG_SP, ST8_REG_X}, 0x94}, +{"ldw", {ST8_REG_Y, ST8_REG_SP}, 0x9096}, +{"ldw", {ST8_REG_SP, ST8_REG_Y}, 0x9094}, +//mov +{"mov", {ST8_LONGMEM, ST8_BYTE}, 0x35}, +{"mov", {ST8_SHORTMEM, ST8_SHORTMEM}, 0x45}, +{"mov", {ST8_LONGMEM, ST8_LONGMEM}, 0x55}, +//mul +{"mul", {ST8_REG_X, ST8_REG_A}, 0x42}, +{"mul", {ST8_REG_Y, ST8_REG_A}, 0x9042}, +//neg +{"neg", {ST8_REG_A}, 0x40}, +{"neg", {ST8_SHORTMEM}, 0x30}, +{"neg", {ST8_LONGMEM}, 0x7250}, +{"neg", {ST8_INDX}, 0x70}, +{"neg", {ST8_SHORTOFF_X}, 0x60}, +{"neg", {ST8_LONGOFF_X}, 0x7240}, +{"neg", {ST8_INDY}, 0x9070}, +{"neg", {ST8_SHORTOFF_Y}, 0x9060}, +{"neg", {ST8_LONGOFF_Y}, 0x9040}, +{"neg", {ST8_SHORTOFF_SP}, 0x00}, +{"neg", {ST8_SHORTPTRW}, 0x9230}, +{"neg", {ST8_LONGPTRW}, 0x7230}, +{"neg", {ST8_SHORTPTRW_X}, 0x9260}, +{"neg", {ST8_LONGPTRW_X}, 0x7260}, +{"neg", {ST8_SHORTPTRW_Y}, 0x9160}, +//negw +{"negw", {ST8_REG_X}, 0x50}, +{"negw", {ST8_REG_Y}, 0x9050}, +//or +{"or", {ST8_REG_A, ST8_BYTE}, 0xAA}, +{"or", {ST8_REG_A, ST8_SHORTMEM}, 0xBA}, +{"or", {ST8_REG_A, ST8_LONGMEM}, 0xCA}, +{"or", {ST8_REG_A, ST8_INDX}, 0xFA}, +{"or", {ST8_REG_A, ST8_SHORTOFF_X}, 0xEA}, +{"or", {ST8_REG_A, ST8_LONGOFF_X}, 0xDA}, +{"or", {ST8_REG_A, ST8_INDY}, 0x90FA}, +{"or", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90EA}, +{"or", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90DA}, +{"or", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x1A}, +{"or", {ST8_REG_A, ST8_SHORTPTRW}, 0x92CA}, +{"or", {ST8_REG_A, ST8_LONGPTRW}, 0x72CA}, +{"or", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92DA}, +{"or", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72DA}, +{"or", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91DA}, +//pop +{"pop", {ST8_REG_A}, 0x84}, +{"pop", {ST8_REG_CC}, 0x86}, +{"pop", {ST8_LONGMEM}, 0x32}, +//popw +{"popw", {ST8_REG_X}, 0x85}, +{"popw", {ST8_REG_Y}, 0x9085}, +//push +{"push", {ST8_REG_A}, 0x88}, +{"push", {ST8_REG_CC}, 0x8A}, +{"push", {ST8_BYTE}, 0x4B}, +{"push", {ST8_LONGMEM}, 0x3B}, +//pushw +{"pushw", {ST8_REG_X}, 0x89}, +{"pushw", {ST8_REG_Y}, 0x9089}, +//rcf +{"rcf", {}, 0x98}, +//ret +{"ret", {}, 0x81}, +//retf +{"retf", {}, 0x87}, +//rim +{"rim", {}, 0x9A}, +//rlc +{"rlc", {ST8_REG_A}, 0x49}, +{"rlc", {ST8_SHORTMEM}, 0x39}, +{"rlc", {ST8_LONGMEM}, 0x7259}, +{"rlc", {ST8_INDX}, 0x79}, +{"rlc", {ST8_SHORTOFF_X}, 0x69}, +{"rlc", {ST8_LONGOFF_X}, 0x7249}, +{"rlc", {ST8_INDY}, 0x9079}, +{"rlc", {ST8_SHORTOFF_Y}, 0x9069}, +{"rlc", {ST8_LONGOFF_Y}, 0x9049}, +{"rlc", {ST8_SHORTOFF_SP}, 0x09}, +{"rlc", {ST8_SHORTPTRW}, 0x9239}, +{"rlc", {ST8_LONGPTRW}, 0x7239}, +{"rlc", {ST8_SHORTPTRW_X}, 0x9269}, +{"rlc", {ST8_LONGPTRW_X}, 0x7269}, +{"rlc", {ST8_SHORTPTRW_Y}, 0x9169}, +//rlcw +{"rlcw", {ST8_REG_X}, 0x59}, +{"rlcw", {ST8_REG_Y}, 0x9059}, +//rlwa +{"rlwa", {ST8_REG_X, ST8_REG_A}, 0x02}, +{"rlwa", {ST8_REG_Y, ST8_REG_A}, 0x9002}, +//rrc +{"rrc", {ST8_REG_A}, 0x46}, +{"rrc", {ST8_SHORTMEM}, 0x36}, +{"rrc", {ST8_LONGMEM}, 0x7256}, +{"rrc", {ST8_INDX}, 0x76}, +{"rrc", {ST8_SHORTOFF_X}, 0x66}, +{"rrc", {ST8_LONGOFF_X}, 0x7246}, +{"rrc", {ST8_INDY}, 0x9076}, +{"rrc", {ST8_SHORTOFF_Y}, 0x9066}, +{"rrc", {ST8_LONGOFF_Y}, 0x9046}, +{"rrc", {ST8_SHORTOFF_SP}, 0x06}, +{"rrc", {ST8_SHORTPTRW}, 0x9236}, +{"rrc", {ST8_LONGPTRW}, 0x7236}, +{"rrc", {ST8_SHORTPTRW_X}, 0x9266}, +{"rrc", {ST8_LONGPTRW_X}, 0x7266}, +{"rrc", {ST8_SHORTPTRW_Y}, 0x9166}, +//rrcw +{"rrcw", {ST8_REG_X}, 0x56}, +{"rrcw", {ST8_REG_Y}, 0x9056}, +//rrwa +{"rrwa", {ST8_REG_X, ST8_REG_A}, 0x01}, +{"rrwa", {ST8_REG_Y, ST8_REG_A}, 0x9001}, +//rvf +{"rvf", {}, 0x9C}, +//sbc +{"sbc", {ST8_REG_A, ST8_BYTE}, 0xA2}, +{"sbc", {ST8_REG_A, ST8_SHORTMEM}, 0xB2}, +{"sbc", {ST8_REG_A, ST8_LONGMEM}, 0xC2}, +{"sbc", {ST8_REG_A, ST8_INDX}, 0xF2}, +{"sbc", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE2}, +{"sbc", {ST8_REG_A, ST8_LONGOFF_X}, 0xD2}, +{"sbc", {ST8_REG_A, ST8_INDY}, 0x90F2}, +{"sbc", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E2}, +{"sbc", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D2}, +{"sbc", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x12}, +{"sbc", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C2}, +{"sbc", {ST8_REG_A, ST8_LONGPTRW}, 0x72C2}, +{"sbc", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D2}, +{"sbc", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D2}, +{"sbc", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D2}, +//scf +{"scf", {}, 0x99}, +//sim +{"sim", {}, 0x9B}, +//sll +{"sll", {ST8_REG_A}, 0x48}, +{"sll", {ST8_SHORTMEM}, 0x38}, +{"sll", {ST8_LONGMEM}, 0x7258}, +{"sll", {ST8_INDX}, 0x78}, +{"sll", {ST8_SHORTOFF_X}, 0x68}, +{"sll", {ST8_LONGOFF_X}, 0x7248}, +{"sll", {ST8_INDY}, 0x9078}, +{"sll", {ST8_SHORTOFF_Y}, 0x9068}, +{"sll", {ST8_LONGOFF_Y}, 0x9048}, +{"sll", {ST8_SHORTOFF_SP}, 0x08}, +{"sll", {ST8_SHORTPTRW}, 0x9238}, +{"sll", {ST8_LONGPTRW}, 0x7238}, +{"sll", {ST8_SHORTPTRW_X}, 0x9268}, +{"sll", {ST8_LONGPTRW_X}, 0x7268}, +{"sll", {ST8_SHORTPTRW_Y}, 0x9168}, +//sllw +{"sllw", {ST8_REG_X}, 0x58}, +{"sllw", {ST8_REG_Y}, 0x9058}, +//sla +{"sla", {ST8_REG_A}, 0x48}, +{"sla", {ST8_SHORTMEM}, 0x38}, +{"sla", {ST8_LONGMEM}, 0x7258}, +{"sla", {ST8_INDX}, 0x78}, +{"sla", {ST8_SHORTOFF_X}, 0x68}, +{"sla", {ST8_LONGOFF_X}, 0x7248}, +{"sla", {ST8_INDY}, 0x9078}, +{"sla", {ST8_SHORTOFF_Y}, 0x9068}, +{"sla", {ST8_LONGOFF_Y}, 0x9048}, +{"sla", {ST8_SHORTOFF_SP}, 0x08}, +{"sla", {ST8_SHORTPTRW}, 0x9238}, +{"sla", {ST8_LONGPTRW}, 0x7238}, +{"sla", {ST8_SHORTPTRW_X}, 0x9268}, +{"sla", {ST8_LONGPTRW_X}, 0x7268}, +{"sla", {ST8_SHORTPTRW_Y}, 0x9168}, +//slaw +{"slaw", {ST8_REG_X}, 0x58}, +{"slaw", {ST8_REG_Y}, 0x9058}, +//sra +{"sra", {ST8_REG_A}, 0x47}, +{"sra", {ST8_SHORTMEM}, 0x37}, +{"sra", {ST8_LONGMEM}, 0x7257}, +{"sra", {ST8_INDX}, 0x77}, +{"sra", {ST8_SHORTOFF_X}, 0x67}, +{"sra", {ST8_LONGOFF_X}, 0x7247}, +{"sra", {ST8_INDY}, 0x9077}, +{"sra", {ST8_SHORTOFF_Y}, 0x9067}, +{"sra", {ST8_LONGOFF_Y}, 0x9047}, +{"sra", {ST8_SHORTOFF_SP}, 0x07}, +{"sra", {ST8_SHORTPTRW}, 0x9237}, +{"sra", {ST8_LONGPTRW}, 0x7237}, +{"sra", {ST8_SHORTPTRW_X}, 0x9267}, +{"sra", {ST8_LONGPTRW_X}, 0x7267}, +{"sra", {ST8_SHORTPTRW_Y}, 0x9167}, +//sraw +{"sraw", {ST8_REG_X}, 0x57}, +{"sraw", {ST8_REG_Y}, 0x9057}, +//srl +{"srl", {ST8_REG_A}, 0x44}, +{"srl", {ST8_SHORTMEM}, 0x34}, +{"srl", {ST8_LONGMEM}, 0x7254}, +{"srl", {ST8_INDX}, 0x74}, +{"srl", {ST8_SHORTOFF_X}, 0x64}, +{"srl", {ST8_LONGOFF_X}, 0x7244}, +{"srl", {ST8_INDY}, 0x9074}, +{"srl", {ST8_SHORTOFF_Y}, 0x9064}, +{"srl", {ST8_LONGOFF_Y}, 0x9044}, +{"srl", {ST8_SHORTOFF_SP}, 0x04}, +{"srl", {ST8_SHORTPTRW}, 0x9234}, +{"srl", {ST8_LONGPTRW}, 0x7234}, +{"srl", {ST8_SHORTPTRW_X}, 0x9264}, +{"srl", {ST8_LONGPTRW_X}, 0x7264}, +{"srl", {ST8_SHORTPTRW_Y}, 0x9164}, +//sraw +{"srlw", {ST8_REG_X}, 0x54}, +{"srlw", {ST8_REG_Y}, 0x9054}, +//sub +{"sub", {ST8_REG_A, ST8_BYTE}, 0xA0}, +{"sub", {ST8_REG_A, ST8_SHORTMEM}, 0xB0}, +{"sub", {ST8_REG_A, ST8_LONGMEM}, 0xC0}, +{"sub", {ST8_REG_A, ST8_INDX}, 0xF0}, +{"sub", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE0}, +{"sub", {ST8_REG_A, ST8_LONGOFF_X}, 0xD0}, +{"sub", {ST8_REG_A, ST8_INDY}, 0x90F0}, +{"sub", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E0}, +{"sub", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D0}, +{"sub", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x10}, +{"sub", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C0}, +{"sub", {ST8_REG_A, ST8_LONGPTRW}, 0x72C0}, +{"sub", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D0}, +{"sub", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D0}, +{"sub", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D0}, +{"sub", {ST8_REG_SP, ST8_BYTE}, 0x52}, +//subw +{"subw", {ST8_REG_X, ST8_WORD}, 0x1D}, +{"subw", {ST8_REG_X, ST8_LONGMEM}, 0x72B0}, +{"subw", {ST8_REG_X, ST8_SHORTOFF_SP}, 0x72F0}, +{"subw", {ST8_REG_Y, ST8_WORD}, 0x72A2}, +{"subw", {ST8_REG_Y, ST8_LONGMEM}, 0x72B2}, +{"subw", {ST8_REG_Y, ST8_SHORTOFF_SP}, 0x72F2}, +//swap +{"swap", {ST8_REG_A}, 0x4E}, +{"swap", {ST8_SHORTMEM}, 0x3E}, +{"swap", {ST8_LONGMEM}, 0x725E}, +{"swap", {ST8_INDX}, 0x7E}, +{"swap", {ST8_SHORTOFF_X}, 0x6E}, +{"swap", {ST8_LONGOFF_X}, 0x724E}, +{"swap", {ST8_INDY}, 0x907E}, +{"swap", {ST8_SHORTOFF_Y}, 0x906E}, +{"swap", {ST8_LONGOFF_Y}, 0x904E}, +{"swap", {ST8_SHORTOFF_SP}, 0x0E}, +{"swap", {ST8_SHORTPTRW}, 0x923E}, +{"swap", {ST8_LONGPTRW}, 0x723E}, +{"swap", {ST8_SHORTPTRW_X}, 0x926E}, +{"swap", {ST8_LONGPTRW_X}, 0x726E}, +{"swap", {ST8_SHORTPTRW_Y}, 0x916E}, +//swapw +{"swapw", {ST8_REG_X}, 0x5E}, +{"swapw", {ST8_REG_Y}, 0x905E}, +//tnz +{"tnz", {ST8_REG_A}, 0x4D}, +{"tnz", {ST8_SHORTMEM}, 0x3D}, +{"tnz", {ST8_LONGMEM}, 0x725D}, +{"tnz", {ST8_INDX}, 0x7D}, +{"tnz", {ST8_SHORTOFF_X}, 0x6D}, +{"tnz", {ST8_LONGOFF_X}, 0x724D}, +{"tnz", {ST8_INDY}, 0x907D}, +{"tnz", {ST8_SHORTOFF_Y}, 0x906D}, +{"tnz", {ST8_LONGOFF_Y}, 0x904D}, +{"tnz", {ST8_SHORTOFF_SP}, 0x0D}, +{"tnz", {ST8_SHORTPTRW}, 0x923D}, +{"tnz", {ST8_LONGPTRW}, 0x723D}, +{"tnz", {ST8_SHORTPTRW_X}, 0x926D}, +{"tnz", {ST8_LONGPTRW_X}, 0x726D}, +{"tnz", {ST8_SHORTPTRW_Y}, 0x916D}, +//tnzw +{"tnzw", {ST8_REG_X}, 0x5D}, +{"tnzw", {ST8_REG_Y}, 0x905D}, +//trap +{"trap", {}, 0x83}, +//wfe +{"wfe", {}, 0x728F}, +//wfi +{"wfi", {}, 0x8F}, +//xor +{"xor", {ST8_REG_A, ST8_BYTE}, 0xA8}, +{"xor", {ST8_REG_A, ST8_SHORTMEM}, 0xB8}, +{"xor", {ST8_REG_A, ST8_LONGMEM}, 0xC8}, +{"xor", {ST8_REG_A, ST8_INDX}, 0xF8}, +{"xor", {ST8_REG_A, ST8_SHORTOFF_X}, 0xE8}, +{"xor", {ST8_REG_A, ST8_LONGOFF_X}, 0xD8}, +{"xor", {ST8_REG_A, ST8_INDY}, 0x90F8}, +{"xor", {ST8_REG_A, ST8_SHORTOFF_Y}, 0x90E8}, +{"xor", {ST8_REG_A, ST8_LONGOFF_Y}, 0x90D8}, +{"xor", {ST8_REG_A, ST8_SHORTOFF_SP}, 0x18}, +{"xor", {ST8_REG_A, ST8_SHORTPTRW}, 0x92C8}, +{"xor", {ST8_REG_A, ST8_LONGPTRW}, 0x72C8}, +{"xor", {ST8_REG_A, ST8_SHORTPTRW_X}, 0x92D8}, +{"xor", {ST8_REG_A, ST8_LONGPTRW_X}, 0x72D8}, +{"xor", {ST8_REG_A, ST8_SHORTPTRW_Y}, 0x91D8}, + {NULL, {ST8_END}, 0}, +}; + +unsigned int stm8_opcode_size(unsigned int number) +{ + int i; + for(i = sizeof(int); i > 0; i--) { + if(number & 0xFF << (i-1)*8) + return(i); + } + return(1); +} + +int stm8_compute_insn_size(struct stm8_opcodes_s opcode) { + int i, ret = 0; + for(i = 0; opcode.constraints[i] != ST8_END; i++) { + switch(opcode.constraints[i]) { + case ST8_PCREL: + case ST8_SHORTMEM: + case ST8_BYTE: + case ST8_SHORTPTRW_Y: + case ST8_SHORTPTRW_X: + case ST8_SHORTPTRW: + case ST8_SHORTOFF_X: + case ST8_SHORTOFF_Y: + case ST8_SHORTOFF_SP: + ret++; + break; + case ST8_LONGPTRE_Y: + case ST8_LONGPTRE_X: + case ST8_LONGPTRW_Y: + case ST8_LONGPTRW_X: + case ST8_LONGPTRE: + case ST8_LONGPTRW: + case ST8_LONGOFF_X: + case ST8_LONGOFF_Y: + case ST8_LONGMEM: + case ST8_WORD: + ret += 2; + break; + case ST8_EXTMEM: + case ST8_EXTOFF_X: + case ST8_EXTOFF_Y: + ret += 3; + break; + case ST8_END: + case ST8_BIT_0: + case ST8_BIT_1: + case ST8_BIT_2: + case ST8_BIT_3: + case ST8_BIT_4: + case ST8_BIT_5: + case ST8_BIT_6: + case ST8_BIT_7: + case ST8_REG_CC: + case ST8_REG_A: + case ST8_REG_X: + case ST8_REG_Y: + case ST8_REG_SP: + case ST8_REG_XL: + case ST8_REG_XH: + case ST8_REG_YL: + case ST8_REG_YH: + case ST8_INDX: + case ST8_INDY: + break; + } + } + ret += stm8_opcode_size(opcode.bin_opcode); + return(ret); +} -- 2.12.2