* [Qemu-devel] [PATCH v17 1/9] target-avr: AVR cores support is added.
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 18:13 ` Peter Maydell
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 2/9] target-avr: adding AVR CPU features/flavors Michael Rolnik
` (11 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
1. basic CPU structure
2. registers
3. no instructions
4. saving sreg, rampD, rampX, rampY, rampD, eind in HW representation
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
MAINTAINERS | 5 +
arch_init.c | 2 +
configure | 5 +
default-configs/avr-softmmu.mak | 21 +++
include/disas/bfd.h | 6 +
include/sysemu/arch_init.h | 1 +
target-avr/Makefile.objs | 24 ++++
target-avr/cpu-qom.h | 85 ++++++++++++
target-avr/cpu.c | 292 ++++++++++++++++++++++++++++++++++++++++
target-avr/cpu.h | 180 +++++++++++++++++++++++++
target-avr/gdbstub.c | 86 ++++++++++++
target-avr/helper.c | 89 ++++++++++++
target-avr/helper.h | 22 +++
target-avr/machine.c | 115 ++++++++++++++++
target-avr/translate.c | 256 +++++++++++++++++++++++++++++++++++
target-avr/translate.h | 115 ++++++++++++++++
16 files changed, 1304 insertions(+)
create mode 100644 default-configs/avr-softmmu.mak
create mode 100644 target-avr/Makefile.objs
create mode 100644 target-avr/cpu-qom.h
create mode 100644 target-avr/cpu.c
create mode 100644 target-avr/cpu.h
create mode 100644 target-avr/gdbstub.c
create mode 100644 target-avr/helper.c
create mode 100644 target-avr/helper.h
create mode 100644 target-avr/machine.c
create mode 100644 target-avr/translate.c
create mode 100644 target-avr/translate.h
diff --git a/MAINTAINERS b/MAINTAINERS
index b6fb84e..c793e90 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -110,6 +110,11 @@ F: disas/arm.c
F: disas/arm-a64.cc
F: disas/libvixl/
+AVR
+M: Michael Rolnik <mrolnik@gmail.com>
+S: Maintained
+F: target-avr/
+
CRIS
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
diff --git a/arch_init.c b/arch_init.c
index fa05973..be6e6de 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -80,6 +80,8 @@ int graphic_depth = 32;
#define QEMU_ARCH QEMU_ARCH_UNICORE32
#elif defined(TARGET_TRICORE)
#define QEMU_ARCH QEMU_ARCH_TRICORE
+#elif defined(TARGET_AVR)
+#define QEMU_ARCH QEMU_ARCH_AVR
#endif
const uint32_t arch_type = QEMU_ARCH;
diff --git a/configure b/configure
index 4b808f9..8ac60f0 100755
--- a/configure
+++ b/configure
@@ -5663,6 +5663,8 @@ case "$target_name" in
bflt="yes"
gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
;;
+ avr)
+ ;;
cris)
;;
lm32)
@@ -5861,6 +5863,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
disas_config "ARM_A64"
fi
;;
+ avr)
+ disas_config "AVR"
+ ;;
cris)
disas_config "CRIS"
;;
diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak
new file mode 100644
index 0000000..003465d
--- /dev/null
+++ b/default-configs/avr-softmmu.mak
@@ -0,0 +1,21 @@
+#
+# QEMU AVR CPU
+#
+# Copyright (c) 2016 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
+# <http://www.gnu.org/licenses/lgpl-2.1.html>
+#
+
+# Default configuration for avr-softmmu
diff --git a/include/disas/bfd.h b/include/disas/bfd.h
index 8a3488c..8ccd108 100644
--- a/include/disas/bfd.h
+++ b/include/disas/bfd.h
@@ -213,6 +213,12 @@ enum bfd_architecture
#define bfd_mach_m32r 0 /* backwards compatibility */
bfd_arch_mn10200, /* Matsushita MN10200 */
bfd_arch_mn10300, /* Matsushita MN10300 */
+ bfd_arch_avr, /* Atmel AVR microcontrollers. */
+#define bfd_mach_avr1 1
+#define bfd_mach_avr2 2
+#define bfd_mach_avr3 3
+#define bfd_mach_avr4 4
+#define bfd_mach_avr5 5
bfd_arch_cris, /* Axis CRIS */
#define bfd_mach_cris_v0_v10 255
#define bfd_mach_cris_v32 32
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index d690dfa..8c75777 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -23,6 +23,7 @@ enum {
QEMU_ARCH_UNICORE32 = (1 << 14),
QEMU_ARCH_MOXIE = (1 << 15),
QEMU_ARCH_TRICORE = (1 << 16),
+ QEMU_ARCH_AVR = (1 << 17),
};
extern const uint32_t arch_type;
diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs
new file mode 100644
index 0000000..85f9261
--- /dev/null
+++ b/target-avr/Makefile.objs
@@ -0,0 +1,24 @@
+#
+# QEMU AVR CPU
+#
+# Copyright (c) 2016 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
+# <http://www.gnu.org/licenses/lgpl-2.1.html>
+#
+
+obj-y += translate.o cpu.o helper.o
+obj-y += gdbstub.o
+obj-$(CONFIG_SOFTMMU) += machine.o
+
diff --git a/target-avr/cpu-qom.h b/target-avr/cpu-qom.h
new file mode 100644
index 0000000..20af8d6
--- /dev/null
+++ b/target-avr/cpu-qom.h
@@ -0,0 +1,85 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#ifndef QEMU_AVR_CPU_QOM_H
+#define QEMU_AVR_CPU_QOM_H
+
+#include "qom/cpu.h"
+
+#define TYPE_AVR_CPU "avr"
+
+#define AVR_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU)
+#define AVR_CPU(obj) \
+ OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU)
+#define AVR_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_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.
+ */
+typedef struct AVRCPUClass {
+ CPUClass parent_class;
+
+ DeviceRealize parent_realize;
+ void (*parent_reset)(CPUState *cpu);
+} AVRCPUClass;
+
+/**
+ * AVRCPU:
+ * @env: #CPUAVRState
+ *
+ * A AVR CPU.
+ */
+typedef struct AVRCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUAVRState env;
+} AVRCPU;
+
+static inline AVRCPU *avr_env_get_cpu(CPUAVRState *env)
+{
+ return container_of(env, AVRCPU, env);
+}
+
+#define ENV_GET_CPU(e) CPU(avr_env_get_cpu(e))
+#define ENV_OFFSET offsetof(AVRCPU, env)
+
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vms_avr_cpu;
+#endif
+
+void avr_cpu_do_interrupt(CPUState *cpu);
+bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void avr_cpu_dump_state(CPUState *cs, FILE *f,
+ fprintf_function cpu_fprintf, int flags);
+hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int avr_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
+#endif
+
diff --git a/target-avr/cpu.c b/target-avr/cpu.c
new file mode 100644
index 0000000..e99f804
--- /dev/null
+++ b/target-avr/cpu.c
@@ -0,0 +1,292 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "migration/vmstate.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(CPUState *s)
+{
+ AVRCPU *cpu = AVR_CPU(s);
+ AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
+ CPUAVRState *env = &cpu->env;
+
+ mcc->parent_reset(s);
+
+ 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;
+
+ memset(env->r, 0, sizeof(env->r));
+
+ tlb_flush(s, 1);
+}
+
+static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
+{
+ info->mach = bfd_arch_avr;
+ info->print_insn = NULL;
+}
+
+static void avr_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev);
+
+ 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)
+{
+ CPUState *cs = CPU(obj);
+ AVRCPU *cpu = AVR_CPU(obj);
+ static int inited;
+
+ cs->env_ptr = &cpu->env;
+ cpu_exec_init(cs, &error_abort);
+
+#ifndef CONFIG_USER_ONLY
+ qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 37);
+#endif
+
+ if (tcg_enabled() && !inited) {
+ inited = 1;
+ avr_translate_init();
+ }
+}
+
+static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+ char **cpuname;
+
+ if (!cpu_model) {
+ return NULL;
+ }
+
+ cpuname = g_strsplit(cpu_model, ",", 1);
+ typename = g_strdup_printf("%s-" TYPE_AVR_CPU, cpuname[0]);
+ oc = object_class_by_name(typename);
+
+ g_strfreev(cpuname);
+ g_free(typename);
+
+ if (!oc
+ || !object_class_dynamic_cast(oc, TYPE_AVR_CPU)
+ || object_class_is_abstract(oc)) {
+ return NULL;
+ }
+
+ return oc;
+}
+
+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;
+
+ mcc->parent_reset = cc->reset;
+ cc->reset = avr_cpu_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;
+#if !defined(CONFIG_USER_ONLY)
+ cc->memory_rw_debug = avr_cpu_memory_rw_debug;
+#endif
+#ifdef CONFIG_USER_ONLY
+ cc->handle_mmu_fault = avr_cpu_handle_mmu_fault;
+#else
+ cc->get_phys_page_debug = avr_cpu_get_phys_page_debug;
+ cc->vmsd = &vms_avr_cpu;
+#endif
+ cc->disas_set_info = avr_cpu_disas_set_info;
+ 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;
+
+/*
+ * Reason: avr_cpu_initfn() calls cpu_exec_init(), which saves
+ * the object in cpus -> dangling pointer after final
+ * object_unref().
+ */
+ dc->cannot_destroy_with_object_finalize_yet = true;
+}
+
+typedef struct AVRCPUInfo {
+ const char *name;
+ void (*initfn)(Object *obj);
+} AVRCPUInfo;
+
+static const AVRCPUInfo avr_cpus[] = {
+};
+
+static gint avr_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+ const char *name_a;
+ const char *name_b;
+
+ name_a = object_class_get_name(class_a);
+ name_b = object_class_get_name(class_b);
+
+ return strcmp(name_a, name_b);
+}
+
+static void avr_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CPUListState *s = user_data;
+ const char *typename;
+ char *name;
+
+ typename = object_class_get_name(oc);
+ name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_AVR_CPU));
+ (*s->cpu_fprintf)(s->file, " %s\n", name);
+ g_free(name);
+}
+
+void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ CPUListState s = {
+ .file = f,
+ .cpu_fprintf = cpu_fprintf,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_AVR_CPU, false);
+ list = g_slist_sort(list, avr_cpu_list_compare);
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ g_slist_foreach(list, avr_cpu_list_entry, &s);
+ g_slist_free(list);
+}
+
+AVRCPU *cpu_avr_init(const char *cpu_model)
+{
+ return AVR_CPU(cpu_generic_init(TYPE_AVR_CPU, cpu_model));
+}
+
+static void cpu_register(const AVRCPUInfo *info)
+{
+ TypeInfo type_info = {
+ .parent = TYPE_AVR_CPU,
+ .instance_size = sizeof(AVRCPU),
+ .instance_init = info->initfn,
+ .class_size = sizeof(AVRCPUClass),
+ };
+
+ type_info.name = g_strdup_printf("%s-" TYPE_AVR_CPU, info->name);
+ type_register(&type_info);
+ g_free((void *)type_info.name);
+}
+
+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,
+};
+
+static void avr_cpu_register_types(void)
+{
+ int i;
+ type_register_static(&avr_cpu_type_info);
+
+ for (i = 0; i < ARRAY_SIZE(avr_cpus); i++) {
+ cpu_register(&avr_cpus[i]);
+ }
+}
+
+type_init(avr_cpu_register_types)
+
diff --git a/target-avr/cpu.h b/target-avr/cpu.h
new file mode 100644
index 0000000..bf02bca
--- /dev/null
+++ b/target-avr/cpu.h
@@ -0,0 +1,180 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#if !defined(CPU_AVR_H)
+#define CPU_AVR_H
+
+#include "qemu-common.h"
+
+#define TARGET_LONG_BITS 32
+
+#define CPUArchState struct CPUAVRState
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+
+/*
+ * 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
+
+/*
+ * 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)
+
+#define PHYS_ADDR_MASK 0xfff00000
+
+#define PHYS_BASE_CODE 0x00000000
+#define PHYS_BASE_DATA 0x00800000
+#define PHYS_BASE_REGS 0x10000000
+
+#define VIRT_BASE_CODE 0x00000000
+#define VIRT_BASE_DATA 0x00000000
+#define VIRT_BASE_REGS 0x00000000
+
+/*
+ * there are two groups of registers
+ * 1. CPU regs - accessible by LD/ST and CPU itself
+ * 2. CPU IO regs - accessible by LD/ST and IN/OUT
+ */
+#define AVR_CPU_REGS 0x0020
+#define AVR_CPU_IO_REGS 0x0040
+#define AVR_REGS (AVR_CPU_IO_REGS + AVR_CPU_REGS)
+
+#define AVR_CPU_REGS_BASE 0x0000
+#define AVR_CPU_IO_REGS_BASE (AVR_CPU_REGS_BASE + AVR_CPU_REGS)
+
+#define AVR_CPU_REGS_LAST (AVR_CPU_REGS_BASE + AVR_CPU_REGS - 1)
+#define AVR_CPU_IO_REGS_LAST (AVR_CPU_IO_REGS_BASE + AVR_CPU_IO_REGS - 1)
+
+typedef struct CPUAVRState CPUAVRState;
+
+struct CPUAVRState {
+ uint32_t pc_w; /* 0x003fffff up to 22 bits */
+
+ uint32_t sregC; /* 0x00000001 1 bits */
+ uint32_t sregZ; /* 0x0000ffff 16 bits, negative logic */
+ uint32_t sregN; /* 0x00000001 1 bits */
+ uint32_t sregV; /* 0x00000001 1 bits */
+ uint32_t sregS; /* 0x00000001 1 bits */
+ uint32_t sregH; /* 0x00000001 1 bits */
+ uint32_t sregT; /* 0x00000001 1 bits */
+ uint32_t sregI; /* 0x00000001 1 bits */
+
+ 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[AVR_CPU_REGS];
+ /* 8 bits each */
+ uint32_t sp; /* 16 bits */
+
+ uint64_t intsrc; /* interrupt sources */
+
+ /* Those resources are used only in QEMU core */
+ CPU_COMMON
+};
+
+#define cpu_list avr_cpu_list
+#define cpu_signal_handler cpu_avr_signal_handler
+
+#include "exec/cpu-all.h"
+#include "cpu-qom.h"
+
+static inline int cpu_mmu_index(CPUAVRState *env, bool ifetch)
+{
+ return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
+}
+
+void avr_translate_init(void);
+
+AVRCPU *cpu_avr_init(const char *cpu_model);
+
+#define cpu_init(cpu_model) CPU(cpu_avr_init(cpu_model))
+
+void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_avr_exec(CPUState *cpu);
+int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc);
+int avr_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+ int mmu_idx);
+int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
+ int len, bool is_write);
+
+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;
+ *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 & 0x01) << 0
+ | (env->sregZ == 0 ? 1 : 0) << 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 ? 0 : 1;
+ 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;
+}
+
+#include "exec/exec-all.h"
+
+#endif /* !defined (CPU_AVR_H) */
+
diff --git a/target-avr/gdbstub.c b/target-avr/gdbstub.c
new file mode 100644
index 0000000..a540389
--- /dev/null
+++ b/target-avr/gdbstub.c
@@ -0,0 +1,86 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int avr_cpu_gdb_read_register(CPUState *cs, uint8_t *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/target-avr/helper.c b/target-avr/helper.c
new file mode 100644
index 0000000..b48222d
--- /dev/null
+++ b/target-avr/helper.c
@@ -0,0 +1,89 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "hw/irq.h"
+#include "include/hw/sysbus.h"
+#include "include/sysemu/sysemu.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+
+bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+ bool ret = false;
+ return ret;
+}
+
+void avr_cpu_do_interrupt(CPUState *cs)
+{
+}
+
+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 */
+}
+
+int avr_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx)
+{
+ /* currently it's assumed that this will never happen */
+ cs->exception_index = EXCP_DEBUG;
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ return 1;
+}
+
+void tlb_fill(CPUState *cs, target_ulong vaddr, MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr)
+{
+ target_ulong page_size = TARGET_PAGE_SIZE;
+ int prot = 0;
+ MemTxAttrs attrs = {};
+ uint32_t paddr;
+
+ vaddr &= TARGET_PAGE_MASK;
+
+ if (mmu_idx == MMU_CODE_IDX) {
+ paddr = PHYS_BASE_CODE + vaddr - VIRT_BASE_CODE;
+ prot = PAGE_READ | PAGE_EXEC;
+ } else {
+ paddr = PHYS_BASE_DATA + vaddr - VIRT_BASE_DATA;
+ prot = PAGE_READ | PAGE_WRITE;
+ }
+
+ tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
+}
+
+void helper_debug(CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
diff --git a/target-avr/helper.h b/target-avr/helper.h
new file mode 100644
index 0000000..c60ac3e
--- /dev/null
+++ b/target-avr/helper.h
@@ -0,0 +1,22 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+DEF_HELPER_1(debug, void, env)
+
diff --git a/target-avr/machine.c b/target-avr/machine.c
new file mode 100644
index 0000000..cf472ac
--- /dev/null
+++ b/target-avr/machine.c
@@ -0,0 +1,115 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "cpu.h"
+#include "hw/boards.h"
+#include "migration/qemu-file.h"
+
+static int get_sreg(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAVRState *env = opaque;
+ uint8_t sreg;
+
+ sreg = qemu_get_ubyte(f);
+ cpu_set_sreg(env, sreg);
+ return 0;
+}
+
+static void put_sreg(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAVRState *env = opaque;
+ uint8_t sreg = cpu_get_sreg(env);
+
+ qemu_put_ubyte(f, sreg);
+}
+
+static const VMStateInfo vms_sreg = {
+ .name = "sreg",
+ .get = get_sreg,
+ .put = put_sreg,
+};
+
+static int get_segment(QEMUFile *f, void *opaque, size_t size)
+{
+ uint32_t *ramp = opaque;
+ uint8_t temp;
+
+ temp = qemu_get_ubyte(f);
+ *ramp = ((uint32_t)temp) << 16;
+ return 0;
+}
+
+static void put_segment(QEMUFile *f, void *opaque, size_t size)
+{
+ uint32_t *ramp = opaque;
+ uint8_t temp = *ramp >> 16;
+
+ qemu_put_ubyte(f, temp);
+}
+
+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_ARRAY(env.r, AVRCPU, AVR_CPU_REGS),
+
+ 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/target-avr/translate.c b/target-avr/translate.c
new file mode 100644
index 0000000..b5ca59e
--- /dev/null
+++ b/target-avr/translate.c
@@ -0,0 +1,256 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "translate.h"
+
+TCGv_env cpu_env;
+
+TCGv cpu_pc;
+
+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_r[32];
+TCGv cpu_eind;
+TCGv cpu_sp;
+
+#include "exec/gen-icount.h"
+#define REG(x) (cpu_r[x])
+
+void avr_translate_init(void)
+{
+ int i;
+ static int done_init;
+
+ if (done_init) {
+ return;
+ }
+#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
+ cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+ 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");
+
+ for (i = 0; i < 32; i++) {
+ char name[16];
+
+ sprintf(name, "r[%d]", i);
+
+ cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), name);
+ }
+
+ done_init = 1;
+}
+
+static void decode_opc(AVRCPU *cpu, DisasContext *ctx, InstInfo *inst)
+{
+ CPUAVRState *env = &cpu->env;
+
+ inst->opcode = cpu_ldl_code(env, inst->cpc * 2);/* pc points to words */
+ inst->length = 16;
+ inst->translate = NULL;
+
+ if (inst->length == 16) {
+ inst->npc = inst->cpc + 1;
+ /* get opcode as 16bit value */
+ inst->opcode = inst->opcode & 0x0000ffff;
+ }
+ if (inst->length == 32) {
+ inst->npc = inst->cpc + 2;
+ /* get opcode as 32bit value */
+ inst->opcode = (inst->opcode << 16)
+ | (inst->opcode >> 16);
+ }
+}
+
+/* generate intermediate code for basic block 'tb'. */
+void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb)
+{
+ AVRCPU *cpu = avr_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+ DisasContext ctx;
+ target_ulong pc_start;
+ int num_insns, max_insns;
+ target_ulong cpc;
+ target_ulong npc;
+
+ pc_start = tb->pc / 2;
+ ctx.tb = tb;
+ ctx.memidx = 0;
+ ctx.bstate = BS_NONE;
+ ctx.singlestep = cs->singlestep_enabled;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+
+ if (max_insns == 0) {
+ max_insns = CF_COUNT_MASK;
+ }
+ if (max_insns > TCG_MAX_INSNS) {
+ max_insns = TCG_MAX_INSNS;
+ }
+
+ gen_tb_start(tb);
+
+ /* decode first instruction */
+ ctx.inst[0].cpc = pc_start;
+ decode_opc(cpu, &ctx, &ctx.inst[0]);
+ do {
+ /* set curr/next PCs */
+ cpc = ctx.inst[0].cpc;
+ npc = ctx.inst[0].npc;
+
+ /* decode next instruction */
+ ctx.inst[1].cpc = ctx.inst[0].npc;
+ decode_opc(cpu, &ctx, &ctx.inst[1]);
+
+ /* translate current instruction */
+ tcg_gen_insn_start(cpc);
+ num_insns++;
+
+ /*
+ * this is due to some strange GDB behavior
+ * let's assume main is has 0x100 address
+ * b main - sets a breakpoint to 0x00000100 address (code)
+ * b *0x100 - sets a breakpoint to 0x00800100 address (data)
+ */
+ if (unlikely(cpu_breakpoint_test(cs, PHYS_BASE_CODE + cpc * 2, BP_ANY))
+ || cpu_breakpoint_test(cs, PHYS_BASE_DATA + cpc * 2, BP_ANY)) {
+ tcg_gen_movi_i32(cpu_pc, cpc);
+ gen_helper_debug(cpu_env);
+ ctx.bstate = BS_EXCP;
+ goto done_generating;
+ }
+
+ if (ctx.inst[0].translate) {
+ ctx.bstate = ctx.inst[0].translate(env, &ctx, ctx.inst[0].opcode);
+ }
+
+ if (num_insns >= max_insns) {
+ break; /* max translated instructions limit reached */
+ }
+ if (ctx.singlestep) {
+ break; /* single step */
+ }
+ if ((cpc & (TARGET_PAGE_SIZE - 1)) == 0) {
+ break; /* page boundary */
+ }
+
+ ctx.inst[0] = ctx.inst[1]; /* make next inst curr */
+ } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
+
+ if (tb->cflags & CF_LAST_IO) {
+ gen_io_end();
+ }
+
+ if (ctx.singlestep) {
+ if (ctx.bstate == BS_STOP || ctx.bstate == BS_NONE) {
+ tcg_gen_movi_tl(cpu_pc, npc);
+ }
+ gen_helper_debug(cpu_env);
+ tcg_gen_exit_tb(0);
+ } else {
+ switch (ctx.bstate) {
+ case BS_STOP:
+ case BS_NONE:
+ gen_goto_tb(env, &ctx, 0, npc);
+ break;
+ case BS_EXCP:
+ tcg_gen_exit_tb(0);
+ break;
+ default:
+ break;
+ }
+ }
+
+done_generating:
+ gen_tb_end(tb, num_insns);
+
+ tb->size = (npc - pc_start) * 2;
+ tb->icount = num_insns;
+}
+
+void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb,
+ target_ulong *data)
+{
+ env->pc_w = data[0];
+}
+
+void avr_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
+ int flags)
+{
+ AVRCPU *cpu = AVR_CPU(cs);
+ CPUAVRState *env = &cpu->env;
+ int i;
+
+ cpu_fprintf(f, "\n");
+ cpu_fprintf(f, "PC: %06x\n", env->pc_w);
+ cpu_fprintf(f, "SP: %04x\n", env->sp);
+ cpu_fprintf(f, "rampD: %02x\n", env->rampD >> 16);
+ cpu_fprintf(f, "rampX: %02x\n", env->rampX >> 16);
+ cpu_fprintf(f, "rampY: %02x\n", env->rampY >> 16);
+ cpu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16);
+ cpu_fprintf(f, "EIND: %02x\n", env->eind);
+ cpu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]);
+ cpu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]);
+ cpu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]);
+ cpu_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' : '-');
+
+ cpu_fprintf(f, "\n");
+ for (i = 0; i < ARRAY_SIZE(env->r); i++) {
+ cpu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]);
+
+ if ((i % 8) == 7) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ cpu_fprintf(f, "\n");
+}
+
diff --git a/target-avr/translate.h b/target-avr/translate.h
new file mode 100644
index 0000000..9dc707e
--- /dev/null
+++ b/target-avr/translate.h
@@ -0,0 +1,115 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#ifndef AVR_TRANSLATE_H_
+#define AVR_TRANSLATE_H_
+
+#include "qemu/osdep.h"
+
+#include "tcg/tcg.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+#include "exec/log.h"
+
+extern TCGv_env cpu_env;
+
+extern TCGv cpu_pc;
+
+extern TCGv cpu_Cf;
+extern TCGv cpu_Zf;
+extern TCGv cpu_Nf;
+extern TCGv cpu_Vf;
+extern TCGv cpu_Sf;
+extern TCGv cpu_Hf;
+extern TCGv cpu_Tf;
+extern TCGv cpu_If;
+
+extern TCGv cpu_rampD;
+extern TCGv cpu_rampX;
+extern TCGv cpu_rampY;
+extern TCGv cpu_rampZ;
+
+extern TCGv cpu_r[32];
+extern TCGv cpu_eind;
+extern TCGv cpu_sp;
+
+enum {
+ BS_NONE = 0, /* Nothing special (none of the below) */
+ BS_STOP = 1, /* We want to stop translation for any reason */
+ BS_BRANCH = 2, /* A branch condition is reached */
+ BS_EXCP = 3, /* An exception condition is reached */
+};
+
+uint32_t get_opcode(uint8_t const *code, unsigned bitBase, unsigned bitSize);
+
+typedef struct DisasContext DisasContext;
+typedef struct InstInfo InstInfo;
+
+typedef int (*translate_function_t)(CPUAVRState *env, DisasContext *ctx,
+ uint32_t opcode);
+struct InstInfo {
+ target_long cpc;
+ target_long npc;
+ uint32_t opcode;
+ translate_function_t translate;
+ unsigned length;
+};
+
+/* This is the state at translation time. */
+struct DisasContext {
+ struct TranslationBlock *tb;
+
+ InstInfo inst[2];/* two consecutive instructions */
+
+ /* Routine used to access memory */
+ int memidx;
+ int bstate;
+ int singlestep;
+};
+
+void avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode,
+ translate_function_t *translate);
+
+static inline void gen_goto_tb(CPUAVRState *env, DisasContext *ctx,
+ int n, target_ulong dest)
+{
+ TranslationBlock *tb;
+
+ tb = ctx->tb;
+
+ if (ctx->singlestep == 0) {
+ tcg_gen_goto_tb(n);
+ tcg_gen_movi_i32(cpu_pc, dest);
+ tcg_gen_exit_tb((uintptr_t)tb + n);
+ } else {
+ tcg_gen_movi_i32(cpu_pc, dest);
+ gen_helper_debug(cpu_env);
+ tcg_gen_exit_tb(0);
+ }
+}
+
+#endif
+
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 1/9] target-avr: AVR cores support is added.
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 1/9] target-avr: AVR cores support is added Michael Rolnik
@ 2016-08-18 18:13 ` Peter Maydell
0 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2016-08-18 18:13 UTC (permalink / raw)
To: Michael Rolnik; +Cc: QEMU Developers, Richard Henderson
On 18 August 2016 at 13:07, Michael Rolnik <mrolnik@gmail.com> wrote:
> 1. basic CPU structure
> 2. registers
> 3. no instructions
> 4. saving sreg, rampD, rampX, rampY, rampD, eind in HW representation
>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
(please include my reviewed-by tag in the commit message for this
patch if/when you send out future versions of the patchset,
unless you make changes to this patch. That way I know I don't
need to look at it again next time around.)
thanks
-- PMM
^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 2/9] target-avr: adding AVR CPU features/flavors
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 1/9] target-avr: AVR cores support is added Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 18:14 ` Peter Maydell
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 3/9] target-avr: adding a sample AVR board Michael Rolnik
` (10 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/cpu.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
target-avr/cpu.h | 48 +++++++++
2 files changed, 359 insertions(+)
diff --git a/target-avr/cpu.c b/target-avr/cpu.c
index e99f804..d817266 100644
--- a/target-avr/cpu.c
+++ b/target-avr/cpu.c
@@ -200,12 +200,323 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data)
dc->cannot_destroy_with_object_finalize_yet = true;
}
+static void avr_avr1_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+}
+
+static void avr_avr2_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+}
+
+static void avr_avr25_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+}
+
+static void avr_avr3_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+}
+
+static void avr_avr31_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+}
+
+static void avr_avr35_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+}
+
+static void avr_avr4_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr5_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr51_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr6_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_xmega2_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega4_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega5_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPD);
+ avr_set_feature(env, AVR_FEATURE_RAMPX);
+ avr_set_feature(env, AVR_FEATURE_RAMPY);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega6_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega7_initfn(Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPD);
+ avr_set_feature(env, AVR_FEATURE_RAMPX);
+ avr_set_feature(env, AVR_FEATURE_RAMPY);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
typedef struct AVRCPUInfo {
const char *name;
void (*initfn)(Object *obj);
} AVRCPUInfo;
static const AVRCPUInfo avr_cpus[] = {
+ {.name = "avr1", .initfn = avr_avr1_initfn},
+ {.name = "avr2", .initfn = avr_avr2_initfn},
+ {.name = "avr25", .initfn = avr_avr25_initfn},
+ {.name = "avr3", .initfn = avr_avr3_initfn},
+ {.name = "avr31", .initfn = avr_avr31_initfn},
+ {.name = "avr35", .initfn = avr_avr35_initfn},
+ {.name = "avr4", .initfn = avr_avr4_initfn},
+ {.name = "avr5", .initfn = avr_avr5_initfn},
+ {.name = "avr51", .initfn = avr_avr51_initfn},
+ {.name = "avr6", .initfn = avr_avr6_initfn},
+ {.name = "xmega2", .initfn = avr_xmega2_initfn},
+ {.name = "xmega4", .initfn = avr_xmega4_initfn},
+ {.name = "xmega5", .initfn = avr_xmega5_initfn},
+ {.name = "xmega6", .initfn = avr_xmega6_initfn},
+ {.name = "xmega7", .initfn = avr_xmega7_initfn},
};
static gint avr_cpu_list_compare(gconstpointer a, gconstpointer b)
diff --git a/target-avr/cpu.h b/target-avr/cpu.h
index bf02bca..f18528e 100644
--- a/target-avr/cpu.h
+++ b/target-avr/cpu.h
@@ -78,6 +78,42 @@
#define AVR_CPU_REGS_LAST (AVR_CPU_REGS_BASE + AVR_CPU_REGS - 1)
#define AVR_CPU_IO_REGS_LAST (AVR_CPU_IO_REGS_BASE + AVR_CPU_IO_REGS - 1)
+enum avr_features {
+ 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,
+};
+
typedef struct CPUAVRState CPUAVRState;
struct CPUAVRState {
@@ -104,10 +140,22 @@ struct CPUAVRState {
uint64_t intsrc; /* interrupt sources */
+ uint32_t features;
+
/* Those resources are used only in QEMU core */
CPU_COMMON
};
+static inline int avr_feature(CPUAVRState *env, int feature)
+{
+ return (env->features & (1U << feature)) != 0;
+}
+
+static inline void avr_set_feature(CPUAVRState *env, int feature)
+{
+ env->features |= (1U << feature);
+}
+
#define cpu_list avr_cpu_list
#define cpu_signal_handler cpu_avr_signal_handler
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 3/9] target-avr: adding a sample AVR board
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 1/9] target-avr: AVR cores support is added Michael Rolnik
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 2/9] target-avr: adding AVR CPU features/flavors Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 18:14 ` Peter Maydell
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 4/9] target-avr: adding instructions encodings Michael Rolnik
` (9 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
MAINTAINERS | 1 +
hw/avr/Makefile.objs | 21 ++++++++++
hw/avr/sample.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 134 insertions(+)
create mode 100644 hw/avr/Makefile.objs
create mode 100644 hw/avr/sample.c
diff --git a/MAINTAINERS b/MAINTAINERS
index c793e90..f38b997 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -114,6 +114,7 @@ AVR
M: Michael Rolnik <mrolnik@gmail.com>
S: Maintained
F: target-avr/
+F: hw/avr/
CRIS
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs
new file mode 100644
index 0000000..8f537c9
--- /dev/null
+++ b/hw/avr/Makefile.objs
@@ -0,0 +1,21 @@
+#
+# QEMU AVR CPU
+#
+# Copyright (c) 2016 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
+# <http://www.gnu.org/licenses/lgpl-2.1.html>
+#
+
+obj-y += sample.o
diff --git a/hw/avr/sample.c b/hw/avr/sample.c
new file mode 100644
index 0000000..e1cf56c
--- /dev/null
+++ b/hw/avr/sample.c
@@ -0,0 +1,112 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+/*
+ * NOTE:
+ * This is not a real AVR board !!! This is an example !!!
+ *
+ * This example can be used to build a real AVR board.
+ *
+ * This example board loads provided binary file into flash memory and
+ * executes it from 0x00000000 address in the code memory space.
+ *
+ * Currently used for AVR CPU validation
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "ui/console.h"
+#include "hw/boards.h"
+#include "hw/devices.h"
+#include "hw/loader.h"
+#include "qemu/error-report.h"
+#include "exec/address-spaces.h"
+#include "include/hw/sysbus.h"
+
+#define VIRT_BASE_FLASH 0x00000000
+#define VIRT_BASE_ISRAM 0x00000100
+#define VIRT_BASE_EXMEM 0x00001100
+#define VIRT_BASE_EEPROM 0x00000000
+
+#define SIZE_FLASH 0x00020000
+#define SIZE_ISRAM 0x00001000
+#define SIZE_EXMEM 0x00010000
+#define SIZE_EEPROM 0x00001000
+#define SIZE_IOREG SIZE_REGS
+
+#define PHYS_BASE_FLASH (PHYS_BASE_CODE)
+
+#define PHYS_BASE_ISRAM (PHYS_BASE_DATA)
+#define PHYS_BASE_EXMEM (PHYS_BASE_ISRAM + SIZE_ISRAM)
+#define PHYS_BASE_EEPROM (PHYS_BASE_EXMEM + SIZE_EXMEM)
+
+#define PHYS_BASE_IOREG (PHYS_BASE_REGS + 0x20)
+
+static void sample_init(MachineState *machine)
+{
+ MemoryRegion *address_space_mem;
+ MemoryRegion *ram;
+ MemoryRegion *flash;
+ unsigned ram_size = SIZE_ISRAM + SIZE_EXMEM;
+ AVRCPU *cpu_avr ATTRIBUTE_UNUSED;
+ const char *firmware = NULL;
+ const char *filename;
+
+ address_space_mem = get_system_memory();
+ ram = g_new(MemoryRegion, 1);
+ flash = g_new(MemoryRegion, 1);
+
+ cpu_avr = cpu_avr_init("avr5");
+
+ memory_region_allocate_system_memory(ram, NULL, "avr.ram", ram_size);
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_ISRAM, ram);
+
+ memory_region_init_rom(flash, NULL, "avr.flash", SIZE_FLASH, &error_fatal);
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_FLASH, flash);
+ vmstate_register_ram_global(flash);
+
+ if (machine->firmware) {
+ firmware = machine->firmware;
+ }
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware);
+ if (!filename) {
+ error_report("Could not find flash image file '%s'", firmware);
+ exit(1);
+ }
+
+ load_image_targphys(filename, PHYS_BASE_FLASH, SIZE_FLASH);
+}
+
+static void sample_machine_init(MachineClass *mc)
+{
+ mc->desc = "AVR sample/example board";
+ mc->init = sample_init;
+ mc->is_default = 1;
+}
+
+DEFINE_MACHINE("sample", sample_machine_init)
+
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 3/9] target-avr: adding a sample AVR board
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 3/9] target-avr: adding a sample AVR board Michael Rolnik
@ 2016-08-18 18:14 ` Peter Maydell
0 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2016-08-18 18:14 UTC (permalink / raw)
To: Michael Rolnik; +Cc: QEMU Developers, Richard Henderson
On 18 August 2016 at 13:07, Michael Rolnik <mrolnik@gmail.com> wrote:
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> ---
> MAINTAINERS | 1 +
> hw/avr/Makefile.objs | 21 ++++++++++
> hw/avr/sample.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 134 insertions(+)
> create mode 100644 hw/avr/Makefile.objs
> create mode 100644 hw/avr/sample.c
>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 4/9] target-avr: adding instructions encodings
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (2 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 3/9] target-avr: adding a sample AVR board Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 5/9] target-avr: adding AVR interrupt handling Michael Rolnik
` (8 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/translate-inst.h | 805 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 805 insertions(+)
create mode 100644 target-avr/translate-inst.h
diff --git a/target-avr/translate-inst.h b/target-avr/translate-inst.h
new file mode 100644
index 0000000..9dc22a0
--- /dev/null
+++ b/target-avr/translate-inst.h
@@ -0,0 +1,805 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#ifndef AVR_TRANSLATE_INST_H_
+#define AVR_TRANSLATE_INST_H_
+
+typedef struct DisasContext DisasContext;
+
+int avr_translate_NOP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_MOVW(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MOVW_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+
+static inline uint32_t MOVW_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+int avr_translate_MULS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MULS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+
+static inline uint32_t MULS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+int avr_translate_MULSU(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MULSU_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t MULSU_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_FMUL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t FMUL_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t FMUL_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_FMULS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t FMULS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t FMULS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_FMULSU(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t FMULSU_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t FMULSU_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_CPC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CPC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t CPC_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_SBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t SBC_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_ADD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ADD_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t ADD_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_AND(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t AND_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t AND_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_EOR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t EOR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t EOR_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_OR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t OR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t OR_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_MOV(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MOV_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t MOV_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_CPSE(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CPSE_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t CPSE_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_CP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CP_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t CP_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_SUB(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SUB_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t SUB_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_ADC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ADC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t ADC_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_CPI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CPI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+static inline uint32_t CPI_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 8, 4) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_SBCI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBCI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+static inline uint32_t SBCI_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 8, 4) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_ORI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ORI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+static inline uint32_t ORI_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 8, 4) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_SUBI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SUBI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+static inline uint32_t SUBI_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 8, 4) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_ANDI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ANDI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+static inline uint32_t ANDI_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 8, 4) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_LDDZ(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDDZ_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t LDDZ_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 13, 1) << 5) |
+ (extract32(opcode, 10, 2) << 3) |
+ (extract32(opcode, 0, 3));
+}
+
+int avr_translate_LDDY(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDDY_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t LDDY_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 13, 1) << 5) |
+ (extract32(opcode, 10, 2) << 3) |
+ (extract32(opcode, 0, 3));
+}
+
+int avr_translate_STDZ(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STDZ_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t STDZ_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 13, 1) << 5) |
+ (extract32(opcode, 10, 2) << 3) |
+ (extract32(opcode, 0, 3));
+}
+
+int avr_translate_STDY(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STDY_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t STDY_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 13, 1) << 5) |
+ (extract32(opcode, 10, 2) << 3) |
+ (extract32(opcode, 0, 3));
+}
+
+int avr_translate_LDS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 16);
+}
+
+static inline uint32_t LDS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 20, 5);
+}
+
+int avr_translate_LDZ2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDZ2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDZ3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDZ3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LPM2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LPM2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LPMX(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LPMX_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ELPM2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ELPM2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ELPMX(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ELPMX_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDY2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDY2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDY3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDY3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDX1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDX1_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDX2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDX2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDX3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDX3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_POP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t POP_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 16);
+}
+
+static inline uint32_t STS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 20, 5);
+}
+
+int avr_translate_STZ2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STZ2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STZ3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STZ3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_XCH(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t XCH_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LAS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LAS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LAC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LAC_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LAT(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LAT_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STY2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STY2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STY3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STY3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STX1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STX1_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STX2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STX2_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STX3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STX3_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_PUSH(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t PUSH_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_COM(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t COM_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_NEG(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t NEG_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_SWAP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SWAP_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_INC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t INC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ASR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ASR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LSR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LSR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ROR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ROR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_BSET(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BSET_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_IJMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_EIJMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_BCLR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BCLR_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_RET(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_RETI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_ICALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_EICALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_SLEEP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_BREAK(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_WDR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_LPM1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_ELPM1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_SPM(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_SPMX(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_DEC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t DEC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_DES(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t DES_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+int avr_translate_JMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t JMP_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 20, 5) << 17) |
+ (extract32(opcode, 0, 17));
+}
+
+int avr_translate_CALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CALL_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 20, 5) << 17) |
+ (extract32(opcode, 0, 17));
+}
+
+int avr_translate_ADIW(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ADIW_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 2);
+}
+
+static inline uint32_t ADIW_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 6, 2) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_SBIW(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBIW_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 2);
+}
+
+static inline uint32_t SBIW_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 6, 2) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_CBI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CBI_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t CBI_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_SBIC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBIC_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t SBIC_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_SBI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBI_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t SBI_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_SBIS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBIS_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t SBIS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_MUL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MUL_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t MUL_Rr(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 1) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_IN(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t IN_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t IN_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 2) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_OUT(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t OUT_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+static inline uint32_t OUT_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 9, 2) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_RJMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t RJMP_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 12);
+}
+
+int avr_translate_LDI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+static inline uint32_t LDI_Imm(uint32_t opcode)
+{
+ return (extract32(opcode, 8, 4) << 4) |
+ (extract32(opcode, 0, 4));
+}
+
+int avr_translate_RCALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t RCALL_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 12);
+}
+
+int avr_translate_BRBS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BRBS_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t BRBS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 7);
+}
+
+int avr_translate_BRBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BRBC_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t BRBC_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 7);
+}
+
+int avr_translate_BLD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BLD_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t BLD_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_BST(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BST_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t BST_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_SBRC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBRC_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t SBRC_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_SBRS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBRS_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+
+static inline uint32_t SBRS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+#endif
+
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 5/9] target-avr: adding AVR interrupt handling
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (3 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 4/9] target-avr: adding instructions encodings Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 18:32 ` Peter Maydell
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 6/9] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions Michael Rolnik
` (7 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/helper.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/target-avr/helper.c b/target-avr/helper.c
index b48222d..8511fb7 100644
--- a/target-avr/helper.c
+++ b/target-avr/helper.c
@@ -32,11 +32,66 @@
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; /* TODO: where to get it */
+
+ 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,
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 5/9] target-avr: adding AVR interrupt handling
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 5/9] target-avr: adding AVR interrupt handling Michael Rolnik
@ 2016-08-18 18:32 ` Peter Maydell
0 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2016-08-18 18:32 UTC (permalink / raw)
To: Michael Rolnik; +Cc: QEMU Developers, Richard Henderson
On 18 August 2016 at 13:07, Michael Rolnik <mrolnik@gmail.com> wrote:
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> ---
> target-avr/helper.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 55 insertions(+)
>
> diff --git a/target-avr/helper.c b/target-avr/helper.c
> index b48222d..8511fb7 100644
> --- a/target-avr/helper.c
> +++ b/target-avr/helper.c
> @@ -32,11 +32,66 @@
> 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;
> + }
> + }
Are you sure that you need to handle CPU_INTERRUPT_RESET here?
It looks to me like the code in cpu-exec.c should deal with it
for you.
> + 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 */
I think clearing the env->intsrc bit should go in avr_cpu_do_interrupt().
> + cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
I'm not sure what the interrupt model for this CPU is,
but other CPU models don't do this, so maybe you don't
want to either. (The usual model is that CPU_INTERRUPT_HARD
corresponds to an interrupt input signal to the CPU;
for instance on ARM it's the IRQ line. When the signal
goes high we call cpu_interrupt(cs, CPU_INTERRUPT_HARD)
which sets the bit, and when it goes low we call
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD) which clears
the bit.)
> +
> + 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; /* TODO: where to get it */
> +
> + if (cs->exception_index == EXCP_RESET) {
> + vector = 0;
> + } else if (env->intsrc != 0) {
> + vector = ctz32(env->intsrc) + 1;
> + }
Should env->intsrc==0 really be treated like reset?
(If it's a can't-happen case then asserting would probably be good.)
> +
> + 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,
> --
> 2.4.9 (Apple Git-60)
thanks
-- PMM
^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 6/9] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (4 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 5/9] target-avr: adding AVR interrupt handling Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 18:16 ` Peter Maydell
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 7/9] target-avr: adding instruction translation Michael Rolnik
` (6 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/cpu.h | 10 ++
target-avr/helper.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++-
target-avr/helper.h | 7 ++
target-avr/translate.c | 8 ++
4 files changed, 277 insertions(+), 4 deletions(-)
diff --git a/target-avr/cpu.h b/target-avr/cpu.h
index f18528e..4d40fc9 100644
--- a/target-avr/cpu.h
+++ b/target-avr/cpu.h
@@ -139,6 +139,7 @@ struct CPUAVRState {
uint32_t sp; /* 16 bits */
uint64_t intsrc; /* interrupt sources */
+ bool fullacc;/* CPU/MEM if true MEM only otherwise */
uint32_t features;
@@ -181,6 +182,10 @@ int avr_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
int len, bool is_write);
+enum {
+ TB_FLAGS_FULL_ACCESS = 1,
+};
+
static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
@@ -188,6 +193,11 @@ static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
*pc = env->pc_w * 2;
*cs_base = 0;
+
+ if (env->fullacc) {
+ flags |= TB_FLAGS_FULL_ACCESS;
+ }
+
*pflags = flags;
}
diff --git a/target-avr/helper.c b/target-avr/helper.c
index 8511fb7..378153f 100644
--- a/target-avr/helper.c
+++ b/target-avr/helper.c
@@ -28,6 +28,7 @@
#include "exec/cpu_ldst.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
+#include "exec/ioport.h"
bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
@@ -79,11 +80,11 @@ void avr_cpu_do_interrupt(CPUState *cs)
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 & 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);
+ cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8);
} else {
cpu_stb_data(env, env->sp--, (ret & 0x0000ff));
}
@@ -127,13 +128,55 @@ void tlb_fill(CPUState *cs, target_ulong vaddr, MMUAccessType access_type,
paddr = PHYS_BASE_CODE + vaddr - VIRT_BASE_CODE;
prot = PAGE_READ | PAGE_EXEC;
} else {
- paddr = PHYS_BASE_DATA + vaddr - VIRT_BASE_DATA;
- prot = PAGE_READ | PAGE_WRITE;
+#if VIRT_BASE_REGS == 0
+ if (vaddr < VIRT_BASE_REGS + AVR_REGS) {
+#else
+ if (VIRT_BASE_REGS <= vaddr && vaddr < VIRT_BASE_REGS + SIZE_REGS) {
+#endif
+ /*
+ * this is a write into CPU registers, exit and rebuilt this TB
+ * to use full write
+ */
+ AVRCPU *cpu = AVR_CPU(cs);
+ CPUAVRState *env = &cpu->env;
+ env->fullacc = 1;
+ cpu_loop_exit_restore(cs, retaddr);
+ } else {
+ /*
+ * this is a write into memory. nothing special
+ */
+ paddr = PHYS_BASE_DATA + vaddr - VIRT_BASE_DATA;
+ prot = PAGE_READ | PAGE_WRITE;
+ }
}
tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
}
+void helper_sleep(CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_HLT;
+ cpu_loop_exit(cs);
+}
+
+void helper_unsupported(CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_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, qemu_logfile, fprintf, 0);
+ }
+ cpu_loop_exit(cs);
+}
+
void helper_debug(CPUAVRState *env)
{
CPUState *cs = CPU(avr_env_get_cpu(env));
@@ -142,3 +185,208 @@ void helper_debug(CPUAVRState *env)
cpu_loop_exit(cs);
}
+void helper_wdr(CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_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: {
+ data = 0xff & (env->rampD >> 16); /* RAMPD */
+ break;
+ }
+ case 0x39: {
+ data = 0xff & (env->rampX >> 16); /* RAMPX */
+ break;
+ }
+ case 0x3a: {
+ data = 0xff & (env->rampY >> 16); /* RAMPY */
+ break;
+ }
+ case 0x3b: {
+ data = 0xff & (env->rampZ >> 16); /* RAMPZ */
+ break;
+ }
+ case 0x3c: {
+ data = 0xff & (env->eind >> 16); /* EIND */
+ 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: {
+ /*
+ * CPU does not know how to read this register, pass it to the
+ * device/board
+ */
+
+ cpu_physical_memory_read(PHYS_BASE_REGS + port
+ + AVR_CPU_IO_REGS_BASE, &data, 1);
+ }
+ }
+
+ 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 0x04: {
+ qemu_irq irq;
+ CPUState *cpu = CPU(avr_env_get_cpu(env));
+ irq = qdev_get_gpio_in(DEVICE(cpu), 3);
+ qemu_set_irq(irq, 1);
+ break;
+ }
+ case 0x38: {
+ if (avr_feature(env, AVR_FEATURE_RAMPD)) {
+ env->rampD = (data & 0xff) << 16; /* RAMPD */
+ }
+ break;
+ }
+ case 0x39: {
+ if (avr_feature(env, AVR_FEATURE_RAMPX)) {
+ env->rampX = (data & 0xff) << 16; /* RAMPX */
+ }
+ break;
+ }
+ case 0x3a: {
+ if (avr_feature(env, AVR_FEATURE_RAMPY)) {
+ env->rampY = (data & 0xff) << 16; /* RAMPY */
+ }
+ break;
+ }
+ case 0x3b: {
+ if (avr_feature(env, AVR_FEATURE_RAMPZ)) {
+ env->rampZ = (data & 0xff) << 16; /* RAMPZ */
+ }
+ break;
+ }
+ case 0x3c: {
+ env->eind = (data & 0xff) << 16; /* EIDN */
+ 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: {
+ /*
+ * CPU does not know how to write this register, pass it to the
+ * device/board
+ */
+ cpu_physical_memory_write(PHYS_BASE_REGS + port
+ + AVR_CPU_IO_REGS_BASE, &data, 1);
+ }
+ }
+}
+
+/*
+ * 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;
+ switch (addr) {
+ /* CPU registers */
+ case AVR_CPU_REGS_BASE ... AVR_CPU_REGS_LAST: {
+ data = env->r[addr - AVR_CPU_REGS_BASE];
+ break;
+ }
+ /* CPU IO registers */
+ case AVR_CPU_IO_REGS_BASE ... AVR_CPU_IO_REGS_LAST: {
+ data = helper_inb(env, addr);
+ break;
+ }
+
+ /* memory */
+ default: {
+ cpu_physical_memory_read(PHYS_BASE_DATA + addr - VIRT_BASE_DATA,
+ &data, 1);
+ }
+ }
+
+ env->fullacc = false;
+
+ return data;
+}
+
+/*
+ * this function implements LD instruction when there is a posibility to write
+ * into a CPU register
+ */
+void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr)
+{
+ switch (addr) {
+ /* CPU registers */
+ case AVR_CPU_REGS_BASE ... AVR_CPU_REGS_LAST: {
+ env->r[addr - AVR_CPU_REGS_BASE] = data;
+ break;
+ }
+
+ /* CPU IO registers */
+ case AVR_CPU_IO_REGS_BASE ... AVR_CPU_IO_REGS_LAST: {
+ helper_outb(env, data, addr);
+ break;
+ }
+
+ /* memory */
+ default: {
+ cpu_physical_memory_write(PHYS_BASE_DATA + addr - VIRT_BASE_DATA,
+ &data, 1);
+ }
+ }
+
+ env->fullacc = false;
+}
+
diff --git a/target-avr/helper.h b/target-avr/helper.h
index c60ac3e..a533d2a 100644
--- a/target-avr/helper.h
+++ b/target-avr/helper.h
@@ -18,5 +18,12 @@
* <http://www.gnu.org/licenses/lgpl-2.1.html>
*/
+DEF_HELPER_1(wdr, void, env)
DEF_HELPER_1(debug, 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/target-avr/translate.c b/target-avr/translate.c
index b5ca59e..0fa8292 100644
--- a/target-avr/translate.c
+++ b/target-avr/translate.c
@@ -128,6 +128,14 @@ void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb)
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
+ 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;
+ }
gen_tb_start(tb);
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 6/9] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 6/9] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions Michael Rolnik
@ 2016-08-18 18:16 ` Peter Maydell
0 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2016-08-18 18:16 UTC (permalink / raw)
To: Michael Rolnik; +Cc: QEMU Developers, Richard Henderson
On 18 August 2016 at 13:07, Michael Rolnik <mrolnik@gmail.com> wrote:
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> @@ -79,11 +80,11 @@ void avr_cpu_do_interrupt(CPUState *cs)
>
> 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 & 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);
> + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8);
> } else {
> cpu_stb_data(env, env->sp--, (ret & 0x0000ff));
> }
These whitespace changes should be squashed into the commit where the
code was added.
thanks
-- PMM
^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 7/9] target-avr: adding instruction translation
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (5 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 6/9] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 8/9] target-avr: instruction decoder generator Michael Rolnik
` (5 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/Makefile.objs | 1 +
target-avr/translate-inst.c | 2641 +++++++++++++++++++++++++++++++++++++++++++
target-avr/translate.h | 1 +
3 files changed, 2643 insertions(+)
create mode 100644 target-avr/translate-inst.c
diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs
index 85f9261..f4a82c4 100644
--- a/target-avr/Makefile.objs
+++ b/target-avr/Makefile.objs
@@ -20,5 +20,6 @@
obj-y += translate.o cpu.o helper.o
obj-y += gdbstub.o
+obj-y += translate-inst.o
obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-avr/translate-inst.c b/target-avr/translate-inst.c
new file mode 100644
index 0000000..a0beebc
--- /dev/null
+++ b/target-avr/translate-inst.c
@@ -0,0 +1,2641 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "translate.h"
+#include "translate-inst.h"
+#include "qemu/bitops.h"
+
+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();
+
+ /* Cf & Hf */
+ 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();
+
+ /* Vf */
+ /* 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_mov_tl(cpu_Zf, R); /* Zf = 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_push_ret(CPUAVRState *env, int ret)
+{
+ if (avr_feature(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(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(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(CPUAVRState *env, TCGv ret)
+{
+ if (avr_feature(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(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(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_jmp_ez(void)
+{
+ tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
+ tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
+ tcg_gen_exit_tb(0);
+}
+
+static void gen_jmp_z(void)
+{
+ tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
+ tcg_gen_exit_tb(0);
+}
+
+/*
+ * 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]);
+}
+
+/*
+ * Adds two registers and the contents of the C Flag and places the result in
+ * the destination register Rd.
+ */
+int avr_translate_ADC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ADC_Rd(opcode)];
+ TCGv Rr = cpu_r[ADC_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_add_CHf(R, Rd, Rr);
+ gen_add_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * Adds two registers without the C Flag and places the result in the
+ * destination register Rd.
+ */
+int avr_translate_ADD(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ADD_Rd(opcode)];
+ TCGv Rr = cpu_r[ADD_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_add_CHf(R, Rd, Rr);
+ gen_add_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_ADIW(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ADIW_SBIW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[24 + 2 * ADIW_Rd(opcode)];
+ TCGv RdH = cpu_r[25 + 2 * ADIW_Rd(opcode)];
+ int Imm = (ADIW_Imm(opcode));
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ /* Cf */
+ tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
+ tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
+
+ /* Vf */
+ tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
+ tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
+
+ /* Zf */
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+
+ /* Nf */
+ tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
+
+ /* Sf */
+ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
+
+ /* R */
+ 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 BS_NONE;
+}
+
+/*
+ * Performs the logical AND between the contents of register Rd and register
+ * Rr and places the result in the destination register Rd.
+ */
+int avr_translate_AND(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[AND_Rd(opcode)];
+ TCGv Rr = cpu_r[AND_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
+
+ /* Vf */
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+
+ /* Zf */
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * Performs the logical AND between the contents of register Rd and a constant
+ * and places the result in the destination register Rd.
+ */
+int avr_translate_ANDI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + ANDI_Rd(opcode)];
+ int Imm = (ANDI_Imm(opcode));
+
+ /* op */
+ tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
+
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_ASR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ASR_Rd(opcode)];
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_andi_tl(t1, Rd, 0x80); /* t1 = (Rd & 0x80) | (Rd >> 1) */
+ tcg_gen_shri_tl(t2, Rd, 1);
+ tcg_gen_or_tl(t1, t1, t2);
+
+ /* Cf */
+ tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */
+
+ /* Vf */
+ tcg_gen_and_tl(cpu_Vf, cpu_Nf, cpu_Cf);/* Vf = Nf & Cf */
+
+ gen_ZNSf(t1);
+
+ /* op */
+ tcg_gen_mov_tl(Rd, t1);
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+
+ return BS_NONE;
+}
+
+/*
+ * Clears a single Flag in SREG.
+ */
+int avr_translate_BCLR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ switch (BCLR_Bit(opcode)) {
+ case 0x00: {
+ tcg_gen_movi_tl(cpu_Cf, 0x00);
+ break;
+ }
+ case 0x01: {
+ tcg_gen_movi_tl(cpu_Zf, 0x01);
+ 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 BS_NONE;
+}
+
+/*
+ * Copies the T Flag in the SREG (Status Register) to bit b in register Rd.
+ */
+int avr_translate_BLD(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[BLD_Rd(opcode)];
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_andi_tl(Rd, Rd, ~(1u << BLD_Bit(opcode))); /* clear bit */
+ tcg_gen_shli_tl(t1, cpu_Tf, BLD_Bit(opcode)); /* create mask */
+ tcg_gen_or_tl(Rd, Rd, t1);
+
+ tcg_temp_free_i32(t1);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_BRBC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGLabel *taken = gen_new_label();
+ int Imm = sextract32(BRBC_Imm(opcode), 0, 7);
+
+ switch (BRBC_Bit(opcode)) {
+ case 0x00: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Cf, 0, taken);
+ break;
+ }
+ case 0x01: {
+ tcg_gen_brcondi_i32(TCG_COND_NE, cpu_Zf, 0, taken);
+ break;
+ }
+ case 0x02: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Nf, 0, taken);
+ break;
+ }
+ case 0x03: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Vf, 0, taken);
+ break;
+ }
+ case 0x04: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Sf, 0, taken);
+ break;
+ }
+ case 0x05: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Hf, 0, taken);
+ break;
+ }
+ case 0x06: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Tf, 0, taken);
+ break;
+ }
+ case 0x07: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_If, 0, taken);
+ break;
+ }
+ }
+
+ gen_goto_tb(env, ctx, 1, ctx->inst[0].npc);
+ gen_set_label(taken);
+ gen_goto_tb(env, ctx, 0, ctx->inst[0].npc + Imm);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_BRBS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGLabel *taken = gen_new_label();
+ int Imm = sextract32(BRBS_Imm(opcode), 0, 7);
+
+ switch (BRBS_Bit(opcode)) {
+ case 0x00: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Cf, 1, taken);
+ break;
+ }
+ case 0x01: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Zf, 0, taken);
+ break;
+ }
+ case 0x02: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Nf, 1, taken);
+ break;
+ }
+ case 0x03: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Vf, 1, taken);
+ break;
+ }
+ case 0x04: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Sf, 1, taken);
+ break;
+ }
+ case 0x05: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Hf, 1, taken);
+ break;
+ }
+ case 0x06: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Tf, 1, taken);
+ break;
+ }
+ case 0x07: {
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_If, 1, taken);
+ break;
+ }
+ }
+
+ gen_goto_tb(env, ctx, 1, ctx->inst[0].npc);
+ gen_set_label(taken);
+ gen_goto_tb(env, ctx, 0, ctx->inst[0].npc + Imm);
+
+ return BS_BRANCH;
+}
+
+/*
+ * Sets a single Flag or bit in SREG.
+ */
+int avr_translate_BSET(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ switch (BSET_Bit(opcode)) {
+ case 0x00: {
+ tcg_gen_movi_tl(cpu_Cf, 0x01);
+ break;
+ }
+ case 0x01: {
+ tcg_gen_movi_tl(cpu_Zf, 0x00);
+ 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_BREAK(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_BREAK) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+/*
+ * Stores bit b from Rd to the T Flag in SREG (Status Register).
+ */
+int avr_translate_BST(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[BST_Rd(opcode)];
+
+ tcg_gen_andi_tl(cpu_Tf, Rd, 1 << BST_Bit(opcode));
+ tcg_gen_shri_tl(cpu_Tf, cpu_Tf, BST_Bit(opcode));
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_CALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_JMP_CALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int Imm = CALL_Imm(opcode);
+ int ret = ctx->inst[0].npc;
+
+ gen_push_ret(env, ret);
+
+ gen_goto_tb(env, ctx, 0, Imm);
+
+ return BS_BRANCH;
+}
+
+/*
+ * Clears a specified bit in an I/O Register. This instruction operates on
+ * the lower 32 I/O Registers – addresses 0-31.
+ */
+int avr_translate_CBI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv data = tcg_temp_new_i32();
+ TCGv port = tcg_const_i32(CBI_Imm(opcode));
+
+ gen_helper_inb(data, cpu_env, port);
+ tcg_gen_andi_tl(data, data, ~(1 << CBI_Bit(opcode)));
+ gen_helper_outb(cpu_env, port, data);
+
+ tcg_temp_free_i32(data);
+ tcg_temp_free_i32(port);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_COM(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[COM_Rd(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_xori_tl(Rd, Rd, 0xff);
+
+ 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_CP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CP_Rd(opcode)];
+ TCGv Rr = cpu_r[CP_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_CPC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CPC_Rd(opcode)];
+ TCGv Rr = cpu_r[CPC_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ 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_or_tl(cpu_Zf, cpu_Zf, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_CPI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + CPI_Rd(opcode)];
+ int Imm = CPI_Imm(opcode);
+ TCGv Rr = tcg_const_i32(Imm);
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ 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 BS_NONE;
+}
+
+/*
+ * This instruction performs a compare between two registers Rd and Rr, and
+ * skips the next instruction if Rd = Rr.
+ */
+int avr_translate_CPSE(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CPSE_Rd(opcode)];
+ TCGv Rr = cpu_r[CPSE_Rr(opcode)];
+ TCGLabel *skip = gen_new_label();
+
+ /* PC if next inst is skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc);
+ tcg_gen_brcond_i32(TCG_COND_EQ, Rd, Rr, skip);
+ /* PC if next inst is not skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc);
+ gen_set_label(skip);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_DEC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[DEC_Rd(opcode)];
+
+ tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
+ tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
+
+ /* cpu_Vf = Rd == 0x7f */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f);
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_DES(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ /* TODO: */
+ if (avr_feature(env, AVR_FEATURE_DES) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_EICALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_EIJMP_EICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int ret = ctx->inst[0].npc;
+
+ gen_push_ret(env, ret);
+
+ gen_jmp_ez();
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_EIJMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_EIJMP_EICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_jmp_ez();
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ * Refer to the device documentation for a detailed description. This
+ * instruction is not available in all devices. Refer to the device specific
+ * instruction set summary.
+ */
+int avr_translate_ELPM1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ 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 BS_NONE;
+}
+
+int avr_translate_ELPM2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[ELPM2_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_ELPMX(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[ELPMX_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+/*
+ * Performs the logical EOR between the contents of register Rd and
+ * register Rr and places the result in the destination register Rd.
+ */
+int avr_translate_EOR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[EOR_Rd(opcode)];
+ TCGv Rr = cpu_r[EOR_Rr(opcode)];
+
+ tcg_gen_xor_tl(Rd, Rd, Rr);
+
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit unsigned
+ * multiplication and shifts the result one bit left.
+ */
+int avr_translate_FMUL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + FMUL_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + FMUL_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+ tcg_gen_shli_tl(R, R, 1);
+
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_andi_tl(R1, R, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
+ * and shifts the result one bit left.
+ */
+int avr_translate_FMULS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + FMULS_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + FMULS_Rr(opcode)];
+ 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_shli_tl(R, R, 1);
+
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_andi_tl(R1, R, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
+ * and shifts the result one bit left.
+ */
+int avr_translate_FMULSU(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + FMULSU_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + FMULSU_Rr(opcode)];
+ 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_shli_tl(R, R, 1);
+
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_andi_tl(R1, R, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_ICALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_IJMP_ICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int ret = ctx->inst[0].npc;
+
+ gen_push_ret(env, ret);
+ gen_jmp_z();
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_IJMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_IJMP_ICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_jmp_z();
+
+ return BS_BRANCH;
+}
+
+/*
+ * Loads data from the I/O Space (Ports, Timers, Configuration Registers,
+ * etc.) into register Rd in the Register File.
+ */
+int avr_translate_IN(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[IN_Rd(opcode)];
+ int Imm = IN_Imm(opcode);
+ TCGv port = tcg_const_i32(Imm);
+
+ gen_helper_inb(Rd, cpu_env, port);
+
+ tcg_temp_free_i32(port);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_INC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[INC_Rd(opcode)];
+
+ tcg_gen_addi_tl(Rd, Rd, 1);
+ tcg_gen_andi_tl(Rd, Rd, 0xff);
+
+ /* cpu_Vf = Rd == 0x80 */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80);
+ gen_ZNSf(Rd);
+ return BS_NONE;
+}
+
+/*
+ * 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
+ */
+int avr_translate_JMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_JMP_CALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_goto_tb(env, ctx, 0, JMP_Imm(opcode));
+ return BS_BRANCH;
+}
+
+/*
+ * 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] */
+ }
+}
+
+int avr_translate_LAC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[LAC_Rr(opcode)];
+ 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] */
+ /* t1 = t0 & (0xff - Rr) = t0 and ~Rr */
+ tcg_gen_andc_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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LAS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[LAS_Rr(opcode)];
+ 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LAT(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[LAT_Rr(opcode)];
+ 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, 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LDX1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDX1_Rd(opcode)];
+ TCGv addr = gen_get_xaddr();
+
+ gen_data_load(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDX2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDX2_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_LDX3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDX3_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LDY2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDY2_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_LDY3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDY3_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_LDDY(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDDY_Rd(opcode)];
+ TCGv addr = gen_get_yaddr();
+
+ tcg_gen_addi_tl(addr, addr, LDDY_Imm(opcode)); /* addr = addr + q */
+ gen_data_load(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LDZ2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDZ2_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_LDZ3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDZ3_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_LDDZ(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDDZ_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_addi_tl(addr, addr, LDDZ_Imm(opcode));
+ /* addr = addr + q */
+ gen_data_load(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Loads an 8 bit constant directly to register 16 to 31.
+ */
+int avr_translate_LDI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + LDI_Rd(opcode)];
+ int imm = LDI_Imm(opcode);
+
+ tcg_gen_movi_tl(Rd, imm);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LDS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDS_Rd(opcode)];
+ TCGv addr = tcg_temp_new_i32();
+ TCGv H = cpu_rampD;
+
+ tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 16);
+ tcg_gen_ori_tl(addr, addr, LDS_Imm(opcode));
+
+ gen_data_load(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ * 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. Refer to the device
+ * documentation for a detailed description. The LPM instruction is not
+ * available in all devices. Refer to the device specific instruction set
+ * summary
+ */
+int avr_translate_LPM1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_LPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ 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 BS_NONE;
+}
+
+int avr_translate_LPM2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_LPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[LPM2_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_LPMX(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_LPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[LPMX_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_LSR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LSR_Rd(opcode)];
+
+ tcg_gen_andi_tl(cpu_Cf, Rd, 1);
+
+ tcg_gen_shri_tl(Rd, Rd, 1);
+
+ gen_ZNSf(Rd);
+ tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_MOV(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[MOV_Rd(opcode)];
+ TCGv Rr = cpu_r[MOV_Rr(opcode)];
+
+ tcg_gen_mov_tl(Rd, Rr);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_MOVW(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MOVW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[MOVW_Rd(opcode) * 2 + 0];
+ TCGv RdH = cpu_r[MOVW_Rd(opcode) * 2 + 1];
+ TCGv RrL = cpu_r[MOVW_Rr(opcode) * 2 + 0];
+ TCGv RrH = cpu_r[MOVW_Rr(opcode) * 2 + 1];
+
+ tcg_gen_mov_tl(RdH, RrH);
+ tcg_gen_mov_tl(RdL, RrL);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
+ */
+int avr_translate_MUL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[MUL_Rd(opcode)];
+ TCGv Rr = cpu_r[MUL_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+
+ tcg_gen_mov_tl(R0, R);
+ tcg_gen_andi_tl(R0, R0, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_mov_tl(R1, R);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(16) */
+ tcg_gen_mov_tl(cpu_Zf, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
+ */
+int avr_translate_MULS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + MULS_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + MULS_Rr(opcode)];
+ 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_mov_tl(R0, R);
+ tcg_gen_andi_tl(R0, R0, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_mov_tl(R1, R);
+ tcg_gen_andi_tl(R1, R0, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(16) */
+ tcg_gen_mov_tl(cpu_Zf, R);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
+ * signed and an unsigned number.
+ */
+int avr_translate_MULSU(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + MULSU_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + MULSU_Rr(opcode)];
+ 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_mov_tl(R0, R);
+ tcg_gen_andi_tl(R0, R0, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_mov_tl(R1, R);
+ tcg_gen_andi_tl(R1, R0, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_mov_tl(cpu_Zf, R);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * Replaces the contents of register Rd with its two’s complement; the
+ * value $80 is left unchanged.
+ */
+int avr_translate_NEG(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SUB_Rd(opcode)];
+ TCGv t0 = tcg_const_i32(0);
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, t0, Rd);
+ gen_sub_Vf(R, t0, Rd);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * This instruction performs a single cycle No Operation.
+ */
+int avr_translate_NOP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+
+ /* NOP */
+
+ return BS_NONE;
+}
+
+/*
+ * Performs the logical OR between the contents of register Rd and register
+ * Rr and places the result in the destination register Rd.
+ */
+int avr_translate_OR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[OR_Rd(opcode)];
+ TCGv Rr = cpu_r[OR_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_or_tl(R, Rd, Rr);
+
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * Performs the logical OR between the contents of register Rd and a
+ * constant and places the result in the destination register Rd.
+ */
+int avr_translate_ORI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + ORI_Rd(opcode)];
+ int Imm = (ORI_Imm(opcode));
+
+ tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
+
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+ * Stores data from register Rr in the Register File to I/O Space (Ports,
+ * Timers, Configuration Registers, etc.).
+ */
+int avr_translate_OUT(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[OUT_Rd(opcode)];
+ int Imm = OUT_Imm(opcode);
+ TCGv port = tcg_const_i32(Imm);
+
+ gen_helper_outb(cpu_env, port, Rd);
+
+ tcg_temp_free_i32(port);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_POP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[POP_Rd(opcode)];
+
+ tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
+ gen_data_load(ctx, Rd, cpu_sp);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_PUSH(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[PUSH_Rd(opcode)];
+
+ gen_data_store(ctx, Rd, cpu_sp);
+ tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_RCALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ int ret = ctx->inst[0].npc;
+ int dst = ctx->inst[0].npc + sextract32(RCALL_Imm(opcode), 0, 12);
+
+ gen_push_ret(env, ret);
+
+ gen_goto_tb(env, ctx, 0, dst);
+
+ return BS_BRANCH;
+}
+
+/*
+ * Returns from subroutine. The return address is loaded from the STACK.
+ * The Stack Pointer uses a preincrement scheme during RET.
+ */
+int avr_translate_RET(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_pop_ret(env, cpu_pc);
+
+ tcg_gen_exit_tb(0);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_RETI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_pop_ret(env, cpu_pc);
+
+ tcg_gen_movi_tl(cpu_If, 1);
+
+ tcg_gen_exit_tb(0);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_RJMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ int dst = ctx->inst[0].npc + sextract32(RJMP_Imm(opcode), 0, 12);
+
+ gen_goto_tb(env, ctx, 0, dst);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_ROR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ROR_Rd(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+
+ tcg_gen_shli_tl(t0, cpu_Cf, 7);
+ tcg_gen_andi_tl(cpu_Cf, Rd, 0);
+ tcg_gen_shri_tl(Rd, Rd, 1);
+ tcg_gen_or_tl(Rd, Rd, t0);
+
+ gen_ZNSf(Rd);
+ tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_NONE;
+}
+
+/*
+ * Subtracts two registers and subtracts with the C Flag and places the
+ * result in the destination register Rd.
+ */
+int avr_translate_SBC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SBC_Rd(opcode)];
+ TCGv Rr = cpu_r[SBC_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * SBCI – Subtract Immediate with Carry
+ */
+int avr_translate_SBCI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + SBCI_Rd(opcode)];
+ TCGv Rr = tcg_const_i32(SBCI_Imm(opcode));
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+ tcg_temp_free_i32(Rr);
+
+ return BS_NONE;
+}
+
+/*
+ * Sets a specified bit in an I/O Register. This instruction operates on
+ * the lower 32 I/O Registers – addresses 0-31.
+ */
+int avr_translate_SBI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv data = tcg_temp_new_i32();
+ TCGv port = tcg_const_i32(SBI_Imm(opcode));
+
+ gen_helper_inb(data, cpu_env, port);
+ tcg_gen_ori_tl(data, data, 1 << SBI_Bit(opcode));
+ gen_helper_outb(cpu_env, port, data);
+
+ tcg_temp_free_i32(port);
+ tcg_temp_free_i32(data);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_SBIC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv data = tcg_temp_new_i32();
+ TCGv port = tcg_const_i32(SBIC_Imm(opcode));
+ TCGLabel *skip = gen_new_label();
+
+ gen_helper_inb(data, cpu_env, port);
+
+ /* PC if next inst is skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc);
+ tcg_gen_andi_tl(data, data, 1 << SBIC_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_EQ, data, 0, skip);
+ /* PC if next inst is not skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc);
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(port);
+ tcg_temp_free_i32(data);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_SBIS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv data = tcg_temp_new_i32();
+ TCGv port = tcg_const_i32(SBIS_Imm(opcode));
+ TCGLabel *skip = gen_new_label();
+
+ gen_helper_inb(data, cpu_env, port);
+
+ /* PC if next inst is skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc);
+ tcg_gen_andi_tl(data, data, 1 << SBIS_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_NE, data, 0, skip);
+ /* PC if next inst is not skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc);
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(port);
+ tcg_temp_free_i32(data);
+
+ return BS_BRANCH;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_SBIW(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ADIW_SBIW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[24 + 2 * SBIW_Rd(opcode)];
+ TCGv RdH = cpu_r[25 + 2 * SBIW_Rd(opcode)];
+ int Imm = (SBIW_Imm(opcode));
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ /* Cf */
+ tcg_gen_andc_tl(cpu_Cf, R, Rd);
+ tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
+
+ /* Vf */
+ tcg_gen_andc_tl(cpu_Vf, Rd, R);
+ tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
+
+ /* Zf */
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+
+ /* Nf */
+ tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
+
+ /* Sf */
+ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
+
+ /* R */
+ 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 BS_NONE;
+}
+
+/*
+ * This instruction tests a single bit in a register and skips the next
+ * instruction if the bit is cleared.
+ */
+int avr_translate_SBRC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rr = cpu_r[SBRC_Rr(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip = gen_new_label();
+
+ /* PC if next inst is skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc);
+ tcg_gen_andi_tl(t0, Rr, 1 << SBRC_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, skip);
+ /* PC if next inst is not skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc);
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_BRANCH;
+}
+
+/*
+ * This instruction tests a single bit in a register and skips the next
+ * instruction if the bit is set.
+ */
+int avr_translate_SBRS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rr = cpu_r[SBRS_Rr(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip = gen_new_label();
+
+ /* PC if next inst is skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc);
+ tcg_gen_andi_tl(t0, Rr, 1 << SBRS_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, skip);
+ /* PC if next inst is not skipped */
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc);
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_BRANCH;
+}
+
+/*
+ * This instruction sets the circuit in sleep mode defined by the MCU
+ * Control Register.
+ */
+int avr_translate_SLEEP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_helper_sleep(cpu_env);
+
+ return BS_EXCP;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_SPM(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_SPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+int avr_translate_SPMX(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_SPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+int avr_translate_STX1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STX1_Rr(opcode)];
+ TCGv addr = gen_get_xaddr();
+
+ gen_data_store(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STX2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STX2_Rr(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_STX3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STX3_Rr(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_STY2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STY2_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_STY3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STY3_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_STDY(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STDY_Rd(opcode)];
+ TCGv addr = gen_get_yaddr();
+
+ tcg_gen_addi_tl(addr, addr, STDY_Imm(opcode));
+ /* addr = addr + q */
+ gen_data_store(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STZ2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STZ2_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_STZ3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STZ3_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+int avr_translate_STDZ(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STDZ_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_addi_tl(addr, addr, STDZ_Imm(opcode));
+ /* addr = addr + q */
+ gen_data_store(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_STS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STS_Rd(opcode)];
+ TCGv addr = tcg_temp_new_i32();
+ TCGv H = cpu_rampD;
+
+ tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 16);
+ tcg_gen_ori_tl(addr, addr, STS_Imm(opcode));
+
+ gen_data_store(ctx, Rd, addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ * Subtracts two registers and places the result in the destination
+ * register Rd.
+ */
+int avr_translate_SUB(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SUB_Rd(opcode)];
+ TCGv Rr = cpu_r[SUB_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_SUBI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + SUBI_Rd(opcode)];
+ TCGv Rr = tcg_const_i32(SUBI_Imm(opcode));
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr);
+ /* R = Rd - Imm */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+ tcg_temp_free_i32(Rr);
+
+ return BS_NONE;
+}
+
+/*
+ * Swaps high and low nibbles in a register.
+ */
+int avr_translate_SWAP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SWAP_Rd(opcode)];
+ 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 BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_WDR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_helper_wdr(cpu_env);
+
+ return BS_NONE;
+}
+
+/*
+ * 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.
+ */
+int avr_translate_XCH(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[XCH_Rd(opcode)];
+ 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 BS_NONE;
+}
+
diff --git a/target-avr/translate.h b/target-avr/translate.h
index 9dc707e..444d235 100644
--- a/target-avr/translate.h
+++ b/target-avr/translate.h
@@ -33,6 +33,7 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "exec/log.h"
+#include "translate-inst.h"
extern TCGv_env cpu_env;
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 8/9] target-avr: instruction decoder generator
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (6 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 7/9] target-avr: adding instruction translation Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 9/9] target-avr: adding instruction decoder Michael Rolnik
` (4 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/cpugen/CMakeLists.txt | 38 +++
target-avr/cpugen/README.md | 17 ++
target-avr/cpugen/cpu/avr.yaml | 214 ++++++++++++++
target-avr/cpugen/src/CMakeLists.txt | 63 ++++
target-avr/cpugen/src/cpugen.cpp | 458 +++++++++++++++++++++++++++++
target-avr/cpugen/src/utils.cpp | 27 ++
target-avr/cpugen/src/utils.h | 79 +++++
target-avr/cpugen/xsl/decode.c.xsl | 103 +++++++
target-avr/cpugen/xsl/translate-inst.h.xsl | 118 ++++++++
target-avr/cpugen/xsl/utils.xsl | 108 +++++++
10 files changed, 1225 insertions(+)
create mode 100644 target-avr/cpugen/CMakeLists.txt
create mode 100644 target-avr/cpugen/README.md
create mode 100644 target-avr/cpugen/cpu/avr.yaml
create mode 100644 target-avr/cpugen/src/CMakeLists.txt
create mode 100644 target-avr/cpugen/src/cpugen.cpp
create mode 100644 target-avr/cpugen/src/utils.cpp
create mode 100644 target-avr/cpugen/src/utils.h
create mode 100644 target-avr/cpugen/xsl/decode.c.xsl
create mode 100644 target-avr/cpugen/xsl/translate-inst.h.xsl
create mode 100644 target-avr/cpugen/xsl/utils.xsl
diff --git a/target-avr/cpugen/CMakeLists.txt b/target-avr/cpugen/CMakeLists.txt
new file mode 100644
index 0000000..ded391c
--- /dev/null
+++ b/target-avr/cpugen/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(cpugen)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -g3")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+
+set(Boost_USE_STATIC_LIBS ON)
+find_package(
+ Boost 1.60.0
+ REQUIRED
+ COMPONENTS
+ system
+ regex)
+#set(BUILD_SHARED_LIBS OFF)
+#set(BUILD_STATIC_LIBS ON)
+add_subdirectory(tinyxml2)
+add_subdirectory(yaml-cpp)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../yaml-cpp/include
+ ${Boost_INCLUDE_DIRS}
+)
+
+add_executable(
+ cpugen
+ src/cpugen.cpp
+ src/utils.cpp
+)
+
+target_link_libraries(
+ cpugen
+ yaml-cpp
+ tinyxml2
+ ${Boost_LIBRARIES}
+)
diff --git a/target-avr/cpugen/README.md b/target-avr/cpugen/README.md
new file mode 100644
index 0000000..f0caa8b
--- /dev/null
+++ b/target-avr/cpugen/README.md
@@ -0,0 +1,17 @@
+# CPUGEN
+## How to build
+within ```cpugen``` directory do
+```
+git clone https://github.com/leethomason/tinyxml2
+git clone https://github.com/jbeder/yaml-cpp
+mkdir build
+cd build
+cmake ..
+make
+```
+## How to use
+```
+cpugen ../cpu/avr.yaml
+xsltproc ../xsl/decode.c.xsl output.xml > ../../decode.c
+xsltproc ../xsl/translate-inst.h.xsl output.xml > ../../translate-inst.h
+```
diff --git a/target-avr/cpugen/cpu/avr.yaml b/target-avr/cpugen/cpu/avr.yaml
new file mode 100644
index 0000000..a626859
--- /dev/null
+++ b/target-avr/cpugen/cpu/avr.yaml
@@ -0,0 +1,214 @@
+cpu:
+ name: avr
+ instructions:
+ - ADC:
+ opcode: 0001 11 hRr[1] Rd[5] lRr[4]
+ - ADD:
+ opcode: 0000 11 hRr[1] Rd[5] lRr[4]
+ - ADIW:
+ opcode: 1001 0110 hImm[2] Rd[2] lImm[4]
+ - AND:
+ opcode: 0010 00 hRr[1] Rd[5] lRr[4]
+ - ANDI:
+ opcode: 0111 hImm[4] Rd[4] lImm[4]
+ - ASR:
+ opcode: 1001 010 Rd[5] 0101
+ - BCLR:
+ opcode: 1001 0100 1 Bit[3] 1000
+ - BLD:
+ opcode: 1111 100 Rd[5] 0 Bit[3]
+ - BRBC:
+ opcode: 1111 01 Imm[7] Bit[3]
+ - BRBS:
+ opcode: 1111 00 Imm[7] Bit[3]
+ - BREAK:
+ opcode: 1001 0101 1001 1000
+ - BSET:
+ opcode: 1001 0100 0 Bit[3] 1000
+ - BST:
+ opcode: 1111 101 Rd[5] 0 Bit[3]
+ - CALL:
+ opcode: 1001 010 hImm[5] 111 lImm[17]
+ - CBI:
+ opcode: 1001 1000 Imm[5] Bit[3]
+ - COM:
+ opcode: 1001 010 Rd[5] 0000
+ - CP:
+ opcode: 0001 01 hRr[1] Rd[5] lRr[4]
+ - CPC:
+ opcode: 0000 01 hRr[1] Rd[5] lRr[4]
+ - CPI:
+ opcode: 0011 hImm[4] Rd[4] lImm[4]
+ - CPSE:
+ opcode: 0001 00 hRr[1] Rd[5] lRr[4]
+ - DEC:
+ opcode: 1001 010 Rd[5] 1010
+ - DES:
+ opcode: 1001 0100 Imm[4] 1011
+ - EICALL:
+ opcode: 1001 0101 0001 1001
+ - EIJMP:
+ opcode: 1001 0100 0001 1001
+ - ELPM1:
+ opcode: 1001 0101 1101 1000
+ - ELPM2:
+ opcode: 1001 000 Rd[5] 0110
+ - ELPMX:
+ opcode: 1001 000 Rd[5] 0111
+ - EOR:
+ opcode: 0010 01 hRr[1] Rd[5] lRr[4]
+ - FMUL:
+ opcode: 0000 0011 0 Rd[3] 1 Rr[3]
+ - FMULS:
+ opcode: 0000 0011 1 Rd[3] 0 Rr[3]
+ - FMULSU:
+ opcode: 0000 0011 1 Rd[3] 1 Rr[3]
+ - ICALL:
+ opcode: 1001 0101 0000 1001
+ - IJMP:
+ opcode: 1001 0100 0000 1001
+ - IN:
+ opcode: 1011 0 hImm[2] Rd[5] lImm[4]
+ - INC:
+ opcode: 1001 010 Rd[5] 0011
+ - JMP:
+ opcode: 1001 010 hImm[5] 110 lImm[17]
+ - LAC:
+ opcode: 1001 001 Rr[5] 0110
+ - LAS:
+ opcode: 1001 001 Rr[5] 0101
+ - LAT:
+ opcode: 1001 001 Rr[5] 0111
+ - LDX1:
+ opcode: 1001 000 Rd[5] 1100
+ - LDX2:
+ opcode: 1001 000 Rd[5] 1101
+ - LDX3:
+ opcode: 1001 000 Rd[5] 1110
+# - LDY1:
+# opcode: 1000 000 Rd[5] 1000
+ - LDY2:
+ opcode: 1001 000 Rd[5] 1001
+ - LDY3:
+ opcode: 1001 000 Rd[5] 1010
+ - LDDY:
+ opcode: 10 hImm[1] 0 mImm[2] 0 Rd[5] 1 lImm[3]
+# - LDZ1:
+# opcode: 1000 000 Rd[5] 0000
+ - LDZ2:
+ opcode: 1001 000 Rd[5] 0001
+ - LDZ3:
+ opcode: 1001 000 Rd[5] 0010
+ - LDDZ:
+ opcode: 10 hImm[1] 0 mImm[2] 0 Rd[5] 0 lImm[3]
+ - LDI:
+ opcode: 1110 hImm[4] Rd[4] lImm[4]
+ - LDS:
+ opcode: 1001 000 Rd[5] 0000 Imm[16]
+# - LDS16:
+# opcode: 1010 0 hImm[3] Rd[4] lImm[4]
+ - LPM1:
+ opcode: 1001 0101 1100 1000
+ - LPM2:
+ opcode: 1001 000 Rd[5] 0100
+ - LPMX:
+ opcode: 1001 000 Rd[5] 0101
+ - LSR:
+ opcode: 1001 010 Rd[5] 0110
+ - MOV:
+ opcode: 0010 11 hRr[1] Rd[5] lRr[4]
+ - MOVW:
+ opcode: 0000 0001 Rd[4] Rr[4]
+ - MUL:
+ opcode: 1001 11 hRr[1] Rd[5] lRr[4]
+ - MULS:
+ opcode: 0000 0010 Rd[4] Rr[4]
+ - MULSU:
+ opcode: 0000 0011 0 Rd[3] 0 Rr[3]
+ - NEG:
+ opcode: 1001 010 Rd[5] 0001
+ - NOP:
+ opcode: 0000 0000 0000 0000
+ - OR:
+ opcode: 0010 10 hRr[1] Rd[5] lRr[4]
+ - ORI:
+ opcode: 0110 hImm[4] Rd[4] lImm[4]
+ - OUT:
+ opcode: 1011 1 hImm[2] Rd[5] lImm[4]
+ - POP:
+ opcode: 1001 000 Rd[5] 1111
+ - PUSH:
+ opcode: 1001 001 Rd[5] 1111
+ - RCALL:
+ opcode: 1101 Imm[12]
+ - RET:
+ opcode: 1001 0101 0000 1000
+ - RETI:
+ opcode: 1001 0101 0001 1000
+ - RJMP:
+ opcode: 1100 Imm[12]
+ - ROR:
+ opcode: 1001 010 Rd[5] 0111
+ - SBC:
+ opcode: 0000 10 hRr[1] Rd[5] lRr[4]
+ - SBCI:
+ opcode: 0100 hImm[4] Rd[4] lImm[4]
+ - SBI:
+ opcode: 1001 1010 Imm[5] Bit[3]
+ - SBIC:
+ opcode: 1001 1001 Imm[5] Bit[3]
+ - SBIS:
+ opcode: 1001 1011 Imm[5] Bit[3]
+ - SBIW:
+ opcode: 1001 0111 hImm[2] Rd[2] lImm[4]
+# - SBR:
+# opcode: 0110 hImm[4] Rd[4] lImm[4]
+ - SBRC:
+ opcode: 1111 110 Rr[5] 0 Bit[3]
+ - SBRS:
+ opcode: 1111 111 Rr[5] 0 Bit[3]
+ - SLEEP:
+ opcode: 1001 0101 1000 1000
+ - SPM:
+ opcode: 1001 0101 1110 1000
+ - SPMX:
+ opcode: 1001 0101 1111 1000
+ - STX1:
+ opcode: 1001 001 Rr[5] 1100
+ - STX2:
+ opcode: 1001 001 Rr[5] 1101
+ - STX3:
+ opcode: 1001 001 Rr[5] 1110
+# - STY1:
+# opcode: 1000 001 Rd[5] 1000
+ - STY2:
+ opcode: 1001 001 Rd[5] 1001
+ - STY3:
+ opcode: 1001 001 Rd[5] 1010
+ - STDY:
+ opcode: 10 hImm[1] 0 mImm[2] 1 Rd[5] 1 lImm[3]
+# - STZ1:
+# opcode: 1000 001 Rd[5] 0000
+ - STZ2:
+ opcode: 1001 001 Rd[5] 0001
+ - STZ3:
+ opcode: 1001 001 Rd[5] 0010
+ - STDZ:
+ opcode: 10 hImm[1] 0 mImm[2] 1 Rd[5] 0 lImm[3]
+ - STS:
+ opcode: 1001 001 Rd[5] 0000 Imm[16]
+# - STS16:
+# opcode: 1010 1 hImm[3] Rd[4] lImm[4]
+ - SUB:
+ opcode: 0001 10 hRr[1] Rd[5] lRr[4]
+ - SUBI:
+ opcode: 0101 hImm[4] Rd[4] lImm[4]
+ - SWAP:
+ opcode: 1001 010 Rd[5] 0010
+# - TST:
+# opcode: 0010 00 Rd[10]
+ - WDR:
+ opcode: 1001 0101 1010 1000
+ - XCH:
+ opcode: 1001 001 Rd[5] 0100
+
diff --git a/target-avr/cpugen/src/CMakeLists.txt b/target-avr/cpugen/src/CMakeLists.txt
new file mode 100644
index 0000000..45360b1
--- /dev/null
+++ b/target-avr/cpugen/src/CMakeLists.txt
@@ -0,0 +1,63 @@
+#
+# CPUGEN
+#
+# Copyright (c) 2016 Michael Rolnik
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+cmake_minimum_required(VERSION 2.8)
+
+project(cpugen)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -g3")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+
+set(Boost_USE_STATIC_LIBS ON)
+find_package(
+ Boost 1.60.0
+ REQUIRED
+ COMPONENTS
+ system
+ regex)
+set(BUILD_SHARED_LIBS OFF)
+set(BUILD_STATIC_LIBS ON)
+add_subdirectory(../tinyxml2 ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2)
+add_subdirectory(../yaml-cpp ${CMAKE_CURRENT_BINARY_DIR}/yaml-cpp)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../yaml-cpp/include
+ ${Boost_INCLUDE_DIRS}
+)
+
+add_executable(
+ cpugen
+ cpugen.cpp
+ utils.cpp
+)
+
+target_link_libraries(
+ cpugen
+ yaml-cpp
+ tinyxml2_static
+ ${Boost_LIBRARIES}
+)
+
diff --git a/target-avr/cpugen/src/cpugen.cpp b/target-avr/cpugen/src/cpugen.cpp
new file mode 100644
index 0000000..8ad4bfc
--- /dev/null
+++ b/target-avr/cpugen/src/cpugen.cpp
@@ -0,0 +1,458 @@
+/*
+ * CPUGEN
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <limits>
+#include <stdint.h>
+#include <algorithm>
+#include <iomanip>
+#include <string>
+#include <vector>
+#include <boost/regex.hpp>
+
+#include "yaml-cpp/yaml.h"
+#include "tinyxml2/tinyxml2.h"
+
+#include "utils.h"
+
+#include <boost/algorithm/string.hpp>
+
+struct inst_info_t {
+ std::string name;
+ std::string opcode;
+
+ tinyxml2::XMLElement *nodeFields;
+};
+
+struct cpu_info_t {
+ std::string name;
+ std::vector<inst_info_t * > instructions;
+};
+
+int countbits(uint64_t value)
+{
+ int counter = 0;
+ uint64_t mask = 1;
+
+ for (size_t i = 0; i < sizeof(value) * 8; ++i) {
+ if (value & mask) {
+ counter++;
+ }
+
+ mask <<= 1;
+ }
+
+ return counter;
+}
+
+int encode(uint64_t mask, uint64_t value)
+{
+ uint64_t i = 0x0000000000000001;
+ uint64_t j = 0x0000000000000001;
+ uint64_t v = 0x0000000000000000;
+
+ for (size_t it = 0; it < sizeof(value) * 8; ++it) {
+ if (mask & i) {
+ if (value & j) {
+ v |= i;
+ }
+ j <<= 1;
+ }
+
+ i <<= 1;
+ }
+
+ return v;
+}
+
+std::string num2hex(uint64_t value)
+{
+ std::ostringstream str;
+ str << "0x" << std::hex << std::setw(8) << std::setfill('0') << value;
+
+ return str.str();
+}
+
+tinyxml2::XMLDocument doc;
+
+void operator >> (const YAML::Node & node, inst_info_t & info)
+{
+ for (auto it = node.begin(); it != node.end(); ++it) {
+ const YAML::Node & curr = it->second;
+ std::string name = it->first.as<std::string>();
+
+ info.opcode = curr["opcode"].as<std::string>();
+
+ const char *response;
+ std::vector<std::string> fields;
+ std::string opcode = "";
+ int offset;
+ tinyxml2::XMLElement *nodeFields = doc.NewElement("fields");
+ uint32_t bitoffset = 0;
+
+ do {
+ opcode = info.opcode;
+ boost::replace_all(info.opcode, " ", " ");
+ boost::replace_all(info.opcode, "0 0", "00");
+ boost::replace_all(info.opcode, "0 1", "01");
+ boost::replace_all(info.opcode, "1 0", "10");
+ boost::replace_all(info.opcode, "1 1", "11");
+ } while (opcode != info.opcode);
+
+ boost::replace_all(info.opcode, "- -", "--");
+
+ fields = boost::split(fields, info.opcode, boost::is_any_of(" "));
+
+ opcode = "";
+ info.opcode = "";
+ unsigned f = 0;
+ for (int i = 0; i < fields.size(); i++) {
+ std::string field = fields[i];
+
+ if (field.empty()) {
+ continue;
+ }
+
+ size_t len = field.length();
+ boost::cmatch match;
+ tinyxml2::XMLElement *nodeField = doc.NewElement("field");
+
+ nodeFields->LinkEndChild(nodeField);
+
+ if (boost::regex_match(field.c_str(),
+ match,
+ boost::regex("^[01]+$"))) {
+ int length = field.length();
+
+ nodeField->SetAttribute("name", field.c_str());
+ nodeField->SetAttribute("length", length);
+ nodeField->SetAttribute("offset", bitoffset);
+
+ info.opcode += field;
+
+ bitoffset += len;
+ } else if (boost::regex_match(
+ field.c_str(),
+ match,
+ boost::regex("^[-]+$")))
+ {
+ int length = field.length();
+
+ nodeField->SetAttribute("name", "RESERVED");
+ nodeField->SetAttribute("length", length);
+ nodeField->SetAttribute("offset", bitoffset);
+
+ info.opcode += field;
+
+ bitoffset += len;
+ } else if (boost::regex_match(field.c_str(),
+ match,
+ boost::regex("^([a-zA-Z][a-zA-Z0-9]*)\\[([0-9]+)\\]"))) {
+ int length = std::atoi(match[2].first);
+ std::string name = std::string(match[1].first, match[1].second);
+
+ nodeField->SetAttribute("name", name.c_str());
+ nodeField->SetAttribute("length", length);
+ nodeField->SetAttribute("offset", bitoffset);
+
+ for (int j = 0; j < length; j++) {
+ info.opcode += 'a' + f;
+ }
+
+ f++;
+
+ bitoffset += length;
+ } else if (field == "~") {
+ /* nothing */
+ } else {
+ std::cout << "cannot parse " << name
+ << ": '" << field << "'" << std::endl;
+ exit(0);
+ }
+ }
+
+ info.nodeFields = nodeFields;
+ info.name = name;
+ }
+}
+
+void operator >> (inst_info_t & info, tinyxml2::XMLElement & node)
+{
+ node.SetAttribute("length", (unsigned)info.opcode.length());
+ node.SetAttribute("name", info.name.c_str());
+ node.SetAttribute("opcode", info.opcode.c_str());
+}
+
+void operator >> (const YAML::Node & node, cpu_info_t & cpu)
+{
+ const YAML::Node & insts = node["instructions"];
+
+ cpu.name = node["name"].as<std::string>();
+
+ for (unsigned i = 0; i < insts.size(); i++) {
+ inst_info_t *inst = new inst_info_t();
+
+ insts[i] >> (*inst);
+
+ if (inst->opcode != "" &&inst->opcode != "~") {
+ cpu.instructions.push_back(inst);
+ }
+ }
+}
+
+std::pair<size_t, size_t> getMinMaxInstructionLength(
+ std::vector<inst_info_t * > &instructions)
+{
+ size_t min = std::numeric_limits<size_t>::max();
+ size_t max = std::numeric_limits<size_t>::min();
+
+ for (size_t i = 0; i < instructions.size(); i++) {
+ inst_info_t *inst = instructions[i];
+ std::string opcode = inst->opcode;
+ size_t length = opcode.length();
+
+ if (opcode != "~") {
+ min = std::min(min, length);
+ max = std::max(max, length);
+ }
+ }
+
+ return std::make_pair(min, max);
+}
+
+uint64_t getXs(std::string const &opcode, size_t len, char chr)
+{
+ uint64_t result = 0;
+ size_t cur;
+ uint64_t bit = 1ull << (len - 1);
+
+ for (cur = 0; cur < len; cur++) {
+ if (opcode[cur] == chr) {
+ result |= bit;
+ }
+
+ bit >>= 1;
+ }
+
+ return result;
+}
+
+uint64_t get0s(std::string const &opcode, size_t len)
+{
+ return getXs(opcode, len, '0');
+}
+
+uint64_t get1s(std::string const &opcode, size_t len)
+{
+ return getXs(opcode, len, '1');
+}
+
+class InstSorter
+{
+ public:
+ InstSorter(size_t offset, size_t length)
+ : offset(offset), length(length)
+ {
+
+ }
+
+ bool operator()(inst_info_t *a, inst_info_t *b)
+ {
+ uint64_t field0;
+ uint64_t field1;
+ uint64_t fieldA;
+ uint64_t fieldB;
+
+ field0 = get0s(a->opcode, length);
+ field1 = get1s(a->opcode, length);
+ fieldA = field0 | field1;
+
+ field0 = get0s(b->opcode, length);
+ field1 = get1s(b->opcode, length);
+ fieldB = field0 | field1;
+
+ return fieldB < fieldA;
+ }
+
+ private:
+ size_t offset;
+ size_t length;
+
+};
+
+void divide(uint64_t select0, uint64_t select1,
+ std::vector<inst_info_t * > &info,
+ size_t level, tinyxml2::XMLElement *root)
+{
+ std::pair<size_t, size_t> minmaxSize;
+
+ minmaxSize = getMinMaxInstructionLength(info);
+
+ size_t minlen = minmaxSize.first;
+ size_t maxlen = minmaxSize.second;
+ size_t bits = std::min(minlen, sizeof(select0) * 8);
+ uint64_t all1 = (1ULL << bits) - 1;
+ uint64_t all0 = (1ULL << bits) - 1;
+ uint64_t allx = (1ULL << bits) - 1;
+ uint64_t diff;
+
+ for (size_t i = 0; i < info.size(); ++i) {
+ std::string opcode = info[i]->opcode;
+ uint64_t field0 = get0s(opcode, minlen);
+ uint64_t field1 = get1s(opcode, minlen);
+ uint64_t fieldx = field0 | field1;
+
+ if (opcode == "~") {
+ continue;
+ }
+ all0 &= field0;
+ all1 &= field1;
+ allx &= fieldx;
+ }
+
+ diff = allx ^ (all0 | all1);
+
+ if (diff == 0) {
+ tinyxml2::XMLElement *oopsNode = doc.NewElement("oops");
+ oopsNode->SetAttribute("bits", (unsigned)bits);
+ oopsNode->SetAttribute("maxlen", (unsigned)maxlen);
+ oopsNode->SetAttribute("allx", num2hex(allx).c_str());
+ oopsNode->SetAttribute("all0", num2hex(all0).c_str());
+ oopsNode->SetAttribute("all1", num2hex(all1).c_str());
+ oopsNode->SetAttribute("select0", num2hex(select0).c_str());
+ oopsNode->SetAttribute("select1", num2hex(select1).c_str());
+ root->LinkEndChild(oopsNode);
+
+ std::sort(info.begin(), info.end(), InstSorter(0, minlen));
+
+ for (size_t i = 0; i < info.size(); ++i) {
+ inst_info_t *inst = info[i];
+ tinyxml2::XMLElement *instNode = doc.NewElement("instruction");
+ tinyxml2::XMLElement *matchNode = doc.NewElement("match01");
+
+ uint64_t field0 = get0s(inst->opcode, minlen);
+ uint64_t field1 = get1s(inst->opcode, minlen);
+ uint64_t fieldx = field0 | field1;
+
+ root->LinkEndChild(matchNode);
+ matchNode->LinkEndChild(instNode);
+
+ matchNode->SetAttribute("mask", num2hex(fieldx).c_str());
+ matchNode->SetAttribute("value", num2hex(field1).c_str());
+
+ *inst >> *instNode;
+
+ instNode->LinkEndChild(inst->nodeFields);
+ }
+
+ return;
+ }
+
+ uint64_t bitsN = countbits(diff); /* number of meaningfull bits */
+
+ tinyxml2::XMLElement *switchNode = doc.NewElement("switch");
+ switchNode->SetAttribute("bits", (unsigned)bits);
+ switchNode->SetAttribute("bitoffset", (unsigned)0);
+ switchNode->SetAttribute("mask", num2hex(diff).c_str());
+ root->LinkEndChild(switchNode);
+
+ /* there are at most 1 << length subsets */
+ for (size_t s = 0; s < (1 << bitsN); ++s) {
+ std::vector<inst_info_t * > subset;
+ uint64_t index = encode(diff, s);
+
+ tinyxml2::XMLElement *caseNode = doc.NewElement("case");
+ caseNode->SetAttribute("value", num2hex(index).c_str());
+ switchNode->LinkEndChild(caseNode);
+
+ for (size_t i = 0; i < info.size(); ++i) {
+ std::string opcode = info[i]->opcode;
+ uint64_t field0 = get0s(opcode, minlen);
+ uint64_t field1 = get1s(opcode, minlen);
+
+ if (((field0 & diff) == (~index & diff))
+ && ((field1 & diff) == (index & diff))) {
+ subset.push_back(info[i]);
+ }
+ }
+
+ if (subset.size() == 1) {
+ inst_info_t *inst = subset[0];
+ tinyxml2::XMLElement *instNode = doc.NewElement("instruction");
+
+ *inst >> *instNode;
+
+ instNode->LinkEndChild(inst->nodeFields);
+
+ caseNode->LinkEndChild(instNode);
+ } else if (subset.size() > 1) {
+ /* this is a set of instructions, continue dividing */
+ divide(select0 | (diff & ~index),
+ select1 | (diff & index),
+ subset,
+ level + 2,
+ caseNode);
+ }
+ }
+}
+
+void generateParser(cpu_info_t & cpu)
+{
+ tinyxml2::XMLElement *cpuNode = doc.NewElement("cpu");
+ tinyxml2::XMLElement *instNode = doc.NewElement("instructions");
+
+ cpuNode->SetAttribute("name", cpu.name.c_str());
+ cpuNode->LinkEndChild(instNode);
+
+ doc.LinkEndChild(cpuNode);
+
+ divide(0, 0, cpu.instructions, 1, instNode);
+
+ doc.SaveFile("output.xml");
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ std::cerr << "error: usage: cpuarg [input.yaml]" << std::endl;
+ std::exit(0);
+ }
+
+ try {
+ const char *filename = argv[1];
+ std::ifstream input(filename);
+ YAML::Node doc = YAML::Load(input);
+ cpu_info_t cpu;
+
+ doc["cpu"] >> cpu;
+
+ generateParser(cpu);
+ } catch(const YAML::Exception & e) {
+ std::cerr << e.what() << "\n";
+ }
+}
+
diff --git a/target-avr/cpugen/src/utils.cpp b/target-avr/cpugen/src/utils.cpp
new file mode 100644
index 0000000..2261139
--- /dev/null
+++ b/target-avr/cpugen/src/utils.cpp
@@ -0,0 +1,27 @@
+/*
+ * CPUGEN
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "utils.h"
+#include <sstream>
+
diff --git a/target-avr/cpugen/src/utils.h b/target-avr/cpugen/src/utils.h
new file mode 100644
index 0000000..067f7d9
--- /dev/null
+++ b/target-avr/cpugen/src/utils.h
@@ -0,0 +1,79 @@
+/*
+ * CPUGEN
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef UTILS_H_
+#define UTILS_H_
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <iomanip>
+
+typedef std::vector<std::string> string_vector_t;
+
+std::string extract(std::string & str, std::string delimiter);
+std::string rextract(std::string & str, std::string del);
+string_vector_t split(std::string str, std::string delimeter);
+std::string join(string_vector_t const &vec, std::string delimeter);
+
+int countbits(uint64_t value);
+int encode(uint64_t mask, uint64_t value);
+std::string num2hex(uint64_t value);
+
+class multi
+{
+/*
+ http://www.angelikalanger.com/Articles/Cuj/05.Manipulators/Manipulators.html
+*/
+ public:
+ multi(char c, size_t n)
+ : how_many_(n)
+ , what_(c)
+ {
+ }
+
+ private:
+ const size_t how_many_;
+ const char what_;
+
+ public:
+ template <class Ostream>
+ Ostream & apply(Ostream & os) const
+ {
+ for (unsigned int i = 0; i < how_many_; ++i) {
+ os.put(what_);
+ }
+ os.flush();
+ return os;
+ }
+};
+
+template <class Ostream>
+Ostream & operator << (Ostream & os, const multi & m)
+{
+ return m.apply(os);
+}
+
+#endif
+
diff --git a/target-avr/cpugen/xsl/decode.c.xsl b/target-avr/cpugen/xsl/decode.c.xsl
new file mode 100644
index 0000000..b8aa02c
--- /dev/null
+++ b/target-avr/cpugen/xsl/decode.c.xsl
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+<!--
+ CPUGEN
+
+ Copyright (c) 2016 Michael Rolnik
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
+ xmlns:func = "http://exslt.org/functions"
+ xmlns:str = "http://exslt.org/strings"
+ xmlns:mine = "mrolnik@gmail.com"
+ extension-element-prefixes="func"
+ >
+
+ <xsl:strip-space elements="*"/>
+ <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/>
+
+ <xsl:include href="utils.xsl"/>
+
+ <xsl:template match="/cpu/instructions">
+ <xsl:value-of select="$license" />
+ <xsl:text>
+#include <stdint.h>
+#include "translate.h"
+
+void </xsl:text><xsl:value-of select="/cpu/@name"/><xsl:text>_decode(uint32_t pc, uint32_t *l, uint32_t c, translate_function_t *t)
+{
+</xsl:text>
+ <xsl:apply-templates select="switch">
+ <xsl:with-param name="ident" ><xsl:value-of select="$tab"/></xsl:with-param>
+ </xsl:apply-templates>
+<xsl:text>
+}
+</xsl:text>
+</xsl:template>
+
+ <xsl:template match="switch">
+ <xsl:param name="ident" />
+ <xsl:if test="not (@bitoffset = ../../@bitoffset and @bits = ../../@bits)" >
+ <xsl:value-of select="concat($ident, 'uint32_t opc = extract32(c, ', @bitoffset, ', ', @bits, ');', $newline)" />
+ </xsl:if>
+ <xsl:value-of select="concat($ident, 'switch (opc & ', @mask, ') {', $newline)"/>
+ <xsl:apply-templates select="case">
+ <xsl:with-param name="ident" ><xsl:value-of select="$ident"/><xsl:value-of select="$tab"/></xsl:with-param>
+ </xsl:apply-templates>
+ <xsl:value-of select="concat($ident, '}', $newline)"/>
+ </xsl:template>
+
+ <xsl:template match="case">
+ <xsl:param name="ident" />
+
+ <xsl:value-of select="concat($ident, 'case ', @value, ': {', $newline)"/>
+ <xsl:apply-templates select="switch">
+ <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param>
+ </xsl:apply-templates>
+ <xsl:apply-templates select="match01">
+ <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param>
+ </xsl:apply-templates>
+ <xsl:apply-templates select="instruction">
+ <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param>
+ </xsl:apply-templates>
+ <xsl:value-of select="concat($ident, $tab, 'break;', $newline)"/>
+ <xsl:value-of select="concat($ident, '}', $newline)"/>
+ </xsl:template>
+
+ <xsl:template match="instruction">
+ <xsl:param name="ident" />
+
+ <xsl:value-of select="concat($ident, '*l = ', string-length(@opcode), ';', $newline)" />
+ <xsl:value-of select="concat($ident, '*t = &', /cpu/@name, '_translate_', @name, ';', $newline)" />
+ </xsl:template>
+
+ <xsl:template match="match01">
+ <xsl:param name="ident" />
+
+ <xsl:value-of select="concat($ident, 'if((opc & ', @mask, ' == ', @value, ') {', $newline)" />
+ <xsl:apply-templates select="instruction">
+ <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param>
+ </xsl:apply-templates>
+ <xsl:value-of select="concat($ident, 'break;', $newline)"/>
+ <xsl:value-of select="concat($ident, '}', $newline)"/>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/target-avr/cpugen/xsl/translate-inst.h.xsl b/target-avr/cpugen/xsl/translate-inst.h.xsl
new file mode 100644
index 0000000..2830ce3
--- /dev/null
+++ b/target-avr/cpugen/xsl/translate-inst.h.xsl
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+
+<!--
+ CPUGEN
+
+ Copyright (c) 2016 Michael Rolnik
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
+ xmlns:func = "http://exslt.org/functions"
+ xmlns:str = "http://exslt.org/strings"
+ xmlns:mine = "mrolnik@gmail.com"
+ extension-element-prefixes="func"
+ >
+
+ <xsl:include href="utils.xsl"/>
+
+<xsl:strip-space elements="*"/>
+<xsl:output method="text" omit-xml-declaration="yes" indent="yes"/>
+
+<xsl:template match="/cpu/instructions">
+ <xsl:value-of select="$license" />
+<xsl:text>
+#ifndef AVR_TRANSLATE_INST_H_
+#define AVR_TRANSLATE_INST_H_
+
+typedef struct DisasContext DisasContext;
+
+</xsl:text>
+
+<xsl:apply-templates select="//instruction" />
+
+<xsl:text>
+#endif
+</xsl:text>
+</xsl:template>
+
+<xsl:template match="instruction">
+ <xsl:variable name="length" select="string-length(@opcode)" />
+ <xsl:variable name="datatype" select="mine:get-opcode-struct-type($length)" />
+ <xsl:variable name="namestem" select="@name"/>
+ <xsl:variable name="ilength" select="@length"/>
+
+ <xsl:value-of select="concat('int ', /cpu/@name, '_translate_', @name, '(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);', $newline)" />
+ <xsl:for-each select="fields/field">
+ <xsl:sort select="position()" data-type="number" order="descending"/>
+ <xsl:choose>
+ <xsl:when test="str:replace(str:replace(@name, '0', ''), '1', '') = ''">
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="field" select="substring(@name, 2, string-length(@name) - 1)" />
+ <xsl:variable name="h" select="../field[@name = concat('h', $field)]"/>
+ <xsl:variable name="l" select="../field[@name = concat('l', $field)]"/>
+ <xsl:variable name="m" select="../field[@name = concat('m', $field)]"/>
+
+ <xsl:if test="not($h/@name = @name or $m/@name = @name or $l/@name = @name)">
+ <xsl:value-of select="concat('static inline uint32_t ', $namestem, '_', @name, '(uint32_t opcode)', $newline)" />
+ <xsl:value-of select="concat('{', $newline)" />
+ <xsl:value-of select="concat(' return extract32(opcode, ', $ilength - @offset - @length, ', ', @length, ');', $newline)" />
+ <xsl:value-of select="concat('}', $newline)" />
+ </xsl:if>
+
+ <xsl:if test="$l and $h and ($h/@name = @name)">
+ <xsl:value-of select="concat('static inline uint32_t ', $namestem, '_', $field, '(uint32_t opcode)', $newline)" />
+ <xsl:value-of select="concat('{', $newline)" />
+ <xsl:value-of select="' return '" />
+
+<xsl:variable name="l_length" select="$l/@length"/>
+<xsl:variable name="l_offset" select="$ilength - $l/@offset - $l_length"/>
+
+<xsl:variable name="m_length" select="$m/@length"/>
+<xsl:variable name="m_offset" select="$ilength - $m/@offset - $m_length"/>
+
+<xsl:variable name="h_length" select="$h/@length"/>
+<xsl:variable name="h_offset" select="$ilength - $h/@offset - $h_length"/>
+
+
+ <xsl:choose>
+ <xsl:when test="$h and $m and $l">
+ <xsl:value-of select="concat('(extract32(opcode, ', $h_offset, ', ', $h_length, ') << ', $l_length + $m_length, ') | ')" />
+ <xsl:value-of select="concat('(extract32(opcode, ', $m_offset, ', ', $m_length, ') << ', $l_length, ') | ')" />
+ <xsl:value-of select="concat('(extract32(opcode, ', $l_offset, ', ', $l_length, '))')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat('(extract32(opcode, ', $h_offset, ', ', $h_length, ') << ', $l_length, ') | ')" />
+ <xsl:value-of select="concat('(extract32(opcode, ', $l_offset, ', ', $l_length, '))')" />
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:value-of select="concat(';', $newline)"/>
+ <xsl:value-of select="concat('}', $newline)"/>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:value-of select="$newline" />
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/target-avr/cpugen/xsl/utils.xsl b/target-avr/cpugen/xsl/utils.xsl
new file mode 100644
index 0000000..b4511b6
--- /dev/null
+++ b/target-avr/cpugen/xsl/utils.xsl
@@ -0,0 +1,108 @@
+<?xml version="1.0"?>
+<!--
+ CPUGEN
+
+ Copyright (c) 2016 Michael Rolnik
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+-->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
+ xmlns:str = "http://exslt.org/strings"
+ xmlns:func = "http://exslt.org/functions"
+ xmlns:exsl = "http://exslt.org/common"
+ xmlns:mine = "mrolnik@gmail.com"
+ extension-element-prefixes="func">
+
+ <xsl:output method = "text" />
+ <xsl:strip-space elements="*"/>
+
+ <xsl:variable name="newline">
+ <xsl:text>
+</xsl:text>
+ </xsl:variable>
+ <xsl:variable name="license">
+ <xsl:text>/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+</xsl:text>
+ </xsl:variable>
+
+ <xsl:variable name="tab">
+ <xsl:text> </xsl:text>
+ </xsl:variable>
+
+ <func:function name="mine:pad" as="string">
+ <xsl:param name="str" as="xs:string"/>
+ <xsl:param name="len" as="xs:integer"/>
+ <xsl:variable name="lstr" select="string-length($str)"/>
+ <xsl:variable name="pad" select="str:padding($len - $lstr, ' ')"/>
+ <func:result select="concat($str,$pad)"/>
+ </func:function>
+
+ <func:function name="mine:toupper" as="string">
+ <xsl:param name="str" as="xs:string"/>
+ <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ ,-.'" />
+ <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz____'" />
+ <func:result select="translate($str, $upper, $lower)" />
+ </func:function>
+
+ <func:function name="mine:toname" as="string">
+ <xsl:param name="str" as="xs:string"/>
+ <xsl:variable name="src" select="'. ,-'" />
+ <xsl:variable name="dst" select="'_'" />
+ <func:result select="translate($str, $src, $dst)" />
+ </func:function>
+
+ <func:function name="mine:get-opcode-struct-type">
+ <xsl:param name="length"/>
+ <xsl:choose>
+ <xsl:when test="$length < '9'">
+ <func:result select="'uint8_t '"/>
+ </xsl:when>
+ <xsl:when test="$length < '17'">
+ <func:result select="'uint16_t'"/>
+ </xsl:when>
+ <xsl:when test="$length < '33'">
+ <func:result select="'uint32_t'"/>
+ </xsl:when>
+ <xsl:when test="$length < '65'">
+ <func:result select="'uint64_t'"/>
+ </xsl:when>
+ </xsl:choose>
+ </func:function>
+
+</xsl:stylesheet>
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH v17 9/9] target-avr: adding instruction decoder
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (7 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 8/9] target-avr: instruction decoder generator Michael Rolnik
@ 2016-08-18 12:07 ` Michael Rolnik
2016-08-18 12:26 ` [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores no-reply
` (3 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: Michael Rolnik @ 2016-08-18 12:07 UTC (permalink / raw)
To: qemu-devel; +Cc: rth, peter.maydell, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/Makefile.objs | 1 +
target-avr/decode.c | 693 +++++++++++++++++++++++++++++++++++++++++++++++
target-avr/translate.c | 2 +
3 files changed, 696 insertions(+)
create mode 100644 target-avr/decode.c
diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs
index f4a82c4..b500989 100644
--- a/target-avr/Makefile.objs
+++ b/target-avr/Makefile.objs
@@ -21,5 +21,6 @@
obj-y += translate.o cpu.o helper.o
obj-y += gdbstub.o
obj-y += translate-inst.o
+obj-y += decode.o
obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-avr/decode.c b/target-avr/decode.c
new file mode 100644
index 0000000..243bab3
--- /dev/null
+++ b/target-avr/decode.c
@@ -0,0 +1,693 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 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
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include <stdint.h>
+#include "translate.h"
+
+void avr_decode(uint32_t pc, uint32_t *l, uint32_t c, translate_function_t *t)
+{
+ uint32_t opc = extract32(c, 0, 16);
+ switch (opc & 0x0000d000) {
+ case 0x00000000: {
+ switch (opc & 0x00002c00) {
+ case 0x00000000: {
+ switch (opc & 0x00000300) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_NOP;
+ break;
+ }
+ case 0x00000100: {
+ *l = 16;
+ *t = &avr_translate_MOVW;
+ break;
+ }
+ case 0x00000200: {
+ *l = 16;
+ *t = &avr_translate_MULS;
+ break;
+ }
+ case 0x00000300: {
+ switch (opc & 0x00000088) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_MULSU;
+ break;
+ }
+ case 0x00000008: {
+ *l = 16;
+ *t = &avr_translate_FMUL;
+ break;
+ }
+ case 0x00000080: {
+ *l = 16;
+ *t = &avr_translate_FMULS;
+ break;
+ }
+ case 0x00000088: {
+ *l = 16;
+ *t = &avr_translate_FMULSU;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ *l = 16;
+ *t = &avr_translate_CPC;
+ break;
+ }
+ case 0x00000800: {
+ *l = 16;
+ *t = &avr_translate_SBC;
+ break;
+ }
+ case 0x00000c00: {
+ *l = 16;
+ *t = &avr_translate_ADD;
+ break;
+ }
+ case 0x00002000: {
+ *l = 16;
+ *t = &avr_translate_AND;
+ break;
+ }
+ case 0x00002400: {
+ *l = 16;
+ *t = &avr_translate_EOR;
+ break;
+ }
+ case 0x00002800: {
+ *l = 16;
+ *t = &avr_translate_OR;
+ break;
+ }
+ case 0x00002c00: {
+ *l = 16;
+ *t = &avr_translate_MOV;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00001000: {
+ switch (opc & 0x00002000) {
+ case 0x00000000: {
+ switch (opc & 0x00000c00) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_CPSE;
+ break;
+ }
+ case 0x00000400: {
+ *l = 16;
+ *t = &avr_translate_CP;
+ break;
+ }
+ case 0x00000800: {
+ *l = 16;
+ *t = &avr_translate_SUB;
+ break;
+ }
+ case 0x00000c00: {
+ *l = 16;
+ *t = &avr_translate_ADC;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00002000: {
+ *l = 16;
+ *t = &avr_translate_CPI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00004000: {
+ switch (opc & 0x00002000) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_SBCI;
+ break;
+ }
+ case 0x00002000: {
+ *l = 16;
+ *t = &avr_translate_ORI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00005000: {
+ switch (opc & 0x00002000) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_SUBI;
+ break;
+ }
+ case 0x00002000: {
+ *l = 16;
+ *t = &avr_translate_ANDI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00008000: {
+ switch (opc & 0x00000208) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_LDDZ;
+ break;
+ }
+ case 0x00000008: {
+ *l = 16;
+ *t = &avr_translate_LDDY;
+ break;
+ }
+ case 0x00000200: {
+ *l = 16;
+ *t = &avr_translate_STDZ;
+ break;
+ }
+ case 0x00000208: {
+ *l = 16;
+ *t = &avr_translate_STDY;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00009000: {
+ switch (opc & 0x00002800) {
+ case 0x00000000: {
+ switch (opc & 0x00000600) {
+ case 0x00000000: {
+ switch (opc & 0x0000000f) {
+ case 0x00000000: {
+ *l = 32;
+ *t = &avr_translate_LDS;
+ break;
+ }
+ case 0x00000001: {
+ *l = 16;
+ *t = &avr_translate_LDZ2;
+ break;
+ }
+ case 0x00000002: {
+ *l = 16;
+ *t = &avr_translate_LDZ3;
+ break;
+ }
+ case 0x00000003: {
+ break;
+ }
+ case 0x00000004: {
+ *l = 16;
+ *t = &avr_translate_LPM2;
+ break;
+ }
+ case 0x00000005: {
+ *l = 16;
+ *t = &avr_translate_LPMX;
+ break;
+ }
+ case 0x00000006: {
+ *l = 16;
+ *t = &avr_translate_ELPM2;
+ break;
+ }
+ case 0x00000007: {
+ *l = 16;
+ *t = &avr_translate_ELPMX;
+ break;
+ }
+ case 0x00000008: {
+ break;
+ }
+ case 0x00000009: {
+ *l = 16;
+ *t = &avr_translate_LDY2;
+ break;
+ }
+ case 0x0000000a: {
+ *l = 16;
+ *t = &avr_translate_LDY3;
+ break;
+ }
+ case 0x0000000b: {
+ break;
+ }
+ case 0x0000000c: {
+ *l = 16;
+ *t = &avr_translate_LDX1;
+ break;
+ }
+ case 0x0000000d: {
+ *l = 16;
+ *t = &avr_translate_LDX2;
+ break;
+ }
+ case 0x0000000e: {
+ *l = 16;
+ *t = &avr_translate_LDX3;
+ break;
+ }
+ case 0x0000000f: {
+ *l = 16;
+ *t = &avr_translate_POP;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000200: {
+ switch (opc & 0x0000000f) {
+ case 0x00000000: {
+ *l = 32;
+ *t = &avr_translate_STS;
+ break;
+ }
+ case 0x00000001: {
+ *l = 16;
+ *t = &avr_translate_STZ2;
+ break;
+ }
+ case 0x00000002: {
+ *l = 16;
+ *t = &avr_translate_STZ3;
+ break;
+ }
+ case 0x00000003: {
+ break;
+ }
+ case 0x00000004: {
+ *l = 16;
+ *t = &avr_translate_XCH;
+ break;
+ }
+ case 0x00000005: {
+ *l = 16;
+ *t = &avr_translate_LAS;
+ break;
+ }
+ case 0x00000006: {
+ *l = 16;
+ *t = &avr_translate_LAC;
+ break;
+ }
+ case 0x00000007: {
+ *l = 16;
+ *t = &avr_translate_LAT;
+ break;
+ }
+ case 0x00000008: {
+ break;
+ }
+ case 0x00000009: {
+ *l = 16;
+ *t = &avr_translate_STY2;
+ break;
+ }
+ case 0x0000000a: {
+ *l = 16;
+ *t = &avr_translate_STY3;
+ break;
+ }
+ case 0x0000000b: {
+ break;
+ }
+ case 0x0000000c: {
+ *l = 16;
+ *t = &avr_translate_STX1;
+ break;
+ }
+ case 0x0000000d: {
+ *l = 16;
+ *t = &avr_translate_STX2;
+ break;
+ }
+ case 0x0000000e: {
+ *l = 16;
+ *t = &avr_translate_STX3;
+ break;
+ }
+ case 0x0000000f: {
+ *l = 16;
+ *t = &avr_translate_PUSH;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ switch (opc & 0x0000000e) {
+ case 0x00000000: {
+ switch (opc & 0x00000001) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_COM;
+ break;
+ }
+ case 0x00000001: {
+ *l = 16;
+ *t = &avr_translate_NEG;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000002: {
+ switch (opc & 0x00000001) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_SWAP;
+ break;
+ }
+ case 0x00000001: {
+ *l = 16;
+ *t = &avr_translate_INC;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000004: {
+ *l = 16;
+ *t = &avr_translate_ASR;
+ break;
+ }
+ case 0x00000006: {
+ switch (opc & 0x00000001) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_LSR;
+ break;
+ }
+ case 0x00000001: {
+ *l = 16;
+ *t = &avr_translate_ROR;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000008: {
+ switch (opc & 0x00000181) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_BSET;
+ break;
+ }
+ case 0x00000001: {
+ switch (opc & 0x00000010) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_IJMP;
+ break;
+ }
+ case 0x00000010: {
+ *l = 16;
+ *t = &avr_translate_EIJMP;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000080: {
+ *l = 16;
+ *t = &avr_translate_BCLR;
+ break;
+ }
+ case 0x00000081: {
+ break;
+ }
+ case 0x00000100: {
+ switch (opc & 0x00000010) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_RET;
+ break;
+ }
+ case 0x00000010: {
+ *l = 16;
+ *t = &avr_translate_RETI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000101: {
+ switch (opc & 0x00000010) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_ICALL;
+ break;
+ }
+ case 0x00000010: {
+ *l = 16;
+ *t = &avr_translate_EICALL;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000180: {
+ switch (opc & 0x00000070) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_SLEEP;
+ break;
+ }
+ case 0x00000010: {
+ *l = 16;
+ *t = &avr_translate_BREAK;
+ break;
+ }
+ case 0x00000020: {
+ *l = 16;
+ *t = &avr_translate_WDR;
+ break;
+ }
+ case 0x00000030: {
+ break;
+ }
+ case 0x00000040: {
+ *l = 16;
+ *t = &avr_translate_LPM1;
+ break;
+ }
+ case 0x00000050: {
+ *l = 16;
+ *t = &avr_translate_ELPM1;
+ break;
+ }
+ case 0x00000060: {
+ *l = 16;
+ *t = &avr_translate_SPM;
+ break;
+ }
+ case 0x00000070: {
+ *l = 16;
+ *t = &avr_translate_SPMX;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000181: {
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000000a: {
+ switch (opc & 0x00000001) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_DEC;
+ break;
+ }
+ case 0x00000001: {
+ *l = 16;
+ *t = &avr_translate_DES;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000000c: {
+ *l = 32;
+ *t = &avr_translate_JMP;
+ break;
+ }
+ case 0x0000000e: {
+ *l = 32;
+ *t = &avr_translate_CALL;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000600: {
+ switch (opc & 0x00000100) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_ADIW;
+ break;
+ }
+ case 0x00000100: {
+ *l = 16;
+ *t = &avr_translate_SBIW;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000800: {
+ switch (opc & 0x00000400) {
+ case 0x00000000: {
+ switch (opc & 0x00000300) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_CBI;
+ break;
+ }
+ case 0x00000100: {
+ *l = 16;
+ *t = &avr_translate_SBIC;
+ break;
+ }
+ case 0x00000200: {
+ *l = 16;
+ *t = &avr_translate_SBI;
+ break;
+ }
+ case 0x00000300: {
+ *l = 16;
+ *t = &avr_translate_SBIS;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ *l = 16;
+ *t = &avr_translate_MUL;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00002000: {
+ *l = 16;
+ *t = &avr_translate_IN;
+ break;
+ }
+ case 0x00002800: {
+ *l = 16;
+ *t = &avr_translate_OUT;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000c000: {
+ switch (opc & 0x00002000) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_RJMP;
+ break;
+ }
+ case 0x00002000: {
+ *l = 16;
+ *t = &avr_translate_LDI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000d000: {
+ switch (opc & 0x00002000) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_RCALL;
+ break;
+ }
+ case 0x00002000: {
+ switch (opc & 0x00000c00) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_BRBS;
+ break;
+ }
+ case 0x00000400: {
+ *l = 16;
+ *t = &avr_translate_BRBC;
+ break;
+ }
+ case 0x00000800: {
+ switch (opc & 0x00000200) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_BLD;
+ break;
+ }
+ case 0x00000200: {
+ *l = 16;
+ *t = &avr_translate_BST;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000c00: {
+ switch (opc & 0x00000200) {
+ case 0x00000000: {
+ *l = 16;
+ *t = &avr_translate_SBRC;
+ break;
+ }
+ case 0x00000200: {
+ *l = 16;
+ *t = &avr_translate_SBRS;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+}
+
diff --git a/target-avr/translate.c b/target-avr/translate.c
index 0fa8292..74b8383 100644
--- a/target-avr/translate.c
+++ b/target-avr/translate.c
@@ -90,6 +90,8 @@ static void decode_opc(AVRCPU *cpu, DisasContext *ctx, InstInfo *inst)
inst->length = 16;
inst->translate = NULL;
+ avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate);
+
if (inst->length == 16) {
inst->npc = inst->cpc + 1;
/* get opcode as 16bit value */
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (8 preceding siblings ...)
2016-08-18 12:07 ` [Qemu-devel] [PATCH v17 9/9] target-avr: adding instruction decoder Michael Rolnik
@ 2016-08-18 12:26 ` no-reply
2016-08-18 18:34 ` Peter Maydell
` (2 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: no-reply @ 2016-08-18 12:26 UTC (permalink / raw)
To: mrolnik; +Cc: famz, qemu-devel, peter.maydell, rth
Hi,
Your series seems to have some coding style problems. See output below for
more information:
Message-id: 1471522070-77598-1-git-send-email-mrolnik@gmail.com
Subject: [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores
Type: series
=== TEST SCRIPT BEGIN ===
#!/bin/bash
BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0
# Useful git options
git config --local diff.renamelimit 0
git config --local diff.renames True
commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
echo "Checking PATCH $n/$total: $(git show --no-patch --format=%s $c)..."
if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
failed=1
echo
fi
n=$((n+1))
done
exit $failed
=== TEST SCRIPT END ===
Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
* [new tag] patchew/1471522070-77598-1-git-send-email-mrolnik@gmail.com -> patchew/1471522070-77598-1-git-send-email-mrolnik@gmail.com
Switched to a new branch 'test'
294e7a4 target-avr: adding instruction decoder
3d36738 target-avr: instruction decoder generator
35bf67b target-avr: adding instruction translation
18e3870 target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
3ccde73 target-avr: adding AVR interrupt handling
8786607 target-avr: adding instructions encodings
f48b5f2 target-avr: adding a sample AVR board
5a2840e target-avr: adding AVR CPU features/flavors
4e72990 target-avr: AVR cores support is added.
=== OUTPUT BEGIN ===
Checking PATCH 1/9: target-avr: AVR cores support is added....
Checking PATCH 2/9: target-avr: adding AVR CPU features/flavors...
Checking PATCH 3/9: target-avr: adding a sample AVR board...
Checking PATCH 4/9: target-avr: adding instructions encodings...
Checking PATCH 5/9: target-avr: adding AVR interrupt handling...
Checking PATCH 6/9: target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions...
Checking PATCH 7/9: target-avr: adding instruction translation...
Checking PATCH 8/9: target-avr: instruction decoder generator...
ERROR: suspect code indent for conditional statements (4, 4)
#810: FILE: target-avr/cpugen/src/cpugen.cpp:440:
+ if (argc != 2) {
[...]
+ }
total: 1 errors, 0 warnings, 1225 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 9/9: target-avr: adding instruction decoder...
=== OUTPUT END ===
Test command exited with code: 1
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (9 preceding siblings ...)
2016-08-18 12:26 ` [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores no-reply
@ 2016-08-18 18:34 ` Peter Maydell
2016-09-05 10:52 ` Michael Rolnik
2016-09-16 6:45 ` Michael Rolnik
12 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2016-08-18 18:34 UTC (permalink / raw)
To: Michael Rolnik; +Cc: QEMU Developers, Richard Henderson
On 18 August 2016 at 13:07, Michael Rolnik <mrolnik@gmail.com> wrote:
> This series of patches adds 8bit AVR cores to QEMU.
> All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully tested yet.
> However I was able to execute simple code with functions. e.g fibonacci calculation.
> This series of patches include a non real, sample board.
> No fuses support yet. PC is set to 0 at reset.
>
First 3 patches look good to me; I put in a comment on one or
two of the other patches but mostly I intend to leave the
review of the instruction generation patches to Richard.
thanks
-- PMM
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (10 preceding siblings ...)
2016-08-18 18:34 ` Peter Maydell
@ 2016-09-05 10:52 ` Michael Rolnik
2016-09-16 6:45 ` Michael Rolnik
12 siblings, 0 replies; 19+ messages in thread
From: Michael Rolnik @ 2016-09-05 10:52 UTC (permalink / raw)
To: QEMU Developers; +Cc: Michael Rolnik
ping
On Thu, Aug 18, 2016 at 3:07 PM, Michael Rolnik <mrolnik@gmail.com> wrote:
> This series of patches adds 8bit AVR cores to QEMU.
> All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully
> tested yet.
> However I was able to execute simple code with functions. e.g fibonacci
> calculation.
> This series of patches include a non real, sample board.
> No fuses support yet. PC is set to 0 at reset.
>
> the patches include the following
> 1. just a basic 8bit AVR CPU, without instruction decoding or translation
> 2. CPU features which allow define the following 8bit AVR cores
> avr1
> avr2 avr25
> avr3 avr31 avr35
> avr4
> avr5 avr51
> avr6
> xmega2 xmega4 xmega5 xmega6 xmega7
> 3. a definition of sample machine with SRAM, FLASH and CPU which allows to
> execute simple code
> 4. encoding for all AVR instructions
> 5. interrupt handling
> 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions
> 7. a decoder which given an opcode decides what istruction it is
> 8. translation of AVR instruction into TCG
> 9. all features together
>
> changes since v3
> 1. rampD/X/Y/Z registers are encoded as 0x00ff0000 (instead of 0x000000ff)
> for faster address manipulaton
> 2. ffs changed to ctz32
> 3. duplicate code removed at avr_cpu_do_interrupt
> 4. using andc instead of not + and
> 5. fixing V flag calculation in varios instructions
> 6. freeing local variables in PUSH
> 7. tcg_const_local_i32 -> tcg_const_i32
> 8. using sextract32 instead of my implementation
> 9. fixing BLD instruction
> 10.xor(r) instead of 0xff - r at COM
> 11.fixing MULS/MULSU not to modify inputs' content
> 12.using SUB for NEG
> 13.fixing tcg_gen_qemu_ld/st call in XCH
>
> changes since v4
> 1. target is now defined as big endian in order to optimize
> push_ret/pop_ret
> 2. all style warnings are fixed
> 3. adding cpu_set/get_sreg functions
> 4. simplifying gen_goto_tb as there is no real paging
> 5. env->pc -> env->pc_w
> 6. making flag dump more compact
> 7. more spacing
> 8. renaming CODE/DATA_INDEX -> MMU_CODE/DATA_IDX
> 9. removing avr_set_feature
> 10. SPL/SPH set bug fix
> 11. switching stb_phys to cpu_stb_data
> 12. cleaning up avr_decode
> 13. saving sreg, rampD/X/Y/Z, eind in HW format (savevm)
> 14. saving CPU features (savevm)
>
> changes since v5
> 1. BLD bug fix
> 2. decoder generator is added
>
> chages since v6
> 1. using cpu_get_sreg/cpu_set_sreg in avr_cpu_gdb_read_register/avr_
> cpu_gdb_write_register
> 2. configure the target as little endian because otherwise GDB does not
> work
> 3. fixing and testing gen_push_ret/gen_pop_ret
>
> changes since v7
> 1. folding back v6
> 2. logging at helper_outb and helper_inb are done for non supported yet
> registers only
> 3. MAINTAINERS updated
>
> changes since v8
> 1. removing hw/avr from hw/Makefile.obj as it should not be built for all
> 2. making linux compilable
> 3. testing on
> a. Mac, Apple LLVM version 7.0.0
> b. Ubuntu 12.04, gcc 4.9.2
> c. Fedora 23, gcc 5.3.1
> 4. folding back some patches
> 5. translation bug fixes for ORI, CPI, XOR instructions
> 6. propper handling of cpu register writes though memory
>
> changes since v9
> 1. removing forward declarations of static functions
> 2. disabling debug prints
> 3. switching to case range instead of if else if ...
> 4. LD/ST IN/OUT accessing CPU maintainder registers are not routed to any
> device
> 5. commenst about sample board and sample IO device added
> 6. sample board description is more descriptive now
> 7. memory_region_allocate_system_memory is used to create RAM
> 8. now there are helper_fullrd & helper_fullwr when LD/ST try to access
> registers
>
> changes since v10
> 1. movig back fullwr & fullrd into the commit where outb and inb were
> introduced
> 2. changing tlb_fill function signature
> 3. adding empty line between functions
> 4. adding newline on the last line of the file
> 5. using tb->flags to generae full access ST/LD instructions
> 6. fixing SBRC bug
> 7. folding back 10th commit
> 8. whenever a new file is introduced it's added to Makefile.objs
>
> changes since v11
> 1. updating to v2.7.0-rc
> 2. removing assignment to env->fullacc from gen_intermediate_code
>
> changes since v12
> 1. fixing spacing
> 2. fixing get/put_segment functions
> 3. removing target-avr/machine.h file
> 4. VMSTATE_SINGLE_TEST -> VMSTATE_SINGLE
> 5. comment spelling
> 6. removing hw/avr/sample_io.c
> 7. char const* -> const char*
> 8. proper ram allocation
> 9. fixing breakpoint functionality.
> 10.env1 -> env
> 11.fixing avr_cpu_gdb_write_register & avr_cpu_gdb_read_register functions
> 12.any cpu is removed
> 12.feature bits are not saved into vm state
>
> changes since v13
> 1. rebasing to v2.7.0-rc1
>
> changes since v14
> 1. I made self review with git gui tool. (I did not know such a thing
> exists)
> 2. removing all double/tripple spaces
> 3. removing comment reference to SampleIO
> 4. folding back some changes, so there is not deleted lines in my code
> 5. moving avr configuration, within configure file, before chris
>
> changes since v15
> 1. removing IO registers cache from CPU
> 2. implementing CBI/SBI as read(helper_inb), modify, write(helper_outb)
> 3. implementing CBIC/SBIC as read(helper_inb), check, branch
> 4. adding missing tcg_temp_free_i32 for tcg_const_i32
>
> changes since v16
> 1. removing EXT IO registers knoledge from CPU. These registers are
> accessible
> by LD/ST only. CPU has no interest in them
>
>
> Michael Rolnik (9):
> target-avr: AVR cores support is added.
> target-avr: adding AVR CPU features/flavors
> target-avr: adding a sample AVR board
> target-avr: adding instructions encodings
> target-avr: adding AVR interrupt handling
> target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported
> instructions
> target-avr: adding instruction translation
> target-avr: instruction decoder generator
> target-avr: adding instruction decoder
>
> MAINTAINERS | 6 +
> arch_init.c | 2 +
> configure | 5 +
> default-configs/avr-softmmu.mak | 21 +
> hw/avr/Makefile.objs | 21 +
> hw/avr/sample.c | 112 ++
> include/disas/bfd.h | 6 +
> include/sysemu/arch_init.h | 1 +
> target-avr/Makefile.objs | 26 +
> target-avr/cpu-qom.h | 85 +
> target-avr/cpu.c | 603 +++++++
> target-avr/cpu.h | 238 +++
> target-avr/cpugen/CMakeLists.txt | 38 +
> target-avr/cpugen/README.md | 17 +
> target-avr/cpugen/cpu/avr.yaml | 214 +++
> target-avr/cpugen/src/CMakeLists.txt | 63 +
> target-avr/cpugen/src/cpugen.cpp | 458 +++++
> target-avr/cpugen/src/utils.cpp | 27 +
> target-avr/cpugen/src/utils.h | 79 +
> target-avr/cpugen/xsl/decode.c.xsl | 103 ++
> target-avr/cpugen/xsl/translate-inst.h.xsl | 118 ++
> target-avr/cpugen/xsl/utils.xsl | 108 ++
> target-avr/decode.c | 693 ++++++++
> target-avr/gdbstub.c | 86 +
> target-avr/helper.c | 392 +++++
> target-avr/helper.h | 29 +
> target-avr/machine.c | 115 ++
> target-avr/translate-inst.c | 2641
> ++++++++++++++++++++++++++++
> target-avr/translate-inst.h | 805 +++++++++
> target-avr/translate.c | 266 +++
> target-avr/translate.h | 116 ++
> 31 files changed, 7494 insertions(+)
> create mode 100644 default-configs/avr-softmmu.mak
> create mode 100644 hw/avr/Makefile.objs
> create mode 100644 hw/avr/sample.c
> create mode 100644 target-avr/Makefile.objs
> create mode 100644 target-avr/cpu-qom.h
> create mode 100644 target-avr/cpu.c
> create mode 100644 target-avr/cpu.h
> create mode 100644 target-avr/cpugen/CMakeLists.txt
> create mode 100644 target-avr/cpugen/README.md
> create mode 100644 target-avr/cpugen/cpu/avr.yaml
> create mode 100644 target-avr/cpugen/src/CMakeLists.txt
> create mode 100644 target-avr/cpugen/src/cpugen.cpp
> create mode 100644 target-avr/cpugen/src/utils.cpp
> create mode 100644 target-avr/cpugen/src/utils.h
> create mode 100644 target-avr/cpugen/xsl/decode.c.xsl
> create mode 100644 target-avr/cpugen/xsl/translate-inst.h.xsl
> create mode 100644 target-avr/cpugen/xsl/utils.xsl
> create mode 100644 target-avr/decode.c
> create mode 100644 target-avr/gdbstub.c
> create mode 100644 target-avr/helper.c
> create mode 100644 target-avr/helper.h
> create mode 100644 target-avr/machine.c
> create mode 100644 target-avr/translate-inst.c
> create mode 100644 target-avr/translate-inst.h
> create mode 100644 target-avr/translate.c
> create mode 100644 target-avr/translate.h
>
> --
> 2.4.9 (Apple Git-60)
>
>
--
Best Regards,
Michael Rolnik
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores
2016-08-18 12:07 [Qemu-devel] [PATCH v17 0/9] 8bit AVR cores Michael Rolnik
` (11 preceding siblings ...)
2016-09-05 10:52 ` Michael Rolnik
@ 2016-09-16 6:45 ` Michael Rolnik
12 siblings, 0 replies; 19+ messages in thread
From: Michael Rolnik @ 2016-09-16 6:45 UTC (permalink / raw)
To: QEMU Developers
ping
On Thu, Aug 18, 2016 at 3:07 PM, Michael Rolnik <mrolnik@gmail.com> wrote:
> This series of patches adds 8bit AVR cores to QEMU.
> All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully
> tested yet.
> However I was able to execute simple code with functions. e.g fibonacci
> calculation.
> This series of patches include a non real, sample board.
> No fuses support yet. PC is set to 0 at reset.
>
> the patches include the following
> 1. just a basic 8bit AVR CPU, without instruction decoding or translation
> 2. CPU features which allow define the following 8bit AVR cores
> avr1
> avr2 avr25
> avr3 avr31 avr35
> avr4
> avr5 avr51
> avr6
> xmega2 xmega4 xmega5 xmega6 xmega7
> 3. a definition of sample machine with SRAM, FLASH and CPU which allows to
> execute simple code
> 4. encoding for all AVR instructions
> 5. interrupt handling
> 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions
> 7. a decoder which given an opcode decides what istruction it is
> 8. translation of AVR instruction into TCG
> 9. all features together
>
> changes since v3
> 1. rampD/X/Y/Z registers are encoded as 0x00ff0000 (instead of 0x000000ff)
> for faster address manipulaton
> 2. ffs changed to ctz32
> 3. duplicate code removed at avr_cpu_do_interrupt
> 4. using andc instead of not + and
> 5. fixing V flag calculation in varios instructions
> 6. freeing local variables in PUSH
> 7. tcg_const_local_i32 -> tcg_const_i32
> 8. using sextract32 instead of my implementation
> 9. fixing BLD instruction
> 10.xor(r) instead of 0xff - r at COM
> 11.fixing MULS/MULSU not to modify inputs' content
> 12.using SUB for NEG
> 13.fixing tcg_gen_qemu_ld/st call in XCH
>
> changes since v4
> 1. target is now defined as big endian in order to optimize
> push_ret/pop_ret
> 2. all style warnings are fixed
> 3. adding cpu_set/get_sreg functions
> 4. simplifying gen_goto_tb as there is no real paging
> 5. env->pc -> env->pc_w
> 6. making flag dump more compact
> 7. more spacing
> 8. renaming CODE/DATA_INDEX -> MMU_CODE/DATA_IDX
> 9. removing avr_set_feature
> 10. SPL/SPH set bug fix
> 11. switching stb_phys to cpu_stb_data
> 12. cleaning up avr_decode
> 13. saving sreg, rampD/X/Y/Z, eind in HW format (savevm)
> 14. saving CPU features (savevm)
>
> changes since v5
> 1. BLD bug fix
> 2. decoder generator is added
>
> chages since v6
> 1. using cpu_get_sreg/cpu_set_sreg in avr_cpu_gdb_read_register/avr_
> cpu_gdb_write_register
> 2. configure the target as little endian because otherwise GDB does not
> work
> 3. fixing and testing gen_push_ret/gen_pop_ret
>
> changes since v7
> 1. folding back v6
> 2. logging at helper_outb and helper_inb are done for non supported yet
> registers only
> 3. MAINTAINERS updated
>
> changes since v8
> 1. removing hw/avr from hw/Makefile.obj as it should not be built for all
> 2. making linux compilable
> 3. testing on
> a. Mac, Apple LLVM version 7.0.0
> b. Ubuntu 12.04, gcc 4.9.2
> c. Fedora 23, gcc 5.3.1
> 4. folding back some patches
> 5. translation bug fixes for ORI, CPI, XOR instructions
> 6. propper handling of cpu register writes though memory
>
> changes since v9
> 1. removing forward declarations of static functions
> 2. disabling debug prints
> 3. switching to case range instead of if else if ...
> 4. LD/ST IN/OUT accessing CPU maintainder registers are not routed to any
> device
> 5. commenst about sample board and sample IO device added
> 6. sample board description is more descriptive now
> 7. memory_region_allocate_system_memory is used to create RAM
> 8. now there are helper_fullrd & helper_fullwr when LD/ST try to access
> registers
>
> changes since v10
> 1. movig back fullwr & fullrd into the commit where outb and inb were
> introduced
> 2. changing tlb_fill function signature
> 3. adding empty line between functions
> 4. adding newline on the last line of the file
> 5. using tb->flags to generae full access ST/LD instructions
> 6. fixing SBRC bug
> 7. folding back 10th commit
> 8. whenever a new file is introduced it's added to Makefile.objs
>
> changes since v11
> 1. updating to v2.7.0-rc
> 2. removing assignment to env->fullacc from gen_intermediate_code
>
> changes since v12
> 1. fixing spacing
> 2. fixing get/put_segment functions
> 3. removing target-avr/machine.h file
> 4. VMSTATE_SINGLE_TEST -> VMSTATE_SINGLE
> 5. comment spelling
> 6. removing hw/avr/sample_io.c
> 7. char const* -> const char*
> 8. proper ram allocation
> 9. fixing breakpoint functionality.
> 10.env1 -> env
> 11.fixing avr_cpu_gdb_write_register & avr_cpu_gdb_read_register functions
> 12.any cpu is removed
> 12.feature bits are not saved into vm state
>
> changes since v13
> 1. rebasing to v2.7.0-rc1
>
> changes since v14
> 1. I made self review with git gui tool. (I did not know such a thing
> exists)
> 2. removing all double/tripple spaces
> 3. removing comment reference to SampleIO
> 4. folding back some changes, so there is not deleted lines in my code
> 5. moving avr configuration, within configure file, before chris
>
> changes since v15
> 1. removing IO registers cache from CPU
> 2. implementing CBI/SBI as read(helper_inb), modify, write(helper_outb)
> 3. implementing CBIC/SBIC as read(helper_inb), check, branch
> 4. adding missing tcg_temp_free_i32 for tcg_const_i32
>
> changes since v16
> 1. removing EXT IO registers knoledge from CPU. These registers are
> accessible
> by LD/ST only. CPU has no interest in them
>
>
> Michael Rolnik (9):
> target-avr: AVR cores support is added.
> target-avr: adding AVR CPU features/flavors
> target-avr: adding a sample AVR board
> target-avr: adding instructions encodings
> target-avr: adding AVR interrupt handling
> target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported
> instructions
> target-avr: adding instruction translation
> target-avr: instruction decoder generator
> target-avr: adding instruction decoder
>
> MAINTAINERS | 6 +
> arch_init.c | 2 +
> configure | 5 +
> default-configs/avr-softmmu.mak | 21 +
> hw/avr/Makefile.objs | 21 +
> hw/avr/sample.c | 112 ++
> include/disas/bfd.h | 6 +
> include/sysemu/arch_init.h | 1 +
> target-avr/Makefile.objs | 26 +
> target-avr/cpu-qom.h | 85 +
> target-avr/cpu.c | 603 +++++++
> target-avr/cpu.h | 238 +++
> target-avr/cpugen/CMakeLists.txt | 38 +
> target-avr/cpugen/README.md | 17 +
> target-avr/cpugen/cpu/avr.yaml | 214 +++
> target-avr/cpugen/src/CMakeLists.txt | 63 +
> target-avr/cpugen/src/cpugen.cpp | 458 +++++
> target-avr/cpugen/src/utils.cpp | 27 +
> target-avr/cpugen/src/utils.h | 79 +
> target-avr/cpugen/xsl/decode.c.xsl | 103 ++
> target-avr/cpugen/xsl/translate-inst.h.xsl | 118 ++
> target-avr/cpugen/xsl/utils.xsl | 108 ++
> target-avr/decode.c | 693 ++++++++
> target-avr/gdbstub.c | 86 +
> target-avr/helper.c | 392 +++++
> target-avr/helper.h | 29 +
> target-avr/machine.c | 115 ++
> target-avr/translate-inst.c | 2641
> ++++++++++++++++++++++++++++
> target-avr/translate-inst.h | 805 +++++++++
> target-avr/translate.c | 266 +++
> target-avr/translate.h | 116 ++
> 31 files changed, 7494 insertions(+)
> create mode 100644 default-configs/avr-softmmu.mak
> create mode 100644 hw/avr/Makefile.objs
> create mode 100644 hw/avr/sample.c
> create mode 100644 target-avr/Makefile.objs
> create mode 100644 target-avr/cpu-qom.h
> create mode 100644 target-avr/cpu.c
> create mode 100644 target-avr/cpu.h
> create mode 100644 target-avr/cpugen/CMakeLists.txt
> create mode 100644 target-avr/cpugen/README.md
> create mode 100644 target-avr/cpugen/cpu/avr.yaml
> create mode 100644 target-avr/cpugen/src/CMakeLists.txt
> create mode 100644 target-avr/cpugen/src/cpugen.cpp
> create mode 100644 target-avr/cpugen/src/utils.cpp
> create mode 100644 target-avr/cpugen/src/utils.h
> create mode 100644 target-avr/cpugen/xsl/decode.c.xsl
> create mode 100644 target-avr/cpugen/xsl/translate-inst.h.xsl
> create mode 100644 target-avr/cpugen/xsl/utils.xsl
> create mode 100644 target-avr/decode.c
> create mode 100644 target-avr/gdbstub.c
> create mode 100644 target-avr/helper.c
> create mode 100644 target-avr/helper.h
> create mode 100644 target-avr/machine.c
> create mode 100644 target-avr/translate-inst.c
> create mode 100644 target-avr/translate-inst.h
> create mode 100644 target-avr/translate.c
> create mode 100644 target-avr/translate.h
>
> --
> 2.4.9 (Apple Git-60)
>
>
--
Best Regards,
Michael Rolnik
^ permalink raw reply [flat|nested] 19+ messages in thread