From 376c1693aa1fd9d25bf5612b9e86c630ac7b5745 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Fri, 11 Oct 2024 21:13:49 +0200 Subject: [PATCH 01/31] qemu/tcg: fix UC_HOOK_MEM_READ on aarch64. Directly jump into the slow path when there is any hookmem enabled. This fixes #1908. Signed-off-by: Glenn Baker --- qemu/tcg/aarch64/tcg-target.inc.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/qemu/tcg/aarch64/tcg-target.inc.c b/qemu/tcg/aarch64/tcg-target.inc.c index c1f6e108b3..00bd066d19 100644 --- a/qemu/tcg/aarch64/tcg-target.inc.c +++ b/qemu/tcg/aarch64/tcg-target.inc.c @@ -1581,13 +1581,20 @@ static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target) tcg_out_insn(s, 3406, ADR, rd, offset); } +static inline bool has_hookmem(TCGContext *s) +{ + return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); +} + static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; MemOp opc = get_memop(oi); MemOp size = opc & MO_SIZE; - if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) { + const int type = has_hookmem(s) ? R_AARCH64_JUMP26 : R_AARCH64_CONDBR19; + if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -1612,7 +1619,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) MemOp opc = get_memop(oi); MemOp size = opc & MO_SIZE; - if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) { + const int type = has_hookmem(s) ? R_AARCH64_JUMP26 : R_AARCH64_CONDBR19; + if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -1711,7 +1719,11 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, /* If not equal, we jump to the slow path. */ *label_ptr = s->code_ptr; - tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); + // Unicorn: fast path if hookmem is not enabled + if (!has_hookmem(s)) + tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); + else + tcg_out_insn(s, 3206, B, 0); } #endif /* CONFIG_SOFTMMU */ From bfe3acb432958b3f54655e05e25469963dea3bae Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Mon, 14 Oct 2024 20:36:48 +0200 Subject: [PATCH 02/31] qemu/tcg: fix UC_HOOK_MEM_READ on ppc64. Directly jump into the slow path when there is any hookmem enabled. Signed-off-by: Glenn Baker --- qemu/tcg/ppc/tcg-target.inc.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/qemu/tcg/ppc/tcg-target.inc.c b/qemu/tcg/ppc/tcg-target.inc.c index 41a1c511c3..ce739f52ee 100644 --- a/qemu/tcg/ppc/tcg-target.inc.c +++ b/qemu/tcg/ppc/tcg-target.inc.c @@ -2008,13 +2008,20 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi, label->label_ptr[0] = lptr; } +static inline bool has_hookmem(TCGContext *s) +{ + return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); +} + static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; MemOp opc = get_memop(oi); TCGReg hi, lo, arg = TCG_REG_R3; - if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) { + const int type = has_hookmem(s) ? R_PPC_REL24 : R_PPC_REL14; + if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -2062,7 +2069,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) MemOp s_bits = opc & MO_SIZE; TCGReg hi, lo, arg = TCG_REG_R3; - if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) { + const int type = has_hookmem(s) ? R_PPC_REL24 : R_PPC_REL14; + if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -2142,7 +2150,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) /* Load a pointer into the current opcode w/conditional branch-link. */ label_ptr = s->code_ptr; - tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); + // Unicorn: fast path if hookmem is not enabled + if (!has_hookmem(s)) + tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); + else + tcg_out32(s, B | LK); rbase = TCG_REG_R3; #else /* !CONFIG_SOFTMMU */ @@ -2217,7 +2229,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) /* Load a pointer into the current opcode w/conditional branch-link. */ label_ptr = s->code_ptr; - tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); + // Unicorn: fast path if hookmem is not enabled + if (!has_hookmem(s)) + tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); + else + tcg_out32(s, B | LK); rbase = TCG_REG_R3; #else /* !CONFIG_SOFTMMU */ From d84208e829b33296d578479d81cf6ab891e1bf6b Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 22 Oct 2024 15:46:50 +0200 Subject: [PATCH 03/31] qemu/tcg: check for UC_HOOK_MEM_READ_AFTER. Use has_hookmem() helper to determine wether "slow-path" TLB read is needed. Add this helper to x86 architecture as well so that to check for all hookmem. Signed-off-by: Glenn Baker --- qemu/tcg/aarch64/tcg-target.inc.c | 1 + qemu/tcg/i386/tcg-target.inc.c | 9 ++++++++- qemu/tcg/ppc/tcg-target.inc.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/qemu/tcg/aarch64/tcg-target.inc.c b/qemu/tcg/aarch64/tcg-target.inc.c index 00bd066d19..dfc11c96c8 100644 --- a/qemu/tcg/aarch64/tcg-target.inc.c +++ b/qemu/tcg/aarch64/tcg-target.inc.c @@ -1584,6 +1584,7 @@ static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target) static inline bool has_hookmem(TCGContext *s) { return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); } diff --git a/qemu/tcg/i386/tcg-target.inc.c b/qemu/tcg/i386/tcg-target.inc.c index fc5cdbba44..8e51ddebbb 100644 --- a/qemu/tcg/i386/tcg-target.inc.c +++ b/qemu/tcg/i386/tcg-target.inc.c @@ -1679,6 +1679,13 @@ static void * const qemu_st_helpers[16] = { [MO_BEQ] = helper_be_stq_mmu, }; +static inline bool has_hookmem(TCGContext *s) +{ + return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); +} + /* Perform the TLB load and compare. Inputs: @@ -1763,7 +1770,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, tcg_out_mov(s, ttype, r1, addrlo); // Unicorn: fast path if hookmem is not enable - if (!HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) && !HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE)) + if (!has_hookmem(s)) tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0); else /* slow_path, so data access will go via load_helper() */ diff --git a/qemu/tcg/ppc/tcg-target.inc.c b/qemu/tcg/ppc/tcg-target.inc.c index ce739f52ee..ba5ef05e28 100644 --- a/qemu/tcg/ppc/tcg-target.inc.c +++ b/qemu/tcg/ppc/tcg-target.inc.c @@ -2011,6 +2011,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi, static inline bool has_hookmem(TCGContext *s) { return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); } From 7a5711ce1d6ce3f17fa756b6e3cbecdd8a52e156 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 22 Oct 2024 16:33:23 +0200 Subject: [PATCH 04/31] qemu/tcg: factor out has_hookmem(). It's the same implementation for all architectures, so factor out has_hookmem() into tcg_uc_has_hookmem(). Signed-off-by: Glenn Baker --- qemu/include/tcg/tcg.h | 7 +++++++ qemu/tcg/aarch64/tcg-target.inc.c | 13 +++---------- qemu/tcg/i386/tcg-target.inc.c | 9 +-------- qemu/tcg/ppc/tcg-target.inc.c | 15 ++++----------- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/qemu/include/tcg/tcg.h b/qemu/include/tcg/tcg.h index 9908acaa57..e5afa98881 100644 --- a/qemu/include/tcg/tcg.h +++ b/qemu/include/tcg/tcg.h @@ -1577,4 +1577,11 @@ struct jit_code_entry { void uc_del_inline_hook(uc_engine *uc, struct hook *hk); void uc_add_inline_hook(uc_engine *uc, struct hook *hk, void** args, int args_len); +static inline bool tcg_uc_has_hookmem(TCGContext *s) +{ + return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || + HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); +} + #endif /* TCG_H */ diff --git a/qemu/tcg/aarch64/tcg-target.inc.c b/qemu/tcg/aarch64/tcg-target.inc.c index dfc11c96c8..3c2a148a05 100644 --- a/qemu/tcg/aarch64/tcg-target.inc.c +++ b/qemu/tcg/aarch64/tcg-target.inc.c @@ -1581,20 +1581,13 @@ static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target) tcg_out_insn(s, 3406, ADR, rd, offset); } -static inline bool has_hookmem(TCGContext *s) -{ - return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || - HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || - HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); -} - static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; MemOp opc = get_memop(oi); MemOp size = opc & MO_SIZE; - const int type = has_hookmem(s) ? R_AARCH64_JUMP26 : R_AARCH64_CONDBR19; + const int type = tcg_uc_has_hookmem(s) ? R_AARCH64_JUMP26 : R_AARCH64_CONDBR19; if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -1620,7 +1613,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) MemOp opc = get_memop(oi); MemOp size = opc & MO_SIZE; - const int type = has_hookmem(s) ? R_AARCH64_JUMP26 : R_AARCH64_CONDBR19; + const int type = tcg_uc_has_hookmem(s) ? R_AARCH64_JUMP26 : R_AARCH64_CONDBR19; if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -1721,7 +1714,7 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, /* If not equal, we jump to the slow path. */ *label_ptr = s->code_ptr; // Unicorn: fast path if hookmem is not enabled - if (!has_hookmem(s)) + if (!tcg_uc_has_hookmem(s)) tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); else tcg_out_insn(s, 3206, B, 0); diff --git a/qemu/tcg/i386/tcg-target.inc.c b/qemu/tcg/i386/tcg-target.inc.c index 8e51ddebbb..15cc1c05d9 100644 --- a/qemu/tcg/i386/tcg-target.inc.c +++ b/qemu/tcg/i386/tcg-target.inc.c @@ -1679,13 +1679,6 @@ static void * const qemu_st_helpers[16] = { [MO_BEQ] = helper_be_stq_mmu, }; -static inline bool has_hookmem(TCGContext *s) -{ - return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || - HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || - HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); -} - /* Perform the TLB load and compare. Inputs: @@ -1770,7 +1763,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, tcg_out_mov(s, ttype, r1, addrlo); // Unicorn: fast path if hookmem is not enable - if (!has_hookmem(s)) + if (!tcg_uc_has_hookmem(s)) tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0); else /* slow_path, so data access will go via load_helper() */ diff --git a/qemu/tcg/ppc/tcg-target.inc.c b/qemu/tcg/ppc/tcg-target.inc.c index ba5ef05e28..00b7942901 100644 --- a/qemu/tcg/ppc/tcg-target.inc.c +++ b/qemu/tcg/ppc/tcg-target.inc.c @@ -2008,20 +2008,13 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi, label->label_ptr[0] = lptr; } -static inline bool has_hookmem(TCGContext *s) -{ - return HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) || - HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ_AFTER) || - HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE); -} - static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; MemOp opc = get_memop(oi); TCGReg hi, lo, arg = TCG_REG_R3; - const int type = has_hookmem(s) ? R_PPC_REL24 : R_PPC_REL14; + const int type = tcg_uc_has_hookmem(s) ? R_PPC_REL24 : R_PPC_REL14; if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -2070,7 +2063,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) MemOp s_bits = opc & MO_SIZE; TCGReg hi, lo, arg = TCG_REG_R3; - const int type = has_hookmem(s) ? R_PPC_REL24 : R_PPC_REL14; + const int type = tcg_uc_has_hookmem(s) ? R_PPC_REL24 : R_PPC_REL14; if (!patch_reloc(lb->label_ptr[0], type, (intptr_t)s->code_ptr, 0)) { return false; } @@ -2152,7 +2145,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) /* Load a pointer into the current opcode w/conditional branch-link. */ label_ptr = s->code_ptr; // Unicorn: fast path if hookmem is not enabled - if (!has_hookmem(s)) + if (!tcg_uc_has_hookmem(s)) tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); else tcg_out32(s, B | LK); @@ -2231,7 +2224,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) /* Load a pointer into the current opcode w/conditional branch-link. */ label_ptr = s->code_ptr; // Unicorn: fast path if hookmem is not enabled - if (!has_hookmem(s)) + if (!tcg_uc_has_hookmem(s)) tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK); else tcg_out32(s, B | LK); From 0f1251b88ea6e54b1a0afa9c8e03a74c32733a06 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 27 Mar 2024 10:50:02 +0100 Subject: [PATCH 05/31] Import AVR target from QEMU v5.2.0. Signed-off-by: Glenn Baker --- qemu/target/avr/cpu-param.h | 36 + qemu/target/avr/cpu-qom.h | 49 + qemu/target/avr/cpu.c | 366 +++++ qemu/target/avr/cpu.h | 256 +++ qemu/target/avr/disas.c | 245 +++ qemu/target/avr/gdbstub.c | 84 + qemu/target/avr/helper.c | 348 ++++ qemu/target/avr/helper.h | 29 + qemu/target/avr/insn.decode | 187 +++ qemu/target/avr/machine.c | 119 ++ qemu/target/avr/translate.c | 3061 +++++++++++++++++++++++++++++++++++ 11 files changed, 4780 insertions(+) create mode 100644 qemu/target/avr/cpu-param.h create mode 100644 qemu/target/avr/cpu-qom.h create mode 100644 qemu/target/avr/cpu.c create mode 100644 qemu/target/avr/cpu.h create mode 100644 qemu/target/avr/disas.c create mode 100644 qemu/target/avr/gdbstub.c create mode 100644 qemu/target/avr/helper.c create mode 100644 qemu/target/avr/helper.h create mode 100644 qemu/target/avr/insn.decode create mode 100644 qemu/target/avr/machine.c create mode 100644 qemu/target/avr/translate.c diff --git a/qemu/target/avr/cpu-param.h b/qemu/target/avr/cpu-param.h new file mode 100644 index 0000000000..7ef4e7c679 --- /dev/null +++ b/qemu/target/avr/cpu-param.h @@ -0,0 +1,36 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef AVR_CPU_PARAM_H +#define AVR_CPU_PARAM_H + +#define TARGET_LONG_BITS 32 +/* + * TARGET_PAGE_BITS cannot be more than 8 bits because + * 1. all IO registers occupy [0x0000 .. 0x00ff] address range, and they + * should be implemented as a device and not memory + * 2. SRAM starts at the address 0x0100 + */ +#define TARGET_PAGE_BITS 8 +#define TARGET_PHYS_ADDR_SPACE_BITS 24 +#define TARGET_VIRT_ADDR_SPACE_BITS 24 +#define NB_MMU_MODES 2 + +#endif diff --git a/qemu/target/avr/cpu-qom.h b/qemu/target/avr/cpu-qom.h new file mode 100644 index 0000000000..9fa6989c18 --- /dev/null +++ b/qemu/target/avr/cpu-qom.h @@ -0,0 +1,49 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef QEMU_AVR_QOM_H +#define QEMU_AVR_QOM_H + +#include "hw/core/cpu.h" +#include "qom/object.h" + +#define TYPE_AVR_CPU "avr-cpu" + +OBJECT_DECLARE_TYPE(AVRCPU, AVRCPUClass, + AVR_CPU) + +/** + * AVRCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * @vr: Version Register value. + * + * A AVR CPU model. + */ +struct AVRCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; + DeviceReset parent_reset; +}; + + +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c new file mode 100644 index 0000000000..5d9c4ad5bf --- /dev/null +++ b/qemu/target/avr/cpu.c @@ -0,0 +1,366 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/qemu-print.h" +#include "exec/exec-all.h" +#include "cpu.h" +#include "disas/dis-asm.h" + +static void avr_cpu_set_pc(CPUState *cs, vaddr value) +{ + AVRCPU *cpu = AVR_CPU(cs); + + cpu->env.pc_w = value / 2; /* internally PC points to words */ +} + +static bool avr_cpu_has_work(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + return (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_RESET)) + && cpu_interrupts_enabled(env); +} + +static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + env->pc_w = tb->pc / 2; /* internally PC points to words */ +} + +static void avr_cpu_reset(DeviceState *ds) +{ + CPUState *cs = CPU(ds); + AVRCPU *cpu = AVR_CPU(cs); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); + CPUAVRState *env = &cpu->env; + + mcc->parent_reset(ds); + + env->pc_w = 0; + env->sregI = 1; + env->sregC = 0; + env->sregZ = 0; + env->sregN = 0; + env->sregV = 0; + env->sregS = 0; + env->sregH = 0; + env->sregT = 0; + + env->rampD = 0; + env->rampX = 0; + env->rampY = 0; + env->rampZ = 0; + env->eind = 0; + env->sp = 0; + + env->skip = 0; + + memset(env->r, 0, sizeof(env->r)); +} + +static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_arch_avr; + info->print_insn = avr_print_insn; +} + +static void avr_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + qemu_init_vcpu(cs); + cpu_reset(cs); + + mcc->parent_realize(dev, errp); +} + +static void avr_cpu_set_int(void *opaque, int irq, int level) +{ + AVRCPU *cpu = opaque; + CPUAVRState *env = &cpu->env; + CPUState *cs = CPU(cpu); + uint64_t mask = (1ull << irq); + + if (level) { + env->intsrc |= mask; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + env->intsrc &= ~mask; + if (env->intsrc == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + } +} + +static void avr_cpu_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + + cpu_set_cpustate_pointers(cpu); + + /* Set the number of interrupts supported by the CPU. */ + qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, + sizeof(cpu->env.intsrc) * 8); +} + +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + oc = object_class_by_name(cpu_model); + if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL || + object_class_is_abstract(oc)) { + oc = NULL; + } + return oc; +} + +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + int i; + + qemu_fprintf(f, "\n"); + qemu_fprintf(f, "PC: %06x\n", env->pc_w * 2); /* PC points to words */ + qemu_fprintf(f, "SP: %04x\n", env->sp); + qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); + qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); + qemu_fprintf(f, "rampY: %02x\n", env->rampY >> 16); + qemu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16); + qemu_fprintf(f, "EIND: %02x\n", env->eind >> 16); + qemu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]); + qemu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]); + qemu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]); + qemu_fprintf(f, "SREG: [ %c %c %c %c %c %c %c %c ]\n", + env->sregI ? 'I' : '-', + env->sregT ? 'T' : '-', + env->sregH ? 'H' : '-', + env->sregS ? 'S' : '-', + env->sregV ? 'V' : '-', + env->sregN ? '-' : 'N', /* Zf has negative logic */ + env->sregZ ? 'Z' : '-', + env->sregC ? 'I' : '-'); + qemu_fprintf(f, "SKIP: %02x\n", env->skip); + + qemu_fprintf(f, "\n"); + for (i = 0; i < ARRAY_SIZE(env->r); i++) { + qemu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); + + if ((i % 8) == 7) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "\n"); +} + +static void avr_cpu_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + AVRCPUClass *mcc = AVR_CPU_CLASS(oc); + + mcc->parent_realize = dc->realize; + dc->realize = avr_cpu_realizefn; + + device_class_set_parent_reset(dc, avr_cpu_reset, &mcc->parent_reset); + + cc->class_by_name = avr_cpu_class_by_name; + + cc->has_work = avr_cpu_has_work; + cc->do_interrupt = avr_cpu_do_interrupt; + cc->cpu_exec_interrupt = avr_cpu_exec_interrupt; + cc->dump_state = avr_cpu_dump_state; + cc->set_pc = avr_cpu_set_pc; + cc->memory_rw_debug = avr_cpu_memory_rw_debug; + cc->get_phys_page_debug = avr_cpu_get_phys_page_debug; + cc->tlb_fill = avr_cpu_tlb_fill; + cc->vmsd = &vms_avr_cpu; + cc->disas_set_info = avr_cpu_disas_set_info; + cc->tcg_initialize = avr_cpu_tcg_init; + cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; + cc->gdb_read_register = avr_cpu_gdb_read_register; + cc->gdb_write_register = avr_cpu_gdb_write_register; + cc->gdb_num_core_regs = 35; + cc->gdb_core_xml_file = "avr-cpu.xml"; +} + +/* + * Setting features of AVR core type avr5 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * ata5702m322, ata5782, ata5790, ata5790n, ata5791, ata5795, ata5831, ata6613c, + * ata6614q, ata8210, ata8510, atmega16, atmega16a, atmega161, atmega162, + * atmega163, atmega164a, atmega164p, atmega164pa, atmega165, atmega165a, + * atmega165p, atmega165pa, atmega168, atmega168a, atmega168p, atmega168pa, + * atmega168pb, atmega169, atmega169a, atmega169p, atmega169pa, atmega16hvb, + * atmega16hvbrevb, atmega16m1, atmega16u4, atmega32a, atmega32, atmega323, + * atmega324a, atmega324p, atmega324pa, atmega325, atmega325a, atmega325p, + * atmega325pa, atmega3250, atmega3250a, atmega3250p, atmega3250pa, atmega328, + * atmega328p, atmega328pb, atmega329, atmega329a, atmega329p, atmega329pa, + * atmega3290, atmega3290a, atmega3290p, atmega3290pa, atmega32c1, atmega32m1, + * atmega32u4, atmega32u6, atmega406, atmega64, atmega64a, atmega640, atmega644, + * atmega644a, atmega644p, atmega644pa, atmega645, atmega645a, atmega645p, + * atmega6450, atmega6450a, atmega6450p, atmega649, atmega649a, atmega649p, + * atmega6490, atmega16hva, atmega16hva2, atmega32hvb, atmega6490a, atmega6490p, + * atmega64c1, atmega64m1, atmega64hve, atmega64hve2, atmega64rfr2, + * atmega644rfr2, atmega32hvbrevb, at90can32, at90can64, at90pwm161, at90pwm216, + * at90pwm316, at90scr100, at90usb646, at90usb647, at94k, m3000 + */ +static void avr_avr5_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +/* + * Setting features of AVR core type avr51 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * atmega128, atmega128a, atmega1280, atmega1281, atmega1284, atmega1284p, + * atmega128rfa1, atmega128rfr2, atmega1284rfr2, at90can128, at90usb1286, + * at90usb1287 + */ +static void avr_avr51_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_RAMPZ); + set_avr_feature(env, AVR_FEATURE_ELPMX); + set_avr_feature(env, AVR_FEATURE_ELPM); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +/* + * Setting features of AVR core type avr6 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * atmega2560, atmega2561, atmega256rfr2, atmega2564rfr2 + */ +static void avr_avr6_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_3_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_RAMPZ); + set_avr_feature(env, AVR_FEATURE_EIJMP_EICALL); + set_avr_feature(env, AVR_FEATURE_ELPMX); + set_avr_feature(env, AVR_FEATURE_ELPM); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +typedef struct AVRCPUInfo { + const char *name; + void (*initfn)(Object *obj); +} AVRCPUInfo; + + +static void avr_cpu_list_entry(gpointer data, gpointer user_data) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(data)); + + qemu_printf("%s\n", typename); +} + +void avr_cpu_list(void) +{ + GSList *list; + list = object_class_get_list_sorted(TYPE_AVR_CPU, false); + g_slist_foreach(list, avr_cpu_list_entry, NULL); + g_slist_free(list); +} + +#define DEFINE_AVR_CPU_TYPE(model, initfn) \ + { \ + .parent = TYPE_AVR_CPU, \ + .instance_init = initfn, \ + .name = AVR_CPU_TYPE_NAME(model), \ + } + +static const TypeInfo avr_cpu_type_info[] = { + { + .name = TYPE_AVR_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(AVRCPU), + .instance_init = avr_cpu_initfn, + .class_size = sizeof(AVRCPUClass), + .class_init = avr_cpu_class_init, + .abstract = true, + }, + DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn), + DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn), + DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn), +}; + +DEFINE_TYPES(avr_cpu_type_info) diff --git a/qemu/target/avr/cpu.h b/qemu/target/avr/cpu.h new file mode 100644 index 0000000000..d148e8c75a --- /dev/null +++ b/qemu/target/avr/cpu.h @@ -0,0 +1,256 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef QEMU_AVR_CPU_H +#define QEMU_AVR_CPU_H + +#include "cpu-qom.h" +#include "exec/cpu-defs.h" + +#ifdef CONFIG_USER_ONLY +#error "AVR 8-bit does not support user mode" +#endif + +#define AVR_CPU_TYPE_SUFFIX "-" TYPE_AVR_CPU +#define AVR_CPU_TYPE_NAME(name) (name AVR_CPU_TYPE_SUFFIX) +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU + +#define TCG_GUEST_DEFAULT_MO 0 + +/* + * AVR has two memory spaces, data & code. + * e.g. both have 0 address + * ST/LD instructions access data space + * LPM/SPM and instruction fetching access code memory space + */ +#define MMU_CODE_IDX 0 +#define MMU_DATA_IDX 1 + +#define EXCP_RESET 1 +#define EXCP_INT(n) (EXCP_RESET + (n) + 1) + +/* Number of CPU registers */ +#define NUMBER_OF_CPU_REGISTERS 32 +/* Number of IO registers accessible by ld/st/in/out */ +#define NUMBER_OF_IO_REGISTERS 64 + +/* + * Offsets of AVR memory regions in host memory space. + * + * This is needed because the AVR has separate code and data address + * spaces that both have start from zero but have to go somewhere in + * host memory. + * + * It's also useful to know where some things are, like the IO registers. + */ +/* Flash program memory */ +#define OFFSET_CODE 0x00000000 +/* CPU registers, IO registers, and SRAM */ +#define OFFSET_DATA 0x00800000 +/* CPU registers specifically, these are mapped at the start of data */ +#define OFFSET_CPU_REGISTERS OFFSET_DATA +/* + * IO registers, including status register, stack pointer, and memory + * mapped peripherals, mapped just after CPU registers + */ +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NUMBER_OF_CPU_REGISTERS) + +typedef enum AVRFeature { + AVR_FEATURE_SRAM, + + AVR_FEATURE_1_BYTE_PC, + AVR_FEATURE_2_BYTE_PC, + AVR_FEATURE_3_BYTE_PC, + + AVR_FEATURE_1_BYTE_SP, + AVR_FEATURE_2_BYTE_SP, + + AVR_FEATURE_BREAK, + AVR_FEATURE_DES, + AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */ + + AVR_FEATURE_EIJMP_EICALL, + AVR_FEATURE_IJMP_ICALL, + AVR_FEATURE_JMP_CALL, + + AVR_FEATURE_ADIW_SBIW, + + AVR_FEATURE_SPM, + AVR_FEATURE_SPMX, + + AVR_FEATURE_ELPMX, + AVR_FEATURE_ELPM, + AVR_FEATURE_LPMX, + AVR_FEATURE_LPM, + + AVR_FEATURE_MOVW, + AVR_FEATURE_MUL, + AVR_FEATURE_RAMPD, + AVR_FEATURE_RAMPX, + AVR_FEATURE_RAMPY, + AVR_FEATURE_RAMPZ, +} AVRFeature; + +typedef struct CPUAVRState CPUAVRState; + +struct CPUAVRState { + uint32_t pc_w; /* 0x003fffff up to 22 bits */ + + uint32_t sregC; /* 0x00000001 1 bit */ + uint32_t sregZ; /* 0x00000001 1 bit */ + uint32_t sregN; /* 0x00000001 1 bit */ + uint32_t sregV; /* 0x00000001 1 bit */ + uint32_t sregS; /* 0x00000001 1 bit */ + uint32_t sregH; /* 0x00000001 1 bit */ + uint32_t sregT; /* 0x00000001 1 bit */ + uint32_t sregI; /* 0x00000001 1 bit */ + + uint32_t rampD; /* 0x00ff0000 8 bits */ + uint32_t rampX; /* 0x00ff0000 8 bits */ + uint32_t rampY; /* 0x00ff0000 8 bits */ + uint32_t rampZ; /* 0x00ff0000 8 bits */ + uint32_t eind; /* 0x00ff0000 8 bits */ + + uint32_t r[NUMBER_OF_CPU_REGISTERS]; /* 8 bits each */ + uint32_t sp; /* 16 bits */ + + uint32_t skip; /* if set skip instruction */ + + uint64_t intsrc; /* interrupt sources */ + bool fullacc; /* CPU/MEM if true MEM only otherwise */ + + uint64_t features; +}; + +/** + * AVRCPU: + * @env: #CPUAVRState + * + * A AVR CPU. + */ +typedef struct AVRCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPUAVRState env; +} AVRCPU; + +extern const struct VMStateDescription vms_avr_cpu; + +void avr_cpu_do_interrupt(CPUState *cpu); +bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); +hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); +int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +int avr_print_insn(bfd_vma addr, disassemble_info *info); + +static inline int avr_feature(CPUAVRState *env, AVRFeature feature) +{ + return (env->features & (1U << feature)) != 0; +} + +static inline void set_avr_feature(CPUAVRState *env, int feature) +{ + env->features |= (1U << feature); +} + +#define cpu_list avr_cpu_list +#define cpu_signal_handler cpu_avr_signal_handler +#define cpu_mmu_index avr_cpu_mmu_index + +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) +{ + return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; +} + +void avr_cpu_tcg_init(void); + +void avr_cpu_list(void); +int cpu_avr_exec(CPUState *cpu); +int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc); +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, + int len, bool is_write); + +enum { + TB_FLAGS_FULL_ACCESS = 1, + TB_FLAGS_SKIP = 2, +}; + +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + + *pc = env->pc_w * 2; + *cs_base = 0; + + if (env->fullacc) { + flags |= TB_FLAGS_FULL_ACCESS; + } + if (env->skip) { + flags |= TB_FLAGS_SKIP; + } + + *pflags = flags; +} + +static inline int cpu_interrupts_enabled(CPUAVRState *env) +{ + return env->sregI != 0; +} + +static inline uint8_t cpu_get_sreg(CPUAVRState *env) +{ + uint8_t sreg; + sreg = (env->sregC) << 0 + | (env->sregZ) << 1 + | (env->sregN) << 2 + | (env->sregV) << 3 + | (env->sregS) << 4 + | (env->sregH) << 5 + | (env->sregT) << 6 + | (env->sregI) << 7; + return sreg; +} + +static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg) +{ + env->sregC = (sreg >> 0) & 0x01; + env->sregZ = (sreg >> 1) & 0x01; + env->sregN = (sreg >> 2) & 0x01; + env->sregV = (sreg >> 3) & 0x01; + env->sregS = (sreg >> 4) & 0x01; + env->sregH = (sreg >> 5) & 0x01; + env->sregT = (sreg >> 6) & 0x01; + env->sregI = (sreg >> 7) & 0x01; +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +typedef CPUAVRState CPUArchState; +typedef AVRCPU ArchCPU; + +#include "exec/cpu-all.h" + +#endif /* !defined (QEMU_AVR_CPU_H) */ diff --git a/qemu/target/avr/disas.c b/qemu/target/avr/disas.c new file mode 100644 index 0000000000..b7689e8d7c --- /dev/null +++ b/qemu/target/avr/disas.c @@ -0,0 +1,245 @@ +/* + * AVR disassembler + * + * Copyright (c) 2019-2020 Richard Henderson + * Copyright (c) 2019-2020 Michael Rolnik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" + +typedef struct { + disassemble_info *info; + uint16_t next_word; + bool next_word_used; +} DisasContext; + +static int to_regs_16_31_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 16); +} + +static int to_regs_16_23_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 8); +} + +static int to_regs_24_30_by_two(DisasContext *ctx, int indx) +{ + return 24 + (indx % 4) * 2; +} + +static int to_regs_00_30_by_two(DisasContext *ctx, int indx) +{ + return (indx % 16) * 2; +} + +static uint16_t next_word(DisasContext *ctx) +{ + ctx->next_word_used = true; + return ctx->next_word; +} + +static int append_16(DisasContext *ctx, int x) +{ + return x << 16 | next_word(ctx); +} + +/* Include the auto-generated decoder. */ +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode-insn.c.inc" + +#define output(mnemonic, format, ...) \ + (pctx->info->fprintf_func(pctx->info->stream, "%-9s " format, \ + mnemonic, ##__VA_ARGS__)) + +int avr_print_insn(bfd_vma addr, disassemble_info *info) +{ + DisasContext ctx; + DisasContext *pctx = &ctx; + bfd_byte buffer[4]; + uint16_t insn; + int status; + + ctx.info = info; + + status = info->read_memory_func(addr, buffer, 4, info); + if (status != 0) { + info->memory_error_func(status, addr, info); + return -1; + } + insn = bfd_getl16(buffer); + ctx.next_word = bfd_getl16(buffer + 2); + ctx.next_word_used = false; + + if (!decode_insn(&ctx, insn)) { + output(".db", "0x%02x, 0x%02x", buffer[0], buffer[1]); + } + + return ctx.next_word_used ? 4 : 2; +} + + +#define INSN(opcode, format, ...) \ +static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ +{ \ + output(#opcode, format, ##__VA_ARGS__); \ + return true; \ +} + +#define INSN_MNEMONIC(opcode, mnemonic, format, ...) \ +static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ +{ \ + output(mnemonic, format, ##__VA_ARGS__); \ + return true; \ +} + +/* + * C Z N V S H T I + * 0 1 2 3 4 5 6 7 + */ +static const char brbc[][5] = { + "BRCC", "BRNE", "BRPL", "BRVC", "BRGE", "BRHC", "BRTC", "BRID" +}; + +static const char brbs[][5] = { + "BRCS", "BREQ", "BRMI", "BRVS", "BRLT", "BRHS", "BRTS", "BRIE" +}; + +static const char bset[][4] = { + "SEC", "SEZ", "SEN", "SEZ", "SES", "SEH", "SET", "SEI" +}; + +static const char bclr[][4] = { + "CLC", "CLZ", "CLN", "CLZ", "CLS", "CLH", "CLT", "CLI" +}; + +/* + * Arithmetic Instructions + */ +INSN(ADD, "r%d, r%d", a->rd, a->rr) +INSN(ADC, "r%d, r%d", a->rd, a->rr) +INSN(ADIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) +INSN(SUB, "r%d, r%d", a->rd, a->rr) +INSN(SUBI, "r%d, %d", a->rd, a->imm) +INSN(SBC, "r%d, r%d", a->rd, a->rr) +INSN(SBCI, "r%d, %d", a->rd, a->imm) +INSN(SBIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) +INSN(AND, "r%d, r%d", a->rd, a->rr) +INSN(ANDI, "r%d, %d", a->rd, a->imm) +INSN(OR, "r%d, r%d", a->rd, a->rr) +INSN(ORI, "r%d, %d", a->rd, a->imm) +INSN(EOR, "r%d, r%d", a->rd, a->rr) +INSN(COM, "r%d", a->rd) +INSN(NEG, "r%d", a->rd) +INSN(INC, "r%d", a->rd) +INSN(DEC, "r%d", a->rd) +INSN(MUL, "r%d, r%d", a->rd, a->rr) +INSN(MULS, "r%d, r%d", a->rd, a->rr) +INSN(MULSU, "r%d, r%d", a->rd, a->rr) +INSN(FMUL, "r%d, r%d", a->rd, a->rr) +INSN(FMULS, "r%d, r%d", a->rd, a->rr) +INSN(FMULSU, "r%d, r%d", a->rd, a->rr) +INSN(DES, "%d", a->imm) + +/* + * Branch Instructions + */ +INSN(RJMP, ".%+d", a->imm * 2) +INSN(IJMP, "") +INSN(EIJMP, "") +INSN(JMP, "0x%x", a->imm * 2) +INSN(RCALL, ".%+d", a->imm * 2) +INSN(ICALL, "") +INSN(EICALL, "") +INSN(CALL, "0x%x", a->imm * 2) +INSN(RET, "") +INSN(RETI, "") +INSN(CPSE, "r%d, r%d", a->rd, a->rr) +INSN(CP, "r%d, r%d", a->rd, a->rr) +INSN(CPC, "r%d, r%d", a->rd, a->rr) +INSN(CPI, "r%d, %d", a->rd, a->imm) +INSN(SBRC, "r%d, %d", a->rr, a->bit) +INSN(SBRS, "r%d, %d", a->rr, a->bit) +INSN(SBIC, "$%d, %d", a->reg, a->bit) +INSN(SBIS, "$%d, %d", a->reg, a->bit) +INSN_MNEMONIC(BRBS, brbs[a->bit], ".%+d", a->imm * 2) +INSN_MNEMONIC(BRBC, brbc[a->bit], ".%+d", a->imm * 2) + +/* + * Data Transfer Instructions + */ +INSN(MOV, "r%d, r%d", a->rd, a->rr) +INSN(MOVW, "r%d:r%d, r%d:r%d", a->rd + 1, a->rd, a->rr + 1, a->rr) +INSN(LDI, "r%d, %d", a->rd, a->imm) +INSN(LDS, "r%d, %d", a->rd, a->imm) +INSN(LDX1, "r%d, X", a->rd) +INSN(LDX2, "r%d, X+", a->rd) +INSN(LDX3, "r%d, -X", a->rd) +INSN(LDY2, "r%d, Y+", a->rd) +INSN(LDY3, "r%d, -Y", a->rd) +INSN(LDZ2, "r%d, Z+", a->rd) +INSN(LDZ3, "r%d, -Z", a->rd) +INSN(LDDY, "r%d, Y+%d", a->rd, a->imm) +INSN(LDDZ, "r%d, Z+%d", a->rd, a->imm) +INSN(STS, "%d, r%d", a->imm, a->rd) +INSN(STX1, "X, r%d", a->rr) +INSN(STX2, "X+, r%d", a->rr) +INSN(STX3, "-X, r%d", a->rr) +INSN(STY2, "Y+, r%d", a->rd) +INSN(STY3, "-Y, r%d", a->rd) +INSN(STZ2, "Z+, r%d", a->rd) +INSN(STZ3, "-Z, r%d", a->rd) +INSN(STDY, "Y+%d, r%d", a->imm, a->rd) +INSN(STDZ, "Z+%d, r%d", a->imm, a->rd) +INSN(LPM1, "") +INSN(LPM2, "r%d, Z", a->rd) +INSN(LPMX, "r%d, Z+", a->rd) +INSN(ELPM1, "") +INSN(ELPM2, "r%d, Z", a->rd) +INSN(ELPMX, "r%d, Z+", a->rd) +INSN(SPM, "") +INSN(SPMX, "Z+") +INSN(IN, "r%d, $%d", a->rd, a->imm) +INSN(OUT, "$%d, r%d", a->imm, a->rd) +INSN(PUSH, "r%d", a->rd) +INSN(POP, "r%d", a->rd) +INSN(XCH, "Z, r%d", a->rd) +INSN(LAC, "Z, r%d", a->rd) +INSN(LAS, "Z, r%d", a->rd) +INSN(LAT, "Z, r%d", a->rd) + +/* + * Bit and Bit-test Instructions + */ +INSN(LSR, "r%d", a->rd) +INSN(ROR, "r%d", a->rd) +INSN(ASR, "r%d", a->rd) +INSN(SWAP, "r%d", a->rd) +INSN(SBI, "$%d, %d", a->reg, a->bit) +INSN(CBI, "%d, %d", a->reg, a->bit) +INSN(BST, "r%d, %d", a->rd, a->bit) +INSN(BLD, "r%d, %d", a->rd, a->bit) +INSN_MNEMONIC(BSET, bset[a->bit], "") +INSN_MNEMONIC(BCLR, bclr[a->bit], "") + +/* + * MCU Control Instructions + */ +INSN(BREAK, "") +INSN(NOP, "") +INSN(SLEEP, "") +INSN(WDR, "") diff --git a/qemu/target/avr/gdbstub.c b/qemu/target/avr/gdbstub.c new file mode 100644 index 0000000000..c28ed67efe --- /dev/null +++ b/qemu/target/avr/gdbstub.c @@ -0,0 +1,84 @@ +/* + * QEMU AVR gdbstub + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" + +int avr_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + /* R */ + if (n < 32) { + return gdb_get_reg8(mem_buf, env->r[n]); + } + + /* SREG */ + if (n == 32) { + uint8_t sreg = cpu_get_sreg(env); + + return gdb_get_reg8(mem_buf, sreg); + } + + /* SP */ + if (n == 33) { + return gdb_get_reg16(mem_buf, env->sp & 0x0000ffff); + } + + /* PC */ + if (n == 34) { + return gdb_get_reg32(mem_buf, env->pc_w * 2); + } + + return 0; +} + +int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + /* R */ + if (n < 32) { + env->r[n] = *mem_buf; + return 1; + } + + /* SREG */ + if (n == 32) { + cpu_set_sreg(env, *mem_buf); + return 1; + } + + /* SP */ + if (n == 33) { + env->sp = lduw_p(mem_buf); + return 2; + } + + /* PC */ + if (n == 34) { + env->pc_w = ldl_p(mem_buf) / 2; + return 4; + } + + return 0; +} diff --git a/qemu/target/avr/helper.c b/qemu/target/avr/helper.c new file mode 100644 index 0000000000..d96d14372b --- /dev/null +++ b/qemu/target/avr/helper.c @@ -0,0 +1,348 @@ +/* + * QEMU AVR CPU helpers + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/address-spaces.h" +#include "exec/helper-proto.h" + +bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + bool ret = false; + CPUClass *cc = CPU_GET_CLASS(cs); + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + if (interrupt_request & CPU_INTERRUPT_RESET) { + if (cpu_interrupts_enabled(env)) { + cs->exception_index = EXCP_RESET; + cc->do_interrupt(cs); + + cs->interrupt_request &= ~CPU_INTERRUPT_RESET; + + ret = true; + } + } + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && env->intsrc != 0) { + int index = ctz32(env->intsrc); + cs->exception_index = EXCP_INT(index); + cc->do_interrupt(cs); + + env->intsrc &= env->intsrc - 1; /* clear the interrupt */ + cs->interrupt_request &= ~CPU_INTERRUPT_HARD; + + ret = true; + } + } + return ret; +} + +void avr_cpu_do_interrupt(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + uint32_t ret = env->pc_w; + int vector = 0; + int size = avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1; + int base = 0; + + if (cs->exception_index == EXCP_RESET) { + vector = 0; + } else if (env->intsrc != 0) { + vector = ctz32(env->intsrc) + 1; + } + + if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); + } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + } else { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + } + + env->pc_w = base + vector * size; + env->sregI = 0; /* clear Global Interrupt Flag */ + + cs->exception_index = -1; +} + +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, + int len, bool is_write) +{ + return cpu_memory_rw_debug(cs, addr, buf, len, is_write); +} + +hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + return addr; /* I assume 1:1 address correspondance */ +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + int prot = 0; + MemTxAttrs attrs = {}; + uint32_t paddr; + + address &= TARGET_PAGE_MASK; + + if (mmu_idx == MMU_CODE_IDX) { + /* access to code in flash */ + paddr = OFFSET_CODE + address; + prot = PAGE_READ | PAGE_EXEC; + if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) { + error_report("execution left flash memory"); + abort(); + } + } else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* + * access to CPU registers, exit and rebuilt this TB to use full access + * incase it touches specially handled registers like SREG or SP + */ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + env->fullacc = 1; + cpu_loop_exit_restore(cs, retaddr); + } else { + /* access to memory. nothing special */ + paddr = OFFSET_DATA + address; + prot = PAGE_READ | PAGE_WRITE; + } + + tlb_set_page_with_attrs(cs, address, paddr, attrs, prot, + mmu_idx, TARGET_PAGE_SIZE); + + return true; +} + +/* + * helpers + */ + +void helper_sleep(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cpu_loop_exit(cs); +} + +void helper_unsupported(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + /* + * I count not find what happens on the real platform, so + * it's EXCP_DEBUG for meanwhile + */ + cs->exception_index = EXCP_DEBUG; + if (qemu_loglevel_mask(LOG_UNIMP)) { + qemu_log("UNSUPPORTED\n"); + cpu_dump_state(cs, stderr, 0); + } + cpu_loop_exit(cs); +} + +void helper_debug(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_break(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_wdr(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + /* WD is not implemented yet, placeholder */ + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +/* + * This function implements IN instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is read and returned + * b. otherwise io address is translated to mem address and physical memory + * is read. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ + target_ulong data = 0; + + switch (port) { + case 0x38: /* RAMPD */ + data = 0xff & (env->rampD >> 16); + break; + case 0x39: /* RAMPX */ + data = 0xff & (env->rampX >> 16); + break; + case 0x3a: /* RAMPY */ + data = 0xff & (env->rampY >> 16); + break; + case 0x3b: /* RAMPZ */ + data = 0xff & (env->rampZ >> 16); + break; + case 0x3c: /* EIND */ + data = 0xff & (env->eind >> 16); + break; + case 0x3d: /* SPL */ + data = env->sp & 0x00ff; + break; + case 0x3e: /* SPH */ + data = env->sp >> 8; + break; + case 0x3f: /* SREG */ + data = cpu_get_sreg(env); + break; + default: + /* not a special register, pass to normal memory access */ + data = address_space_ldub(&address_space_memory, + OFFSET_IO_REGISTERS + port, + MEMTXATTRS_UNSPECIFIED, NULL); + } + + return data; +} + +/* + * This function implements OUT instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is written into the register + * b. otherwise io address is translated to mem address and physical memory + * is written. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ + data &= 0x000000ff; + + switch (port) { + case 0x38: /* RAMPD */ + if (avr_feature(env, AVR_FEATURE_RAMPD)) { + env->rampD = (data & 0xff) << 16; + } + break; + case 0x39: /* RAMPX */ + if (avr_feature(env, AVR_FEATURE_RAMPX)) { + env->rampX = (data & 0xff) << 16; + } + break; + case 0x3a: /* RAMPY */ + if (avr_feature(env, AVR_FEATURE_RAMPY)) { + env->rampY = (data & 0xff) << 16; + } + break; + case 0x3b: /* RAMPZ */ + if (avr_feature(env, AVR_FEATURE_RAMPZ)) { + env->rampZ = (data & 0xff) << 16; + } + break; + case 0x3c: /* EIDN */ + env->eind = (data & 0xff) << 16; + break; + case 0x3d: /* SPL */ + env->sp = (env->sp & 0xff00) | (data); + break; + case 0x3e: /* SPH */ + if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { + env->sp = (env->sp & 0x00ff) | (data << 8); + } + break; + case 0x3f: /* SREG */ + cpu_set_sreg(env, data); + break; + default: + /* not a special register, pass to normal memory access */ + address_space_stb(&address_space_memory, OFFSET_IO_REGISTERS + port, + data, MEMTXATTRS_UNSPECIFIED, NULL); + } +} + +/* + * this function implements LD instruction when there is a posibility to read + * from a CPU register + */ +target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) +{ + uint8_t data; + + env->fullacc = false; + + if (addr < NUMBER_OF_CPU_REGISTERS) { + /* CPU registers */ + data = env->r[addr]; + } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* IO registers */ + data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); + } else { + /* memory */ + data = address_space_ldub(&address_space_memory, OFFSET_DATA + addr, + MEMTXATTRS_UNSPECIFIED, NULL); + } + return data; +} + +/* + * this function implements ST instruction when there is a posibility to write + * into a CPU register + */ +void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) +{ + env->fullacc = false; + + /* Following logic assumes this: */ + assert(OFFSET_CPU_REGISTERS == OFFSET_DATA); + assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS + + NUMBER_OF_CPU_REGISTERS); + + if (addr < NUMBER_OF_CPU_REGISTERS) { + /* CPU registers */ + env->r[addr] = data; + } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* IO registers */ + helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); + } else { + /* memory */ + address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, + MEMTXATTRS_UNSPECIFIED, NULL); + } +} diff --git a/qemu/target/avr/helper.h b/qemu/target/avr/helper.h new file mode 100644 index 0000000000..8e1ae7fda0 --- /dev/null +++ b/qemu/target/avr/helper.h @@ -0,0 +1,29 @@ +/* + * QEMU AVR CPU helpers + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +DEF_HELPER_1(wdr, void, env) +DEF_HELPER_1(debug, void, env) +DEF_HELPER_1(break, void, env) +DEF_HELPER_1(sleep, void, env) +DEF_HELPER_1(unsupported, void, env) +DEF_HELPER_3(outb, void, env, i32, i32) +DEF_HELPER_2(inb, tl, env, i32) +DEF_HELPER_3(fullwr, void, env, i32, i32) +DEF_HELPER_2(fullrd, tl, env, i32) diff --git a/qemu/target/avr/insn.decode b/qemu/target/avr/insn.decode new file mode 100644 index 0000000000..482c23ad0c --- /dev/null +++ b/qemu/target/avr/insn.decode @@ -0,0 +1,187 @@ +# +# AVR instruction decode definitions. +# +# Copyright (c) 2019-2020 Michael Rolnik +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . +# + +# +# regs_16_31_by_one = [16 .. 31] +# regs_16_23_by_one = [16 .. 23] +# regs_24_30_by_two = [24, 26, 28, 30] +# regs_00_30_by_two = [0, 2, 4, 6, 8, .. 30] + +%rd 4:5 +%rr 9:1 0:4 + +%rd_a 4:4 !function=to_regs_16_31_by_one +%rd_b 4:3 !function=to_regs_16_23_by_one +%rd_c 4:2 !function=to_regs_24_30_by_two +%rr_a 0:4 !function=to_regs_16_31_by_one +%rr_b 0:3 !function=to_regs_16_23_by_one + +%imm6 6:2 0:4 +%imm8 8:4 0:4 + +%io_imm 9:2 0:4 +%ldst_d_imm 13:1 10:2 0:3 + + +&rd_rr rd rr +&rd_imm rd imm + +@op_rd_rr .... .. . ..... .... &rd_rr rd=%rd rr=%rr +@op_rd_imm6 .... .... .. .. .... &rd_imm rd=%rd_c imm=%imm6 +@op_rd_imm8 .... .... .... .... &rd_imm rd=%rd_a imm=%imm8 +@fmul .... .... . ... . ... &rd_rr rd=%rd_b rr=%rr_b + +# +# Arithmetic Instructions +# +ADD 0000 11 . ..... .... @op_rd_rr +ADC 0001 11 . ..... .... @op_rd_rr +ADIW 1001 0110 .. .. .... @op_rd_imm6 +SUB 0001 10 . ..... .... @op_rd_rr +SUBI 0101 .... .... .... @op_rd_imm8 +SBC 0000 10 . ..... .... @op_rd_rr +SBCI 0100 .... .... .... @op_rd_imm8 +SBIW 1001 0111 .. .. .... @op_rd_imm6 +AND 0010 00 . ..... .... @op_rd_rr +ANDI 0111 .... .... .... @op_rd_imm8 +OR 0010 10 . ..... .... @op_rd_rr +ORI 0110 .... .... .... @op_rd_imm8 +EOR 0010 01 . ..... .... @op_rd_rr +COM 1001 010 rd:5 0000 +NEG 1001 010 rd:5 0001 +INC 1001 010 rd:5 0011 +DEC 1001 010 rd:5 1010 +MUL 1001 11 . ..... .... @op_rd_rr +MULS 0000 0010 .... .... &rd_rr rd=%rd_a rr=%rr_a +MULSU 0000 0011 0 ... 0 ... @fmul +FMUL 0000 0011 0 ... 1 ... @fmul +FMULS 0000 0011 1 ... 0 ... @fmul +FMULSU 0000 0011 1 ... 1 ... @fmul +DES 1001 0100 imm:4 1011 + +# +# Branch Instructions +# + +# The 22-bit immediate is partially in the opcode word, +# and partially in the next. Use append_16 to build the +# complete 22-bit value. +%imm_call 4:5 0:1 !function=append_16 + +@op_bit .... .... . bit:3 .... +@op_bit_imm .... .. imm:s7 bit:3 + +RJMP 1100 imm:s12 +IJMP 1001 0100 0000 1001 +EIJMP 1001 0100 0001 1001 +JMP 1001 010 ..... 110 . imm=%imm_call +RCALL 1101 imm:s12 +ICALL 1001 0101 0000 1001 +EICALL 1001 0101 0001 1001 +CALL 1001 010 ..... 111 . imm=%imm_call +RET 1001 0101 0000 1000 +RETI 1001 0101 0001 1000 +CPSE 0001 00 . ..... .... @op_rd_rr +CP 0001 01 . ..... .... @op_rd_rr +CPC 0000 01 . ..... .... @op_rd_rr +CPI 0011 .... .... .... @op_rd_imm8 +SBRC 1111 110 rr:5 0 bit:3 +SBRS 1111 111 rr:5 0 bit:3 +SBIC 1001 1001 reg:5 bit:3 +SBIS 1001 1011 reg:5 bit:3 +BRBS 1111 00 ....... ... @op_bit_imm +BRBC 1111 01 ....... ... @op_bit_imm + +# +# Data Transfer Instructions +# + +%rd_d 4:4 !function=to_regs_00_30_by_two +%rr_d 0:4 !function=to_regs_00_30_by_two + +@io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm +@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm + +# The 16-bit immediate is completely in the next word. +# Fields cannot be defined with no bits, so we cannot play +# the same trick and append to a zero-bit value. +# Defer reading the immediate until trans_{LDS,STS}. +@ldst_s .... ... rd:5 .... imm=0 + +MOV 0010 11 . ..... .... @op_rd_rr +MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d +LDI 1110 .... .... .... @op_rd_imm8 +LDS 1001 000 ..... 0000 @ldst_s +LDX1 1001 000 rd:5 1100 +LDX2 1001 000 rd:5 1101 +LDX3 1001 000 rd:5 1110 +LDY2 1001 000 rd:5 1001 +LDY3 1001 000 rd:5 1010 +LDZ2 1001 000 rd:5 0001 +LDZ3 1001 000 rd:5 0010 +LDDY 10 . 0 .. 0 ..... 1 ... @ldst_d +LDDZ 10 . 0 .. 0 ..... 0 ... @ldst_d +STS 1001 001 ..... 0000 @ldst_s +STX1 1001 001 rr:5 1100 +STX2 1001 001 rr:5 1101 +STX3 1001 001 rr:5 1110 +STY2 1001 001 rd:5 1001 +STY3 1001 001 rd:5 1010 +STZ2 1001 001 rd:5 0001 +STZ3 1001 001 rd:5 0010 +STDY 10 . 0 .. 1 ..... 1 ... @ldst_d +STDZ 10 . 0 .. 1 ..... 0 ... @ldst_d +LPM1 1001 0101 1100 1000 +LPM2 1001 000 rd:5 0100 +LPMX 1001 000 rd:5 0101 +ELPM1 1001 0101 1101 1000 +ELPM2 1001 000 rd:5 0110 +ELPMX 1001 000 rd:5 0111 +SPM 1001 0101 1110 1000 +SPMX 1001 0101 1111 1000 +IN 1011 0 .. ..... .... @io_rd_imm +OUT 1011 1 .. ..... .... @io_rd_imm +PUSH 1001 001 rd:5 1111 +POP 1001 000 rd:5 1111 +XCH 1001 001 rd:5 0100 +LAC 1001 001 rd:5 0110 +LAS 1001 001 rd:5 0101 +LAT 1001 001 rd:5 0111 + +# +# Bit and Bit-test Instructions +# +LSR 1001 010 rd:5 0110 +ROR 1001 010 rd:5 0111 +ASR 1001 010 rd:5 0101 +SWAP 1001 010 rd:5 0010 +SBI 1001 1010 reg:5 bit:3 +CBI 1001 1000 reg:5 bit:3 +BST 1111 101 rd:5 0 bit:3 +BLD 1111 100 rd:5 0 bit:3 +BSET 1001 0100 0 bit:3 1000 +BCLR 1001 0100 1 bit:3 1000 + +# +# MCU Control Instructions +# +BREAK 1001 0101 1001 1000 +NOP 0000 0000 0000 0000 +SLEEP 1001 0101 1000 1000 +WDR 1001 0101 1010 1000 diff --git a/qemu/target/avr/machine.c b/qemu/target/avr/machine.c new file mode 100644 index 0000000000..e315442787 --- /dev/null +++ b/qemu/target/avr/machine.c @@ -0,0 +1,119 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" + +static int get_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + CPUAVRState *env = opaque; + uint8_t sreg; + + sreg = qemu_get_byte(f); + cpu_set_sreg(env, sreg); + return 0; +} + +static int put_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + CPUAVRState *env = opaque; + uint8_t sreg = cpu_get_sreg(env); + + qemu_put_byte(f, sreg); + return 0; +} + +static const VMStateInfo vms_sreg = { + .name = "sreg", + .get = get_sreg, + .put = put_sreg, +}; + +static int get_segment(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + uint32_t *ramp = opaque; + uint8_t temp; + + temp = qemu_get_byte(f); + *ramp = ((uint32_t)temp) << 16; + return 0; +} + +static int put_segment(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + uint32_t *ramp = opaque; + uint8_t temp = *ramp >> 16; + + qemu_put_byte(f, temp); + return 0; +} + +static const VMStateInfo vms_rampD = { + .name = "rampD", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampX = { + .name = "rampX", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampY = { + .name = "rampY", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampZ = { + .name = "rampZ", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_eind = { + .name = "eind", + .get = get_segment, + .put = put_segment, +}; + +const VMStateDescription vms_avr_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.pc_w, AVRCPU), + VMSTATE_UINT32(env.sp, AVRCPU), + VMSTATE_UINT32(env.skip, AVRCPU), + + VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NUMBER_OF_CPU_REGISTERS), + + VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState), + VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t), + VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t), + VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t), + VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t), + VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t), + + VMSTATE_END_OF_LIST() + } +}; diff --git a/qemu/target/avr/translate.c b/qemu/target/avr/translate.c new file mode 100644 index 0000000000..850c5941d9 --- /dev/null +++ b/qemu/target/avr/translate.c @@ -0,0 +1,3061 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "qemu/qemu-print.h" +#include "tcg/tcg.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/tcg-op.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/log.h" +#include "exec/translator.h" +#include "exec/gen-icount.h" + +/* + * Define if you want a BREAK instruction translated to a breakpoint + * Active debugging connection is assumed + * This is for + * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests + * tests + */ +#undef BREAKPOINT_ON_BREAK + +static TCGv cpu_pc; + +static TCGv cpu_Cf; +static TCGv cpu_Zf; +static TCGv cpu_Nf; +static TCGv cpu_Vf; +static TCGv cpu_Sf; +static TCGv cpu_Hf; +static TCGv cpu_Tf; +static TCGv cpu_If; + +static TCGv cpu_rampD; +static TCGv cpu_rampX; +static TCGv cpu_rampY; +static TCGv cpu_rampZ; + +static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS]; +static TCGv cpu_eind; +static TCGv cpu_sp; + +static TCGv cpu_skip; + +static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; +#define REG(x) (cpu_r[x]) + +enum { + DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */ + DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */ + DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */ +}; + +typedef struct DisasContext DisasContext; + +/* This is the state at translation time. */ +struct DisasContext { + TranslationBlock *tb; + + CPUAVRState *env; + CPUState *cs; + + target_long npc; + uint32_t opcode; + + /* Routine used to access memory */ + int memidx; + int bstate; + int singlestep; + + /* + * some AVR instructions can make the following instruction to be skipped + * Let's name those instructions + * A - instruction that can skip the next one + * B - instruction that can be skipped. this depends on execution of A + * there are two scenarios + * 1. A and B belong to the same translation block + * 2. A is the last instruction in the translation block and B is the last + * + * following variables are used to simplify the skipping logic, they are + * used in the following manner (sketch) + * + * TCGLabel *skip_label = NULL; + * if (ctx.skip_cond != TCG_COND_NEVER) { + * skip_label = gen_new_label(); + * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label); + * } + * + * if (free_skip_var0) { + * tcg_temp_free(skip_var0); + * free_skip_var0 = false; + * } + * + * translate(&ctx); + * + * if (skip_label) { + * gen_set_label(skip_label); + * } + */ + TCGv skip_var0; + TCGv skip_var1; + TCGCond skip_cond; + bool free_skip_var0; +}; + +void avr_cpu_tcg_init(void) +{ + int i; + +#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) + cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); + cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); + cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); + cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); + cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); + cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); + cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); + cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); + cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); + cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD"); + cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX"); + cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY"); + cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ"); + cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind"); + cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); + cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip"); + + for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) { + cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), + reg_names[i]); + } +#undef AVR_REG_OFFS +} + +static int to_regs_16_31_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 16); +} + +static int to_regs_16_23_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 8); +} + +static int to_regs_24_30_by_two(DisasContext *ctx, int indx) +{ + return 24 + (indx % 4) * 2; +} + +static int to_regs_00_30_by_two(DisasContext *ctx, int indx) +{ + return (indx % 16) * 2; +} + +static uint16_t next_word(DisasContext *ctx) +{ + return cpu_lduw_code(ctx->env, ctx->npc++ * 2); +} + +static int append_16(DisasContext *ctx, int x) +{ + return x << 16 | next_word(ctx); +} + +static bool avr_have_feature(DisasContext *ctx, int feature) +{ + if (!avr_feature(ctx->env, feature)) { + gen_helper_unsupported(cpu_env); + ctx->bstate = DISAS_NORETURN; + return false; + } + return true; +} + +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode-insn.c.inc" + +/* + * Arithmetic Instructions + */ + +/* + * Utility functions for updating status registers: + * + * - gen_add_CHf() + * - gen_add_Vf() + * - gen_sub_CHf() + * - gen_sub_Vf() + * - gen_NSf() + * - gen_ZNSf() + * + */ + +static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + TCGv t3 = tcg_temp_new_i32(); + + tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ + tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ + tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ + tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ + tcg_gen_or_tl(t1, t1, t3); + + tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ + tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */ + /* = (Rd ^ R) & ~(Rd ^ Rr) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_andc_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + TCGv t3 = tcg_temp_new_i32(); + + tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */ + tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */ + tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */ + tcg_gen_and_tl(t3, t3, R); + tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */ + + tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */ + tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */ + /* = (Rd ^ R) & (Rd ^ R) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_and_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_NSf(TCGv R) +{ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +static void gen_ZNSf(TCGv R) +{ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +/* + * Adds two registers without the C Flag and places the result in the + * destination register Rd. + */ +static bool trans_ADD(DisasContext *ctx, arg_ADD *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds two registers and the contents of the C Flag and places the result in + * the destination register Rd. + */ +static bool trans_ADC(DisasContext *ctx, arg_ADC *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */ + tcg_gen_add_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds an immediate value (0 - 63) to a register pair and places the result + * in the register pair. This instruction operates on the upper four register + * pairs, and is well suited for operations on the pointer registers. This + * instruction is not available in all devices. Refer to the device specific + * instruction set summary. + */ +static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + int Imm = (a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv Rd = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ + tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); + tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */ + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */ + + /* update output registers */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts two registers and places the result in the destination + * register Rd. + */ +static bool trans_SUB(DisasContext *ctx, arg_SUB *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts a register and a constant and places the result in the + * destination register Rd. This instruction is working on Register R16 to R31 + * and is very well suited for operations on the X, Y, and Z-pointers. + */ +static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = tcg_const_i32(a->imm); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * Subtracts two registers and subtracts with the C Flag and places the + * result in the destination register Rd. + */ +static bool trans_SBC(DisasContext *ctx, arg_SBC *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + + return true; +} + +/* + * SBCI -- Subtract Immediate with Carry + */ +static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = tcg_const_i32(a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * Subtracts an immediate value (0-63) from a register pair and places the + * result in the register pair. This instruction operates on the upper four + * register pairs, and is well suited for operations on the Pointer Registers. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + int Imm = (a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv Rd = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ + tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, R, Rd); + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */ + tcg_gen_andc_tl(cpu_Vf, Rd, R); + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ + + /* update output registers */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical AND between the contents of register Rd and register + * Rr and places the result in the destination register Rd. + */ +static bool trans_AND(DisasContext *ctx, arg_AND *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical AND between the contents of register Rd and a constant + * and places the result in the destination register Rd. + */ +static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int Imm = (a->imm); + + tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Performs the logical OR between the contents of register Rd and register + * Rr and places the result in the destination register Rd. + */ +static bool trans_OR(DisasContext *ctx, arg_OR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_or_tl(R, Rd, Rr); + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical OR between the contents of register Rd and a + * constant and places the result in the destination register Rd. + */ +static bool trans_ORI(DisasContext *ctx, arg_ORI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int Imm = (a->imm); + + tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Performs the logical EOR between the contents of register Rd and + * register Rr and places the result in the destination register Rd. + */ +static bool trans_EOR(DisasContext *ctx, arg_EOR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + + tcg_gen_xor_tl(Rd, Rd, Rr); + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(Rd); + + return true; +} + +/* + * Clears the specified bits in register Rd. Performs the logical AND + * between the contents of register Rd and the complement of the constant mask + * K. The result will be placed in register Rd. + */ +static bool trans_COM(DisasContext *ctx, arg_COM *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_xori_tl(Rd, Rd, 0xff); + + /* update status register */ + tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ + gen_ZNSf(Rd); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Replaces the contents of register Rd with its two's complement; the + * value $80 is left unchanged. + */ +static bool trans_NEG(DisasContext *ctx, arg_NEG *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_const_i32(0); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, t0, Rd); + gen_sub_Vf(R, t0, Rd); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds one -1- to the contents of register Rd and places the result in the + * destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the INC instruction to be used on a loop counter in + * multiple-precision computations. When operating on unsigned numbers, only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are available. + */ +static bool trans_INC(DisasContext *ctx, arg_INC *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_addi_tl(Rd, Rd, 1); + tcg_gen_andi_tl(Rd, Rd, 0xff); + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Subtracts one -1- from the contents of register Rd and places the result + * in the destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the DEC instruction to be used on a loop counter in + * multiple-precision computations. When operating on unsigned values, only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are available. + */ +static bool trans_DEC(DisasContext *ctx, arg_DEC *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ + tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */ + gen_ZNSf(Rd); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication. + */ +static bool trans_MUL(DisasContext *ctx, arg_MUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication. + */ +static bool trans_MULS(DisasContext *ctx, arg_MULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a + * signed and an unsigned number. + */ +static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned + * multiplication and shifts the result one bit left. + */ +static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * The module is an instruction set extension to the AVR CPU, performing + * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in + * the CPU register file, registers R0-R7, where LSB of data is placed in LSB + * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including + * parity bits) is placed in registers R8- R15, organized in the register file + * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES + * instruction performs one round in the DES algorithm. Sixteen rounds must be + * executed in increasing order to form the correct DES ciphertext or + * plaintext. Intermediate results are stored in the register file (R0-R15) + * after each DES instruction. The instruction's operand (K) determines which + * round is executed, and the half carry flag (H) determines whether encryption + * or decryption is performed. The DES algorithm is described in + * "Specifications for the Data Encryption Standard" (Federal Information + * Processing Standards Publication 46). Intermediate results in this + * implementation differ from the standard because the initial permutation and + * the inverse initial permutation are performed each iteration. This does not + * affect the result in the final ciphertext or plaintext, but reduces + * execution time. + */ +static bool trans_DES(DisasContext *ctx, arg_DES *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { + return true; + } + + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + + return true; +} + +/* + * Branch Instructions + */ +static void gen_jmp_ez(DisasContext *ctx) +{ + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); + ctx->bstate = DISAS_LOOKUP; +} + +static void gen_jmp_z(DisasContext *ctx) +{ + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + ctx->bstate = DISAS_LOOKUP; +} + +static void gen_push_ret(DisasContext *ctx, int ret) +{ + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + + TCGv t0 = tcg_const_i32((ret & 0x0000ff)); + + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + + TCGv t0 = tcg_const_i32((ret & 0x00ffff)); + + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + + TCGv lo = tcg_const_i32((ret & 0x0000ff)); + TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8); + + tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + +static void gen_pop_ret(DisasContext *ctx, TCGv ret) +{ + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + TCGv lo = tcg_temp_new_i32(); + TCGv hi = tcg_temp_new_i32(); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + + tcg_gen_deposit_tl(ret, lo, hi, 8, 16); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + TranslationBlock *tb = ctx->tb; + + if (ctx->singlestep == 0) { + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(cpu_pc, dest); + tcg_gen_exit_tb(tb, n); + } else { + tcg_gen_movi_i32(cpu_pc, dest); + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(NULL, 0); + } + ctx->bstate = DISAS_NORETURN; +} + +/* + * Relative jump to an address within PC - 2K +1 and PC + 2K (words). For + * AVR microcontrollers with Program memory not exceeding 4K words (8KB) this + * instruction can address the entire memory from every address location. See + * also JMP. + */ +static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a) +{ + int dst = ctx->npc + a->imm; + + gen_goto_tb(ctx, 0, dst); + + return true; +} + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File. The Z-pointer Register is 16 bits wide and + * allows jump within the lowest 64K words (128KB) section of Program memory. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + gen_jmp_z(ctx); + + return true; +} + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. This + * instruction allows for indirect jumps to the entire 4M (words) Program + * memory space. See also IJMP. This instruction is not available in all + * devices. Refer to the device specific instruction set summary. + */ +static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + gen_jmp_ez(ctx); + return true; +} + +/* + * Jump to an address within the entire 4M (words) Program memory. See also + * RJMP. This instruction is not available in all devices. Refer to the device + * specific instruction set summary.0 + */ +static bool trans_JMP(DisasContext *ctx, arg_JMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + gen_goto_tb(ctx, 0, a->imm); + + return true; +} + +/* + * Relative call to an address within PC - 2K + 1 and PC + 2K (words). The + * return address (the instruction after the RCALL) is stored onto the Stack. + * See also CALL. For AVR microcontrollers with Program memory not exceeding 4K + * words (8KB) this instruction can address the entire memory from every + * address location. The Stack Pointer uses a post-decrement scheme during + * RCALL. + */ +static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a) +{ + int ret = ctx->npc; + int dst = ctx->npc + a->imm; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, dst); + + return true; +} + +/* + * Calls to a subroutine within the entire 4M (words) Program memory. The + * return address (to the instruction after the CALL) will be stored onto the + * Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_z(ctx); + + return true; +} + +/* + * Indirect call of a subroutine pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. This + * instruction allows for indirect calls to the entire 4M (words) Program + * memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme + * during EICALL. This instruction is not available in all devices. Refer to + * the device specific instruction set summary. + */ +static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_ez(ctx); + return true; +} + +/* + * Calls to a subroutine within the entire Program memory. The return + * address (to the instruction after the CALL) will be stored onto the Stack. + * (See also RCALL). The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_CALL(DisasContext *ctx, arg_CALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + int Imm = a->imm; + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, Imm); + + return true; +} + +/* + * Returns from subroutine. The return address is loaded from the STACK. + * The Stack Pointer uses a preincrement scheme during RET. + */ +static bool trans_RET(DisasContext *ctx, arg_RET *a) +{ + gen_pop_ret(ctx, cpu_pc); + + ctx->bstate = DISAS_LOOKUP; + return true; +} + +/* + * Returns from interrupt. The return address is loaded from the STACK and + * the Global Interrupt Flag is set. Note that the Status Register is not + * automatically stored when entering an interrupt routine, and it is not + * restored when returning from an interrupt routine. This must be handled by + * the application program. The Stack Pointer uses a pre-increment scheme + * during RETI. + */ +static bool trans_RETI(DisasContext *ctx, arg_RETI *a) +{ + gen_pop_ret(ctx, cpu_pc); + tcg_gen_movi_tl(cpu_If, 1); + + /* Need to return to main loop to re-evaluate interrupts. */ + ctx->bstate = DISAS_EXIT; + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr, and + * skips the next instruction if Rd = Rr. + */ +static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) +{ + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = cpu_r[a->rd]; + ctx->skip_var1 = cpu_r[a->rr]; + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr. + * None of the registers are changed. All conditional branches can be used + * after this instruction. + */ +static bool trans_CP(DisasContext *ctx, arg_CP *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr and + * also takes into account the previous carry. None of the registers are + * changed. All conditional branches can be used after this instruction. + */ +static bool trans_CPC(DisasContext *ctx, arg_CPC *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs a compare between register Rd and a constant. + * The register is not changed. All conditional branches can be used after this + * instruction. + */ +static bool trans_CPI(DisasContext *ctx, arg_CPI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int Imm = a->imm; + TCGv Rr = tcg_const_i32(Imm); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is cleared. + */ +static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) +{ + TCGv Rr = cpu_r[a->rr]; + + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = tcg_temp_new(); + ctx->free_skip_var0 = true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is set. + */ +static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) +{ + TCGv Rr = cpu_r[a->rr]; + + ctx->skip_cond = TCG_COND_NE; + ctx->skip_var0 = tcg_temp_new(); + ctx->free_skip_var0 = true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is cleared. This instruction operates on the + * lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) +{ + TCGv temp = tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = temp; + ctx->free_skip_var0 = true; + + return true; +} + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is set. This instruction operates on the lower + * 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) +{ + TCGv temp = tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond = TCG_COND_NE; + ctx->skip_var0 = temp; + ctx->free_skip_var0 = true; + + return true; +} + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is cleared. This instruction branches relatively + * to PC in either direction (PC - 63 < = destination <= PC + 64). The + * parameter k is the offset from PC and is represented in two's complement + * form. + */ +static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) +{ + TCGLabel *not_taken = gen_new_label(); + + TCGv var; + + switch (a->bit) { + case 0x00: + var = cpu_Cf; + break; + case 0x01: + var = cpu_Zf; + break; + case 0x02: + var = cpu_Nf; + break; + case 0x03: + var = cpu_Vf; + break; + case 0x04: + var = cpu_Sf; + break; + case 0x05: + var = cpu_Hf; + break; + case 0x06: + var = cpu_Tf; + break; + case 0x07: + var = cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate = DISAS_CHAIN; + return true; +} + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is set. This instruction branches relatively to + * PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k + * is the offset from PC and is represented in two's complement form. + */ +static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) +{ + TCGLabel *not_taken = gen_new_label(); + + TCGv var; + + switch (a->bit) { + case 0x00: + var = cpu_Cf; + break; + case 0x01: + var = cpu_Zf; + break; + case 0x02: + var = cpu_Nf; + break; + case 0x03: + var = cpu_Vf; + break; + case 0x04: + var = cpu_Sf; + break; + case 0x05: + var = cpu_Hf; + break; + case 0x06: + var = cpu_Tf; + break; + case 0x07: + var = cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate = DISAS_CHAIN; + return true; +} + +/* + * Data Transfer Instructions + */ + +/* + * in the gen_set_addr & gen_get_addr functions + * H assumed to be in 0x00ff0000 format + * M assumed to be in 0x000000ff format + * L assumed to be in 0x000000ff format + */ +static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) +{ + + tcg_gen_andi_tl(L, addr, 0x000000ff); + + tcg_gen_andi_tl(M, addr, 0x0000ff00); + tcg_gen_shri_tl(M, M, 8); + + tcg_gen_andi_tl(H, addr, 0x00ff0000); +} + +static void gen_set_xaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]); +} + +static void gen_set_yaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]); +} + +static void gen_set_zaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]); +} + +static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) +{ + TCGv addr = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(addr, M, H, 8, 8); + tcg_gen_deposit_tl(addr, L, addr, 8, 16); + + return addr; +} + +static TCGv gen_get_xaddr(void) +{ + return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]); +} + +static TCGv gen_get_yaddr(void) +{ + return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]); +} + +static TCGv gen_get_zaddr(void) +{ + return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]); +} + +/* + * Load one byte indirect from data space to register and stores an clear + * the bits in data space specified by the register. The instruction can only + * be used towards internal SRAM. The data location is pointed to by the Z (16 + * bits) Pointer Register in the Register File. Memory access is limited to the + * current data segment of 64KB. To access another data segment in devices with + * more than 64KB data space, the RAMPZ in register in the I/O area has to be + * changed. The Z-pointer Register is left unchanged by the operation. This + * instruction is especially suited for clearing status bits stored in SRAM. + */ +static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) +{ + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullwr(cpu_env, data, addr); + } else { + tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */ + } +} + +static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) +{ + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullrd(data, cpu_env, addr); + } else { + tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */ + } +} + +/* + * This instruction makes a copy of one register into another. The source + * register Rr is left unchanged, while the destination register Rd is loaded + * with a copy of Rr. + */ +static bool trans_MOV(DisasContext *ctx, arg_MOV *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + + tcg_gen_mov_tl(Rd, Rr); + + return true; +} + +/* + * This instruction makes a copy of one register pair into another register + * pair. The source register pair Rr+1:Rr is left unchanged, while the + * destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr. This + * instruction is not available in all devices. Refer to the device specific + * instruction set summary. + */ +static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) { + return true; + } + + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + TCGv RrL = cpu_r[a->rr]; + TCGv RrH = cpu_r[a->rr + 1]; + + tcg_gen_mov_tl(RdH, RrH); + tcg_gen_mov_tl(RdL, RrL); + + return true; +} + +/* + * Loads an 8 bit constant directly to register 16 to 31. + */ +static bool trans_LDI(DisasContext *ctx, arg_LDI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int imm = a->imm; + + tcg_gen_movi_tl(Rd, imm); + + return true; +} + +/* + * Loads one byte from the data space to a register. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the register file only. The EEPROM has a separate address space. + * A 16-bit address must be supplied. Memory access is limited to the current + * data segment of 64KB. The LDS instruction uses the RAMPD Register to access + * memory above 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPD in register in the I/O area has to be changed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_LDS(DisasContext *ctx, arg_LDS *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_rampD; + a->imm = next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect from the data space to a register. For parts + * with SRAM, the data space consists of the Register File, I/O memory and + * internal SRAM (and external SRAM if applicable). For parts without SRAM, the + * data space consists of the Register File only. In some parts the Flash + * Memory has been mapped to the data space and can be read using this command. + * The EEPROM has a separate address space. The data location is pointed to by + * the X (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data segment + * in devices with more than 64KB data space, the RAMPX in register in the I/O + * area has to be changed. The X-pointer Register can either be left unchanged + * by the operation, or it can be post-incremented or predecremented. These + * features are especially suited for accessing arrays, tables, and Stack + * Pointer usage of the X-pointer Register. Note that only the low byte of the + * X-pointer is updated in devices with no more than 256 bytes data space. For + * such devices, the high byte of the pointer is not used by this instruction + * and can be used for other purposes. The RAMPX Register in the I/O area is + * updated in parts with more than 64KB data space or more than 64KB Program + * memory, and the increment/decrement is added to the entire 24-bit address on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. + */ +static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect with or without displacement from the data space + * to a register. For parts with SRAM, the data space consists of the Register + * File, I/O memory and internal SRAM (and external SRAM if applicable). For + * parts without SRAM, the data space consists of the Register File only. In + * some parts the Flash Memory has been mapped to the data space and can be + * read using this command. The EEPROM has a separate address space. The data + * location is pointed to by the Y (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. The Y-pointer Register + * can either be left unchanged by the operation, or it can be post-incremented + * or predecremented. These features are especially suited for accessing + * arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that + * only the low byte of the Y-pointer is updated in devices with no more than + * 256 bytes data space. For such devices, the high byte of the pointer is not + * used by this instruction and can be used for other purposes. The RAMPY + * Register in the I/O area is updated in parts with more than 64KB data space + * or more than 64KB Program memory, and the increment/decrement/displacement + * is added to the entire 24-bit address on such devices. Not all variants of + * this instruction is available in all devices. Refer to the device specific + * instruction set summary. In the Reduced Core tinyAVR the LD instruction can + * be used to achieve the same operation as LPM since the program memory is + * mapped to the data memory space. + */ +static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect with or without displacement from the data space + * to a register. For parts with SRAM, the data space consists of the Register + * File, I/O memory and internal SRAM (and external SRAM if applicable). For + * parts without SRAM, the data space consists of the Register File only. In + * some parts the Flash Memory has been mapped to the data space and can be + * read using this command. The EEPROM has a separate address space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPZ in register in the I/O area has to be changed. The Z-pointer Register + * can either be left unchanged by the operation, or it can be post-incremented + * or predecremented. These features are especially suited for Stack Pointer + * usage of the Z-pointer Register, however because the Z-pointer Register can + * be used for indirect subroutine calls, indirect jumps and table lookup, it + * is often more convenient to use the X or Y-pointer as a dedicated Stack + * Pointer. Note that only the low byte of the Z-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPZ Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the + * increment/decrement/displacement is added to the entire 24-bit address on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. For using the Z-pointer for table lookup in Program memory see the + * LPM and ELPM instructions. + */ +static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte from a Register to the data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the Register File only. The EEPROM has a separate address space. + * A 16-bit address must be supplied. Memory access is limited to the current + * data segment of 64KB. The STS instruction uses the RAMPD Register to access + * memory above 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPD in register in the I/O area has to be changed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_STS(DisasContext *ctx, arg_STS *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_rampD; + a->imm = next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect from a register to data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory, and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the Register File only. The EEPROM has a separate address space. + * + * The data location is pointed to by the X (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPX in register in the I/O area has to be changed. + * + * The X-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the + * X-pointer Register. Note that only the low byte of the X-pointer is updated + * in devices with no more than 256 bytes data space. For such devices, the high + * byte of the pointer is not used by this instruction and can be used for other + * purposes. The RAMPX Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement is added to the entire 24-bit address on such devices. + */ +static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) +{ + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) +{ + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) +{ + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect with or without displacement from a register to data + * space. For parts with SRAM, the data space consists of the Register File, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EEPROM + * has a separate address space. + * + * The data location is pointed to by the Y (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer + * Register. Note that only the low byte of the Y-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPY Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STDY(DisasContext *ctx, arg_STDY *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect with or without displacement from a register to data + * space. For parts with SRAM, the data space consists of the Register File, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EEPROM + * has a separate address space. + * + * The data location is pointed to by the Y (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer + * Register. Note that only the low byte of the Y-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPY Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte pointed to by the Z-register into the destination + * register Rd. This instruction features a 100% space effective constant + * initialization or constant data fetch. The Program memory is organized in + * 16-bit words while the Z-pointer is a byte address. Thus, the least + * significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high + * byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of + * Program memory. The Zpointer Register can either be left unchanged by the + * operation, or it can be incremented. The incrementation does not apply to + * the RAMPZ Register. + * + * Devices with Self-Programming capability can use the LPM instruction to read + * the Fuse and Lock bit values. + */ +static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + TCGv Rd = cpu_r[0]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + tcg_gen_andi_tl(L, addr, 0xff); + tcg_gen_shri_tl(addr, addr, 8); + tcg_gen_andi_tl(H, addr, 0xff); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte pointed to by the Z-register and the RAMPZ Register in + * the I/O space, and places this byte in the destination register Rd. This + * instruction features a 100% space effective constant initialization or + * constant data fetch. The Program memory is organized in 16-bit words while + * the Z-pointer is a byte address. Thus, the least significant bit of the + * Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This + * instruction can address the entire Program memory space. The Z-pointer + * Register can either be left unchanged by the operation, or it can be + * incremented. The incrementation applies to the entire 24-bit concatenation + * of the RAMPZ and Z-pointer Registers. + * + * Devices with Self-Programming capability can use the ELPM instruction to + * read the Fuse and Lock bit value. + */ +static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + TCGv Rd = cpu_r[0]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * SPM can be used to erase a page in the Program memory, to write a page + * in the Program memory (that is already erased), and to set Boot Loader Lock + * bits. In some devices, the Program memory can be written one word at a time, + * in other devices an entire page can be programmed simultaneously after first + * filling a temporary page buffer. In all cases, the Program memory must be + * erased one page at a time. When erasing the Program memory, the RAMPZ and + * Z-register are used as page address. When writing the Program memory, the + * RAMPZ and Z-register are used as page or word address, and the R1:R0 + * register pair is used as data(1). When setting the Boot Loader Lock bits, + * the R1:R0 register pair is used as data. Refer to the device documentation + * for detailed description of SPM usage. This instruction can address the + * entire Program memory. + * + * The SPM instruction is not available in all devices. Refer to the device + * specific instruction set summary. + * + * Note: 1. R1 determines the instruction high byte, and R0 determines the + * instruction low byte. + */ +static bool trans_SPM(DisasContext *ctx, arg_SPM *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) { + return true; + } + + return true; +} + +static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) { + return true; + } + + return true; +} + +/* + * Loads data from the I/O Space (Ports, Timers, Configuration Registers, + * etc.) into register Rd in the Register File. + */ +static bool trans_IN(DisasContext *ctx, arg_IN *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv port = tcg_const_i32(a->imm); + + gen_helper_inb(Rd, cpu_env, port); + + tcg_temp_free_i32(port); + + return true; +} + +/* + * Stores data from register Rr in the Register File to I/O Space (Ports, + * Timers, Configuration Registers, etc.). + */ +static bool trans_OUT(DisasContext *ctx, arg_OUT *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv port = tcg_const_i32(a->imm); + + gen_helper_outb(cpu_env, port, Rd); + + tcg_temp_free_i32(port); + + return true; +} + +/* + * This instruction stores the contents of register Rr on the STACK. The + * Stack Pointer is post-decremented by 1 after the PUSH. This instruction is + * not available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) +{ + TCGv Rd = cpu_r[a->rd]; + + gen_data_store(ctx, Rd, cpu_sp); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + return true; +} + +/* + * This instruction loads register Rd with a byte from the STACK. The Stack + * Pointer is pre-incremented by 1 before the POP. This instruction is not + * available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_POP(DisasContext *ctx, arg_POP *a) +{ + /* + * Using a temp to work around some strange behaviour: + * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + * gen_data_load(ctx, Rd, cpu_sp); + * seems to cause the add to happen twice. + * This doesn't happen if either the add or the load is removed. + */ + TCGv t1 = tcg_temp_new_i32(); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_addi_tl(t1, cpu_sp, 1); + gen_data_load(ctx, Rd, t1); + tcg_gen_mov_tl(cpu_sp, t1); + + return true; +} + +/* + * Exchanges one byte indirect between register and data space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for writing/reading status bits stored in SRAM. + */ +static bool trans_XCH(DisasContext *ctx, arg_XCH *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + TCGv addr = gen_get_zaddr(); + + gen_data_load(ctx, t0, addr); + gen_data_store(ctx, Rd, addr); + tcg_gen_mov_tl(Rd, t0); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Load one byte indirect from data space to register and set bits in data + * space specified by the register. The instruction can only be used towards + * internal SRAM. The data location is pointed to by the Z (16 bits) Pointer + * Register in the Register File. Memory access is limited to the current data + * segment of 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for setting status bits stored in SRAM. + */ +static bool trans_LAS(DisasContext *ctx, arg_LAS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rr = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_or_tl(t1, t0, Rr); + tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Load one byte indirect from data space to register and stores and clear + * the bits in data space specified by the register. The instruction can + * only be used towards internal SRAM. The data location is pointed to by + * the Z (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data + * segment in devices with more than 64KB data space, the RAMPZ in register + * in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for clearing status bits stored in SRAM. + */ +static bool trans_LAC(DisasContext *ctx, arg_LAC *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rr = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */ + tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Load one byte indirect from data space to register and toggles bits in + * the data space specified by the register. The instruction can only be used + * towards SRAM. The data location is pointed to by the Z (16 bits) Pointer + * Register in the Register File. Memory access is limited to the current data + * segment of 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for changing status bits stored in SRAM. + */ +static bool trans_LAT(DisasContext *ctx, arg_LAT *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_xor_tl(t1, t0, Rd); + tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Bit and Bit-test Instructions + */ +static void gen_rshift_ZNVSf(TCGv R) +{ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf); + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is + * loaded into the C Flag of the SREG. This operation effectively divides an + * unsigned value by two. The C Flag can be used to round the result. + */ +static bool trans_LSR(DisasContext *ctx, arg_LSR *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + tcg_gen_shri_tl(Rd, Rd, 1); + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */ + tcg_gen_movi_tl(cpu_Nf, 0); + tcg_gen_mov_tl(cpu_Vf, cpu_Cf); + tcg_gen_mov_tl(cpu_Sf, cpu_Vf); + + return true; +} + +/* + * Shifts all bits in Rd one place to the right. The C Flag is shifted into + * bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined + * with ASR, effectively divides multi-byte signed values by two. Combined with + * LSR it effectively divides multi-byte unsigned values by two. The Carry Flag + * can be used to round the result. + */ +static bool trans_ROR(DisasContext *ctx, arg_ROR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_shli_tl(t0, cpu_Cf, 7); + + /* update status register */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + + /* update output register */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + /* update status register */ + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 + * is loaded into the C Flag of the SREG. This operation effectively divides a + * signed value by two without changing its sign. The Carry Flag can be used to + * round the result. + */ +static bool trans_ASR(DisasContext *ctx, arg_ASR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + + /* update status register */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */ + + /* update output register */ + tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + /* update status register */ + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Swaps high and low nibbles in a register. + */ +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(t0, Rd, 0x0f); + tcg_gen_shli_tl(t0, t0, 4); + tcg_gen_andi_tl(t1, Rd, 0xf0); + tcg_gen_shri_tl(t1, t1, 4); + tcg_gen_or_tl(Rd, t0, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Sets a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBI(DisasContext *ctx, arg_SBI *a) +{ + TCGv data = tcg_temp_new_i32(); + TCGv port = tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_ori_tl(data, data, 1 << a->bit); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(port); + tcg_temp_free_i32(data); + + return true; +} + +/* + * Clears a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_CBI(DisasContext *ctx, arg_CBI *a) +{ + TCGv data = tcg_temp_new_i32(); + TCGv port = tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_andi_tl(data, data, ~(1 << a->bit)); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(data); + tcg_temp_free_i32(port); + + return true; +} + +/* + * Stores bit b from Rd to the T Flag in SREG (Status Register). + */ +static bool trans_BST(DisasContext *ctx, arg_BST *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); + tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit); + + return true; +} + +/* + * Copies the T Flag in the SREG (Status Register) to bit b in register Rd. + */ +static bool trans_BLD(DisasContext *ctx, arg_BLD *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */ + tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */ + tcg_gen_or_tl(Rd, Rd, t1); + + tcg_temp_free_i32(t1); + + return true; +} + +/* + * Sets a single Flag or bit in SREG. + */ +static bool trans_BSET(DisasContext *ctx, arg_BSET *a) +{ + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x01); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x01); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x01); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x01); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x01); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x01); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x01); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x01); + break; + } + + return true; +} + +/* + * Clears a single Flag in SREG. + */ +static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) +{ + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x00); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x00); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x00); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x00); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x00); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x00); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x00); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x00); + break; + } + + return true; +} + +/* + * MCU Control Instructions + */ + +/* + * The BREAK instruction is used by the On-chip Debug system, and is + * normally not used in the application software. When the BREAK instruction is + * executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip + * Debugger access to internal resources. If any Lock bits are set, or either + * the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK + * instruction as a NOP and will not enter the Stopped mode. This instruction + * is not available in all devices. Refer to the device specific instruction + * set summary. + */ +static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) { + return true; + } + +#ifdef BREAKPOINT_ON_BREAK + tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); + gen_helper_debug(cpu_env); + ctx->bstate = DISAS_EXIT; +#else + /* NOP */ +#endif + + return true; +} + +/* + * This instruction performs a single cycle No Operation. + */ +static bool trans_NOP(DisasContext *ctx, arg_NOP *a) +{ + + /* NOP */ + + return true; +} + +/* + * This instruction sets the circuit in sleep mode defined by the MCU + * Control Register. + */ +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) +{ + gen_helper_sleep(cpu_env); + ctx->bstate = DISAS_NORETURN; + return true; +} + +/* + * This instruction resets the Watchdog Timer. This instruction must be + * executed within a limited time given by the WD prescaler. See the Watchdog + * Timer hardware specification. + */ +static bool trans_WDR(DisasContext *ctx, arg_WDR *a) +{ + gen_helper_wdr(cpu_env); + + return true; +} + +/* + * Core translation mechanism functions: + * + * - translate() + * - canonicalize_skip() + * - gen_intermediate_code() + * - restore_state_to_opc() + * + */ +static void translate(DisasContext *ctx) +{ + uint32_t opcode = next_word(ctx); + + if (!decode_insn(ctx, opcode)) { + gen_helper_unsupported(cpu_env); + ctx->bstate = DISAS_NORETURN; + } +} + +/* Standardize the cpu_skip condition to NE. */ +static bool canonicalize_skip(DisasContext *ctx) +{ + switch (ctx->skip_cond) { + case TCG_COND_NEVER: + /* Normal case: cpu_skip is known to be false. */ + return false; + + case TCG_COND_ALWAYS: + /* + * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP. + * The breakpoint is on the instruction being skipped, at the start + * of the TranslationBlock. No need to update. + */ + return false; + + case TCG_COND_NE: + if (ctx->skip_var1 == NULL) { + tcg_gen_mov_tl(cpu_skip, ctx->skip_var0); + } else { + tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 = NULL; + } + break; + + default: + /* Convert to a NE condition vs 0. */ + if (ctx->skip_var1 == NULL) { + tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0); + } else { + tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip, + ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 = NULL; + } + ctx->skip_cond = TCG_COND_NE; + break; + } + if (ctx->free_skip_var0) { + tcg_temp_free(ctx->skip_var0); + ctx->free_skip_var0 = false; + } + ctx->skip_var0 = cpu_skip; + return true; +} + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +{ + CPUAVRState *env = cs->env_ptr; + DisasContext ctx = { + .tb = tb, + .cs = cs, + .env = env, + .memidx = 0, + .bstate = DISAS_NEXT, + .skip_cond = TCG_COND_NEVER, + .singlestep = cs->singlestep_enabled, + }; + target_ulong pc_start = tb->pc / 2; + int num_insns = 0; + + if (tb->flags & TB_FLAGS_FULL_ACCESS) { + /* + * This flag is set by ST/LD instruction we will regenerate it ONLY + * with mem/cpu memory access instead of mem access + */ + max_insns = 1; + } + if (ctx.singlestep) { + max_insns = 1; + } + + gen_tb_start(tb); + + ctx.npc = pc_start; + if (tb->flags & TB_FLAGS_SKIP) { + ctx.skip_cond = TCG_COND_ALWAYS; + ctx.skip_var0 = cpu_skip; + } + + do { + TCGLabel *skip_label = NULL; + + /* translate current instruction */ + tcg_gen_insn_start(ctx.npc); + num_insns++; + + /* + * this is due to some strange GDB behavior + * let's assume main has address 0x100 + * b main - sets breakpoint at address 0x00000100 (code) + * b *0x100 - sets breakpoint at address 0x00800100 (data) + */ + if (unlikely(!ctx.singlestep && + (cpu_breakpoint_test(cs, OFFSET_CODE + ctx.npc * 2, BP_ANY) || + cpu_breakpoint_test(cs, OFFSET_DATA + ctx.npc * 2, BP_ANY)))) { + canonicalize_skip(&ctx); + tcg_gen_movi_tl(cpu_pc, ctx.npc); + gen_helper_debug(cpu_env); + goto done_generating; + } + + /* Conditionally skip the next instruction, if indicated. */ + if (ctx.skip_cond != TCG_COND_NEVER) { + skip_label = gen_new_label(); + if (ctx.skip_var0 == cpu_skip) { + /* + * Copy cpu_skip so that we may zero it before the branch. + * This ensures that cpu_skip is non-zero after the label + * if and only if the skipped insn itself sets a skip. + */ + ctx.free_skip_var0 = true; + ctx.skip_var0 = tcg_temp_new(); + tcg_gen_mov_tl(ctx.skip_var0, cpu_skip); + tcg_gen_movi_tl(cpu_skip, 0); + } + if (ctx.skip_var1 == NULL) { + tcg_gen_brcondi_tl(ctx.skip_cond, ctx.skip_var0, 0, skip_label); + } else { + tcg_gen_brcond_tl(ctx.skip_cond, ctx.skip_var0, + ctx.skip_var1, skip_label); + ctx.skip_var1 = NULL; + } + if (ctx.free_skip_var0) { + tcg_temp_free(ctx.skip_var0); + ctx.free_skip_var0 = false; + } + ctx.skip_cond = TCG_COND_NEVER; + ctx.skip_var0 = NULL; + } + + translate(&ctx); + + if (skip_label) { + canonicalize_skip(&ctx); + gen_set_label(skip_label); + if (ctx.bstate == DISAS_NORETURN) { + ctx.bstate = DISAS_CHAIN; + } + } + } while (ctx.bstate == DISAS_NEXT + && num_insns < max_insns + && (ctx.npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4 + && !tcg_op_buf_full()); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + + bool nonconst_skip = canonicalize_skip(&ctx); + + switch (ctx.bstate) { + case DISAS_NORETURN: + assert(!nonconst_skip); + break; + case DISAS_NEXT: + case DISAS_TOO_MANY: + case DISAS_CHAIN: + if (!nonconst_skip) { + /* Note gen_goto_tb checks singlestep. */ + gen_goto_tb(&ctx, 1, ctx.npc); + break; + } + tcg_gen_movi_tl(cpu_pc, ctx.npc); + /* fall through */ + case DISAS_LOOKUP: + if (!ctx.singlestep) { + tcg_gen_lookup_and_goto_ptr(); + break; + } + /* fall through */ + case DISAS_EXIT: + if (ctx.singlestep) { + gen_helper_debug(cpu_env); + } else { + tcg_gen_exit_tb(NULL, 0); + } + break; + default: + g_assert_not_reached(); + } + +done_generating: + gen_tb_end(tb, num_insns); + + tb->size = (ctx.npc - pc_start) * 2; + tb->icount = num_insns; + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) + && qemu_log_in_addr_range(tb->pc)) { + FILE *fd; + fd = qemu_log_lock(); + qemu_log("IN: %s\n", lookup_symbol(tb->pc)); + log_target_disas(cs, tb->pc, tb->size); + qemu_log("\n"); + qemu_log_unlock(fd); + } +#endif +} + +void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc_w = data[0]; +} From d8d1318d2658e36d06dcbb8d641d4c8a68ac0783 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:21 +0100 Subject: [PATCH 06/31] qemu/target/avr: Register AVR support with the rest of QEMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AVR related definitions into QEMU, make AVR support buildable. [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-23-huth@tuxfamily.org> [PMD: Fixed @avr tag in qapi/machine.json] Signed-off-by: Philippe Mathieu-Daudé (cherry picked from commit 42f3ff001339e37df4f13b709d2db00a488ee45c) Signed-off-by: Glenn Baker --- qemu/MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qemu/MAINTAINERS b/qemu/MAINTAINERS index 8cbc1fac2b..ed80410291 100644 --- a/qemu/MAINTAINERS +++ b/qemu/MAINTAINERS @@ -952,6 +952,15 @@ F: include/hw/*/nrf51*.h F: include/hw/*/microbit*.h F: tests/qtest/microbit-test.c +AVR Machines +------------- + +AVR MCUs +M: Michael Rolnik +R: Sarah Harris +S: Maintained +F: default-configs/avr-softmmu.mak + CRIS Machines ------------- Axis Dev88 From b1859cb1a0df38f68e6818ba615b5fbd3f39498f Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 27 Mar 2024 21:10:09 +0100 Subject: [PATCH 07/31] qemu/target/avr: pregenerate decoder. Signed-off-by: Glenn Baker --- qemu/target/avr/decode-insn.c.inc | 1096 +++++++++++++++++++++++++++++ 1 file changed, 1096 insertions(+) create mode 100644 qemu/target/avr/decode-insn.c.inc diff --git a/qemu/target/avr/decode-insn.c.inc b/qemu/target/avr/decode-insn.c.inc new file mode 100644 index 0000000000..90e910e6d1 --- /dev/null +++ b/qemu/target/avr/decode-insn.c.inc @@ -0,0 +1,1096 @@ +/* This file is autogenerated by scripts/decodetree.py. */ + +typedef struct { + int bit; + int rd; +} arg_decode_insn10; + +typedef struct { + int rd; +} arg_decode_insn2; + +typedef struct { + int imm; +} arg_decode_insn3; + +typedef struct { + int bit; +} arg_decode_insn4; + +typedef struct { + int bit; + int imm; +} arg_decode_insn5; + +typedef struct { +} arg_decode_insn6; + +typedef struct { + int bit; + int rr; +} arg_decode_insn7; + +typedef struct { + int bit; + int reg; +} arg_decode_insn8; + +typedef struct { + int rr; +} arg_decode_insn9; + +typedef struct { + int imm; + int rd; +} arg_rd_imm; + +typedef struct { + int rd; + int rr; +} arg_rd_rr; + +typedef arg_rd_rr arg_ADD; +static bool trans_ADD(DisasContext *ctx, arg_ADD *a); +typedef arg_rd_rr arg_ADC; +static bool trans_ADC(DisasContext *ctx, arg_ADC *a); +typedef arg_rd_imm arg_ADIW; +static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a); +typedef arg_rd_rr arg_SUB; +static bool trans_SUB(DisasContext *ctx, arg_SUB *a); +typedef arg_rd_imm arg_SUBI; +static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a); +typedef arg_rd_rr arg_SBC; +static bool trans_SBC(DisasContext *ctx, arg_SBC *a); +typedef arg_rd_imm arg_SBCI; +static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a); +typedef arg_rd_imm arg_SBIW; +static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a); +typedef arg_rd_rr arg_AND; +static bool trans_AND(DisasContext *ctx, arg_AND *a); +typedef arg_rd_imm arg_ANDI; +static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a); +typedef arg_rd_rr arg_OR; +static bool trans_OR(DisasContext *ctx, arg_OR *a); +typedef arg_rd_imm arg_ORI; +static bool trans_ORI(DisasContext *ctx, arg_ORI *a); +typedef arg_rd_rr arg_EOR; +static bool trans_EOR(DisasContext *ctx, arg_EOR *a); +typedef arg_decode_insn2 arg_COM; +static bool trans_COM(DisasContext *ctx, arg_COM *a); +typedef arg_decode_insn2 arg_NEG; +static bool trans_NEG(DisasContext *ctx, arg_NEG *a); +typedef arg_decode_insn2 arg_INC; +static bool trans_INC(DisasContext *ctx, arg_INC *a); +typedef arg_decode_insn2 arg_DEC; +static bool trans_DEC(DisasContext *ctx, arg_DEC *a); +typedef arg_rd_rr arg_MUL; +static bool trans_MUL(DisasContext *ctx, arg_MUL *a); +typedef arg_rd_rr arg_MULS; +static bool trans_MULS(DisasContext *ctx, arg_MULS *a); +typedef arg_rd_rr arg_MULSU; +static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a); +typedef arg_rd_rr arg_FMUL; +static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a); +typedef arg_rd_rr arg_FMULS; +static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a); +typedef arg_rd_rr arg_FMULSU; +static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a); +typedef arg_decode_insn3 arg_DES; +static bool trans_DES(DisasContext *ctx, arg_DES *a); +typedef arg_decode_insn3 arg_RJMP; +static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a); +typedef arg_decode_insn6 arg_IJMP; +static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a); +typedef arg_decode_insn6 arg_EIJMP; +static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a); +typedef arg_decode_insn3 arg_JMP; +static bool trans_JMP(DisasContext *ctx, arg_JMP *a); +typedef arg_decode_insn3 arg_RCALL; +static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a); +typedef arg_decode_insn6 arg_ICALL; +static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a); +typedef arg_decode_insn6 arg_EICALL; +static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a); +typedef arg_decode_insn3 arg_CALL; +static bool trans_CALL(DisasContext *ctx, arg_CALL *a); +typedef arg_decode_insn6 arg_RET; +static bool trans_RET(DisasContext *ctx, arg_RET *a); +typedef arg_decode_insn6 arg_RETI; +static bool trans_RETI(DisasContext *ctx, arg_RETI *a); +typedef arg_rd_rr arg_CPSE; +static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a); +typedef arg_rd_rr arg_CP; +static bool trans_CP(DisasContext *ctx, arg_CP *a); +typedef arg_rd_rr arg_CPC; +static bool trans_CPC(DisasContext *ctx, arg_CPC *a); +typedef arg_rd_imm arg_CPI; +static bool trans_CPI(DisasContext *ctx, arg_CPI *a); +typedef arg_decode_insn7 arg_SBRC; +static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a); +typedef arg_decode_insn7 arg_SBRS; +static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a); +typedef arg_decode_insn8 arg_SBIC; +static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a); +typedef arg_decode_insn8 arg_SBIS; +static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a); +typedef arg_decode_insn5 arg_BRBS; +static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a); +typedef arg_decode_insn5 arg_BRBC; +static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a); +typedef arg_rd_rr arg_MOV; +static bool trans_MOV(DisasContext *ctx, arg_MOV *a); +typedef arg_rd_rr arg_MOVW; +static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a); +typedef arg_rd_imm arg_LDI; +static bool trans_LDI(DisasContext *ctx, arg_LDI *a); +typedef arg_rd_imm arg_LDS; +static bool trans_LDS(DisasContext *ctx, arg_LDS *a); +typedef arg_decode_insn2 arg_LDX1; +static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a); +typedef arg_decode_insn2 arg_LDX2; +static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a); +typedef arg_decode_insn2 arg_LDX3; +static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a); +typedef arg_decode_insn2 arg_LDY2; +static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a); +typedef arg_decode_insn2 arg_LDY3; +static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a); +typedef arg_decode_insn2 arg_LDZ2; +static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a); +typedef arg_decode_insn2 arg_LDZ3; +static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a); +typedef arg_rd_imm arg_LDDY; +static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a); +typedef arg_rd_imm arg_LDDZ; +static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a); +typedef arg_rd_imm arg_STS; +static bool trans_STS(DisasContext *ctx, arg_STS *a); +typedef arg_decode_insn9 arg_STX1; +static bool trans_STX1(DisasContext *ctx, arg_STX1 *a); +typedef arg_decode_insn9 arg_STX2; +static bool trans_STX2(DisasContext *ctx, arg_STX2 *a); +typedef arg_decode_insn9 arg_STX3; +static bool trans_STX3(DisasContext *ctx, arg_STX3 *a); +typedef arg_decode_insn2 arg_STY2; +static bool trans_STY2(DisasContext *ctx, arg_STY2 *a); +typedef arg_decode_insn2 arg_STY3; +static bool trans_STY3(DisasContext *ctx, arg_STY3 *a); +typedef arg_decode_insn2 arg_STZ2; +static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a); +typedef arg_decode_insn2 arg_STZ3; +static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a); +typedef arg_rd_imm arg_STDY; +static bool trans_STDY(DisasContext *ctx, arg_STDY *a); +typedef arg_rd_imm arg_STDZ; +static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a); +typedef arg_decode_insn6 arg_LPM1; +static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a); +typedef arg_decode_insn2 arg_LPM2; +static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a); +typedef arg_decode_insn2 arg_LPMX; +static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a); +typedef arg_decode_insn6 arg_ELPM1; +static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a); +typedef arg_decode_insn2 arg_ELPM2; +static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a); +typedef arg_decode_insn2 arg_ELPMX; +static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a); +typedef arg_decode_insn6 arg_SPM; +static bool trans_SPM(DisasContext *ctx, arg_SPM *a); +typedef arg_decode_insn6 arg_SPMX; +static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a); +typedef arg_rd_imm arg_IN; +static bool trans_IN(DisasContext *ctx, arg_IN *a); +typedef arg_rd_imm arg_OUT; +static bool trans_OUT(DisasContext *ctx, arg_OUT *a); +typedef arg_decode_insn2 arg_PUSH; +static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a); +typedef arg_decode_insn2 arg_POP; +static bool trans_POP(DisasContext *ctx, arg_POP *a); +typedef arg_decode_insn2 arg_XCH; +static bool trans_XCH(DisasContext *ctx, arg_XCH *a); +typedef arg_decode_insn2 arg_LAC; +static bool trans_LAC(DisasContext *ctx, arg_LAC *a); +typedef arg_decode_insn2 arg_LAS; +static bool trans_LAS(DisasContext *ctx, arg_LAS *a); +typedef arg_decode_insn2 arg_LAT; +static bool trans_LAT(DisasContext *ctx, arg_LAT *a); +typedef arg_decode_insn2 arg_LSR; +static bool trans_LSR(DisasContext *ctx, arg_LSR *a); +typedef arg_decode_insn2 arg_ROR; +static bool trans_ROR(DisasContext *ctx, arg_ROR *a); +typedef arg_decode_insn2 arg_ASR; +static bool trans_ASR(DisasContext *ctx, arg_ASR *a); +typedef arg_decode_insn2 arg_SWAP; +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a); +typedef arg_decode_insn8 arg_SBI; +static bool trans_SBI(DisasContext *ctx, arg_SBI *a); +typedef arg_decode_insn8 arg_CBI; +static bool trans_CBI(DisasContext *ctx, arg_CBI *a); +typedef arg_decode_insn10 arg_BST; +static bool trans_BST(DisasContext *ctx, arg_BST *a); +typedef arg_decode_insn10 arg_BLD; +static bool trans_BLD(DisasContext *ctx, arg_BLD *a); +typedef arg_decode_insn4 arg_BSET; +static bool trans_BSET(DisasContext *ctx, arg_BSET *a); +typedef arg_decode_insn4 arg_BCLR; +static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a); +typedef arg_decode_insn6 arg_BREAK; +static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a); +typedef arg_decode_insn6 arg_NOP; +static bool trans_NOP(DisasContext *ctx, arg_NOP *a); +typedef arg_decode_insn6 arg_SLEEP; +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a); +typedef arg_decode_insn6 arg_WDR; +static bool trans_WDR(DisasContext *ctx, arg_WDR *a); + +static void decode_insn_extract_decode_insn_Fmt_10(DisasContext *ctx, arg_decode_insn6 *a, uint16_t insn) +{ +} + +static void decode_insn_extract_decode_insn_Fmt_11(DisasContext *ctx, arg_decode_insn3 *a, uint16_t insn) +{ + a->imm = append_16(ctx, deposit32(extract32(insn, 0, 1), 1, 31, extract32(insn, 4, 5))); +} + +static void decode_insn_extract_decode_insn_Fmt_12(DisasContext *ctx, arg_decode_insn7 *a, uint16_t insn) +{ + a->rr = extract32(insn, 4, 5); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_decode_insn_Fmt_13(DisasContext *ctx, arg_decode_insn8 *a, uint16_t insn) +{ + a->reg = extract32(insn, 3, 5); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_decode_insn_Fmt_17(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = to_regs_00_30_by_two(ctx, extract32(insn, 4, 4)); + a->rr = to_regs_00_30_by_two(ctx, extract32(insn, 0, 4)); +} + +static void decode_insn_extract_decode_insn_Fmt_18(DisasContext *ctx, arg_decode_insn9 *a, uint16_t insn) +{ + a->rr = extract32(insn, 4, 5); +} + +static void decode_insn_extract_decode_insn_Fmt_19(DisasContext *ctx, arg_decode_insn10 *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_decode_insn_Fmt_4(DisasContext *ctx, arg_decode_insn2 *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); +} + +static void decode_insn_extract_decode_insn_Fmt_5(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = to_regs_16_31_by_one(ctx, extract32(insn, 4, 4)); + a->rr = to_regs_16_31_by_one(ctx, extract32(insn, 0, 4)); +} + +static void decode_insn_extract_decode_insn_Fmt_6(DisasContext *ctx, arg_decode_insn3 *a, uint16_t insn) +{ + a->imm = extract32(insn, 4, 4); +} + +static void decode_insn_extract_decode_insn_Fmt_9(DisasContext *ctx, arg_decode_insn3 *a, uint16_t insn) +{ + a->imm = sextract32(insn, 0, 12); +} + +static void decode_insn_extract_fmul(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = to_regs_16_23_by_one(ctx, extract32(insn, 4, 3)); + a->rr = to_regs_16_23_by_one(ctx, extract32(insn, 0, 3)); +} + +static void decode_insn_extract_io_rd_imm(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->imm = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 9, 2)); +} + +static void decode_insn_extract_ldst_d(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->imm = deposit32(deposit32(extract32(insn, 0, 3), 3, 29, extract32(insn, 10, 2)), 5, 27, extract32(insn, 13, 1)); +} + +static void decode_insn_extract_ldst_s(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->imm = 0; +} + +static void decode_insn_extract_op_bit(DisasContext *ctx, arg_decode_insn4 *a, uint16_t insn) +{ + a->bit = extract32(insn, 4, 3); +} + +static void decode_insn_extract_op_bit_imm(DisasContext *ctx, arg_decode_insn5 *a, uint16_t insn) +{ + a->imm = sextract32(insn, 3, 7); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_op_rd_imm6(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = to_regs_24_30_by_two(ctx, extract32(insn, 4, 2)); + a->imm = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 6, 2)); +} + +static void decode_insn_extract_op_rd_imm8(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = to_regs_16_31_by_one(ctx, extract32(insn, 4, 4)); + a->imm = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 8, 4)); +} + +static void decode_insn_extract_op_rd_rr(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->rr = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 9, 1)); +} + +bool decode_insn(DisasContext *ctx, uint16_t insn) +{ + union { + arg_decode_insn10 f_decode_insn10; + arg_decode_insn2 f_decode_insn2; + arg_decode_insn3 f_decode_insn3; + arg_decode_insn4 f_decode_insn4; + arg_decode_insn5 f_decode_insn5; + arg_decode_insn6 f_decode_insn6; + arg_decode_insn7 f_decode_insn7; + arg_decode_insn8 f_decode_insn8; + arg_decode_insn9 f_decode_insn9; + arg_rd_imm f_rd_imm; + arg_rd_rr f_rd_rr; + } u; + + switch (insn & 0x0000d000) { + case 0x00000000: + /* 00.0.... ........ */ + switch (insn & 0x00002c00) { + case 0x00000000: + /* 000000.. ........ */ + switch ((insn >> 8) & 0x3) { + case 0x0: + /* 00000000 ........ */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch (insn & 0x000000ff) { + case 0x00000000: + /* 00000000 00000000 */ + /* insn.decode:185 */ + if (trans_NOP(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x1: + /* 00000001 ........ */ + /* insn.decode:128 */ + decode_insn_extract_decode_insn_Fmt_17(ctx, &u.f_rd_rr, insn); + if (trans_MOVW(ctx, &u.f_rd_rr)) return true; + break; + case 0x2: + /* 00000010 ........ */ + /* insn.decode:71 */ + decode_insn_extract_decode_insn_Fmt_5(ctx, &u.f_rd_rr, insn); + if (trans_MULS(ctx, &u.f_rd_rr)) return true; + break; + case 0x3: + /* 00000011 ........ */ + decode_insn_extract_fmul(ctx, &u.f_rd_rr, insn); + switch (insn & 0x00000088) { + case 0x00000000: + /* 00000011 0...0... */ + /* insn.decode:72 */ + if (trans_MULSU(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000008: + /* 00000011 0...1... */ + /* insn.decode:73 */ + if (trans_FMUL(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000080: + /* 00000011 1...0... */ + /* insn.decode:74 */ + if (trans_FMULS(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000088: + /* 00000011 1...1... */ + /* insn.decode:75 */ + if (trans_FMULSU(ctx, &u.f_rd_rr)) return true; + break; + } + break; + } + break; + case 0x00000400: + /* 000001.. ........ */ + /* insn.decode:102 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_CPC(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000800: + /* 000010.. ........ */ + /* insn.decode:58 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_SBC(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000c00: + /* 000011.. ........ */ + /* insn.decode:53 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_ADD(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002000: + /* 001000.. ........ */ + /* insn.decode:61 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_AND(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002400: + /* 001001.. ........ */ + /* insn.decode:65 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_EOR(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002800: + /* 001010.. ........ */ + /* insn.decode:63 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_OR(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002c00: + /* 001011.. ........ */ + /* insn.decode:127 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_MOV(ctx, &u.f_rd_rr)) return true; + break; + } + break; + case 0x00001000: + /* 00.1.... ........ */ + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 0001.... ........ */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + switch ((insn >> 10) & 0x3) { + case 0x0: + /* 000100.. ........ */ + /* insn.decode:100 */ + if (trans_CPSE(ctx, &u.f_rd_rr)) return true; + break; + case 0x1: + /* 000101.. ........ */ + /* insn.decode:101 */ + if (trans_CP(ctx, &u.f_rd_rr)) return true; + break; + case 0x2: + /* 000110.. ........ */ + /* insn.decode:56 */ + if (trans_SUB(ctx, &u.f_rd_rr)) return true; + break; + case 0x3: + /* 000111.. ........ */ + /* insn.decode:54 */ + if (trans_ADC(ctx, &u.f_rd_rr)) return true; + break; + } + break; + case 0x1: + /* 0011.... ........ */ + /* insn.decode:103 */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + if (trans_CPI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00004000: + /* 01.0.... ........ */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 0100.... ........ */ + /* insn.decode:59 */ + if (trans_SBCI(ctx, &u.f_rd_imm)) return true; + break; + case 0x1: + /* 0110.... ........ */ + /* insn.decode:64 */ + if (trans_ORI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00005000: + /* 01.1.... ........ */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 0101.... ........ */ + /* insn.decode:57 */ + if (trans_SUBI(ctx, &u.f_rd_imm)) return true; + break; + case 0x1: + /* 0111.... ........ */ + /* insn.decode:62 */ + if (trans_ANDI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00008000: + /* 10.0.... ........ */ + decode_insn_extract_ldst_d(ctx, &u.f_rd_imm, insn); + switch (insn & 0x00000208) { + case 0x00000000: + /* 10.0..0. ....0... */ + /* insn.decode:139 */ + if (trans_LDDZ(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000008: + /* 10.0..0. ....1... */ + /* insn.decode:138 */ + if (trans_LDDY(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000200: + /* 10.0..1. ....0... */ + /* insn.decode:149 */ + if (trans_STDZ(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000208: + /* 10.0..1. ....1... */ + /* insn.decode:148 */ + if (trans_STDY(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00009000: + /* 10.1.... ........ */ + switch (insn & 0x00002800) { + case 0x00000000: + /* 10010... ........ */ + switch ((insn >> 9) & 0x3) { + case 0x0: + /* 1001000. ........ */ + switch (insn & 0x0000000f) { + case 0x00000000: + /* 1001000. ....0000 */ + /* insn.decode:130 */ + decode_insn_extract_ldst_s(ctx, &u.f_rd_imm, insn); + if (trans_LDS(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000001: + /* 1001000. ....0001 */ + /* insn.decode:136 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDZ2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000002: + /* 1001000. ....0010 */ + /* insn.decode:137 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDZ3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000004: + /* 1001000. ....0100 */ + /* insn.decode:151 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LPM2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000005: + /* 1001000. ....0101 */ + /* insn.decode:152 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LPMX(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000006: + /* 1001000. ....0110 */ + /* insn.decode:154 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_ELPM2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000007: + /* 1001000. ....0111 */ + /* insn.decode:155 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_ELPMX(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000009: + /* 1001000. ....1001 */ + /* insn.decode:134 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDY2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000a: + /* 1001000. ....1010 */ + /* insn.decode:135 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDY3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000c: + /* 1001000. ....1100 */ + /* insn.decode:131 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDX1(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000d: + /* 1001000. ....1101 */ + /* insn.decode:132 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDX2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000e: + /* 1001000. ....1110 */ + /* insn.decode:133 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDX3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000f: + /* 1001000. ....1111 */ + /* insn.decode:161 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_POP(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x1: + /* 1001001. ........ */ + switch (insn & 0x0000000f) { + case 0x00000000: + /* 1001001. ....0000 */ + /* insn.decode:140 */ + decode_insn_extract_ldst_s(ctx, &u.f_rd_imm, insn); + if (trans_STS(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000001: + /* 1001001. ....0001 */ + /* insn.decode:146 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STZ2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000002: + /* 1001001. ....0010 */ + /* insn.decode:147 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STZ3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000004: + /* 1001001. ....0100 */ + /* insn.decode:162 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_XCH(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000005: + /* 1001001. ....0101 */ + /* insn.decode:164 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LAS(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000006: + /* 1001001. ....0110 */ + /* insn.decode:163 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LAC(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000007: + /* 1001001. ....0111 */ + /* insn.decode:165 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LAT(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000009: + /* 1001001. ....1001 */ + /* insn.decode:144 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STY2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000a: + /* 1001001. ....1010 */ + /* insn.decode:145 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STY3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000c: + /* 1001001. ....1100 */ + /* insn.decode:141 */ + decode_insn_extract_decode_insn_Fmt_18(ctx, &u.f_decode_insn9, insn); + if (trans_STX1(ctx, &u.f_decode_insn9)) return true; + break; + case 0x0000000d: + /* 1001001. ....1101 */ + /* insn.decode:142 */ + decode_insn_extract_decode_insn_Fmt_18(ctx, &u.f_decode_insn9, insn); + if (trans_STX2(ctx, &u.f_decode_insn9)) return true; + break; + case 0x0000000e: + /* 1001001. ....1110 */ + /* insn.decode:143 */ + decode_insn_extract_decode_insn_Fmt_18(ctx, &u.f_decode_insn9, insn); + if (trans_STX3(ctx, &u.f_decode_insn9)) return true; + break; + case 0x0000000f: + /* 1001001. ....1111 */ + /* insn.decode:160 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_PUSH(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x2: + /* 1001010. ........ */ + switch ((insn >> 1) & 0x7) { + case 0x0: + /* 1001010. ....000. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....0000 */ + /* insn.decode:66 */ + if (trans_COM(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....0001 */ + /* insn.decode:67 */ + if (trans_NEG(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x1: + /* 1001010. ....001. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....0010 */ + /* insn.decode:173 */ + if (trans_SWAP(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....0011 */ + /* insn.decode:68 */ + if (trans_INC(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x2: + /* 1001010. ....010. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000001: + /* 1001010. ....0101 */ + /* insn.decode:172 */ + if (trans_ASR(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x3: + /* 1001010. ....011. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....0110 */ + /* insn.decode:170 */ + if (trans_LSR(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....0111 */ + /* insn.decode:171 */ + if (trans_ROR(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x4: + /* 1001010. ....100. */ + switch (insn & 0x00000181) { + case 0x00000000: + /* 10010100 0...1000 */ + /* insn.decode:178 */ + decode_insn_extract_op_bit(ctx, &u.f_decode_insn4, insn); + if (trans_BSET(ctx, &u.f_decode_insn4)) return true; + break; + case 0x00000001: + /* 10010100 0...1001 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010100 00001001 */ + /* insn.decode:91 */ + if (trans_IJMP(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010100 00011001 */ + /* insn.decode:92 */ + if (trans_EIJMP(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x00000080: + /* 10010100 1...1000 */ + /* insn.decode:179 */ + decode_insn_extract_op_bit(ctx, &u.f_decode_insn4, insn); + if (trans_BCLR(ctx, &u.f_decode_insn4)) return true; + break; + case 0x00000100: + /* 10010101 0...1000 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010101 00001000 */ + /* insn.decode:98 */ + if (trans_RET(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010101 00011000 */ + /* insn.decode:99 */ + if (trans_RETI(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x00000101: + /* 10010101 0...1001 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010101 00001001 */ + /* insn.decode:95 */ + if (trans_ICALL(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010101 00011001 */ + /* insn.decode:96 */ + if (trans_EICALL(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x00000180: + /* 10010101 1...1000 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010101 10001000 */ + /* insn.decode:186 */ + if (trans_SLEEP(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010101 10011000 */ + /* insn.decode:184 */ + if (trans_BREAK(ctx, &u.f_decode_insn6)) return true; + break; + case 0x2: + /* 10010101 10101000 */ + /* insn.decode:187 */ + if (trans_WDR(ctx, &u.f_decode_insn6)) return true; + break; + case 0x4: + /* 10010101 11001000 */ + /* insn.decode:150 */ + if (trans_LPM1(ctx, &u.f_decode_insn6)) return true; + break; + case 0x5: + /* 10010101 11011000 */ + /* insn.decode:153 */ + if (trans_ELPM1(ctx, &u.f_decode_insn6)) return true; + break; + case 0x6: + /* 10010101 11101000 */ + /* insn.decode:156 */ + if (trans_SPM(ctx, &u.f_decode_insn6)) return true; + break; + case 0x7: + /* 10010101 11111000 */ + /* insn.decode:157 */ + if (trans_SPMX(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + } + break; + case 0x5: + /* 1001010. ....101. */ + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....1010 */ + /* insn.decode:69 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_DEC(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....1011 */ + decode_insn_extract_decode_insn_Fmt_6(ctx, &u.f_decode_insn3, insn); + switch ((insn >> 8) & 0x1) { + case 0x0: + /* 10010100 ....1011 */ + /* insn.decode:76 */ + if (trans_DES(ctx, &u.f_decode_insn3)) return true; + break; + } + break; + } + break; + case 0x6: + /* 1001010. ....110. */ + /* insn.decode:93 */ + decode_insn_extract_decode_insn_Fmt_11(ctx, &u.f_decode_insn3, insn); + if (trans_JMP(ctx, &u.f_decode_insn3)) return true; + break; + case 0x7: + /* 1001010. ....111. */ + /* insn.decode:97 */ + decode_insn_extract_decode_insn_Fmt_11(ctx, &u.f_decode_insn3, insn); + if (trans_CALL(ctx, &u.f_decode_insn3)) return true; + break; + } + break; + case 0x3: + /* 1001011. ........ */ + decode_insn_extract_op_rd_imm6(ctx, &u.f_rd_imm, insn); + switch ((insn >> 8) & 0x1) { + case 0x0: + /* 10010110 ........ */ + /* insn.decode:55 */ + if (trans_ADIW(ctx, &u.f_rd_imm)) return true; + break; + case 0x1: + /* 10010111 ........ */ + /* insn.decode:60 */ + if (trans_SBIW(ctx, &u.f_rd_imm)) return true; + break; + } + break; + } + break; + case 0x00000800: + /* 10011... ........ */ + switch ((insn >> 10) & 0x1) { + case 0x0: + /* 100110.. ........ */ + decode_insn_extract_decode_insn_Fmt_13(ctx, &u.f_decode_insn8, insn); + switch ((insn >> 8) & 0x3) { + case 0x0: + /* 10011000 ........ */ + /* insn.decode:175 */ + if (trans_CBI(ctx, &u.f_decode_insn8)) return true; + break; + case 0x1: + /* 10011001 ........ */ + /* insn.decode:106 */ + if (trans_SBIC(ctx, &u.f_decode_insn8)) return true; + break; + case 0x2: + /* 10011010 ........ */ + /* insn.decode:174 */ + if (trans_SBI(ctx, &u.f_decode_insn8)) return true; + break; + case 0x3: + /* 10011011 ........ */ + /* insn.decode:107 */ + if (trans_SBIS(ctx, &u.f_decode_insn8)) return true; + break; + } + break; + case 0x1: + /* 100111.. ........ */ + /* insn.decode:70 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_MUL(ctx, &u.f_rd_rr)) return true; + break; + } + break; + case 0x00002000: + /* 10110... ........ */ + /* insn.decode:158 */ + decode_insn_extract_io_rd_imm(ctx, &u.f_rd_imm, insn); + if (trans_IN(ctx, &u.f_rd_imm)) return true; + break; + case 0x00002800: + /* 10111... ........ */ + /* insn.decode:159 */ + decode_insn_extract_io_rd_imm(ctx, &u.f_rd_imm, insn); + if (trans_OUT(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x0000c000: + /* 11.0.... ........ */ + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 1100.... ........ */ + /* insn.decode:90 */ + decode_insn_extract_decode_insn_Fmt_9(ctx, &u.f_decode_insn3, insn); + if (trans_RJMP(ctx, &u.f_decode_insn3)) return true; + break; + case 0x1: + /* 1110.... ........ */ + /* insn.decode:129 */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + if (trans_LDI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x0000d000: + /* 11.1.... ........ */ + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 1101.... ........ */ + /* insn.decode:94 */ + decode_insn_extract_decode_insn_Fmt_9(ctx, &u.f_decode_insn3, insn); + if (trans_RCALL(ctx, &u.f_decode_insn3)) return true; + break; + case 0x1: + /* 1111.... ........ */ + switch ((insn >> 10) & 0x3) { + case 0x0: + /* 111100.. ........ */ + /* insn.decode:108 */ + decode_insn_extract_op_bit_imm(ctx, &u.f_decode_insn5, insn); + if (trans_BRBS(ctx, &u.f_decode_insn5)) return true; + break; + case 0x1: + /* 111101.. ........ */ + /* insn.decode:109 */ + decode_insn_extract_op_bit_imm(ctx, &u.f_decode_insn5, insn); + if (trans_BRBC(ctx, &u.f_decode_insn5)) return true; + break; + case 0x2: + /* 111110.. ........ */ + decode_insn_extract_decode_insn_Fmt_19(ctx, &u.f_decode_insn10, insn); + switch (insn & 0x00000208) { + case 0x00000000: + /* 1111100. ....0... */ + /* insn.decode:177 */ + if (trans_BLD(ctx, &u.f_decode_insn10)) return true; + break; + case 0x00000200: + /* 1111101. ....0... */ + /* insn.decode:176 */ + if (trans_BST(ctx, &u.f_decode_insn10)) return true; + break; + } + break; + case 0x3: + /* 111111.. ........ */ + decode_insn_extract_decode_insn_Fmt_12(ctx, &u.f_decode_insn7, insn); + switch (insn & 0x00000208) { + case 0x00000000: + /* 1111110. ....0... */ + /* insn.decode:104 */ + if (trans_SBRC(ctx, &u.f_decode_insn7)) return true; + break; + case 0x00000200: + /* 1111111. ....0... */ + /* insn.decode:105 */ + if (trans_SBRS(ctx, &u.f_decode_insn7)) return true; + break; + } + break; + } + break; + } + break; + } + return false; +} From 4c466b9f28cd10fccaa533b2f3aa8a60f80bbe3c Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Thu, 28 Mar 2024 12:45:18 +0100 Subject: [PATCH 08/31] qemu/target/avr: pregenerate overrides (extern symbols). Signed-off-by: Glenn Baker --- qemu/avr.h | 1291 ++++++++++++++++++++++++++++++++++++++++++++++++++++ symbols.sh | 16 +- 2 files changed, 1306 insertions(+), 1 deletion(-) create mode 100644 qemu/avr.h diff --git a/qemu/avr.h b/qemu/avr.h new file mode 100644 index 0000000000..a3748edd2f --- /dev/null +++ b/qemu/avr.h @@ -0,0 +1,1291 @@ +/* Autogen header for Unicorn Engine - DONOT MODIFY */ +#ifndef UNICORN_AUTOGEN_avr_H +#define UNICORN_AUTOGEN_avr_H +#ifndef UNICORN_ARCH_POSTFIX +#define UNICORN_ARCH_POSTFIX _avr +#endif +#define uc_add_inline_hook uc_add_inline_hook_avr +#define uc_del_inline_hook uc_del_inline_hook_avr +#define tb_invalidate_phys_range tb_invalidate_phys_range_avr +#define use_idiv_instructions use_idiv_instructions_avr +#define arm_arch arm_arch_avr +#define tb_target_set_jmp_target tb_target_set_jmp_target_avr +#define have_bmi1 have_bmi1_avr +#define have_popcnt have_popcnt_avr +#define have_avx1 have_avx1_avr +#define have_avx2 have_avx2_avr +#define have_isa have_isa_avr +#define have_altivec have_altivec_avr +#define have_vsx have_vsx_avr +#define flush_icache_range flush_icache_range_avr +#define s390_facilities s390_facilities_avr +#define tcg_dump_op tcg_dump_op_avr +#define tcg_dump_ops tcg_dump_ops_avr +#define tcg_gen_and_i64 tcg_gen_and_i64_avr +#define tcg_gen_discard_i64 tcg_gen_discard_i64_avr +#define tcg_gen_ld16s_i64 tcg_gen_ld16s_i64_avr +#define tcg_gen_ld16u_i64 tcg_gen_ld16u_i64_avr +#define tcg_gen_ld32s_i64 tcg_gen_ld32s_i64_avr +#define tcg_gen_ld32u_i64 tcg_gen_ld32u_i64_avr +#define tcg_gen_ld8s_i64 tcg_gen_ld8s_i64_avr +#define tcg_gen_ld8u_i64 tcg_gen_ld8u_i64_avr +#define tcg_gen_ld_i64 tcg_gen_ld_i64_avr +#define tcg_gen_mov_i64 tcg_gen_mov_i64_avr +#define tcg_gen_movi_i64 tcg_gen_movi_i64_avr +#define tcg_gen_mul_i64 tcg_gen_mul_i64_avr +#define tcg_gen_or_i64 tcg_gen_or_i64_avr +#define tcg_gen_sar_i64 tcg_gen_sar_i64_avr +#define tcg_gen_shl_i64 tcg_gen_shl_i64_avr +#define tcg_gen_shr_i64 tcg_gen_shr_i64_avr +#define tcg_gen_st_i64 tcg_gen_st_i64_avr +#define tcg_gen_xor_i64 tcg_gen_xor_i64_avr +#define cpu_icount_to_ns cpu_icount_to_ns_avr +#define cpu_is_stopped cpu_is_stopped_avr +#define cpu_get_ticks cpu_get_ticks_avr +#define cpu_get_clock cpu_get_clock_avr +#define cpu_resume cpu_resume_avr +#define qemu_init_vcpu qemu_init_vcpu_avr +#define cpu_stop_current cpu_stop_current_avr +#define resume_all_vcpus resume_all_vcpus_avr +#define vm_start vm_start_avr +#define address_space_dispatch_compact address_space_dispatch_compact_avr +#define flatview_translate flatview_translate_avr +#define address_space_translate_for_iotlb address_space_translate_for_iotlb_avr +#define qemu_get_cpu qemu_get_cpu_avr +#define cpu_address_space_init cpu_address_space_init_avr +#define cpu_get_address_space cpu_get_address_space_avr +#define cpu_exec_unrealizefn cpu_exec_unrealizefn_avr +#define cpu_exec_initfn cpu_exec_initfn_avr +#define cpu_exec_realizefn cpu_exec_realizefn_avr +#define tb_invalidate_phys_addr tb_invalidate_phys_addr_avr +#define cpu_watchpoint_insert cpu_watchpoint_insert_avr +#define cpu_watchpoint_remove_by_ref cpu_watchpoint_remove_by_ref_avr +#define cpu_watchpoint_remove_all cpu_watchpoint_remove_all_avr +#define cpu_watchpoint_address_matches cpu_watchpoint_address_matches_avr +#define cpu_breakpoint_insert cpu_breakpoint_insert_avr +#define cpu_breakpoint_remove cpu_breakpoint_remove_avr +#define cpu_breakpoint_remove_by_ref cpu_breakpoint_remove_by_ref_avr +#define cpu_breakpoint_remove_all cpu_breakpoint_remove_all_avr +#define cpu_abort cpu_abort_avr +#define cpu_physical_memory_test_and_clear_dirty cpu_physical_memory_test_and_clear_dirty_avr +#define memory_region_section_get_iotlb memory_region_section_get_iotlb_avr +#define flatview_add_to_dispatch flatview_add_to_dispatch_avr +#define qemu_ram_get_host_addr qemu_ram_get_host_addr_avr +#define qemu_ram_get_offset qemu_ram_get_offset_avr +#define qemu_ram_get_used_length qemu_ram_get_used_length_avr +#define qemu_ram_is_shared qemu_ram_is_shared_avr +#define qemu_ram_pagesize qemu_ram_pagesize_avr +#define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_avr +#define qemu_ram_alloc qemu_ram_alloc_avr +#define qemu_ram_free qemu_ram_free_avr +#define qemu_map_ram_ptr qemu_map_ram_ptr_avr +#define qemu_ram_block_host_offset qemu_ram_block_host_offset_avr +#define qemu_ram_block_from_host qemu_ram_block_from_host_avr +#define qemu_ram_addr_from_host qemu_ram_addr_from_host_avr +#define cpu_check_watchpoint cpu_check_watchpoint_avr +#define iotlb_to_section iotlb_to_section_avr +#define address_space_dispatch_new address_space_dispatch_new_avr +#define address_space_dispatch_free address_space_dispatch_free_avr +#define flatview_read_continue flatview_read_continue_avr +#define address_space_read_full address_space_read_full_avr +#define address_space_write address_space_write_avr +#define address_space_rw address_space_rw_avr +#define cpu_physical_memory_rw cpu_physical_memory_rw_avr +#define address_space_write_rom address_space_write_rom_avr +#define cpu_flush_icache_range cpu_flush_icache_range_avr +#define cpu_exec_init_all cpu_exec_init_all_avr +#define address_space_access_valid address_space_access_valid_avr +#define address_space_map address_space_map_avr +#define address_space_unmap address_space_unmap_avr +#define cpu_physical_memory_map cpu_physical_memory_map_avr +#define cpu_physical_memory_unmap cpu_physical_memory_unmap_avr +#define cpu_memory_rw_debug cpu_memory_rw_debug_avr +#define qemu_target_page_size qemu_target_page_size_avr +#define qemu_target_page_bits qemu_target_page_bits_avr +#define qemu_target_page_bits_min qemu_target_page_bits_min_avr +#define target_words_bigendian target_words_bigendian_avr +#define cpu_physical_memory_is_io cpu_physical_memory_is_io_avr +#define ram_block_discard_range ram_block_discard_range_avr +#define ramblock_is_pmem ramblock_is_pmem_avr +#define page_size_init page_size_init_avr +#define set_preferred_target_page_bits set_preferred_target_page_bits_avr +#define finalize_target_page_bits finalize_target_page_bits_avr +#define cpu_outb cpu_outb_avr +#define cpu_outw cpu_outw_avr +#define cpu_outl cpu_outl_avr +#define cpu_inb cpu_inb_avr +#define cpu_inw cpu_inw_avr +#define cpu_inl cpu_inl_avr +#define memory_map memory_map_avr +#define memory_map_io memory_map_io_avr +#define memory_map_ptr memory_map_ptr_avr +#define memory_unmap memory_unmap_avr +#define memory_free memory_free_avr +#define flatview_unref flatview_unref_avr +#define address_space_get_flatview address_space_get_flatview_avr +#define memory_region_transaction_begin memory_region_transaction_begin_avr +#define memory_region_transaction_commit memory_region_transaction_commit_avr +#define memory_region_init memory_region_init_avr +#define memory_region_access_valid memory_region_access_valid_avr +#define memory_region_dispatch_read memory_region_dispatch_read_avr +#define memory_region_dispatch_write memory_region_dispatch_write_avr +#define memory_region_init_io memory_region_init_io_avr +#define memory_region_init_ram_ptr memory_region_init_ram_ptr_avr +#define memory_region_size memory_region_size_avr +#define memory_region_set_readonly memory_region_set_readonly_avr +#define memory_region_get_ram_ptr memory_region_get_ram_ptr_avr +#define memory_region_from_host memory_region_from_host_avr +#define memory_region_get_ram_addr memory_region_get_ram_addr_avr +#define memory_region_add_subregion memory_region_add_subregion_avr +#define memory_region_del_subregion memory_region_del_subregion_avr +#define memory_region_find memory_region_find_avr +#define memory_listener_register memory_listener_register_avr +#define memory_listener_unregister memory_listener_unregister_avr +#define address_space_remove_listeners address_space_remove_listeners_avr +#define address_space_init address_space_init_avr +#define address_space_destroy address_space_destroy_avr +#define memory_region_init_ram memory_region_init_ram_avr +#define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_avr +#define exec_inline_op exec_inline_op_avr +#define floatx80_default_nan floatx80_default_nan_avr +#define float_raise float_raise_avr +#define float16_is_quiet_nan float16_is_quiet_nan_avr +#define float16_is_signaling_nan float16_is_signaling_nan_avr +#define float32_is_quiet_nan float32_is_quiet_nan_avr +#define float32_is_signaling_nan float32_is_signaling_nan_avr +#define float64_is_quiet_nan float64_is_quiet_nan_avr +#define float64_is_signaling_nan float64_is_signaling_nan_avr +#define floatx80_is_quiet_nan floatx80_is_quiet_nan_avr +#define floatx80_is_signaling_nan floatx80_is_signaling_nan_avr +#define floatx80_silence_nan floatx80_silence_nan_avr +#define propagateFloatx80NaN propagateFloatx80NaN_avr +#define float128_is_quiet_nan float128_is_quiet_nan_avr +#define float128_is_signaling_nan float128_is_signaling_nan_avr +#define float128_silence_nan float128_silence_nan_avr +#define float16_add float16_add_avr +#define float16_sub float16_sub_avr +#define float32_add float32_add_avr +#define float32_sub float32_sub_avr +#define float64_add float64_add_avr +#define float64_sub float64_sub_avr +#define float16_mul float16_mul_avr +#define float32_mul float32_mul_avr +#define float64_mul float64_mul_avr +#define float16_muladd float16_muladd_avr +#define float32_muladd float32_muladd_avr +#define float64_muladd float64_muladd_avr +#define float16_div float16_div_avr +#define float32_div float32_div_avr +#define float64_div float64_div_avr +#define float16_to_float32 float16_to_float32_avr +#define float16_to_float64 float16_to_float64_avr +#define float32_to_float16 float32_to_float16_avr +#define float32_to_float64 float32_to_float64_avr +#define float64_to_float16 float64_to_float16_avr +#define float64_to_float32 float64_to_float32_avr +#define float16_round_to_int float16_round_to_int_avr +#define float32_round_to_int float32_round_to_int_avr +#define float64_round_to_int float64_round_to_int_avr +#define float16_to_int16_scalbn float16_to_int16_scalbn_avr +#define float16_to_int32_scalbn float16_to_int32_scalbn_avr +#define float16_to_int64_scalbn float16_to_int64_scalbn_avr +#define float32_to_int16_scalbn float32_to_int16_scalbn_avr +#define float32_to_int32_scalbn float32_to_int32_scalbn_avr +#define float32_to_int64_scalbn float32_to_int64_scalbn_avr +#define float64_to_int16_scalbn float64_to_int16_scalbn_avr +#define float64_to_int32_scalbn float64_to_int32_scalbn_avr +#define float64_to_int64_scalbn float64_to_int64_scalbn_avr +#define float16_to_int16 float16_to_int16_avr +#define float16_to_int32 float16_to_int32_avr +#define float16_to_int64 float16_to_int64_avr +#define float32_to_int16 float32_to_int16_avr +#define float32_to_int32 float32_to_int32_avr +#define float32_to_int64 float32_to_int64_avr +#define float64_to_int16 float64_to_int16_avr +#define float64_to_int32 float64_to_int32_avr +#define float64_to_int64 float64_to_int64_avr +#define float16_to_int16_round_to_zero float16_to_int16_round_to_zero_avr +#define float16_to_int32_round_to_zero float16_to_int32_round_to_zero_avr +#define float16_to_int64_round_to_zero float16_to_int64_round_to_zero_avr +#define float32_to_int16_round_to_zero float32_to_int16_round_to_zero_avr +#define float32_to_int32_round_to_zero float32_to_int32_round_to_zero_avr +#define float32_to_int64_round_to_zero float32_to_int64_round_to_zero_avr +#define float64_to_int16_round_to_zero float64_to_int16_round_to_zero_avr +#define float64_to_int32_round_to_zero float64_to_int32_round_to_zero_avr +#define float64_to_int64_round_to_zero float64_to_int64_round_to_zero_avr +#define float16_to_uint16_scalbn float16_to_uint16_scalbn_avr +#define float16_to_uint32_scalbn float16_to_uint32_scalbn_avr +#define float16_to_uint64_scalbn float16_to_uint64_scalbn_avr +#define float32_to_uint16_scalbn float32_to_uint16_scalbn_avr +#define float32_to_uint32_scalbn float32_to_uint32_scalbn_avr +#define float32_to_uint64_scalbn float32_to_uint64_scalbn_avr +#define float64_to_uint16_scalbn float64_to_uint16_scalbn_avr +#define float64_to_uint32_scalbn float64_to_uint32_scalbn_avr +#define float64_to_uint64_scalbn float64_to_uint64_scalbn_avr +#define float16_to_uint16 float16_to_uint16_avr +#define float16_to_uint32 float16_to_uint32_avr +#define float16_to_uint64 float16_to_uint64_avr +#define float32_to_uint16 float32_to_uint16_avr +#define float32_to_uint32 float32_to_uint32_avr +#define float32_to_uint64 float32_to_uint64_avr +#define float64_to_uint16 float64_to_uint16_avr +#define float64_to_uint32 float64_to_uint32_avr +#define float64_to_uint64 float64_to_uint64_avr +#define float16_to_uint16_round_to_zero float16_to_uint16_round_to_zero_avr +#define float16_to_uint32_round_to_zero float16_to_uint32_round_to_zero_avr +#define float16_to_uint64_round_to_zero float16_to_uint64_round_to_zero_avr +#define float32_to_uint16_round_to_zero float32_to_uint16_round_to_zero_avr +#define float32_to_uint32_round_to_zero float32_to_uint32_round_to_zero_avr +#define float32_to_uint64_round_to_zero float32_to_uint64_round_to_zero_avr +#define float64_to_uint16_round_to_zero float64_to_uint16_round_to_zero_avr +#define float64_to_uint32_round_to_zero float64_to_uint32_round_to_zero_avr +#define float64_to_uint64_round_to_zero float64_to_uint64_round_to_zero_avr +#define int64_to_float16_scalbn int64_to_float16_scalbn_avr +#define int32_to_float16_scalbn int32_to_float16_scalbn_avr +#define int16_to_float16_scalbn int16_to_float16_scalbn_avr +#define int64_to_float16 int64_to_float16_avr +#define int32_to_float16 int32_to_float16_avr +#define int16_to_float16 int16_to_float16_avr +#define int64_to_float32_scalbn int64_to_float32_scalbn_avr +#define int32_to_float32_scalbn int32_to_float32_scalbn_avr +#define int16_to_float32_scalbn int16_to_float32_scalbn_avr +#define int64_to_float32 int64_to_float32_avr +#define int32_to_float32 int32_to_float32_avr +#define int16_to_float32 int16_to_float32_avr +#define int64_to_float64_scalbn int64_to_float64_scalbn_avr +#define int32_to_float64_scalbn int32_to_float64_scalbn_avr +#define int16_to_float64_scalbn int16_to_float64_scalbn_avr +#define int64_to_float64 int64_to_float64_avr +#define int32_to_float64 int32_to_float64_avr +#define int16_to_float64 int16_to_float64_avr +#define uint64_to_float16_scalbn uint64_to_float16_scalbn_avr +#define uint32_to_float16_scalbn uint32_to_float16_scalbn_avr +#define uint16_to_float16_scalbn uint16_to_float16_scalbn_avr +#define uint64_to_float16 uint64_to_float16_avr +#define uint32_to_float16 uint32_to_float16_avr +#define uint16_to_float16 uint16_to_float16_avr +#define uint64_to_float32_scalbn uint64_to_float32_scalbn_avr +#define uint32_to_float32_scalbn uint32_to_float32_scalbn_avr +#define uint16_to_float32_scalbn uint16_to_float32_scalbn_avr +#define uint64_to_float32 uint64_to_float32_avr +#define uint32_to_float32 uint32_to_float32_avr +#define uint16_to_float32 uint16_to_float32_avr +#define uint64_to_float64_scalbn uint64_to_float64_scalbn_avr +#define uint32_to_float64_scalbn uint32_to_float64_scalbn_avr +#define uint16_to_float64_scalbn uint16_to_float64_scalbn_avr +#define uint64_to_float64 uint64_to_float64_avr +#define uint32_to_float64 uint32_to_float64_avr +#define uint16_to_float64 uint16_to_float64_avr +#define float16_min float16_min_avr +#define float16_minnum float16_minnum_avr +#define float16_minnummag float16_minnummag_avr +#define float16_max float16_max_avr +#define float16_maxnum float16_maxnum_avr +#define float16_maxnummag float16_maxnummag_avr +#define float32_min float32_min_avr +#define float32_minnum float32_minnum_avr +#define float32_minnummag float32_minnummag_avr +#define float32_max float32_max_avr +#define float32_maxnum float32_maxnum_avr +#define float32_maxnummag float32_maxnummag_avr +#define float64_min float64_min_avr +#define float64_minnum float64_minnum_avr +#define float64_minnummag float64_minnummag_avr +#define float64_max float64_max_avr +#define float64_maxnum float64_maxnum_avr +#define float64_maxnummag float64_maxnummag_avr +#define float16_compare float16_compare_avr +#define float16_compare_quiet float16_compare_quiet_avr +#define float32_compare float32_compare_avr +#define float32_compare_quiet float32_compare_quiet_avr +#define float64_compare float64_compare_avr +#define float64_compare_quiet float64_compare_quiet_avr +#define float16_scalbn float16_scalbn_avr +#define float32_scalbn float32_scalbn_avr +#define float64_scalbn float64_scalbn_avr +#define float16_sqrt float16_sqrt_avr +#define float32_sqrt float32_sqrt_avr +#define float64_sqrt float64_sqrt_avr +#define float16_default_nan float16_default_nan_avr +#define float32_default_nan float32_default_nan_avr +#define float64_default_nan float64_default_nan_avr +#define float128_default_nan float128_default_nan_avr +#define float16_silence_nan float16_silence_nan_avr +#define float32_silence_nan float32_silence_nan_avr +#define float64_silence_nan float64_silence_nan_avr +#define float16_squash_input_denormal float16_squash_input_denormal_avr +#define float32_squash_input_denormal float32_squash_input_denormal_avr +#define float64_squash_input_denormal float64_squash_input_denormal_avr +#define normalizeFloatx80Subnormal normalizeFloatx80Subnormal_avr +#define roundAndPackFloatx80 roundAndPackFloatx80_avr +#define normalizeRoundAndPackFloatx80 normalizeRoundAndPackFloatx80_avr +#define int32_to_floatx80 int32_to_floatx80_avr +#define int32_to_float128 int32_to_float128_avr +#define int64_to_floatx80 int64_to_floatx80_avr +#define int64_to_float128 int64_to_float128_avr +#define uint64_to_float128 uint64_to_float128_avr +#define float32_to_floatx80 float32_to_floatx80_avr +#define float32_to_float128 float32_to_float128_avr +#define float32_rem float32_rem_avr +#define float32_exp2 float32_exp2_avr +#define float32_log2 float32_log2_avr +#define float32_eq float32_eq_avr +#define float32_le float32_le_avr +#define float32_lt float32_lt_avr +#define float32_unordered float32_unordered_avr +#define float32_eq_quiet float32_eq_quiet_avr +#define float32_le_quiet float32_le_quiet_avr +#define float32_lt_quiet float32_lt_quiet_avr +#define float32_unordered_quiet float32_unordered_quiet_avr +#define float64_to_floatx80 float64_to_floatx80_avr +#define float64_to_float128 float64_to_float128_avr +#define float64_rem float64_rem_avr +#define float64_log2 float64_log2_avr +#define float64_eq float64_eq_avr +#define float64_le float64_le_avr +#define float64_lt float64_lt_avr +#define float64_unordered float64_unordered_avr +#define float64_eq_quiet float64_eq_quiet_avr +#define float64_le_quiet float64_le_quiet_avr +#define float64_lt_quiet float64_lt_quiet_avr +#define float64_unordered_quiet float64_unordered_quiet_avr +#define floatx80_to_int32 floatx80_to_int32_avr +#define floatx80_to_int32_round_to_zero floatx80_to_int32_round_to_zero_avr +#define floatx80_to_int64 floatx80_to_int64_avr +#define floatx80_to_int64_round_to_zero floatx80_to_int64_round_to_zero_avr +#define floatx80_to_float32 floatx80_to_float32_avr +#define floatx80_to_float64 floatx80_to_float64_avr +#define floatx80_to_float128 floatx80_to_float128_avr +#define floatx80_round floatx80_round_avr +#define floatx80_round_to_int floatx80_round_to_int_avr +#define floatx80_add floatx80_add_avr +#define floatx80_sub floatx80_sub_avr +#define floatx80_mul floatx80_mul_avr +#define floatx80_div floatx80_div_avr +#define floatx80_rem floatx80_rem_avr +#define floatx80_sqrt floatx80_sqrt_avr +#define floatx80_eq floatx80_eq_avr +#define floatx80_le floatx80_le_avr +#define floatx80_lt floatx80_lt_avr +#define floatx80_unordered floatx80_unordered_avr +#define floatx80_eq_quiet floatx80_eq_quiet_avr +#define floatx80_le_quiet floatx80_le_quiet_avr +#define floatx80_lt_quiet floatx80_lt_quiet_avr +#define floatx80_unordered_quiet floatx80_unordered_quiet_avr +#define float128_to_int32 float128_to_int32_avr +#define float128_to_int32_round_to_zero float128_to_int32_round_to_zero_avr +#define float128_to_int64 float128_to_int64_avr +#define float128_to_int64_round_to_zero float128_to_int64_round_to_zero_avr +#define float128_to_uint64 float128_to_uint64_avr +#define float128_to_uint64_round_to_zero float128_to_uint64_round_to_zero_avr +#define float128_to_uint32_round_to_zero float128_to_uint32_round_to_zero_avr +#define float128_to_uint32 float128_to_uint32_avr +#define float128_to_float32 float128_to_float32_avr +#define float128_to_float64 float128_to_float64_avr +#define float128_to_floatx80 float128_to_floatx80_avr +#define float128_round_to_int float128_round_to_int_avr +#define float128_add float128_add_avr +#define float128_sub float128_sub_avr +#define float128_mul float128_mul_avr +#define float128_div float128_div_avr +#define float128_rem float128_rem_avr +#define float128_sqrt float128_sqrt_avr +#define float128_eq float128_eq_avr +#define float128_le float128_le_avr +#define float128_lt float128_lt_avr +#define float128_unordered float128_unordered_avr +#define float128_eq_quiet float128_eq_quiet_avr +#define float128_le_quiet float128_le_quiet_avr +#define float128_lt_quiet float128_lt_quiet_avr +#define float128_unordered_quiet float128_unordered_quiet_avr +#define floatx80_compare floatx80_compare_avr +#define floatx80_compare_quiet floatx80_compare_quiet_avr +#define float128_compare float128_compare_avr +#define float128_compare_quiet float128_compare_quiet_avr +#define floatx80_scalbn floatx80_scalbn_avr +#define float128_scalbn float128_scalbn_avr +#define softfloat_init softfloat_init_avr +#define tcg_optimize tcg_optimize_avr +#define gen_new_label gen_new_label_avr +#define tcg_can_emit_vec_op tcg_can_emit_vec_op_avr +#define tcg_expand_vec_op tcg_expand_vec_op_avr +#define tcg_register_jit tcg_register_jit_avr +#define tcg_tb_insert tcg_tb_insert_avr +#define tcg_tb_remove tcg_tb_remove_avr +#define tcg_tb_lookup tcg_tb_lookup_avr +#define tcg_tb_foreach tcg_tb_foreach_avr +#define tcg_nb_tbs tcg_nb_tbs_avr +#define tcg_region_reset_all tcg_region_reset_all_avr +#define tcg_region_init tcg_region_init_avr +#define tcg_code_size tcg_code_size_avr +#define tcg_code_capacity tcg_code_capacity_avr +#define tcg_tb_phys_invalidate_count tcg_tb_phys_invalidate_count_avr +#define tcg_malloc_internal tcg_malloc_internal_avr +#define tcg_pool_reset tcg_pool_reset_avr +#define tcg_context_init tcg_context_init_avr +#define tcg_tb_alloc tcg_tb_alloc_avr +#define tcg_prologue_init tcg_prologue_init_avr +#define tcg_func_start tcg_func_start_avr +#define tcg_set_frame tcg_set_frame_avr +#define tcg_global_mem_new_internal tcg_global_mem_new_internal_avr +#define tcg_temp_new_internal tcg_temp_new_internal_avr +#define tcg_temp_new_vec tcg_temp_new_vec_avr +#define tcg_temp_new_vec_matching tcg_temp_new_vec_matching_avr +#define tcg_temp_free_internal tcg_temp_free_internal_avr +#define tcg_const_i32 tcg_const_i32_avr +#define tcg_const_i64 tcg_const_i64_avr +#define tcg_const_local_i32 tcg_const_local_i32_avr +#define tcg_const_local_i64 tcg_const_local_i64_avr +#define tcg_op_supported tcg_op_supported_avr +#define tcg_gen_callN tcg_gen_callN_avr +#define tcg_op_remove tcg_op_remove_avr +#define tcg_emit_op tcg_emit_op_avr +#define tcg_op_insert_before tcg_op_insert_before_avr +#define tcg_op_insert_after tcg_op_insert_after_avr +#define tcg_cpu_exec_time tcg_cpu_exec_time_avr +#define tcg_gen_code tcg_gen_code_avr +#define tcg_gen_op1 tcg_gen_op1_avr +#define tcg_gen_op2 tcg_gen_op2_avr +#define tcg_gen_op3 tcg_gen_op3_avr +#define tcg_gen_op4 tcg_gen_op4_avr +#define tcg_gen_op5 tcg_gen_op5_avr +#define tcg_gen_op6 tcg_gen_op6_avr +#define tcg_gen_mb tcg_gen_mb_avr +#define tcg_gen_addi_i32 tcg_gen_addi_i32_avr +#define tcg_gen_subfi_i32 tcg_gen_subfi_i32_avr +#define tcg_gen_subi_i32 tcg_gen_subi_i32_avr +#define tcg_gen_andi_i32 tcg_gen_andi_i32_avr +#define tcg_gen_ori_i32 tcg_gen_ori_i32_avr +#define tcg_gen_xori_i32 tcg_gen_xori_i32_avr +#define tcg_gen_shli_i32 tcg_gen_shli_i32_avr +#define tcg_gen_shri_i32 tcg_gen_shri_i32_avr +#define tcg_gen_sari_i32 tcg_gen_sari_i32_avr +#define tcg_gen_brcond_i32 tcg_gen_brcond_i32_avr +#define tcg_gen_brcondi_i32 tcg_gen_brcondi_i32_avr +#define tcg_gen_setcond_i32 tcg_gen_setcond_i32_avr +#define tcg_gen_setcondi_i32 tcg_gen_setcondi_i32_avr +#define tcg_gen_muli_i32 tcg_gen_muli_i32_avr +#define tcg_gen_div_i32 tcg_gen_div_i32_avr +#define tcg_gen_rem_i32 tcg_gen_rem_i32_avr +#define tcg_gen_divu_i32 tcg_gen_divu_i32_avr +#define tcg_gen_remu_i32 tcg_gen_remu_i32_avr +#define tcg_gen_andc_i32 tcg_gen_andc_i32_avr +#define tcg_gen_eqv_i32 tcg_gen_eqv_i32_avr +#define tcg_gen_nand_i32 tcg_gen_nand_i32_avr +#define tcg_gen_nor_i32 tcg_gen_nor_i32_avr +#define tcg_gen_orc_i32 tcg_gen_orc_i32_avr +#define tcg_gen_clz_i32 tcg_gen_clz_i32_avr +#define tcg_gen_clzi_i32 tcg_gen_clzi_i32_avr +#define tcg_gen_ctz_i32 tcg_gen_ctz_i32_avr +#define tcg_gen_ctzi_i32 tcg_gen_ctzi_i32_avr +#define tcg_gen_clrsb_i32 tcg_gen_clrsb_i32_avr +#define tcg_gen_ctpop_i32 tcg_gen_ctpop_i32_avr +#define tcg_gen_rotl_i32 tcg_gen_rotl_i32_avr +#define tcg_gen_rotli_i32 tcg_gen_rotli_i32_avr +#define tcg_gen_rotr_i32 tcg_gen_rotr_i32_avr +#define tcg_gen_rotri_i32 tcg_gen_rotri_i32_avr +#define tcg_gen_deposit_i32 tcg_gen_deposit_i32_avr +#define tcg_gen_deposit_z_i32 tcg_gen_deposit_z_i32_avr +#define tcg_gen_extract_i32 tcg_gen_extract_i32_avr +#define tcg_gen_sextract_i32 tcg_gen_sextract_i32_avr +#define tcg_gen_extract2_i32 tcg_gen_extract2_i32_avr +#define tcg_gen_movcond_i32 tcg_gen_movcond_i32_avr +#define tcg_gen_add2_i32 tcg_gen_add2_i32_avr +#define tcg_gen_sub2_i32 tcg_gen_sub2_i32_avr +#define tcg_gen_mulu2_i32 tcg_gen_mulu2_i32_avr +#define tcg_gen_muls2_i32 tcg_gen_muls2_i32_avr +#define tcg_gen_mulsu2_i32 tcg_gen_mulsu2_i32_avr +#define tcg_gen_ext8s_i32 tcg_gen_ext8s_i32_avr +#define tcg_gen_ext16s_i32 tcg_gen_ext16s_i32_avr +#define tcg_gen_ext8u_i32 tcg_gen_ext8u_i32_avr +#define tcg_gen_ext16u_i32 tcg_gen_ext16u_i32_avr +#define tcg_gen_bswap16_i32 tcg_gen_bswap16_i32_avr +#define tcg_gen_bswap32_i32 tcg_gen_bswap32_i32_avr +#define tcg_gen_smin_i32 tcg_gen_smin_i32_avr +#define tcg_gen_umin_i32 tcg_gen_umin_i32_avr +#define tcg_gen_smax_i32 tcg_gen_smax_i32_avr +#define tcg_gen_umax_i32 tcg_gen_umax_i32_avr +#define tcg_gen_abs_i32 tcg_gen_abs_i32_avr +#define tcg_gen_addi_i64 tcg_gen_addi_i64_avr +#define tcg_gen_subfi_i64 tcg_gen_subfi_i64_avr +#define tcg_gen_subi_i64 tcg_gen_subi_i64_avr +#define tcg_gen_andi_i64 tcg_gen_andi_i64_avr +#define tcg_gen_ori_i64 tcg_gen_ori_i64_avr +#define tcg_gen_xori_i64 tcg_gen_xori_i64_avr +#define tcg_gen_shli_i64 tcg_gen_shli_i64_avr +#define tcg_gen_shri_i64 tcg_gen_shri_i64_avr +#define tcg_gen_sari_i64 tcg_gen_sari_i64_avr +#define tcg_gen_brcond_i64 tcg_gen_brcond_i64_avr +#define tcg_gen_brcondi_i64 tcg_gen_brcondi_i64_avr +#define tcg_gen_setcond_i64 tcg_gen_setcond_i64_avr +#define tcg_gen_setcondi_i64 tcg_gen_setcondi_i64_avr +#define tcg_gen_muli_i64 tcg_gen_muli_i64_avr +#define tcg_gen_div_i64 tcg_gen_div_i64_avr +#define tcg_gen_rem_i64 tcg_gen_rem_i64_avr +#define tcg_gen_divu_i64 tcg_gen_divu_i64_avr +#define tcg_gen_remu_i64 tcg_gen_remu_i64_avr +#define tcg_gen_ext8s_i64 tcg_gen_ext8s_i64_avr +#define tcg_gen_ext16s_i64 tcg_gen_ext16s_i64_avr +#define tcg_gen_ext32s_i64 tcg_gen_ext32s_i64_avr +#define tcg_gen_ext8u_i64 tcg_gen_ext8u_i64_avr +#define tcg_gen_ext16u_i64 tcg_gen_ext16u_i64_avr +#define tcg_gen_ext32u_i64 tcg_gen_ext32u_i64_avr +#define tcg_gen_bswap16_i64 tcg_gen_bswap16_i64_avr +#define tcg_gen_bswap32_i64 tcg_gen_bswap32_i64_avr +#define tcg_gen_bswap64_i64 tcg_gen_bswap64_i64_avr +#define tcg_gen_not_i64 tcg_gen_not_i64_avr +#define tcg_gen_andc_i64 tcg_gen_andc_i64_avr +#define tcg_gen_eqv_i64 tcg_gen_eqv_i64_avr +#define tcg_gen_nand_i64 tcg_gen_nand_i64_avr +#define tcg_gen_nor_i64 tcg_gen_nor_i64_avr +#define tcg_gen_orc_i64 tcg_gen_orc_i64_avr +#define tcg_gen_clz_i64 tcg_gen_clz_i64_avr +#define tcg_gen_clzi_i64 tcg_gen_clzi_i64_avr +#define tcg_gen_ctz_i64 tcg_gen_ctz_i64_avr +#define tcg_gen_ctzi_i64 tcg_gen_ctzi_i64_avr +#define tcg_gen_clrsb_i64 tcg_gen_clrsb_i64_avr +#define tcg_gen_ctpop_i64 tcg_gen_ctpop_i64_avr +#define tcg_gen_rotl_i64 tcg_gen_rotl_i64_avr +#define tcg_gen_rotli_i64 tcg_gen_rotli_i64_avr +#define tcg_gen_rotr_i64 tcg_gen_rotr_i64_avr +#define tcg_gen_rotri_i64 tcg_gen_rotri_i64_avr +#define tcg_gen_deposit_i64 tcg_gen_deposit_i64_avr +#define tcg_gen_deposit_z_i64 tcg_gen_deposit_z_i64_avr +#define tcg_gen_extract_i64 tcg_gen_extract_i64_avr +#define tcg_gen_sextract_i64 tcg_gen_sextract_i64_avr +#define tcg_gen_extract2_i64 tcg_gen_extract2_i64_avr +#define tcg_gen_movcond_i64 tcg_gen_movcond_i64_avr +#define tcg_gen_add2_i64 tcg_gen_add2_i64_avr +#define tcg_gen_sub2_i64 tcg_gen_sub2_i64_avr +#define tcg_gen_mulu2_i64 tcg_gen_mulu2_i64_avr +#define tcg_gen_muls2_i64 tcg_gen_muls2_i64_avr +#define tcg_gen_mulsu2_i64 tcg_gen_mulsu2_i64_avr +#define tcg_gen_smin_i64 tcg_gen_smin_i64_avr +#define tcg_gen_umin_i64 tcg_gen_umin_i64_avr +#define tcg_gen_smax_i64 tcg_gen_smax_i64_avr +#define tcg_gen_umax_i64 tcg_gen_umax_i64_avr +#define tcg_gen_abs_i64 tcg_gen_abs_i64_avr +#define tcg_gen_extrl_i64_i32 tcg_gen_extrl_i64_i32_avr +#define tcg_gen_extrh_i64_i32 tcg_gen_extrh_i64_i32_avr +#define tcg_gen_extu_i32_i64 tcg_gen_extu_i32_i64_avr +#define tcg_gen_ext_i32_i64 tcg_gen_ext_i32_i64_avr +#define tcg_gen_concat_i32_i64 tcg_gen_concat_i32_i64_avr +#define tcg_gen_extr_i64_i32 tcg_gen_extr_i64_i32_avr +#define tcg_gen_extr32_i64 tcg_gen_extr32_i64_avr +#define tcg_gen_exit_tb tcg_gen_exit_tb_avr +#define tcg_gen_goto_tb tcg_gen_goto_tb_avr +#define tcg_gen_lookup_and_goto_ptr tcg_gen_lookup_and_goto_ptr_avr +#define check_exit_request check_exit_request_avr +#define tcg_gen_qemu_ld_i32 tcg_gen_qemu_ld_i32_avr +#define tcg_gen_qemu_st_i32 tcg_gen_qemu_st_i32_avr +#define tcg_gen_qemu_ld_i64 tcg_gen_qemu_ld_i64_avr +#define tcg_gen_qemu_st_i64 tcg_gen_qemu_st_i64_avr +#define tcg_gen_atomic_cmpxchg_i32 tcg_gen_atomic_cmpxchg_i32_avr +#define tcg_gen_atomic_cmpxchg_i64 tcg_gen_atomic_cmpxchg_i64_avr +#define tcg_gen_atomic_fetch_add_i32 tcg_gen_atomic_fetch_add_i32_avr +#define tcg_gen_atomic_fetch_add_i64 tcg_gen_atomic_fetch_add_i64_avr +#define tcg_gen_atomic_fetch_and_i32 tcg_gen_atomic_fetch_and_i32_avr +#define tcg_gen_atomic_fetch_and_i64 tcg_gen_atomic_fetch_and_i64_avr +#define tcg_gen_atomic_fetch_or_i32 tcg_gen_atomic_fetch_or_i32_avr +#define tcg_gen_atomic_fetch_or_i64 tcg_gen_atomic_fetch_or_i64_avr +#define tcg_gen_atomic_fetch_xor_i32 tcg_gen_atomic_fetch_xor_i32_avr +#define tcg_gen_atomic_fetch_xor_i64 tcg_gen_atomic_fetch_xor_i64_avr +#define tcg_gen_atomic_fetch_smin_i32 tcg_gen_atomic_fetch_smin_i32_avr +#define tcg_gen_atomic_fetch_smin_i64 tcg_gen_atomic_fetch_smin_i64_avr +#define tcg_gen_atomic_fetch_umin_i32 tcg_gen_atomic_fetch_umin_i32_avr +#define tcg_gen_atomic_fetch_umin_i64 tcg_gen_atomic_fetch_umin_i64_avr +#define tcg_gen_atomic_fetch_smax_i32 tcg_gen_atomic_fetch_smax_i32_avr +#define tcg_gen_atomic_fetch_smax_i64 tcg_gen_atomic_fetch_smax_i64_avr +#define tcg_gen_atomic_fetch_umax_i32 tcg_gen_atomic_fetch_umax_i32_avr +#define tcg_gen_atomic_fetch_umax_i64 tcg_gen_atomic_fetch_umax_i64_avr +#define tcg_gen_atomic_add_fetch_i32 tcg_gen_atomic_add_fetch_i32_avr +#define tcg_gen_atomic_add_fetch_i64 tcg_gen_atomic_add_fetch_i64_avr +#define tcg_gen_atomic_and_fetch_i32 tcg_gen_atomic_and_fetch_i32_avr +#define tcg_gen_atomic_and_fetch_i64 tcg_gen_atomic_and_fetch_i64_avr +#define tcg_gen_atomic_or_fetch_i32 tcg_gen_atomic_or_fetch_i32_avr +#define tcg_gen_atomic_or_fetch_i64 tcg_gen_atomic_or_fetch_i64_avr +#define tcg_gen_atomic_xor_fetch_i32 tcg_gen_atomic_xor_fetch_i32_avr +#define tcg_gen_atomic_xor_fetch_i64 tcg_gen_atomic_xor_fetch_i64_avr +#define tcg_gen_atomic_smin_fetch_i32 tcg_gen_atomic_smin_fetch_i32_avr +#define tcg_gen_atomic_smin_fetch_i64 tcg_gen_atomic_smin_fetch_i64_avr +#define tcg_gen_atomic_umin_fetch_i32 tcg_gen_atomic_umin_fetch_i32_avr +#define tcg_gen_atomic_umin_fetch_i64 tcg_gen_atomic_umin_fetch_i64_avr +#define tcg_gen_atomic_smax_fetch_i32 tcg_gen_atomic_smax_fetch_i32_avr +#define tcg_gen_atomic_smax_fetch_i64 tcg_gen_atomic_smax_fetch_i64_avr +#define tcg_gen_atomic_umax_fetch_i32 tcg_gen_atomic_umax_fetch_i32_avr +#define tcg_gen_atomic_umax_fetch_i64 tcg_gen_atomic_umax_fetch_i64_avr +#define tcg_gen_atomic_xchg_i32 tcg_gen_atomic_xchg_i32_avr +#define tcg_gen_atomic_xchg_i64 tcg_gen_atomic_xchg_i64_avr +#define simd_desc simd_desc_avr +#define tcg_gen_gvec_2_ool tcg_gen_gvec_2_ool_avr +#define tcg_gen_gvec_2i_ool tcg_gen_gvec_2i_ool_avr +#define tcg_gen_gvec_3_ool tcg_gen_gvec_3_ool_avr +#define tcg_gen_gvec_4_ool tcg_gen_gvec_4_ool_avr +#define tcg_gen_gvec_5_ool tcg_gen_gvec_5_ool_avr +#define tcg_gen_gvec_2_ptr tcg_gen_gvec_2_ptr_avr +#define tcg_gen_gvec_3_ptr tcg_gen_gvec_3_ptr_avr +#define tcg_gen_gvec_4_ptr tcg_gen_gvec_4_ptr_avr +#define tcg_gen_gvec_5_ptr tcg_gen_gvec_5_ptr_avr +#define tcg_gen_gvec_2 tcg_gen_gvec_2_avr +#define tcg_gen_gvec_2i tcg_gen_gvec_2i_avr +#define tcg_gen_gvec_2s tcg_gen_gvec_2s_avr +#define tcg_gen_gvec_3 tcg_gen_gvec_3_avr +#define tcg_gen_gvec_3i tcg_gen_gvec_3i_avr +#define tcg_gen_gvec_4 tcg_gen_gvec_4_avr +#define tcg_gen_gvec_mov tcg_gen_gvec_mov_avr +#define tcg_gen_gvec_dup_i32 tcg_gen_gvec_dup_i32_avr +#define tcg_gen_gvec_dup_i64 tcg_gen_gvec_dup_i64_avr +#define tcg_gen_gvec_dup_mem tcg_gen_gvec_dup_mem_avr +#define tcg_gen_gvec_dup64i tcg_gen_gvec_dup64i_avr +#define tcg_gen_gvec_dup32i tcg_gen_gvec_dup32i_avr +#define tcg_gen_gvec_dup16i tcg_gen_gvec_dup16i_avr +#define tcg_gen_gvec_dup8i tcg_gen_gvec_dup8i_avr +#define tcg_gen_gvec_not tcg_gen_gvec_not_avr +#define tcg_gen_vec_add8_i64 tcg_gen_vec_add8_i64_avr +#define tcg_gen_vec_add16_i64 tcg_gen_vec_add16_i64_avr +#define tcg_gen_vec_add32_i64 tcg_gen_vec_add32_i64_avr +#define tcg_gen_gvec_add tcg_gen_gvec_add_avr +#define tcg_gen_gvec_adds tcg_gen_gvec_adds_avr +#define tcg_gen_gvec_addi tcg_gen_gvec_addi_avr +#define tcg_gen_gvec_subs tcg_gen_gvec_subs_avr +#define tcg_gen_vec_sub8_i64 tcg_gen_vec_sub8_i64_avr +#define tcg_gen_vec_sub16_i64 tcg_gen_vec_sub16_i64_avr +#define tcg_gen_vec_sub32_i64 tcg_gen_vec_sub32_i64_avr +#define tcg_gen_gvec_sub tcg_gen_gvec_sub_avr +#define tcg_gen_gvec_mul tcg_gen_gvec_mul_avr +#define tcg_gen_gvec_muls tcg_gen_gvec_muls_avr +#define tcg_gen_gvec_muli tcg_gen_gvec_muli_avr +#define tcg_gen_gvec_ssadd tcg_gen_gvec_ssadd_avr +#define tcg_gen_gvec_sssub tcg_gen_gvec_sssub_avr +#define tcg_gen_gvec_usadd tcg_gen_gvec_usadd_avr +#define tcg_gen_gvec_ussub tcg_gen_gvec_ussub_avr +#define tcg_gen_gvec_smin tcg_gen_gvec_smin_avr +#define tcg_gen_gvec_umin tcg_gen_gvec_umin_avr +#define tcg_gen_gvec_smax tcg_gen_gvec_smax_avr +#define tcg_gen_gvec_umax tcg_gen_gvec_umax_avr +#define tcg_gen_vec_neg8_i64 tcg_gen_vec_neg8_i64_avr +#define tcg_gen_vec_neg16_i64 tcg_gen_vec_neg16_i64_avr +#define tcg_gen_vec_neg32_i64 tcg_gen_vec_neg32_i64_avr +#define tcg_gen_gvec_neg tcg_gen_gvec_neg_avr +#define tcg_gen_gvec_abs tcg_gen_gvec_abs_avr +#define tcg_gen_gvec_and tcg_gen_gvec_and_avr +#define tcg_gen_gvec_or tcg_gen_gvec_or_avr +#define tcg_gen_gvec_xor tcg_gen_gvec_xor_avr +#define tcg_gen_gvec_andc tcg_gen_gvec_andc_avr +#define tcg_gen_gvec_orc tcg_gen_gvec_orc_avr +#define tcg_gen_gvec_nand tcg_gen_gvec_nand_avr +#define tcg_gen_gvec_nor tcg_gen_gvec_nor_avr +#define tcg_gen_gvec_eqv tcg_gen_gvec_eqv_avr +#define tcg_gen_gvec_ands tcg_gen_gvec_ands_avr +#define tcg_gen_gvec_andi tcg_gen_gvec_andi_avr +#define tcg_gen_gvec_xors tcg_gen_gvec_xors_avr +#define tcg_gen_gvec_xori tcg_gen_gvec_xori_avr +#define tcg_gen_gvec_ors tcg_gen_gvec_ors_avr +#define tcg_gen_gvec_ori tcg_gen_gvec_ori_avr +#define tcg_gen_vec_shl8i_i64 tcg_gen_vec_shl8i_i64_avr +#define tcg_gen_vec_shl16i_i64 tcg_gen_vec_shl16i_i64_avr +#define tcg_gen_gvec_shli tcg_gen_gvec_shli_avr +#define tcg_gen_vec_shr8i_i64 tcg_gen_vec_shr8i_i64_avr +#define tcg_gen_vec_shr16i_i64 tcg_gen_vec_shr16i_i64_avr +#define tcg_gen_gvec_shri tcg_gen_gvec_shri_avr +#define tcg_gen_vec_sar8i_i64 tcg_gen_vec_sar8i_i64_avr +#define tcg_gen_vec_sar16i_i64 tcg_gen_vec_sar16i_i64_avr +#define tcg_gen_gvec_sari tcg_gen_gvec_sari_avr +#define tcg_gen_gvec_shls tcg_gen_gvec_shls_avr +#define tcg_gen_gvec_shrs tcg_gen_gvec_shrs_avr +#define tcg_gen_gvec_sars tcg_gen_gvec_sars_avr +#define tcg_gen_gvec_shlv tcg_gen_gvec_shlv_avr +#define tcg_gen_gvec_shrv tcg_gen_gvec_shrv_avr +#define tcg_gen_gvec_sarv tcg_gen_gvec_sarv_avr +#define tcg_gen_gvec_cmp tcg_gen_gvec_cmp_avr +#define tcg_gen_gvec_bitsel tcg_gen_gvec_bitsel_avr +#define tcg_can_emit_vecop_list tcg_can_emit_vecop_list_avr +#define vec_gen_2 vec_gen_2_avr +#define vec_gen_3 vec_gen_3_avr +#define vec_gen_4 vec_gen_4_avr +#define tcg_gen_mov_vec tcg_gen_mov_vec_avr +#define tcg_const_zeros_vec tcg_const_zeros_vec_avr +#define tcg_const_ones_vec tcg_const_ones_vec_avr +#define tcg_const_zeros_vec_matching tcg_const_zeros_vec_matching_avr +#define tcg_const_ones_vec_matching tcg_const_ones_vec_matching_avr +#define tcg_gen_dup64i_vec tcg_gen_dup64i_vec_avr +#define tcg_gen_dup32i_vec tcg_gen_dup32i_vec_avr +#define tcg_gen_dup16i_vec tcg_gen_dup16i_vec_avr +#define tcg_gen_dup8i_vec tcg_gen_dup8i_vec_avr +#define tcg_gen_dupi_vec tcg_gen_dupi_vec_avr +#define tcg_gen_dup_i64_vec tcg_gen_dup_i64_vec_avr +#define tcg_gen_dup_i32_vec tcg_gen_dup_i32_vec_avr +#define tcg_gen_dup_mem_vec tcg_gen_dup_mem_vec_avr +#define tcg_gen_ld_vec tcg_gen_ld_vec_avr +#define tcg_gen_st_vec tcg_gen_st_vec_avr +#define tcg_gen_stl_vec tcg_gen_stl_vec_avr +#define tcg_gen_and_vec tcg_gen_and_vec_avr +#define tcg_gen_or_vec tcg_gen_or_vec_avr +#define tcg_gen_xor_vec tcg_gen_xor_vec_avr +#define tcg_gen_andc_vec tcg_gen_andc_vec_avr +#define tcg_gen_orc_vec tcg_gen_orc_vec_avr +#define tcg_gen_nand_vec tcg_gen_nand_vec_avr +#define tcg_gen_nor_vec tcg_gen_nor_vec_avr +#define tcg_gen_eqv_vec tcg_gen_eqv_vec_avr +#define tcg_gen_not_vec tcg_gen_not_vec_avr +#define tcg_gen_neg_vec tcg_gen_neg_vec_avr +#define tcg_gen_abs_vec tcg_gen_abs_vec_avr +#define tcg_gen_shli_vec tcg_gen_shli_vec_avr +#define tcg_gen_shri_vec tcg_gen_shri_vec_avr +#define tcg_gen_sari_vec tcg_gen_sari_vec_avr +#define tcg_gen_cmp_vec tcg_gen_cmp_vec_avr +#define tcg_gen_add_vec tcg_gen_add_vec_avr +#define tcg_gen_sub_vec tcg_gen_sub_vec_avr +#define tcg_gen_mul_vec tcg_gen_mul_vec_avr +#define tcg_gen_ssadd_vec tcg_gen_ssadd_vec_avr +#define tcg_gen_usadd_vec tcg_gen_usadd_vec_avr +#define tcg_gen_sssub_vec tcg_gen_sssub_vec_avr +#define tcg_gen_ussub_vec tcg_gen_ussub_vec_avr +#define tcg_gen_smin_vec tcg_gen_smin_vec_avr +#define tcg_gen_umin_vec tcg_gen_umin_vec_avr +#define tcg_gen_smax_vec tcg_gen_smax_vec_avr +#define tcg_gen_umax_vec tcg_gen_umax_vec_avr +#define tcg_gen_shlv_vec tcg_gen_shlv_vec_avr +#define tcg_gen_shrv_vec tcg_gen_shrv_vec_avr +#define tcg_gen_sarv_vec tcg_gen_sarv_vec_avr +#define tcg_gen_shls_vec tcg_gen_shls_vec_avr +#define tcg_gen_shrs_vec tcg_gen_shrs_vec_avr +#define tcg_gen_sars_vec tcg_gen_sars_vec_avr +#define tcg_gen_bitsel_vec tcg_gen_bitsel_vec_avr +#define tcg_gen_cmpsel_vec tcg_gen_cmpsel_vec_avr +#define tb_htable_lookup tb_htable_lookup_avr +#define tb_set_jmp_target tb_set_jmp_target_avr +#define cpu_exec cpu_exec_avr +#define cpu_loop_exit_noexc cpu_loop_exit_noexc_avr +#define cpu_reloading_memory_map cpu_reloading_memory_map_avr +#define cpu_loop_exit cpu_loop_exit_avr +#define cpu_loop_exit_restore cpu_loop_exit_restore_avr +#define cpu_loop_exit_atomic cpu_loop_exit_atomic_avr +#define tlb_init tlb_init_avr +#define tlb_flush_by_mmuidx tlb_flush_by_mmuidx_avr +#define tlb_flush tlb_flush_avr +#define tlb_flush_by_mmuidx_all_cpus tlb_flush_by_mmuidx_all_cpus_avr +#define tlb_flush_all_cpus tlb_flush_all_cpus_avr +#define tlb_flush_by_mmuidx_all_cpus_synced tlb_flush_by_mmuidx_all_cpus_synced_avr +#define tlb_flush_all_cpus_synced tlb_flush_all_cpus_synced_avr +#define tlb_flush_page_by_mmuidx tlb_flush_page_by_mmuidx_avr +#define tlb_flush_page tlb_flush_page_avr +#define tlb_flush_page_by_mmuidx_all_cpus tlb_flush_page_by_mmuidx_all_cpus_avr +#define tlb_flush_page_all_cpus tlb_flush_page_all_cpus_avr +#define tlb_flush_page_by_mmuidx_all_cpus_synced tlb_flush_page_by_mmuidx_all_cpus_synced_avr +#define tlb_flush_page_all_cpus_synced tlb_flush_page_all_cpus_synced_avr +#define tlb_protect_code tlb_protect_code_avr +#define tlb_unprotect_code tlb_unprotect_code_avr +#define tlb_reset_dirty tlb_reset_dirty_avr +#define tlb_set_dirty tlb_set_dirty_avr +#define tlb_set_page_with_attrs tlb_set_page_with_attrs_avr +#define tlb_set_page tlb_set_page_avr +#define get_page_addr_code_hostp get_page_addr_code_hostp_avr +#define get_page_addr_code get_page_addr_code_avr +#define probe_access probe_access_avr +#define tlb_vaddr_to_host tlb_vaddr_to_host_avr +#define helper_ret_ldub_mmu helper_ret_ldub_mmu_avr +#define helper_le_lduw_mmu helper_le_lduw_mmu_avr +#define helper_be_lduw_mmu helper_be_lduw_mmu_avr +#define helper_le_ldul_mmu helper_le_ldul_mmu_avr +#define helper_be_ldul_mmu helper_be_ldul_mmu_avr +#define helper_le_ldq_mmu helper_le_ldq_mmu_avr +#define helper_be_ldq_mmu helper_be_ldq_mmu_avr +#define helper_ret_ldsb_mmu helper_ret_ldsb_mmu_avr +#define helper_le_ldsw_mmu helper_le_ldsw_mmu_avr +#define helper_be_ldsw_mmu helper_be_ldsw_mmu_avr +#define helper_le_ldsl_mmu helper_le_ldsl_mmu_avr +#define helper_be_ldsl_mmu helper_be_ldsl_mmu_avr +#define cpu_ldub_mmuidx_ra cpu_ldub_mmuidx_ra_avr +#define cpu_ldsb_mmuidx_ra cpu_ldsb_mmuidx_ra_avr +#define cpu_lduw_mmuidx_ra cpu_lduw_mmuidx_ra_avr +#define cpu_ldsw_mmuidx_ra cpu_ldsw_mmuidx_ra_avr +#define cpu_ldl_mmuidx_ra cpu_ldl_mmuidx_ra_avr +#define cpu_ldq_mmuidx_ra cpu_ldq_mmuidx_ra_avr +#define cpu_ldub_data_ra cpu_ldub_data_ra_avr +#define cpu_ldsb_data_ra cpu_ldsb_data_ra_avr +#define cpu_lduw_data_ra cpu_lduw_data_ra_avr +#define cpu_ldsw_data_ra cpu_ldsw_data_ra_avr +#define cpu_ldl_data_ra cpu_ldl_data_ra_avr +#define cpu_ldq_data_ra cpu_ldq_data_ra_avr +#define cpu_ldub_data cpu_ldub_data_avr +#define cpu_ldsb_data cpu_ldsb_data_avr +#define cpu_lduw_data cpu_lduw_data_avr +#define cpu_ldsw_data cpu_ldsw_data_avr +#define cpu_ldl_data cpu_ldl_data_avr +#define cpu_ldq_data cpu_ldq_data_avr +#define helper_ret_stb_mmu helper_ret_stb_mmu_avr +#define helper_le_stw_mmu helper_le_stw_mmu_avr +#define helper_be_stw_mmu helper_be_stw_mmu_avr +#define helper_le_stl_mmu helper_le_stl_mmu_avr +#define helper_be_stl_mmu helper_be_stl_mmu_avr +#define helper_le_stq_mmu helper_le_stq_mmu_avr +#define helper_be_stq_mmu helper_be_stq_mmu_avr +#define cpu_stb_mmuidx_ra cpu_stb_mmuidx_ra_avr +#define cpu_stw_mmuidx_ra cpu_stw_mmuidx_ra_avr +#define cpu_stl_mmuidx_ra cpu_stl_mmuidx_ra_avr +#define cpu_stq_mmuidx_ra cpu_stq_mmuidx_ra_avr +#define cpu_stb_data_ra cpu_stb_data_ra_avr +#define cpu_stw_data_ra cpu_stw_data_ra_avr +#define cpu_stl_data_ra cpu_stl_data_ra_avr +#define cpu_stq_data_ra cpu_stq_data_ra_avr +#define cpu_stb_data cpu_stb_data_avr +#define cpu_stw_data cpu_stw_data_avr +#define cpu_stl_data cpu_stl_data_avr +#define cpu_stq_data cpu_stq_data_avr +#define helper_atomic_cmpxchgb_mmu helper_atomic_cmpxchgb_mmu_avr +#define helper_atomic_xchgb_mmu helper_atomic_xchgb_mmu_avr +#define helper_atomic_fetch_addb_mmu helper_atomic_fetch_addb_mmu_avr +#define helper_atomic_fetch_andb_mmu helper_atomic_fetch_andb_mmu_avr +#define helper_atomic_fetch_orb_mmu helper_atomic_fetch_orb_mmu_avr +#define helper_atomic_fetch_xorb_mmu helper_atomic_fetch_xorb_mmu_avr +#define helper_atomic_add_fetchb_mmu helper_atomic_add_fetchb_mmu_avr +#define helper_atomic_and_fetchb_mmu helper_atomic_and_fetchb_mmu_avr +#define helper_atomic_or_fetchb_mmu helper_atomic_or_fetchb_mmu_avr +#define helper_atomic_xor_fetchb_mmu helper_atomic_xor_fetchb_mmu_avr +#define helper_atomic_fetch_sminb_mmu helper_atomic_fetch_sminb_mmu_avr +#define helper_atomic_fetch_uminb_mmu helper_atomic_fetch_uminb_mmu_avr +#define helper_atomic_fetch_smaxb_mmu helper_atomic_fetch_smaxb_mmu_avr +#define helper_atomic_fetch_umaxb_mmu helper_atomic_fetch_umaxb_mmu_avr +#define helper_atomic_smin_fetchb_mmu helper_atomic_smin_fetchb_mmu_avr +#define helper_atomic_umin_fetchb_mmu helper_atomic_umin_fetchb_mmu_avr +#define helper_atomic_smax_fetchb_mmu helper_atomic_smax_fetchb_mmu_avr +#define helper_atomic_umax_fetchb_mmu helper_atomic_umax_fetchb_mmu_avr +#define helper_atomic_cmpxchgw_le_mmu helper_atomic_cmpxchgw_le_mmu_avr +#define helper_atomic_xchgw_le_mmu helper_atomic_xchgw_le_mmu_avr +#define helper_atomic_fetch_addw_le_mmu helper_atomic_fetch_addw_le_mmu_avr +#define helper_atomic_fetch_andw_le_mmu helper_atomic_fetch_andw_le_mmu_avr +#define helper_atomic_fetch_orw_le_mmu helper_atomic_fetch_orw_le_mmu_avr +#define helper_atomic_fetch_xorw_le_mmu helper_atomic_fetch_xorw_le_mmu_avr +#define helper_atomic_add_fetchw_le_mmu helper_atomic_add_fetchw_le_mmu_avr +#define helper_atomic_and_fetchw_le_mmu helper_atomic_and_fetchw_le_mmu_avr +#define helper_atomic_or_fetchw_le_mmu helper_atomic_or_fetchw_le_mmu_avr +#define helper_atomic_xor_fetchw_le_mmu helper_atomic_xor_fetchw_le_mmu_avr +#define helper_atomic_fetch_sminw_le_mmu helper_atomic_fetch_sminw_le_mmu_avr +#define helper_atomic_fetch_uminw_le_mmu helper_atomic_fetch_uminw_le_mmu_avr +#define helper_atomic_fetch_smaxw_le_mmu helper_atomic_fetch_smaxw_le_mmu_avr +#define helper_atomic_fetch_umaxw_le_mmu helper_atomic_fetch_umaxw_le_mmu_avr +#define helper_atomic_smin_fetchw_le_mmu helper_atomic_smin_fetchw_le_mmu_avr +#define helper_atomic_umin_fetchw_le_mmu helper_atomic_umin_fetchw_le_mmu_avr +#define helper_atomic_smax_fetchw_le_mmu helper_atomic_smax_fetchw_le_mmu_avr +#define helper_atomic_umax_fetchw_le_mmu helper_atomic_umax_fetchw_le_mmu_avr +#define helper_atomic_cmpxchgw_be_mmu helper_atomic_cmpxchgw_be_mmu_avr +#define helper_atomic_xchgw_be_mmu helper_atomic_xchgw_be_mmu_avr +#define helper_atomic_fetch_andw_be_mmu helper_atomic_fetch_andw_be_mmu_avr +#define helper_atomic_fetch_orw_be_mmu helper_atomic_fetch_orw_be_mmu_avr +#define helper_atomic_fetch_xorw_be_mmu helper_atomic_fetch_xorw_be_mmu_avr +#define helper_atomic_and_fetchw_be_mmu helper_atomic_and_fetchw_be_mmu_avr +#define helper_atomic_or_fetchw_be_mmu helper_atomic_or_fetchw_be_mmu_avr +#define helper_atomic_xor_fetchw_be_mmu helper_atomic_xor_fetchw_be_mmu_avr +#define helper_atomic_fetch_sminw_be_mmu helper_atomic_fetch_sminw_be_mmu_avr +#define helper_atomic_fetch_uminw_be_mmu helper_atomic_fetch_uminw_be_mmu_avr +#define helper_atomic_fetch_smaxw_be_mmu helper_atomic_fetch_smaxw_be_mmu_avr +#define helper_atomic_fetch_umaxw_be_mmu helper_atomic_fetch_umaxw_be_mmu_avr +#define helper_atomic_smin_fetchw_be_mmu helper_atomic_smin_fetchw_be_mmu_avr +#define helper_atomic_umin_fetchw_be_mmu helper_atomic_umin_fetchw_be_mmu_avr +#define helper_atomic_smax_fetchw_be_mmu helper_atomic_smax_fetchw_be_mmu_avr +#define helper_atomic_umax_fetchw_be_mmu helper_atomic_umax_fetchw_be_mmu_avr +#define helper_atomic_fetch_addw_be_mmu helper_atomic_fetch_addw_be_mmu_avr +#define helper_atomic_add_fetchw_be_mmu helper_atomic_add_fetchw_be_mmu_avr +#define helper_atomic_cmpxchgl_le_mmu helper_atomic_cmpxchgl_le_mmu_avr +#define helper_atomic_xchgl_le_mmu helper_atomic_xchgl_le_mmu_avr +#define helper_atomic_fetch_addl_le_mmu helper_atomic_fetch_addl_le_mmu_avr +#define helper_atomic_fetch_andl_le_mmu helper_atomic_fetch_andl_le_mmu_avr +#define helper_atomic_fetch_orl_le_mmu helper_atomic_fetch_orl_le_mmu_avr +#define helper_atomic_fetch_xorl_le_mmu helper_atomic_fetch_xorl_le_mmu_avr +#define helper_atomic_add_fetchl_le_mmu helper_atomic_add_fetchl_le_mmu_avr +#define helper_atomic_and_fetchl_le_mmu helper_atomic_and_fetchl_le_mmu_avr +#define helper_atomic_or_fetchl_le_mmu helper_atomic_or_fetchl_le_mmu_avr +#define helper_atomic_xor_fetchl_le_mmu helper_atomic_xor_fetchl_le_mmu_avr +#define helper_atomic_fetch_sminl_le_mmu helper_atomic_fetch_sminl_le_mmu_avr +#define helper_atomic_fetch_uminl_le_mmu helper_atomic_fetch_uminl_le_mmu_avr +#define helper_atomic_fetch_smaxl_le_mmu helper_atomic_fetch_smaxl_le_mmu_avr +#define helper_atomic_fetch_umaxl_le_mmu helper_atomic_fetch_umaxl_le_mmu_avr +#define helper_atomic_smin_fetchl_le_mmu helper_atomic_smin_fetchl_le_mmu_avr +#define helper_atomic_umin_fetchl_le_mmu helper_atomic_umin_fetchl_le_mmu_avr +#define helper_atomic_smax_fetchl_le_mmu helper_atomic_smax_fetchl_le_mmu_avr +#define helper_atomic_umax_fetchl_le_mmu helper_atomic_umax_fetchl_le_mmu_avr +#define helper_atomic_cmpxchgl_be_mmu helper_atomic_cmpxchgl_be_mmu_avr +#define helper_atomic_xchgl_be_mmu helper_atomic_xchgl_be_mmu_avr +#define helper_atomic_fetch_andl_be_mmu helper_atomic_fetch_andl_be_mmu_avr +#define helper_atomic_fetch_orl_be_mmu helper_atomic_fetch_orl_be_mmu_avr +#define helper_atomic_fetch_xorl_be_mmu helper_atomic_fetch_xorl_be_mmu_avr +#define helper_atomic_and_fetchl_be_mmu helper_atomic_and_fetchl_be_mmu_avr +#define helper_atomic_or_fetchl_be_mmu helper_atomic_or_fetchl_be_mmu_avr +#define helper_atomic_xor_fetchl_be_mmu helper_atomic_xor_fetchl_be_mmu_avr +#define helper_atomic_fetch_sminl_be_mmu helper_atomic_fetch_sminl_be_mmu_avr +#define helper_atomic_fetch_uminl_be_mmu helper_atomic_fetch_uminl_be_mmu_avr +#define helper_atomic_fetch_smaxl_be_mmu helper_atomic_fetch_smaxl_be_mmu_avr +#define helper_atomic_fetch_umaxl_be_mmu helper_atomic_fetch_umaxl_be_mmu_avr +#define helper_atomic_smin_fetchl_be_mmu helper_atomic_smin_fetchl_be_mmu_avr +#define helper_atomic_umin_fetchl_be_mmu helper_atomic_umin_fetchl_be_mmu_avr +#define helper_atomic_smax_fetchl_be_mmu helper_atomic_smax_fetchl_be_mmu_avr +#define helper_atomic_umax_fetchl_be_mmu helper_atomic_umax_fetchl_be_mmu_avr +#define helper_atomic_fetch_addl_be_mmu helper_atomic_fetch_addl_be_mmu_avr +#define helper_atomic_add_fetchl_be_mmu helper_atomic_add_fetchl_be_mmu_avr +#define helper_atomic_cmpxchgq_le_mmu helper_atomic_cmpxchgq_le_mmu_avr +#define helper_atomic_xchgq_le_mmu helper_atomic_xchgq_le_mmu_avr +#define helper_atomic_fetch_addq_le_mmu helper_atomic_fetch_addq_le_mmu_avr +#define helper_atomic_fetch_andq_le_mmu helper_atomic_fetch_andq_le_mmu_avr +#define helper_atomic_fetch_orq_le_mmu helper_atomic_fetch_orq_le_mmu_avr +#define helper_atomic_fetch_xorq_le_mmu helper_atomic_fetch_xorq_le_mmu_avr +#define helper_atomic_add_fetchq_le_mmu helper_atomic_add_fetchq_le_mmu_avr +#define helper_atomic_and_fetchq_le_mmu helper_atomic_and_fetchq_le_mmu_avr +#define helper_atomic_or_fetchq_le_mmu helper_atomic_or_fetchq_le_mmu_avr +#define helper_atomic_xor_fetchq_le_mmu helper_atomic_xor_fetchq_le_mmu_avr +#define helper_atomic_fetch_sminq_le_mmu helper_atomic_fetch_sminq_le_mmu_avr +#define helper_atomic_fetch_uminq_le_mmu helper_atomic_fetch_uminq_le_mmu_avr +#define helper_atomic_fetch_smaxq_le_mmu helper_atomic_fetch_smaxq_le_mmu_avr +#define helper_atomic_fetch_umaxq_le_mmu helper_atomic_fetch_umaxq_le_mmu_avr +#define helper_atomic_smin_fetchq_le_mmu helper_atomic_smin_fetchq_le_mmu_avr +#define helper_atomic_umin_fetchq_le_mmu helper_atomic_umin_fetchq_le_mmu_avr +#define helper_atomic_smax_fetchq_le_mmu helper_atomic_smax_fetchq_le_mmu_avr +#define helper_atomic_umax_fetchq_le_mmu helper_atomic_umax_fetchq_le_mmu_avr +#define helper_atomic_cmpxchgq_be_mmu helper_atomic_cmpxchgq_be_mmu_avr +#define helper_atomic_xchgq_be_mmu helper_atomic_xchgq_be_mmu_avr +#define helper_atomic_fetch_andq_be_mmu helper_atomic_fetch_andq_be_mmu_avr +#define helper_atomic_fetch_orq_be_mmu helper_atomic_fetch_orq_be_mmu_avr +#define helper_atomic_fetch_xorq_be_mmu helper_atomic_fetch_xorq_be_mmu_avr +#define helper_atomic_and_fetchq_be_mmu helper_atomic_and_fetchq_be_mmu_avr +#define helper_atomic_or_fetchq_be_mmu helper_atomic_or_fetchq_be_mmu_avr +#define helper_atomic_xor_fetchq_be_mmu helper_atomic_xor_fetchq_be_mmu_avr +#define helper_atomic_fetch_sminq_be_mmu helper_atomic_fetch_sminq_be_mmu_avr +#define helper_atomic_fetch_uminq_be_mmu helper_atomic_fetch_uminq_be_mmu_avr +#define helper_atomic_fetch_smaxq_be_mmu helper_atomic_fetch_smaxq_be_mmu_avr +#define helper_atomic_fetch_umaxq_be_mmu helper_atomic_fetch_umaxq_be_mmu_avr +#define helper_atomic_smin_fetchq_be_mmu helper_atomic_smin_fetchq_be_mmu_avr +#define helper_atomic_umin_fetchq_be_mmu helper_atomic_umin_fetchq_be_mmu_avr +#define helper_atomic_smax_fetchq_be_mmu helper_atomic_smax_fetchq_be_mmu_avr +#define helper_atomic_umax_fetchq_be_mmu helper_atomic_umax_fetchq_be_mmu_avr +#define helper_atomic_fetch_addq_be_mmu helper_atomic_fetch_addq_be_mmu_avr +#define helper_atomic_add_fetchq_be_mmu helper_atomic_add_fetchq_be_mmu_avr +#define helper_atomic_cmpxchgb helper_atomic_cmpxchgb_avr +#define helper_atomic_xchgb helper_atomic_xchgb_avr +#define helper_atomic_fetch_addb helper_atomic_fetch_addb_avr +#define helper_atomic_fetch_andb helper_atomic_fetch_andb_avr +#define helper_atomic_fetch_orb helper_atomic_fetch_orb_avr +#define helper_atomic_fetch_xorb helper_atomic_fetch_xorb_avr +#define helper_atomic_add_fetchb helper_atomic_add_fetchb_avr +#define helper_atomic_and_fetchb helper_atomic_and_fetchb_avr +#define helper_atomic_or_fetchb helper_atomic_or_fetchb_avr +#define helper_atomic_xor_fetchb helper_atomic_xor_fetchb_avr +#define helper_atomic_fetch_sminb helper_atomic_fetch_sminb_avr +#define helper_atomic_fetch_uminb helper_atomic_fetch_uminb_avr +#define helper_atomic_fetch_smaxb helper_atomic_fetch_smaxb_avr +#define helper_atomic_fetch_umaxb helper_atomic_fetch_umaxb_avr +#define helper_atomic_smin_fetchb helper_atomic_smin_fetchb_avr +#define helper_atomic_umin_fetchb helper_atomic_umin_fetchb_avr +#define helper_atomic_smax_fetchb helper_atomic_smax_fetchb_avr +#define helper_atomic_umax_fetchb helper_atomic_umax_fetchb_avr +#define helper_atomic_cmpxchgw_le helper_atomic_cmpxchgw_le_avr +#define helper_atomic_xchgw_le helper_atomic_xchgw_le_avr +#define helper_atomic_fetch_addw_le helper_atomic_fetch_addw_le_avr +#define helper_atomic_fetch_andw_le helper_atomic_fetch_andw_le_avr +#define helper_atomic_fetch_orw_le helper_atomic_fetch_orw_le_avr +#define helper_atomic_fetch_xorw_le helper_atomic_fetch_xorw_le_avr +#define helper_atomic_add_fetchw_le helper_atomic_add_fetchw_le_avr +#define helper_atomic_and_fetchw_le helper_atomic_and_fetchw_le_avr +#define helper_atomic_or_fetchw_le helper_atomic_or_fetchw_le_avr +#define helper_atomic_xor_fetchw_le helper_atomic_xor_fetchw_le_avr +#define helper_atomic_fetch_sminw_le helper_atomic_fetch_sminw_le_avr +#define helper_atomic_fetch_uminw_le helper_atomic_fetch_uminw_le_avr +#define helper_atomic_fetch_smaxw_le helper_atomic_fetch_smaxw_le_avr +#define helper_atomic_fetch_umaxw_le helper_atomic_fetch_umaxw_le_avr +#define helper_atomic_smin_fetchw_le helper_atomic_smin_fetchw_le_avr +#define helper_atomic_umin_fetchw_le helper_atomic_umin_fetchw_le_avr +#define helper_atomic_smax_fetchw_le helper_atomic_smax_fetchw_le_avr +#define helper_atomic_umax_fetchw_le helper_atomic_umax_fetchw_le_avr +#define helper_atomic_cmpxchgw_be helper_atomic_cmpxchgw_be_avr +#define helper_atomic_xchgw_be helper_atomic_xchgw_be_avr +#define helper_atomic_fetch_andw_be helper_atomic_fetch_andw_be_avr +#define helper_atomic_fetch_orw_be helper_atomic_fetch_orw_be_avr +#define helper_atomic_fetch_xorw_be helper_atomic_fetch_xorw_be_avr +#define helper_atomic_and_fetchw_be helper_atomic_and_fetchw_be_avr +#define helper_atomic_or_fetchw_be helper_atomic_or_fetchw_be_avr +#define helper_atomic_xor_fetchw_be helper_atomic_xor_fetchw_be_avr +#define helper_atomic_fetch_sminw_be helper_atomic_fetch_sminw_be_avr +#define helper_atomic_fetch_uminw_be helper_atomic_fetch_uminw_be_avr +#define helper_atomic_fetch_smaxw_be helper_atomic_fetch_smaxw_be_avr +#define helper_atomic_fetch_umaxw_be helper_atomic_fetch_umaxw_be_avr +#define helper_atomic_smin_fetchw_be helper_atomic_smin_fetchw_be_avr +#define helper_atomic_umin_fetchw_be helper_atomic_umin_fetchw_be_avr +#define helper_atomic_smax_fetchw_be helper_atomic_smax_fetchw_be_avr +#define helper_atomic_umax_fetchw_be helper_atomic_umax_fetchw_be_avr +#define helper_atomic_fetch_addw_be helper_atomic_fetch_addw_be_avr +#define helper_atomic_add_fetchw_be helper_atomic_add_fetchw_be_avr +#define helper_atomic_cmpxchgl_le helper_atomic_cmpxchgl_le_avr +#define helper_atomic_xchgl_le helper_atomic_xchgl_le_avr +#define helper_atomic_fetch_addl_le helper_atomic_fetch_addl_le_avr +#define helper_atomic_fetch_andl_le helper_atomic_fetch_andl_le_avr +#define helper_atomic_fetch_orl_le helper_atomic_fetch_orl_le_avr +#define helper_atomic_fetch_xorl_le helper_atomic_fetch_xorl_le_avr +#define helper_atomic_add_fetchl_le helper_atomic_add_fetchl_le_avr +#define helper_atomic_and_fetchl_le helper_atomic_and_fetchl_le_avr +#define helper_atomic_or_fetchl_le helper_atomic_or_fetchl_le_avr +#define helper_atomic_xor_fetchl_le helper_atomic_xor_fetchl_le_avr +#define helper_atomic_fetch_sminl_le helper_atomic_fetch_sminl_le_avr +#define helper_atomic_fetch_uminl_le helper_atomic_fetch_uminl_le_avr +#define helper_atomic_fetch_smaxl_le helper_atomic_fetch_smaxl_le_avr +#define helper_atomic_fetch_umaxl_le helper_atomic_fetch_umaxl_le_avr +#define helper_atomic_smin_fetchl_le helper_atomic_smin_fetchl_le_avr +#define helper_atomic_umin_fetchl_le helper_atomic_umin_fetchl_le_avr +#define helper_atomic_smax_fetchl_le helper_atomic_smax_fetchl_le_avr +#define helper_atomic_umax_fetchl_le helper_atomic_umax_fetchl_le_avr +#define helper_atomic_cmpxchgl_be helper_atomic_cmpxchgl_be_avr +#define helper_atomic_xchgl_be helper_atomic_xchgl_be_avr +#define helper_atomic_fetch_andl_be helper_atomic_fetch_andl_be_avr +#define helper_atomic_fetch_orl_be helper_atomic_fetch_orl_be_avr +#define helper_atomic_fetch_xorl_be helper_atomic_fetch_xorl_be_avr +#define helper_atomic_and_fetchl_be helper_atomic_and_fetchl_be_avr +#define helper_atomic_or_fetchl_be helper_atomic_or_fetchl_be_avr +#define helper_atomic_xor_fetchl_be helper_atomic_xor_fetchl_be_avr +#define helper_atomic_fetch_sminl_be helper_atomic_fetch_sminl_be_avr +#define helper_atomic_fetch_uminl_be helper_atomic_fetch_uminl_be_avr +#define helper_atomic_fetch_smaxl_be helper_atomic_fetch_smaxl_be_avr +#define helper_atomic_fetch_umaxl_be helper_atomic_fetch_umaxl_be_avr +#define helper_atomic_smin_fetchl_be helper_atomic_smin_fetchl_be_avr +#define helper_atomic_umin_fetchl_be helper_atomic_umin_fetchl_be_avr +#define helper_atomic_smax_fetchl_be helper_atomic_smax_fetchl_be_avr +#define helper_atomic_umax_fetchl_be helper_atomic_umax_fetchl_be_avr +#define helper_atomic_fetch_addl_be helper_atomic_fetch_addl_be_avr +#define helper_atomic_add_fetchl_be helper_atomic_add_fetchl_be_avr +#define helper_atomic_cmpxchgq_le helper_atomic_cmpxchgq_le_avr +#define helper_atomic_xchgq_le helper_atomic_xchgq_le_avr +#define helper_atomic_fetch_addq_le helper_atomic_fetch_addq_le_avr +#define helper_atomic_fetch_andq_le helper_atomic_fetch_andq_le_avr +#define helper_atomic_fetch_orq_le helper_atomic_fetch_orq_le_avr +#define helper_atomic_fetch_xorq_le helper_atomic_fetch_xorq_le_avr +#define helper_atomic_add_fetchq_le helper_atomic_add_fetchq_le_avr +#define helper_atomic_and_fetchq_le helper_atomic_and_fetchq_le_avr +#define helper_atomic_or_fetchq_le helper_atomic_or_fetchq_le_avr +#define helper_atomic_xor_fetchq_le helper_atomic_xor_fetchq_le_avr +#define helper_atomic_fetch_sminq_le helper_atomic_fetch_sminq_le_avr +#define helper_atomic_fetch_uminq_le helper_atomic_fetch_uminq_le_avr +#define helper_atomic_fetch_smaxq_le helper_atomic_fetch_smaxq_le_avr +#define helper_atomic_fetch_umaxq_le helper_atomic_fetch_umaxq_le_avr +#define helper_atomic_smin_fetchq_le helper_atomic_smin_fetchq_le_avr +#define helper_atomic_umin_fetchq_le helper_atomic_umin_fetchq_le_avr +#define helper_atomic_smax_fetchq_le helper_atomic_smax_fetchq_le_avr +#define helper_atomic_umax_fetchq_le helper_atomic_umax_fetchq_le_avr +#define helper_atomic_cmpxchgq_be helper_atomic_cmpxchgq_be_avr +#define helper_atomic_xchgq_be helper_atomic_xchgq_be_avr +#define helper_atomic_fetch_andq_be helper_atomic_fetch_andq_be_avr +#define helper_atomic_fetch_orq_be helper_atomic_fetch_orq_be_avr +#define helper_atomic_fetch_xorq_be helper_atomic_fetch_xorq_be_avr +#define helper_atomic_and_fetchq_be helper_atomic_and_fetchq_be_avr +#define helper_atomic_or_fetchq_be helper_atomic_or_fetchq_be_avr +#define helper_atomic_xor_fetchq_be helper_atomic_xor_fetchq_be_avr +#define helper_atomic_fetch_sminq_be helper_atomic_fetch_sminq_be_avr +#define helper_atomic_fetch_uminq_be helper_atomic_fetch_uminq_be_avr +#define helper_atomic_fetch_smaxq_be helper_atomic_fetch_smaxq_be_avr +#define helper_atomic_fetch_umaxq_be helper_atomic_fetch_umaxq_be_avr +#define helper_atomic_smin_fetchq_be helper_atomic_smin_fetchq_be_avr +#define helper_atomic_umin_fetchq_be helper_atomic_umin_fetchq_be_avr +#define helper_atomic_smax_fetchq_be helper_atomic_smax_fetchq_be_avr +#define helper_atomic_umax_fetchq_be helper_atomic_umax_fetchq_be_avr +#define helper_atomic_fetch_addq_be helper_atomic_fetch_addq_be_avr +#define helper_atomic_add_fetchq_be helper_atomic_add_fetchq_be_avr +#define cpu_ldub_code cpu_ldub_code_avr +#define cpu_lduw_code cpu_lduw_code_avr +#define cpu_ldl_code cpu_ldl_code_avr +#define cpu_ldq_code cpu_ldq_code_avr +#define helper_div_i32 helper_div_i32_avr +#define helper_rem_i32 helper_rem_i32_avr +#define helper_divu_i32 helper_divu_i32_avr +#define helper_remu_i32 helper_remu_i32_avr +#define helper_shl_i64 helper_shl_i64_avr +#define helper_shr_i64 helper_shr_i64_avr +#define helper_sar_i64 helper_sar_i64_avr +#define helper_div_i64 helper_div_i64_avr +#define helper_rem_i64 helper_rem_i64_avr +#define helper_divu_i64 helper_divu_i64_avr +#define helper_remu_i64 helper_remu_i64_avr +#define helper_muluh_i64 helper_muluh_i64_avr +#define helper_mulsh_i64 helper_mulsh_i64_avr +#define helper_clz_i32 helper_clz_i32_avr +#define helper_ctz_i32 helper_ctz_i32_avr +#define helper_clz_i64 helper_clz_i64_avr +#define helper_ctz_i64 helper_ctz_i64_avr +#define helper_clrsb_i32 helper_clrsb_i32_avr +#define helper_clrsb_i64 helper_clrsb_i64_avr +#define helper_ctpop_i32 helper_ctpop_i32_avr +#define helper_ctpop_i64 helper_ctpop_i64_avr +#define helper_lookup_tb_ptr helper_lookup_tb_ptr_avr +#define helper_exit_atomic helper_exit_atomic_avr +#define helper_gvec_add8 helper_gvec_add8_avr +#define helper_gvec_add16 helper_gvec_add16_avr +#define helper_gvec_add32 helper_gvec_add32_avr +#define helper_gvec_add64 helper_gvec_add64_avr +#define helper_gvec_adds8 helper_gvec_adds8_avr +#define helper_gvec_adds16 helper_gvec_adds16_avr +#define helper_gvec_adds32 helper_gvec_adds32_avr +#define helper_gvec_adds64 helper_gvec_adds64_avr +#define helper_gvec_sub8 helper_gvec_sub8_avr +#define helper_gvec_sub16 helper_gvec_sub16_avr +#define helper_gvec_sub32 helper_gvec_sub32_avr +#define helper_gvec_sub64 helper_gvec_sub64_avr +#define helper_gvec_subs8 helper_gvec_subs8_avr +#define helper_gvec_subs16 helper_gvec_subs16_avr +#define helper_gvec_subs32 helper_gvec_subs32_avr +#define helper_gvec_subs64 helper_gvec_subs64_avr +#define helper_gvec_mul8 helper_gvec_mul8_avr +#define helper_gvec_mul16 helper_gvec_mul16_avr +#define helper_gvec_mul32 helper_gvec_mul32_avr +#define helper_gvec_mul64 helper_gvec_mul64_avr +#define helper_gvec_muls8 helper_gvec_muls8_avr +#define helper_gvec_muls16 helper_gvec_muls16_avr +#define helper_gvec_muls32 helper_gvec_muls32_avr +#define helper_gvec_muls64 helper_gvec_muls64_avr +#define helper_gvec_neg8 helper_gvec_neg8_avr +#define helper_gvec_neg16 helper_gvec_neg16_avr +#define helper_gvec_neg32 helper_gvec_neg32_avr +#define helper_gvec_neg64 helper_gvec_neg64_avr +#define helper_gvec_abs8 helper_gvec_abs8_avr +#define helper_gvec_abs16 helper_gvec_abs16_avr +#define helper_gvec_abs32 helper_gvec_abs32_avr +#define helper_gvec_abs64 helper_gvec_abs64_avr +#define helper_gvec_mov helper_gvec_mov_avr +#define helper_gvec_dup64 helper_gvec_dup64_avr +#define helper_gvec_dup32 helper_gvec_dup32_avr +#define helper_gvec_dup16 helper_gvec_dup16_avr +#define helper_gvec_dup8 helper_gvec_dup8_avr +#define helper_gvec_not helper_gvec_not_avr +#define helper_gvec_and helper_gvec_and_avr +#define helper_gvec_or helper_gvec_or_avr +#define helper_gvec_xor helper_gvec_xor_avr +#define helper_gvec_andc helper_gvec_andc_avr +#define helper_gvec_orc helper_gvec_orc_avr +#define helper_gvec_nand helper_gvec_nand_avr +#define helper_gvec_nor helper_gvec_nor_avr +#define helper_gvec_eqv helper_gvec_eqv_avr +#define helper_gvec_ands helper_gvec_ands_avr +#define helper_gvec_xors helper_gvec_xors_avr +#define helper_gvec_ors helper_gvec_ors_avr +#define helper_gvec_shl8i helper_gvec_shl8i_avr +#define helper_gvec_shl16i helper_gvec_shl16i_avr +#define helper_gvec_shl32i helper_gvec_shl32i_avr +#define helper_gvec_shl64i helper_gvec_shl64i_avr +#define helper_gvec_shr8i helper_gvec_shr8i_avr +#define helper_gvec_shr16i helper_gvec_shr16i_avr +#define helper_gvec_shr32i helper_gvec_shr32i_avr +#define helper_gvec_shr64i helper_gvec_shr64i_avr +#define helper_gvec_sar8i helper_gvec_sar8i_avr +#define helper_gvec_sar16i helper_gvec_sar16i_avr +#define helper_gvec_sar32i helper_gvec_sar32i_avr +#define helper_gvec_sar64i helper_gvec_sar64i_avr +#define helper_gvec_shl8v helper_gvec_shl8v_avr +#define helper_gvec_shl16v helper_gvec_shl16v_avr +#define helper_gvec_shl32v helper_gvec_shl32v_avr +#define helper_gvec_shl64v helper_gvec_shl64v_avr +#define helper_gvec_shr8v helper_gvec_shr8v_avr +#define helper_gvec_shr16v helper_gvec_shr16v_avr +#define helper_gvec_shr32v helper_gvec_shr32v_avr +#define helper_gvec_shr64v helper_gvec_shr64v_avr +#define helper_gvec_sar8v helper_gvec_sar8v_avr +#define helper_gvec_sar16v helper_gvec_sar16v_avr +#define helper_gvec_sar32v helper_gvec_sar32v_avr +#define helper_gvec_sar64v helper_gvec_sar64v_avr +#define helper_gvec_eq8 helper_gvec_eq8_avr +#define helper_gvec_ne8 helper_gvec_ne8_avr +#define helper_gvec_lt8 helper_gvec_lt8_avr +#define helper_gvec_le8 helper_gvec_le8_avr +#define helper_gvec_ltu8 helper_gvec_ltu8_avr +#define helper_gvec_leu8 helper_gvec_leu8_avr +#define helper_gvec_eq16 helper_gvec_eq16_avr +#define helper_gvec_ne16 helper_gvec_ne16_avr +#define helper_gvec_lt16 helper_gvec_lt16_avr +#define helper_gvec_le16 helper_gvec_le16_avr +#define helper_gvec_ltu16 helper_gvec_ltu16_avr +#define helper_gvec_leu16 helper_gvec_leu16_avr +#define helper_gvec_eq32 helper_gvec_eq32_avr +#define helper_gvec_ne32 helper_gvec_ne32_avr +#define helper_gvec_lt32 helper_gvec_lt32_avr +#define helper_gvec_le32 helper_gvec_le32_avr +#define helper_gvec_ltu32 helper_gvec_ltu32_avr +#define helper_gvec_leu32 helper_gvec_leu32_avr +#define helper_gvec_eq64 helper_gvec_eq64_avr +#define helper_gvec_ne64 helper_gvec_ne64_avr +#define helper_gvec_lt64 helper_gvec_lt64_avr +#define helper_gvec_le64 helper_gvec_le64_avr +#define helper_gvec_ltu64 helper_gvec_ltu64_avr +#define helper_gvec_leu64 helper_gvec_leu64_avr +#define helper_gvec_ssadd8 helper_gvec_ssadd8_avr +#define helper_gvec_ssadd16 helper_gvec_ssadd16_avr +#define helper_gvec_ssadd32 helper_gvec_ssadd32_avr +#define helper_gvec_ssadd64 helper_gvec_ssadd64_avr +#define helper_gvec_sssub8 helper_gvec_sssub8_avr +#define helper_gvec_sssub16 helper_gvec_sssub16_avr +#define helper_gvec_sssub32 helper_gvec_sssub32_avr +#define helper_gvec_sssub64 helper_gvec_sssub64_avr +#define helper_gvec_usadd8 helper_gvec_usadd8_avr +#define helper_gvec_usadd16 helper_gvec_usadd16_avr +#define helper_gvec_usadd32 helper_gvec_usadd32_avr +#define helper_gvec_usadd64 helper_gvec_usadd64_avr +#define helper_gvec_ussub8 helper_gvec_ussub8_avr +#define helper_gvec_ussub16 helper_gvec_ussub16_avr +#define helper_gvec_ussub32 helper_gvec_ussub32_avr +#define helper_gvec_ussub64 helper_gvec_ussub64_avr +#define helper_gvec_smin8 helper_gvec_smin8_avr +#define helper_gvec_smin16 helper_gvec_smin16_avr +#define helper_gvec_smin32 helper_gvec_smin32_avr +#define helper_gvec_smin64 helper_gvec_smin64_avr +#define helper_gvec_smax8 helper_gvec_smax8_avr +#define helper_gvec_smax16 helper_gvec_smax16_avr +#define helper_gvec_smax32 helper_gvec_smax32_avr +#define helper_gvec_smax64 helper_gvec_smax64_avr +#define helper_gvec_umin8 helper_gvec_umin8_avr +#define helper_gvec_umin16 helper_gvec_umin16_avr +#define helper_gvec_umin32 helper_gvec_umin32_avr +#define helper_gvec_umin64 helper_gvec_umin64_avr +#define helper_gvec_umax8 helper_gvec_umax8_avr +#define helper_gvec_umax16 helper_gvec_umax16_avr +#define helper_gvec_umax32 helper_gvec_umax32_avr +#define helper_gvec_umax64 helper_gvec_umax64_avr +#define helper_gvec_bitsel helper_gvec_bitsel_avr +#define cpu_restore_state cpu_restore_state_avr +#define page_collection_lock page_collection_lock_avr +#define page_collection_unlock page_collection_unlock_avr +#define free_code_gen_buffer free_code_gen_buffer_avr +#define tcg_exec_init tcg_exec_init_avr +#define tb_cleanup tb_cleanup_avr +#define tb_flush tb_flush_avr +#define tb_phys_invalidate tb_phys_invalidate_avr +#define tb_gen_code tb_gen_code_avr +#define tb_exec_lock tb_exec_lock_avr +#define tb_exec_unlock tb_exec_unlock_avr +#define tb_invalidate_phys_page_range tb_invalidate_phys_page_range_avr +#define tb_invalidate_phys_range tb_invalidate_phys_range_avr +#define tb_invalidate_phys_page_fast tb_invalidate_phys_page_fast_avr +#define tb_check_watchpoint tb_check_watchpoint_avr +#define cpu_io_recompile cpu_io_recompile_avr +#define tb_flush_jmp_cache tb_flush_jmp_cache_avr +#define tcg_flush_softmmu_tlb tcg_flush_softmmu_tlb_avr +#define translator_loop_temp_check translator_loop_temp_check_avr +#define translator_loop translator_loop_avr +#define helper_atomic_cmpxchgo_le_mmu helper_atomic_cmpxchgo_le_mmu_avr +#define helper_atomic_cmpxchgo_be_mmu helper_atomic_cmpxchgo_be_mmu_avr +#define helper_atomic_ldo_le_mmu helper_atomic_ldo_le_mmu_avr +#define helper_atomic_ldo_be_mmu helper_atomic_ldo_be_mmu_avr +#define helper_atomic_sto_le_mmu helper_atomic_sto_le_mmu_avr +#define helper_atomic_sto_be_mmu helper_atomic_sto_be_mmu_avr +#define unassigned_mem_ops unassigned_mem_ops_avr +#define floatx80_infinity floatx80_infinity_avr +#define dup_const_func dup_const_func_avr +#define gen_helper_raise_exception gen_helper_raise_exception_avr +#define gen_helper_raise_interrupt gen_helper_raise_interrupt_avr +#define gen_helper_vfp_get_fpscr gen_helper_vfp_get_fpscr_avr +#define gen_helper_vfp_set_fpscr gen_helper_vfp_set_fpscr_avr +#define gen_helper_cpsr_read gen_helper_cpsr_read_avr +#define gen_helper_cpsr_write gen_helper_cpsr_write_avr +#define helper_sleep helper_sleep_avr +#define helper_unsupported helper_unsupported_avr +#define helper_debug helper_debug_avr +#define helper_break helper_break_avr +#define helper_inb helper_inb_avr +#define helper_outb helper_outb_avr +#define helper_fullrd helper_fullrd_avr +#define helper_fullwr helper_fullwr_avr +#define helper_wdr helper_wdr_avr +#define gen_intermediate_code gen_intermediate_code_avr +#define restore_state_to_opc restore_state_to_opc_avr +#endif diff --git a/symbols.sh b/symbols.sh index 29600c7e2d..8249fbf29e 100755 --- a/symbols.sh +++ b/symbols.sh @@ -6284,7 +6284,21 @@ restore_state_to_opc \ helper_uc_tricore_exit \ " -ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore" +avr_SYMBOLS=" +helper_sleep \ +helper_unsupported \ +helper_debug \ +helper_break \ +helper_inb \ +helper_outb \ +helper_fullrd \ +helper_fullwr \ +helper_wdr \ +gen_intermediate_code \ +restore_state_to_opc \ +" + +ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore avr" for arch in $ARCHS; do From 1d20309a3c42a35ea71c1f462cab70d3f60faa02 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 27 Mar 2024 10:51:49 +0100 Subject: [PATCH 09/31] qemu/target/avr: add initial Unicorn integration. Signed-off-by: Glenn Baker --- qemu/include/tcg/tcg.h | 19 ++- qemu/target/avr/cpu-qom.h | 17 ++- qemu/target/avr/cpu.c | 112 +++++++++++--- qemu/target/avr/cpu.h | 8 +- qemu/target/avr/helper.c | 25 +++- qemu/target/avr/helper.h | 8 + qemu/target/avr/translate.c | 243 +++++++++++++++++++++++++------ qemu/target/avr/unicorn_helper.h | 163 +++++++++++++++++++++ 8 files changed, 523 insertions(+), 72 deletions(-) create mode 100644 qemu/target/avr/unicorn_helper.h diff --git a/qemu/include/tcg/tcg.h b/qemu/include/tcg/tcg.h index e5afa98881..a88aad109d 100644 --- a/qemu/include/tcg/tcg.h +++ b/qemu/include/tcg/tcg.h @@ -712,7 +712,7 @@ struct TCGContext { void *tb_ret_addr; /* target/riscv/translate.c */ - TCGv cpu_gpr[32], cpu_pc; // also target/mips/translate.c + TCGv cpu_gpr[32], cpu_pc; // also target/mips/translate.c, target/avr/translate.c TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ TCGv load_res; TCGv load_val; @@ -807,6 +807,23 @@ struct TCGContext { char s390x_cpu_reg_names[16][4]; // renamed from original cpu_reg_names[][] to avoid name clash with m68k TCGv_i64 regs[16]; + + // target/avr/translate.c + TCGv cpu_Cf; + TCGv cpu_Zf; + TCGv cpu_Nf; + TCGv cpu_Vf; + TCGv cpu_Sf; + TCGv cpu_Hf; + TCGv cpu_Tf; + TCGv cpu_If; + TCGv cpu_rampD; + TCGv cpu_rampX; + TCGv cpu_rampY; + TCGv cpu_rampZ; + TCGv cpu_eind; + TCGv cpu_sp; + TCGv cpu_skip; }; static inline size_t temp_idx(TCGContext *tcg_ctx, TCGTemp *ts) diff --git a/qemu/target/avr/cpu-qom.h b/qemu/target/avr/cpu-qom.h index 9fa6989c18..9ba1ea1b37 100644 --- a/qemu/target/avr/cpu-qom.h +++ b/qemu/target/avr/cpu-qom.h @@ -22,12 +22,19 @@ #define QEMU_AVR_QOM_H #include "hw/core/cpu.h" -#include "qom/object.h" + +typedef void Object; +typedef void ObjectClass; + +typedef void DeviceState; +typedef void (*DeviceRealize)(DeviceState *ds); +typedef void (*DeviceReset)(DeviceState *ds); #define TYPE_AVR_CPU "avr-cpu" -OBJECT_DECLARE_TYPE(AVRCPU, AVRCPUClass, - AVR_CPU) +#define AVR_CPU(obj) ((AVRCPU *)obj) +#define AVR_CPU_CLASS(klass) ((AVRCPUClass *)klass) +#define AVR_CPU_GET_CLASS(obj) (&((AVRCPU *)obj)->cc) /** * AVRCPUClass: @@ -37,13 +44,13 @@ OBJECT_DECLARE_TYPE(AVRCPU, AVRCPUClass, * * A AVR CPU model. */ -struct AVRCPUClass { +typedef struct AVRCPUClass { /*< private >*/ CPUClass parent_class; /*< public >*/ DeviceRealize parent_realize; DeviceReset parent_reset; -}; +} AVRCPUClass; #endif /* !defined (QEMU_AVR_CPU_QOM_H) */ diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c index 5d9c4ad5bf..ecf713f9c8 100644 --- a/qemu/target/avr/cpu.c +++ b/qemu/target/avr/cpu.c @@ -19,11 +19,10 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "cpu.h" #include "disas/dis-asm.h" +#include "unicorn_helper.h" static void avr_cpu_set_pc(CPUState *cs, vaddr value) { @@ -56,7 +55,8 @@ static void avr_cpu_reset(DeviceState *ds) AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); CPUAVRState *env = &cpu->env; - mcc->parent_reset(ds); + if (mcc->parent_reset) + mcc->parent_reset(ds); env->pc_w = 0; env->sregI = 1; @@ -80,29 +80,28 @@ static void avr_cpu_reset(DeviceState *ds) memset(env->r, 0, sizeof(env->r)); } +#if 0 static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) { info->mach = bfd_arch_avr; info->print_insn = avr_print_insn; } +#endif -static void avr_cpu_realizefn(DeviceState *dev, Error **errp) +static void avr_cpu_realizefn(DeviceState *dev) { CPUState *cs = CPU(dev); AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); - Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } + cpu_exec_realizefn(cs); qemu_init_vcpu(cs); cpu_reset(cs); - mcc->parent_realize(dev, errp); + if (mcc->parent_realize) + mcc->parent_realize(dev); } +#if 0 static void avr_cpu_set_int(void *opaque, int irq, int level) { AVRCPU *cpu = opaque; @@ -120,18 +119,24 @@ static void avr_cpu_set_int(void *opaque, int irq, int level) } } } +#endif -static void avr_cpu_initfn(Object *obj) +static void avr_cpu_initfn(Object *obj, struct uc_struct *uc) { AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *const env = &cpu->env; + env->uc = uc; cpu_set_cpustate_pointers(cpu); +#if 0 /* Set the number of interrupts supported by the CPU. */ qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, sizeof(cpu->env.intsrc) * 8); +#endif } +#if 0 static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -143,7 +148,9 @@ static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) } return oc; } +#endif +#if 0 static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) { AVRCPU *cpu = AVR_CPU(cs); @@ -182,36 +189,45 @@ static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) } qemu_fprintf(f, "\n"); } +#endif static void avr_cpu_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); AVRCPUClass *mcc = AVR_CPU_CLASS(oc); - mcc->parent_realize = dc->realize; - dc->realize = avr_cpu_realizefn; - - device_class_set_parent_reset(dc, avr_cpu_reset, &mcc->parent_reset); + mcc->parent_realize = NULL; + mcc->parent_reset = NULL; +#if 0 cc->class_by_name = avr_cpu_class_by_name; +#endif + cc->reset = avr_cpu_reset; cc->has_work = avr_cpu_has_work; cc->do_interrupt = avr_cpu_do_interrupt; cc->cpu_exec_interrupt = avr_cpu_exec_interrupt; +#if 0 cc->dump_state = avr_cpu_dump_state; +#endif cc->set_pc = avr_cpu_set_pc; +#if 0 cc->memory_rw_debug = avr_cpu_memory_rw_debug; +#endif cc->get_phys_page_debug = avr_cpu_get_phys_page_debug; cc->tlb_fill = avr_cpu_tlb_fill; +#if 0 cc->vmsd = &vms_avr_cpu; cc->disas_set_info = avr_cpu_disas_set_info; +#endif cc->tcg_initialize = avr_cpu_tcg_init; cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; +#if 0 cc->gdb_read_register = avr_cpu_gdb_read_register; cc->gdb_write_register = avr_cpu_gdb_write_register; cc->gdb_num_core_regs = 35; cc->gdb_core_xml_file = "avr-cpu.xml"; +#endif } /* @@ -321,11 +337,28 @@ static void avr_avr6_initfn(Object *obj) } typedef struct AVRCPUInfo { + int model; const char *name; void (*initfn)(Object *obj); } AVRCPUInfo; +static const AVRCPUInfo avr_cpu_info[] ={ + {UC_CPU_AVR_AVR5, "avr5", avr_avr5_initfn}, + {UC_CPU_AVR_AVR51, "avr51", avr_avr51_initfn}, + {UC_CPU_AVR_AVR6, "avr6", avr_avr6_initfn}, +}; + +static const AVRCPUInfo *avr_cpu_info_get(int cpu_model) +{ + for (int i = 0; i < ARRAY_SIZE(avr_cpu_info); i++) { + const AVRCPUInfo *const cip = &avr_cpu_info[i]; + if (cpu_model == cip->model) + return cip; + } + return NULL; +} +#if 0 static void avr_cpu_list_entry(gpointer data, gpointer user_data) { const char *typename = object_class_get_name(OBJECT_CLASS(data)); @@ -364,3 +397,48 @@ static const TypeInfo avr_cpu_type_info[] = { }; DEFINE_TYPES(avr_cpu_type_info) +#endif + +AVRCPU *cpu_avr_init(struct uc_struct *uc) +{ + AVRCPU *cpu; + CPUState *cs; + CPUClass *cc; + ObjectClass *oc; + + cpu = calloc(1, sizeof(*cpu)); + if (cpu == NULL) { + return NULL; + } + + if (uc->cpu_model == INT_MAX) + uc->cpu_model = UC_CPU_AVR_AVR6; + const AVRCPUInfo *const cip = avr_cpu_info_get(uc->cpu_model); + if (!cip) { + free(cpu); + return NULL; + } + + cs = &cpu->parent_obj; + cc = &AVR_CPU_GET_CLASS(cpu)->parent_class; + oc = (ObjectClass *)cc; + cs->cc = cc; + cs->uc = uc; + uc->cpu = cs; + + cpu_class_init(uc, cc); + avr_cpu_class_init(oc, NULL); + + cpu_common_initfn(uc, cs); + avr_cpu_initfn(cs, uc); + cip->initfn(cs); + + avr_cpu_realizefn(cs); + + // init address space + cpu_address_space_init(cs, 0, cs->memory); + + qemu_init_vcpu(cs); + + return cpu; +} diff --git a/qemu/target/avr/cpu.h b/qemu/target/avr/cpu.h index d148e8c75a..380374b37b 100644 --- a/qemu/target/avr/cpu.h +++ b/qemu/target/avr/cpu.h @@ -23,6 +23,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "disas/dis-asm.h" #ifdef CONFIG_USER_ONLY #error "AVR 8-bit does not support user mode" @@ -137,6 +138,9 @@ struct CPUAVRState { bool fullacc; /* CPU/MEM if true MEM only otherwise */ uint64_t features; + + // Unicorn engine + struct uc_struct *uc; }; /** @@ -152,6 +156,8 @@ typedef struct AVRCPU { CPUNegativeOffsetState neg; CPUAVRState env; + + AVRCPUClass cc; } AVRCPU; extern const struct VMStateDescription vms_avr_cpu; @@ -182,7 +188,7 @@ static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; } -void avr_cpu_tcg_init(void); +void avr_cpu_tcg_init(struct uc_struct *uc); void avr_cpu_list(void); int cpu_avr_exec(CPUState *cpu); diff --git a/qemu/target/avr/helper.c b/qemu/target/avr/helper.c index d96d14372b..459236c688 100644 --- a/qemu/target/avr/helper.c +++ b/qemu/target/avr/helper.c @@ -21,8 +21,8 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" -#include "exec/address-spaces.h" #include "exec/helper-proto.h" +#include "unicorn_helper.h" bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { @@ -160,10 +160,12 @@ void helper_unsupported(CPUAVRState *env) * it's EXCP_DEBUG for meanwhile */ cs->exception_index = EXCP_DEBUG; +#if 0 if (qemu_loglevel_mask(LOG_UNIMP)) { qemu_log("UNSUPPORTED\n"); cpu_dump_state(cs, stderr, 0); } +#endif cpu_loop_exit(cs); } @@ -204,6 +206,9 @@ void helper_wdr(CPUAVRState *env) */ target_ulong helper_inb(CPUAVRState *env, uint32_t port) { + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + target_ulong data = 0; switch (port) { @@ -253,6 +258,9 @@ target_ulong helper_inb(CPUAVRState *env, uint32_t port) */ void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) { + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + data &= 0x000000ff; switch (port) { @@ -303,6 +311,9 @@ void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) */ target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) { + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + uint8_t data; env->fullacc = false; @@ -327,6 +338,9 @@ target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) */ void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) { + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + env->fullacc = false; /* Following logic assumes this: */ @@ -346,3 +360,12 @@ void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) MEMTXATTRS_UNSPECIFIED, NULL); } } + +void helper_uc_avr_exit(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); +} diff --git a/qemu/target/avr/helper.h b/qemu/target/avr/helper.h index 8e1ae7fda0..06fc1d323c 100644 --- a/qemu/target/avr/helper.h +++ b/qemu/target/avr/helper.h @@ -18,6 +18,14 @@ * */ +/* + Modified for Unicorn Engine by Glenn Baker , 2024 +*/ + +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) +DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) +DEF_HELPER_1(uc_avr_exit,void, env) + DEF_HELPER_1(wdr, void, env) DEF_HELPER_1(debug, void, env) DEF_HELPER_1(break, void, env) diff --git a/qemu/target/avr/translate.c b/qemu/target/avr/translate.c index 850c5941d9..2907497c41 100644 --- a/qemu/target/avr/translate.c +++ b/qemu/target/avr/translate.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu/qemu-print.h" #include "tcg/tcg.h" #include "cpu.h" #include "exec/exec-all.h" @@ -27,9 +26,31 @@ #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" -#include "exec/log.h" #include "exec/translator.h" #include "exec/gen-icount.h" +#include "unicorn_helper.h" + +#define gen_decl(func, ...) \ + glue(gen_,func)(TCGContext *tcg_ctx, ## __VA_ARGS__) +#define gen_call(func, ...) \ + glue(gen_,func)(tcg_ctx, ## __VA_ARGS__) + +#define gen_io_end() gen_call(io_end) +#define gen_tb_start(...) gen_call(tb_start, __VA_ARGS__) +#define gen_tb_end(...) gen_call(tb_end, __VA_ARGS__) + +#define gen_helper_call(name, ...) \ + glue(gen_helper_,name)(tcg_ctx, ## __VA_ARGS__) +#define gen_helper_unsupported(...) \ + gen_helper_call(unsupported, __VA_ARGS__) + +#define gen_helper_debug(...) gen_helper_call(debug, __VA_ARGS__) +#define gen_helper_sleep(...) gen_helper_call(sleep, __VA_ARGS__) +#define gen_helper_inb(...) gen_helper_call(inb, __VA_ARGS__) +#define gen_helper_outb(...) gen_helper_call(outb, __VA_ARGS__) +#define gen_helper_fullrd(...) gen_helper_call(fullrd, __VA_ARGS__) +#define gen_helper_fullwr(...) gen_helper_call(fullwr, __VA_ARGS__) +#define gen_helper_wdr(...) gen_helper_call(wdr, __VA_ARGS__) /* * Define if you want a BREAK instruction translated to a breakpoint @@ -40,27 +61,23 @@ */ #undef BREAKPOINT_ON_BREAK -static TCGv cpu_pc; - -static TCGv cpu_Cf; -static TCGv cpu_Zf; -static TCGv cpu_Nf; -static TCGv cpu_Vf; -static TCGv cpu_Sf; -static TCGv cpu_Hf; -static TCGv cpu_Tf; -static TCGv cpu_If; - -static TCGv cpu_rampD; -static TCGv cpu_rampX; -static TCGv cpu_rampY; -static TCGv cpu_rampZ; - -static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS]; -static TCGv cpu_eind; -static TCGv cpu_sp; - -static TCGv cpu_skip; +#define cpu_pc (tcg_ctx->cpu_pc) +#define cpu_Cf (tcg_ctx->cpu_Cf) +#define cpu_Zf (tcg_ctx->cpu_ZF) +#define cpu_Nf (tcg_ctx->cpu_NF) +#define cpu_Vf (tcg_ctx->cpu_VF) +#define cpu_Sf (tcg_ctx->cpu_Sf) +#define cpu_Hf (tcg_ctx->cpu_Hf) +#define cpu_Tf (tcg_ctx->cpu_Tf) +#define cpu_If (tcg_ctx->cpu_If) +#define cpu_rampD (tcg_ctx->cpu_rampD) +#define cpu_rampX (tcg_ctx->cpu_rampX) +#define cpu_rampY (tcg_ctx->cpu_rampY) +#define cpu_rampZ (tcg_ctx->cpu_rampZ) +#define cpu_r (tcg_ctx->cpu_gpr) +#define cpu_eind (tcg_ctx->cpu_eind) +#define cpu_sp (tcg_ctx->cpu_sp) +#define cpu_skip (tcg_ctx->cpu_skip) static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -74,6 +91,7 @@ enum { DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */ DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */ DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */ + DISAS_UC_EXIT = DISAS_TARGET_3, /* Unicorn: special state for exiting in the middle of tb. */ }; typedef struct DisasContext DisasContext; @@ -128,10 +146,13 @@ struct DisasContext { bool free_skip_var0; }; -void avr_cpu_tcg_init(void) +void avr_cpu_tcg_init(struct uc_struct *uc) { int i; + INIT_TCG_CONTEXT_FROM_UC(uc); + INIT_CPU_ENV_FROM_TCG_CONTEXT(tcg_ctx); + #define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); @@ -189,6 +210,7 @@ static int append_16(DisasContext *ctx, int x) static bool avr_have_feature(DisasContext *ctx, int feature) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); if (!avr_feature(ctx->env, feature)) { gen_helper_unsupported(cpu_env); ctx->bstate = DISAS_NORETURN; @@ -216,7 +238,7 @@ static bool decode_insn(DisasContext *ctx, uint16_t insn); * */ -static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +static void gen_decl(add_CHf, TCGv R, TCGv Rd, TCGv Rr) { TCGv t1 = tcg_temp_new_i32(); TCGv t2 = tcg_temp_new_i32(); @@ -237,7 +259,7 @@ static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) tcg_temp_free_i32(t1); } -static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +static void gen_decl(add_Vf, TCGv R, TCGv Rd, TCGv Rr) { TCGv t1 = tcg_temp_new_i32(); TCGv t2 = tcg_temp_new_i32(); @@ -254,7 +276,7 @@ static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) tcg_temp_free_i32(t1); } -static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) +static void gen_decl(sub_CHf, TCGv R, TCGv Rd, TCGv Rr) { TCGv t1 = tcg_temp_new_i32(); TCGv t2 = tcg_temp_new_i32(); @@ -275,7 +297,7 @@ static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) tcg_temp_free_i32(t1); } -static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) +static void gen_decl(sub_Vf, TCGv R, TCGv Rd, TCGv Rr) { TCGv t1 = tcg_temp_new_i32(); TCGv t2 = tcg_temp_new_i32(); @@ -292,13 +314,13 @@ static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) tcg_temp_free_i32(t1); } -static void gen_NSf(TCGv R) +static void gen_decl(NSf, TCGv R) { tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ } -static void gen_ZNSf(TCGv R) +static void gen_decl(ZNSf, TCGv R) { tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ @@ -307,12 +329,23 @@ static void gen_ZNSf(TCGv R) tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ } +#define gen_add_CHf(...) gen_call(add_CHf, __VA_ARGS__) +#define gen_add_Vf(...) gen_call(add_Vf, __VA_ARGS__) +#define gen_sub_CHf(...) gen_call(sub_CHf, __VA_ARGS__) +#define gen_sub_Vf(...) gen_call(sub_Vf, __VA_ARGS__) +#define gen_NSf(...) gen_call(NSf, __VA_ARGS__) +#define gen_ZNSf(...) gen_call(ZNSf, __VA_ARGS__) + +#define gen_new_label_avr() gen_call(new_label_avr) +#define gen_set_label(...) gen_call(set_label, __VA_ARGS__) + /* * Adds two registers without the C Flag and places the result in the * destination register Rd. */ static bool trans_ADD(DisasContext *ctx, arg_ADD *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -339,6 +372,7 @@ static bool trans_ADD(DisasContext *ctx, arg_ADD *a) */ static bool trans_ADC(DisasContext *ctx, arg_ADC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -373,6 +407,7 @@ static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv RdL = cpu_r[a->rd]; TCGv RdH = cpu_r[a->rd + 1]; int Imm = (a->imm); @@ -408,6 +443,7 @@ static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) */ static bool trans_SUB(DisasContext *ctx, arg_SUB *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -436,6 +472,7 @@ static bool trans_SUB(DisasContext *ctx, arg_SUB *a) */ static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = tcg_const_i32(a->imm); TCGv R = tcg_temp_new_i32(); @@ -463,6 +500,7 @@ static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) */ static bool trans_SBC(DisasContext *ctx, arg_SBC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -497,6 +535,7 @@ static bool trans_SBC(DisasContext *ctx, arg_SBC *a) */ static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = tcg_const_i32(a->imm); TCGv R = tcg_temp_new_i32(); @@ -540,6 +579,7 @@ static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv RdL = cpu_r[a->rd]; TCGv RdH = cpu_r[a->rd + 1]; int Imm = (a->imm); @@ -575,6 +615,7 @@ static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) */ static bool trans_AND(DisasContext *ctx, arg_AND *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -600,6 +641,7 @@ static bool trans_AND(DisasContext *ctx, arg_AND *a) */ static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; int Imm = (a->imm); @@ -618,6 +660,7 @@ static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) */ static bool trans_OR(DisasContext *ctx, arg_OR *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -642,6 +685,7 @@ static bool trans_OR(DisasContext *ctx, arg_OR *a) */ static bool trans_ORI(DisasContext *ctx, arg_ORI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; int Imm = (a->imm); @@ -660,6 +704,7 @@ static bool trans_ORI(DisasContext *ctx, arg_ORI *a) */ static bool trans_EOR(DisasContext *ctx, arg_EOR *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; @@ -679,6 +724,7 @@ static bool trans_EOR(DisasContext *ctx, arg_EOR *a) */ static bool trans_COM(DisasContext *ctx, arg_COM *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv R = tcg_temp_new_i32(); @@ -700,6 +746,7 @@ static bool trans_COM(DisasContext *ctx, arg_COM *a) */ static bool trans_NEG(DisasContext *ctx, arg_NEG *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv t0 = tcg_const_i32(0); TCGv R = tcg_temp_new_i32(); @@ -731,6 +778,7 @@ static bool trans_NEG(DisasContext *ctx, arg_NEG *a) */ static bool trans_INC(DisasContext *ctx, arg_INC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; tcg_gen_addi_tl(Rd, Rd, 1); @@ -753,6 +801,7 @@ static bool trans_INC(DisasContext *ctx, arg_INC *a) */ static bool trans_DEC(DisasContext *ctx, arg_DEC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ @@ -774,6 +823,7 @@ static bool trans_MUL(DisasContext *ctx, arg_MUL *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv R0 = cpu_r[0]; TCGv R1 = cpu_r[1]; TCGv Rd = cpu_r[a->rd]; @@ -802,6 +852,7 @@ static bool trans_MULS(DisasContext *ctx, arg_MULS *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv R0 = cpu_r[0]; TCGv R1 = cpu_r[1]; TCGv Rd = cpu_r[a->rd]; @@ -838,6 +889,7 @@ static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv R0 = cpu_r[0]; TCGv R1 = cpu_r[1]; TCGv Rd = cpu_r[a->rd]; @@ -871,6 +923,7 @@ static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv R0 = cpu_r[0]; TCGv R1 = cpu_r[1]; TCGv Rd = cpu_r[a->rd]; @@ -905,6 +958,7 @@ static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv R0 = cpu_r[0]; TCGv R1 = cpu_r[1]; TCGv Rd = cpu_r[a->rd]; @@ -945,6 +999,7 @@ static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv R0 = cpu_r[0]; TCGv R1 = cpu_r[1]; TCGv Rd = cpu_r[a->rd]; @@ -1009,6 +1064,7 @@ static bool trans_DES(DisasContext *ctx, arg_DES *a) */ static void gen_jmp_ez(DisasContext *ctx) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); ctx->bstate = DISAS_LOOKUP; @@ -1016,12 +1072,14 @@ static void gen_jmp_ez(DisasContext *ctx) static void gen_jmp_z(DisasContext *ctx) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); ctx->bstate = DISAS_LOOKUP; } static void gen_push_ret(DisasContext *ctx, int ret) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { TCGv t0 = tcg_const_i32((ret & 0x0000ff)); @@ -1057,6 +1115,7 @@ static void gen_push_ret(DisasContext *ctx, int ret) static void gen_pop_ret(DisasContext *ctx, TCGv ret) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); @@ -1083,6 +1142,7 @@ static void gen_pop_ret(DisasContext *ctx, TCGv ret) static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TranslationBlock *tb = ctx->tb; if (ctx->singlestep == 0) { @@ -1252,6 +1312,7 @@ static bool trans_CALL(DisasContext *ctx, arg_CALL *a) */ static bool trans_RET(DisasContext *ctx, arg_RET *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); gen_pop_ret(ctx, cpu_pc); ctx->bstate = DISAS_LOOKUP; @@ -1268,6 +1329,7 @@ static bool trans_RET(DisasContext *ctx, arg_RET *a) */ static bool trans_RETI(DisasContext *ctx, arg_RETI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); gen_pop_ret(ctx, cpu_pc); tcg_gen_movi_tl(cpu_If, 1); @@ -1282,6 +1344,7 @@ static bool trans_RETI(DisasContext *ctx, arg_RETI *a) */ static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); ctx->skip_cond = TCG_COND_EQ; ctx->skip_var0 = cpu_r[a->rd]; ctx->skip_var1 = cpu_r[a->rr]; @@ -1295,6 +1358,7 @@ static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) */ static bool trans_CP(DisasContext *ctx, arg_CP *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -1319,6 +1383,7 @@ static bool trans_CP(DisasContext *ctx, arg_CP *a) */ static bool trans_CPC(DisasContext *ctx, arg_CPC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; TCGv R = tcg_temp_new_i32(); @@ -1351,6 +1416,7 @@ static bool trans_CPC(DisasContext *ctx, arg_CPC *a) */ static bool trans_CPI(DisasContext *ctx, arg_CPI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; int Imm = a->imm; TCGv Rr = tcg_const_i32(Imm); @@ -1376,6 +1442,7 @@ static bool trans_CPI(DisasContext *ctx, arg_CPI *a) */ static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rr = cpu_r[a->rr]; ctx->skip_cond = TCG_COND_EQ; @@ -1392,6 +1459,7 @@ static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) */ static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rr = cpu_r[a->rr]; ctx->skip_cond = TCG_COND_NE; @@ -1409,6 +1477,7 @@ static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) */ static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TCGv temp = tcg_const_i32(a->reg); gen_helper_inb(temp, cpu_env, temp); @@ -1427,6 +1496,7 @@ static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) */ static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TCGv temp = tcg_const_i32(a->reg); gen_helper_inb(temp, cpu_env, temp); @@ -1447,6 +1517,7 @@ static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) */ static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGLabel *not_taken = gen_new_label(); TCGv var; @@ -1496,6 +1567,7 @@ static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) */ static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGLabel *not_taken = gen_new_label(); TCGv var; @@ -1547,9 +1619,8 @@ static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) * M assumed to be in 0x000000ff format * L assumed to be in 0x000000ff format */ -static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) +static void gen_decl(set_addr, TCGv addr, TCGv H, TCGv M, TCGv L) { - tcg_gen_andi_tl(L, addr, 0x000000ff); tcg_gen_andi_tl(M, addr, 0x0000ff00); @@ -1558,22 +1629,22 @@ static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) tcg_gen_andi_tl(H, addr, 0x00ff0000); } -static void gen_set_xaddr(TCGv addr) +static void gen_set_xaddr(TCGContext *tcg_ctx, TCGv addr) { - gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]); + gen_set_addr(tcg_ctx, addr, cpu_rampX, cpu_r[27], cpu_r[26]); } -static void gen_set_yaddr(TCGv addr) +static void gen_set_yaddr(TCGContext *tcg_ctx, TCGv addr) { - gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]); + gen_set_addr(tcg_ctx, addr, cpu_rampY, cpu_r[29], cpu_r[28]); } -static void gen_set_zaddr(TCGv addr) +static void gen_set_zaddr(TCGContext *tcg_ctx, TCGv addr) { - gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]); + gen_set_addr(tcg_ctx, addr, cpu_rampZ, cpu_r[31], cpu_r[30]); } -static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) +static TCGv gen_decl(get_addr, TCGv H, TCGv M, TCGv L) { TCGv addr = tcg_temp_new_i32(); @@ -1583,21 +1654,28 @@ static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) return addr; } -static TCGv gen_get_xaddr(void) +static TCGv gen_get_xaddr(TCGContext *tcg_ctx) { - return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]); + return gen_get_addr(tcg_ctx, cpu_rampX, cpu_r[27], cpu_r[26]); } -static TCGv gen_get_yaddr(void) +static TCGv gen_get_yaddr(TCGContext *tcg_ctx) { - return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]); + return gen_get_addr(tcg_ctx, cpu_rampY, cpu_r[29], cpu_r[28]); } -static TCGv gen_get_zaddr(void) +static TCGv gen_get_zaddr(TCGContext *tcg_ctx) { - return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]); + return gen_get_addr(tcg_ctx, cpu_rampZ, cpu_r[31], cpu_r[30]); } +#define gen_set_xaddr(...) gen_call(set_xaddr, __VA_ARGS__) +#define gen_set_yaddr(...) gen_call(set_yaddr, __VA_ARGS__) +#define gen_set_zaddr(...) gen_call(set_zaddr, __VA_ARGS__) +#define gen_get_xaddr() gen_call(get_xaddr) +#define gen_get_yaddr() gen_call(get_yaddr) +#define gen_get_zaddr() gen_call(get_zaddr) + /* * Load one byte indirect from data space to register and stores an clear * the bits in data space specified by the register. The instruction can only @@ -1610,6 +1688,7 @@ static TCGv gen_get_zaddr(void) */ static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { gen_helper_fullwr(cpu_env, data, addr); } else { @@ -1619,6 +1698,7 @@ static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { gen_helper_fullrd(data, cpu_env, addr); } else { @@ -1633,6 +1713,7 @@ static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) */ static bool trans_MOV(DisasContext *ctx, arg_MOV *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv Rr = cpu_r[a->rr]; @@ -1654,6 +1735,7 @@ static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv RdL = cpu_r[a->rd]; TCGv RdH = cpu_r[a->rd + 1]; TCGv RrL = cpu_r[a->rr]; @@ -1670,6 +1752,7 @@ static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) */ static bool trans_LDI(DisasContext *ctx, arg_LDI *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; int imm = a->imm; @@ -1692,6 +1775,7 @@ static bool trans_LDI(DisasContext *ctx, arg_LDI *a) */ static bool trans_LDS(DisasContext *ctx, arg_LDS *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_rampD; @@ -1735,6 +1819,7 @@ static bool trans_LDS(DisasContext *ctx, arg_LDS *a) */ static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_xaddr(); @@ -1747,6 +1832,7 @@ static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_xaddr(); @@ -1762,6 +1848,7 @@ static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_xaddr(); @@ -1801,6 +1888,7 @@ static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) */ static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_yaddr(); @@ -1816,6 +1904,7 @@ static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_yaddr(); @@ -1830,6 +1919,7 @@ static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_yaddr(); @@ -1872,6 +1962,7 @@ static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) */ static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -1887,6 +1978,7 @@ static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -1902,6 +1994,7 @@ static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -1927,6 +2020,7 @@ static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) */ static bool trans_STS(DisasContext *ctx, arg_STS *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_rampD; @@ -1965,6 +2059,7 @@ static bool trans_STS(DisasContext *ctx, arg_STS *a) */ static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rr]; TCGv addr = gen_get_xaddr(); @@ -1977,6 +2072,7 @@ static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rr]; TCGv addr = gen_get_xaddr(); @@ -1991,6 +2087,7 @@ static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rr]; TCGv addr = gen_get_xaddr(); @@ -2028,6 +2125,7 @@ static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) */ static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_yaddr(); @@ -2042,6 +2140,7 @@ static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_yaddr(); @@ -2056,6 +2155,7 @@ static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) static bool trans_STDY(DisasContext *ctx, arg_STDY *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_yaddr(); @@ -2092,6 +2192,7 @@ static bool trans_STDY(DisasContext *ctx, arg_STDY *a) */ static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -2107,6 +2208,7 @@ static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -2122,6 +2224,7 @@ static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -2153,6 +2256,7 @@ static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[0]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_r[31]; @@ -2173,6 +2277,7 @@ static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_r[31]; @@ -2193,6 +2298,7 @@ static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_r[31]; @@ -2232,6 +2338,7 @@ static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[0]; TCGv addr = gen_get_zaddr(); @@ -2248,6 +2355,7 @@ static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -2264,6 +2372,7 @@ static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); @@ -2322,6 +2431,7 @@ static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) */ static bool trans_IN(DisasContext *ctx, arg_IN *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv port = tcg_const_i32(a->imm); @@ -2338,6 +2448,7 @@ static bool trans_IN(DisasContext *ctx, arg_IN *a) */ static bool trans_OUT(DisasContext *ctx, arg_OUT *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv port = tcg_const_i32(a->imm); @@ -2356,6 +2467,7 @@ static bool trans_OUT(DisasContext *ctx, arg_OUT *a) */ static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; gen_data_store(ctx, Rd, cpu_sp); @@ -2379,6 +2491,7 @@ static bool trans_POP(DisasContext *ctx, arg_POP *a) * seems to cause the add to happen twice. * This doesn't happen if either the add or the load is removed. */ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv t1 = tcg_temp_new_i32(); TCGv Rd = cpu_r[a->rd]; @@ -2405,6 +2518,7 @@ static bool trans_XCH(DisasContext *ctx, arg_XCH *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv t0 = tcg_temp_new_i32(); TCGv addr = gen_get_zaddr(); @@ -2436,6 +2550,7 @@ static bool trans_LAS(DisasContext *ctx, arg_LAS *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rr = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); TCGv t0 = tcg_temp_new_i32(); @@ -2471,6 +2586,7 @@ static bool trans_LAC(DisasContext *ctx, arg_LAC *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rr = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); TCGv t0 = tcg_temp_new_i32(); @@ -2506,6 +2622,7 @@ static bool trans_LAT(DisasContext *ctx, arg_LAT *a) return true; } + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); TCGv t0 = tcg_temp_new_i32(); @@ -2526,7 +2643,7 @@ static bool trans_LAT(DisasContext *ctx, arg_LAT *a) /* * Bit and Bit-test Instructions */ -static void gen_rshift_ZNVSf(TCGv R) +static void gen_decl(rshift_ZNVSf, TCGv R) { tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ @@ -2534,6 +2651,8 @@ static void gen_rshift_ZNVSf(TCGv R) tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ } +#define gen_rshift_ZNVSf(...) gen_call(rshift_ZNVSf, __VA_ARGS__) + /* * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is * loaded into the C Flag of the SREG. This operation effectively divides an @@ -2541,6 +2660,7 @@ static void gen_rshift_ZNVSf(TCGv R) */ static bool trans_LSR(DisasContext *ctx, arg_LSR *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; tcg_gen_andi_tl(cpu_Cf, Rd, 1); @@ -2564,6 +2684,7 @@ static bool trans_LSR(DisasContext *ctx, arg_LSR *a) */ static bool trans_ROR(DisasContext *ctx, arg_ROR *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv t0 = tcg_temp_new_i32(); @@ -2592,6 +2713,7 @@ static bool trans_ROR(DisasContext *ctx, arg_ROR *a) */ static bool trans_ASR(DisasContext *ctx, arg_ASR *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv t0 = tcg_temp_new_i32(); @@ -2616,6 +2738,7 @@ static bool trans_ASR(DisasContext *ctx, arg_ASR *a) */ static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv t0 = tcg_temp_new_i32(); TCGv t1 = tcg_temp_new_i32(); @@ -2638,6 +2761,7 @@ static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) */ static bool trans_SBI(DisasContext *ctx, arg_SBI *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TCGv data = tcg_temp_new_i32(); TCGv port = tcg_const_i32(a->reg); @@ -2657,6 +2781,7 @@ static bool trans_SBI(DisasContext *ctx, arg_SBI *a) */ static bool trans_CBI(DisasContext *ctx, arg_CBI *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); TCGv data = tcg_temp_new_i32(); TCGv port = tcg_const_i32(a->reg); @@ -2675,6 +2800,7 @@ static bool trans_CBI(DisasContext *ctx, arg_CBI *a) */ static bool trans_BST(DisasContext *ctx, arg_BST *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); @@ -2688,6 +2814,7 @@ static bool trans_BST(DisasContext *ctx, arg_BST *a) */ static bool trans_BLD(DisasContext *ctx, arg_BLD *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); TCGv Rd = cpu_r[a->rd]; TCGv t1 = tcg_temp_new_i32(); @@ -2705,6 +2832,7 @@ static bool trans_BLD(DisasContext *ctx, arg_BLD *a) */ static bool trans_BSET(DisasContext *ctx, arg_BSET *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); switch (a->bit) { case 0x00: tcg_gen_movi_tl(cpu_Cf, 0x01); @@ -2740,6 +2868,7 @@ static bool trans_BSET(DisasContext *ctx, arg_BSET *a) */ static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); switch (a->bit) { case 0x00: tcg_gen_movi_tl(cpu_Cf, 0x00); @@ -2791,6 +2920,7 @@ static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) } #ifdef BREAKPOINT_ON_BREAK + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); gen_helper_debug(cpu_env); ctx->bstate = DISAS_EXIT; @@ -2818,6 +2948,7 @@ static bool trans_NOP(DisasContext *ctx, arg_NOP *a) */ static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); gen_helper_sleep(cpu_env); ctx->bstate = DISAS_NORETURN; return true; @@ -2830,6 +2961,7 @@ static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) */ static bool trans_WDR(DisasContext *ctx, arg_WDR *a) { + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); gen_helper_wdr(cpu_env); return true; @@ -2846,8 +2978,17 @@ static bool trans_WDR(DisasContext *ctx, arg_WDR *a) */ static void translate(DisasContext *ctx) { - uint32_t opcode = next_word(ctx); + INIT_UC_CONTEXT_FROM_DISAS(ctx); + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + + // Unicorn: end address tells us to stop emulation + const target_ulong insn_pc = ctx->npc; + if (uc_addr_is_exit(uc, insn_pc*2)) { + ctx->bstate = DISAS_UC_EXIT; + return; + } + uint32_t opcode = next_word(ctx); if (!decode_insn(ctx, opcode)) { gen_helper_unsupported(cpu_env); ctx->bstate = DISAS_NORETURN; @@ -2857,6 +2998,7 @@ static void translate(DisasContext *ctx) /* Standardize the cpu_skip condition to NE. */ static bool canonicalize_skip(DisasContext *ctx) { + INIT_TCG_CONTEXT_FROM_DISAS(ctx); switch (ctx->skip_cond) { case TCG_COND_NEVER: /* Normal case: cpu_skip is known to be false. */ @@ -2914,6 +3056,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) target_ulong pc_start = tb->pc / 2; int num_insns = 0; + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(&ctx); if (tb->flags & TB_FLAGS_FULL_ACCESS) { /* * This flag is set by ST/LD instruction we will regenerate it ONLY @@ -3031,6 +3174,10 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) tcg_gen_exit_tb(NULL, 0); } break; + case DISAS_UC_EXIT: + tcg_gen_movi_tl(cpu_pc, ctx.npc); + gen_helper_uc_avr_exit(tcg_ctx, cpu_env); + break; default: g_assert_not_reached(); } @@ -3042,6 +3189,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) tb->icount = num_insns; #ifdef DEBUG_DISAS +#if 0 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) && qemu_log_in_addr_range(tb->pc)) { FILE *fd; @@ -3052,6 +3200,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) qemu_log_unlock(fd); } #endif +#endif } void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, diff --git a/qemu/target/avr/unicorn_helper.h b/qemu/target/avr/unicorn_helper.h new file mode 100644 index 0000000000..9419ea47e4 --- /dev/null +++ b/qemu/target/avr/unicorn_helper.h @@ -0,0 +1,163 @@ +#ifndef QEMU_UNICORN_HELPER_H +#define QEMU_UNICORN_HELPER_H + +#include + +#define UC_GET_TCG_CONTEXT(uc) ((uc)->tcg_ctx) +#define DISAS_GET_UC_CONTEXT(ctx) ((ctx)->env->uc) +#define DISAS_GET_TCG_CONTEXT(ctx) UC_GET_TCG_CONTEXT(DISAS_GET_UC_CONTEXT(ctx)) + +#define INIT_UC_CONTEXT_FROM_DISAS(ctx) \ + struct uc_struct *const uc = DISAS_GET_UC_CONTEXT(ctx) +#define INIT_TCG_CONTEXT_FROM_UC(uc) \ + TCGContext *const tcg_ctx = UC_GET_TCG_CONTEXT(uc) +#define INIT_CPU_ENV_FROM_TCG_CONTEXT(ctx) \ + TCGv_ptr const cpu_env = (ctx)->cpu_env +#define INIT_TCG_CONTEXT_FROM_DISAS(ctx) \ + INIT_TCG_CONTEXT_FROM_UC((ctx)->env->uc) +#define INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx) \ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); \ + INIT_CPU_ENV_FROM_TCG_CONTEXT(tcg_ctx) + +/* "qapi/error.h */ +#include +#define error_report(...) \ + (error)(EXIT_FAILURE, 0, __VA_ARGS__) + +/* "exec/address-spaces.h" */ +#define address_space_memory \ + (cpu->uc->address_space_memory) +#define address_space_ldub(...) \ + glue(address_space_ldub, UNICORN_ARCH_POSTFIX)(uc, __VA_ARGS__) +#define address_space_stb(...) \ + glue(address_space_stb, UNICORN_ARCH_POSTFIX)(uc, __VA_ARGS__) + +/* "tcg/tch.h" */ +#define tcg_wrapper_I(func, ...) \ + (glue(tcg_,func))(tcg_ctx, ## __VA_ARGS__) +#define tcg_wrapper_X(func, ...) \ + tcg_wrapper_I(glue(func,_avr), ## __VA_ARGS__) +#define tcg_wrapper_tl(func, ...) \ + tcg_wrapper_I(glue(func,_i32), ## __VA_ARGS__) + +#undef tcg_const_i32 +#define tcg_const_i32(...) tcg_wrapper_X(const_i32, __VA_ARGS__) +#undef tcg_gen_addi_i32 +#define tcg_gen_addi_i32(...) tcg_wrapper_X(gen_addi_i32, __VA_ARGS__) +//#undef tcg_gen_addi_tl +//#define tcg_gen_addi_tl(...) tcg_wrapper_tl(gen_addi, __VA_ARGS__) +#undef tcg_gen_add_i32 +#define tcg_gen_add_i32(...) tcg_wrapper_I(gen_add_i32, __VA_ARGS__) +#undef tcg_gen_add_tl +#define tcg_gen_add_tl(...) tcg_wrapper_tl(gen_add, __VA_ARGS__) +#undef tcg_gen_andc_i32 +#define tcg_gen_andc_i32(...) tcg_wrapper_X(gen_andc_i32, __VA_ARGS__) +//#undef tcg_gen_andc_tl +//#define tcg_gen_andc_tl(...) tcg_wrapper_tl(gen_andc, __VA_ARGS__) +#undef tcg_gen_andi_i32 +#define tcg_gen_andi_i32(...) tcg_wrapper_X(gen_andi_i32, __VA_ARGS__) +//#undef tcg_gen_andi_tl +//#define tcg_gen_andi_tl(...) tcg_wrapper_tl(gen_andi, __VA_ARGS__) +#undef tcg_gen_and_i32 +#define tcg_gen_and_i32(...) tcg_wrapper_I(gen_and_i32, __VA_ARGS__) +#undef tcg_gen_and_tl +#define tcg_gen_and_tl(...) tcg_wrapper_tl(gen_and, __VA_ARGS__) +#undef tcg_gen_brcondi_i32 +#define tcg_gen_brcondi_i32(...) tcg_wrapper_X(gen_brcondi_i32, __VA_ARGS__) +//#undef tcg_gen_brcondi_tl +//#define tcg_gen_brcondi_tl(...) tcg_wrapper_tl(gen_brcondi, __VA_ARGS__) +#undef tcg_gen_brcond_i32 +#define tcg_gen_brcond_i32(...) tcg_wrapper_X(gen_brcond_i32, __VA_ARGS__) +//#undef tcg_gen_brcond_tl +//#define tcg_gen_brcond_tl(...) tcg_wrapper_tl(gen_brcond, __VA_ARGS__) +#undef tcg_gen_deposit_i32 +#define tcg_gen_deposit_i32(...) tcg_wrapper_X(gen_deposit_i32, __VA_ARGS__) +//#undef tcg_gen_deposit_tl +//#define tcg_gen_deposit_tl(...) tcg_wrapper_tl(gen_deposit, __VA_ARGS__) +#undef tcg_gen_exit_tb +#define tcg_gen_exit_tb(...) tcg_wrapper_X(gen_exit_tb, __VA_ARGS__) +#undef tcg_gen_ext8s_tl +#define tcg_gen_ext8s_tl(...) tcg_wrapper_tl(gen_ext8s, __VA_ARGS__) +#undef tcg_gen_goto_tb +#define tcg_gen_goto_tb(...) tcg_wrapper_X(gen_goto_tb, __VA_ARGS__) +#undef tcg_gen_insn_start +#define tcg_gen_insn_start(...) tcg_wrapper_I(gen_insn_start, __VA_ARGS__) +#undef tcg_gen_movcond_tl +#define tcg_gen_movcond_tl(...) tcg_wrapper_tl(gen_movcond, __VA_ARGS__) +#undef tcg_gen_movi_i32 +#define tcg_gen_movi_i32(...) tcg_wrapper_I(gen_movi_i32, __VA_ARGS__) +//#undef tcg_gen_movi_i32 +//#define tcg_gen_movi_i32(...) tcg_wrapper(gen_movi_i32, __VA_ARGS__) +#undef tcg_gen_movi_tl +#define tcg_gen_movi_tl(...) tcg_wrapper_tl(gen_movi, __VA_ARGS__) +#undef tcg_gen_mov_i32 +#define tcg_gen_mov_i32(...) tcg_wrapper(gen_mov_i32, __VA_ARGS__) +#undef tcg_gen_mov_tl +#define tcg_gen_mov_tl(...) tcg_wrapper_tl(gen_mov, __VA_ARGS__) +#undef tcg_gen_mul_i32 +#define tcg_gen_mul_i32(...) tcg_wrapper(gen_mul_i32, __VA_ARGS__) +#undef tcg_gen_mul_tl +#define tcg_gen_mul_tl(...) tcg_wrapper_tl(gen_mul, __VA_ARGS__) +#undef tcg_gen_not_i32 +#define tcg_gen_not_i32(...) tcg_wrapper(gen_not_i32, __VA_ARGS__) +#undef tcg_gen_not_tl +#define tcg_gen_not_tl(...) tcg_wrapper_tl(gen_not, __VA_ARGS__) +#undef tcg_gen_ori_i32 +#define tcg_gen_ori_i32(...) tcg_wrapper_X(gen_ori_i32, __VA_ARGS__) +//#undef tcg_gen_ori_tl +//#define tcg_gen_ori_tl(...) tcg_wrapper_tl(gen_ori, __VA_ARGS__) +#undef tcg_gen_or_i32 +#define tcg_gen_or_i32(...) tcg_wrapper_I(gen_or_i32, __VA_ARGS__) +#undef tcg_gen_or_tl +#define tcg_gen_or_tl(...) tcg_wrapper_tl(gen_or, __VA_ARGS__) +#undef tcg_gen_qemu_ld8u +#define tcg_gen_qemu_ld8u(...) tcg_wrapper_I(gen_qemu_ld8u, __VA_ARGS__) +#undef tcg_gen_qemu_ld_tl +#define tcg_gen_qemu_ld_tl(...) tcg_wrapper_tl(gen_qemu_ld, __VA_ARGS__) +#undef tcg_gen_qemu_st8 +#define tcg_gen_qemu_st8(...) tcg_wrapper_I(gen_qemu_st8, __VA_ARGS__) +#undef tcg_gen_qemu_st_tl +#define tcg_gen_qemu_st_tl(...) tcg_wrapper_tl(gen_qemu_st, __VA_ARGS__) +#undef tcg_gen_setcondi_tl +#define tcg_gen_setcondi_tl(...) tcg_wrapper_tl(gen_setcondi, __VA_ARGS__) +#undef tcg_gen_setcond_tl +#define tcg_gen_setcond_tl(...) tcg_wrapper_tl(gen_setcond, __VA_ARGS__) +#undef tcg_gen_shli_i32 +#define tcg_gen_shli_i32(...) tcg_wrapper_X(gen_shli_i32, __VA_ARGS__) +//#undef tcg_gen_shli_tl +//#define tcg_gen_shli_tl(...) tcg_wrapper_tl(gen_shli, __VA_ARGS__) +#undef tcg_gen_shri_i32 +#define tcg_gen_shri_i32(...) tcg_wrapper_X(gen_shri_i32, __VA_ARGS__) +//#undef tcg_gen_shri_tl +//#define tcg_gen_shri_tl(...) tcg_wrapper_tl(gen_shri, __VA_ARGS__) +#undef tcg_gen_subi_i32 +#define tcg_gen_subi_i32(...) tcg_wrapper_X(gen_subi_i32, __VA_ARGS__) +//#undef tcg_gen_subi_tl +//#define tcg_gen_subi_tl(...) tcg_wrapper_tl(gen_subi, __VA_ARGS__) +#undef tcg_gen_sub_i32 +#define tcg_gen_sub_i32(...) tcg_wrapper(gen_sub_i32, __VA_ARGS__) +#undef tcg_gen_sub_tl +#define tcg_gen_sub_tl(...) tcg_wrapper_tl(gen_sub, __VA_ARGS__) +#undef tcg_gen_xori_i32 +#define tcg_gen_xori_i32(...) tcg_wrapper_X(gen_xori_i32, __VA_ARGS__) +//#undef tcg_gen_xori_tl +//#define tcg_gen_xori_tl(...) tcg_wrapper_tl(gen_xori, __VA_ARGS__) +#undef tcg_gen_xor_i32 +#define tcg_gen_xor_i32(...) tcg_wrapper(gen_xor_i32, __VA_ARGS__) +#undef tcg_gen_xor_tl +#define tcg_gen_xor_tl(...) tcg_wrapper_tl(gen_xor, __VA_ARGS__) +#undef tcg_global_mem_new_i32 +#define tcg_global_mem_new_i32(...) tcg_wrapper_I(global_mem_new_i32, __VA_ARGS__) +#undef tcg_temp_new_i32 +#define tcg_temp_new_i32() tcg_wrapper_I(temp_new_i32) +#undef tcg_temp_free +#define tcg_temp_free(...) tcg_wrapper_tl(temp_free, __VA_ARGS__) +#undef tcg_temp_free_i32 +#define tcg_temp_free_i32(...) tcg_wrapper_I(temp_free_i32, __VA_ARGS__) +#undef tcg_op_buf_full +#define tcg_op_buf_full() tcg_wrapper_I(op_buf_full) +#undef tcg_gen_lookup_and_goto_ptr +#define tcg_gen_lookup_and_goto_ptr() \ + tcg_wrapper_X(gen_lookup_and_goto_ptr) + +#endif /* QEMU_UNICORN_HELPER_H */ From d4eccc2c0b42ee5908db52af71a14f12758ea1f0 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 3 Apr 2024 10:02:57 +0200 Subject: [PATCH 10/31] qemu/target/avr: add support for block and insn hooks. Signed-off-by: Glenn Baker --- qemu/target/avr/translate.c | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/qemu/target/avr/translate.c b/qemu/target/avr/translate.c index 2907497c41..a21ec5c6a6 100644 --- a/qemu/target/avr/translate.c +++ b/qemu/target/avr/translate.c @@ -2988,11 +2988,35 @@ static void translate(DisasContext *ctx) return; } + // Unicorn: trace this instruction on request + bool insn_hook = false; + TCGOp *insn_prev_op = NULL; + if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, insn_pc*2)) { + + // sync PC in advance + tcg_gen_movi_tl(cpu_pc, insn_pc); + + // save the last operand + insn_prev_op = tcg_last_op(tcg_ctx); + insn_hook = true; + gen_uc_tracecode(tcg_ctx, 0xf1, UC_HOOK_CODE_IDX, uc, insn_pc*2); + + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); + } + uint32_t opcode = next_word(ctx); if (!decode_insn(ctx, opcode)) { gen_helper_unsupported(cpu_env); ctx->bstate = DISAS_NORETURN; } + + if (insn_hook) { + // Unicorn: patch the callback to have the proper instruction size. + TCGOp *const tcg_op = insn_prev_op ? + QTAILQ_NEXT(insn_prev_op, link) : QTAILQ_FIRST(&tcg_ctx->ops); + tcg_op->args[1] = (ctx->npc - insn_pc)*2; + } } /* Standardize the cpu_skip condition to NE. */ @@ -3056,7 +3080,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) target_ulong pc_start = tb->pc / 2; int num_insns = 0; + INIT_UC_CONTEXT_FROM_DISAS(&ctx); INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(&ctx); + if (tb->flags & TB_FLAGS_FULL_ACCESS) { /* * This flag is set by ST/LD instruction we will regenerate it ONLY @@ -3068,6 +3094,17 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) max_insns = 1; } + // Unicorn: trace this block on request + bool block_hook = false; + TCGOp *block_prev_op = NULL; + if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_BLOCK, tb->pc)) { + + // save the last operand + block_prev_op = tcg_last_op(tcg_ctx); + block_hook = true; + gen_uc_tracecode(tcg_ctx, 0xf8, UC_HOOK_BLOCK_IDX, uc, tb->pc); + } + gen_tb_start(tb); ctx.npc = pc_start; @@ -3188,6 +3225,15 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) tb->size = (ctx.npc - pc_start) * 2; tb->icount = num_insns; + hooked_regions_check(uc, tb->pc, tb->size); + + if (block_hook) { + // Unicorn: patch the callback to have the proper block size. + TCGOp *const tcg_op = block_prev_op ? + QTAILQ_NEXT(block_prev_op, link) : QTAILQ_FIRST(&tcg_ctx->ops); + tcg_op->args[1] = (ctx.npc - pc_start)*2; + } + #ifdef DEBUG_DISAS #if 0 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) From 3ab8db24ce8c70515aed392ec1a8ccd2901229a7 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 27 Mar 2024 21:11:55 +0100 Subject: [PATCH 11/31] Add Unicorn/AVR support. Signed-off-by: Glenn Baker --- CMakeLists.txt | 52 +++++++- include/uc_priv.h | 1 + include/unicorn/avr.h | 90 ++++++++++++++ include/unicorn/unicorn.h | 2 + qemu/configure | 12 +- qemu/target/avr/unicorn.c | 241 ++++++++++++++++++++++++++++++++++++++ qemu/target/avr/unicorn.h | 26 ++++ uc.c | 25 ++++ 8 files changed, 447 insertions(+), 2 deletions(-) create mode 100644 include/unicorn/avr.h create mode 100644 qemu/target/avr/unicorn.c create mode 100644 qemu/target/avr/unicorn.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c389bc34f..7affcfe1ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ option(UNICORN_FUZZ "Enable fuzzing" OFF) option(UNICORN_LOGGING "Enable logging" OFF) option(UNICORN_BUILD_TESTS "Build unicorn tests" ${PROJECT_IS_TOP_LEVEL}) option(UNICORN_INSTALL "Enable unicorn installation" ${PROJECT_IS_TOP_LEVEL}) -set(UNICORN_ARCH "x86;arm;aarch64;riscv;mips;sparc;m68k;ppc;s390x;tricore" CACHE STRING "Enabled unicorn architectures") +set(UNICORN_ARCH "x86;arm;aarch64;riscv;mips;sparc;m68k;ppc;s390x;tricore;avr" CACHE STRING "Enabled unicorn architectures") option(UNICORN_TRACER "Trace unicorn execution" OFF) foreach(ARCH_LOOP ${UNICORN_ARCH}) @@ -272,6 +272,11 @@ else() set(UNICORN_TARGET_ARCH "tricore") break() endif() + string(FIND ${UC_COMPILER_MACRO} "__AVR__" UC_RET) + if (${UC_RET} GREATER_EQUAL "0") + set(UNICORN_TARGET_ARCH "avr") + break() + endif() message(FATAL_ERROR "Unknown host compiler: ${CMAKE_C_COMPILER}.") endwhile(TRUE) endif() @@ -307,6 +312,9 @@ else() if (UNICORN_HAS_TRICORE) set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_TRICORE ") endif() + if (UNICORN_HAS_AVR) + set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_AVR ") + endif() set(EXTRA_CFLAGS "${EXTRA_CFLAGS}-fPIC") if(ANDROID_ABI) @@ -358,6 +366,9 @@ else() if (UNICORN_HAS_TRICORE) set (TARGET_LIST "${TARGET_LIST}tricore-softmmu, ") endif() + if (UNICORN_HAS_AVR) + set (TARGET_LIST "${TARGET_LIST}avr-softmmu, ") + endif() set(TARGET_LIST "${TARGET_LIST} ") # GEN config-host.mak & target directories @@ -455,6 +466,12 @@ else() OUTPUT_FILE ${CMAKE_BINARY_DIR}/tricore-softmmu/config-target.h ) endif() + if (UNICORN_HAS_AVR) + execute_process(COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/qemu/scripts/create_config + INPUT_FILE ${CMAKE_BINARY_DIR}/avr-softmmu/config-target.mak + OUTPUT_FILE ${CMAKE_BINARY_DIR}/avr-softmmu/config-target.h + ) + endif() add_compile_options( ${UNICORN_CFLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/qemu/tcg/${UNICORN_TARGET_ARCH} @@ -1153,6 +1170,34 @@ endif() endif() +if (UNICORN_HAS_AVR) +add_library(avr-softmmu STATIC + ${UNICORN_ARCH_COMMON} + + qemu/target/avr/cpu.c + qemu/target/avr/helper.c + qemu/target/avr/translate.c + qemu/target/avr/unicorn.c +) + +if(MSVC) + target_compile_options(avr-softmmu PRIVATE + -DNEED_CPU_H + /FIavr.h + /I${CMAKE_CURRENT_SOURCE_DIR}/msvc/avr-softmmu + /I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/avr + ) +else() + target_compile_options(avr-softmmu PRIVATE + -DNEED_CPU_H + -include avr.h + -I${CMAKE_BINARY_DIR}/avr-softmmu + -I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/avr + ) +endif() +endif() + + set(UNICORN_SRCS uc.c @@ -1327,6 +1372,11 @@ if (UNICORN_HAS_TRICORE) target_link_libraries(tricore-softmmu unicorn-common) set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_tricore) endif() +if (UNICORN_HAS_AVR) + set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_AVR) + set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} avr-softmmu) + target_link_libraries(avr-softmmu unicorn-common) +endif() # Extra tests set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_mem) diff --git a/include/uc_priv.h b/include/uc_priv.h index f9195b4d63..b862b7aec9 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -35,6 +35,7 @@ (UC_MODE_RISCV32 | UC_MODE_RISCV64 | UC_MODE_LITTLE_ENDIAN) #define UC_MODE_S390X_MASK (UC_MODE_BIG_ENDIAN) #define UC_MODE_TRICORE_MASK (UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_AVR_MASK (UC_MODE_LITTLE_ENDIAN) #define ARR_SIZE(a) (sizeof(a) / sizeof(a[0])) diff --git a/include/unicorn/avr.h b/include/unicorn/avr.h new file mode 100644 index 0000000000..67b74d2942 --- /dev/null +++ b/include/unicorn/avr.h @@ -0,0 +1,90 @@ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +/* + Created for Unicorn Engine by Glenn Baker , 2024 +*/ + +#ifndef UNICORN_AVR_H +#define UNICORN_AVR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning(disable : 4201) +#endif + +//> AVR CPU +typedef enum uc_cpu_avr { + UC_CPU_AVR_AVR5 = 5, + UC_CPU_AVR_AVR51 = 51, + UC_CPU_AVR_AVR6 = 6, +} uc_cpu_avr; + +//> AVR registers +typedef enum uc_avr_reg { + UC_AVR_REG_INVALID = 0, + + // General purpose registers (GPR) + UC_AVR_REG_R0 = 1, + UC_AVR_REG_R1, + UC_AVR_REG_R2, + UC_AVR_REG_R3, + UC_AVR_REG_R4, + UC_AVR_REG_R5, + UC_AVR_REG_R6, + UC_AVR_REG_R7, + UC_AVR_REG_R8, + UC_AVR_REG_R9, + UC_AVR_REG_R10, + UC_AVR_REG_R11, + UC_AVR_REG_R12, + UC_AVR_REG_R13, + UC_AVR_REG_R14, + UC_AVR_REG_R15, + UC_AVR_REG_R16, + UC_AVR_REG_R17, + UC_AVR_REG_R18, + UC_AVR_REG_R19, + UC_AVR_REG_R20, + UC_AVR_REG_R21, + UC_AVR_REG_R22, + UC_AVR_REG_R23, + UC_AVR_REG_R24, + UC_AVR_REG_R25, + UC_AVR_REG_R26, + UC_AVR_REG_R27, + UC_AVR_REG_R28, + UC_AVR_REG_R29, + UC_AVR_REG_R30, + UC_AVR_REG_R31, + + UC_AVR_REG_PC, + UC_AVR_REG_SP, + + UC_AVR_REG_RAMPD = UC_AVR_REG_PC + 16 + 8, + UC_AVR_REG_RAMPX, + UC_AVR_REG_RAMPY, + UC_AVR_REG_RAMPZ, + UC_AVR_REG_EIND, + UC_AVR_REG_SPL, + UC_AVR_REG_SPH, + UC_AVR_REG_SREG, + + //> Alias registers + UC_AVR_REG_Xhi = UC_AVR_REG_R27, + UC_AVR_REG_Xlo = UC_AVR_REG_R26, + UC_AVR_REG_Yhi = UC_AVR_REG_R29, + UC_AVR_REG_Ylo = UC_AVR_REG_R28, + UC_AVR_REG_Zhi = UC_AVR_REG_R31, + UC_AVR_REG_Zlo = UC_AVR_REG_R30, +} uc_avr_reg; + +#ifdef __cplusplus +} +#endif + +#endif /* UNICORN_AVR_H */ diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index c057dcc964..df07a68007 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -36,6 +36,7 @@ typedef size_t uc_hook; #include "riscv.h" #include "s390x.h" #include "tricore.h" +#include "avr.h" #ifdef __GNUC__ #define DEFAULT_VISIBILITY __attribute__((visibility("default"))) @@ -106,6 +107,7 @@ typedef enum uc_arch { UC_ARCH_RISCV, // RISCV architecture UC_ARCH_S390X, // S390X architecture UC_ARCH_TRICORE, // TriCore architecture + UC_ARCH_AVR, // AVR architecture UC_ARCH_MAX, } uc_arch; diff --git a/qemu/configure b/qemu/configure index 11f8b0f5ae..ddd64d6cf3 100755 --- a/qemu/configure +++ b/qemu/configure @@ -491,6 +491,8 @@ elif check_define __aarch64__ ; then cpu="aarch64" elif check_define __tricore__ ; then cpu="tricore" +elif check_define __AVR__ ; then + cpu="avr" else cpu=$(uname -m) fi @@ -534,6 +536,10 @@ case "$cpu" in cpu="tricore" supported_cpu="yes" ;; + avr) + cpu="avr" + supported_cpu="yes" + ;; *) # This will result in either an error or falling back to TCI later ARCH=unknown @@ -859,7 +865,7 @@ default_target_list="aarch64-softmmu \ arm-softmmu m68k-softmmu mips64el-softmmu mips64-softmmu mipsel-softmmu \ mips-softmmu ppc64-softmmu ppc-softmmu sparc64-softmmu sparc-softmmu \ x86_64-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu \ - tricore-softmmu" + tricore-softmmu avr-softmmu" if test x"$show_help" = x"yes" ; then cat << EOF @@ -2789,6 +2795,10 @@ case "$target_name" in TARGET_ARCH=tricore TARGET_BASE_ARCH=tricore ;; + avr) + TARGET_ARCH=avr + TARGET_BASE_ARCH=avr + ;; unicore32) ;; xtensa|xtensaeb) diff --git a/qemu/target/avr/unicorn.c b/qemu/target/avr/unicorn.c new file mode 100644 index 0000000000..ddeed9518c --- /dev/null +++ b/qemu/target/avr/unicorn.c @@ -0,0 +1,241 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh , 2015 */ + +/* + Created for Unicorn Engine by Glenn Baker , 2024 +*/ + +#include "qemu/typedefs.h" +#include "unicorn/unicorn.h" +#include "sysemu/cpus.h" +#include "sysemu/tcg.h" +#include "cpu.h" +#include "uc_priv.h" +#include "unicorn_common.h" +#include "unicorn.h" + +AVRCPU *cpu_avr_init(struct uc_struct *uc); + +static inline uint32_t get_pc(CPUAVRState *env) +{ + return env->pc_w*2; +} + +static uint64_t avr_get_pc(struct uc_struct *uc) +{ + return get_pc((CPUAVRState *)uc->cpu->env_ptr); +} + +static inline void set_pc(CPUAVRState *env, uint32_t value) +{ + env->pc_w = value/2; +} + +static void avr_set_pc(struct uc_struct *uc, uint64_t address) +{ + set_pc((CPUAVRState *)uc->cpu->env_ptr, address); +} + +void avr_reg_reset(struct uc_struct *uc) +{ +} + +#define GET_BYTE(x, n) (((x) >> (n)*8) & 0xff) +#define SET_BYTE(x, n, b) (x = ((x) & ~(0xff << ((n)*8))) | ((b) << ((n)*8))) +#define GET_RAMP(reg) GET_BYTE(env->glue(ramp,reg), 2) +#define SET_RAMP(reg, val) SET_BYTE(env->glue(ramp,reg), 2, val) + +static void reg_read(CPUAVRState *env, unsigned int regid, void *value) +{ + switch (regid) { + case UC_AVR_REG_PC: + *(uint32_t *)value = get_pc(env); + break; + case UC_AVR_REG_SP: + *(uint32_t *)value = env->sp; + break; + + case UC_AVR_REG_RAMPD: + *(uint8_t *)value = GET_RAMP(D); + break; + case UC_AVR_REG_RAMPX: + *(uint8_t *)value = GET_RAMP(X); + break; + case UC_AVR_REG_RAMPY: + *(uint8_t *)value = GET_RAMP(Y); + break; + case UC_AVR_REG_RAMPZ: + *(uint8_t *)value = GET_RAMP(Z); + break; + case UC_AVR_REG_EIND: + *(uint8_t *)value = GET_BYTE(env->eind, 2); + break; + case UC_AVR_REG_SPL: + *(uint8_t *)value = GET_BYTE(env->sp, 0); + break; + case UC_AVR_REG_SPH: + *(uint8_t *)value = GET_BYTE(env->sp, 1); + break; + case UC_AVR_REG_SREG: + *(uint8_t *)value = cpu_get_sreg(env); + break; + + default: + if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { + *(int8_t *)value = (int8_t)env->r[regid - UC_AVR_REG_R0]; + } + break; + } +} + +int avr_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, + int count) +{ + CPUAVRState *env = &(AVR_CPU(uc->cpu)->env); + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + reg_read(env, regid, value); + } + + return 0; +} + +int avr_context_reg_read(struct uc_context *uc, unsigned int *regs, + void **vals, int count) +{ + CPUAVRState *env = (CPUAVRState *)uc->data; + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + reg_read(env, regid, value); + } + + return 0; +} + +static void reg_write(CPUAVRState *env, unsigned int regid, + const void *value) +{ + switch (regid) { + case UC_AVR_REG_PC: + set_pc(env, *(uint32_t *)value); + break; + case UC_AVR_REG_SP: + env->sp = *(uint32_t *)value; + break; + + case UC_AVR_REG_RAMPD: + SET_RAMP(D, *(uint8_t *)value); + break; + case UC_AVR_REG_RAMPX: + SET_RAMP(X, *(uint8_t *)value); + break; + case UC_AVR_REG_RAMPY: + SET_RAMP(Y, *(uint8_t *)value); + break; + case UC_AVR_REG_RAMPZ: + SET_RAMP(Z, *(uint8_t *)value); + break; + case UC_AVR_REG_EIND: + SET_BYTE(env->eind, 2, *(uint8_t *)value); + break; + case UC_AVR_REG_SPL: + SET_BYTE(env->sp, 0, *(uint8_t *)value); + break; + case UC_AVR_REG_SPH: + SET_BYTE(env->sp, 1, *(uint8_t *)value); + break; + case UC_AVR_REG_SREG: + cpu_set_sreg(env, *(uint8_t *)value); + break; + + default: + if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { + env->r[regid - UC_AVR_REG_R0] = *(uint8_t *)value; + } + } +} + +int avr_reg_write(struct uc_struct *uc, unsigned int *regs, + void *const *vals, int count) +{ + CPUAVRState *env = &(AVR_CPU(uc->cpu)->env); + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + reg_write(env, regid, value); + if (regid == UC_AVR_REG_PC) { + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + } + } + + return 0; +} + +int avr_context_reg_write(struct uc_context *uc, unsigned int *regs, + void *const *vals, int count) +{ + CPUAVRState *env = (CPUAVRState *)uc->data; + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + reg_write(env, regid, value); + } + + return 0; +} + +static int avr_cpus_init(struct uc_struct *uc, const char *cpu_model) +{ + AVRCPU *cpu; + + cpu = cpu_avr_init(uc); + if (cpu == NULL) { + return -1; + } + + return 0; +} + +static void avr_release(void *ctx) +{ + int i; + TCGContext *tcg_ctx = (TCGContext *)ctx; + AVRCPU *cpu = (AVRCPU *)tcg_ctx->uc->cpu; + CPUTLBDesc *d = cpu->neg.tlb.d; + CPUTLBDescFast *f = cpu->neg.tlb.f; + CPUTLBDesc *desc; + CPUTLBDescFast *fast; + + release_common(ctx); + for (i = 0; i < NB_MMU_MODES; i++) { + desc = &(d[i]); + fast = &(f[i]); + g_free(desc->iotlb); + g_free(fast->table); + } +} + +void avr_uc_init(struct uc_struct *uc) +{ + uc->reg_read = avr_reg_read; + uc->reg_write = avr_reg_write; + uc->reg_reset = avr_reg_reset; + uc->set_pc = avr_set_pc; + uc->get_pc = avr_get_pc; + uc->cpus_init = avr_cpus_init; + uc->release = avr_release; + uc->cpu_context_size = offsetof(CPUAVRState, features); + uc_common_init(uc); +} diff --git a/qemu/target/avr/unicorn.h b/qemu/target/avr/unicorn.h new file mode 100644 index 0000000000..817e592111 --- /dev/null +++ b/qemu/target/avr/unicorn.h @@ -0,0 +1,26 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh , 2015 */ + +/* + Modified for Unicorn Engine by Glenn Baker , 2024 +*/ + +#ifndef UC_QEMU_TARGET_AVR_H +#define UC_QEMU_TARGET_AVR_H + +// functions to read & write registers +int avr_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, + int count); +int avr_reg_write(struct uc_struct *uc, unsigned int *regs, + void *const *vals, int count); + +int avr_context_reg_read(struct uc_context *uc, unsigned int *regs, + void **vals, int count); +int avr_context_reg_write(struct uc_context *uc, unsigned int *regs, + void *const *vals, int count); + +void avr_reg_reset(struct uc_struct *uc); + +void avr_uc_init(struct uc_struct *uc); + +#endif /* UC_QEMU_TARGET_AVR_H */ diff --git a/uc.c b/uc.c index 0ff4196f1f..477c5d1170 100644 --- a/uc.c +++ b/uc.c @@ -26,6 +26,7 @@ #include "qemu/target/riscv/unicorn.h" #include "qemu/target/s390x/unicorn.h" #include "qemu/target/tricore/unicorn.h" +#include "qemu/target/avr/unicorn.h" #include "qemu/include/tcg/tcg-apple-jit.h" #include "qemu/include/qemu/queue.h" @@ -237,6 +238,10 @@ bool uc_arch_supported(uc_arch arch) #ifdef UNICORN_HAS_TRICORE case UC_ARCH_TRICORE: return true; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + return true; #endif /* Invalid or disabled arch */ default: @@ -474,6 +479,15 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) } uc->init_arch = uc_init_tricore; break; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + if ((mode & ~UC_MODE_AVR_MASK)) { + free(uc); + return UC_ERR_MODE; + } + uc->init_arch = avr_uc_init; + break; #endif } @@ -1057,6 +1071,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, case UC_ARCH_TRICORE: uc_reg_write(uc, UC_TRICORE_REG_PC, &begin_pc32); break; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + uc_reg_write(uc, UC_AVR_REG_PC, &begin_pc32); + break; #endif } @@ -2289,6 +2308,12 @@ static context_reg_rw_t find_context_reg_rw(uc_arch arch, uc_mode mode) rw.read = reg_read_tricore; rw.write = reg_write_tricore; break; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + rw->context_reg_read = avr_context_reg_read; + rw->context_reg_write = avr_context_reg_write; + break; #endif } From 0b8932ff126f626ffc3814933dc91ff6652c6f1f Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Thu, 4 Apr 2024 10:50:43 +0200 Subject: [PATCH 12/31] Use alternate Flash program memory (code) base for AVR targets. This is needed because the AVR CPU has separate code and data address spaces that both start from zero. Use 0x08000000 base for Flash memory and 0x00000000 base for CPU registers, IO registers and SRAM as the fast case. Signed-off-by: Glenn Baker --- include/unicorn/avr.h | 6 ++++++ qemu/target/avr/cpu.h | 14 ++++++++++++++ qemu/target/avr/helper.c | 10 ++++++---- qemu/target/avr/translate.c | 32 +++++++++++++++++++++++--------- qemu/target/avr/unicorn.c | 27 +++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/include/unicorn/avr.h b/include/unicorn/avr.h index 67b74d2942..0af7b11c68 100644 --- a/include/unicorn/avr.h +++ b/include/unicorn/avr.h @@ -24,6 +24,12 @@ typedef enum uc_cpu_avr { UC_CPU_AVR_AVR6 = 6, } uc_cpu_avr; +//> AVR memory +typedef enum uc_avr_mem { + // Flash program memory (code) + UC_AVR_MEM_FLASH = 0x08000000, +} uc_avr_mem; + //> AVR registers typedef enum uc_avr_reg { UC_AVR_REG_INVALID = 0, diff --git a/qemu/target/avr/cpu.h b/qemu/target/avr/cpu.h index 380374b37b..42344756aa 100644 --- a/qemu/target/avr/cpu.h +++ b/qemu/target/avr/cpu.h @@ -61,10 +61,16 @@ * * It's also useful to know where some things are, like the IO registers. */ +#if 1 +// Unicorn: +#define OFFSET_CODE 0x08000000 /* UC_AVR_MEM_FLASH */ +#define OFFSET_DATA 0x00000000 +#else /* Flash program memory */ #define OFFSET_CODE 0x00000000 /* CPU registers, IO registers, and SRAM */ #define OFFSET_DATA 0x00800000 +#endif /* CPU registers specifically, these are mapped at the start of data */ #define OFFSET_CPU_REGISTERS OFFSET_DATA /* @@ -107,6 +113,8 @@ typedef enum AVRFeature { AVR_FEATURE_RAMPX, AVR_FEATURE_RAMPY, AVR_FEATURE_RAMPZ, + + AVR_FEATURE_FLASH, /* Unicorn: was Flash program memory mapped? */ } AVRFeature; typedef struct CPUAVRState CPUAVRState; @@ -188,6 +196,12 @@ static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; } +static inline uint32_t avr_code_base(CPUAVRState *env) +{ + return OFFSET_CODE && avr_feature(env, AVR_FEATURE_FLASH) ? + OFFSET_CODE : 0; +} + void avr_cpu_tcg_init(struct uc_struct *uc); void avr_cpu_list(void); diff --git a/qemu/target/avr/helper.c b/qemu/target/avr/helper.c index 459236c688..e2dbc672fe 100644 --- a/qemu/target/avr/helper.c +++ b/qemu/target/avr/helper.c @@ -112,12 +112,14 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, if (mmu_idx == MMU_CODE_IDX) { /* access to code in flash */ - paddr = OFFSET_CODE + address; + paddr = avr_code_base(&AVR_CPU(cs)->env) | address; prot = PAGE_READ | PAGE_EXEC; +#if 0 if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) { error_report("execution left flash memory"); abort(); } +#endif } else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { /* * access to CPU registers, exit and rebuilt this TB to use full access @@ -129,7 +131,7 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, cpu_loop_exit_restore(cs, retaddr); } else { /* access to memory. nothing special */ - paddr = OFFSET_DATA + address; + paddr = OFFSET_DATA | address; prot = PAGE_READ | PAGE_WRITE; } @@ -326,7 +328,7 @@ target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); } else { /* memory */ - data = address_space_ldub(&address_space_memory, OFFSET_DATA + addr, + data = address_space_ldub(&address_space_memory, OFFSET_DATA | addr, MEMTXATTRS_UNSPECIFIED, NULL); } return data; @@ -356,7 +358,7 @@ void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); } else { /* memory */ - address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, + address_space_stb(&address_space_memory, OFFSET_DATA | addr, data, MEMTXATTRS_UNSPECIFIED, NULL); } } diff --git a/qemu/target/avr/translate.c b/qemu/target/avr/translate.c index a21ec5c6a6..9ebc7dcf45 100644 --- a/qemu/target/avr/translate.c +++ b/qemu/target/avr/translate.c @@ -200,7 +200,8 @@ static int to_regs_00_30_by_two(DisasContext *ctx, int indx) static uint16_t next_word(DisasContext *ctx) { - return cpu_lduw_code(ctx->env, ctx->npc++ * 2); + // Unicorn: + return cpu_lduw_code(ctx->env, avr_code_base(ctx->env) | (ctx->npc++ * 2)); } static int append_16(DisasContext *ctx, int x) @@ -1706,6 +1707,19 @@ static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) } } +static void gen_code_load(DisasContext *ctx, TCGv Rd, TCGv addr) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + // Unicorn: + const uint32_t code_base = avr_code_base(ctx->env); + if (code_base) { + TCGv Rc = tcg_const_i32(code_base); + tcg_gen_or_tl(addr, addr, Rc); + tcg_temp_free_i32(Rc); + } + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ +} + /* * This instruction makes a copy of one register into another. The source * register Rr is left unchanged, while the destination register Rd is loaded @@ -2264,7 +2278,7 @@ static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ tcg_gen_or_tl(addr, addr, L); - tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + gen_code_load(ctx, Rd, addr); tcg_temp_free_i32(addr); @@ -2285,7 +2299,7 @@ static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ tcg_gen_or_tl(addr, addr, L); - tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + gen_code_load(ctx, Rd, addr); tcg_temp_free_i32(addr); @@ -2306,7 +2320,7 @@ static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ tcg_gen_or_tl(addr, addr, L); - tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + gen_code_load(ctx, Rd, addr); tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ tcg_gen_andi_tl(L, addr, 0xff); tcg_gen_shri_tl(addr, addr, 8); @@ -2342,7 +2356,7 @@ static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) TCGv Rd = cpu_r[0]; TCGv addr = gen_get_zaddr(); - tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + gen_code_load(ctx, Rd, addr); tcg_temp_free_i32(addr); @@ -2359,7 +2373,7 @@ static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); - tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + gen_code_load(ctx, Rd, addr); tcg_temp_free_i32(addr); @@ -2376,7 +2390,7 @@ static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) TCGv Rd = cpu_r[a->rd]; TCGv addr = gen_get_zaddr(); - tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + gen_code_load(ctx, Rd, addr); tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ gen_set_zaddr(addr); @@ -3127,8 +3141,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) * b *0x100 - sets breakpoint at address 0x00800100 (data) */ if (unlikely(!ctx.singlestep && - (cpu_breakpoint_test(cs, OFFSET_CODE + ctx.npc * 2, BP_ANY) || - cpu_breakpoint_test(cs, OFFSET_DATA + ctx.npc * 2, BP_ANY)))) { + (cpu_breakpoint_test(cs, avr_code_base(env) | ctx.npc * 2, BP_ANY) || + cpu_breakpoint_test(cs, OFFSET_DATA | ctx.npc * 2, BP_ANY)))) { canonicalize_skip(&ctx); tcg_gen_movi_tl(cpu_pc, ctx.npc); gen_helper_debug(cpu_env); diff --git a/qemu/target/avr/unicorn.c b/qemu/target/avr/unicorn.c index ddeed9518c..4fcb53dc12 100644 --- a/qemu/target/avr/unicorn.c +++ b/qemu/target/avr/unicorn.c @@ -227,6 +227,31 @@ static void avr_release(void *ctx) } } +static inline bool is_flash_memory(hwaddr addr, size_t size, uint32_t perms) +{ + if ((addr ^ UC_AVR_MEM_FLASH) >> 24) + return false; + if ((perms & UC_PROT_ALL) != (UC_PROT_READ|UC_PROT_EXEC)) + return false; + return true; +} + +static MemoryRegion *avr_memory_map(struct uc_struct *uc, hwaddr begin, size_t size, uint32_t perms) +{ + MemoryRegion *const mr = memory_map(uc, begin, size, perms); + if (mr && is_flash_memory(begin, size, perms)) + set_avr_feature(&AVR_CPU(uc->cpu)->env, AVR_FEATURE_FLASH); + return mr; +} + +static MemoryRegion *avr_memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, uint32_t perms, void *ptr) +{ + MemoryRegion *const mr = memory_map_ptr(uc, begin, size, perms, ptr); + if (mr && is_flash_memory(begin, size, perms)) + set_avr_feature(&AVR_CPU(uc->cpu)->env, AVR_FEATURE_FLASH); + return mr; +} + void avr_uc_init(struct uc_struct *uc) { uc->reg_read = avr_reg_read; @@ -238,4 +263,6 @@ void avr_uc_init(struct uc_struct *uc) uc->release = avr_release; uc->cpu_context_size = offsetof(CPUAVRState, features); uc_common_init(uc); + uc->memory_map = avr_memory_map; + uc->memory_map_ptr = avr_memory_map_ptr; } From 6d263b430415dad16fee705fff0d7742b53f889d Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 24 Apr 2024 09:59:54 +0200 Subject: [PATCH 13/31] AVR: rework ARCH/CPU models. Separate AVR architectures ("avr5", "avr51", "avr6", etc.) from actual MCU models. Only list the most representative MCU models. Signed-off-by: Glenn Baker --- include/unicorn/avr.h | 31 ++++++++++++++++++++++++++++--- qemu/target/avr/cpu.c | 18 ++++++++++++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/include/unicorn/avr.h b/include/unicorn/avr.h index 0af7b11c68..9a48fed6e8 100644 --- a/include/unicorn/avr.h +++ b/include/unicorn/avr.h @@ -17,11 +17,36 @@ extern "C" { #pragma warning(disable : 4201) #endif +//> AVR architectures +typedef enum uc_avr_arch { + UC_AVR_ARCH_AVR1 = 10, + UC_AVR_ARCH_AVR2 = 20, + UC_AVR_ARCH_AVR25 = 25, + UC_AVR_ARCH_AVR3 = 30, + UC_AVR_ARCH_AVR4 = 40, + UC_AVR_ARCH_AVR5 = 50, + UC_AVR_ARCH_AVR51 = 51, + UC_AVR_ARCH_AVR6 = 60, +} uc_avr_arch; + +#define UC_CPU_AVR_ARCH 1000 + //> AVR CPU typedef enum uc_cpu_avr { - UC_CPU_AVR_AVR5 = 5, - UC_CPU_AVR_AVR51 = 51, - UC_CPU_AVR_AVR6 = 6, + // Enhanced Core with 16K up to 64K of program memory ("AVR5") + UC_CPU_AVR_ATMEGA16 = UC_AVR_ARCH_AVR5*UC_CPU_AVR_ARCH + 16, + UC_CPU_AVR_ATMEGA32 = UC_AVR_ARCH_AVR5*UC_CPU_AVR_ARCH + 32, + UC_CPU_AVR_ATMEGA64 = UC_AVR_ARCH_AVR5*UC_CPU_AVR_ARCH + 64, + + // Enhanced Core with 128K of program memory ("AVR5.1") + UC_CPU_AVR_ATMEGA128 = UC_AVR_ARCH_AVR51*UC_CPU_AVR_ARCH + 128, + UC_CPU_AVR_ATMEGA128RFR2, + UC_CPU_AVR_ATMEGA1280, + + // Enhanced Core with 128K+ of program memory, i.e. 3-byte PC ("AVR6") + UC_CPU_AVR_ATMEGA256 = UC_AVR_ARCH_AVR6*UC_CPU_AVR_ARCH + 256, + UC_CPU_AVR_ATMEGA256RFR2, + UC_CPU_AVR_ATMEGA2560, } uc_cpu_avr; //> AVR memory diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c index ecf713f9c8..31a7ded0dc 100644 --- a/qemu/target/avr/cpu.c +++ b/qemu/target/avr/cpu.c @@ -343,9 +343,19 @@ typedef struct AVRCPUInfo { } AVRCPUInfo; static const AVRCPUInfo avr_cpu_info[] ={ - {UC_CPU_AVR_AVR5, "avr5", avr_avr5_initfn}, - {UC_CPU_AVR_AVR51, "avr51", avr_avr51_initfn}, - {UC_CPU_AVR_AVR6, "avr6", avr_avr6_initfn}, + {UC_CPU_AVR_ATMEGA16, "arch:avr5", avr_avr5_initfn}, + {UC_CPU_AVR_ATMEGA16, "atmega16", avr_avr5_initfn}, + {UC_CPU_AVR_ATMEGA32, "atmega32", avr_avr5_initfn}, + {UC_CPU_AVR_ATMEGA64, "atmega64", avr_avr5_initfn}, + + {UC_CPU_AVR_ATMEGA128, "arch:avr51", avr_avr51_initfn}, + {UC_CPU_AVR_ATMEGA128, "atmega128", avr_avr51_initfn}, + {UC_CPU_AVR_ATMEGA128RFR2, "atmega128rfr2", avr_avr51_initfn}, + {UC_CPU_AVR_ATMEGA1280, "atmega1280", avr_avr51_initfn}, + + {UC_CPU_AVR_ATMEGA256, "arch:avr6", avr_avr6_initfn}, + {UC_CPU_AVR_ATMEGA256RFR2, "atmega256rfr2", avr_avr6_initfn}, + {UC_CPU_AVR_ATMEGA2560, "atmega2560", avr_avr6_initfn}, }; static const AVRCPUInfo *avr_cpu_info_get(int cpu_model) @@ -412,7 +422,7 @@ AVRCPU *cpu_avr_init(struct uc_struct *uc) } if (uc->cpu_model == INT_MAX) - uc->cpu_model = UC_CPU_AVR_AVR6; + uc->cpu_model = UC_CPU_AVR_ATMEGA128; const AVRCPUInfo *const cip = avr_cpu_info_get(uc->cpu_model); if (!cip) { free(cpu); From d150f71064e732075d94f1a2a409fc7dcb660418 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 24 Apr 2024 11:39:31 +0200 Subject: [PATCH 14/31] AVR: add 16-bit & 32-bit register accessors. Signed-off-by: Glenn Baker --- include/unicorn/avr.h | 68 +++++++++++++++++++++++++++++++++++++++ qemu/target/avr/unicorn.c | 40 +++++++++++++++++++++-- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/include/unicorn/avr.h b/include/unicorn/avr.h index 9a48fed6e8..0487d3fd09 100644 --- a/include/unicorn/avr.h +++ b/include/unicorn/avr.h @@ -105,6 +105,70 @@ typedef enum uc_avr_reg { UC_AVR_REG_SPH, UC_AVR_REG_SREG, + //> 16-bit coalesced registers + UC_AVR_REG_R0W = UC_AVR_REG_PC + 32, + UC_AVR_REG_R1W, + UC_AVR_REG_R2W, + UC_AVR_REG_R3W, + UC_AVR_REG_R4W, + UC_AVR_REG_R5W, + UC_AVR_REG_R6W, + UC_AVR_REG_R7W, + UC_AVR_REG_R8W, + UC_AVR_REG_R9W, + UC_AVR_REG_R10W, + UC_AVR_REG_R11W, + UC_AVR_REG_R12W, + UC_AVR_REG_R13W, + UC_AVR_REG_R14W, + UC_AVR_REG_R15W, + UC_AVR_REG_R16W, + UC_AVR_REG_R17W, + UC_AVR_REG_R18W, + UC_AVR_REG_R19W, + UC_AVR_REG_R20W, + UC_AVR_REG_R21W, + UC_AVR_REG_R22W, + UC_AVR_REG_R23W, + UC_AVR_REG_R24W, + UC_AVR_REG_R25W, + UC_AVR_REG_R26W, + UC_AVR_REG_R27W, + UC_AVR_REG_R28W, + UC_AVR_REG_R29W, + UC_AVR_REG_R30W, + + //> 32-bit coalesced registers + UC_AVR_REG_R0D = UC_AVR_REG_PC + 64, + UC_AVR_REG_R1D, + UC_AVR_REG_R2D, + UC_AVR_REG_R3D, + UC_AVR_REG_R4D, + UC_AVR_REG_R5D, + UC_AVR_REG_R6D, + UC_AVR_REG_R7D, + UC_AVR_REG_R8D, + UC_AVR_REG_R9D, + UC_AVR_REG_R10D, + UC_AVR_REG_R11D, + UC_AVR_REG_R12D, + UC_AVR_REG_R13D, + UC_AVR_REG_R14D, + UC_AVR_REG_R15D, + UC_AVR_REG_R16D, + UC_AVR_REG_R17D, + UC_AVR_REG_R18D, + UC_AVR_REG_R19D, + UC_AVR_REG_R20D, + UC_AVR_REG_R21D, + UC_AVR_REG_R22D, + UC_AVR_REG_R23D, + UC_AVR_REG_R24D, + UC_AVR_REG_R25D, + UC_AVR_REG_R26D, + UC_AVR_REG_R27D, + UC_AVR_REG_R28D, + //> Alias registers UC_AVR_REG_Xhi = UC_AVR_REG_R27, UC_AVR_REG_Xlo = UC_AVR_REG_R26, @@ -112,6 +176,10 @@ typedef enum uc_avr_reg { UC_AVR_REG_Ylo = UC_AVR_REG_R28, UC_AVR_REG_Zhi = UC_AVR_REG_R31, UC_AVR_REG_Zlo = UC_AVR_REG_R30, + + UC_AVR_REG_X = UC_AVR_REG_R26W, + UC_AVR_REG_Y = UC_AVR_REG_R28W, + UC_AVR_REG_Z = UC_AVR_REG_R30W, } uc_avr_reg; #ifdef __cplusplus diff --git a/qemu/target/avr/unicorn.c b/qemu/target/avr/unicorn.c index 4fcb53dc12..260456f085 100644 --- a/qemu/target/avr/unicorn.c +++ b/qemu/target/avr/unicorn.c @@ -80,12 +80,26 @@ static void reg_read(CPUAVRState *env, unsigned int regid, void *value) *(uint8_t *)value = cpu_get_sreg(env); break; - default: + default: { + uint64_t v = 0; if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { *(int8_t *)value = (int8_t)env->r[regid - UC_AVR_REG_R0]; } + else if (regid >= UC_AVR_REG_R0W && regid <= UC_AVR_REG_R30W) { + const uint32_t *const r = &env->r[regid - UC_AVR_REG_R0W]; + for (int k = 0; k < 2; k++) + SET_BYTE(v, k, (r[k] & 0xff)); + *(int16_t *)value = (int16_t)v; + } + else if (regid >= UC_AVR_REG_R0D && regid <= UC_AVR_REG_R28D) { + const uint32_t *const r = &env->r[regid - UC_AVR_REG_R0D]; + for (int k = 0; k < 4; k++) + SET_BYTE(v, k, (r[k] & 0xff)); + *(int32_t *)value = (int32_t)v; + } break; } + } } int avr_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, @@ -154,10 +168,30 @@ static void reg_write(CPUAVRState *env, unsigned int regid, cpu_set_sreg(env, *(uint8_t *)value); break; - default: + default: { + uint64_t v; + uint32_t *r = NULL; + int rlen = 0; if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { - env->r[regid - UC_AVR_REG_R0] = *(uint8_t *)value; + v = *(uint8_t *)value; + r = &env->r[regid - UC_AVR_REG_R0]; + rlen = 1; + } + else if (regid >= UC_AVR_REG_R0W && regid <= UC_AVR_REG_R30W) { + v = *(uint16_t *)value; + r = &env->r[regid - UC_AVR_REG_R0W]; + rlen = 2; } + else if (regid >= UC_AVR_REG_R0D && regid <= UC_AVR_REG_R28D) { + v = *(uint32_t *)value; + r = &env->r[regid - UC_AVR_REG_R0D]; + rlen = 4; + } + if (r && rlen > 0) { + for (int k = 0; k < rlen; k++) + r[k] = GET_BYTE(v, k); + } + } } } From eb21e2f16e9f211961d4f50f16c41c8d43108cf2 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 24 Apr 2024 18:55:08 +0200 Subject: [PATCH 15/31] AVR: fix selection and validation of CPU model. Signed-off-by: Glenn Baker --- qemu/target/avr/cpu.c | 5 +++++ qemu/target/avr/unicorn.h | 2 ++ uc.c | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c index 31a7ded0dc..461d304a78 100644 --- a/qemu/target/avr/cpu.c +++ b/qemu/target/avr/cpu.c @@ -368,6 +368,11 @@ static const AVRCPUInfo *avr_cpu_info_get(int cpu_model) return NULL; } +int avr_cpu_model_valid(int cpu_model) +{ + return avr_cpu_info_get(cpu_model) != NULL; +} + #if 0 static void avr_cpu_list_entry(gpointer data, gpointer user_data) { diff --git a/qemu/target/avr/unicorn.h b/qemu/target/avr/unicorn.h index 817e592111..40cbd3b52e 100644 --- a/qemu/target/avr/unicorn.h +++ b/qemu/target/avr/unicorn.h @@ -23,4 +23,6 @@ void avr_reg_reset(struct uc_struct *uc); void avr_uc_init(struct uc_struct *uc); +int avr_cpu_model_valid(int cpu_model); + #endif /* UC_QEMU_TARGET_AVR_H */ diff --git a/uc.c b/uc.c index 477c5d1170..c2548d060c 100644 --- a/uc.c +++ b/uc.c @@ -2737,6 +2737,11 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) err = UC_ERR_ARG; break; } + } else if (uc->arch == UC_ARCH_AVR) { + if (!avr_cpu_model_valid(model)) { + err = UC_ERR_ARG; + break; + } } else { err = UC_ERR_ARG; break; From 1c99b55ebb971672aa468da112d24f10cd8aace3 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Thu, 28 Mar 2024 21:11:54 +0100 Subject: [PATCH 16/31] Add AVR code samples. Signed-off-by: Glenn Baker --- CMakeLists.txt | 1 + samples/Makefile | 3 + samples/sample_avr.c | 127 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 samples/sample_avr.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7affcfe1ea..c05bd0cd3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1375,6 +1375,7 @@ endif() if (UNICORN_HAS_AVR) set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_AVR) set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} avr-softmmu) + set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_avr) target_link_libraries(avr-softmmu unicorn-common) endif() diff --git a/samples/Makefile b/samples/Makefile index cbb3d91fb7..b896aecb43 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -93,6 +93,9 @@ endif ifneq (,$(findstring tricore,$(UNICORN_ARCHS))) SOURCES += sample_tricore.c endif +ifneq (,$(findstring avr,$(UNICORN_ARCHS))) +SOURCES += sample_avr.c +endif BINS = $(SOURCES:.c=$(BIN_EXT)) OBJS = $(SOURCES:.c=.o) diff --git a/samples/sample_avr.c b/samples/sample_avr.c new file mode 100644 index 0000000000..c20df62599 --- /dev/null +++ b/samples/sample_avr.c @@ -0,0 +1,127 @@ +/* + Created for Unicorn Engine by Glenn Baker , 2024 +*/ + +/* Sample code to demonstrate how to emulate AVR code */ + +#include +#include +#include + +// Code to be emulated +static const uint32_t CODE_BASE = 0x0000; +static const uint8_t CODE[] = + "\x86\x0f" // add r24, r22 + "\x97\x1f" // adc r25, r23 + "\x88\x0f" // add r24, r24 + "\x99\x1f" // adc r25, r25 + "\x01\x96" // adiw r24, 0x01 + "\x08\x95" // ret + ; +static const uint32_t CODE_SIZE = sizeof(CODE) - 1; +static const uint32_t CODE_SIZE_ALIGNED = (CODE_SIZE + 0xff) & -0x100; + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, + void *user_data) +{ + printf(">>> Tracing basic block at 0x%" PRIx64 ", block size = 0x%x\n", + address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, + void *user_data) +{ + printf(">>> Tracing instruction at 0x%" PRIx64 + ", instruction size = 0x%x\n", + address, size); +} + +static bool is_error(uc_err err, const char *what) +{ + if (err != UC_ERR_OK) { + fprintf(stderr, "error: failed on %s() with error %u: %s\n", + what, err, uc_strerror(err)); + return true; + } + return false; +} + +static bool test_avr(void) +{ + uc_engine *uc = NULL; + uc_hook trace1, trace2; + bool success = false; + + printf("Emulate AVR code\n"); + do { + // Initialize emulator in AVR mode + uc_err err = uc_open(UC_ARCH_AVR, UC_MODE_LITTLE_ENDIAN, &uc); + if (is_error(err, "uc_open")) + break; + + // Map program code + err = uc_mem_map(uc, CODE_BASE, CODE_SIZE_ALIGNED, UC_PROT_READ|UC_PROT_EXEC); + if (is_error(err, "uc_mem_map")) + break; + + // Write machine code to be emulated to memory + err = uc_mem_write(uc, CODE_BASE, CODE, CODE_SIZE); + if (is_error(err, "uc_mem_write")) + break; + + // Tracing all basic blocks with customized callback + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); + if (is_error(err, "uc_hook_add[UC_HOOK_BLOCK]")) + break; + + // Tracing one instruction at CODE_BASE with customized callback + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, CODE_BASE, + CODE_BASE + 1); + if (is_error(err, "uc_hook_add[UC_HOOK_CODE]")) + break; + + // Initialize registers + uint8_t regs[32]; + memset(regs, 0, sizeof(regs)); + regs[25] = 0; regs[24] = 1; + regs[23] = 0; regs[22] = 2; + + int reg_ids[32]; + void *reg_vals[32]; + for (unsigned i = 0; i < 4; i++) { + reg_ids[i] = UC_AVR_REG_R0 + 22 + i; + reg_vals[i] = ®s[22 + i]; + } + err = uc_reg_write_batch(uc, reg_ids, reg_vals, 4); + if (is_error(err, "uc_reg_write_batch")) + break; + + // Emulate machine code in infinite time (last param = 0), or + // when finishing all the code. + err = uc_emu_start(uc, CODE_BASE, CODE_BASE + 4, 0, 0); + if (is_error(err, "uc_emu_start")) + break; + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_AVR_REG_R25, ®s[25]); + uc_reg_read(uc, UC_AVR_REG_R24, ®s[24]); + uc_reg_read(uc, UC_AVR_REG_R23, ®s[23]); + uc_reg_read(uc, UC_AVR_REG_R22, ®s[22]); + printf(">>> r25,r24 = 0x%02x%02x\n", regs[25], regs[24]); + if (regs[25] == 0 && regs[24] == 3 && regs[23] == 0 && regs[22] == 2) + success = true; + } while (0); + + if (uc) + uc_close(uc); + return success; +} + +int main(int argc, char **argv, char **envp) +{ + if (!test_avr()) + abort(); + return 0; +} From 3c5f3ea6691684d7ac1f67af97d561b0a4f9d048 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 3 Apr 2024 10:26:06 +0200 Subject: [PATCH 17/31] Add AVR unit tests. Signed-off-by: Glenn Baker --- CMakeLists.txt | 1 + tests/unit/test_avr.c | 265 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 tests/unit/test_avr.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c05bd0cd3b..a428ec4d48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1377,6 +1377,7 @@ if (UNICORN_HAS_AVR) set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} avr-softmmu) set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_avr) target_link_libraries(avr-softmmu unicorn-common) + set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_avr) endif() # Extra tests diff --git a/tests/unit/test_avr.c b/tests/unit/test_avr.c new file mode 100644 index 0000000000..1ffe0509b6 --- /dev/null +++ b/tests/unit/test_avr.c @@ -0,0 +1,265 @@ +#include +#include "unicorn_test.h" + +#define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +#define PAGE_SIZE 256 +#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & -PAGE_SIZE) + +enum { + ADDR__init__, + ADDR_test_func, + ADDR_test_1, + ADDR_main, + ADDR_abort, + ADDR_exit, + ADDR__stop_program, + ADDR__data__, +}; + +static const uint16_t ADDR[] = { + 0x0000, // __init__ + 0x001a, // test_func() + 0x0030, // test_1() + 0x0058, // main() + 0x0062, // abort() + 0x006c, // _exit() + 0x006e, // __stop_program() + 0x0070, // __data__ + 0x0072, // __size__ +}; + +static const uint8_t FLASH[] = + // 00000000 <__ctors_end>: + "\x12\xe0" // ldi r17, 0x02 + "\xa0\xe0" // ldi r26, 0x00 + "\xb2\xe0" // ldi r27, 0x02 + "\xe0\xe7" // ldi r30, 0x70 + "\xf0\xe0" // ldi r31, 0x00 + "\x00\xe0" // ldi r16, 0x00 + "\x0b\xbf" // out 0x3b, r16 + "\x02\xc0" // rjmp .+4 + "\x07\x90" // elpm r0, Z+ + "\x0d\x92" // st X+, r0 + "\xa2\x30" // cpi r26, 0x02 + "\xb1\x07" // cpc r27, r17 + "\xd9\xf7" // brne .-10 + + // 0000001a : + "\x20\x91\x00\x02" // lds r18, 0x0200 + "\x30\x91\x01\x02" // lds r19, 0x0201 + "\x86\x0f" // add r24, r22 + "\x97\x1f" // adc r25, r23 + "\x88\x0f" // add r24, r24 + "\x99\x1f" // adc r25, r25 + "\x82\x0f" // add r24, r18 + "\x93\x1f" // adc r25, r19 + "\x08\x95" // ret + + // 00000030 : + "\x62\xe0" // ldi r22, 0x02 + "\x70\xe0" // ldi r23, 0x00 + "\x81\xe0" // ldi r24, 0x01 + "\x90\xe0" // ldi r25, 0x00 + "\x0e\x94\x0d\x00" // call 0x1a + "\x07\x97" // sbiw r24, 0x07 + "\x11\xf0" // breq .+4 + "\x0e\x94\x31\x00" // call 0x62 + "\x60\xe8" // ldi r22, 0x80 + "\x70\xe0" // ldi r23, 0x00 + "\x80\xe4" // ldi r24, 0x40 + "\x90\xe0" // ldi r25, 0x00 + "\x0e\x94\x0d\x00" // call 0x1a + "\x81\x38" // cpi r24, 0x81 + "\x91\x40" // sbci r25, 0x01 + "\xa9\xf7" // brne .-22 + "\x08\x95" // ret + + // 00000058
: + "\x0e\x94\x18\x00" // call 0x30 + "\x80\xe0" // ldi r24, 0x00 + "\x90\xe0" // ldi r25, 0x00 + "\x08\x95" // ret + + // 00000062 : + "\x81\xe0" // ldi r24, 0x01 + "\x90\xe0" // ldi r25, 0x00 + "\xf8\x94" // cli + "\x0c\x94\x36\x00" // jmp 0x6c + + // 0000006c <_exit>: + "\xf8\x94" // cli + + // 0000006e <__stop_program>: + "\xff\xcf" // rjmp .-2 + + // 0x000070 .data + "\x01\x00" + ; +const uint64_t FLASH_SIZE = sizeof(FLASH); + +const uint64_t MEM_BASE = 0x0200; +const uint64_t MEM_SIZE = 0x0100; + +static void uc_common_setup(uc_engine **uc, uc_cpu_avr cpu_model, + const uint8_t *code, uint64_t code_size) +{ + OK(uc_open(UC_ARCH_AVR, UC_MODE_LITTLE_ENDIAN, uc)); + if (cpu_model != 0) + OK(uc_ctl_set_cpu_model(*uc, cpu_model)); + + OK(uc_mem_map(*uc, UC_AVR_MEM_FLASH, PAGE_ALIGN(code_size), + UC_PROT_READ|UC_PROT_EXEC)); + OK(uc_mem_write(*uc, UC_AVR_MEM_FLASH, code, code_size)); + OK(uc_mem_map(*uc, MEM_BASE, MEM_SIZE, UC_PROT_READ|UC_PROT_WRITE)); +} + +static void test_avr_basic_alu(void) +{ + uc_engine *uc = NULL; + uint8_t r[32] = {0,}; + uint16_t r_func_arg0 = 1, r_func_arg1 = 2, r_func_ret; + r[24] = 1; + r[22] = 2; + + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); + OK(uc_reg_write(uc, UC_AVR_REG_R24W, &r_func_arg0)); + OK(uc_reg_write(uc, UC_AVR_REG_R22W, &r_func_arg1)); + + const uint64_t code_start = ADDR[ADDR_test_func] + 8; + OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0)); + + uint32_t r_pc; + OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); + OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); + OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24])); + OK(uc_reg_read(uc, UC_AVR_REG_R23, &r[23])); + OK(uc_reg_read(uc, UC_AVR_REG_R22, &r[22])); + + TEST_CHECK(r_pc == code_start + 4); + TEST_CHECK(r[25] == 0 && r[24] == 3); + TEST_CHECK(r[23] == 0 && r[22] == 2); + + OK(uc_reg_read(uc, UC_AVR_REG_R24W, &r_func_ret)); + OK(uc_reg_read(uc, UC_AVR_REG_R22W, &r_func_arg1)); + + TEST_CHECK(r_func_ret == r[24]); + TEST_CHECK(r_func_arg1 == r[22]); + + OK(uc_close(uc)); +} + +typedef struct MEM_HOOK_RESULT_s { + uc_mem_type type; + uint64_t address; + int size; + uint64_t value; +} MEM_HOOK_RESULT; + +typedef struct MEM_HOOK_RESULTS_s { + uint64_t count; + MEM_HOOK_RESULT results[16]; +} MEM_HOOK_RESULTS; + +static bool test_avr_basic_mem_cb_eventmem(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data) +{ + MEM_HOOK_RESULTS *const r = user_data; + + uint64_t count = r->count; + if (count >= ARRAY_ELEMS(r->results)) { + TEST_ASSERT(false); + } + + r->results[count].type = type; + r->results[count].address = address; + r->results[count].size = size; + r->results[count].value = value; + r->count++; + return true; +} + +static void test_avr_basic_mem(void) +{ + uc_engine *uc = NULL; + uc_hook eventmem_hook; + MEM_HOOK_RESULTS eventmem_trace = {0}; + + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); + OK(uc_hook_add(uc, &eventmem_hook, UC_HOOK_MEM_VALID, + test_avr_basic_mem_cb_eventmem, &eventmem_trace, 1, 0)); + + const uint64_t code_start = ADDR[ADDR__init__]; + OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0)); + + uint32_t r_pc; + OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); + TEST_CHECK(r_pc == ADDR[ADDR__init__+1]); + + const uint16_t DATA_BASE = ADDR[ADDR__data__]; + const uint16_t DATA_SIZE = ADDR[ADDR__data__+1] - DATA_BASE; + const uint8_t *const DATA = &FLASH[ADDR[ADDR__data__]]; + + // Check SRAM was correctly initialized with data from Flash program memory + uint8_t mem[DATA_SIZE]; + OK(uc_mem_read(uc, MEM_BASE, mem, sizeof(mem))); + TEST_CHECK(memcmp(mem, DATA, DATA_SIZE) == 0); + + TEST_CHECK(eventmem_trace.count == 2*DATA_SIZE); + for (unsigned i = 0; i < DATA_SIZE; i++) { + const MEM_HOOK_RESULT *const mr = &eventmem_trace.results[2*i]; + TEST_CHECK(mr->type == UC_MEM_READ); + TEST_CHECK(mr->address == (UC_AVR_MEM_FLASH|(DATA_BASE+i))); + TEST_CHECK(mr->size == 1); + TEST_CHECK(mr->value == 0); + + const MEM_HOOK_RESULT *const mw = &eventmem_trace.results[2*i+1]; + TEST_CHECK(mw->type == UC_MEM_WRITE); + TEST_CHECK(mw->address == MEM_BASE+i); + TEST_CHECK(mw->size == 1); + TEST_CHECK(mw->value == DATA[i]); + } + + OK(uc_close(uc)); +} + +static void test_avr_full_exec(void) +{ + uc_engine *uc = NULL; + + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); + + const uint64_t code_start = ADDR[ADDR__init__]; + OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0)); + + uint32_t r_pc; + OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); + TEST_CHECK(r_pc == ADDR[ADDR__init__+1]); + + uint32_t r_sp = MEM_BASE + MEM_SIZE - 1; + OK(uc_reg_write(uc, UC_AVR_REG_SP, &r_sp)); + + const uint64_t exits[] = { + ADDR[ADDR_main], + ADDR[ADDR__stop_program] + }; + OK(uc_ctl_exits_enable(uc)); + OK(uc_ctl_set_exits(uc, exits, ARRAY_ELEMS(exits))); + + const uint64_t code_main = ADDR[ADDR_main]; + OK(uc_emu_start(uc, code_main, 0, 0, 0)); + + uint8_t r[32] = {0,}; + OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); + OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24])); + TEST_CHECK(r[25] == 0 && r[24] == 0); + + OK(uc_close(uc)); +} + +TEST_LIST = { + {"test_avr_basic_alu", test_avr_basic_alu}, + {"test_avr_basic_mem", test_avr_basic_mem}, + {"test_avr_full_exec", test_avr_full_exec}, + {NULL, NULL} +}; From 602d2bae4d7abd27aecbfeafe13381686ef54e90 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 27 Mar 2024 22:47:22 +0100 Subject: [PATCH 18/31] bindings: update const generator for AVR. Signed-off-by: Glenn Baker --- bindings/const_generator.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 982b48f4cb..2243548cec 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -6,7 +6,7 @@ INCL_DIR = os.path.join('..', 'include', 'unicorn') -include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'riscv.h', 's390x.h', 'tricore.h', 'unicorn.h' ] +include = [ 'arm.h', 'arm64.h', 'avr.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'riscv.h', 's390x.h', 'tricore.h', 'unicorn.h' ] template = { 'python': { @@ -17,6 +17,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'avr', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', @@ -37,6 +38,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'avr', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', @@ -57,6 +59,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'avr', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', @@ -77,6 +80,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', + 'avr.h': 'AVR', 'mips.h': 'Mips', 'x86.h': 'X86', 'sparc.h': 'Sparc', @@ -97,6 +101,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', + 'avr.h': 'AVR', 'mips.h': 'Mips', 'x86.h': 'X86', 'sparc.h': 'Sparc', @@ -117,6 +122,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', + 'avr.h': 'AVR', 'mips.h': 'Mips', 'x86.h': 'X86', 'sparc.h': 'Sparc', @@ -137,6 +143,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'AVR', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', From abbff497c742d38b841873791211772c89daafe0 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 24 Apr 2024 11:43:32 +0200 Subject: [PATCH 19/31] bindings: regenerate constants for AVR support. Signed-off-by: Glenn Baker --- bindings/dotnet/UnicornEngine/Const/AVR.fs | 155 ++++++++++++++++++ bindings/dotnet/UnicornEngine/Const/Common.fs | 3 +- bindings/go/unicorn/avr_const.go | 150 +++++++++++++++++ bindings/go/unicorn/unicorn_const.go | 3 +- .../java/src/main/java/unicorn/AVRConst.java | 153 +++++++++++++++++ .../src/main/java/unicorn/UnicornConst.java | 3 +- bindings/pascal/unicorn/AVRConst.pas | 155 ++++++++++++++++++ bindings/pascal/unicorn/UnicornConst.pas | 3 +- bindings/python/unicorn/avr_const.py | 147 +++++++++++++++++ bindings/python/unicorn/unicorn_const.py | 3 +- .../lib/unicorn_engine/avr_const.rb | 150 +++++++++++++++++ .../lib/unicorn_engine/unicorn_const.rb | 3 +- bindings/zig/unicorn/AVR_const.zig | 151 +++++++++++++++++ bindings/zig/unicorn/unicorn_const.zig | 3 +- 14 files changed, 1075 insertions(+), 7 deletions(-) create mode 100644 bindings/dotnet/UnicornEngine/Const/AVR.fs create mode 100644 bindings/go/unicorn/avr_const.go create mode 100644 bindings/java/src/main/java/unicorn/AVRConst.java create mode 100644 bindings/pascal/unicorn/AVRConst.pas create mode 100644 bindings/python/unicorn/avr_const.py create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb create mode 100644 bindings/zig/unicorn/AVR_const.zig diff --git a/bindings/dotnet/UnicornEngine/Const/AVR.fs b/bindings/dotnet/UnicornEngine/Const/AVR.fs new file mode 100644 index 0000000000..d7613dac85 --- /dev/null +++ b/bindings/dotnet/UnicornEngine/Const/AVR.fs @@ -0,0 +1,155 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +namespace UnicornEngine.Const + +open System + +[] +module AVR = + + // AVR architectures + let UC_AVR_ARCH_AVR1 = 10 + let UC_AVR_ARCH_AVR2 = 20 + let UC_AVR_ARCH_AVR25 = 25 + let UC_AVR_ARCH_AVR3 = 30 + let UC_AVR_ARCH_AVR4 = 40 + let UC_AVR_ARCH_AVR5 = 50 + let UC_AVR_ARCH_AVR51 = 51 + let UC_AVR_ARCH_AVR6 = 60 + let UC_CPU_AVR_ARCH = 1000 + + // AVR CPU + let UC_CPU_AVR_ATMEGA16 = 50016 + let UC_CPU_AVR_ATMEGA32 = 50032 + let UC_CPU_AVR_ATMEGA64 = 50064 + let UC_CPU_AVR_ATMEGA128 = 51128 + let UC_CPU_AVR_ATMEGA128RFR2 = 51129 + let UC_CPU_AVR_ATMEGA1280 = 51130 + let UC_CPU_AVR_ATMEGA256 = 60256 + let UC_CPU_AVR_ATMEGA256RFR2 = 60257 + let UC_CPU_AVR_ATMEGA2560 = 60258 + + // AVR memory + let UC_AVR_MEM_FLASH = 134217728 + + // AVR registers + + let UC_AVR_REG_INVALID = 0 + let UC_AVR_REG_R0 = 1 + let UC_AVR_REG_R1 = 2 + let UC_AVR_REG_R2 = 3 + let UC_AVR_REG_R3 = 4 + let UC_AVR_REG_R4 = 5 + let UC_AVR_REG_R5 = 6 + let UC_AVR_REG_R6 = 7 + let UC_AVR_REG_R7 = 8 + let UC_AVR_REG_R8 = 9 + let UC_AVR_REG_R9 = 10 + let UC_AVR_REG_R10 = 11 + let UC_AVR_REG_R11 = 12 + let UC_AVR_REG_R12 = 13 + let UC_AVR_REG_R13 = 14 + let UC_AVR_REG_R14 = 15 + let UC_AVR_REG_R15 = 16 + let UC_AVR_REG_R16 = 17 + let UC_AVR_REG_R17 = 18 + let UC_AVR_REG_R18 = 19 + let UC_AVR_REG_R19 = 20 + let UC_AVR_REG_R20 = 21 + let UC_AVR_REG_R21 = 22 + let UC_AVR_REG_R22 = 23 + let UC_AVR_REG_R23 = 24 + let UC_AVR_REG_R24 = 25 + let UC_AVR_REG_R25 = 26 + let UC_AVR_REG_R26 = 27 + let UC_AVR_REG_R27 = 28 + let UC_AVR_REG_R28 = 29 + let UC_AVR_REG_R29 = 30 + let UC_AVR_REG_R30 = 31 + let UC_AVR_REG_R31 = 32 + let UC_AVR_REG_PC = 33 + let UC_AVR_REG_SP = 34 + let UC_AVR_REG_RAMPD = 57 + let UC_AVR_REG_RAMPX = 58 + let UC_AVR_REG_RAMPY = 59 + let UC_AVR_REG_RAMPZ = 60 + let UC_AVR_REG_EIND = 61 + let UC_AVR_REG_SPL = 62 + let UC_AVR_REG_SPH = 63 + let UC_AVR_REG_SREG = 64 + + // 16-bit coalesced registers + let UC_AVR_REG_R0W = 65 + let UC_AVR_REG_R1W = 66 + let UC_AVR_REG_R2W = 67 + let UC_AVR_REG_R3W = 68 + let UC_AVR_REG_R4W = 69 + let UC_AVR_REG_R5W = 70 + let UC_AVR_REG_R6W = 71 + let UC_AVR_REG_R7W = 72 + let UC_AVR_REG_R8W = 73 + let UC_AVR_REG_R9W = 74 + let UC_AVR_REG_R10W = 75 + let UC_AVR_REG_R11W = 76 + let UC_AVR_REG_R12W = 77 + let UC_AVR_REG_R13W = 78 + let UC_AVR_REG_R14W = 79 + let UC_AVR_REG_R15W = 80 + let UC_AVR_REG_R16W = 81 + let UC_AVR_REG_R17W = 82 + let UC_AVR_REG_R18W = 83 + let UC_AVR_REG_R19W = 84 + let UC_AVR_REG_R20W = 85 + let UC_AVR_REG_R21W = 86 + let UC_AVR_REG_R22W = 87 + let UC_AVR_REG_R23W = 88 + let UC_AVR_REG_R24W = 89 + let UC_AVR_REG_R25W = 90 + let UC_AVR_REG_R26W = 91 + let UC_AVR_REG_R27W = 92 + let UC_AVR_REG_R28W = 93 + let UC_AVR_REG_R29W = 94 + let UC_AVR_REG_R30W = 95 + + // 32-bit coalesced registers + let UC_AVR_REG_R0D = 97 + let UC_AVR_REG_R1D = 98 + let UC_AVR_REG_R2D = 99 + let UC_AVR_REG_R3D = 100 + let UC_AVR_REG_R4D = 101 + let UC_AVR_REG_R5D = 102 + let UC_AVR_REG_R6D = 103 + let UC_AVR_REG_R7D = 104 + let UC_AVR_REG_R8D = 105 + let UC_AVR_REG_R9D = 106 + let UC_AVR_REG_R10D = 107 + let UC_AVR_REG_R11D = 108 + let UC_AVR_REG_R12D = 109 + let UC_AVR_REG_R13D = 110 + let UC_AVR_REG_R14D = 111 + let UC_AVR_REG_R15D = 112 + let UC_AVR_REG_R16D = 113 + let UC_AVR_REG_R17D = 114 + let UC_AVR_REG_R18D = 115 + let UC_AVR_REG_R19D = 116 + let UC_AVR_REG_R20D = 117 + let UC_AVR_REG_R21D = 118 + let UC_AVR_REG_R22D = 119 + let UC_AVR_REG_R23D = 120 + let UC_AVR_REG_R24D = 121 + let UC_AVR_REG_R25D = 122 + let UC_AVR_REG_R26D = 123 + let UC_AVR_REG_R27D = 124 + let UC_AVR_REG_R28D = 125 + + // Alias registers + let UC_AVR_REG_Xhi = 28 + let UC_AVR_REG_Xlo = 27 + let UC_AVR_REG_Yhi = 30 + let UC_AVR_REG_Ylo = 29 + let UC_AVR_REG_Zhi = 32 + let UC_AVR_REG_Zlo = 31 + let UC_AVR_REG_X = 91 + let UC_AVR_REG_Y = 93 + let UC_AVR_REG_Z = 95 + diff --git a/bindings/dotnet/UnicornEngine/Const/Common.fs b/bindings/dotnet/UnicornEngine/Const/Common.fs index 76f1ce118b..4b97dbdbb5 100644 --- a/bindings/dotnet/UnicornEngine/Const/Common.fs +++ b/bindings/dotnet/UnicornEngine/Const/Common.fs @@ -28,7 +28,8 @@ module Common = let UC_ARCH_RISCV = 8 let UC_ARCH_S390X = 9 let UC_ARCH_TRICORE = 10 - let UC_ARCH_MAX = 11 + let UC_ARCH_AVR = 11 + let UC_ARCH_MAX = 12 let UC_MODE_LITTLE_ENDIAN = 0 let UC_MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/go/unicorn/avr_const.go b/bindings/go/unicorn/avr_const.go new file mode 100644 index 0000000000..985bf7d009 --- /dev/null +++ b/bindings/go/unicorn/avr_const.go @@ -0,0 +1,150 @@ +package unicorn +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [avr_const.go] +const ( + +// AVR architectures + AVR_ARCH_AVR1 = 10 + AVR_ARCH_AVR2 = 20 + AVR_ARCH_AVR25 = 25 + AVR_ARCH_AVR3 = 30 + AVR_ARCH_AVR4 = 40 + AVR_ARCH_AVR5 = 50 + AVR_ARCH_AVR51 = 51 + AVR_ARCH_AVR6 = 60 + CPU_AVR_ARCH = 1000 + +// AVR CPU + CPU_AVR_ATMEGA16 = 50016 + CPU_AVR_ATMEGA32 = 50032 + CPU_AVR_ATMEGA64 = 50064 + CPU_AVR_ATMEGA128 = 51128 + CPU_AVR_ATMEGA128RFR2 = 51129 + CPU_AVR_ATMEGA1280 = 51130 + CPU_AVR_ATMEGA256 = 60256 + CPU_AVR_ATMEGA256RFR2 = 60257 + CPU_AVR_ATMEGA2560 = 60258 + +// AVR memory + AVR_MEM_FLASH = 134217728 + +// AVR registers + + AVR_REG_INVALID = 0 + AVR_REG_R0 = 1 + AVR_REG_R1 = 2 + AVR_REG_R2 = 3 + AVR_REG_R3 = 4 + AVR_REG_R4 = 5 + AVR_REG_R5 = 6 + AVR_REG_R6 = 7 + AVR_REG_R7 = 8 + AVR_REG_R8 = 9 + AVR_REG_R9 = 10 + AVR_REG_R10 = 11 + AVR_REG_R11 = 12 + AVR_REG_R12 = 13 + AVR_REG_R13 = 14 + AVR_REG_R14 = 15 + AVR_REG_R15 = 16 + AVR_REG_R16 = 17 + AVR_REG_R17 = 18 + AVR_REG_R18 = 19 + AVR_REG_R19 = 20 + AVR_REG_R20 = 21 + AVR_REG_R21 = 22 + AVR_REG_R22 = 23 + AVR_REG_R23 = 24 + AVR_REG_R24 = 25 + AVR_REG_R25 = 26 + AVR_REG_R26 = 27 + AVR_REG_R27 = 28 + AVR_REG_R28 = 29 + AVR_REG_R29 = 30 + AVR_REG_R30 = 31 + AVR_REG_R31 = 32 + AVR_REG_PC = 33 + AVR_REG_SP = 34 + AVR_REG_RAMPD = 57 + AVR_REG_RAMPX = 58 + AVR_REG_RAMPY = 59 + AVR_REG_RAMPZ = 60 + AVR_REG_EIND = 61 + AVR_REG_SPL = 62 + AVR_REG_SPH = 63 + AVR_REG_SREG = 64 + +// 16-bit coalesced registers + AVR_REG_R0W = 65 + AVR_REG_R1W = 66 + AVR_REG_R2W = 67 + AVR_REG_R3W = 68 + AVR_REG_R4W = 69 + AVR_REG_R5W = 70 + AVR_REG_R6W = 71 + AVR_REG_R7W = 72 + AVR_REG_R8W = 73 + AVR_REG_R9W = 74 + AVR_REG_R10W = 75 + AVR_REG_R11W = 76 + AVR_REG_R12W = 77 + AVR_REG_R13W = 78 + AVR_REG_R14W = 79 + AVR_REG_R15W = 80 + AVR_REG_R16W = 81 + AVR_REG_R17W = 82 + AVR_REG_R18W = 83 + AVR_REG_R19W = 84 + AVR_REG_R20W = 85 + AVR_REG_R21W = 86 + AVR_REG_R22W = 87 + AVR_REG_R23W = 88 + AVR_REG_R24W = 89 + AVR_REG_R25W = 90 + AVR_REG_R26W = 91 + AVR_REG_R27W = 92 + AVR_REG_R28W = 93 + AVR_REG_R29W = 94 + AVR_REG_R30W = 95 + +// 32-bit coalesced registers + AVR_REG_R0D = 97 + AVR_REG_R1D = 98 + AVR_REG_R2D = 99 + AVR_REG_R3D = 100 + AVR_REG_R4D = 101 + AVR_REG_R5D = 102 + AVR_REG_R6D = 103 + AVR_REG_R7D = 104 + AVR_REG_R8D = 105 + AVR_REG_R9D = 106 + AVR_REG_R10D = 107 + AVR_REG_R11D = 108 + AVR_REG_R12D = 109 + AVR_REG_R13D = 110 + AVR_REG_R14D = 111 + AVR_REG_R15D = 112 + AVR_REG_R16D = 113 + AVR_REG_R17D = 114 + AVR_REG_R18D = 115 + AVR_REG_R19D = 116 + AVR_REG_R20D = 117 + AVR_REG_R21D = 118 + AVR_REG_R22D = 119 + AVR_REG_R23D = 120 + AVR_REG_R24D = 121 + AVR_REG_R25D = 122 + AVR_REG_R26D = 123 + AVR_REG_R27D = 124 + AVR_REG_R28D = 125 + +// Alias registers + AVR_REG_Xhi = 28 + AVR_REG_Xlo = 27 + AVR_REG_Yhi = 30 + AVR_REG_Ylo = 29 + AVR_REG_Zhi = 32 + AVR_REG_Zlo = 31 + AVR_REG_X = 91 + AVR_REG_Y = 93 + AVR_REG_Z = 95 +) \ No newline at end of file diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 16b03619ae..796f8d2b06 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -23,7 +23,8 @@ const ( ARCH_RISCV = 8 ARCH_S390X = 9 ARCH_TRICORE = 10 - ARCH_MAX = 11 + ARCH_AVR = 11 + ARCH_MAX = 12 MODE_LITTLE_ENDIAN = 0 MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/java/src/main/java/unicorn/AVRConst.java b/bindings/java/src/main/java/unicorn/AVRConst.java new file mode 100644 index 0000000000..066fd97774 --- /dev/null +++ b/bindings/java/src/main/java/unicorn/AVRConst.java @@ -0,0 +1,153 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +package unicorn; + +public interface AVRConst { + + // AVR architectures + public static final int UC_AVR_ARCH_AVR1 = 10; + public static final int UC_AVR_ARCH_AVR2 = 20; + public static final int UC_AVR_ARCH_AVR25 = 25; + public static final int UC_AVR_ARCH_AVR3 = 30; + public static final int UC_AVR_ARCH_AVR4 = 40; + public static final int UC_AVR_ARCH_AVR5 = 50; + public static final int UC_AVR_ARCH_AVR51 = 51; + public static final int UC_AVR_ARCH_AVR6 = 60; + public static final int UC_CPU_AVR_ARCH = 1000; + + // AVR CPU + public static final int UC_CPU_AVR_ATMEGA16 = 50016; + public static final int UC_CPU_AVR_ATMEGA32 = 50032; + public static final int UC_CPU_AVR_ATMEGA64 = 50064; + public static final int UC_CPU_AVR_ATMEGA128 = 51128; + public static final int UC_CPU_AVR_ATMEGA128RFR2 = 51129; + public static final int UC_CPU_AVR_ATMEGA1280 = 51130; + public static final int UC_CPU_AVR_ATMEGA256 = 60256; + public static final int UC_CPU_AVR_ATMEGA256RFR2 = 60257; + public static final int UC_CPU_AVR_ATMEGA2560 = 60258; + + // AVR memory + public static final int UC_AVR_MEM_FLASH = 134217728; + + // AVR registers + + public static final int UC_AVR_REG_INVALID = 0; + public static final int UC_AVR_REG_R0 = 1; + public static final int UC_AVR_REG_R1 = 2; + public static final int UC_AVR_REG_R2 = 3; + public static final int UC_AVR_REG_R3 = 4; + public static final int UC_AVR_REG_R4 = 5; + public static final int UC_AVR_REG_R5 = 6; + public static final int UC_AVR_REG_R6 = 7; + public static final int UC_AVR_REG_R7 = 8; + public static final int UC_AVR_REG_R8 = 9; + public static final int UC_AVR_REG_R9 = 10; + public static final int UC_AVR_REG_R10 = 11; + public static final int UC_AVR_REG_R11 = 12; + public static final int UC_AVR_REG_R12 = 13; + public static final int UC_AVR_REG_R13 = 14; + public static final int UC_AVR_REG_R14 = 15; + public static final int UC_AVR_REG_R15 = 16; + public static final int UC_AVR_REG_R16 = 17; + public static final int UC_AVR_REG_R17 = 18; + public static final int UC_AVR_REG_R18 = 19; + public static final int UC_AVR_REG_R19 = 20; + public static final int UC_AVR_REG_R20 = 21; + public static final int UC_AVR_REG_R21 = 22; + public static final int UC_AVR_REG_R22 = 23; + public static final int UC_AVR_REG_R23 = 24; + public static final int UC_AVR_REG_R24 = 25; + public static final int UC_AVR_REG_R25 = 26; + public static final int UC_AVR_REG_R26 = 27; + public static final int UC_AVR_REG_R27 = 28; + public static final int UC_AVR_REG_R28 = 29; + public static final int UC_AVR_REG_R29 = 30; + public static final int UC_AVR_REG_R30 = 31; + public static final int UC_AVR_REG_R31 = 32; + public static final int UC_AVR_REG_PC = 33; + public static final int UC_AVR_REG_SP = 34; + public static final int UC_AVR_REG_RAMPD = 57; + public static final int UC_AVR_REG_RAMPX = 58; + public static final int UC_AVR_REG_RAMPY = 59; + public static final int UC_AVR_REG_RAMPZ = 60; + public static final int UC_AVR_REG_EIND = 61; + public static final int UC_AVR_REG_SPL = 62; + public static final int UC_AVR_REG_SPH = 63; + public static final int UC_AVR_REG_SREG = 64; + + // 16-bit coalesced registers + public static final int UC_AVR_REG_R0W = 65; + public static final int UC_AVR_REG_R1W = 66; + public static final int UC_AVR_REG_R2W = 67; + public static final int UC_AVR_REG_R3W = 68; + public static final int UC_AVR_REG_R4W = 69; + public static final int UC_AVR_REG_R5W = 70; + public static final int UC_AVR_REG_R6W = 71; + public static final int UC_AVR_REG_R7W = 72; + public static final int UC_AVR_REG_R8W = 73; + public static final int UC_AVR_REG_R9W = 74; + public static final int UC_AVR_REG_R10W = 75; + public static final int UC_AVR_REG_R11W = 76; + public static final int UC_AVR_REG_R12W = 77; + public static final int UC_AVR_REG_R13W = 78; + public static final int UC_AVR_REG_R14W = 79; + public static final int UC_AVR_REG_R15W = 80; + public static final int UC_AVR_REG_R16W = 81; + public static final int UC_AVR_REG_R17W = 82; + public static final int UC_AVR_REG_R18W = 83; + public static final int UC_AVR_REG_R19W = 84; + public static final int UC_AVR_REG_R20W = 85; + public static final int UC_AVR_REG_R21W = 86; + public static final int UC_AVR_REG_R22W = 87; + public static final int UC_AVR_REG_R23W = 88; + public static final int UC_AVR_REG_R24W = 89; + public static final int UC_AVR_REG_R25W = 90; + public static final int UC_AVR_REG_R26W = 91; + public static final int UC_AVR_REG_R27W = 92; + public static final int UC_AVR_REG_R28W = 93; + public static final int UC_AVR_REG_R29W = 94; + public static final int UC_AVR_REG_R30W = 95; + + // 32-bit coalesced registers + public static final int UC_AVR_REG_R0D = 97; + public static final int UC_AVR_REG_R1D = 98; + public static final int UC_AVR_REG_R2D = 99; + public static final int UC_AVR_REG_R3D = 100; + public static final int UC_AVR_REG_R4D = 101; + public static final int UC_AVR_REG_R5D = 102; + public static final int UC_AVR_REG_R6D = 103; + public static final int UC_AVR_REG_R7D = 104; + public static final int UC_AVR_REG_R8D = 105; + public static final int UC_AVR_REG_R9D = 106; + public static final int UC_AVR_REG_R10D = 107; + public static final int UC_AVR_REG_R11D = 108; + public static final int UC_AVR_REG_R12D = 109; + public static final int UC_AVR_REG_R13D = 110; + public static final int UC_AVR_REG_R14D = 111; + public static final int UC_AVR_REG_R15D = 112; + public static final int UC_AVR_REG_R16D = 113; + public static final int UC_AVR_REG_R17D = 114; + public static final int UC_AVR_REG_R18D = 115; + public static final int UC_AVR_REG_R19D = 116; + public static final int UC_AVR_REG_R20D = 117; + public static final int UC_AVR_REG_R21D = 118; + public static final int UC_AVR_REG_R22D = 119; + public static final int UC_AVR_REG_R23D = 120; + public static final int UC_AVR_REG_R24D = 121; + public static final int UC_AVR_REG_R25D = 122; + public static final int UC_AVR_REG_R26D = 123; + public static final int UC_AVR_REG_R27D = 124; + public static final int UC_AVR_REG_R28D = 125; + + // Alias registers + public static final int UC_AVR_REG_Xhi = 28; + public static final int UC_AVR_REG_Xlo = 27; + public static final int UC_AVR_REG_Yhi = 30; + public static final int UC_AVR_REG_Ylo = 29; + public static final int UC_AVR_REG_Zhi = 32; + public static final int UC_AVR_REG_Zlo = 31; + public static final int UC_AVR_REG_X = 91; + public static final int UC_AVR_REG_Y = 93; + public static final int UC_AVR_REG_Z = 95; + +} diff --git a/bindings/java/src/main/java/unicorn/UnicornConst.java b/bindings/java/src/main/java/unicorn/UnicornConst.java index b0d135a845..6e138e0313 100644 --- a/bindings/java/src/main/java/unicorn/UnicornConst.java +++ b/bindings/java/src/main/java/unicorn/UnicornConst.java @@ -25,7 +25,8 @@ public interface UnicornConst { public static final int UC_ARCH_RISCV = 8; public static final int UC_ARCH_S390X = 9; public static final int UC_ARCH_TRICORE = 10; - public static final int UC_ARCH_MAX = 11; + public static final int UC_ARCH_AVR = 11; + public static final int UC_ARCH_MAX = 12; public static final int UC_MODE_LITTLE_ENDIAN = 0; public static final int UC_MODE_BIG_ENDIAN = 1073741824; diff --git a/bindings/pascal/unicorn/AVRConst.pas b/bindings/pascal/unicorn/AVRConst.pas new file mode 100644 index 0000000000..c607d54ac9 --- /dev/null +++ b/bindings/pascal/unicorn/AVRConst.pas @@ -0,0 +1,155 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit AVRConst; + +interface + +const +// AVR architectures + UC_AVR_ARCH_AVR1 = 10; + UC_AVR_ARCH_AVR2 = 20; + UC_AVR_ARCH_AVR25 = 25; + UC_AVR_ARCH_AVR3 = 30; + UC_AVR_ARCH_AVR4 = 40; + UC_AVR_ARCH_AVR5 = 50; + UC_AVR_ARCH_AVR51 = 51; + UC_AVR_ARCH_AVR6 = 60; + UC_CPU_AVR_ARCH = 1000; + +// AVR CPU + UC_CPU_AVR_ATMEGA16 = 50016; + UC_CPU_AVR_ATMEGA32 = 50032; + UC_CPU_AVR_ATMEGA64 = 50064; + UC_CPU_AVR_ATMEGA128 = 51128; + UC_CPU_AVR_ATMEGA128RFR2 = 51129; + UC_CPU_AVR_ATMEGA1280 = 51130; + UC_CPU_AVR_ATMEGA256 = 60256; + UC_CPU_AVR_ATMEGA256RFR2 = 60257; + UC_CPU_AVR_ATMEGA2560 = 60258; + +// AVR memory + UC_AVR_MEM_FLASH = 134217728; + +// AVR registers + + UC_AVR_REG_INVALID = 0; + UC_AVR_REG_R0 = 1; + UC_AVR_REG_R1 = 2; + UC_AVR_REG_R2 = 3; + UC_AVR_REG_R3 = 4; + UC_AVR_REG_R4 = 5; + UC_AVR_REG_R5 = 6; + UC_AVR_REG_R6 = 7; + UC_AVR_REG_R7 = 8; + UC_AVR_REG_R8 = 9; + UC_AVR_REG_R9 = 10; + UC_AVR_REG_R10 = 11; + UC_AVR_REG_R11 = 12; + UC_AVR_REG_R12 = 13; + UC_AVR_REG_R13 = 14; + UC_AVR_REG_R14 = 15; + UC_AVR_REG_R15 = 16; + UC_AVR_REG_R16 = 17; + UC_AVR_REG_R17 = 18; + UC_AVR_REG_R18 = 19; + UC_AVR_REG_R19 = 20; + UC_AVR_REG_R20 = 21; + UC_AVR_REG_R21 = 22; + UC_AVR_REG_R22 = 23; + UC_AVR_REG_R23 = 24; + UC_AVR_REG_R24 = 25; + UC_AVR_REG_R25 = 26; + UC_AVR_REG_R26 = 27; + UC_AVR_REG_R27 = 28; + UC_AVR_REG_R28 = 29; + UC_AVR_REG_R29 = 30; + UC_AVR_REG_R30 = 31; + UC_AVR_REG_R31 = 32; + UC_AVR_REG_PC = 33; + UC_AVR_REG_SP = 34; + UC_AVR_REG_RAMPD = 57; + UC_AVR_REG_RAMPX = 58; + UC_AVR_REG_RAMPY = 59; + UC_AVR_REG_RAMPZ = 60; + UC_AVR_REG_EIND = 61; + UC_AVR_REG_SPL = 62; + UC_AVR_REG_SPH = 63; + UC_AVR_REG_SREG = 64; + +// 16-bit coalesced registers + UC_AVR_REG_R0W = 65; + UC_AVR_REG_R1W = 66; + UC_AVR_REG_R2W = 67; + UC_AVR_REG_R3W = 68; + UC_AVR_REG_R4W = 69; + UC_AVR_REG_R5W = 70; + UC_AVR_REG_R6W = 71; + UC_AVR_REG_R7W = 72; + UC_AVR_REG_R8W = 73; + UC_AVR_REG_R9W = 74; + UC_AVR_REG_R10W = 75; + UC_AVR_REG_R11W = 76; + UC_AVR_REG_R12W = 77; + UC_AVR_REG_R13W = 78; + UC_AVR_REG_R14W = 79; + UC_AVR_REG_R15W = 80; + UC_AVR_REG_R16W = 81; + UC_AVR_REG_R17W = 82; + UC_AVR_REG_R18W = 83; + UC_AVR_REG_R19W = 84; + UC_AVR_REG_R20W = 85; + UC_AVR_REG_R21W = 86; + UC_AVR_REG_R22W = 87; + UC_AVR_REG_R23W = 88; + UC_AVR_REG_R24W = 89; + UC_AVR_REG_R25W = 90; + UC_AVR_REG_R26W = 91; + UC_AVR_REG_R27W = 92; + UC_AVR_REG_R28W = 93; + UC_AVR_REG_R29W = 94; + UC_AVR_REG_R30W = 95; + +// 32-bit coalesced registers + UC_AVR_REG_R0D = 97; + UC_AVR_REG_R1D = 98; + UC_AVR_REG_R2D = 99; + UC_AVR_REG_R3D = 100; + UC_AVR_REG_R4D = 101; + UC_AVR_REG_R5D = 102; + UC_AVR_REG_R6D = 103; + UC_AVR_REG_R7D = 104; + UC_AVR_REG_R8D = 105; + UC_AVR_REG_R9D = 106; + UC_AVR_REG_R10D = 107; + UC_AVR_REG_R11D = 108; + UC_AVR_REG_R12D = 109; + UC_AVR_REG_R13D = 110; + UC_AVR_REG_R14D = 111; + UC_AVR_REG_R15D = 112; + UC_AVR_REG_R16D = 113; + UC_AVR_REG_R17D = 114; + UC_AVR_REG_R18D = 115; + UC_AVR_REG_R19D = 116; + UC_AVR_REG_R20D = 117; + UC_AVR_REG_R21D = 118; + UC_AVR_REG_R22D = 119; + UC_AVR_REG_R23D = 120; + UC_AVR_REG_R24D = 121; + UC_AVR_REG_R25D = 122; + UC_AVR_REG_R26D = 123; + UC_AVR_REG_R27D = 124; + UC_AVR_REG_R28D = 125; + +// Alias registers + UC_AVR_REG_Xhi = 28; + UC_AVR_REG_Xlo = 27; + UC_AVR_REG_Yhi = 30; + UC_AVR_REG_Ylo = 29; + UC_AVR_REG_Zhi = 32; + UC_AVR_REG_Zlo = 31; + UC_AVR_REG_X = 91; + UC_AVR_REG_Y = 93; + UC_AVR_REG_Z = 95; + +implementation +end. \ No newline at end of file diff --git a/bindings/pascal/unicorn/UnicornConst.pas b/bindings/pascal/unicorn/UnicornConst.pas index 92a99d4a56..63a447f2e9 100644 --- a/bindings/pascal/unicorn/UnicornConst.pas +++ b/bindings/pascal/unicorn/UnicornConst.pas @@ -26,7 +26,8 @@ interface UC_ARCH_RISCV = 8; UC_ARCH_S390X = 9; UC_ARCH_TRICORE = 10; - UC_ARCH_MAX = 11; + UC_ARCH_AVR = 11; + UC_ARCH_MAX = 12; UC_MODE_LITTLE_ENDIAN = 0; UC_MODE_BIG_ENDIAN = 1073741824; diff --git a/bindings/python/unicorn/avr_const.py b/bindings/python/unicorn/avr_const.py new file mode 100644 index 0000000000..1bf80a3fa5 --- /dev/null +++ b/bindings/python/unicorn/avr_const.py @@ -0,0 +1,147 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [avr_const.py] + +# AVR architectures +UC_AVR_ARCH_AVR1 = 10 +UC_AVR_ARCH_AVR2 = 20 +UC_AVR_ARCH_AVR25 = 25 +UC_AVR_ARCH_AVR3 = 30 +UC_AVR_ARCH_AVR4 = 40 +UC_AVR_ARCH_AVR5 = 50 +UC_AVR_ARCH_AVR51 = 51 +UC_AVR_ARCH_AVR6 = 60 +UC_CPU_AVR_ARCH = 1000 + +# AVR CPU +UC_CPU_AVR_ATMEGA16 = 50016 +UC_CPU_AVR_ATMEGA32 = 50032 +UC_CPU_AVR_ATMEGA64 = 50064 +UC_CPU_AVR_ATMEGA128 = 51128 +UC_CPU_AVR_ATMEGA128RFR2 = 51129 +UC_CPU_AVR_ATMEGA1280 = 51130 +UC_CPU_AVR_ATMEGA256 = 60256 +UC_CPU_AVR_ATMEGA256RFR2 = 60257 +UC_CPU_AVR_ATMEGA2560 = 60258 + +# AVR memory +UC_AVR_MEM_FLASH = 134217728 + +# AVR registers + +UC_AVR_REG_INVALID = 0 +UC_AVR_REG_R0 = 1 +UC_AVR_REG_R1 = 2 +UC_AVR_REG_R2 = 3 +UC_AVR_REG_R3 = 4 +UC_AVR_REG_R4 = 5 +UC_AVR_REG_R5 = 6 +UC_AVR_REG_R6 = 7 +UC_AVR_REG_R7 = 8 +UC_AVR_REG_R8 = 9 +UC_AVR_REG_R9 = 10 +UC_AVR_REG_R10 = 11 +UC_AVR_REG_R11 = 12 +UC_AVR_REG_R12 = 13 +UC_AVR_REG_R13 = 14 +UC_AVR_REG_R14 = 15 +UC_AVR_REG_R15 = 16 +UC_AVR_REG_R16 = 17 +UC_AVR_REG_R17 = 18 +UC_AVR_REG_R18 = 19 +UC_AVR_REG_R19 = 20 +UC_AVR_REG_R20 = 21 +UC_AVR_REG_R21 = 22 +UC_AVR_REG_R22 = 23 +UC_AVR_REG_R23 = 24 +UC_AVR_REG_R24 = 25 +UC_AVR_REG_R25 = 26 +UC_AVR_REG_R26 = 27 +UC_AVR_REG_R27 = 28 +UC_AVR_REG_R28 = 29 +UC_AVR_REG_R29 = 30 +UC_AVR_REG_R30 = 31 +UC_AVR_REG_R31 = 32 +UC_AVR_REG_PC = 33 +UC_AVR_REG_SP = 34 +UC_AVR_REG_RAMPD = 57 +UC_AVR_REG_RAMPX = 58 +UC_AVR_REG_RAMPY = 59 +UC_AVR_REG_RAMPZ = 60 +UC_AVR_REG_EIND = 61 +UC_AVR_REG_SPL = 62 +UC_AVR_REG_SPH = 63 +UC_AVR_REG_SREG = 64 + +# 16-bit coalesced registers +UC_AVR_REG_R0W = 65 +UC_AVR_REG_R1W = 66 +UC_AVR_REG_R2W = 67 +UC_AVR_REG_R3W = 68 +UC_AVR_REG_R4W = 69 +UC_AVR_REG_R5W = 70 +UC_AVR_REG_R6W = 71 +UC_AVR_REG_R7W = 72 +UC_AVR_REG_R8W = 73 +UC_AVR_REG_R9W = 74 +UC_AVR_REG_R10W = 75 +UC_AVR_REG_R11W = 76 +UC_AVR_REG_R12W = 77 +UC_AVR_REG_R13W = 78 +UC_AVR_REG_R14W = 79 +UC_AVR_REG_R15W = 80 +UC_AVR_REG_R16W = 81 +UC_AVR_REG_R17W = 82 +UC_AVR_REG_R18W = 83 +UC_AVR_REG_R19W = 84 +UC_AVR_REG_R20W = 85 +UC_AVR_REG_R21W = 86 +UC_AVR_REG_R22W = 87 +UC_AVR_REG_R23W = 88 +UC_AVR_REG_R24W = 89 +UC_AVR_REG_R25W = 90 +UC_AVR_REG_R26W = 91 +UC_AVR_REG_R27W = 92 +UC_AVR_REG_R28W = 93 +UC_AVR_REG_R29W = 94 +UC_AVR_REG_R30W = 95 + +# 32-bit coalesced registers +UC_AVR_REG_R0D = 97 +UC_AVR_REG_R1D = 98 +UC_AVR_REG_R2D = 99 +UC_AVR_REG_R3D = 100 +UC_AVR_REG_R4D = 101 +UC_AVR_REG_R5D = 102 +UC_AVR_REG_R6D = 103 +UC_AVR_REG_R7D = 104 +UC_AVR_REG_R8D = 105 +UC_AVR_REG_R9D = 106 +UC_AVR_REG_R10D = 107 +UC_AVR_REG_R11D = 108 +UC_AVR_REG_R12D = 109 +UC_AVR_REG_R13D = 110 +UC_AVR_REG_R14D = 111 +UC_AVR_REG_R15D = 112 +UC_AVR_REG_R16D = 113 +UC_AVR_REG_R17D = 114 +UC_AVR_REG_R18D = 115 +UC_AVR_REG_R19D = 116 +UC_AVR_REG_R20D = 117 +UC_AVR_REG_R21D = 118 +UC_AVR_REG_R22D = 119 +UC_AVR_REG_R23D = 120 +UC_AVR_REG_R24D = 121 +UC_AVR_REG_R25D = 122 +UC_AVR_REG_R26D = 123 +UC_AVR_REG_R27D = 124 +UC_AVR_REG_R28D = 125 + +# Alias registers +UC_AVR_REG_Xhi = 28 +UC_AVR_REG_Xlo = 27 +UC_AVR_REG_Yhi = 30 +UC_AVR_REG_Ylo = 29 +UC_AVR_REG_Zhi = 32 +UC_AVR_REG_Zlo = 31 +UC_AVR_REG_X = 91 +UC_AVR_REG_Y = 93 +UC_AVR_REG_Z = 95 diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 46c53ddc14..249f8fed6b 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -21,7 +21,8 @@ UC_ARCH_RISCV = 8 UC_ARCH_S390X = 9 UC_ARCH_TRICORE = 10 -UC_ARCH_MAX = 11 +UC_ARCH_AVR = 11 +UC_ARCH_MAX = 12 UC_MODE_LITTLE_ENDIAN = 0 UC_MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb new file mode 100644 index 0000000000..126ebd0c8f --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb @@ -0,0 +1,150 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [avr_const.rb] + +module UnicornEngine + +# AVR architectures + UC_AVR_ARCH_AVR1 = 10 + UC_AVR_ARCH_AVR2 = 20 + UC_AVR_ARCH_AVR25 = 25 + UC_AVR_ARCH_AVR3 = 30 + UC_AVR_ARCH_AVR4 = 40 + UC_AVR_ARCH_AVR5 = 50 + UC_AVR_ARCH_AVR51 = 51 + UC_AVR_ARCH_AVR6 = 60 + UC_CPU_AVR_ARCH = 1000 + +# AVR CPU + UC_CPU_AVR_ATMEGA16 = 50016 + UC_CPU_AVR_ATMEGA32 = 50032 + UC_CPU_AVR_ATMEGA64 = 50064 + UC_CPU_AVR_ATMEGA128 = 51128 + UC_CPU_AVR_ATMEGA128RFR2 = 51129 + UC_CPU_AVR_ATMEGA1280 = 51130 + UC_CPU_AVR_ATMEGA256 = 60256 + UC_CPU_AVR_ATMEGA256RFR2 = 60257 + UC_CPU_AVR_ATMEGA2560 = 60258 + +# AVR memory + UC_AVR_MEM_FLASH = 134217728 + +# AVR registers + + UC_AVR_REG_INVALID = 0 + UC_AVR_REG_R0 = 1 + UC_AVR_REG_R1 = 2 + UC_AVR_REG_R2 = 3 + UC_AVR_REG_R3 = 4 + UC_AVR_REG_R4 = 5 + UC_AVR_REG_R5 = 6 + UC_AVR_REG_R6 = 7 + UC_AVR_REG_R7 = 8 + UC_AVR_REG_R8 = 9 + UC_AVR_REG_R9 = 10 + UC_AVR_REG_R10 = 11 + UC_AVR_REG_R11 = 12 + UC_AVR_REG_R12 = 13 + UC_AVR_REG_R13 = 14 + UC_AVR_REG_R14 = 15 + UC_AVR_REG_R15 = 16 + UC_AVR_REG_R16 = 17 + UC_AVR_REG_R17 = 18 + UC_AVR_REG_R18 = 19 + UC_AVR_REG_R19 = 20 + UC_AVR_REG_R20 = 21 + UC_AVR_REG_R21 = 22 + UC_AVR_REG_R22 = 23 + UC_AVR_REG_R23 = 24 + UC_AVR_REG_R24 = 25 + UC_AVR_REG_R25 = 26 + UC_AVR_REG_R26 = 27 + UC_AVR_REG_R27 = 28 + UC_AVR_REG_R28 = 29 + UC_AVR_REG_R29 = 30 + UC_AVR_REG_R30 = 31 + UC_AVR_REG_R31 = 32 + UC_AVR_REG_PC = 33 + UC_AVR_REG_SP = 34 + UC_AVR_REG_RAMPD = 57 + UC_AVR_REG_RAMPX = 58 + UC_AVR_REG_RAMPY = 59 + UC_AVR_REG_RAMPZ = 60 + UC_AVR_REG_EIND = 61 + UC_AVR_REG_SPL = 62 + UC_AVR_REG_SPH = 63 + UC_AVR_REG_SREG = 64 + +# 16-bit coalesced registers + UC_AVR_REG_R0W = 65 + UC_AVR_REG_R1W = 66 + UC_AVR_REG_R2W = 67 + UC_AVR_REG_R3W = 68 + UC_AVR_REG_R4W = 69 + UC_AVR_REG_R5W = 70 + UC_AVR_REG_R6W = 71 + UC_AVR_REG_R7W = 72 + UC_AVR_REG_R8W = 73 + UC_AVR_REG_R9W = 74 + UC_AVR_REG_R10W = 75 + UC_AVR_REG_R11W = 76 + UC_AVR_REG_R12W = 77 + UC_AVR_REG_R13W = 78 + UC_AVR_REG_R14W = 79 + UC_AVR_REG_R15W = 80 + UC_AVR_REG_R16W = 81 + UC_AVR_REG_R17W = 82 + UC_AVR_REG_R18W = 83 + UC_AVR_REG_R19W = 84 + UC_AVR_REG_R20W = 85 + UC_AVR_REG_R21W = 86 + UC_AVR_REG_R22W = 87 + UC_AVR_REG_R23W = 88 + UC_AVR_REG_R24W = 89 + UC_AVR_REG_R25W = 90 + UC_AVR_REG_R26W = 91 + UC_AVR_REG_R27W = 92 + UC_AVR_REG_R28W = 93 + UC_AVR_REG_R29W = 94 + UC_AVR_REG_R30W = 95 + +# 32-bit coalesced registers + UC_AVR_REG_R0D = 97 + UC_AVR_REG_R1D = 98 + UC_AVR_REG_R2D = 99 + UC_AVR_REG_R3D = 100 + UC_AVR_REG_R4D = 101 + UC_AVR_REG_R5D = 102 + UC_AVR_REG_R6D = 103 + UC_AVR_REG_R7D = 104 + UC_AVR_REG_R8D = 105 + UC_AVR_REG_R9D = 106 + UC_AVR_REG_R10D = 107 + UC_AVR_REG_R11D = 108 + UC_AVR_REG_R12D = 109 + UC_AVR_REG_R13D = 110 + UC_AVR_REG_R14D = 111 + UC_AVR_REG_R15D = 112 + UC_AVR_REG_R16D = 113 + UC_AVR_REG_R17D = 114 + UC_AVR_REG_R18D = 115 + UC_AVR_REG_R19D = 116 + UC_AVR_REG_R20D = 117 + UC_AVR_REG_R21D = 118 + UC_AVR_REG_R22D = 119 + UC_AVR_REG_R23D = 120 + UC_AVR_REG_R24D = 121 + UC_AVR_REG_R25D = 122 + UC_AVR_REG_R26D = 123 + UC_AVR_REG_R27D = 124 + UC_AVR_REG_R28D = 125 + +# Alias registers + UC_AVR_REG_Xhi = 28 + UC_AVR_REG_Xlo = 27 + UC_AVR_REG_Yhi = 30 + UC_AVR_REG_Ylo = 29 + UC_AVR_REG_Zhi = 32 + UC_AVR_REG_Zlo = 31 + UC_AVR_REG_X = 91 + UC_AVR_REG_Y = 93 + UC_AVR_REG_Z = 95 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb index 8c004ed0e8..f8c5132f7e 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb @@ -23,7 +23,8 @@ module UnicornEngine UC_ARCH_RISCV = 8 UC_ARCH_S390X = 9 UC_ARCH_TRICORE = 10 - UC_ARCH_MAX = 11 + UC_ARCH_AVR = 11 + UC_ARCH_MAX = 12 UC_MODE_LITTLE_ENDIAN = 0 UC_MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/zig/unicorn/AVR_const.zig b/bindings/zig/unicorn/AVR_const.zig new file mode 100644 index 0000000000..e408f18e01 --- /dev/null +++ b/bindings/zig/unicorn/AVR_const.zig @@ -0,0 +1,151 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +pub const AVRConst = enum(c_int) { + +// AVR architectures + AVR_ARCH_AVR1 = 10, + AVR_ARCH_AVR2 = 20, + AVR_ARCH_AVR25 = 25, + AVR_ARCH_AVR3 = 30, + AVR_ARCH_AVR4 = 40, + AVR_ARCH_AVR5 = 50, + AVR_ARCH_AVR51 = 51, + AVR_ARCH_AVR6 = 60, + CPU_AVR_ARCH = 1000, + +// AVR CPU + CPU_AVR_ATMEGA16 = 50016, + CPU_AVR_ATMEGA32 = 50032, + CPU_AVR_ATMEGA64 = 50064, + CPU_AVR_ATMEGA128 = 51128, + CPU_AVR_ATMEGA128RFR2 = 51129, + CPU_AVR_ATMEGA1280 = 51130, + CPU_AVR_ATMEGA256 = 60256, + CPU_AVR_ATMEGA256RFR2 = 60257, + CPU_AVR_ATMEGA2560 = 60258, + +// AVR memory + AVR_MEM_FLASH = 134217728, + +// AVR registers + + AVR_REG_INVALID = 0, + AVR_REG_R0 = 1, + AVR_REG_R1 = 2, + AVR_REG_R2 = 3, + AVR_REG_R3 = 4, + AVR_REG_R4 = 5, + AVR_REG_R5 = 6, + AVR_REG_R6 = 7, + AVR_REG_R7 = 8, + AVR_REG_R8 = 9, + AVR_REG_R9 = 10, + AVR_REG_R10 = 11, + AVR_REG_R11 = 12, + AVR_REG_R12 = 13, + AVR_REG_R13 = 14, + AVR_REG_R14 = 15, + AVR_REG_R15 = 16, + AVR_REG_R16 = 17, + AVR_REG_R17 = 18, + AVR_REG_R18 = 19, + AVR_REG_R19 = 20, + AVR_REG_R20 = 21, + AVR_REG_R21 = 22, + AVR_REG_R22 = 23, + AVR_REG_R23 = 24, + AVR_REG_R24 = 25, + AVR_REG_R25 = 26, + AVR_REG_R26 = 27, + AVR_REG_R27 = 28, + AVR_REG_R28 = 29, + AVR_REG_R29 = 30, + AVR_REG_R30 = 31, + AVR_REG_R31 = 32, + AVR_REG_PC = 33, + AVR_REG_SP = 34, + AVR_REG_RAMPD = 57, + AVR_REG_RAMPX = 58, + AVR_REG_RAMPY = 59, + AVR_REG_RAMPZ = 60, + AVR_REG_EIND = 61, + AVR_REG_SPL = 62, + AVR_REG_SPH = 63, + AVR_REG_SREG = 64, + +// 16-bit coalesced registers + AVR_REG_R0W = 65, + AVR_REG_R1W = 66, + AVR_REG_R2W = 67, + AVR_REG_R3W = 68, + AVR_REG_R4W = 69, + AVR_REG_R5W = 70, + AVR_REG_R6W = 71, + AVR_REG_R7W = 72, + AVR_REG_R8W = 73, + AVR_REG_R9W = 74, + AVR_REG_R10W = 75, + AVR_REG_R11W = 76, + AVR_REG_R12W = 77, + AVR_REG_R13W = 78, + AVR_REG_R14W = 79, + AVR_REG_R15W = 80, + AVR_REG_R16W = 81, + AVR_REG_R17W = 82, + AVR_REG_R18W = 83, + AVR_REG_R19W = 84, + AVR_REG_R20W = 85, + AVR_REG_R21W = 86, + AVR_REG_R22W = 87, + AVR_REG_R23W = 88, + AVR_REG_R24W = 89, + AVR_REG_R25W = 90, + AVR_REG_R26W = 91, + AVR_REG_R27W = 92, + AVR_REG_R28W = 93, + AVR_REG_R29W = 94, + AVR_REG_R30W = 95, + +// 32-bit coalesced registers + AVR_REG_R0D = 97, + AVR_REG_R1D = 98, + AVR_REG_R2D = 99, + AVR_REG_R3D = 100, + AVR_REG_R4D = 101, + AVR_REG_R5D = 102, + AVR_REG_R6D = 103, + AVR_REG_R7D = 104, + AVR_REG_R8D = 105, + AVR_REG_R9D = 106, + AVR_REG_R10D = 107, + AVR_REG_R11D = 108, + AVR_REG_R12D = 109, + AVR_REG_R13D = 110, + AVR_REG_R14D = 111, + AVR_REG_R15D = 112, + AVR_REG_R16D = 113, + AVR_REG_R17D = 114, + AVR_REG_R18D = 115, + AVR_REG_R19D = 116, + AVR_REG_R20D = 117, + AVR_REG_R21D = 118, + AVR_REG_R22D = 119, + AVR_REG_R23D = 120, + AVR_REG_R24D = 121, + AVR_REG_R25D = 122, + AVR_REG_R26D = 123, + AVR_REG_R27D = 124, + AVR_REG_R28D = 125, + +// Alias registers + AVR_REG_Xhi = 28, + AVR_REG_Xlo = 27, + AVR_REG_Yhi = 30, + AVR_REG_Ylo = 29, + AVR_REG_Zhi = 32, + AVR_REG_Zlo = 31, + AVR_REG_X = 91, + AVR_REG_Y = 93, + AVR_REG_Z = 95, + +}; diff --git a/bindings/zig/unicorn/unicorn_const.zig b/bindings/zig/unicorn/unicorn_const.zig index aaf1169f58..e0511746ea 100644 --- a/bindings/zig/unicorn/unicorn_const.zig +++ b/bindings/zig/unicorn/unicorn_const.zig @@ -23,7 +23,8 @@ pub const unicornConst = enum(c_int) { ARCH_RISCV = 8, ARCH_S390X = 9, ARCH_TRICORE = 10, - ARCH_MAX = 11, + ARCH_AVR = 11, + ARCH_MAX = 12, MODE_LITTLE_ENDIAN = 0, MODE_BIG_ENDIAN = 1073741824, From a1984d308908074c5c507092dafe688209c1948d Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 2 Oct 2024 17:10:06 +0200 Subject: [PATCH 20/31] build: update build systems for AVR support. Signed-off-by: Glenn Baker --- Cargo.toml | 3 ++- build.zig | 1 + msvc/avr-softmmu/config-target.h | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 msvc/avr-softmmu/config-target.h diff --git a/Cargo.toml b/Cargo.toml index 862b11dbe7..3e98fbe024 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ pkg-config = { version = "0.3" } [features] default = ["arch_all"] dynamic_linkage = [] -arch_all = ["arch_x86", "arch_arm", "arch_aarch64", "arch_riscv", "arch_mips", "arch_sparc", "arch_m68k", "arch_ppc", "arch_s390x", "arch_tricore"] +arch_all = ["arch_x86", "arch_arm", "arch_aarch64", "arch_riscv", "arch_mips", "arch_sparc", "arch_m68k", "arch_ppc", "arch_s390x", "arch_tricore", "arch_avr"] arch_x86 = [] arch_arm = [] arch_aarch64 = [] @@ -53,3 +53,4 @@ arch_m68k = [] arch_ppc = [] arch_s390x = [] arch_tricore = [] +arch_avr = [] diff --git a/build.zig b/build.zig index e1eae62470..ca5f905bfb 100644 --- a/build.zig +++ b/build.zig @@ -74,6 +74,7 @@ pub fn build(b: *std.Build) void { .{ .file_type = .zig, .root_file_path = "bindings/zig/sample/sample_riscv_zig.zig" }, .{ .file_type = .c, .root_file_path = "samples/sample_arm.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_arm64.c" }, + .{ .file_type = .c, .root_file_path = "samples/sample_avr.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_ctl.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_batch_reg.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_m68k.c" }, diff --git a/msvc/avr-softmmu/config-target.h b/msvc/avr-softmmu/config-target.h new file mode 100644 index 0000000000..3afeec6c7a --- /dev/null +++ b/msvc/avr-softmmu/config-target.h @@ -0,0 +1,5 @@ +/* Automatically generated by create_config - do not modify */ +#define TARGET_AVR 1 +#define TARGET_NAME "avr" +#define TARGET_AVR 1 +#define CONFIG_SOFTMMU 1 From 2f9061bb0a00a608e0fe46f585931cf5c8491faa Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 2 Oct 2024 14:56:13 +0200 Subject: [PATCH 21/31] AVR: drop built-in disassembler tools. Signed-off-by: Glenn Baker --- qemu/target/avr/cpu.c | 1 - qemu/target/avr/cpu.h | 2 - qemu/target/avr/disas.c | 245 ---------------------------------------- 3 files changed, 248 deletions(-) delete mode 100644 qemu/target/avr/disas.c diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c index 461d304a78..f01cb313af 100644 --- a/qemu/target/avr/cpu.c +++ b/qemu/target/avr/cpu.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "exec/exec-all.h" #include "cpu.h" -#include "disas/dis-asm.h" #include "unicorn_helper.h" static void avr_cpu_set_pc(CPUState *cs, vaddr value) diff --git a/qemu/target/avr/cpu.h b/qemu/target/avr/cpu.h index 42344756aa..f7781c7ffe 100644 --- a/qemu/target/avr/cpu.h +++ b/qemu/target/avr/cpu.h @@ -23,7 +23,6 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" -#include "disas/dis-asm.h" #ifdef CONFIG_USER_ONLY #error "AVR 8-bit does not support user mode" @@ -175,7 +174,6 @@ bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -int avr_print_insn(bfd_vma addr, disassemble_info *info); static inline int avr_feature(CPUAVRState *env, AVRFeature feature) { diff --git a/qemu/target/avr/disas.c b/qemu/target/avr/disas.c deleted file mode 100644 index b7689e8d7c..0000000000 --- a/qemu/target/avr/disas.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * AVR disassembler - * - * Copyright (c) 2019-2020 Richard Henderson - * Copyright (c) 2019-2020 Michael Rolnik - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "qemu/osdep.h" -#include "cpu.h" - -typedef struct { - disassemble_info *info; - uint16_t next_word; - bool next_word_used; -} DisasContext; - -static int to_regs_16_31_by_one(DisasContext *ctx, int indx) -{ - return 16 + (indx % 16); -} - -static int to_regs_16_23_by_one(DisasContext *ctx, int indx) -{ - return 16 + (indx % 8); -} - -static int to_regs_24_30_by_two(DisasContext *ctx, int indx) -{ - return 24 + (indx % 4) * 2; -} - -static int to_regs_00_30_by_two(DisasContext *ctx, int indx) -{ - return (indx % 16) * 2; -} - -static uint16_t next_word(DisasContext *ctx) -{ - ctx->next_word_used = true; - return ctx->next_word; -} - -static int append_16(DisasContext *ctx, int x) -{ - return x << 16 | next_word(ctx); -} - -/* Include the auto-generated decoder. */ -static bool decode_insn(DisasContext *ctx, uint16_t insn); -#include "decode-insn.c.inc" - -#define output(mnemonic, format, ...) \ - (pctx->info->fprintf_func(pctx->info->stream, "%-9s " format, \ - mnemonic, ##__VA_ARGS__)) - -int avr_print_insn(bfd_vma addr, disassemble_info *info) -{ - DisasContext ctx; - DisasContext *pctx = &ctx; - bfd_byte buffer[4]; - uint16_t insn; - int status; - - ctx.info = info; - - status = info->read_memory_func(addr, buffer, 4, info); - if (status != 0) { - info->memory_error_func(status, addr, info); - return -1; - } - insn = bfd_getl16(buffer); - ctx.next_word = bfd_getl16(buffer + 2); - ctx.next_word_used = false; - - if (!decode_insn(&ctx, insn)) { - output(".db", "0x%02x, 0x%02x", buffer[0], buffer[1]); - } - - return ctx.next_word_used ? 4 : 2; -} - - -#define INSN(opcode, format, ...) \ -static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ -{ \ - output(#opcode, format, ##__VA_ARGS__); \ - return true; \ -} - -#define INSN_MNEMONIC(opcode, mnemonic, format, ...) \ -static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ -{ \ - output(mnemonic, format, ##__VA_ARGS__); \ - return true; \ -} - -/* - * C Z N V S H T I - * 0 1 2 3 4 5 6 7 - */ -static const char brbc[][5] = { - "BRCC", "BRNE", "BRPL", "BRVC", "BRGE", "BRHC", "BRTC", "BRID" -}; - -static const char brbs[][5] = { - "BRCS", "BREQ", "BRMI", "BRVS", "BRLT", "BRHS", "BRTS", "BRIE" -}; - -static const char bset[][4] = { - "SEC", "SEZ", "SEN", "SEZ", "SES", "SEH", "SET", "SEI" -}; - -static const char bclr[][4] = { - "CLC", "CLZ", "CLN", "CLZ", "CLS", "CLH", "CLT", "CLI" -}; - -/* - * Arithmetic Instructions - */ -INSN(ADD, "r%d, r%d", a->rd, a->rr) -INSN(ADC, "r%d, r%d", a->rd, a->rr) -INSN(ADIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) -INSN(SUB, "r%d, r%d", a->rd, a->rr) -INSN(SUBI, "r%d, %d", a->rd, a->imm) -INSN(SBC, "r%d, r%d", a->rd, a->rr) -INSN(SBCI, "r%d, %d", a->rd, a->imm) -INSN(SBIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) -INSN(AND, "r%d, r%d", a->rd, a->rr) -INSN(ANDI, "r%d, %d", a->rd, a->imm) -INSN(OR, "r%d, r%d", a->rd, a->rr) -INSN(ORI, "r%d, %d", a->rd, a->imm) -INSN(EOR, "r%d, r%d", a->rd, a->rr) -INSN(COM, "r%d", a->rd) -INSN(NEG, "r%d", a->rd) -INSN(INC, "r%d", a->rd) -INSN(DEC, "r%d", a->rd) -INSN(MUL, "r%d, r%d", a->rd, a->rr) -INSN(MULS, "r%d, r%d", a->rd, a->rr) -INSN(MULSU, "r%d, r%d", a->rd, a->rr) -INSN(FMUL, "r%d, r%d", a->rd, a->rr) -INSN(FMULS, "r%d, r%d", a->rd, a->rr) -INSN(FMULSU, "r%d, r%d", a->rd, a->rr) -INSN(DES, "%d", a->imm) - -/* - * Branch Instructions - */ -INSN(RJMP, ".%+d", a->imm * 2) -INSN(IJMP, "") -INSN(EIJMP, "") -INSN(JMP, "0x%x", a->imm * 2) -INSN(RCALL, ".%+d", a->imm * 2) -INSN(ICALL, "") -INSN(EICALL, "") -INSN(CALL, "0x%x", a->imm * 2) -INSN(RET, "") -INSN(RETI, "") -INSN(CPSE, "r%d, r%d", a->rd, a->rr) -INSN(CP, "r%d, r%d", a->rd, a->rr) -INSN(CPC, "r%d, r%d", a->rd, a->rr) -INSN(CPI, "r%d, %d", a->rd, a->imm) -INSN(SBRC, "r%d, %d", a->rr, a->bit) -INSN(SBRS, "r%d, %d", a->rr, a->bit) -INSN(SBIC, "$%d, %d", a->reg, a->bit) -INSN(SBIS, "$%d, %d", a->reg, a->bit) -INSN_MNEMONIC(BRBS, brbs[a->bit], ".%+d", a->imm * 2) -INSN_MNEMONIC(BRBC, brbc[a->bit], ".%+d", a->imm * 2) - -/* - * Data Transfer Instructions - */ -INSN(MOV, "r%d, r%d", a->rd, a->rr) -INSN(MOVW, "r%d:r%d, r%d:r%d", a->rd + 1, a->rd, a->rr + 1, a->rr) -INSN(LDI, "r%d, %d", a->rd, a->imm) -INSN(LDS, "r%d, %d", a->rd, a->imm) -INSN(LDX1, "r%d, X", a->rd) -INSN(LDX2, "r%d, X+", a->rd) -INSN(LDX3, "r%d, -X", a->rd) -INSN(LDY2, "r%d, Y+", a->rd) -INSN(LDY3, "r%d, -Y", a->rd) -INSN(LDZ2, "r%d, Z+", a->rd) -INSN(LDZ3, "r%d, -Z", a->rd) -INSN(LDDY, "r%d, Y+%d", a->rd, a->imm) -INSN(LDDZ, "r%d, Z+%d", a->rd, a->imm) -INSN(STS, "%d, r%d", a->imm, a->rd) -INSN(STX1, "X, r%d", a->rr) -INSN(STX2, "X+, r%d", a->rr) -INSN(STX3, "-X, r%d", a->rr) -INSN(STY2, "Y+, r%d", a->rd) -INSN(STY3, "-Y, r%d", a->rd) -INSN(STZ2, "Z+, r%d", a->rd) -INSN(STZ3, "-Z, r%d", a->rd) -INSN(STDY, "Y+%d, r%d", a->imm, a->rd) -INSN(STDZ, "Z+%d, r%d", a->imm, a->rd) -INSN(LPM1, "") -INSN(LPM2, "r%d, Z", a->rd) -INSN(LPMX, "r%d, Z+", a->rd) -INSN(ELPM1, "") -INSN(ELPM2, "r%d, Z", a->rd) -INSN(ELPMX, "r%d, Z+", a->rd) -INSN(SPM, "") -INSN(SPMX, "Z+") -INSN(IN, "r%d, $%d", a->rd, a->imm) -INSN(OUT, "$%d, r%d", a->imm, a->rd) -INSN(PUSH, "r%d", a->rd) -INSN(POP, "r%d", a->rd) -INSN(XCH, "Z, r%d", a->rd) -INSN(LAC, "Z, r%d", a->rd) -INSN(LAS, "Z, r%d", a->rd) -INSN(LAT, "Z, r%d", a->rd) - -/* - * Bit and Bit-test Instructions - */ -INSN(LSR, "r%d", a->rd) -INSN(ROR, "r%d", a->rd) -INSN(ASR, "r%d", a->rd) -INSN(SWAP, "r%d", a->rd) -INSN(SBI, "$%d, %d", a->reg, a->bit) -INSN(CBI, "%d, %d", a->reg, a->bit) -INSN(BST, "r%d, %d", a->rd, a->bit) -INSN(BLD, "r%d, %d", a->rd, a->bit) -INSN_MNEMONIC(BSET, bset[a->bit], "") -INSN_MNEMONIC(BCLR, bclr[a->bit], "") - -/* - * MCU Control Instructions - */ -INSN(BREAK, "") -INSN(NOP, "") -INSN(SLEEP, "") -INSN(WDR, "") From 89024938fec851119dd5079f523d657e603285b9 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 2 Oct 2024 14:55:27 +0200 Subject: [PATCH 22/31] AVR: update for new v2.1.x APIs. Signed-off-by: Glenn Baker --- qemu/avr.h | 4 ++ qemu/target/avr/cpu.c | 1 + qemu/target/avr/unicorn.c | 118 +++++++++++++++----------------------- qemu/target/avr/unicorn.h | 17 ++---- uc.c | 6 +- 5 files changed, 59 insertions(+), 87 deletions(-) diff --git a/qemu/avr.h b/qemu/avr.h index a3748edd2f..55ad340599 100644 --- a/qemu/avr.h +++ b/qemu/avr.h @@ -1288,4 +1288,8 @@ #define helper_wdr helper_wdr_avr #define gen_intermediate_code gen_intermediate_code_avr #define restore_state_to_opc restore_state_to_opc_avr + +#define reg_read reg_read_avr +#define reg_write reg_write_avr +#define uc_init uc_init_avr #endif diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c index f01cb313af..2938516352 100644 --- a/qemu/target/avr/cpu.c +++ b/qemu/target/avr/cpu.c @@ -367,6 +367,7 @@ static const AVRCPUInfo *avr_cpu_info_get(int cpu_model) return NULL; } +DEFAULT_VISIBILITY int avr_cpu_model_valid(int cpu_model) { return avr_cpu_info_get(cpu_model) != NULL; diff --git a/qemu/target/avr/unicorn.c b/qemu/target/avr/unicorn.c index 260456f085..75dd9c2460 100644 --- a/qemu/target/avr/unicorn.c +++ b/qemu/target/avr/unicorn.c @@ -36,7 +36,7 @@ static void avr_set_pc(struct uc_struct *uc, uint64_t address) set_pc((CPUAVRState *)uc->cpu->env_ptr, address); } -void avr_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { } @@ -45,126 +45,130 @@ void avr_reg_reset(struct uc_struct *uc) #define GET_RAMP(reg) GET_BYTE(env->glue(ramp,reg), 2) #define SET_RAMP(reg, val) SET_BYTE(env->glue(ramp,reg), 2, val) -static void reg_read(CPUAVRState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUAVRState *const env = _env; + uc_err ret = UC_ERR_ARG; + switch (regid) { case UC_AVR_REG_PC: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = get_pc(env); break; case UC_AVR_REG_SP: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->sp; break; case UC_AVR_REG_RAMPD: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_RAMP(D); break; case UC_AVR_REG_RAMPX: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_RAMP(X); break; case UC_AVR_REG_RAMPY: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_RAMP(Y); break; case UC_AVR_REG_RAMPZ: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_RAMP(Z); break; case UC_AVR_REG_EIND: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_BYTE(env->eind, 2); break; case UC_AVR_REG_SPL: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_BYTE(env->sp, 0); break; case UC_AVR_REG_SPH: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = GET_BYTE(env->sp, 1); break; case UC_AVR_REG_SREG: + CHECK_REG_TYPE(uint8_t); *(uint8_t *)value = cpu_get_sreg(env); break; default: { uint64_t v = 0; if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { + CHECK_REG_TYPE(uint8_t); *(int8_t *)value = (int8_t)env->r[regid - UC_AVR_REG_R0]; } else if (regid >= UC_AVR_REG_R0W && regid <= UC_AVR_REG_R30W) { const uint32_t *const r = &env->r[regid - UC_AVR_REG_R0W]; for (int k = 0; k < 2; k++) SET_BYTE(v, k, (r[k] & 0xff)); + CHECK_REG_TYPE(uint16_t); *(int16_t *)value = (int16_t)v; } else if (regid >= UC_AVR_REG_R0D && regid <= UC_AVR_REG_R28D) { const uint32_t *const r = &env->r[regid - UC_AVR_REG_R0D]; for (int k = 0; k < 4; k++) SET_BYTE(v, k, (r[k] & 0xff)); + CHECK_REG_TYPE(uint32_t); *(int32_t *)value = (int32_t)v; } break; } } + return ret; } -int avr_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - CPUAVRState *env = &(AVR_CPU(uc->cpu)->env); - int i; + CPUAVRState *const env = _env; + uc_err ret = UC_ERR_ARG; - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int avr_context_reg_read(struct uc_context *uc, unsigned int *regs, - void **vals, int count) -{ - CPUAVRState *env = (CPUAVRState *)uc->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -static void reg_write(CPUAVRState *env, unsigned int regid, - const void *value) -{ switch (regid) { case UC_AVR_REG_PC: + CHECK_REG_TYPE(uint32_t); set_pc(env, *(uint32_t *)value); + *setpc = 1; break; case UC_AVR_REG_SP: + CHECK_REG_TYPE(uint32_t); env->sp = *(uint32_t *)value; break; case UC_AVR_REG_RAMPD: + CHECK_REG_TYPE(uint8_t); SET_RAMP(D, *(uint8_t *)value); break; case UC_AVR_REG_RAMPX: + CHECK_REG_TYPE(uint8_t); SET_RAMP(X, *(uint8_t *)value); break; case UC_AVR_REG_RAMPY: + CHECK_REG_TYPE(uint8_t); SET_RAMP(Y, *(uint8_t *)value); break; case UC_AVR_REG_RAMPZ: + CHECK_REG_TYPE(uint8_t); SET_RAMP(Z, *(uint8_t *)value); break; case UC_AVR_REG_EIND: + CHECK_REG_TYPE(uint8_t); SET_BYTE(env->eind, 2, *(uint8_t *)value); break; case UC_AVR_REG_SPL: + CHECK_REG_TYPE(uint8_t); SET_BYTE(env->sp, 0, *(uint8_t *)value); break; case UC_AVR_REG_SPH: + CHECK_REG_TYPE(uint8_t); SET_BYTE(env->sp, 1, *(uint8_t *)value); break; case UC_AVR_REG_SREG: + CHECK_REG_TYPE(uint8_t); cpu_set_sreg(env, *(uint8_t *)value); break; @@ -176,16 +180,19 @@ static void reg_write(CPUAVRState *env, unsigned int regid, v = *(uint8_t *)value; r = &env->r[regid - UC_AVR_REG_R0]; rlen = 1; + CHECK_REG_TYPE(uint8_t); } else if (regid >= UC_AVR_REG_R0W && regid <= UC_AVR_REG_R30W) { v = *(uint16_t *)value; r = &env->r[regid - UC_AVR_REG_R0W]; rlen = 2; + CHECK_REG_TYPE(uint16_t); } else if (regid >= UC_AVR_REG_R0D && regid <= UC_AVR_REG_R28D) { v = *(uint32_t *)value; r = &env->r[regid - UC_AVR_REG_R0D]; rlen = 4; + CHECK_REG_TYPE(uint32_t); } if (r && rlen > 0) { for (int k = 0; k < rlen; k++) @@ -193,41 +200,7 @@ static void reg_write(CPUAVRState *env, unsigned int regid, } } } -} - -int avr_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count) -{ - CPUAVRState *env = &(AVR_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_AVR_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - } - } - - return 0; -} - -int avr_context_reg_write(struct uc_context *uc, unsigned int *regs, - void *const *vals, int count) -{ - CPUAVRState *env = (CPUAVRState *)uc->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int avr_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -286,11 +259,12 @@ static MemoryRegion *avr_memory_map_ptr(struct uc_struct *uc, hwaddr begin, size return mr; } -void avr_uc_init(struct uc_struct *uc) +DEFAULT_VISIBILITY +void uc_init(struct uc_struct *uc) { - uc->reg_read = avr_reg_read; - uc->reg_write = avr_reg_write; - uc->reg_reset = avr_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = avr_set_pc; uc->get_pc = avr_get_pc; uc->cpus_init = avr_cpus_init; diff --git a/qemu/target/avr/unicorn.h b/qemu/target/avr/unicorn.h index 40cbd3b52e..a90b109016 100644 --- a/qemu/target/avr/unicorn.h +++ b/qemu/target/avr/unicorn.h @@ -9,19 +9,12 @@ #define UC_QEMU_TARGET_AVR_H // functions to read & write registers -int avr_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int avr_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count); +uc_err reg_read_avr(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_avr(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -int avr_context_reg_read(struct uc_context *uc, unsigned int *regs, - void **vals, int count); -int avr_context_reg_write(struct uc_context *uc, unsigned int *regs, - void *const *vals, int count); - -void avr_reg_reset(struct uc_struct *uc); - -void avr_uc_init(struct uc_struct *uc); +void uc_init_avr(struct uc_struct *uc); int avr_cpu_model_valid(int cpu_model); diff --git a/uc.c b/uc.c index c2548d060c..67303fa6b9 100644 --- a/uc.c +++ b/uc.c @@ -486,7 +486,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = avr_uc_init; + uc->init_arch = uc_init_avr; break; #endif } @@ -2311,8 +2311,8 @@ static context_reg_rw_t find_context_reg_rw(uc_arch arch, uc_mode mode) #endif #ifdef UNICORN_HAS_AVR case UC_ARCH_AVR: - rw->context_reg_read = avr_context_reg_read; - rw->context_reg_write = avr_context_reg_write; + rw.read = reg_read_avr; + rw.write = reg_write_avr; break; #endif } From b1cdf8547efd6e62692275a911d20285cdd4a7d7 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 2 Oct 2024 16:04:13 +0200 Subject: [PATCH 23/31] AVR: fix cpu_reset() prototype. Signed-off-by: Glenn Baker --- qemu/target/avr/cpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c index 2938516352..d361487153 100644 --- a/qemu/target/avr/cpu.c +++ b/qemu/target/avr/cpu.c @@ -47,15 +47,14 @@ static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) env->pc_w = tb->pc / 2; /* internally PC points to words */ } -static void avr_cpu_reset(DeviceState *ds) +static void avr_cpu_reset(CPUState *cs) { - CPUState *cs = CPU(ds); AVRCPU *cpu = AVR_CPU(cs); AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); CPUAVRState *env = &cpu->env; if (mcc->parent_reset) - mcc->parent_reset(ds); + mcc->parent_reset(cs); env->pc_w = 0; env->sregI = 1; From 5b5d1f8f743e2d3ff2e313f3ec89de4639251b67 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 2 Oct 2024 16:07:57 +0200 Subject: [PATCH 24/31] AVR: drop unused error_report() function override. Signed-off-by: Glenn Baker --- qemu/target/avr/unicorn_helper.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qemu/target/avr/unicorn_helper.h b/qemu/target/avr/unicorn_helper.h index 9419ea47e4..117b375f19 100644 --- a/qemu/target/avr/unicorn_helper.h +++ b/qemu/target/avr/unicorn_helper.h @@ -20,9 +20,11 @@ INIT_CPU_ENV_FROM_TCG_CONTEXT(tcg_ctx) /* "qapi/error.h */ +#if 0 #include #define error_report(...) \ (error)(EXIT_FAILURE, 0, __VA_ARGS__) +#endif /* "exec/address-spaces.h" */ #define address_space_memory \ From 5eefbee35dcbef9b42e9a5e94853b9b9be0dcfd4 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Wed, 2 Oct 2024 21:06:12 +0200 Subject: [PATCH 25/31] AVR: fix compilation on non-Linux platforms. Signed-off-by: Glenn Baker --- qemu/target/avr/decode-insn.c.inc | 1 + qemu/target/avr/helper.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu/target/avr/decode-insn.c.inc b/qemu/target/avr/decode-insn.c.inc index 90e910e6d1..0e96565474 100644 --- a/qemu/target/avr/decode-insn.c.inc +++ b/qemu/target/avr/decode-insn.c.inc @@ -23,6 +23,7 @@ typedef struct { } arg_decode_insn5; typedef struct { + int noarg_; } arg_decode_insn6; typedef struct { diff --git a/qemu/target/avr/helper.c b/qemu/target/avr/helper.c index e2dbc672fe..60d0a648eb 100644 --- a/qemu/target/avr/helper.c +++ b/qemu/target/avr/helper.c @@ -105,7 +105,7 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, bool probe, uintptr_t retaddr) { int prot = 0; - MemTxAttrs attrs = {}; + MemTxAttrs attrs = {0}; uint32_t paddr; address &= TARGET_PAGE_MASK; From ae2e302834f2a6822ee3d2644d9403d483a9708b Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 8 Oct 2024 10:53:45 +0200 Subject: [PATCH 26/31] AVR: move declarations at the begining of the function. Signed-off-by: Glenn Baker --- samples/sample_avr.c | 10 ++++++---- tests/unit/test_avr.c | 27 ++++++++++++++++----------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/samples/sample_avr.c b/samples/sample_avr.c index c20df62599..9ef461c8fe 100644 --- a/samples/sample_avr.c +++ b/samples/sample_avr.c @@ -52,6 +52,11 @@ static bool test_avr(void) uc_hook trace1, trace2; bool success = false; + uint8_t regs[32]; + int reg_ids[32]; + void *reg_vals[32]; + int i; + printf("Emulate AVR code\n"); do { // Initialize emulator in AVR mode @@ -81,14 +86,11 @@ static bool test_avr(void) break; // Initialize registers - uint8_t regs[32]; memset(regs, 0, sizeof(regs)); regs[25] = 0; regs[24] = 1; regs[23] = 0; regs[22] = 2; - int reg_ids[32]; - void *reg_vals[32]; - for (unsigned i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) { reg_ids[i] = UC_AVR_REG_R0 + 22 + i; reg_vals[i] = ®s[22 + i]; } diff --git a/tests/unit/test_avr.c b/tests/unit/test_avr.c index 1ffe0509b6..9cf03c1cd1 100644 --- a/tests/unit/test_avr.c +++ b/tests/unit/test_avr.c @@ -117,7 +117,9 @@ static void uc_common_setup(uc_engine **uc, uc_cpu_avr cpu_model, static void test_avr_basic_alu(void) { uc_engine *uc = NULL; + uint8_t r[32] = {0,}; + uint32_t r_pc; uint16_t r_func_arg0 = 1, r_func_arg1 = 2, r_func_ret; r[24] = 1; r[22] = 2; @@ -129,7 +131,6 @@ static void test_avr_basic_alu(void) const uint64_t code_start = ADDR[ADDR_test_func] + 8; OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0)); - uint32_t r_pc; OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24])); @@ -185,6 +186,14 @@ static void test_avr_basic_mem(void) uc_hook eventmem_hook; MEM_HOOK_RESULTS eventmem_trace = {0}; + const uint16_t DATA_BASE = ADDR[ADDR__data__]; + const uint16_t DATA_SIZE = ADDR[ADDR__data__+1] - DATA_BASE; + const uint8_t *const DATA = &FLASH[ADDR[ADDR__data__]]; + uint8_t mem[DATA_SIZE]; + + uint32_t r_pc; + int i; + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); OK(uc_hook_add(uc, &eventmem_hook, UC_HOOK_MEM_VALID, test_avr_basic_mem_cb_eventmem, &eventmem_trace, 1, 0)); @@ -192,21 +201,15 @@ static void test_avr_basic_mem(void) const uint64_t code_start = ADDR[ADDR__init__]; OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0)); - uint32_t r_pc; OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); TEST_CHECK(r_pc == ADDR[ADDR__init__+1]); - const uint16_t DATA_BASE = ADDR[ADDR__data__]; - const uint16_t DATA_SIZE = ADDR[ADDR__data__+1] - DATA_BASE; - const uint8_t *const DATA = &FLASH[ADDR[ADDR__data__]]; - // Check SRAM was correctly initialized with data from Flash program memory - uint8_t mem[DATA_SIZE]; OK(uc_mem_read(uc, MEM_BASE, mem, sizeof(mem))); TEST_CHECK(memcmp(mem, DATA, DATA_SIZE) == 0); TEST_CHECK(eventmem_trace.count == 2*DATA_SIZE); - for (unsigned i = 0; i < DATA_SIZE; i++) { + for (i = 0; i < DATA_SIZE; i++) { const MEM_HOOK_RESULT *const mr = &eventmem_trace.results[2*i]; TEST_CHECK(mr->type == UC_MEM_READ); TEST_CHECK(mr->address == (UC_AVR_MEM_FLASH|(DATA_BASE+i))); @@ -227,16 +230,19 @@ static void test_avr_full_exec(void) { uc_engine *uc = NULL; + uint8_t r[32] = {0,}; + uint32_t r_pc; + uint32_t r_sp; + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); const uint64_t code_start = ADDR[ADDR__init__]; OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0)); - uint32_t r_pc; OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); TEST_CHECK(r_pc == ADDR[ADDR__init__+1]); - uint32_t r_sp = MEM_BASE + MEM_SIZE - 1; + r_sp = MEM_BASE + MEM_SIZE - 1; OK(uc_reg_write(uc, UC_AVR_REG_SP, &r_sp)); const uint64_t exits[] = { @@ -249,7 +255,6 @@ static void test_avr_full_exec(void) const uint64_t code_main = ADDR[ADDR_main]; OK(uc_emu_start(uc, code_main, 0, 0, 0)); - uint8_t r[32] = {0,}; OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24])); TEST_CHECK(r[25] == 0 && r[24] == 0); From 66183ba28353b7c203e80a3c0ceb73210a9ccb4a Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 8 Oct 2024 11:04:34 +0200 Subject: [PATCH 27/31] AVR: mention new architecture into README.md. Signed-off-by: Glenn Baker --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9dabbffc52..90d6671c8c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framew Unicorn offers some unparalleled features: -- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, RISCV, SPARC, S390X, TriCore and X86 (16, 32, 64-bit) +- Multi-architecture: ARM, ARM64 (ARMv8), AVR, M68K, MIPS, PowerPC, RISCV, SPARC, S390X, TriCore and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API - Implemented in pure C language, with bindings for Crystal, Clojure, Visual Basic, Perl, Rust, Ruby, Python, Java, .NET, Go, Delphi/Free Pascal, Haskell, Pharo, Lua and Zig. - Native support for Windows & *nix (with Mac OSX, Linux, Android, *BSD & Solaris confirmed) From 9311139c203a02cbc5899fa3f37ca6dbd46e1d3f Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 8 Oct 2024 11:08:44 +0200 Subject: [PATCH 28/31] AVR: add self to CREDITS.txt Signed-off-by: Glenn Baker --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index ee443858b7..f2dc6118a0 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -81,3 +81,4 @@ Ziqiao Kong (lazymio): uc_context_free() API and various bug fix & improvement. Sven Almgren (blindmatrix): bug fix Chenxu Wu (kabeor): Documentation Philipp Takacs: virtual tlb, memory snapshots +Glenn Baker: AVR architecture support From 391816592fca615597112c82f4eb5175ec6b5710 Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 8 Oct 2024 11:28:49 +0200 Subject: [PATCH 29/31] AVR: fix build with older compilers. Signed-off-by: Glenn Baker --- samples/sample_avr.c | 6 ++-- tests/unit/test_avr.c | 70 +++++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/samples/sample_avr.c b/samples/sample_avr.c index 9ef461c8fe..7482bbc204 100644 --- a/samples/sample_avr.c +++ b/samples/sample_avr.c @@ -18,8 +18,10 @@ static const uint8_t CODE[] = "\x01\x96" // adiw r24, 0x01 "\x08\x95" // ret ; -static const uint32_t CODE_SIZE = sizeof(CODE) - 1; -static const uint32_t CODE_SIZE_ALIGNED = (CODE_SIZE + 0xff) & -0x100; +enum { + CODE_SIZE = sizeof(CODE) - 1, + CODE_SIZE_ALIGNED = (CODE_SIZE + 0xff) & -0x100, +}; static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) diff --git a/tests/unit/test_avr.c b/tests/unit/test_avr.c index 9cf03c1cd1..e9e6aecbcc 100644 --- a/tests/unit/test_avr.c +++ b/tests/unit/test_avr.c @@ -7,26 +7,26 @@ #define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & -PAGE_SIZE) enum { - ADDR__init__, - ADDR_test_func, - ADDR_test_1, - ADDR_main, - ADDR_abort, - ADDR_exit, - ADDR__stop_program, - ADDR__data__, + ADDR__init__ = 0x0000, // __init__ + ADDR_test_func = 0x001a, // test_func() + ADDR_test_1 = 0x0030, // test_1() + ADDR_main = 0x0058, // main() + ADDR_abort = 0x0062, // abort() + ADDR_exit = 0x006c, // _exit() + ADDR__stop_program = 0x006e, // __stop_program() + ADDR__data__ = 0x0070, // __data__ + ADDR__data__end = 0x0072, }; -static const uint16_t ADDR[] = { - 0x0000, // __init__ - 0x001a, // test_func() - 0x0030, // test_1() - 0x0058, // main() - 0x0062, // abort() - 0x006c, // _exit() - 0x006e, // __stop_program() - 0x0070, // __data__ - 0x0072, // __size__ +enum { + SIZE__init__ = ADDR_test_func - ADDR__init__, + SIZE_test_func = ADDR_test_1 - ADDR_test_func, + SIZE_test_1 = ADDR_main - ADDR_test_1, + SIZE_main = ADDR_abort - ADDR_main, + SIZE_abort = ADDR_exit - ADDR_abort, + SIZE_exit = ADDR__stop_program - ADDR_exit, + SIZE__stop_program = ADDR__data__ - ADDR__stop_program, + SIZE__data__ = ADDR__data__end - ADDR__data__, }; static const uint8_t FLASH[] = @@ -128,7 +128,7 @@ static void test_avr_basic_alu(void) OK(uc_reg_write(uc, UC_AVR_REG_R24W, &r_func_arg0)); OK(uc_reg_write(uc, UC_AVR_REG_R22W, &r_func_arg1)); - const uint64_t code_start = ADDR[ADDR_test_func] + 8; + const uint64_t code_start = ADDR_test_func + 8; OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0)); OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); @@ -186,10 +186,8 @@ static void test_avr_basic_mem(void) uc_hook eventmem_hook; MEM_HOOK_RESULTS eventmem_trace = {0}; - const uint16_t DATA_BASE = ADDR[ADDR__data__]; - const uint16_t DATA_SIZE = ADDR[ADDR__data__+1] - DATA_BASE; - const uint8_t *const DATA = &FLASH[ADDR[ADDR__data__]]; - uint8_t mem[DATA_SIZE]; + const uint8_t *const DATA = &FLASH[ADDR__data__]; + uint8_t mem[SIZE__data__]; uint32_t r_pc; int i; @@ -198,21 +196,21 @@ static void test_avr_basic_mem(void) OK(uc_hook_add(uc, &eventmem_hook, UC_HOOK_MEM_VALID, test_avr_basic_mem_cb_eventmem, &eventmem_trace, 1, 0)); - const uint64_t code_start = ADDR[ADDR__init__]; - OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0)); + const uint64_t code_start = ADDR__init__; + OK(uc_emu_start(uc, code_start, ADDR__init__ + SIZE__init__, 0, 0)); OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); - TEST_CHECK(r_pc == ADDR[ADDR__init__+1]); + TEST_CHECK(r_pc == ADDR__init__ + SIZE__init__); // Check SRAM was correctly initialized with data from Flash program memory OK(uc_mem_read(uc, MEM_BASE, mem, sizeof(mem))); - TEST_CHECK(memcmp(mem, DATA, DATA_SIZE) == 0); + TEST_CHECK(memcmp(mem, DATA, SIZE__data__) == 0); - TEST_CHECK(eventmem_trace.count == 2*DATA_SIZE); - for (i = 0; i < DATA_SIZE; i++) { + TEST_CHECK(eventmem_trace.count == 2*SIZE__data__); + for (i = 0; i < SIZE__data__; i++) { const MEM_HOOK_RESULT *const mr = &eventmem_trace.results[2*i]; TEST_CHECK(mr->type == UC_MEM_READ); - TEST_CHECK(mr->address == (UC_AVR_MEM_FLASH|(DATA_BASE+i))); + TEST_CHECK(mr->address == (UC_AVR_MEM_FLASH|(ADDR__data__+i))); TEST_CHECK(mr->size == 1); TEST_CHECK(mr->value == 0); @@ -236,23 +234,23 @@ static void test_avr_full_exec(void) uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); - const uint64_t code_start = ADDR[ADDR__init__]; - OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0)); + const uint64_t code_start = ADDR__init__; + OK(uc_emu_start(uc, code_start, ADDR__init__ + SIZE__init__, 0, 0)); OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); - TEST_CHECK(r_pc == ADDR[ADDR__init__+1]); + TEST_CHECK(r_pc == ADDR__init__ + SIZE__init__); r_sp = MEM_BASE + MEM_SIZE - 1; OK(uc_reg_write(uc, UC_AVR_REG_SP, &r_sp)); const uint64_t exits[] = { - ADDR[ADDR_main], - ADDR[ADDR__stop_program] + ADDR_main, + ADDR__stop_program }; OK(uc_ctl_exits_enable(uc)); OK(uc_ctl_set_exits(uc, exits, ARRAY_ELEMS(exits))); - const uint64_t code_main = ADDR[ADDR_main]; + const uint64_t code_main = ADDR_main; OK(uc_emu_start(uc, code_main, 0, 0, 0)); OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); From ab8cc64ab3f5e46b9a5e842942b0c30c7580c50f Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 8 Oct 2024 12:28:52 +0200 Subject: [PATCH 30/31] bindings: add avr constants to python binding module. Signed-off-by: Glenn Baker --- bindings/python/unicorn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index a93e12a05c..04894a8e2b 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Forwarding defs for compatibility -from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const, s390x_const, tricore_const +from . import arm_const, arm64_const, avr_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const, s390x_const, tricore_const from .unicorn_const import * from .unicorn import Uc, ucsubclass, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__ From 9a25b59a813e0d965f027007290e89b96350796b Mon Sep 17 00:00:00 2001 From: Glenn Baker Date: Tue, 8 Oct 2024 13:14:14 +0200 Subject: [PATCH 31/31] rust: add AVR architecture support. Signed-off-by: Glenn Baker --- bindings/rust/build.rs | 3 + bindings/rust/src/avr.rs | 211 +++++++++++++++++++++++++++++ bindings/rust/src/lib.rs | 8 ++ bindings/rust/src/unicorn_const.rs | 3 +- 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 bindings/rust/src/avr.rs diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 821367d39b..43f556e856 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -116,6 +116,9 @@ fn build_with_cmake() { if std::env::var("CARGO_FEATURE_ARCH_TRICORE").is_ok() { archs.push_str("tricore;"); } + if std::env::var("CARGO_FEATURE_ARCH_AVR").is_ok() { + archs.push_str("avr;"); + } if !archs.is_empty() { archs.pop(); diff --git a/bindings/rust/src/avr.rs b/bindings/rust/src/avr.rs new file mode 100644 index 0000000000..1660933497 --- /dev/null +++ b/bindings/rust/src/avr.rs @@ -0,0 +1,211 @@ +#![allow(non_camel_case_types)] +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RegisterAVR { + INVALID = 0, + + // General purpose registers (GPR) + R0 = 1, + R1 = 2, + R2 = 3, + R3 = 4, + R4 = 5, + R5 = 6, + R6 = 7, + R7 = 8, + R8 = 9, + R9 = 10, + R10 = 11, + R11 = 12, + R12 = 13, + R13 = 14, + R14 = 15, + R15 = 16, + R16 = 17, + R17 = 18, + R18 = 19, + R19 = 20, + R20 = 21, + R21 = 22, + R22 = 23, + R23 = 24, + R24 = 25, + R25 = 26, + R26 = 27, + R27 = 28, + R28 = 29, + R29 = 30, + R30 = 31, + R31 = 32, + + PC = 33, + SP = 34, + + RAMPD = 57, + RAMPX = 58, + RAMPY = 59, + RAMPZ = 60, + EIND = 61, + SPL = 62, + SPH = 63, + SREG = 64, + + // 16-bit coalesced registers + R0W = 65, + R1W = 66, + R2W = 67, + R3W = 68, + R4W = 69, + R5W = 70, + R6W = 71, + R7W = 72, + R8W = 73, + R9W = 74, + R10W = 75, + R11W = 76, + R12W = 77, + R13W = 78, + R14W = 79, + R15W = 80, + R16W = 81, + R17W = 82, + R18W = 83, + R19W = 84, + R20W = 85, + R21W = 86, + R22W = 87, + R23W = 88, + R24W = 89, + R25W = 90, + R26W = 91, + R27W = 92, + R28W = 93, + R29W = 94, + R30W = 95, + + // 32-bit coalesced registers + R0D = 97, + R1D = 98, + R2D = 99, + R3D = 100, + R4D = 101, + R5D = 102, + R6D = 103, + R7D = 104, + R8D = 105, + R9D = 106, + R10D = 107, + R11D = 108, + R12D = 109, + R13D = 110, + R14D = 111, + R15D = 112, + R16D = 113, + R17D = 114, + R18D = 115, + R19D = 116, + R20D = 117, + R21D = 118, + R22D = 119, + R23D = 120, + R24D = 121, + R25D = 122, + R26D = 123, + R27D = 124, + R28D = 125, +} + +impl RegisterAVR { + // alias registers + // (assoc) Xhi = 28 + // (assoc) Xlo = 27 + // (assoc) Yhi = 30 + // (assoc) Ylo = 29 + // (assoc) Zhi = 32 + // (assoc) Zlo = 31 + pub const XHI: RegisterAVR = RegisterAVR::R27; + pub const XLO: RegisterAVR = RegisterAVR::R26; + pub const YHI: RegisterAVR = RegisterAVR::R29; + pub const YLO: RegisterAVR = RegisterAVR::R28; + pub const ZHI: RegisterAVR = RegisterAVR::R31; + pub const ZLO: RegisterAVR = RegisterAVR::R30; + + // (assoc) X = 91 + // (assoc) Y = 93 + // (assoc) Z = 95 + pub const X: RegisterAVR = RegisterAVR::R26W; + pub const Y: RegisterAVR = RegisterAVR::R28W; + pub const Z: RegisterAVR = RegisterAVR::R30W; +} + +impl From for i32 { + fn from(r: RegisterAVR) -> Self { + r as i32 + } +} + +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum AvrArch { + UC_AVR_ARCH_AVR1 = 10, + UC_AVR_ARCH_AVR2 = 20, + UC_AVR_ARCH_AVR25 = 25, + UC_AVR_ARCH_AVR3 = 30, + UC_AVR_ARCH_AVR4 = 40, + UC_AVR_ARCH_AVR5 = 50, + UC_AVR_ARCH_AVR51 = 51, + UC_AVR_ARCH_AVR6 = 60, +} + +impl From for i32 { + fn from(value: AvrArch) -> Self { + value as i32 + } +} + +impl From<&AvrArch> for i32 { + fn from(value: &AvrArch) -> Self { + *value as i32 + } +} + +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum AvrCpuModel { + UC_CPU_AVR_ATMEGA16 = 50016, + UC_CPU_AVR_ATMEGA32 = 50032, + UC_CPU_AVR_ATMEGA64 = 50064, + UC_CPU_AVR_ATMEGA128 = 51128, + UC_CPU_AVR_ATMEGA128RFR2 = 51129, + UC_CPU_AVR_ATMEGA1280 = 51130, + UC_CPU_AVR_ATMEGA256 = 60256, + UC_CPU_AVR_ATMEGA256RFR2 = 60257, + UC_CPU_AVR_ATMEGA2560 = 60258, +} + +impl From for i32 { + fn from(value: AvrCpuModel) -> Self { + value as i32 + } +} + +impl From<&AvrCpuModel> for i32 { + fn from(value: &AvrCpuModel) -> Self { + *value as i32 + } +} + +#[repr(i32)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum AvrMem { + // Flash program memory (code) + FLASH = 0x08000000, +} + +impl From for i32 { + fn from(r: AvrMem) -> Self { + r as i32 + } +} diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index a1e7b16925..1d6484260d 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -61,6 +61,12 @@ mod arm64; #[cfg(feature = "arch_arm")] pub use crate::arm64::*; +// include avr support if conditionally compiled in +#[cfg(feature = "arch_avr")] +mod avr; +#[cfg(feature = "arch_avr")] +pub use crate::avr::*; + // include m68k support if conditionally compiled in #[cfg(feature = "arch_m68k")] mod m68k; @@ -1005,6 +1011,8 @@ impl<'a, D> Unicorn<'a, D> { Arch::S390X => Ok(RegisterS390X::PC as i32), #[cfg(feature = "arch_tricore")] Arch::TRICORE => Ok(RegisterTRICORE::PC as i32), + #[cfg(feature = "arch_avr")] + Arch::AVR => Ok(RegisterAVR::PC as i32), // returns `uc_error::ARCH` for `Arch::MAX`, and any // other architecture that are not compiled in _ => Err(uc_error::ARCH), diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 6d122e14c2..ddea2c58c2 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -175,7 +175,8 @@ pub enum Arch { RISCV = 8, S390X = 9, TRICORE = 10, - MAX = 11, + AVR = 11, + MAX = 12, } impl TryFrom for Arch {